linux-and-64bit-cleanup-20050710
[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 #if defined(AFS_64BITPOINTER_ENV)
1495     long J;
1496 #else
1497     int J;
1498 #endif
1499     static char *facility_names[] = {
1500         "xxx",
1501         "afs"
1502     };
1503
1504     /*
1505      * set up output status for future error returns
1506      */
1507     if (status != NULL) {
1508         *status = -1;
1509     }
1510     /*
1511      * check for ok input status
1512      */
1513     if (status_to_convert == 0) {
1514         if (status != NULL) {
1515             *status = 0;
1516         }
1517         strcpy((char *)error_text, "successful completion");
1518         return;
1519     }
1520
1521     /*
1522      * extract the component, facility and status codes
1523      */
1524     facility_code =
1525         (status_to_convert & FACILITY_CODE_MASK) >> FACILITY_CODE_SHIFT;
1526     component_code =
1527         (status_to_convert & COMPONENT_CODE_MASK) >> COMPONENT_CODE_SHIFT;
1528     status_code = (status_to_convert & STATUS_CODE_MASK) >> STATUS_CODE_SHIFT;
1529
1530     /*
1531      * see if this is a recognized facility
1532      */
1533     if (facility_code == 0
1534         || facility_code > sizeof(facility_names) / sizeof(char *)) {
1535         sprintf((char *)error_text, "status %08x (unknown facility)",
1536                 status_to_convert);
1537         return;
1538     }
1539     facility_name = facility_names[facility_code - 1];
1540     /*
1541      * Convert component name from RAD-50 component code.  (Mapping is:
1542      * 0 => 'a', ..., 25 => 'z', 26 => '{', 27 => '0', ..., 36 => '9'.)
1543      */
1544     component_name[3] = 0;
1545     component_name[2] = component_code % 40;
1546     component_code /= 40;
1547     component_name[1] = component_code % 40;
1548     component_name[0] = component_code / 40;
1549     for (i = 0; i < 3; i++) {
1550         component_name[i] += (component_name[i] <= 26) ? 'a' : ('0' - 27);
1551     }
1552     sprintf(filename_prefix, "%3s%3s", facility_name, component_name);
1553     sprintf(nls_filename, RPC_NLS_FORMAT, filename_prefix);
1554
1555     /*
1556      * Open the message file
1557      */
1558 #if     defined(AFS_OSF_ENV)
1559 #if     defined(AFS_OSF20_ENV)
1560     catd = (nl_catd) catopen(nls_filename, 0);
1561 #else
1562     catd = (nl_catd) catopen1(nls_filename, 0);
1563 #endif
1564 #else
1565 #if defined(AFS_64BITPOINTER_ENV)
1566     J = (long)catopen(nls_filename, 0);
1567 #else
1568     J = (int)catopen(nls_filename, 0);
1569 #endif
1570     catd = (nl_catd) J;
1571 #endif
1572     if (catd == (nl_catd) - 1) {
1573         /*
1574          * If we did not succeed in opening message file using NLSPATH,
1575          * try to open the message file in a well-known default area
1576          */
1577       tryagain:
1578 #ifndef RPC_DEFAULT_NLSPATH
1579         sprintf(alt_filename, "%s/C/%s.cat", AFSDIR_CLIENT_ETC_DIRPATH,
1580                 filename_prefix);
1581 #else
1582         sprintf(alt_filename, RPC_DEFAULT_NLSPATH, filename_prefix);
1583 #endif
1584
1585 #if     defined(AFS_OSF_ENV)
1586 #if     defined(AFS_OSF20_ENV)
1587         catd = (nl_catd) catopen(alt_filename, 0);
1588 #else
1589         catd = (nl_catd) catopen1(alt_filename, 0);
1590 #endif
1591 #else
1592 #if defined(AFS_64BITPOINTER_ENV)
1593         J = (long)catopen(alt_filename, 0);
1594 #else
1595         J = (int)catopen(alt_filename, 0);
1596 #endif
1597         catd = (nl_catd) J;
1598 #endif
1599         if (catd == (nl_catd) - 1) {
1600             sprintf((char *)error_text, "status %08x (%s / %s)",
1601                     status_to_convert, facility_name, component_name);
1602             return;
1603         }
1604     }
1605     /*
1606      * try to get the specified message from the file
1607      */
1608 #if     defined(AFS_OSF_ENV) && !defined(AFS_OSF20_ENV)
1609     message = (char *)catgets1(catd, 1, status_code, NO_MESSAGE);
1610 #else
1611     message = (char *)catgets(catd, 1, status_code, NO_MESSAGE);
1612 #endif
1613     /*
1614      * if everything went well, return the resulting message
1615      */
1616     if (strcmp(message, NO_MESSAGE) != 0) {
1617         sprintf((char *)error_text, "%s (%s / %s)", message, facility_name,
1618                 component_name);
1619         if (status != NULL) {
1620             *status = 0;
1621         }
1622     } else {
1623         if (!failed) {
1624             failed = 1;
1625 #if defined(AFS_OSF_ENV) && !defined(AFS_OSF20_ENV)
1626             catclose1(catd);
1627 #else
1628             catclose(catd);
1629 #endif
1630             goto tryagain;
1631         }
1632         sprintf((char *)error_text, "status %08x (%s / %s)",
1633                 status_to_convert, facility_name, component_name);
1634     }
1635 #if     defined(AFS_OSF_ENV) && !defined(AFS_OSF20_ENV)
1636     catclose1(catd);
1637 #else
1638     catclose(catd);
1639 #endif
1640
1641 }
1642
1643
1644 icl_DumpKernel(outFilep, setname)
1645      FILE *outFilep;
1646      char *setname;
1647 {
1648     afs_int32 bufferSize = 0;
1649     afs_int32 *bufferp;
1650     afs_int32 i;
1651     afs_int32 code, retVal = 0;
1652     char tname[64];
1653     afs_int32 nwords;
1654     afs_int32 ix;
1655     afs_int32 rlength;
1656     afs_int32 dummy, dummy2;
1657     struct logInfo *lip;
1658
1659     /* first, enumerate the logs we're interested in */
1660     if (setname) {
1661         int found = 0;
1662         /* dump logs for a particular set */
1663         for (i = 0; i < ICL_LOGSPERSET; i++) {
1664             code =
1665                 afs_syscall(AFSCALL_ICL, ICL_OP_ENUMLOGSBYSET, (long)setname,
1666                             i, (long)tname, sizeof(tname));
1667             if (code) {
1668                 if (errno == EBADF) {
1669                     code = 0;
1670                     continue;   /* missing slot, nothing to worry about */
1671                 }
1672                 break;
1673             }
1674             code =
1675                 afs_syscall(AFSCALL_ICL, ICL_OP_GETLOGINFO, (long)tname,
1676                             (long)&dummy, (long)&dummy2, 0);
1677             if (code)
1678                 break;
1679             found++;
1680             if (dummy > bufferSize)     /* find biggest log */
1681                 bufferSize = dummy;
1682             lip = (struct logInfo *)malloc(sizeof(struct logInfo));
1683             memset((char *)lip, 0, sizeof(*lip));
1684             lip->nextp = allInfo;
1685             allInfo = lip;
1686             lip->name = (char *)malloc(strlen(tname) + 1);
1687             strcpy(lip->name, tname);
1688         }
1689         i = found;
1690     } else {
1691         /* dump all logs */
1692         for (i = 0; i < 1000; i++) {
1693             code =
1694                 afs_syscall(AFSCALL_ICL, ICL_OP_ENUMLOGS, i, (long)tname,
1695                             sizeof(tname), (long)&dummy);
1696             if (code)
1697                 break;
1698             if (dummy > bufferSize)     /* find biggest log */
1699                 bufferSize = dummy;
1700             lip = (struct logInfo *)malloc(sizeof(struct logInfo));
1701             memset((char *)lip, 0, sizeof(*lip));
1702             lip->nextp = allInfo;
1703             allInfo = lip;
1704             lip->name = (char *)malloc(strlen(tname) + 1);
1705             strcpy(lip->name, tname);
1706         }
1707     }
1708
1709     if (bufferSize == 0)
1710         return -1;
1711     bufferp = (afs_int32 *) malloc(sizeof(afs_int32) * bufferSize);
1712     if (!bufferp)
1713         return -1;
1714
1715     fprintf(outFilep, "Found %d logs.\n", i);
1716
1717     /* now print out the contents of each log */
1718     for (lip = allInfo; lip; lip = lip->nextp) {
1719         fprintf(outFilep, "\nContents of log %s:\n", lip->name);
1720         /* read out everything first; gets a more consistent
1721          * snapshot.
1722          */
1723         nwords = 0;             /* total words copied out */
1724         for (i = 0;;) {
1725             /* display all the entries in the log */
1726             if (bufferSize - nwords <= 0)
1727                 break;          /* filled whole buffer */
1728             code =
1729                 afs_syscall(AFSCALL_ICL, ICL_OP_COPYOUT, (long)lip->name,
1730                             (long)(bufferp + nwords), bufferSize - nwords,
1731                             (long)&i);
1732             if (code < 0) {
1733                 /* otherwise we've got an error */
1734                 fprintf(outFilep, "Returned error %d dumping log.\n", errno);
1735                 break;
1736             }
1737             /* otherwise, we have flags in the high order byte, and
1738              * a length (in words) in the remainder.
1739              */
1740             if ((code >> 24) & ICL_COPYOUTF_MISSEDSOME)
1741                 fprintf(outFilep, "Log wrapped; data missing.\n");
1742             code &= 0xffffff;
1743             if (code == 0) {
1744                 /* we're done */
1745                 break;
1746             }
1747             nwords += code;
1748             i += code;
1749         }                       /* for loop over all cookies */
1750
1751         /* otherwise we should display all of the log entries here.
1752          * Note that a record may end in the middle, in which case
1753          * we should start over with the cookie value of the start
1754          * of that record.
1755          */
1756         for (ix = 0; ix < nwords;) {
1757             /* start of a record */
1758             rlength = (bufferp[ix] >> 24) & 0xff;
1759             if (rlength <= 0) {
1760                 fprintf(outFilep, "Internal error: 0 length record\n");
1761                 retVal = -1;
1762                 goto done;
1763             }
1764             /* ensure that entire record fits */
1765             if (ix + rlength > nwords) {
1766                 /* doesn't fit, adjust cookie and break */
1767                 break;
1768             }
1769             /* print the record */
1770             DisplayRecord(outFilep, &bufferp[ix], rlength);
1771             ix += rlength;
1772 #ifdef notdef
1773             /* obsolete: read entire buffer first */
1774             i += rlength;       /* update cookie value, too */
1775 #endif
1776         }                       /* for loop displaying buffer */
1777     }                           /* for loop over all logs */
1778
1779   done:
1780     free(bufferp);
1781     return (retVal);
1782 }
1783
1784 /* clear out log 'name' */
1785 icl_ClearLog(name)
1786      char *name;
1787 {
1788     afs_int32 code;
1789
1790     code = afs_syscall(AFSCALL_ICL, ICL_OP_CLRLOG, (long)name, 0, 0, 0);
1791     return code;
1792 }
1793
1794 /* clear out set 'name' */
1795 icl_ClearSet(name)
1796      char *name;
1797 {
1798     afs_int32 code;
1799
1800     code = afs_syscall(AFSCALL_ICL, ICL_OP_CLRSET, (long)name, 0, 0, 0);
1801     return code;
1802 }
1803
1804 /* clear out all logs */
1805 icl_ClearAll()
1806 {
1807     afs_int32 code;
1808
1809     code = afs_syscall(AFSCALL_ICL, ICL_OP_CLRALL, 0, 0, 0, 0);
1810     return code;
1811 }
1812
1813 /* list out all available sets to outFileP */
1814 int
1815 icl_ListSets(outFileP)
1816      FILE *outFileP;
1817 {
1818     int i;
1819     afs_int32 code = 0;
1820     afs_int32 states;
1821     char tname[64];
1822
1823     for (i = 0; i < 1000; i++) {
1824         code =
1825             afs_syscall(AFSCALL_ICL, ICL_OP_ENUMSETS, i, (long)tname,
1826                         sizeof(tname), (long)&states);
1827         if (code)
1828             break;
1829         (void)fprintf(outFileP, "%s %s%s%s\n", tname,
1830                       (states & ICL_SETF_ACTIVE) ? "active" : "inactive",
1831                       (states & ICL_SETF_FREED) ? " (dormant)" : "",
1832                       (states & ICL_SETF_PERSISTENT) ? " persistent" : "");
1833     }
1834
1835     return 0;
1836 }
1837
1838 /* list out all available logs to outFileP */
1839 int
1840 icl_ListLogs(outFileP, int32flg)
1841      FILE *outFileP;
1842      int int32flg;
1843 {
1844     int i;
1845     int allocated;
1846     afs_int32 code = 0;
1847     afs_int32 logSize;
1848     char tname[64];
1849
1850     for (i = 0; i < 1000; i++) {
1851         code =
1852             afs_syscall(AFSCALL_ICL, ICL_OP_ENUMLOGS, i, (long)tname,
1853                         sizeof(tname), (long)&logSize);
1854         if (code)
1855             break;
1856         if (int32flg) {
1857             /* get more information on the log */
1858             code =
1859                 afs_syscall(AFSCALL_ICL, ICL_OP_GETLOGINFO, (long)tname,
1860                             (long)&logSize, (long)&allocated, 0);
1861             if (code)
1862                 break;
1863             (void)fprintf(outFileP, "%s : %d kbytes (%s)\n", tname,
1864                           logSize / 1024,
1865                           allocated ? "allocated" : "unallocated");
1866         } else
1867             (void)fprintf(outFileP, "%s\n", tname);
1868     }
1869
1870     return 0;
1871 }
1872
1873 /* list out all available logs to outFileP */
1874 int
1875 icl_ListLogsBySet(outFileP, setname, int32flg)
1876      FILE *outFileP;
1877      char *setname;
1878      int int32flg;
1879 {
1880     int i;
1881     afs_int32 code = 0;
1882     afs_int32 logSize;
1883     int allocated;
1884     char tname[64];
1885
1886     for (i = 0; i < ICL_LOGSPERSET; i++) {
1887         code =
1888             afs_syscall(AFSCALL_ICL, ICL_OP_ENUMLOGSBYSET, (long)setname, i,
1889                         (long)tname, sizeof(tname));
1890         if (code) {
1891             if (errno == EBADF) {
1892                 code = 0;
1893                 continue;       /* missing */
1894             }
1895             break;
1896         }
1897         if (int32flg) {
1898             /* get more information on the log */
1899             code =
1900                 afs_syscall(AFSCALL_ICL, ICL_OP_GETLOGINFO, (long)tname,
1901                             (long)&logSize, (long)&allocated, 0);
1902             if (code)
1903                 break;
1904             (void)fprintf(outFileP, "%s : %d kbytes (%s)\n", tname,
1905                           logSize / 1024,
1906                           allocated ? "allocated" : "unallocated");
1907         } else
1908             (void)fprintf(outFileP, "%s\n", tname);
1909     }
1910
1911     return code;
1912 }
1913
1914 /* activate/deactivate/free specified set */
1915 int
1916 icl_ChangeSetState(name, op)
1917      char *name;
1918      afs_int32 op;
1919 {
1920     afs_int32 code;
1921
1922     code = afs_syscall(AFSCALL_ICL, ICL_OP_SETSTAT, (long)name, op, 0, 0);
1923     return code;
1924 }
1925
1926 /* activate/deactivate/free all sets */
1927 int
1928 icl_ChangeAllSetState(op)
1929      afs_int32 op;
1930 {
1931     afs_int32 code;
1932
1933     code = afs_syscall(AFSCALL_ICL, ICL_OP_SETSTATALL, op, 0, 0, 0);
1934     return code;
1935 }
1936
1937 /* set size if log */
1938 int
1939 icl_ChangeLogSize(name, logSize)
1940      char *name;
1941      afs_int32 logSize;
1942 {
1943     afs_int32 code;
1944
1945     code =
1946         afs_syscall(AFSCALL_ICL, ICL_OP_SETLOGSIZE, (long)name, logSize, 0,
1947                     0);
1948     return code;
1949 }
1950
1951 /* get logsize of specified log */
1952 int
1953 icl_GetLogsize(logname, logSizeP, allocatedP)
1954      char *logname;
1955      afs_int32 *logSizeP;
1956      int *allocatedP;
1957 {
1958     afs_int32 code;
1959     code =
1960         afs_syscall(AFSCALL_ICL, ICL_OP_GETLOGINFO, (long)logname,
1961                     (long)logSizeP, (long)allocatedP, 0);
1962     return code;
1963 }
1964
1965 /* get state of specified set */
1966 int
1967 icl_GetSetState(setname, stateP)
1968      char *setname;
1969      afs_int32 *stateP;
1970 {
1971     afs_int32 code;
1972     code =
1973         afs_syscall(AFSCALL_ICL, ICL_OP_GETSETINFO, (long)setname,
1974                     (long)stateP, 0, 0);
1975     return code;
1976 }
1977
1978 icl_TailKernel(outFilep, logname, waitTime)
1979      FILE *outFilep;
1980      char *logname;
1981      afs_int32 waitTime;
1982 {
1983     afs_int32 bufferSize = 0;
1984     afs_int32 newBufferSize;
1985     afs_int32 *bufferp;
1986     afs_int32 i;
1987     afs_int32 code, retVal = 0;
1988     afs_int32 nwords;
1989     afs_int32 ix;
1990     afs_int32 rlength;
1991     int allocated;
1992     struct logInfo *lip;
1993
1994     /* get information about the specified log */
1995     code =
1996         afs_syscall(AFSCALL_ICL, ICL_OP_GETLOGINFO, (long)logname,
1997                     (long)&bufferSize, (long)&allocated, 0);
1998     if (code) {
1999         if (errno == ENOENT)
2000             (void)fprintf(stderr, "'%s' not found\n", logname);
2001         else
2002             (void)fprintf(stderr,
2003                           "cannot get information on log '%s' (errno = %d)\n",
2004                           logname, errno);
2005         return -1;
2006     }
2007
2008     if (!allocated) {
2009         (void)fprintf(stderr, "'%s' not allocated\n", logname);
2010         return 0;
2011     }
2012
2013     if (bufferSize == 0)
2014         return -1;
2015     bufferp = (afs_int32 *) malloc(sizeof(afs_int32) * bufferSize);
2016     if (!bufferp) {
2017         (void)fprintf(stderr, "cannot allocate %d words for buffer\n",
2018                       bufferSize);
2019         return -1;
2020     }
2021
2022     /* start "infinite" loop */
2023     for (;;) {
2024         /* read out all that's currently there */
2025         nwords = 0;             /* total words copied out */
2026         i = 0;                  /* initialize cookie */
2027         for (;;) {
2028             /* display all the entries in the log */
2029             if (bufferSize - nwords <= 0)
2030                 break;          /* filled whole buffer, clear when done */
2031             code =
2032                 afs_syscall(AFSCALL_ICL, ICL_OP_COPYOUTCLR, (long)logname,
2033                             (long)(bufferp + nwords), bufferSize - nwords,
2034                             (long)&i);
2035             if (code < 0) {
2036                 /* otherwise we've got an error */
2037                 fprintf(stderr, "returned error %d dumping log.\n", errno);
2038                 retVal = -1;
2039                 goto tail_done;
2040             }
2041             /* otherwise, we have flags in the high order byte, and
2042              * a length (in words) in the remainder.
2043              */
2044             code &= 0xffffff;
2045             if (code == 0) {
2046                 /* we're done */
2047                 break;
2048             }
2049             nwords += code;
2050             i += code;
2051         }                       /* for loop over all cookies */
2052
2053         /* otherwise we should display all of the log entries here.
2054          * Note that a record may end in the middle, in which case
2055          * we should start over with the cookie value of the start
2056          * of that record.
2057          */
2058         for (ix = 0; ix < nwords;) {
2059             /* start of a record */
2060             rlength = (bufferp[ix] >> 24) & 0xff;
2061             /* ensure that entire record fits */
2062             if (ix + rlength > nwords) {
2063                 /* doesn't fit, adjust cookie and break */
2064                 if (rlength <= 0) {
2065                     fprintf(stderr, "BOGUS: 0 length record\n");
2066                     retVal = -1;
2067                     goto tail_done;
2068                 }
2069                 break;
2070             }
2071             /* print the record */
2072             DisplayRecord(outFilep, &bufferp[ix], rlength);
2073             ix += rlength;
2074         }                       /* for loop displaying buffer */
2075
2076         if (waitTime)
2077             sleep(waitTime);
2078
2079         /* see if things have changed */
2080         code =
2081             afs_syscall(AFSCALL_ICL, ICL_OP_GETLOGINFO, (long)logname,
2082                         (long)&newBufferSize, (long)&allocated, 0);
2083         if (code) {
2084             if (errno == ENOENT)
2085                 (void)fprintf(stderr, "'%s' not found\n", logname);
2086             else
2087                 (void)fprintf(stderr,
2088                               "cannot get information on log '%s' (errno = %d)\n",
2089                               logname, errno);
2090             retVal = -1;
2091             goto tail_done;
2092         }
2093
2094         if (!allocated) {
2095             (void)fprintf(stderr, "'%s' no int32er allocated\n", logname);
2096             retVal = -1;
2097             goto tail_done;
2098         }
2099
2100         if (bufferSize == 0) {
2101             (void)fprintf(stderr, "buffer size has become 0\n");
2102             retVal = -1;
2103             goto tail_done;
2104         }
2105         if (bufferSize != newBufferSize) {
2106             /* have to reallocate a buffer */
2107             bufferSize = newBufferSize;
2108             free(bufferp);
2109             bufferp = (afs_int32 *) malloc(sizeof(afs_int32) * bufferSize);
2110             if (!bufferp) {
2111                 (void)fprintf(stderr, "cannot allocate %d words for buffer\n",
2112                               bufferSize);
2113                 retVal = -1;
2114                 goto tail_done;
2115             }
2116         }
2117     }                           /* infinite loop */
2118
2119   tail_done:
2120     free(bufferp);
2121     return (retVal);
2122 }
2123
2124 #if !defined(AFS_SGI_ENV)
2125 afs_syscall(call, parm0, parm1, parm2, parm3, parm4, parm5, parm6)
2126      long call, parm0, parm1, parm2, parm3, parm4, parm5, parm6;
2127 {
2128     int code, rval;
2129 #ifdef AFS_LINUX20_ENV
2130 #if defined AFS_LINUX_64BIT_KERNEL
2131     long long eparm[4];
2132     /* don't want to sign extend it to 64bit, so using ulong */
2133     eparm[0] = (unsigned long)parm3;
2134     eparm[1] = (unsigned long)parm4;
2135     eparm[2] = (unsigned long)parm5;
2136     eparm[3] = (unsigned long)parm6;
2137 #else
2138     int eparm[4];
2139     eparm[0] = parm3;
2140     eparm[1] = parm4;
2141     eparm[2] = parm5;
2142     eparm[3] = parm6;
2143 #endif
2144     /* Linux can only handle 5 arguments in the actual syscall. */
2145     if (call == AFSCALL_ICL) {
2146         rval = proc_afs_syscall(call, parm0, parm1, parm2, eparm, &code);
2147         if (rval)
2148             code = syscall(AFS_SYSCALL, call, parm0, parm1, parm2, eparm);
2149     } else {
2150         rval = proc_afs_syscall(call, parm0, parm1, parm2, parm3, &code);
2151         if (rval)
2152             code = syscall(AFS_SYSCALL, call, parm0, parm1, parm2, parm3);
2153     }
2154 #if defined(AFS_SPARC64_LINUX20_ENV) || defined(AFS_SPARC_LINUX20_ENV)
2155     /* on sparc this function returns none value, so do it myself */
2156     __asm__ __volatile__("mov   %o0, %i0; ret; restore");
2157 #endif
2158 #else
2159 #if !defined(AFS_SGI_ENV) && !defined(AFS_AIX32_ENV)
2160     code = syscall(AFS_SYSCALL, call, parm0, parm1, parm2, parm3, parm4);
2161 #else
2162 #if defined(AFS_SGI_ENV)
2163     code = syscall(AFS_ICL, call, parm0, parm1, parm2, parm3, parm4);   /* XXX */
2164 #else
2165     code = syscall(AFSCALL_ICL, parm0, parm1, parm2, parm3, parm4);
2166 #endif
2167 #endif
2168 #endif /* AFS_LINUX20_ENV */
2169     return code;
2170 }
2171 #endif
2172
2173
2174 int icl_inited = 0;
2175
2176 /* init function, called once, under icl_lock */
2177 icl_Init()
2178 {
2179     icl_inited = 1;
2180
2181 #ifndef KERNEL
2182     /* setup signal handler, in user space */
2183 #endif /* KERNEL */
2184
2185     return 0;
2186 }
2187
2188 icl_CreateSet(name, baseLogp, fatalLogp, outSetpp)
2189      char *name;
2190      struct afs_icl_log *baseLogp;
2191      struct afs_icl_log *fatalLogp;
2192      struct afs_icl_set **outSetpp;
2193 {
2194     return icl_CreateSetWithFlags(name, baseLogp, fatalLogp, /*flags */ 0,
2195                                   outSetpp);
2196 }
2197
2198 /* create a set, given pointers to base and fatal logs, if any.
2199  * Logs are unlocked, but referenced, and *outSetpp is returned
2200  * referenced.  Function bumps reference count on logs, since it
2201  * addds references from the new icl_set.  When the set is destroyed,
2202  * those references will be released.
2203  */
2204 icl_CreateSetWithFlags(name, baseLogp, fatalLogp, flags, outSetpp)
2205      char *name;
2206      struct afs_icl_log *baseLogp;
2207      struct afs_icl_log *fatalLogp;
2208      afs_uint32 flags;
2209      struct afs_icl_set **outSetpp;
2210 {
2211     register struct afs_icl_set *setp;
2212     register int i;
2213     afs_int32 states = ICL_DEFAULT_SET_STATES;
2214
2215     if (!icl_inited)
2216         icl_Init();
2217
2218     for (setp = icl_allSets; setp; setp = setp->nextp) {
2219         if (strcmp(setp->name, name) == 0) {
2220             setp->refCount++;
2221             *outSetpp = setp;
2222             if (flags & ICL_CRSET_FLAG_PERSISTENT) {
2223                 setp->states |= ICL_SETF_PERSISTENT;
2224             }
2225             return 0;
2226         }
2227     }
2228
2229     /* determine initial state */
2230     if (flags & ICL_CRSET_FLAG_DEFAULT_ON)
2231         states = ICL_SETF_ACTIVE;
2232     else if (flags & ICL_CRSET_FLAG_DEFAULT_OFF)
2233         states = ICL_SETF_FREED;
2234     if (flags & ICL_CRSET_FLAG_PERSISTENT)
2235         states |= ICL_SETF_PERSISTENT;
2236
2237     setp = (struct afs_icl_set *)osi_Alloc(sizeof(struct afs_icl_set));
2238     memset((caddr_t) setp, 0, sizeof(*setp));
2239     setp->refCount = 1;
2240     if (states & ICL_SETF_FREED)
2241         states &= ~ICL_SETF_ACTIVE;     /* if freed, can't be active */
2242     setp->states = states;
2243
2244     setp->name = (char *)osi_Alloc(strlen(name) + 1);
2245     strcpy(setp->name, name);
2246     setp->nevents = ICL_DEFAULTEVENTS;
2247     setp->eventFlags = (char *)osi_Alloc(ICL_DEFAULTEVENTS);
2248     for (i = 0; i < ICL_DEFAULTEVENTS; i++)
2249         setp->eventFlags[i] = 0xff;     /* default to enabled */
2250
2251     /* update this global info under the icl_lock */
2252     setp->nextp = icl_allSets;
2253     icl_allSets = setp;
2254
2255     /* set's basic lock is still held, so we can finish init */
2256     if (baseLogp) {
2257         setp->logs[0] = baseLogp;
2258         icl_LogHold(baseLogp);
2259         if (!(setp->states & ICL_SETF_FREED))
2260             icl_LogUse(baseLogp);       /* log is actually being used */
2261     }
2262     if (fatalLogp) {
2263         setp->logs[1] = fatalLogp;
2264         icl_LogHold(fatalLogp);
2265         if (!(setp->states & ICL_SETF_FREED))
2266             icl_LogUse(fatalLogp);      /* log is actually being used */
2267     }
2268
2269     *outSetpp = setp;
2270     return 0;
2271 }
2272
2273 /* function to change event enabling information for a particular set */
2274 icl_SetEnable(setp, eventID, setValue)
2275      struct afs_icl_set *setp;
2276      afs_int32 eventID;
2277      int setValue;
2278 {
2279     char *tp;
2280
2281     if (!ICL_EVENTOK(setp, eventID)) {
2282         return -1;
2283     }
2284     tp = &setp->eventFlags[ICL_EVENTBYTE(eventID)];
2285     if (setValue)
2286         *tp |= ICL_EVENTMASK(eventID);
2287     else
2288         *tp &= ~(ICL_EVENTMASK(eventID));
2289     return 0;
2290 }
2291
2292 /* return indication of whether a particular event ID is enabled
2293  * for tracing.  If *getValuep is set to 0, the event is disabled,
2294  * otherwise it is enabled.  All events start out enabled by default.
2295  */
2296 icl_GetEnable(setp, eventID, getValuep)
2297      struct afs_icl_set *setp;
2298      afs_int32 eventID;
2299      int *getValuep;
2300 {
2301     if (!ICL_EVENTOK(setp, eventID)) {
2302         return -1;
2303     }
2304     if (setp->eventFlags[ICL_EVENTBYTE(eventID)] & ICL_EVENTMASK(eventID))
2305         *getValuep = 1;
2306     else
2307         *getValuep = 0;
2308     return 0;
2309 }
2310
2311 /* hold and release event sets */
2312 icl_SetHold(setp)
2313      register struct afs_icl_set *setp;
2314 {
2315     setp->refCount++;
2316     return 0;
2317 }
2318
2319 /* free a set.  Called with icl_lock locked */
2320 icl_ZapSet(setp)
2321      register struct afs_icl_set *setp;
2322 {
2323     register struct afs_icl_set **lpp, *tp;
2324     int i;
2325     register struct afs_icl_log *tlp;
2326
2327     for (lpp = &icl_allSets, tp = *lpp; tp; lpp = &tp->nextp, tp = *lpp) {
2328         if (tp == setp) {
2329             /* found the dude we want to remove */
2330             *lpp = setp->nextp;
2331             osi_Free(setp->name, 1 + strlen(setp->name));
2332             osi_Free(setp->eventFlags, ICL_EVENTBYTES(setp->nevents));
2333             for (i = 0; i < ICL_LOGSPERSET; i++) {
2334                 if (tlp = setp->logs[i])
2335                     icl_LogReleNL(tlp);
2336             }
2337             osi_Free(setp, sizeof(struct afs_icl_set));
2338             break;              /* won't find it twice */
2339         }
2340     }
2341     return 0;
2342 }
2343
2344 /* do the release, watching for deleted entries */
2345 icl_SetRele(setp)
2346      register struct afs_icl_set *setp;
2347 {
2348     if (--setp->refCount == 0 && (setp->states & ICL_SETF_DELETED)) {
2349         icl_ZapSet(setp);       /* destroys setp's lock! */
2350     }
2351     return 0;
2352 }
2353
2354 /* free a set entry, dropping its reference count */
2355 icl_SetFree(setp)
2356      register struct afs_icl_set *setp;
2357 {
2358     setp->states |= ICL_SETF_DELETED;
2359     icl_SetRele(setp);
2360     return 0;
2361 }
2362
2363 /* find a set by name, returning it held */
2364 struct afs_icl_set *
2365 icl_FindSet(name)
2366      char *name;
2367 {
2368     register struct afs_icl_set *tp;
2369
2370     for (tp = icl_allSets; tp; tp = tp->nextp) {
2371         if (strcmp(tp->name, name) == 0) {
2372             /* this is the dude we want */
2373             tp->refCount++;
2374             break;
2375         }
2376     }
2377     return tp;
2378 }
2379
2380 /* zero out all the logs in the set */
2381 icl_ZeroSet(setp)
2382      struct afs_icl_set *setp;
2383 {
2384     register int i;
2385     int code = 0;
2386     int tcode;
2387     struct afs_icl_log *logp;
2388
2389     for (i = 0; i < ICL_LOGSPERSET; i++) {
2390         logp = setp->logs[i];
2391         if (logp) {
2392             icl_LogHold(logp);
2393             tcode = icl_ZeroLog(logp);
2394             if (tcode != 0)
2395                 code = tcode;   /* save the last bad one */
2396             icl_LogRele(logp);
2397         }
2398     }
2399     return code;
2400 }
2401
2402 icl_EnumerateSets(aproc, arock)
2403      int (*aproc) ();
2404      char *arock;
2405 {
2406     register struct afs_icl_set *tp, *np;
2407     register afs_int32 code;
2408
2409     code = 0;
2410     for (tp = icl_allSets; tp; tp = np) {
2411         tp->refCount++;         /* hold this guy */
2412         code = (*aproc) (tp->name, arock, tp);
2413         np = tp->nextp;         /* tp may disappear next, but not np */
2414         if (--tp->refCount == 0 && (tp->states & ICL_SETF_DELETED))
2415             icl_ZapSet(tp);
2416         if (code)
2417             break;
2418     }
2419     return code;
2420 }
2421
2422 icl_AddLogToSet(setp, newlogp)
2423      struct afs_icl_set *setp;
2424      struct afs_icl_log *newlogp;
2425 {
2426     register int i;
2427     int code = -1;
2428     struct afs_icl_log *logp;
2429
2430     for (i = 0; i < ICL_LOGSPERSET; i++) {
2431         if (!setp->logs[i]) {
2432             setp->logs[i] = newlogp;
2433             code = i;
2434             icl_LogHold(newlogp);
2435             if (!(setp->states & ICL_SETF_FREED)) {
2436                 /* bump up the number of sets using the log */
2437                 icl_LogUse(newlogp);
2438             }
2439             break;
2440         }
2441     }
2442     return code;
2443 }
2444
2445 icl_SetSetStat(setp, op)
2446      struct afs_icl_set *setp;
2447      int op;
2448 {
2449     int i;
2450     afs_int32 code;
2451     struct afs_icl_log *logp;
2452
2453     switch (op) {
2454     case ICL_OP_SS_ACTIVATE:    /* activate a log */
2455         /*
2456          * If we are not already active, see if we have released
2457          * our demand that the log be allocated (FREED set).  If
2458          * we have, reassert our desire.
2459          */
2460         if (!(setp->states & ICL_SETF_ACTIVE)) {
2461             if (setp->states & ICL_SETF_FREED) {
2462                 /* have to reassert desire for logs */
2463                 for (i = 0; i < ICL_LOGSPERSET; i++) {
2464                     logp = setp->logs[i];
2465                     if (logp) {
2466                         icl_LogHold(logp);
2467                         icl_LogUse(logp);
2468                         icl_LogRele(logp);
2469                     }
2470                 }
2471                 setp->states &= ~ICL_SETF_FREED;
2472             }
2473             setp->states |= ICL_SETF_ACTIVE;
2474         }
2475         code = 0;
2476         break;
2477
2478     case ICL_OP_SS_DEACTIVATE:  /* deactivate a log */
2479         /* this doesn't require anything beyond clearing the ACTIVE flag */
2480         setp->states &= ~ICL_SETF_ACTIVE;
2481         code = 0;
2482         break;
2483
2484     case ICL_OP_SS_FREE:        /* deassert design for log */
2485         /* 
2486          * if we are already in this state, do nothing; otherwise
2487          * deassert desire for log
2488          */
2489         if (setp->states & ICL_SETF_ACTIVE)
2490             code = EINVAL;
2491         else {
2492             if (!(setp->states & ICL_SETF_FREED)) {
2493                 for (i = 0; i < ICL_LOGSPERSET; i++) {
2494                     logp = setp->logs[i];
2495                     if (logp) {
2496                         icl_LogHold(logp);
2497                         icl_LogFreeUse(logp);
2498                         icl_LogRele(logp);
2499                     }
2500                 }
2501                 setp->states |= ICL_SETF_FREED;
2502             }
2503             code = 0;
2504         }
2505         break;
2506
2507     default:
2508         code = EINVAL;
2509     }
2510
2511     return code;
2512 }
2513
2514 struct afs_icl_log *afs_icl_allLogs = 0;
2515
2516 /* hold and release logs */
2517 icl_LogHold(logp)
2518      register struct afs_icl_log *logp;
2519 {
2520     logp->refCount++;
2521     return 0;
2522 }
2523
2524 /* hold and release logs, called with lock already held */
2525 icl_LogHoldNL(logp)
2526      register struct afs_icl_log *logp;
2527 {
2528     logp->refCount++;
2529     return 0;
2530 }
2531
2532 /* keep track of how many sets believe the log itself is allocated */
2533 icl_LogUse(logp)
2534      register struct afs_icl_log *logp;
2535 {
2536     if (logp->setCount == 0) {
2537         /* this is the first set actually using the log -- allocate it */
2538         if (logp->logSize == 0) {
2539             /* we weren't passed in a hint and it wasn't set */
2540             logp->logSize = ICL_DEFAULT_LOGSIZE;
2541         }
2542         logp->datap =
2543             (afs_int32 *) osi_Alloc(sizeof(afs_int32) * logp->logSize);
2544     }
2545     logp->setCount++;
2546     return 0;
2547 }
2548
2549 /* decrement the number of real users of the log, free if possible */
2550 icl_LogFreeUse(logp)
2551      register struct afs_icl_log *logp;
2552 {
2553     if (--logp->setCount == 0) {
2554         /* no more users -- free it (but keep log structure around) */
2555         osi_Free(logp->datap, sizeof(afs_int32) * logp->logSize);
2556         logp->firstUsed = logp->firstFree = 0;
2557         logp->logElements = 0;
2558         logp->datap = NULL;
2559     }
2560     return 0;
2561 }
2562
2563 /* set the size of the log to 'logSize' */
2564 icl_LogSetSize(logp, logSize)
2565      register struct afs_icl_log *logp;
2566      afs_int32 logSize;
2567 {
2568     if (!logp->datap) {
2569         /* nothing to worry about since it's not allocated */
2570         logp->logSize = logSize;
2571     } else {
2572         /* reset log */
2573         logp->firstUsed = logp->firstFree = 0;
2574         logp->logElements = 0;
2575
2576         /* free and allocate a new one */
2577         osi_Free(logp->datap, sizeof(afs_int32) * logp->logSize);
2578         logp->datap = (afs_int32 *) osi_Alloc(sizeof(afs_int32) * logSize);
2579         logp->logSize = logSize;
2580     }
2581
2582     return 0;
2583 }
2584
2585 /* free a log.  Called with icl_lock locked. */
2586 icl_ZapLog(logp)
2587      register struct afs_icl_log *logp;
2588 {
2589     register struct afs_icl_log **lpp, *tp;
2590
2591     for (lpp = &afs_icl_allLogs, tp = *lpp; tp; lpp = &tp->nextp, tp = *lpp) {
2592         if (tp == logp) {
2593             /* found the dude we want to remove */
2594             *lpp = logp->nextp;
2595             osi_Free(logp->name, 1 + strlen(logp->name));
2596             osi_Free(logp->datap, logp->logSize * sizeof(afs_int32));
2597             osi_Free(logp, sizeof(struct icl_log));
2598             break;              /* won't find it twice */
2599         }
2600     }
2601     return 0;
2602 }
2603
2604 /* do the release, watching for deleted entries */
2605 icl_LogRele(logp)
2606      register struct afs_icl_log *logp;
2607 {
2608     if (--logp->refCount == 0 && (logp->states & ICL_LOGF_DELETED)) {
2609         icl_ZapLog(logp);       /* destroys logp's lock! */
2610     }
2611     return 0;
2612 }
2613
2614 /* do the release, watching for deleted entries, log already held */
2615 icl_LogReleNL(logp)
2616      register struct afs_icl_log *logp;
2617 {
2618     if (--logp->refCount == 0 && (logp->states & ICL_LOGF_DELETED)) {
2619         icl_ZapLog(logp);       /* destroys logp's lock! */
2620     }
2621     return 0;
2622 }
2623
2624 /* zero out the log */
2625 int
2626 icl_ZeroLog(register struct afs_icl_log *logp)
2627 {
2628     logp->firstUsed = logp->firstFree = 0;
2629     logp->logElements = 0;
2630     return 0;
2631 }
2632
2633 /* free a log entry, and drop its reference count */
2634 icl_LogFree(logp)
2635      register struct afs_icl_log *logp;
2636 {
2637     logp->states |= ICL_LOGF_DELETED;
2638     icl_LogRele(logp);
2639     return 0;
2640 }
2641
2642
2643 int
2644 icl_EnumerateLogs(int (*aproc)
2645                     (char *name, char *arock, struct afs_icl_log * tp),
2646                   char *arock)
2647 {
2648     register struct afs_icl_log *tp;
2649     register afs_int32 code;
2650
2651     code = 0;
2652     for (tp = afs_icl_allLogs; tp; tp = tp->nextp) {
2653         tp->refCount++;         /* hold this guy */
2654         code = (*aproc) (tp->name, arock, tp);
2655         if (--tp->refCount == 0)
2656             icl_ZapLog(tp);
2657         if (code)
2658             break;
2659     }
2660     return code;
2661 }
2662
2663
2664 afs_icl_bulkSetinfo_t *
2665 GetBulkSetInfo()
2666 {
2667     unsigned int infoSize;
2668
2669     infoSize =
2670         sizeof(afs_icl_bulkSetinfo_t) + (ICL_RPC_MAX_SETS -
2671                                          1) * sizeof(afs_icl_setinfo_t);
2672     if (!setInfo) {
2673         setInfo = (afs_icl_bulkSetinfo_t *) malloc(infoSize);
2674         if (!setInfo) {
2675             (void)fprintf(stderr,
2676                           "Could not allocate the memory for bulk set info structure\n");
2677             exit(1);
2678         }
2679     }
2680     memset((char *)setInfo, 0, infoSize);
2681
2682     return setInfo;
2683 }
2684
2685 afs_icl_bulkLoginfo_t *
2686 GetBulkLogInfo()
2687 {
2688     unsigned int infoSize;
2689
2690     infoSize =
2691         sizeof(afs_icl_bulkLoginfo_t) + (ICL_RPC_MAX_LOGS -
2692                                          1) * sizeof(afs_icl_loginfo_t);
2693     if (!logInfo) {
2694         logInfo = (afs_icl_bulkLoginfo_t *) malloc(infoSize);
2695         if (!logInfo) {
2696             (void)fprintf(stderr,
2697                           "Could not allocate the memory for bulk log info structure\n");
2698             exit(1);
2699         }
2700     }
2701
2702     memset((char *)logInfo, 0, infoSize);
2703     return logInfo;
2704 }
2705
2706
2707 static
2708 DoDump(as, arock)
2709      register struct cmd_syndesc *as;
2710      char *arock;
2711 {
2712     afs_int32 code = 0;
2713     afs_int32 tcode;
2714     afs_int32 waitTime = 10 /* seconds */ ;
2715     int error = 0;
2716     char *logname;
2717     char *filename;
2718     FILE *outfp = stdout;
2719     time_t startTime;
2720     struct cmd_item *itemp;
2721
2722     if (geteuid() != 0) {
2723         printf("fstrace must be run as root\n");
2724         exit(1);
2725     }
2726
2727     if (as->parms[3].items) {
2728         if (!as->parms[1].items) {
2729             (void)fprintf(stderr, "-sleep can only be used with -follow\n");
2730             return 1;
2731         }
2732         waitTime = strtol(as->parms[3].items->data, NULL, 0);
2733     }
2734
2735     if (as->parms[2].items) {
2736         /* try to open the specified output file */
2737         if ((outfp = fopen(as->parms[2].items->data, "w")) == NULL) {
2738             (void)fprintf(stderr, "Cannot open file '%s' for writing\n",
2739                           as->parms[2].items->data);
2740             return 1;
2741         }
2742     }
2743 #ifdef AFS_SGI64_ENV
2744     startTime = time((time_t *) 0);
2745 #else
2746     startTime = time(0);
2747 #endif
2748     (void)fprintf(outfp, "AFS Trace Dump -\n\n   Date: %s\n",
2749                   ctime(&startTime));
2750
2751     if (as->parms[0].items) {
2752         for (itemp = as->parms[0].items; itemp; itemp = itemp->next) {
2753             tcode = icl_DumpKernel(outfp, itemp->data);
2754             if (tcode) {
2755                 (void)fprintf(stderr, "Unable to dump set %s (errno = %d)\n",
2756                               itemp->data, errno);
2757                 code = tcode;
2758             }
2759         }
2760     } else if (as->parms[1].items) {
2761         logname = as->parms[1].items->data;
2762         code = icl_TailKernel(outfp, logname, waitTime);
2763         if (code) {
2764             (void)fprintf(stderr,
2765                           "Error tailing kernel log '%s' (errno = %d)\n",
2766                           logname, errno);
2767         }
2768     } else
2769         code = icl_DumpKernel(outfp, NULL);
2770
2771     (void)fprintf(outfp, "\nAFS Trace Dump - %s\n",
2772                   code ? "FAILED" : "Completed");
2773
2774     if (outfp != stdout)
2775         (void)fclose(outfp);
2776
2777     return code;
2778 }
2779
2780 static void
2781 SetUpDump()
2782 {
2783     struct cmd_syndesc *dumpSyntax;
2784
2785     dumpSyntax =
2786         cmd_CreateSyntax("dump", DoDump, (char *)NULL, "dump AFS trace logs");
2787     (void)cmd_AddParm(dumpSyntax, "-set", CMD_LIST, CMD_OPTIONAL, "set_name");
2788     (void)cmd_AddParm(dumpSyntax, "-follow", CMD_SINGLE, CMD_OPTIONAL,
2789                       "log_name");
2790     (void)cmd_AddParm(dumpSyntax, "-file", CMD_SINGLE, CMD_OPTIONAL,
2791                       "output_filename");
2792     (void)cmd_AddParm(dumpSyntax, "-sleep", CMD_SINGLE, CMD_OPTIONAL,
2793                       "seconds_between_reads");
2794 }
2795
2796 static
2797 DoShowLog(as, arock)
2798      register struct cmd_syndesc *as;
2799      char *arock;
2800 {
2801     afs_int32 retVal = 0;
2802     afs_int32 code = 0;
2803     afs_int32 logSize;
2804     int allocated;
2805     int int32flg = 0;
2806     struct cmd_item *itemp;
2807
2808     if (geteuid() != 0) {
2809         printf("fstrace must be run as root\n");
2810         exit(1);
2811     }
2812     if (as->parms[2].items)
2813         int32flg = 1;
2814
2815     if (as->parms[0].items) {
2816         /* enumerate logs for the specified sets */
2817         for (itemp = as->parms[0].items; itemp; itemp = itemp->next) {
2818             (void)fprintf(stdout, "Logs for set '%s':\n", itemp->data);
2819             code = icl_ListLogsBySet(stdout, itemp->data, int32flg);
2820             if (code) {
2821                 (void)fprintf(stderr,
2822                               "Error in enumerating set %s (errno = %d)\n",
2823                               itemp->data, errno);
2824                 retVal = code;
2825             }
2826         }
2827     } else if (as->parms[1].items) {
2828         /* print out log information */
2829         for (itemp = as->parms[1].items; itemp; itemp = itemp->next) {
2830             code = icl_GetLogsize(itemp->data, &logSize, &allocated);
2831             if (!code)
2832                 (void)fprintf(stdout, "%s : %d kbytes (%s)\n", itemp->data,
2833                               logSize / 1024,
2834                               allocated ? "allocated" : "unallocated");
2835             else {
2836                 (void)fprintf(stderr,
2837                               "Could not find log '%s' (errno = %d)\n",
2838                               itemp->data, errno);
2839                 retVal = code;
2840             }
2841         }
2842     } else {
2843         /* show all logs */
2844         (void)fprintf(stdout, "Available logs:\n");
2845         code = icl_ListLogs(stdout, int32flg);
2846         if (code) {
2847             (void)fprintf(stderr, "Error in listing logs (errno = %d)\n",
2848                           errno);
2849             retVal = code;
2850         }
2851     }
2852
2853     return retVal;
2854 }
2855
2856 static void
2857 SetUpShowLog()
2858 {
2859     struct cmd_syndesc *showSyntax;
2860
2861     showSyntax =
2862         cmd_CreateSyntax("lslog", DoShowLog, (char *)NULL,
2863                          "list available logs");
2864     (void)cmd_AddParm(showSyntax, "-set", CMD_LIST, CMD_OPTIONAL, "set_name");
2865     (void)cmd_AddParm(showSyntax, "-log", CMD_LIST, CMD_OPTIONAL, "log_name");
2866     (void)cmd_AddParm(showSyntax, "-long", CMD_FLAG, CMD_OPTIONAL, "");
2867 }
2868
2869 static
2870 DoShowSet(as, arock)
2871      register struct cmd_syndesc *as;
2872      char *arock;
2873 {
2874     afs_int32 retVal = 0;
2875     afs_int32 code = 0;
2876     afs_int32 state;
2877     struct cmd_item *itemp;
2878
2879     if (geteuid() != 0) {
2880         printf("fstrace must be run as root\n");
2881         exit(1);
2882     }
2883     if (as->parms[0].items) {
2884         /* print information on the specified sets */
2885         for (itemp = as->parms[0].items; itemp; itemp = itemp->next) {
2886             code = icl_GetSetState(itemp->data, &state);
2887             if (code) {
2888                 (void)fprintf(stderr,
2889                               "Error getting status on set %s (errno = %d)\n",
2890                               itemp->data, errno);
2891                 retVal = code;
2892             } else
2893                 (void)fprintf(stdout, "Set %s: %s%s%s\n", itemp->data,
2894                               (state & ICL_SETF_ACTIVE) ? "active" :
2895                               "inactive",
2896                               (state & ICL_SETF_FREED) ? " (dormant)" : "",
2897                               (state & ICL_SETF_PERSISTENT) ? " persistent" :
2898                               "");
2899         }
2900     } else {
2901         /* show all sets */
2902         (void)fprintf(stdout, "Available sets:\n");
2903         code = icl_ListSets(stdout);
2904         if (code) {
2905             (void)fprintf(stderr, "Error in listing sets (errno = %d)\n",
2906                           errno);
2907             retVal = code;
2908         }
2909     }
2910
2911     return retVal;
2912 }
2913
2914 static void
2915 SetUpShowSet()
2916 {
2917     struct cmd_syndesc *showSyntax;
2918
2919     showSyntax =
2920         cmd_CreateSyntax("lsset", DoShowSet, (char *)NULL,
2921                          "list available event sets");
2922     (void)cmd_AddParm(showSyntax, "-set", CMD_LIST, CMD_OPTIONAL, "set_name");
2923 }
2924
2925 static
2926 DoClear(as, arock)
2927      register struct cmd_syndesc *as;
2928      char *arock;
2929 {
2930     afs_int32 retVal = 0;
2931     afs_int32 code = 0;
2932     struct cmd_item *itemp;
2933
2934     if (geteuid() != 0) {
2935         printf("fstrace must be run as root\n");
2936         exit(1);
2937     }
2938     if (as->parms[0].items) {
2939         /* clear logs for the specified sets */
2940         for (itemp = as->parms[0].items; itemp; itemp = itemp->next) {
2941             code = icl_ClearSet(itemp->data);
2942             if (code) {
2943                 (void)fprintf(stderr,
2944                               "Error in clearing set %s (errno = %d)\n",
2945                               itemp->data, errno);
2946                 retVal = code;
2947             }
2948         }
2949     } else if (as->parms[1].items) {
2950         /* clear specified log */
2951         for (itemp = as->parms[0].items; itemp; itemp = itemp->next) {
2952             code = icl_ClearLog(itemp->data);
2953             if (code) {
2954                 (void)fprintf(stderr,
2955                               "Error in clearing log %s (errno = %d)\n",
2956                               itemp->data, errno);
2957                 retVal = code;
2958             }
2959         }
2960     } else {
2961         /* clear all logs */
2962         code = icl_ClearAll();
2963         if (code) {
2964             (void)fprintf(stderr, "Error in clearing logs (errno = %d)\n",
2965                           errno);
2966             retVal = code;
2967         }
2968     }
2969
2970     return retVal;
2971 }
2972
2973 static void
2974 SetUpClear()
2975 {
2976     struct cmd_syndesc *clearSyntax;
2977
2978     clearSyntax =
2979         cmd_CreateSyntax("clear", DoClear, (char *)NULL,
2980                          "clear logs by logname or by event set");
2981     (void)cmd_AddParm(clearSyntax, "-set", CMD_LIST, CMD_OPTIONAL,
2982                       "set_name");
2983     (void)cmd_AddParm(clearSyntax, "-log", CMD_LIST, CMD_OPTIONAL,
2984                       "log_name");
2985 }
2986
2987 static
2988 DoSet(as, arock)
2989      register struct cmd_syndesc *as;
2990      char *arock;
2991 {
2992     afs_int32 retVal = 0;
2993     afs_int32 code = 0;
2994     int op;
2995     int doFree = 0;
2996     char *operation;
2997     struct cmd_item *itemp;
2998
2999     if (geteuid() != 0) {
3000         printf("fstrace must be run as root\n");
3001         exit(1);
3002     }
3003     if (as->parms[1].items) {
3004         op = ICL_OP_SS_ACTIVATE;
3005         operation = "active";
3006     } else if (as->parms[2].items) {
3007         op = ICL_OP_SS_DEACTIVATE;
3008         operation = "inactive";
3009     } else if (as->parms[3].items) {
3010         op = ICL_OP_SS_DEACTIVATE;
3011         operation = "inactive";
3012         doFree = 1;
3013     } else {
3014         /* assume active" */
3015         op = ICL_OP_SS_ACTIVATE;
3016         operation = "active";
3017     }
3018
3019     if (as->parms[0].items) {
3020         /* activate specified sets */
3021         for (itemp = as->parms[0].items; itemp; itemp = itemp->next) {
3022             code = icl_ChangeSetState(itemp->data, op);
3023             if (code) {
3024                 (void)fprintf(stderr,
3025                               "cannot set state of %s to %s (errno = %d)\n",
3026                               itemp->data, operation, errno);
3027                 retVal = code;
3028             } else if (doFree) {
3029                 /* try to make it dormant as well */
3030                 code = icl_ChangeSetState(itemp->data, ICL_OP_SS_FREE);
3031                 if (code) {
3032                     (void)fprintf(stderr,
3033                                   "cannot set state of %s to dormant (errno = %d)\n",
3034                                   itemp->data, errno);
3035                     retVal = code;
3036                 }
3037             }
3038         }
3039     } else {
3040         /* show all sets */
3041         code = icl_ChangeAllSetState(op);
3042         if (code) {
3043             (void)fprintf(stderr,
3044                           "cannot set the state of all sets to %s (errno = %d)\n",
3045                           operation, errno);
3046             retVal = code;
3047         } else if (doFree) {
3048             /* try to make it dormant as well */
3049             code = icl_ChangeAllSetState(ICL_OP_SS_FREE);
3050             if (code) {
3051                 (void)fprintf(stderr,
3052                               "cannot set the state of all sets to dormant (errno = %d)\n",
3053                               errno);
3054                 retVal = code;
3055             }
3056         }
3057     }
3058
3059     return retVal;
3060 }
3061
3062 static void
3063 SetUpSet()
3064 {
3065     struct cmd_syndesc *setSyntax;
3066
3067     setSyntax =
3068         cmd_CreateSyntax("setset", DoSet, (char *)NULL,
3069                          "set state of event sets");
3070     (void)cmd_AddParm(setSyntax, "-set", CMD_LIST, CMD_OPTIONAL, "set_name");
3071     (void)cmd_AddParm(setSyntax, "-active", CMD_FLAG, CMD_OPTIONAL, "");
3072     (void)cmd_AddParm(setSyntax, "-inactive", CMD_FLAG, CMD_OPTIONAL, "");
3073     (void)cmd_AddParm(setSyntax, "-dormant", CMD_FLAG, CMD_OPTIONAL, "");
3074 }
3075
3076 static
3077 DoResize(as, arock)
3078      register struct cmd_syndesc *as;
3079      char *arock;
3080 {
3081     afs_int32 retVal = 0;
3082     afs_int32 code = 0;
3083     afs_int32 bufferSize;
3084     struct cmd_item *itemp;
3085
3086     if (geteuid() != 0) {
3087         printf("fstrace must be run as root\n");
3088         exit(1);
3089     }
3090     /* get buffer size */
3091     bufferSize = atoi(as->parms[1].items->data);
3092     bufferSize *= BUFFER_MULTIPLIER;
3093     if (bufferSize == 0)
3094         bufferSize = ICL_DEFAULT_LOGSIZE;
3095
3096     /* set the size of the specified logs */
3097     if (itemp = as->parms[0].items) {
3098         for (; itemp; itemp = itemp->next) {
3099             code = icl_ChangeLogSize(itemp->data, bufferSize);
3100             if (code) {
3101                 (void)fprintf(stderr,
3102                               "Error in changing log %s buffer size (errno = %d)\n",
3103                               itemp->data, errno);
3104                 retVal = code;
3105             }
3106         }
3107     } else {
3108         /* Use the only current support log, "cmfx" */
3109         code = icl_ChangeLogSize("cmfx", bufferSize);
3110         if (code) {
3111             (void)fprintf(stderr,
3112                           "Error in changing log cmfx buffer size (errno = %d)\n",
3113                           errno);
3114             retVal = code;
3115         }
3116     }
3117
3118     return retVal;
3119 }
3120
3121 static void
3122 SetUpResize()
3123 {
3124     struct cmd_syndesc *setsizeSyntax;
3125
3126     setsizeSyntax =
3127         cmd_CreateSyntax("setlog", DoResize, (char *)NULL,
3128                          "set the size of a log");
3129     (void)cmd_AddParm(setsizeSyntax, "-log", CMD_LIST, CMD_OPTIONAL,
3130                       "log_name");
3131     (void)cmd_AddParm(setsizeSyntax, "-buffersize", CMD_SINGLE, CMD_REQUIRED,
3132                       "1-kilobyte_units");
3133 }
3134
3135 #include "AFS_component_version_number.c"
3136
3137 main(argc, argv)
3138      IN int argc;
3139      IN char *argv[];
3140 {
3141     setlocale(LC_ALL, "");
3142 #ifdef AFS_SGI62_ENV
3143     set_kernel_sizeof_long();
3144 #endif
3145
3146     /* set up user interface then dispatch */
3147     SetUpDump();
3148     SetUpShowLog();
3149     SetUpShowSet();
3150     SetUpClear();
3151     SetUpSet();
3152     SetUpResize();
3153
3154     return (cmd_Dispatch(argc, argv));
3155 }
3156 #else
3157 #include "AFS_component_version_number.c"
3158
3159 main()
3160 {
3161     printf("fstrace is NOT supported for this OS\n");
3162 }
3163 #endif