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