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