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