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