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