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