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