2f9e17d7c14146a8717d6ad60688a7feac5e829d
[openafs.git] / src / venus / fstrace.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 /*
11  * All Rights Reserved
12  */
13 #include <afsconfig.h>
14 #include <afs/param.h>
15
16 RCSID
17     ("$Header$");
18
19 #include <stdio.h>
20 #include <sys/types.h>
21 #if !defined(AFS_SUN3_ENV) && !defined(sys_vax_ul43) 
22 #include <time.h>
23 /*#ifdef        AFS_AIX_ENV*/
24 #include <sys/time.h>
25 /*#endif*/
26 #include <errno.h>
27 #undef abs
28 #include <stdlib.h>
29
30 #include <string.h>
31
32 #include <afs/stds.h>
33 #include <afs/cmd.h>
34 #include <afs/afs_args.h>
35 #include <afs/icl.h>
36 #include <afs/afsutil.h>
37
38 #if defined(AFS_OSF_ENV) || defined(AFS_SGI61_ENV) || (defined(AFS_AIX51_ENV) && defined(AFS_64BIT_KERNEL))
39 /* For SGI 6.2, this is changed to 1 if it's a 32 bit kernel. */
40 int afs_icl_sizeofLong = 2;
41 #else
42 int afs_icl_sizeofLong = 1;
43 #endif
44
45 #if defined(AFS_SGI61_ENV) || (defined(AFS_AIX51_ENV) && defined(AFS_64BIT_KERNEL))
46 int afs_64bit_kernel = 1;       /* Default for 6.2+, and always for 6.1 */
47 extern int afs_icl_sizeofLong;  /* Used in ICL_SIZEHACK() */
48 #ifdef AFS_SGI62_ENV
49 #include <unistd.h>
50
51 /* If _SC_KERN_POINTERS not in sysconf, then we can assume a 32 bit abi. */
52 void
53 set_kernel_sizeof_long(void)
54 {
55     int retval;
56
57
58     retval = sysconf(_SC_KERN_POINTERS);
59     if (retval == 64) {
60         afs_64bit_kernel = 1;
61         afs_icl_sizeofLong = 2;
62     } else {
63         afs_64bit_kernel = 0;
64         afs_icl_sizeofLong = 1;
65     }
66 }
67
68 #endif /* AFS_SGI62_ENV */
69 #endif /* AFS_SGI61_ENV */
70
71 #define BUFFER_MULTIPLIER     1024
72
73 /* make it big enough to snapshot everything at once, since
74  * decoding takes so long.
75  */
76 #define IBSIZE          100000  /* default size */
77
78 struct logInfo {
79     struct logInfo *nextp;
80     char *name;
81 } *allInfo = 0;
82
83 char dumpFileName[256] = "";
84 RegisterIclDumpFileName(name)
85      char *name;
86 {
87     (void)sprintf(dumpFileName, "icl.%.250s", name);
88 }
89
90 /* define globals to use for bulk info */
91 afs_icl_bulkSetinfo_t *setInfo = (afs_icl_bulkSetinfo_t *) 0;
92 afs_icl_bulkLoginfo_t *logInfo = (afs_icl_bulkLoginfo_t *) 0;
93
94 struct afs_icl_set *icl_allSets = 0;
95
96
97 char *name;
98 /* given a type and an address, get the size of the thing
99  * in words.
100  */
101 static
102 icl_GetSize(type, addr)
103      afs_int32 type;
104      char *addr;
105 {
106     int rsize;
107     int tsize;
108
109     rsize = 0;
110     ICL_SIZEHACK(type, addr);
111     return rsize;
112 }
113
114 /* Check types in printf string "bufferp", making sure that each
115  * is compatible with the corresponding parameter type described
116  * by typesp.  Also watch for prematurely running out of parameters
117  * before the string is gone.
118  */
119 #if defined(AFS_SGI61_ENV) || (defined(AFS_AIX51_ENV) && defined(AFS_64BIT_KERNEL))
120 static int
121 CheckTypes(bufferp, typesp, typeCount, outMsgBuffer)
122      char *bufferp;
123      int *typesp;
124      int typeCount;
125      char *outMsgBuffer;
126 {
127     register char tc;
128     int inPercent;
129     int tix;
130
131     inPercent = 0;
132     tix = 0;
133     for (tc = *bufferp;; outMsgBuffer++, tc = *(++bufferp)) {
134         *outMsgBuffer = tc;
135         if (tc == 0) {
136             /* hit end of string.  We win as long as we aren't
137              * in a '%'.
138              */
139             if (inPercent)
140                 return 0;
141             else
142                 return 1;
143         }
144         if (tc == '%') {
145             inPercent = 1 - inPercent;
146             continue;
147         }
148         if (inPercent) {
149             if (tc >= '0' && tc <= '9') {
150                 /* skip digits in % string */
151                 outMsgBuffer--;
152                 continue;
153             }
154             if (tc == 'l') {
155                 /* 'l' is a type modifier. */
156                 outMsgBuffer--;
157                 continue;
158             }
159             /* otherwise, we've finally gotten to the type-describing
160              * character.  Make sure there's a type descriptor, and then
161              * check the type descriptor.
162              */
163             inPercent = 0;
164             if (tix > typeCount)
165                 return 0;       /* no more type descriptors left */
166             if (tc == 's') {
167                 if (typesp[tix] != 1)   /* not a string descriptor */
168                     return 0;
169                 outMsgBuffer--;
170                 *outMsgBuffer = (char)1;
171             }
172             if (tc == 'u' || tc == 'x' || tc == 'd' || tc == 'o') {
173                 if (typesp[tix] != 0)
174                     return 0;   /* not an integer descriptor */
175                 outMsgBuffer--;
176                 switch (tc) {
177                 case 'd':
178                     *outMsgBuffer = (char)2;
179                     break;
180                 case 'u':
181                     *outMsgBuffer = (char)3;
182                     break;
183                 case 'o':
184                     *outMsgBuffer = (char)4;
185                     break;
186                 case 'x':
187                 default:
188                     *outMsgBuffer = (char)5;
189                     break;
190                 }
191             }
192             /* otherwise we're fine, so eat this descriptor */
193             tix++;
194         }
195     }
196     /* not reached */
197 }
198 #else /* AFS_SGI61_ENV */
199 static
200 CheckTypes(bufferp, typesp, typeCount)
201      char *bufferp;
202      int *typesp;
203      int typeCount;
204 {
205     register char tc;
206     int inPercent;
207     int tix;
208
209     inPercent = 0;
210     tix = 0;
211     for (tc = *bufferp;; tc = *(++bufferp)) {
212         if (tc == 0) {
213             /* hit end of string.  We win as long as we aren't
214              * in a '%'.
215              */
216             if (inPercent)
217                 return 0;
218             else
219                 return 1;
220         }
221         if (tc == '%') {
222             inPercent = 1 - inPercent;
223             continue;
224         }
225         if (inPercent) {
226             if (tc >= '0' && tc <= '9')
227                 continue;       /* skip digits in % string */
228             /* otherwise, we've finally gotten to the type-describing
229              * character.  Make sure there's a type descriptor, and then
230              * check the type descriptor.
231              */
232             inPercent = 0;
233             if (tix > typeCount)
234                 return 0;       /* no more type descriptors left */
235             if (tc == 's' && typesp[tix] != 1)  /* not a string descriptor */
236                 return 0;
237             if ((tc == 'u' || tc == 'l' || tc == 'x' || tc == 'd')
238                 && (typesp[tix] != 0))
239                 return 0;       /* not an integer descriptor */
240             /* otherwise we're fine, so eat this descriptor */
241             tix++;
242         }
243     }
244     /* not reached */
245 }
246 #endif /* AFS_SGI61_ENV */
247
248 /* display a single record.
249  * alp points at the first word in the array to be interpreted
250  * rsize gives the # of words in the array
251  */
252 #if defined(AFS_SGI61_ENV) && !defined(AFS_SGI62_ENV)
253 #define uint64_t long long
254 #endif
255 static
256 DisplayRecord(outFilep, alp, rsize)
257      FILE *outFilep;
258      register afs_int32 *alp;
259      afs_int32 rsize;
260 {
261     char msgBuffer[1024];
262 #if defined(AFS_SGI61_ENV) || (defined(AFS_AIX51_ENV) && defined(AFS_64BIT_KERNEL))
263     char outMsgBuffer[1024];
264     uint64_t tempParam;
265     uint64_t printfParms[ICL_MAXEXPANSION * /* max parms */ 4];
266     char *printfStrings[ICL_MAXEXPANSION * /* max parms */ 4];
267 #else /* AFS_SGI61_ENV */
268     long printfParms[ICL_MAXEXPANSION * /* max parms */ 4];
269 #endif /* AFS_SGI61_ENV */
270     int printfTypes[ICL_MAXEXPANSION * 4];
271     int i;
272     afs_int32 done = 0;
273     afs_int32 temp;
274     int j;
275     int type;
276     int pix;                    /* index in alp */
277     int pfpix;                  /* index in printfParms */
278     int pftix;                  /* index in printfTypes */
279     int status;
280     int printed;                /* did we print the string yet? */
281     afs_int32 *tlp;
282     time_t tmv;
283
284     /* decode parameters */
285     temp = alp[0];              /* type encoded in low-order 24 bits, t0 high */
286     pix = 4;
287     pfpix = 0;
288     pftix = 0;
289     /* init things */
290
291     for (i = 0; i < 4 * ICL_MAXEXPANSION; i++)
292         printfParms[i] = 0;
293     /* decode each parameter, getting addrs for afs_hyper_t and strings */
294     for (i = 0; !done && i < 4; i++) {
295         type = (temp >> (18 - i * 6)) & 0x3f;
296         switch (type) {
297         case ICL_TYPE_NONE:
298             done = 1;
299             break;
300         case ICL_TYPE_LONG:
301         case ICL_TYPE_POINTER:
302             printfTypes[pftix++] = 0;
303 #if defined(AFS_SGI61_ENV) || (defined(AFS_AIX51_ENV) && defined(AFS_64BIT_KERNEL))
304             printfParms[pfpix] = alp[pix];
305             printfParms[pfpix] &= 0xffffffff;
306             if (afs_64bit_kernel) {
307                 printfParms[pfpix] <<= 32;
308                 printfParms[pfpix] |= alp[pix + 1];
309             }
310 #elif defined(AFS_OSF_ENV)
311             printfParms[pfpix] = alp[pix + 1];
312             printfParms[pfpix] |= (alp[pix] <<= 32);
313 #else /* !AFS_OSF_ENV && !AFS_SGI61_ENV */
314             printfParms[pfpix] = alp[pix];
315 #endif
316             pfpix++;
317             break;
318         case ICL_TYPE_INT32:
319             printfTypes[pftix++] = 0;
320             printfParms[pfpix++] = alp[pix];
321             break;
322         case ICL_TYPE_HYPER:
323         case ICL_TYPE_INT64:
324             printfTypes[pftix++] = 0;
325             printfParms[pfpix++] = alp[pix];
326             printfTypes[pftix++] = 0;
327             printfParms[pfpix++] = alp[pix + 1];
328             break;
329         case ICL_TYPE_FID:
330             printfTypes[pftix++] = 0;
331             printfParms[pfpix++] = alp[pix];
332             printfTypes[pftix++] = 0;
333             printfParms[pfpix++] = alp[pix + 1];
334             printfTypes[pftix++] = 0;
335             printfParms[pfpix++] = alp[pix + 2];
336             printfTypes[pftix++] = 0;
337             printfParms[pfpix++] = alp[pix + 3];
338             break;
339         case ICL_TYPE_STRING:
340             printfTypes[pftix++] = 1;
341 #ifdef AFS_SGI64_ENV
342             printfStrings[pfpix++] = (char *)&alp[pix];
343 #else /* AFS_SGI64_ENV */
344 #if defined(AFS_SGI61_ENV) || (defined(AFS_AIX51_ENV) && defined(AFS_64BIT_KERNEL))
345             printfStrings[pfpix++] = (char *)&alp[pix];
346 #else /* AFS_SGI61_ENV */
347             printfParms[pfpix++] = (long)&alp[pix];
348 #endif /* AFS_SGI61_ENV */
349 #endif /* AFS_SGI64_ENV */
350             break;
351         case ICL_TYPE_UNIXDATE:
352             tmv = alp[pix];
353             printfParms[pfpix++] = (long)ctime(&tmv);
354             break;
355         default:
356             printf("DisplayRecord: Bad type %d in decode switch.\n", type);
357             done = 1;
358             break;
359         }
360         if (done)
361             break;
362
363         pix += icl_GetSize(type, (char *)&alp[pix]);
364     }
365
366     /* next, try to decode the opcode into a printf string */
367     dce1_error_inq_text(alp[1], msgBuffer, &status);
368
369     /* if we got a string back, and it is compatible with the
370      * parms we've got, then print it.
371      */
372     printed = 0;
373     if (status == 0) {
374 #if defined(AFS_SGI61_ENV) || (defined(AFS_AIX51_ENV) && defined(AFS_64BIT_KERNEL))
375         if (CheckTypes(msgBuffer, printfTypes, pftix, outMsgBuffer)) {
376             /* we have a string to use, but it ends "(dfs / zcm)",
377              * so we remove the extra gunk.
378              */
379             j = strlen(outMsgBuffer);
380             if (j > 12) {
381                 outMsgBuffer[j - 11] = 0;
382                 j -= 11;
383             }
384             pfpix = 0;
385             fprintf(outFilep, "time %d.%06d, pid %u: ", alp[3] / 1000000,
386                     alp[3] % 1000000, alp[2]);
387             for (i = 0; i < j; i++) {
388                 if ((int)outMsgBuffer[i] > 5)
389                     fputc(outMsgBuffer[i], outFilep);
390                 else {
391                     switch (outMsgBuffer[i]) {
392                     case 0:     /* done */
393                         break;
394                     case 1:     /* string */
395                         fprintf(outFilep, "%s", printfStrings[pfpix++]);
396                         break;
397                     case 2:     /* signed integer */
398                         fprintf(outFilep, "%lld", printfParms[pfpix++]);
399                         break;
400                     case 3:     /* unsigned integer */
401                         fprintf(outFilep, "%llu", printfParms[pfpix++]);
402                         break;
403                     case 4:     /* octal integer */
404                         fprintf(outFilep, "%llo", printfParms[pfpix++]);
405                         break;
406                     case 5:     /* hex integer */
407                         fprintf(outFilep, "%llx", printfParms[pfpix++]);
408                         break;
409                     default:
410                         fprintf(outFilep,
411                                 "fstrace: Bad char %d in outMsgBuffer for parm %d\n",
412                                 outMsgBuffer[i], pfpix);
413                         fprintf(outFilep, "fstrace: msgBuffer='%s'\n",
414                                 msgBuffer);
415                         break;
416                     }
417                 }
418             }
419             fprintf(outFilep, "\n");
420             printed = 1;
421         }
422 #else /* AFS_SGI61_ENV */
423         if (CheckTypes(msgBuffer, printfTypes, pftix)) {
424             /* we have a string to use, but it ends "(dfs / zcm)",
425              * so we remove the extra gunk.
426              */
427             j = strlen(msgBuffer);
428             if (j > 12)
429                 msgBuffer[j - 11] = 0;
430             fprintf(outFilep, "time %d.%06d, pid %u: ", alp[3] / 1000000,
431                     alp[3] % 1000000, alp[2]);
432             fprintf(outFilep, msgBuffer, printfParms[0], printfParms[1],
433                     printfParms[2], printfParms[3], printfParms[4],
434                     printfParms[5], printfParms[6], printfParms[7],
435                     printfParms[8], printfParms[9], printfParms[10],
436                     printfParms[11], printfParms[12], printfParms[13],
437                     printfParms[14], printfParms[15]);
438             fprintf(outFilep, "\n");
439             printed = 1;
440         }
441 #endif /* AFS_SGI61_ENV */
442         else {
443             fprintf(outFilep, "Type mismatch, using raw print.\n");
444             fprintf(outFilep, "%s", msgBuffer);
445         }
446     }
447     if (!printed) {
448         if (alp[1] == ICL_INFO_TIMESTAMP) {
449             tmv = alp[4];
450             fprintf(outFilep, "time %d.%06d, pid %u: %s\n", alp[3] / 1000000,
451                     alp[3] % 1000000, alp[2], ctime(&tmv));
452         } else {
453             fprintf(outFilep, "raw op %d, time %d.%06d, pid %u\n", alp[1],
454                     alp[3] / 1000000, alp[3] % 1000000, alp[2]);
455             /* now decode each parameter and print it */
456             pix = 4;
457             done = 0;
458             for (i = 0; !done && i < 4; i++) {
459                 type = (temp >> (18 - i * 6)) & 0x3f;
460                 switch (type) {
461                 case ICL_TYPE_NONE:
462                     done = 1;
463                     break;
464                 case ICL_TYPE_INT32:
465                     fprintf(outFilep, "p%d:%d ", i, alp[pix]);
466                     break;
467                 case ICL_TYPE_LONG:
468 #ifdef AFS_SGI61_ENV
469                     tempParam = alp[pix];
470                     tempParam <<= 32;
471                     tempParam |= alp[pix + 1];
472                     fprintf(outFilep, "p%d:%lld ", i, tempParam);
473 #else /* AFS_SGI61_ENV */
474                     fprintf(outFilep, "p%d:%d ", i, alp[pix]);
475 #endif /* AFS_SGI61_ENV */
476                     break;
477                 case ICL_TYPE_POINTER:
478 #ifdef AFS_SGI61_ENV
479                     tempParam = alp[pix];
480                     tempParam <<= 32;
481                     tempParam |= alp[pix + 1];
482                     fprintf(outFilep, "p%d:0x%llx ", i, tempParam);
483 #else /* AFS_SGI61_ENV */
484                     fprintf(outFilep, "p%d:0x%x ", i, alp[pix]);
485 #endif /* AFS_SGI61_ENV */
486                     break;
487                 case ICL_TYPE_HYPER:
488                 case ICL_TYPE_INT64:
489                     fprintf(outFilep, "p%d:%x.%x ", i, alp[pix],
490                             alp[pix + 1]);
491                     break;
492                 case ICL_TYPE_FID:
493                     fprintf(outFilep, "p%d:%d.%d.%d.%d ", i, alp[pix],
494                             alp[pix + 1], alp[pix + 2], alp[pix + 3]);
495                     break;
496                 case ICL_TYPE_STRING:
497                     fprintf(outFilep, "p%d:%s ", i, (char *)&alp[pix]);
498                     break;
499                 case ICL_TYPE_UNIXDATE:
500                     tmv = alp[pix];
501                     fprintf(outFilep, "p%d:%s ", i,
502                             ctime(&tmv));
503                     break;
504                 default:
505                     printf
506                         ("DisplayRecord: Bad type %d in raw print switch.\n",
507                          type);
508                     done = 1;
509                     break;
510                 }
511                 if (done)
512                     break;
513
514                 pix += icl_GetSize(type, (char *)&alp[pix]);
515             }
516         }
517         fprintf(outFilep, "\n");        /* done with line */
518     }
519 }
520
521
522
523 #include <locale.h>
524 #ifdef  AFS_OSF_ENV
525 #include <limits.h>
526 #endif
527 #include <nl_types.h>
528
529 #if     defined(AFS_OSF_ENV) && !defined(AFS_OSF20_ENV)
530 #include <fcntl.h>
531 static nl_catd catopen1();
532 nl_catd NLcatopen();
533 static nl_catd _do1_open();
534 static nl_catd cat_already_open();
535 static int make_sets();
536 static FILE *open1catfile();
537 static void add_open_cat();
538 static void cat_hard_close();
539 extern char *strchr();
540
541 static int catpid[NL_MAXOPEN];
542 static CATD *catsopen[NL_MAXOPEN];
543 #define PATH_FORMAT     "/usr/lib/nls/msg/%L/%N:/etc/nls/msg/%L/%N"
544 #define DEFAULT_LANG    "C"
545 #define TOO_MANY_HOLES(num_holes, num_non_holes) \
546     (((num_holes) > 100) && ((num_holes) > (num_non_holes)))
547
548 char *
549 rmalloc(n)
550      int n;
551
552         /*----  n: the number of bytes to be malloc'ed  ----*/
553 {
554     char *t;
555
556     t = (char *)malloc(n);
557     if (!t)
558         printf("Failed to get mem\n");
559     return (t);
560 }
561
562 #ifdef  notdef
563 #endif
564 nl_catd
565 catopen1(cat, dummy)
566      char *cat;
567      int dummy;
568         /*---- char *cat:  the name of the cat to be opened ----*/
569         /*---- int dummy:  dummy variable  ----*/
570
571 {
572     int errno_save;
573     nl_catd _do_open();             /*---- routine that actually opens 
574                                            the catalog ---- */
575     CATD *catd;
576
577     errno_save = errno;
578
579 /*
580         if (catd = cat_already_open(cat)) {
581                 catd->_count = catd->_count + 1;
582                 return(catd);
583         }
584 */
585     catd = (CATD *) rmalloc(sizeof(CATD));
586     if (catd == NULL)
587         return (CATD_ERR);
588     catd->_name = (char *)rmalloc(strlen(cat) + 1);
589     if (catd->_name == NULL)
590         return (CATD_ERR);
591     strcpy(catd->_name, cat);
592     catd->_fd = FALSE;
593     catd->_magic = CAT_MAGIC;
594     catd->_mem = FALSE;
595 #ifndef AFS_OSF20_ENV
596     catd->_pid = getpid();
597 #endif
598     catd->_count = 1;
599     if (_do1_open(catd) != CATD_ERR)
600         return (catd);
601     else {
602         free(catd->_name);
603         free(catd);
604         return (CATD_ERR);
605     }
606 }
607
608
609
610 nl_catd
611 _do1_open(catd)
612      nl_catd catd;
613
614         /*---- pointer to the partially set up cat descriptor ----*/
615
616 {
617     int make_sets();            /*---- routine to unpack the sets into 
618                                                 fast acccess mode ----*/
619     void add_open_cat();        /*---- routine to keep a list of 
620                                                opened cats ----*/
621     /*long */ int magic;
622     int i;                      /*---- Misc counter(s) used for loop */
623     struct _catset cs;
624     int errno_save;
625     int num_holes;
626
627     errno_save = errno;
628
629     catd->_fd = open1catfile(catd->_name);
630     if (!catd->_fd) {
631         return (CATD_ERR);
632     }
633     fread((void *)&magic, (size_t) 4, (size_t) 1, catd->_fd);
634     if (magic != CAT_MAGIC) {
635         printf("Magic was %x instead of %x -> %x\n", magic, CAT_MAGIC,
636                CATD_ERR);
637 /*
638                 fclose(catd->_fd);
639                 catd->_fd = NULL;
640                 return( CATD_ERR );
641 */
642     }
643 /*      if ((catd->_mem = shmat((int)fileno(catd->_fd), NULL, SHM_MAP | SHM_RDONLY))
644            == (char * )ERR ) {   */
645
646     if (1) {                    /* disable the shmat, share memory segemnt */
647
648 /*______________________________________________________________________
649         If the file can not be mapped then simulate mapping for the index
650         table so that make_sets cat set things up. (rmalloc an area big
651         enough for the index table and read the whole thing in)
652   ______________________________________________________________________*/
653
654         /* reset the file pointer to the beginning of catalog */
655         fseek(catd->_fd, (long)0, 0);
656
657         /* malloc the header, if fails return error */
658         catd->_hd = (struct _header *)rmalloc(sizeof(struct _header));
659         if (catd->_hd == NULL)
660             return (CATD_ERR);
661
662         /* read in the whole header */
663         fread((void *)catd->_hd, (size_t) sizeof(struct _header), (size_t) 1,
664               catd->_fd);
665
666         /* cs is a dummpy to hold a set temperorily. The purpose of */
667         /* this for loop is to fread the whole catalog so that the  */
668         /* file pointer will be moved to the end of the catalog.    */
669         for (i = 0; i < catd->_hd->_n_sets; i++) {
670             fread((void *)&cs, (size_t) 4, (size_t) 1, catd->_fd);
671             fseek(catd->_fd, (long)(cs._n_msgs * sizeof(struct _msgptr)), 1);
672         }
673
674         /* after the for loop, ftell returns the byte offset of the */
675         /* end of the catalog relative to the begining of the file. */
676         /* i.e. i contains the byte offset of the whole catalog.    */
677         i = ftell(catd->_fd);
678
679         /* malloc _mem as a temp pointer to hold the entire catalog. */
680         catd->_mem = (char *)rmalloc(i);
681         if (catd->_mem == NULL)
682             return (CATD_ERR);
683
684         /* reset the file pointer to the begining. */
685         fseek(catd->_fd, (long)0, 0);
686
687         /* read in the whole catalog into _mem */
688         fread((void *)catd->_mem, (size_t) i, (size_t) 1, catd->_fd);
689
690         /*
691          * If there aren't many holes in the set numbers,
692          * fully expand the compacted set array from the
693          * catalog.  Then in catgets(), we'll be able to use
694          * the set number to index directly into the expanded
695          * array.
696          *
697          * If there are a lot of holes, leave the set array
698          * compacted.  In catgets(), we'll search through it
699          * for the requested set.
700          */
701
702         num_holes = catd->_hd->_setmax - catd->_hd->_n_sets;
703         if (!TOO_MANY_HOLES(num_holes, catd->_hd->_n_sets)) {
704             catd->_sets_expanded = TRUE;
705             catd->_n_sets = catd->_hd->_setmax;
706         } else {
707             catd->_sets_expanded = FALSE;
708             catd->_n_sets = catd->_hd->_n_sets - 1;
709         }
710
711         /* malloc one extra set more than the max. set index */
712         catd->_set =
713             (struct _catset *)rmalloc((catd->_n_sets + 1) *
714                                       sizeof(struct _catset));
715         if (catd->_set == NULL)
716             return (CATD_ERR);
717
718         /* save the max. set number in catd->_setmax */
719         catd->_setmax = catd->_hd->_setmax;
720         /* call make_set to malloc memory for every message */
721         if (make_sets(catd) == -1)
722             return (CATD_ERR);
723         free(catd->_mem);
724         catd->_mem = FALSE;
725         add_open_cat(catd);
726         return (catd);
727     } else {
728
729 /*______________________________________________________________________
730         Normal mapping has occurred, set a few things up and call make_sets
731   ______________________________________________________________________*/
732
733         catd->_hd = (struct _header *)(catd->_mem);
734         catd->_setmax = catd->_hd->_setmax;
735         catd->_set =
736             (struct _catset *)rmalloc((catd->_hd->_setmax + 1) *
737                                       sizeof(struct _catset));
738         if (catd->_set == NULL)
739             return (CATD_ERR);
740         if (make_sets(catd) == -1)
741             return (CATD_ERR);
742         add_open_cat(catd);
743         return (catd);
744     }
745 }
746
747
748 static void
749 add_open_cat(catd)
750      nl_catd catd;
751                 /*---- catd to be added to the list of catalogs ----*/
752
753 {
754     int i = 0;          /*---- Misc counter(s) used for loops ----*/
755     while (i < NL_MAXOPEN && catsopen[i]) {
756         if (!strcmp(catd->_name, catsopen[i]->_name)
757 #ifndef AFS_OSF20_ENV
758             && getpid() == catsopen[i]->_pid)
759 #else
760             )
761 #endif
762             return;             /*---- The catalog is already here ----*/
763         i++;
764     }
765
766     if (i < NL_MAXOPEN) {
767         catsopen[i] = catd;
768         catpid[i] = getpid();
769     }
770 }
771
772
773 /*
774  * 
775  * NAME: make_sets
776  *
777  * FUNCTION: Expands the compacted version of the catalog index table into
778  *      the fast access memory version.
779  *
780  * EXECUTION ENVIRONMENT:
781  *
782  *      Make_set executes under a process.      
783  *
784  * RETURNS: int
785  */
786
787
788 static int
789 make_sets(catd)
790      nl_catd catd;
791 {
792     struct _catset *cset;
793     char *base = catd->_mem;
794     int n_sets = catd->_hd->_n_sets;
795     int i;              /*---- Misc counter(s) used for loops ----*/
796     int j;              /*---- Misc counter(s) used for loops ----*/
797     int msgmax;         /*---- The maximum number of _messages in a set ----*/
798     char *cmpct_set_ptr;        /*---- pointer into the index table ----*/
799     struct _catset cs;          /*---- used to look at the sets in the table -*/
800     int num_holes;
801
802     cmpct_set_ptr = base + sizeof(struct _header);
803
804     for (i = 0; i < n_sets; i++) {
805         /* loop through each compacted set */
806
807         cs = *(struct _catset *)cmpct_set_ptr;
808         /* set the _catset ptr to the base of the current 
809          * compacted set.        */
810
811         cs._mp =
812             (struct _msgptr *)(cmpct_set_ptr + 2 * sizeof(unsigned short));
813         /* set the ms array ptr to the base of
814          * compacted array of _msgptr's     */
815
816         cset =
817             (catd->_sets_expanded) ? &catd->_set[cs._setno] : &catd->_set[i];
818
819         /*
820          * If there aren't many holes in the message numbers,
821          * fully expand the compacted message array from the
822          * catalog.  Then in catgets(), we'll be able to use
823          * the message number to index directly into the
824          * expanded array.
825          *
826          * If there are many holes, leave the message array
827          * compacted.  In catgets(), we'll search through it
828          * for the requested message.
829          */
830
831         msgmax = cs._mp[cs._n_msgs - 1]._msgno;
832         num_holes = msgmax - cs._n_msgs;
833         if (!TOO_MANY_HOLES(num_holes, cs._n_msgs)) {
834             cset->_msgs_expanded = TRUE;
835             cset->_n_msgs = msgmax;
836         } else {
837             cset->_msgs_expanded = FALSE;
838             cset->_n_msgs = cs._n_msgs - 1;
839         }
840
841         cset->_mp =
842             (struct _msgptr *)rmalloc((1 + cset->_n_msgs) *
843                                       sizeof(struct _msgptr));
844         if (cset->_mp == NULL)
845             return (-1);
846
847         cset->_msgtxt =
848             (char **)rmalloc((1 + cset->_n_msgs) * sizeof(char *));
849         if (cset->_msgtxt == NULL)
850             return (-1);
851
852         if (cset->_msgs_expanded) {
853             for (j = 0; j < cs._n_msgs; j++) {
854                 cset->_mp[cs._mp[j]._msgno] = cs._mp[j];
855             }
856         } else {
857             for (j = 0; j < cs._n_msgs; j++) {
858                 cset->_mp[j] = cs._mp[j];
859             }
860         }
861
862         cset->_setno = cs._setno;
863         /* Superfluous but should have the correct data. Increment 
864          * the base of the set pointer.          */
865
866         cmpct_set_ptr +=
867             2 * sizeof(unsigned short) + cs._n_msgs * sizeof(struct _msgptr);
868     }
869     return (0);
870 }
871
872
873
874 /*
875  * 
876  * NAME: opencatfile
877  *
878  * FUNCTION: Opens a catalog file, looking in the language path first (if 
879  *      there is no slash) and returns a pointer to the file stream.
880  *                                                                    
881  * EXECUTION ENVIRONMENT:
882  *
883  *      Opencatfile executes under a process.   
884  *
885  * RETURNS:  Returns a pointer to the file stream, and a NULL pointer on
886  *      failure.
887  */
888
889 static FILE *
890 open1catfile(file)
891      char *file;
892 {
893     extern char *getenv();
894     char fl[PATH_MAX];          /*---- place to hold full path ----*/
895     char *nlspath;              /*---- pointer to the nlspath val ----*/
896     FILE *fp;                   /*---- file pointer ----*/
897     char cpth[PATH_MAX];        /*---- current value of nlspath ----*/
898     char *p, *np;
899     char *fulllang;             /* %L language value */
900     char lang[PATH_MAX];        /* %l language value */
901     char *territory;            /* %t language value */
902     char *codeset;              /* %c language value */
903     char *ptr;                  /* for decompose of $LANG */
904     char *str;
905     char *optr;
906     int nchars;
907     int lenstr;
908     char outptr[PATH_MAX];
909     int valid;
910
911     if (strchr(file, '/')) {
912         if ((fp = fopen(file, "r"))) {
913             fcntl(fileno(fp), F_SETFD, 1);
914             /* set the close-on-exec flag for
915              * child process                */
916             return (fp);
917         }
918     } else {
919         if (!(nlspath = getenv("NLSPATH")))
920             nlspath = PATH_FORMAT;
921         if (!(fulllang = getenv("LANG")))
922             fulllang = DEFAULT_LANG;
923         if (fulllang == DEFAULT_LANG)
924             nlspath = PATH_FORMAT;      /* if fullang is C, use the 
925                                          * the default nlspath:    */
926
927         /*
928          ** LANG is a composite of three fields:
929          ** language_territory.codeset
930          ** and we're going to break it into those
931          ** three fields.
932          */
933
934         strcpy(lang, fulllang);
935
936         territory = "";
937         codeset = "";
938
939         ptr = strchr(lang, '_');
940         if (ptr != NULL) {
941             territory = ptr + 1;
942             *ptr = '\0';
943             ptr = strchr(territory, '.');
944             if (ptr != NULL) {
945                 codeset = ptr + 1;
946                 *ptr = '\0';
947             }
948         } else {
949             ptr = strchr(lang, '.');
950             if (ptr != NULL) {
951                 codeset = ptr + 1;
952                 *ptr = '\0';
953             }
954         }
955
956         np = nlspath;
957         while (*np) {
958             p = cpth;
959             while (*np && *np != ':')
960                 *p++ = *np++;
961             *p = '\0';
962             if (*np)                                    /*----  iff on a colon then advance --*/
963                 np++;
964             valid = 0;
965             if (strlen(cpth)) {
966                 ptr = cpth;
967                 optr = outptr;
968
969                 nchars = 0;
970                 while (*ptr != '\0') {
971                     while ((*ptr != '\0') && (*ptr != '%')
972                            && (nchars < PATH_MAX)) {
973                         *(optr++) = *(ptr++);
974                         nchars++;
975                     }
976                     if (*ptr == '%') {
977                         switch (*(++ptr)) {
978                         case '%':
979                             str = "%";
980                             break;
981                         case 'L':
982                             str = fulllang;
983                             break;
984                         case 'N':
985                             valid = 1;
986                             str = file;
987                             break;
988                         case 'l':
989                             str = lang;
990                             break;
991                         case 't':
992                             str = territory;
993                             break;
994                         case 'c':
995                             str = codeset;
996                             break;
997                         default:
998                             str = "";
999                             break;
1000                         }
1001                         lenstr = strlen(str);
1002                         nchars += lenstr;
1003                         if (nchars < PATH_MAX) {
1004                             strcpy(optr, str);
1005                             optr += lenstr;
1006                         } else {
1007                             break;
1008                         }
1009                         ptr++;
1010                     } else {
1011                         if (nchars >= PATH_MAX) {
1012                             break;
1013                         }
1014                     }
1015                 }
1016                 *optr = '\0';
1017                 strcpy(cpth, outptr);
1018             } else {                    /*----  iff leading | trailing | 
1019                                                 adjacent colons ... --*/
1020                 valid = 1;
1021                 strcpy(cpth, file);
1022             }
1023             if (valid == 1 && (fp = fopen(cpth, "r"))) {
1024                 fcntl(fileno(fp), F_SETFD, 1);
1025                 /* set the close-on-exec flag for
1026                  * child process                */
1027                 return (fp);
1028             }
1029         }
1030         if (fp = fopen(file, "r")) {
1031             fcntl(fileno(fp), F_SETFD, 1);
1032             /* set the close-on-exec flag for
1033              * child process                */
1034             return (fp);
1035         }
1036     }
1037     return (NULL);
1038 }
1039
1040
1041
1042
1043
1044 /*
1045  * 
1046  * NAME: cat_already_open
1047  *
1048  * FUNCTION: Checkes to see if a specific cat has already been opened.
1049  *                                                                    
1050  * EXECUTION ENVIRONMENT:
1051  *
1052  *      Cat_already_open executes under a process.
1053  *
1054  * RETURNS: Returns a pointer to the existing CATD if one exists, and 
1055  *      a NULL pointer if no CATD exists.
1056  */
1057
1058 static nl_catd
1059 cat_already_open(cat)
1060      char *cat;
1061                         /*---- name of the catalog to be opened ----*/
1062
1063 {
1064     int i;                      /*---- Misc counter(s) used for loops ----*/
1065
1066     for (i = 0; i < NL_MAXOPEN && catsopen[i]; i++) {
1067 #ifndef AFS_OSF20_ENV
1068         if (!strcmp(cat, catsopen[i]->_name) && getpid() == catsopen[i]->_pid) {
1069 #else
1070         if (!strcmp(cat, catsopen[i]->_name)) {
1071 #endif
1072             return (catsopen[i]);
1073         }
1074     }
1075     return (0);
1076 }
1077
1078
1079 int
1080 catclose1(catd)                                 /*---- the catd to be closed ----*/
1081      nl_catd catd;      /*---- the catd to be closed ----*/
1082
1083 {
1084     int i;
1085
1086
1087     if (catd == CATD_ERR)
1088         return (-1);
1089     for (i = 0; i < NL_MAXOPEN && catsopen[i]; i++) {
1090 #ifndef AFS_OSF20_ENV
1091         if (catd == catsopen[i] && getpid() == catsopen[i]->_pid)
1092 #else
1093         if (catd == catsopen[i])
1094 #endif
1095             break;
1096     }
1097     if (i == NL_MAXOPEN || catsopen[i] == NULL)
1098         return (-1);
1099     if (catd->_fd == (FILE *) NULL)
1100                                 /*----  return if this is an extra open or
1101                                         a bad catalog discriptor         ----*/
1102         return (-1);
1103     if (cat_already_open(catd->_name)) {
1104         if (catd->_count == 1) {
1105             cat_hard_close(catd);
1106             return (0);                 /*--- the last legal clsoe ---*/
1107         } else if (catd->_count > 1) {
1108             catd->_count = catd->_count - 1;
1109             return (0);                 /*--- a legal close ---*/
1110         } else
1111             return (-1);                /*--- an extra illegal close ---*/
1112     } else {
1113         return (-1);
1114     }
1115 }
1116
1117 static void
1118 cat_hard_close(catd)
1119      nl_catd catd;
1120                 /*---- the catd to be closed ----*/
1121
1122 {
1123     int i;                      /*---- Misc counter(s) used for loops ----*/
1124     int j;                      /*----  Misc counter ----*/
1125
1126     if (catd == CATD_ERR)
1127         return;
1128
1129 /*______________________________________________________________________
1130         remove any entry for the catalog in the catsopen array
1131   ______________________________________________________________________*/
1132
1133     for (i = 0; i < NL_MAXOPEN && catsopen[i]; i++) {
1134         if (catd == catsopen[i]) {
1135             for (; i < NL_MAXOPEN - 1; i++) {
1136                 catsopen[i] = catsopen[i + 1];
1137                 catpid[i] = catpid[i + 1];
1138             }
1139             catsopen[i] = NULL;
1140             catpid[i] = 0;
1141         }
1142     }
1143
1144 /*______________________________________________________________________
1145         close the cat and free up the memory
1146   ______________________________________________________________________*/
1147     if (catd->_mem == FALSE) {
1148         for (i = 0; i <= catd->_n_sets; i++) {
1149             if (catd->_set[i]._mp)
1150                 free(catd->_set[i]._mp);
1151                         /*---- free the _message pointer arrays ----*/
1152
1153             if (catd->_set[i]._msgtxt) {
1154                 for (j = 0; j <= catd->_set[i]._n_msgs; j++) {
1155                     if (catd->_set[i]._msgtxt[j]) {
1156 /*                                      free(catd->_set[i]._msgtxt[j]);*/
1157                     }
1158                 }
1159                 if (catd->_set[i]._msgtxt)
1160                     free(catd->_set[i]._msgtxt);
1161             }
1162         }
1163     }
1164
1165     if (catd->_fd)
1166         fclose(catd->_fd);              /*---- close the ctatlog ----*/
1167     if (catd->_set)
1168         free(catd->_set);               /*---- free the sets ----*/
1169     if (catd->_name)
1170         free(catd->_name);              /*---- free the name ----*/
1171     if (catd->_hd)
1172         free(catd->_hd);                /*---- free the header ----*/
1173     if (catd)
1174         free(catd);                     /*---- free the catd ----*/
1175 }
1176
1177 static char *
1178 _do1_read_msg(nl_catd catd, int setno, int msgno)
1179
1180         /*---- catd: the catd of the catalog to be read from ----*/
1181         /*---- setno: the set number of the message ----*/
1182         /*---- msgno: the msgno of the message ----*/
1183 {
1184     nl_catd catd1;              /*--- catd for different process ----*/
1185     char *_read1_msg();
1186
1187 #ifndef AFS_OSF20_ENV
1188     if (getpid() == catd->_pid)
1189 #else
1190     if (1)
1191 #endif
1192         return (_read1_msg(catd, setno, msgno));
1193     else {
1194         /*
1195          * Since our pid is different from the one in
1196          * catd, catd must have come from a catopen()
1197          * in our parent.  We need a catd of our own.
1198          * The first time through here, the call to
1199          * catopen() creates a new catd and we try to
1200          * open its message catalog.  After that, the
1201          * catopen() just retrieves the catd.
1202          */
1203         if (((catd1 = catopen1(catd->_name, 0)) != CATD_ERR)
1204             && ((catd1->_fd == NL_FILE_CLOSED && _do1_open(catd1) != CATD_ERR)
1205                 || (catd1->_fd != NL_FILE_UNUSED)))
1206             return (_read1_msg(catd1, setno, msgno));
1207         else
1208             return (NULL);
1209     }
1210 }
1211
1212
1213 struct _catset *_cat1_get_catset();
1214 static struct _msgptr *_cat1_get_msgptr();
1215 static char *
1216 _read1_msg(nl_catd catd, int setno, int msgno)
1217 {
1218     struct _catset *set;        /*--- ptr to set's _catset structure ---*/
1219     struct _msgptr *msg;        /*--- ptr to msg's _msgptr structure ---*/
1220     char **msgtxt;              /*--- temporary pointer to the message text
1221                                       for speed.  ----*/
1222
1223     set = _cat1_get_catset(catd, setno);
1224     if (set) {
1225         msg = _cat1_get_msgptr(set, msgno);
1226         if (msg) {
1227             msgtxt = &set->_msgtxt[msg - set->_mp];
1228             if (1 /*!*msgtxt */ ) {
1229                 *msgtxt = (char *)malloc(msg->_msglen + 1);
1230                 if (!*msgtxt)
1231                     return (NULL);
1232
1233                 fseek(catd->_fd, (long)msg->_offset, 0);
1234                 if (fread
1235                     ((void *)*msgtxt, (size_t) (msg->_msglen + 1), (size_t) 1,
1236                      catd->_fd) != 1)
1237                     return (NULL);
1238             }
1239
1240             return (*msgtxt);
1241         }
1242     }
1243     return (NULL);
1244 }
1245
1246 /*
1247  * NAME: compare_sets
1248  *                                                                    
1249  * FUNCTION: Compare function used by bsearch() in _cat_get_catset().
1250  *                                                                    
1251  * ARGUMENTS:
1252  *      key             - pointer to set number we're searching for
1253  *      element         - pointer to current _catset structure
1254  *
1255  * RETURNS: Returns -1, 0, or 1, depending on whether the set number
1256  *          is less than, equal to, or greater than the set number of
1257  *          the _catset structure.
1258  *
1259  */
1260
1261 static int
1262 compare_sets(const void *key, const void *element)
1263 {
1264     int *setno = (int *)key;
1265     struct _catset *set = (struct _catset *)element;
1266
1267     if (*setno < set->_setno)
1268         return -1;
1269     if (*setno > set->_setno)
1270         return 1;
1271
1272     return 0;
1273 }
1274
1275
1276 /*
1277  * NAME: _cat_get_catset
1278  *                                                                    
1279  * FUNCTION: Find a set in the catd->_set array.  Assumes that the
1280  *           sets in the array are sorted by increasing set number.
1281  *                                                                    
1282  * ARGUMENTS:
1283  *      catd            - catalog descripter obtained from catopen()
1284  *      setno           - message catalogue set number
1285  *
1286  * RETURNS: Returns a pointer to the set on success.
1287  *      On any error, returns NULL.
1288  *
1289  */
1290
1291 struct _catset *
1292 _cat1_get_catset(nl_catd catd, int setno)
1293 {
1294     struct _catset *set;
1295
1296     if ((catd == (nl_catd) NULL) || (catd == CATD_ERR))
1297         return (struct _catset *)NULL;
1298
1299     if (catd->_sets_expanded) {
1300         if ((setno < 0) || (setno > catd->_n_sets))
1301             return (struct _catset *)NULL;
1302
1303         set = &catd->_set[setno];
1304
1305         /*
1306          * Catch empty elements in the array.  They aren't
1307          * real sets.
1308          */
1309
1310         if (set->_mp == (struct _msgptr *)NULL)
1311             return (struct _catset *)NULL;
1312     } else {
1313         set =
1314             (struct _catset *)bsearch((void *)&setno, catd->_set,
1315                                       catd->_n_sets + 1,
1316                                       sizeof(struct _catset), compare_sets);
1317
1318         /*
1319          * Since the sets are compacted, there aren't any
1320          * empty elements in the array to check for.
1321          */
1322     }
1323
1324     return set;
1325 }
1326
1327
1328 /*
1329  * NAME: compare_msgs
1330  *                                                                    
1331  * FUNCTION: Compare function used by bsearch() in _cat_get_msgptr().
1332  *                                                                    
1333  * ARGUMENTS:
1334  *      key             - pointer to message number we're searching for
1335  *      element         - pointer to current _msgptr structure
1336  *
1337  * RETURNS: Returns -1, 0, or 1, depending on whether the message
1338  *          number is less than, equal to, or greater than the message
1339  *          number of the _msgptr structure.
1340  *
1341  */
1342
1343 static int
1344 compare_msgs(const void *key, const void *element)
1345 {
1346     int *msgno = (int *)key;
1347     struct _msgptr *msg = (struct _msgptr *)element;
1348
1349     if (*msgno < msg->_msgno)
1350         return -1;
1351     if (*msgno > msg->_msgno)
1352         return 1;
1353
1354     return 0;
1355 }
1356
1357 /*
1358  * NAME: _cat1_get_msgptr
1359  *                                                                    
1360  * FUNCTION: Find a message in a set's set->_mp array.  Assumes that
1361  *           the messages in the array are sorted by increasing
1362  *           message number.
1363  *                                                                    
1364  * ARGUMENTS:
1365  *      set             - ptr to _catset structure
1366  *      msgno           - message catalogue message number
1367  *
1368  * RETURNS: Returns a pointer to the message on success.
1369  *      On any error, returns NULL.
1370  *
1371  */
1372 static struct _msgptr *
1373 _cat1_get_msgptr(struct _catset *set, int msgno)
1374 {
1375     struct _msgptr *msg;
1376
1377     if (set == (struct _catset *)NULL)
1378         return (struct _msgptr *)NULL;
1379
1380     if (set->_mp == (struct _msgptr *)NULL)     /* empty set */
1381         return (struct _msgptr *)NULL;
1382
1383     if (set->_msgs_expanded) {
1384         if ((msgno < 0) || (msgno > set->_n_msgs))
1385             return (struct _msgptr *)NULL;
1386
1387         msg = &set->_mp[msgno];
1388
1389         /*
1390          * Catch empty elements in the array.  They aren't
1391          * real messages.
1392          */
1393
1394         if (!msg->_offset)
1395             return (struct _msgptr *)NULL;
1396     } else {
1397         msg =
1398             (struct _msgptr *)bsearch((void *)&msgno, set->_mp,
1399                                       set->_n_msgs + 1,
1400                                       sizeof(struct _msgptr), compare_msgs);
1401
1402         /*
1403          * Since the messages are compacted, there aren't any
1404          * empty elements in the array to check for.
1405          */
1406     }
1407
1408     return msg;
1409 }
1410
1411 char *
1412 catgets1(nl_catd catd, int setno, int msgno, char *def)
1413         /*---- catd: the catd to get the message from ----*/
1414         /*---- setno: the set number of the message ----*/
1415         /*---- msgno: the message number of the message ----*/
1416         /*---- def: the default string to be returned ----*/
1417 {
1418     int errno_save;
1419     char *_do_read_msg();
1420     char *m;
1421     errno_save = errno;
1422
1423     if (catd == NULL || catd == CATD_ERR || catd->_magic != CAT_MAGIC
1424         || catd->_fd == NL_FILE_UNUSED) {
1425         return (def);
1426     }
1427     if (catd->_fd == NL_FILE_CLOSED) {
1428         catd = _do1_open(catd);
1429         if (catd == CATD_ERR)
1430             return (def);
1431     }
1432
1433     if (catd->_mem) {           /*----  for mapped files ----*/
1434         if (setno <= catd->_hd->_setmax) {
1435             if (msgno < catd->_set[setno]._n_msgs) {
1436                 if (catd->_set[setno]._mp[msgno]._offset) {
1437                     return (catd->_mem +
1438                             catd->_set[setno]._mp[msgno]._offset);
1439                 }
1440             }
1441         }
1442         return (def);
1443     } else {    /*---- for unmapped files ----*/
1444         m = _do1_read_msg(catd, setno, msgno);
1445         if (m == NULL)
1446             return (def);
1447         else
1448             return (m);
1449     }
1450 }
1451
1452 #endif
1453
1454 #define FACILITY_CODE_MASK          0xF0000000
1455 #define FACILITY_CODE_SHIFT         28
1456
1457 #define COMPONENT_CODE_MASK         0x0FFFF000
1458 #define COMPONENT_CODE_SHIFT        12
1459
1460 #define STATUS_CODE_MASK            0x00000FFF
1461 #define STATUS_CODE_SHIFT           0
1462
1463 #define NO_MESSAGE                  "THIS IS NOT A MESSAGE"
1464
1465 /*
1466  * The system-dependant location for the catalog files is defined in sysconf.h
1467  * RPC_DEFAULT_NLSPATH should be defined in sysconf.h. Otherwise we use
1468  * /usr/afs/etc/C/%s.cat 
1469  */
1470
1471 #ifndef RPC_NLS_FORMAT
1472 #define RPC_NLS_FORMAT "%s.cat"
1473 #endif
1474
1475 dce1_error_inq_text(status_to_convert, error_text, status)
1476      afs_uint32 status_to_convert;
1477      unsigned char *error_text;
1478      int *status;
1479
1480 {
1481     unsigned short facility_code;
1482     unsigned short component_code;
1483     unsigned short status_code;
1484     unsigned short i, failed = 0;
1485     nl_catd catd;
1486     char component_name[4];
1487     char *facility_name;
1488     char filename_prefix[7];
1489     char nls_filename[11];
1490     char alt_filename[80];
1491     char *message;
1492 #if defined(AFS_64BITPOINTER_ENV)
1493     long J;
1494 #else
1495     int J;
1496 #endif
1497     static char *facility_names[] = {
1498         "xxx",
1499         "afs"
1500     };
1501
1502     /*
1503      * set up output status for future error returns
1504      */
1505     if (status != NULL) {
1506         *status = -1;
1507     }
1508     /*
1509      * check for ok input status
1510      */
1511     if (status_to_convert == 0) {
1512         if (status != NULL) {
1513             *status = 0;
1514         }
1515         strcpy((char *)error_text, "successful completion");
1516         return;
1517     }
1518
1519     /*
1520      * extract the component, facility and status codes
1521      */
1522     facility_code =
1523         (status_to_convert & FACILITY_CODE_MASK) >> FACILITY_CODE_SHIFT;
1524     component_code =
1525         (status_to_convert & COMPONENT_CODE_MASK) >> COMPONENT_CODE_SHIFT;
1526     status_code = (status_to_convert & STATUS_CODE_MASK) >> STATUS_CODE_SHIFT;
1527
1528     /*
1529      * see if this is a recognized facility
1530      */
1531     if (facility_code == 0
1532         || facility_code > sizeof(facility_names) / sizeof(char *)) {
1533         sprintf((char *)error_text, "status %08x (unknown facility)",
1534                 status_to_convert);
1535         return;
1536     }
1537     facility_name = facility_names[facility_code - 1];
1538     /*
1539      * Convert component name from RAD-50 component code.  (Mapping is:
1540      * 0 => 'a', ..., 25 => 'z', 26 => '{', 27 => '0', ..., 36 => '9'.)
1541      */
1542     component_name[3] = 0;
1543     component_name[2] = component_code % 40;
1544     component_code /= 40;
1545     component_name[1] = component_code % 40;
1546     component_name[0] = component_code / 40;
1547     for (i = 0; i < 3; i++) {
1548         component_name[i] += (component_name[i] <= 26) ? 'a' : ('0' - 27);
1549     }
1550     sprintf(filename_prefix, "%3s%3s", facility_name, component_name);
1551     sprintf(nls_filename, RPC_NLS_FORMAT, filename_prefix);
1552
1553     /*
1554      * Open the message file
1555      */
1556 #if     defined(AFS_OSF_ENV)
1557 #if     defined(AFS_OSF20_ENV)
1558     catd = (nl_catd) catopen(nls_filename, 0);
1559 #else
1560     catd = (nl_catd) catopen1(nls_filename, 0);
1561 #endif
1562 #else
1563 #if defined(AFS_64BITPOINTER_ENV)
1564     J = (long)catopen(nls_filename, 0);
1565 #else
1566     J = (int)catopen(nls_filename, 0);
1567 #endif
1568     catd = (nl_catd) J;
1569 #endif
1570     if (catd == (nl_catd) - 1) {
1571         /*
1572          * If we did not succeed in opening message file using NLSPATH,
1573          * try to open the message file in a well-known default area
1574          */
1575       tryagain:
1576 #ifndef RPC_DEFAULT_NLSPATH
1577         sprintf(alt_filename, "%s/C/%s.cat", AFSDIR_CLIENT_ETC_DIRPATH,
1578                 filename_prefix);
1579 #else
1580         sprintf(alt_filename, RPC_DEFAULT_NLSPATH, filename_prefix);
1581 #endif
1582
1583 #if     defined(AFS_OSF_ENV)
1584 #if     defined(AFS_OSF20_ENV)
1585         catd = (nl_catd) catopen(alt_filename, 0);
1586 #else
1587         catd = (nl_catd) catopen1(alt_filename, 0);
1588 #endif
1589 #else
1590 #if defined(AFS_64BITPOINTER_ENV)
1591         J = (long)catopen(alt_filename, 0);
1592 #else
1593         J = (int)catopen(alt_filename, 0);
1594 #endif
1595         catd = (nl_catd) J;
1596 #endif
1597         if (catd == (nl_catd) - 1) {
1598             sprintf((char *)error_text, "status %08x (%s / %s)",
1599                     status_to_convert, facility_name, component_name);
1600             return;
1601         }
1602     }
1603     /*
1604      * try to get the specified message from the file
1605      */
1606 #if     defined(AFS_OSF_ENV) && !defined(AFS_OSF20_ENV)
1607     message = (char *)catgets1(catd, 1, status_code, NO_MESSAGE);
1608 #else
1609     message = (char *)catgets(catd, 1, status_code, NO_MESSAGE);
1610 #endif
1611     /*
1612      * if everything went well, return the resulting message
1613      */
1614     if (strcmp(message, NO_MESSAGE) != 0) {
1615         sprintf((char *)error_text, "%s (%s / %s)", message, facility_name,
1616                 component_name);
1617         if (status != NULL) {
1618             *status = 0;
1619         }
1620     } else {
1621         if (!failed) {
1622             failed = 1;
1623 #if defined(AFS_OSF_ENV) && !defined(AFS_OSF20_ENV)
1624             catclose1(catd);
1625 #else
1626             catclose(catd);
1627 #endif
1628             goto tryagain;
1629         }
1630         sprintf((char *)error_text, "status %08x (%s / %s)",
1631                 status_to_convert, facility_name, component_name);
1632     }
1633 #if     defined(AFS_OSF_ENV) && !defined(AFS_OSF20_ENV)
1634     catclose1(catd);
1635 #else
1636     catclose(catd);
1637 #endif
1638
1639 }
1640
1641
1642 icl_DumpKernel(outFilep, setname)
1643      FILE *outFilep;
1644      char *setname;
1645 {
1646     afs_int32 bufferSize = 0;
1647     afs_int32 *bufferp;
1648     afs_int32 i;
1649     afs_int32 code, retVal = 0;
1650     char tname[64];
1651     afs_int32 nwords;
1652     afs_int32 ix;
1653     afs_int32 rlength;
1654     afs_int32 dummy, dummy2;
1655     struct logInfo *lip;
1656
1657     /* first, enumerate the logs we're interested in */
1658     if (setname) {
1659         int found = 0;
1660         /* dump logs for a particular set */
1661         for (i = 0; i < ICL_LOGSPERSET; i++) {
1662             code =
1663                 afs_syscall(AFSCALL_ICL, ICL_OP_ENUMLOGSBYSET, (long)setname,
1664                             i, (long)tname, sizeof(tname));
1665             if (code) {
1666                 if (errno == EBADF) {
1667                     code = 0;
1668                     continue;   /* missing slot, nothing to worry about */
1669                 }
1670                 break;
1671             }
1672             code =
1673                 afs_syscall(AFSCALL_ICL, ICL_OP_GETLOGINFO, (long)tname,
1674                             (long)&dummy, (long)&dummy2, 0);
1675             if (code)
1676                 break;
1677             found++;
1678             if (dummy > bufferSize)     /* find biggest log */
1679                 bufferSize = dummy;
1680             lip = (struct logInfo *)malloc(sizeof(struct logInfo));
1681             memset((char *)lip, 0, sizeof(*lip));
1682             lip->nextp = allInfo;
1683             allInfo = lip;
1684             lip->name = (char *)malloc(strlen(tname) + 1);
1685             strcpy(lip->name, tname);
1686         }
1687         i = found;
1688     } else {
1689         /* dump all logs */
1690         for (i = 0; i < 1000; i++) {
1691             code =
1692                 afs_syscall(AFSCALL_ICL, ICL_OP_ENUMLOGS, i, (long)tname,
1693                             sizeof(tname), (long)&dummy);
1694             if (code)
1695                 break;
1696             if (dummy > bufferSize)     /* find biggest log */
1697                 bufferSize = dummy;
1698             lip = (struct logInfo *)malloc(sizeof(struct logInfo));
1699             memset((char *)lip, 0, sizeof(*lip));
1700             lip->nextp = allInfo;
1701             allInfo = lip;
1702             lip->name = (char *)malloc(strlen(tname) + 1);
1703             strcpy(lip->name, tname);
1704         }
1705     }
1706
1707     if (bufferSize == 0)
1708         return -1;
1709     bufferp = (afs_int32 *) malloc(sizeof(afs_int32) * bufferSize);
1710     if (!bufferp)
1711         return -1;
1712
1713     fprintf(outFilep, "Found %d logs.\n", i);
1714
1715     /* now print out the contents of each log */
1716     for (lip = allInfo; lip; lip = lip->nextp) {
1717         fprintf(outFilep, "\nContents of log %s:\n", lip->name);
1718         /* read out everything first; gets a more consistent
1719          * snapshot.
1720          */
1721         nwords = 0;             /* total words copied out */
1722         for (i = 0;;) {
1723             /* display all the entries in the log */
1724             if (bufferSize - nwords <= 0)
1725                 break;          /* filled whole buffer */
1726             code =
1727                 afs_syscall(AFSCALL_ICL, ICL_OP_COPYOUT, (long)lip->name,
1728                             (long)(bufferp + nwords), bufferSize - nwords,
1729                             (long)&i);
1730             if (code < 0) {
1731                 /* otherwise we've got an error */
1732                 fprintf(outFilep, "Returned error %d dumping log.\n", errno);
1733                 break;
1734             }
1735             /* otherwise, we have flags in the high order byte, and
1736              * a length (in words) in the remainder.
1737              */
1738             if ((code >> 24) & ICL_COPYOUTF_MISSEDSOME)
1739                 fprintf(outFilep, "Log wrapped; data missing.\n");
1740             code &= 0xffffff;
1741             if (code == 0) {
1742                 /* we're done */
1743                 break;
1744             }
1745             nwords += code;
1746             i += code;
1747         }                       /* for loop over all cookies */
1748
1749         /* otherwise we should display all of the log entries here.
1750          * Note that a record may end in the middle, in which case
1751          * we should start over with the cookie value of the start
1752          * of that record.
1753          */
1754         for (ix = 0; ix < nwords;) {
1755             /* start of a record */
1756             rlength = (bufferp[ix] >> 24) & 0xff;
1757             if (rlength <= 0) {
1758                 fprintf(outFilep, "Internal error: 0 length record\n");
1759                 retVal = -1;
1760                 goto done;
1761             }
1762             /* ensure that entire record fits */
1763             if (ix + rlength > nwords) {
1764                 /* doesn't fit, adjust cookie and break */
1765                 break;
1766             }
1767             /* print the record */
1768             DisplayRecord(outFilep, &bufferp[ix], rlength);
1769             ix += rlength;
1770 #ifdef notdef
1771             /* obsolete: read entire buffer first */
1772             i += rlength;       /* update cookie value, too */
1773 #endif
1774         }                       /* for loop displaying buffer */
1775     }                           /* for loop over all logs */
1776
1777   done:
1778     free(bufferp);
1779     return (retVal);
1780 }
1781
1782 /* clear out log 'name' */
1783 icl_ClearLog(name)
1784      char *name;
1785 {
1786     afs_int32 code;
1787
1788     code = afs_syscall(AFSCALL_ICL, ICL_OP_CLRLOG, (long)name, 0, 0, 0);
1789     return code;
1790 }
1791
1792 /* clear out set 'name' */
1793 icl_ClearSet(name)
1794      char *name;
1795 {
1796     afs_int32 code;
1797
1798     code = afs_syscall(AFSCALL_ICL, ICL_OP_CLRSET, (long)name, 0, 0, 0);
1799     return code;
1800 }
1801
1802 /* clear out all logs */
1803 icl_ClearAll()
1804 {
1805     afs_int32 code;
1806
1807     code = afs_syscall(AFSCALL_ICL, ICL_OP_CLRALL, 0, 0, 0, 0);
1808     return code;
1809 }
1810
1811 /* list out all available sets to outFileP */
1812 int
1813 icl_ListSets(outFileP)
1814      FILE *outFileP;
1815 {
1816     int i;
1817     afs_int32 code = 0;
1818     afs_int32 states;
1819     char tname[64];
1820
1821     for (i = 0; i < 1000; i++) {
1822         code =
1823             afs_syscall(AFSCALL_ICL, ICL_OP_ENUMSETS, i, (long)tname,
1824                         sizeof(tname), (long)&states);
1825         if (code)
1826             break;
1827         (void)fprintf(outFileP, "%s %s%s%s\n", tname,
1828                       (states & ICL_SETF_ACTIVE) ? "active" : "inactive",
1829                       (states & ICL_SETF_FREED) ? " (dormant)" : "",
1830                       (states & ICL_SETF_PERSISTENT) ? " persistent" : "");
1831     }
1832
1833     return 0;
1834 }
1835
1836 /* list out all available logs to outFileP */
1837 int
1838 icl_ListLogs(outFileP, int32flg)
1839      FILE *outFileP;
1840      int int32flg;
1841 {
1842     int i;
1843     int allocated;
1844     afs_int32 code = 0;
1845     afs_int32 logSize;
1846     char tname[64];
1847
1848     for (i = 0; i < 1000; i++) {
1849         code =
1850             afs_syscall(AFSCALL_ICL, ICL_OP_ENUMLOGS, i, (long)tname,
1851                         sizeof(tname), (long)&logSize);
1852         if (code)
1853             break;
1854         if (int32flg) {
1855             /* get more information on the log */
1856             code =
1857                 afs_syscall(AFSCALL_ICL, ICL_OP_GETLOGINFO, (long)tname,
1858                             (long)&logSize, (long)&allocated, 0);
1859             if (code)
1860                 break;
1861             (void)fprintf(outFileP, "%s : %d kbytes (%s)\n", tname,
1862                           logSize / 1024,
1863                           allocated ? "allocated" : "unallocated");
1864         } else
1865             (void)fprintf(outFileP, "%s\n", tname);
1866     }
1867
1868     return 0;
1869 }
1870
1871 /* list out all available logs to outFileP */
1872 int
1873 icl_ListLogsBySet(outFileP, setname, int32flg)
1874      FILE *outFileP;
1875      char *setname;
1876      int int32flg;
1877 {
1878     int i;
1879     afs_int32 code = 0;
1880     afs_int32 logSize;
1881     int allocated;
1882     char tname[64];
1883
1884     for (i = 0; i < ICL_LOGSPERSET; i++) {
1885         code =
1886             afs_syscall(AFSCALL_ICL, ICL_OP_ENUMLOGSBYSET, (long)setname, i,
1887                         (long)tname, sizeof(tname));
1888         if (code) {
1889             if (errno == EBADF) {
1890                 code = 0;
1891                 continue;       /* missing */
1892             }
1893             break;
1894         }
1895         if (int32flg) {
1896             /* get more information on the log */
1897             code =
1898                 afs_syscall(AFSCALL_ICL, ICL_OP_GETLOGINFO, (long)tname,
1899                             (long)&logSize, (long)&allocated, 0);
1900             if (code)
1901                 break;
1902             (void)fprintf(outFileP, "%s : %d kbytes (%s)\n", tname,
1903                           logSize / 1024,
1904                           allocated ? "allocated" : "unallocated");
1905         } else
1906             (void)fprintf(outFileP, "%s\n", tname);
1907     }
1908
1909     return code;
1910 }
1911
1912 /* activate/deactivate/free specified set */
1913 int
1914 icl_ChangeSetState(name, op)
1915      char *name;
1916      afs_int32 op;
1917 {
1918     afs_int32 code;
1919
1920     code = afs_syscall(AFSCALL_ICL, ICL_OP_SETSTAT, (long)name, op, 0, 0);
1921     return code;
1922 }
1923
1924 /* activate/deactivate/free all sets */
1925 int
1926 icl_ChangeAllSetState(op)
1927      afs_int32 op;
1928 {
1929     afs_int32 code;
1930
1931     code = afs_syscall(AFSCALL_ICL, ICL_OP_SETSTATALL, op, 0, 0, 0);
1932     return code;
1933 }
1934
1935 /* set size if log */
1936 int
1937 icl_ChangeLogSize(name, logSize)
1938      char *name;
1939      afs_int32 logSize;
1940 {
1941     afs_int32 code;
1942
1943     code =
1944         afs_syscall(AFSCALL_ICL, ICL_OP_SETLOGSIZE, (long)name, logSize, 0,
1945                     0);
1946     return code;
1947 }
1948
1949 /* get logsize of specified log */
1950 int
1951 icl_GetLogsize(logname, logSizeP, allocatedP)
1952      char *logname;
1953      afs_int32 *logSizeP;
1954      int *allocatedP;
1955 {
1956     afs_int32 code;
1957     code =
1958         afs_syscall(AFSCALL_ICL, ICL_OP_GETLOGINFO, (long)logname,
1959                     (long)logSizeP, (long)allocatedP, 0);
1960     return code;
1961 }
1962
1963 /* get state of specified set */
1964 int
1965 icl_GetSetState(setname, stateP)
1966      char *setname;
1967      afs_int32 *stateP;
1968 {
1969     afs_int32 code;
1970     code =
1971         afs_syscall(AFSCALL_ICL, ICL_OP_GETSETINFO, (long)setname,
1972                     (long)stateP, 0, 0);
1973     return code;
1974 }
1975
1976 icl_TailKernel(outFilep, logname, waitTime)
1977      FILE *outFilep;
1978      char *logname;
1979      afs_int32 waitTime;
1980 {
1981     afs_int32 bufferSize = 0;
1982     afs_int32 newBufferSize;
1983     afs_int32 *bufferp;
1984     afs_int32 i;
1985     afs_int32 code, retVal = 0;
1986     afs_int32 nwords;
1987     afs_int32 ix;
1988     afs_int32 rlength;
1989     int allocated;
1990     struct logInfo *lip;
1991
1992     /* get information about the specified log */
1993     code =
1994         afs_syscall(AFSCALL_ICL, ICL_OP_GETLOGINFO, (long)logname,
1995                     (long)&bufferSize, (long)&allocated, 0);
1996     if (code) {
1997         if (errno == ENOENT)
1998             (void)fprintf(stderr, "'%s' not found\n", logname);
1999         else
2000             (void)fprintf(stderr,
2001                           "cannot get information on log '%s' (errno = %d)\n",
2002                           logname, errno);
2003         return -1;
2004     }
2005
2006     if (!allocated) {
2007         (void)fprintf(stderr, "'%s' not allocated\n", logname);
2008         return 0;
2009     }
2010
2011     if (bufferSize == 0)
2012         return -1;
2013     bufferp = (afs_int32 *) malloc(sizeof(afs_int32) * bufferSize);
2014     if (!bufferp) {
2015         (void)fprintf(stderr, "cannot allocate %d words for buffer\n",
2016                       bufferSize);
2017         return -1;
2018     }
2019
2020     /* start "infinite" loop */
2021     for (;;) {
2022         /* read out all that's currently there */
2023         nwords = 0;             /* total words copied out */
2024         i = 0;                  /* initialize cookie */
2025         for (;;) {
2026             /* display all the entries in the log */
2027             if (bufferSize - nwords <= 0)
2028                 break;          /* filled whole buffer, clear when done */
2029             code =
2030                 afs_syscall(AFSCALL_ICL, ICL_OP_COPYOUTCLR, (long)logname,
2031                             (long)(bufferp + nwords), bufferSize - nwords,
2032                             (long)&i);
2033             if (code < 0) {
2034                 /* otherwise we've got an error */
2035                 fprintf(stderr, "returned error %d dumping log.\n", errno);
2036                 retVal = -1;
2037                 goto tail_done;
2038             }
2039             /* otherwise, we have flags in the high order byte, and
2040              * a length (in words) in the remainder.
2041              */
2042             code &= 0xffffff;
2043             if (code == 0) {
2044                 /* we're done */
2045                 break;
2046             }
2047             nwords += code;
2048             i += code;
2049         }                       /* for loop over all cookies */
2050
2051         /* otherwise we should display all of the log entries here.
2052          * Note that a record may end in the middle, in which case
2053          * we should start over with the cookie value of the start
2054          * of that record.
2055          */
2056         for (ix = 0; ix < nwords;) {
2057             /* start of a record */
2058             rlength = (bufferp[ix] >> 24) & 0xff;
2059             /* ensure that entire record fits */
2060             if (ix + rlength > nwords) {
2061                 /* doesn't fit, adjust cookie and break */
2062                 if (rlength <= 0) {
2063                     fprintf(stderr, "BOGUS: 0 length record\n");
2064                     retVal = -1;
2065                     goto tail_done;
2066                 }
2067                 break;
2068             }
2069             /* print the record */
2070             DisplayRecord(outFilep, &bufferp[ix], rlength);
2071             ix += rlength;
2072         }                       /* for loop displaying buffer */
2073
2074         if (waitTime)
2075             sleep(waitTime);
2076
2077         /* see if things have changed */
2078         code =
2079             afs_syscall(AFSCALL_ICL, ICL_OP_GETLOGINFO, (long)logname,
2080                         (long)&newBufferSize, (long)&allocated, 0);
2081         if (code) {
2082             if (errno == ENOENT)
2083                 (void)fprintf(stderr, "'%s' not found\n", logname);
2084             else
2085                 (void)fprintf(stderr,
2086                               "cannot get information on log '%s' (errno = %d)\n",
2087                               logname, errno);
2088             retVal = -1;
2089             goto tail_done;
2090         }
2091
2092         if (!allocated) {
2093             (void)fprintf(stderr, "'%s' no int32er allocated\n", logname);
2094             retVal = -1;
2095             goto tail_done;
2096         }
2097
2098         if (bufferSize == 0) {
2099             (void)fprintf(stderr, "buffer size has become 0\n");
2100             retVal = -1;
2101             goto tail_done;
2102         }
2103         if (bufferSize != newBufferSize) {
2104             /* have to reallocate a buffer */
2105             bufferSize = newBufferSize;
2106             free(bufferp);
2107             bufferp = (afs_int32 *) malloc(sizeof(afs_int32) * bufferSize);
2108             if (!bufferp) {
2109                 (void)fprintf(stderr, "cannot allocate %d words for buffer\n",
2110                               bufferSize);
2111                 retVal = -1;
2112                 goto tail_done;
2113             }
2114         }
2115     }                           /* infinite loop */
2116
2117   tail_done:
2118     free(bufferp);
2119     return (retVal);
2120 }
2121
2122 #if !defined(AFS_SGI_ENV)
2123 afs_syscall(call, parm0, parm1, parm2, parm3, parm4, parm5, parm6)
2124      long call, parm0, parm1, parm2, parm3, parm4, parm5, parm6;
2125 {
2126     int code, rval;
2127 #ifdef AFS_LINUX20_ENV
2128 #if defined AFS_LINUX_64BIT_KERNEL
2129     long long eparm[4];
2130     /* don't want to sign extend it to 64bit, so using ulong */
2131     eparm[0] = (unsigned long)parm3;
2132     eparm[1] = (unsigned long)parm4;
2133     eparm[2] = (unsigned long)parm5;
2134     eparm[3] = (unsigned long)parm6;
2135 #else
2136     int eparm[4];
2137     eparm[0] = parm3;
2138     eparm[1] = parm4;
2139     eparm[2] = parm5;
2140     eparm[3] = parm6;
2141 #endif
2142     /* Linux can only handle 5 arguments in the actual syscall. */
2143     if (call == AFSCALL_ICL) {
2144         rval = proc_afs_syscall(call, parm0, parm1, parm2, eparm, &code);
2145         if (rval)
2146             code = syscall(AFS_SYSCALL, call, parm0, parm1, parm2, eparm);
2147     } else {
2148         rval = proc_afs_syscall(call, parm0, parm1, parm2, parm3, &code);
2149         if (rval)
2150             code = syscall(AFS_SYSCALL, call, parm0, parm1, parm2, parm3);
2151     }
2152 #if defined(AFS_SPARC64_LINUX20_ENV) || defined(AFS_SPARC_LINUX20_ENV)
2153     /* on sparc this function returns none value, so do it myself */
2154     __asm__ __volatile__("mov   %o0, %i0; ret; restore");
2155 #endif
2156 #else
2157 #ifdef AFS_DARWIN80_ENV
2158     code = ioctl_afs_syscall(call, parm0, parm1, parm2, parm3, parm4, parm5, &rval);
2159     if (!code) code = rval;
2160 #else
2161 #if !defined(AFS_SGI_ENV) && !defined(AFS_AIX32_ENV)
2162     code = syscall(AFS_SYSCALL, call, parm0, parm1, parm2, parm3, parm4);
2163 #else
2164 #if defined(AFS_SGI_ENV)
2165     code = syscall(AFS_ICL, call, parm0, parm1, parm2, parm3, parm4);   /* XXX */
2166 #else
2167     code = syscall(AFSCALL_ICL, parm0, parm1, parm2, parm3, parm4);
2168 #endif
2169 #endif
2170 #endif
2171 #endif /* AFS_LINUX20_ENV */
2172     return code;
2173 }
2174 #endif
2175
2176
2177 int icl_inited = 0;
2178
2179 /* init function, called once, under icl_lock */
2180 icl_Init()
2181 {
2182     icl_inited = 1;
2183
2184 #ifndef KERNEL
2185     /* setup signal handler, in user space */
2186 #endif /* KERNEL */
2187
2188     return 0;
2189 }
2190
2191 icl_CreateSet(name, baseLogp, fatalLogp, outSetpp)
2192      char *name;
2193      struct afs_icl_log *baseLogp;
2194      struct afs_icl_log *fatalLogp;
2195      struct afs_icl_set **outSetpp;
2196 {
2197     return icl_CreateSetWithFlags(name, baseLogp, fatalLogp, /*flags */ 0,
2198                                   outSetpp);
2199 }
2200
2201 /* create a set, given pointers to base and fatal logs, if any.
2202  * Logs are unlocked, but referenced, and *outSetpp is returned
2203  * referenced.  Function bumps reference count on logs, since it
2204  * addds references from the new icl_set.  When the set is destroyed,
2205  * those references will be released.
2206  */
2207 icl_CreateSetWithFlags(name, baseLogp, fatalLogp, flags, outSetpp)
2208      char *name;
2209      struct afs_icl_log *baseLogp;
2210      struct afs_icl_log *fatalLogp;
2211      afs_uint32 flags;
2212      struct afs_icl_set **outSetpp;
2213 {
2214     register struct afs_icl_set *setp;
2215     register int i;
2216     afs_int32 states = ICL_DEFAULT_SET_STATES;
2217
2218     if (!icl_inited)
2219         icl_Init();
2220
2221     for (setp = icl_allSets; setp; setp = setp->nextp) {
2222         if (strcmp(setp->name, name) == 0) {
2223             setp->refCount++;
2224             *outSetpp = setp;
2225             if (flags & ICL_CRSET_FLAG_PERSISTENT) {
2226                 setp->states |= ICL_SETF_PERSISTENT;
2227             }
2228             return 0;
2229         }
2230     }
2231
2232     /* determine initial state */
2233     if (flags & ICL_CRSET_FLAG_DEFAULT_ON)
2234         states = ICL_SETF_ACTIVE;
2235     else if (flags & ICL_CRSET_FLAG_DEFAULT_OFF)
2236         states = ICL_SETF_FREED;
2237     if (flags & ICL_CRSET_FLAG_PERSISTENT)
2238         states |= ICL_SETF_PERSISTENT;
2239
2240     setp = (struct afs_icl_set *)osi_Alloc(sizeof(struct afs_icl_set));
2241     memset((caddr_t) setp, 0, sizeof(*setp));
2242     setp->refCount = 1;
2243     if (states & ICL_SETF_FREED)
2244         states &= ~ICL_SETF_ACTIVE;     /* if freed, can't be active */
2245     setp->states = states;
2246
2247     setp->name = (char *)osi_Alloc(strlen(name) + 1);
2248     strcpy(setp->name, name);
2249     setp->nevents = ICL_DEFAULTEVENTS;
2250     setp->eventFlags = (char *)osi_Alloc(ICL_DEFAULTEVENTS);
2251     for (i = 0; i < ICL_DEFAULTEVENTS; i++)
2252         setp->eventFlags[i] = 0xff;     /* default to enabled */
2253
2254     /* update this global info under the icl_lock */
2255     setp->nextp = icl_allSets;
2256     icl_allSets = setp;
2257
2258     /* set's basic lock is still held, so we can finish init */
2259     if (baseLogp) {
2260         setp->logs[0] = baseLogp;
2261         icl_LogHold(baseLogp);
2262         if (!(setp->states & ICL_SETF_FREED))
2263             icl_LogUse(baseLogp);       /* log is actually being used */
2264     }
2265     if (fatalLogp) {
2266         setp->logs[1] = fatalLogp;
2267         icl_LogHold(fatalLogp);
2268         if (!(setp->states & ICL_SETF_FREED))
2269             icl_LogUse(fatalLogp);      /* log is actually being used */
2270     }
2271
2272     *outSetpp = setp;
2273     return 0;
2274 }
2275
2276 /* function to change event enabling information for a particular set */
2277 icl_SetEnable(setp, eventID, setValue)
2278      struct afs_icl_set *setp;
2279      afs_int32 eventID;
2280      int setValue;
2281 {
2282     char *tp;
2283
2284     if (!ICL_EVENTOK(setp, eventID)) {
2285         return -1;
2286     }
2287     tp = &setp->eventFlags[ICL_EVENTBYTE(eventID)];
2288     if (setValue)
2289         *tp |= ICL_EVENTMASK(eventID);
2290     else
2291         *tp &= ~(ICL_EVENTMASK(eventID));
2292     return 0;
2293 }
2294
2295 /* return indication of whether a particular event ID is enabled
2296  * for tracing.  If *getValuep is set to 0, the event is disabled,
2297  * otherwise it is enabled.  All events start out enabled by default.
2298  */
2299 icl_GetEnable(setp, eventID, getValuep)
2300      struct afs_icl_set *setp;
2301      afs_int32 eventID;
2302      int *getValuep;
2303 {
2304     if (!ICL_EVENTOK(setp, eventID)) {
2305         return -1;
2306     }
2307     if (setp->eventFlags[ICL_EVENTBYTE(eventID)] & ICL_EVENTMASK(eventID))
2308         *getValuep = 1;
2309     else
2310         *getValuep = 0;
2311     return 0;
2312 }
2313
2314 /* hold and release event sets */
2315 icl_SetHold(setp)
2316      register struct afs_icl_set *setp;
2317 {
2318     setp->refCount++;
2319     return 0;
2320 }
2321
2322 /* free a set.  Called with icl_lock locked */
2323 icl_ZapSet(setp)
2324      register struct afs_icl_set *setp;
2325 {
2326     register struct afs_icl_set **lpp, *tp;
2327     int i;
2328     register struct afs_icl_log *tlp;
2329
2330     for (lpp = &icl_allSets, tp = *lpp; tp; lpp = &tp->nextp, tp = *lpp) {
2331         if (tp == setp) {
2332             /* found the dude we want to remove */
2333             *lpp = setp->nextp;
2334             osi_Free(setp->name, 1 + strlen(setp->name));
2335             osi_Free(setp->eventFlags, ICL_EVENTBYTES(setp->nevents));
2336             for (i = 0; i < ICL_LOGSPERSET; i++) {
2337                 if (tlp = setp->logs[i])
2338                     icl_LogReleNL(tlp);
2339             }
2340             osi_Free(setp, sizeof(struct afs_icl_set));
2341             break;              /* won't find it twice */
2342         }
2343     }
2344     return 0;
2345 }
2346
2347 /* do the release, watching for deleted entries */
2348 icl_SetRele(setp)
2349      register struct afs_icl_set *setp;
2350 {
2351     if (--setp->refCount == 0 && (setp->states & ICL_SETF_DELETED)) {
2352         icl_ZapSet(setp);       /* destroys setp's lock! */
2353     }
2354     return 0;
2355 }
2356
2357 /* free a set entry, dropping its reference count */
2358 icl_SetFree(setp)
2359      register struct afs_icl_set *setp;
2360 {
2361     setp->states |= ICL_SETF_DELETED;
2362     icl_SetRele(setp);
2363     return 0;
2364 }
2365
2366 /* find a set by name, returning it held */
2367 struct afs_icl_set *
2368 icl_FindSet(name)
2369      char *name;
2370 {
2371     register struct afs_icl_set *tp;
2372
2373     for (tp = icl_allSets; tp; tp = tp->nextp) {
2374         if (strcmp(tp->name, name) == 0) {
2375             /* this is the dude we want */
2376             tp->refCount++;
2377             break;
2378         }
2379     }
2380     return tp;
2381 }
2382
2383 /* zero out all the logs in the set */
2384 icl_ZeroSet(setp)
2385      struct afs_icl_set *setp;
2386 {
2387     register int i;
2388     int code = 0;
2389     int tcode;
2390     struct afs_icl_log *logp;
2391
2392     for (i = 0; i < ICL_LOGSPERSET; i++) {
2393         logp = setp->logs[i];
2394         if (logp) {
2395             icl_LogHold(logp);
2396             tcode = icl_ZeroLog(logp);
2397             if (tcode != 0)
2398                 code = tcode;   /* save the last bad one */
2399             icl_LogRele(logp);
2400         }
2401     }
2402     return code;
2403 }
2404
2405 icl_EnumerateSets(aproc, arock)
2406      int (*aproc) ();
2407      char *arock;
2408 {
2409     register struct afs_icl_set *tp, *np;
2410     register afs_int32 code;
2411
2412     code = 0;
2413     for (tp = icl_allSets; tp; tp = np) {
2414         tp->refCount++;         /* hold this guy */
2415         code = (*aproc) (tp->name, arock, tp);
2416         np = tp->nextp;         /* tp may disappear next, but not np */
2417         if (--tp->refCount == 0 && (tp->states & ICL_SETF_DELETED))
2418             icl_ZapSet(tp);
2419         if (code)
2420             break;
2421     }
2422     return code;
2423 }
2424
2425 icl_AddLogToSet(setp, newlogp)
2426      struct afs_icl_set *setp;
2427      struct afs_icl_log *newlogp;
2428 {
2429     register int i;
2430     int code = -1;
2431     struct afs_icl_log *logp;
2432
2433     for (i = 0; i < ICL_LOGSPERSET; i++) {
2434         if (!setp->logs[i]) {
2435             setp->logs[i] = newlogp;
2436             code = i;
2437             icl_LogHold(newlogp);
2438             if (!(setp->states & ICL_SETF_FREED)) {
2439                 /* bump up the number of sets using the log */
2440                 icl_LogUse(newlogp);
2441             }
2442             break;
2443         }
2444     }
2445     return code;
2446 }
2447
2448 icl_SetSetStat(setp, op)
2449      struct afs_icl_set *setp;
2450      int op;
2451 {
2452     int i;
2453     afs_int32 code;
2454     struct afs_icl_log *logp;
2455
2456     switch (op) {
2457     case ICL_OP_SS_ACTIVATE:    /* activate a log */
2458         /*
2459          * If we are not already active, see if we have released
2460          * our demand that the log be allocated (FREED set).  If
2461          * we have, reassert our desire.
2462          */
2463         if (!(setp->states & ICL_SETF_ACTIVE)) {
2464             if (setp->states & ICL_SETF_FREED) {
2465                 /* have to reassert desire for logs */
2466                 for (i = 0; i < ICL_LOGSPERSET; i++) {
2467                     logp = setp->logs[i];
2468                     if (logp) {
2469                         icl_LogHold(logp);
2470                         icl_LogUse(logp);
2471                         icl_LogRele(logp);
2472                     }
2473                 }
2474                 setp->states &= ~ICL_SETF_FREED;
2475             }
2476             setp->states |= ICL_SETF_ACTIVE;
2477         }
2478         code = 0;
2479         break;
2480
2481     case ICL_OP_SS_DEACTIVATE:  /* deactivate a log */
2482         /* this doesn't require anything beyond clearing the ACTIVE flag */
2483         setp->states &= ~ICL_SETF_ACTIVE;
2484         code = 0;
2485         break;
2486
2487     case ICL_OP_SS_FREE:        /* deassert design for log */
2488         /* 
2489          * if we are already in this state, do nothing; otherwise
2490          * deassert desire for log
2491          */
2492         if (setp->states & ICL_SETF_ACTIVE)
2493             code = EINVAL;
2494         else {
2495             if (!(setp->states & ICL_SETF_FREED)) {
2496                 for (i = 0; i < ICL_LOGSPERSET; i++) {
2497                     logp = setp->logs[i];
2498                     if (logp) {
2499                         icl_LogHold(logp);
2500                         icl_LogFreeUse(logp);
2501                         icl_LogRele(logp);
2502                     }
2503                 }
2504                 setp->states |= ICL_SETF_FREED;
2505             }
2506             code = 0;
2507         }
2508         break;
2509
2510     default:
2511         code = EINVAL;
2512     }
2513
2514     return code;
2515 }
2516
2517 struct afs_icl_log *afs_icl_allLogs = 0;
2518
2519 /* hold and release logs */
2520 icl_LogHold(logp)
2521      register struct afs_icl_log *logp;
2522 {
2523     logp->refCount++;
2524     return 0;
2525 }
2526
2527 /* hold and release logs, called with lock already held */
2528 icl_LogHoldNL(logp)
2529      register struct afs_icl_log *logp;
2530 {
2531     logp->refCount++;
2532     return 0;
2533 }
2534
2535 /* keep track of how many sets believe the log itself is allocated */
2536 icl_LogUse(logp)
2537      register struct afs_icl_log *logp;
2538 {
2539     if (logp->setCount == 0) {
2540         /* this is the first set actually using the log -- allocate it */
2541         if (logp->logSize == 0) {
2542             /* we weren't passed in a hint and it wasn't set */
2543             logp->logSize = ICL_DEFAULT_LOGSIZE;
2544         }
2545         logp->datap =
2546             (afs_int32 *) osi_Alloc(sizeof(afs_int32) * logp->logSize);
2547     }
2548     logp->setCount++;
2549     return 0;
2550 }
2551
2552 /* decrement the number of real users of the log, free if possible */
2553 icl_LogFreeUse(logp)
2554      register struct afs_icl_log *logp;
2555 {
2556     if (--logp->setCount == 0) {
2557         /* no more users -- free it (but keep log structure around) */
2558         osi_Free(logp->datap, sizeof(afs_int32) * logp->logSize);
2559         logp->firstUsed = logp->firstFree = 0;
2560         logp->logElements = 0;
2561         logp->datap = NULL;
2562     }
2563     return 0;
2564 }
2565
2566 /* set the size of the log to 'logSize' */
2567 icl_LogSetSize(logp, logSize)
2568      register struct afs_icl_log *logp;
2569      afs_int32 logSize;
2570 {
2571     if (!logp->datap) {
2572         /* nothing to worry about since it's not allocated */
2573         logp->logSize = logSize;
2574     } else {
2575         /* reset log */
2576         logp->firstUsed = logp->firstFree = 0;
2577         logp->logElements = 0;
2578
2579         /* free and allocate a new one */
2580         osi_Free(logp->datap, sizeof(afs_int32) * logp->logSize);
2581         logp->datap = (afs_int32 *) osi_Alloc(sizeof(afs_int32) * logSize);
2582         logp->logSize = logSize;
2583     }
2584
2585     return 0;
2586 }
2587
2588 /* free a log.  Called with icl_lock locked. */
2589 icl_ZapLog(logp)
2590      register struct afs_icl_log *logp;
2591 {
2592     register struct afs_icl_log **lpp, *tp;
2593
2594     for (lpp = &afs_icl_allLogs, tp = *lpp; tp; lpp = &tp->nextp, tp = *lpp) {
2595         if (tp == logp) {
2596             /* found the dude we want to remove */
2597             *lpp = logp->nextp;
2598             osi_Free(logp->name, 1 + strlen(logp->name));
2599             osi_Free(logp->datap, logp->logSize * sizeof(afs_int32));
2600             osi_Free(logp, sizeof(struct icl_log));
2601             break;              /* won't find it twice */
2602         }
2603     }
2604     return 0;
2605 }
2606
2607 /* do the release, watching for deleted entries */
2608 icl_LogRele(logp)
2609      register struct afs_icl_log *logp;
2610 {
2611     if (--logp->refCount == 0 && (logp->states & ICL_LOGF_DELETED)) {
2612         icl_ZapLog(logp);       /* destroys logp's lock! */
2613     }
2614     return 0;
2615 }
2616
2617 /* do the release, watching for deleted entries, log already held */
2618 icl_LogReleNL(logp)
2619      register struct afs_icl_log *logp;
2620 {
2621     if (--logp->refCount == 0 && (logp->states & ICL_LOGF_DELETED)) {
2622         icl_ZapLog(logp);       /* destroys logp's lock! */
2623     }
2624     return 0;
2625 }
2626
2627 /* zero out the log */
2628 int
2629 icl_ZeroLog(register struct afs_icl_log *logp)
2630 {
2631     logp->firstUsed = logp->firstFree = 0;
2632     logp->logElements = 0;
2633     return 0;
2634 }
2635
2636 /* free a log entry, and drop its reference count */
2637 icl_LogFree(logp)
2638      register struct afs_icl_log *logp;
2639 {
2640     logp->states |= ICL_LOGF_DELETED;
2641     icl_LogRele(logp);
2642     return 0;
2643 }
2644
2645
2646 int
2647 icl_EnumerateLogs(int (*aproc)
2648                     (char *name, char *arock, struct afs_icl_log * tp),
2649                   char *arock)
2650 {
2651     register struct afs_icl_log *tp;
2652     register afs_int32 code;
2653
2654     code = 0;
2655     for (tp = afs_icl_allLogs; tp; tp = tp->nextp) {
2656         tp->refCount++;         /* hold this guy */
2657         code = (*aproc) (tp->name, arock, tp);
2658         if (--tp->refCount == 0)
2659             icl_ZapLog(tp);
2660         if (code)
2661             break;
2662     }
2663     return code;
2664 }
2665
2666
2667 afs_icl_bulkSetinfo_t *
2668 GetBulkSetInfo()
2669 {
2670     unsigned int infoSize;
2671
2672     infoSize =
2673         sizeof(afs_icl_bulkSetinfo_t) + (ICL_RPC_MAX_SETS -
2674                                          1) * sizeof(afs_icl_setinfo_t);
2675     if (!setInfo) {
2676         setInfo = (afs_icl_bulkSetinfo_t *) malloc(infoSize);
2677         if (!setInfo) {
2678             (void)fprintf(stderr,
2679                           "Could not allocate the memory for bulk set info structure\n");
2680             exit(1);
2681         }
2682     }
2683     memset((char *)setInfo, 0, infoSize);
2684
2685     return setInfo;
2686 }
2687
2688 afs_icl_bulkLoginfo_t *
2689 GetBulkLogInfo()
2690 {
2691     unsigned int infoSize;
2692
2693     infoSize =
2694         sizeof(afs_icl_bulkLoginfo_t) + (ICL_RPC_MAX_LOGS -
2695                                          1) * sizeof(afs_icl_loginfo_t);
2696     if (!logInfo) {
2697         logInfo = (afs_icl_bulkLoginfo_t *) malloc(infoSize);
2698         if (!logInfo) {
2699             (void)fprintf(stderr,
2700                           "Could not allocate the memory for bulk log info structure\n");
2701             exit(1);
2702         }
2703     }
2704
2705     memset((char *)logInfo, 0, infoSize);
2706     return logInfo;
2707 }
2708
2709
2710 static int
2711 DoDump(struct cmd_syndesc *as, void *arock)
2712 {
2713     afs_int32 code = 0;
2714     afs_int32 tcode;
2715     afs_int32 waitTime = 10 /* seconds */ ;
2716     int error = 0;
2717     char *logname;
2718     char *filename;
2719     FILE *outfp = stdout;
2720     time_t startTime;
2721     struct cmd_item *itemp;
2722
2723     if (geteuid() != 0) {
2724         printf("fstrace must be run as root\n");
2725         exit(1);
2726     }
2727
2728     if (as->parms[3].items) {
2729         if (!as->parms[1].items) {
2730             (void)fprintf(stderr, "-sleep can only be used with -follow\n");
2731             return 1;
2732         }
2733         waitTime = strtol(as->parms[3].items->data, NULL, 0);
2734     }
2735
2736     if (as->parms[2].items) {
2737         /* try to open the specified output file */
2738         if ((outfp = fopen(as->parms[2].items->data, "w")) == NULL) {
2739             (void)fprintf(stderr, "Cannot open file '%s' for writing\n",
2740                           as->parms[2].items->data);
2741             return 1;
2742         }
2743     }
2744 #ifdef AFS_SGI64_ENV
2745     startTime = time((time_t *) 0);
2746 #else
2747     startTime = time(0);
2748 #endif
2749     (void)fprintf(outfp, "AFS Trace Dump -\n\n   Date: %s\n",
2750                   ctime(&startTime));
2751
2752     if (as->parms[0].items) {
2753         for (itemp = as->parms[0].items; itemp; itemp = itemp->next) {
2754             tcode = icl_DumpKernel(outfp, itemp->data);
2755             if (tcode) {
2756                 (void)fprintf(stderr, "Unable to dump set %s (errno = %d)\n",
2757                               itemp->data, errno);
2758                 code = tcode;
2759             }
2760         }
2761     } else if (as->parms[1].items) {
2762         logname = as->parms[1].items->data;
2763         code = icl_TailKernel(outfp, logname, waitTime);
2764         if (code) {
2765             (void)fprintf(stderr,
2766                           "Error tailing kernel log '%s' (errno = %d)\n",
2767                           logname, errno);
2768         }
2769     } else
2770         code = icl_DumpKernel(outfp, NULL);
2771
2772     (void)fprintf(outfp, "\nAFS Trace Dump - %s\n",
2773                   code ? "FAILED" : "Completed");
2774
2775     if (outfp != stdout)
2776         (void)fclose(outfp);
2777
2778     return code;
2779 }
2780
2781 static void
2782 SetUpDump()
2783 {
2784     struct cmd_syndesc *dumpSyntax;
2785
2786     dumpSyntax =
2787         cmd_CreateSyntax("dump", DoDump, NULL, "dump AFS trace logs");
2788     (void)cmd_AddParm(dumpSyntax, "-set", CMD_LIST, CMD_OPTIONAL, "set_name");
2789     (void)cmd_AddParm(dumpSyntax, "-follow", CMD_SINGLE, CMD_OPTIONAL,
2790                       "log_name");
2791     (void)cmd_AddParm(dumpSyntax, "-file", CMD_SINGLE, CMD_OPTIONAL,
2792                       "output_filename");
2793     (void)cmd_AddParm(dumpSyntax, "-sleep", CMD_SINGLE, CMD_OPTIONAL,
2794                       "seconds_between_reads");
2795 }
2796
2797 static int
2798 DoShowLog(register struct cmd_syndesc *as, void *arock)
2799 {
2800     afs_int32 retVal = 0;
2801     afs_int32 code = 0;
2802     afs_int32 logSize;
2803     int allocated;
2804     int int32flg = 0;
2805     struct cmd_item *itemp;
2806
2807     if (geteuid() != 0) {
2808         printf("fstrace must be run as root\n");
2809         exit(1);
2810     }
2811     if (as->parms[2].items)
2812         int32flg = 1;
2813
2814     if (as->parms[0].items) {
2815         /* enumerate logs for the specified sets */
2816         for (itemp = as->parms[0].items; itemp; itemp = itemp->next) {
2817             (void)fprintf(stdout, "Logs for set '%s':\n", itemp->data);
2818             code = icl_ListLogsBySet(stdout, itemp->data, int32flg);
2819             if (code) {
2820                 (void)fprintf(stderr,
2821                               "Error in enumerating set %s (errno = %d)\n",
2822                               itemp->data, errno);
2823                 retVal = code;
2824             }
2825         }
2826     } else if (as->parms[1].items) {
2827         /* print out log information */
2828         for (itemp = as->parms[1].items; itemp; itemp = itemp->next) {
2829             code = icl_GetLogsize(itemp->data, &logSize, &allocated);
2830             if (!code)
2831                 (void)fprintf(stdout, "%s : %d kbytes (%s)\n", itemp->data,
2832                               logSize / 1024,
2833                               allocated ? "allocated" : "unallocated");
2834             else {
2835                 (void)fprintf(stderr,
2836                               "Could not find log '%s' (errno = %d)\n",
2837                               itemp->data, errno);
2838                 retVal = code;
2839             }
2840         }
2841     } else {
2842         /* show all logs */
2843         (void)fprintf(stdout, "Available logs:\n");
2844         code = icl_ListLogs(stdout, int32flg);
2845         if (code) {
2846             (void)fprintf(stderr, "Error in listing logs (errno = %d)\n",
2847                           errno);
2848             retVal = code;
2849         }
2850     }
2851
2852     return retVal;
2853 }
2854
2855 static void
2856 SetUpShowLog()
2857 {
2858     struct cmd_syndesc *showSyntax;
2859
2860     showSyntax =
2861         cmd_CreateSyntax("lslog", DoShowLog, NULL,
2862                          "list available logs");
2863     (void)cmd_AddParm(showSyntax, "-set", CMD_LIST, CMD_OPTIONAL, "set_name");
2864     (void)cmd_AddParm(showSyntax, "-log", CMD_LIST, CMD_OPTIONAL, "log_name");
2865     (void)cmd_AddParm(showSyntax, "-long", CMD_FLAG, CMD_OPTIONAL, "");
2866 }
2867
2868 static int
2869 DoShowSet(register struct cmd_syndesc *as, void *arock)
2870 {
2871     afs_int32 retVal = 0;
2872     afs_int32 code = 0;
2873     afs_int32 state;
2874     struct cmd_item *itemp;
2875
2876     if (geteuid() != 0) {
2877         printf("fstrace must be run as root\n");
2878         exit(1);
2879     }
2880     if (as->parms[0].items) {
2881         /* print information on the specified sets */
2882         for (itemp = as->parms[0].items; itemp; itemp = itemp->next) {
2883             code = icl_GetSetState(itemp->data, &state);
2884             if (code) {
2885                 (void)fprintf(stderr,
2886                               "Error getting status on set %s (errno = %d)\n",
2887                               itemp->data, errno);
2888                 retVal = code;
2889             } else
2890                 (void)fprintf(stdout, "Set %s: %s%s%s\n", itemp->data,
2891                               (state & ICL_SETF_ACTIVE) ? "active" :
2892                               "inactive",
2893                               (state & ICL_SETF_FREED) ? " (dormant)" : "",
2894                               (state & ICL_SETF_PERSISTENT) ? " persistent" :
2895                               "");
2896         }
2897     } else {
2898         /* show all sets */
2899         (void)fprintf(stdout, "Available sets:\n");
2900         code = icl_ListSets(stdout);
2901         if (code) {
2902             (void)fprintf(stderr, "Error in listing sets (errno = %d)\n",
2903                           errno);
2904             retVal = code;
2905         }
2906     }
2907
2908     return retVal;
2909 }
2910
2911 static void
2912 SetUpShowSet()
2913 {
2914     struct cmd_syndesc *showSyntax;
2915
2916     showSyntax =
2917         cmd_CreateSyntax("lsset", DoShowSet, NULL,
2918                          "list available event sets");
2919     (void)cmd_AddParm(showSyntax, "-set", CMD_LIST, CMD_OPTIONAL, "set_name");
2920 }
2921
2922 static int
2923 DoClear(register struct cmd_syndesc *as, void *arock)
2924 {
2925     afs_int32 retVal = 0;
2926     afs_int32 code = 0;
2927     struct cmd_item *itemp;
2928
2929     if (geteuid() != 0) {
2930         printf("fstrace must be run as root\n");
2931         exit(1);
2932     }
2933     if (as->parms[0].items) {
2934         /* clear logs for the specified sets */
2935         for (itemp = as->parms[0].items; itemp; itemp = itemp->next) {
2936             code = icl_ClearSet(itemp->data);
2937             if (code) {
2938                 (void)fprintf(stderr,
2939                               "Error in clearing set %s (errno = %d)\n",
2940                               itemp->data, errno);
2941                 retVal = code;
2942             }
2943         }
2944     } else if (as->parms[1].items) {
2945         /* clear specified log */
2946         for (itemp = as->parms[0].items; itemp; itemp = itemp->next) {
2947             code = icl_ClearLog(itemp->data);
2948             if (code) {
2949                 (void)fprintf(stderr,
2950                               "Error in clearing log %s (errno = %d)\n",
2951                               itemp->data, errno);
2952                 retVal = code;
2953             }
2954         }
2955     } else {
2956         /* clear all logs */
2957         code = icl_ClearAll();
2958         if (code) {
2959             (void)fprintf(stderr, "Error in clearing logs (errno = %d)\n",
2960                           errno);
2961             retVal = code;
2962         }
2963     }
2964
2965     return retVal;
2966 }
2967
2968 static void
2969 SetUpClear()
2970 {
2971     struct cmd_syndesc *clearSyntax;
2972
2973     clearSyntax =
2974         cmd_CreateSyntax("clear", DoClear, NULL,
2975                          "clear logs by logname or by event set");
2976     (void)cmd_AddParm(clearSyntax, "-set", CMD_LIST, CMD_OPTIONAL,
2977                       "set_name");
2978     (void)cmd_AddParm(clearSyntax, "-log", CMD_LIST, CMD_OPTIONAL,
2979                       "log_name");
2980 }
2981
2982 static int
2983 DoSet(register struct cmd_syndesc *as, void *arock)
2984 {
2985     afs_int32 retVal = 0;
2986     afs_int32 code = 0;
2987     int op;
2988     int doFree = 0;
2989     char *operation;
2990     struct cmd_item *itemp;
2991
2992     if (geteuid() != 0) {
2993         printf("fstrace must be run as root\n");
2994         exit(1);
2995     }
2996     if (as->parms[1].items) {
2997         op = ICL_OP_SS_ACTIVATE;
2998         operation = "active";
2999     } else if (as->parms[2].items) {
3000         op = ICL_OP_SS_DEACTIVATE;
3001         operation = "inactive";
3002     } else if (as->parms[3].items) {
3003         op = ICL_OP_SS_DEACTIVATE;
3004         operation = "inactive";
3005         doFree = 1;
3006     } else {
3007         /* assume active" */
3008         op = ICL_OP_SS_ACTIVATE;
3009         operation = "active";
3010     }
3011
3012     if (as->parms[0].items) {
3013         /* activate specified sets */
3014         for (itemp = as->parms[0].items; itemp; itemp = itemp->next) {
3015             code = icl_ChangeSetState(itemp->data, op);
3016             if (code) {
3017                 (void)fprintf(stderr,
3018                               "cannot set state of %s to %s (errno = %d)\n",
3019                               itemp->data, operation, errno);
3020                 retVal = code;
3021             } else if (doFree) {
3022                 /* try to make it dormant as well */
3023                 code = icl_ChangeSetState(itemp->data, ICL_OP_SS_FREE);
3024                 if (code) {
3025                     (void)fprintf(stderr,
3026                                   "cannot set state of %s to dormant (errno = %d)\n",
3027                                   itemp->data, errno);
3028                     retVal = code;
3029                 }
3030             }
3031         }
3032     } else {
3033         /* show all sets */
3034         code = icl_ChangeAllSetState(op);
3035         if (code) {
3036             (void)fprintf(stderr,
3037                           "cannot set the state of all sets to %s (errno = %d)\n",
3038                           operation, errno);
3039             retVal = code;
3040         } else if (doFree) {
3041             /* try to make it dormant as well */
3042             code = icl_ChangeAllSetState(ICL_OP_SS_FREE);
3043             if (code) {
3044                 (void)fprintf(stderr,
3045                               "cannot set the state of all sets to dormant (errno = %d)\n",
3046                               errno);
3047                 retVal = code;
3048             }
3049         }
3050     }
3051
3052     return retVal;
3053 }
3054
3055 static void
3056 SetUpSet()
3057 {
3058     struct cmd_syndesc *setSyntax;
3059
3060     setSyntax =
3061         cmd_CreateSyntax("setset", DoSet, NULL,
3062                          "set state of event sets");
3063     (void)cmd_AddParm(setSyntax, "-set", CMD_LIST, CMD_OPTIONAL, "set_name");
3064     (void)cmd_AddParm(setSyntax, "-active", CMD_FLAG, CMD_OPTIONAL, "");
3065     (void)cmd_AddParm(setSyntax, "-inactive", CMD_FLAG, CMD_OPTIONAL, "");
3066     (void)cmd_AddParm(setSyntax, "-dormant", CMD_FLAG, CMD_OPTIONAL, "");
3067 }
3068
3069 static int
3070 DoResize(register struct cmd_syndesc *as, void *arock)
3071 {
3072     afs_int32 retVal = 0;
3073     afs_int32 code = 0;
3074     afs_int32 bufferSize;
3075     struct cmd_item *itemp;
3076
3077     if (geteuid() != 0) {
3078         printf("fstrace must be run as root\n");
3079         exit(1);
3080     }
3081     /* get buffer size */
3082     bufferSize = atoi(as->parms[1].items->data);
3083     bufferSize *= BUFFER_MULTIPLIER;
3084     if (bufferSize == 0)
3085         bufferSize = ICL_DEFAULT_LOGSIZE;
3086
3087     /* set the size of the specified logs */
3088     if (itemp = as->parms[0].items) {
3089         for (; itemp; itemp = itemp->next) {
3090             code = icl_ChangeLogSize(itemp->data, bufferSize);
3091             if (code) {
3092                 (void)fprintf(stderr,
3093                               "Error in changing log %s buffer size (errno = %d)\n",
3094                               itemp->data, errno);
3095                 retVal = code;
3096             }
3097         }
3098     } else {
3099         /* Use the only current support log, "cmfx" */
3100         code = icl_ChangeLogSize("cmfx", bufferSize);
3101         if (code) {
3102             (void)fprintf(stderr,
3103                           "Error in changing log cmfx buffer size (errno = %d)\n",
3104                           errno);
3105             retVal = code;
3106         }
3107     }
3108
3109     return retVal;
3110 }
3111
3112 static void
3113 SetUpResize()
3114 {
3115     struct cmd_syndesc *setsizeSyntax;
3116
3117     setsizeSyntax =
3118         cmd_CreateSyntax("setlog", DoResize, NULL,
3119                          "set the size of a log");
3120     (void)cmd_AddParm(setsizeSyntax, "-log", CMD_LIST, CMD_OPTIONAL,
3121                       "log_name");
3122     (void)cmd_AddParm(setsizeSyntax, "-buffersize", CMD_SINGLE, CMD_REQUIRED,
3123                       "1-kilobyte_units");
3124 }
3125
3126 #include "AFS_component_version_number.c"
3127
3128 main(argc, argv)
3129      IN int argc;
3130      IN char *argv[];
3131 {
3132     setlocale(LC_ALL, "");
3133 #ifdef AFS_SGI62_ENV
3134     set_kernel_sizeof_long();
3135 #endif
3136
3137     /* set up user interface then dispatch */
3138     SetUpDump();
3139     SetUpShowLog();
3140     SetUpShowSet();
3141     SetUpClear();
3142     SetUpSet();
3143     SetUpResize();
3144
3145     return (cmd_Dispatch(argc, argv));
3146 }
3147 #else
3148 #include "AFS_component_version_number.c"
3149
3150 main()
3151 {
3152     printf("fstrace is NOT supported for this OS\n");
3153 }
3154 #endif