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