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