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