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