venus: fix memory leak
[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 #include <afs/stds.h>
16
17 #include <roken.h>
18
19 #include <afs/cmd.h>
20 #include <afs/afs_args.h>
21 #include <afs/icl.h>
22 #include <afs/afsutil.h>
23 #include <rx/rx.h>
24 #include <afs/vice.h>
25 #include <afs/sys_prototypes.h>
26
27 #if defined(AFS_OSF_ENV) || defined(AFS_SGI61_ENV) || (defined(AFS_AIX51_ENV) && defined(AFS_64BIT_KERNEL))
28 /* For SGI 6.2, this is changed to 1 if it's a 32 bit kernel. */
29 int afs_icl_sizeofLong = 2;
30 #else
31 int afs_icl_sizeofLong = 1;
32 #endif
33
34 #if defined(AFS_SGI61_ENV) || (defined(AFS_AIX51_ENV) && defined(AFS_64BIT_KERNEL))
35 int afs_64bit_kernel = 1;       /* Default for 6.2+, and always for 6.1 */
36 extern int afs_icl_sizeofLong;  /* Used in ICL_SIZEHACK() */
37 #ifdef AFS_SGI62_ENV
38
39 /* If _SC_KERN_POINTERS not in sysconf, then we can assume a 32 bit abi. */
40 void
41 set_kernel_sizeof_long(void)
42 {
43     int retval;
44
45
46     retval = sysconf(_SC_KERN_POINTERS);
47     if (retval == 64) {
48         afs_64bit_kernel = 1;
49         afs_icl_sizeofLong = 2;
50     } else {
51         afs_64bit_kernel = 0;
52         afs_icl_sizeofLong = 1;
53     }
54 }
55
56 #endif /* AFS_SGI62_ENV */
57 #endif /* AFS_SGI61_ENV */
58
59 int afs_syscall(long call, long parm0, long parm1, long parm2, long parm3,
60                 long parm4, long parm5, long parm6);
61 void dce1_error_inq_text(afs_uint32 status_to_convert,
62                          char *error_text, int *status);
63 int icl_CreateSetWithFlags(char *name, struct afs_icl_log *baseLogp,
64                            struct afs_icl_log *fatalLogp, afs_uint32 flags,
65                            struct afs_icl_set **outSetpp);
66 int icl_LogHold(struct afs_icl_log *logp);
67 int icl_LogUse(struct afs_icl_log *logp);
68 int icl_LogReleNL(struct afs_icl_log *logp);
69 int icl_LogRele(struct afs_icl_log *logp);
70 int icl_ZeroLog(struct afs_icl_log *logp);
71 int icl_LogFreeUse(struct afs_icl_log *logp);
72
73 #define BUFFER_MULTIPLIER     1024
74
75 /* make it big enough to snapshot everything at once, since
76  * decoding takes so long.
77  */
78 #define IBSIZE          100000  /* default size */
79
80 struct logInfo {
81     struct logInfo *nextp;
82     char *name;
83 } *allInfo = 0;
84
85 char dumpFileName[256] = "";
86 void
87 RegisterIclDumpFileName(char *name)
88 {
89     (void)sprintf(dumpFileName, "icl.%.250s", name);
90 }
91
92 /* define globals to use for bulk info */
93 afs_icl_bulkSetinfo_t *setInfo = (afs_icl_bulkSetinfo_t *) 0;
94 afs_icl_bulkLoginfo_t *logInfo = (afs_icl_bulkLoginfo_t *) 0;
95
96 struct afs_icl_set *icl_allSets = 0;
97
98
99 char *name;
100 /* given a type and an address, get the size of the thing
101  * in words.
102  */
103 static int
104 icl_GetSize(afs_int32 type, char *addr)
105 {
106     int rsize;
107     int tsize;
108
109     rsize = 0;
110     ICL_SIZEHACK(type, addr, tsize, rsize);
111     return rsize;
112 }
113
114 /* Check types in printf string "bufferp", making sure that each
115  * is compatible with the corresponding parameter type described
116  * by typesp.  Also watch for prematurely running out of parameters
117  * before the string is gone.
118  */
119 #if defined(AFS_SGI61_ENV) || (defined(AFS_AIX51_ENV) && defined(AFS_64BIT_KERNEL))
120 static int
121 CheckTypes(char *bufferp, int *typesp, int typeCount, char *outMsgBuffer)
122 {
123     char tc;
124     int inPercent;
125     int tix;
126
127     inPercent = 0;
128     tix = 0;
129     for (tc = *bufferp;; outMsgBuffer++, tc = *(++bufferp)) {
130         *outMsgBuffer = tc;
131         if (tc == 0) {
132             /* hit end of string.  We win as long as we aren't
133              * in a '%'.
134              */
135             if (inPercent)
136                 return 0;
137             else
138                 return 1;
139         }
140         if (tc == '%') {
141             inPercent = 1 - inPercent;
142             continue;
143         }
144         if (inPercent) {
145             if (tc >= '0' && tc <= '9') {
146                 /* skip digits in % string */
147                 outMsgBuffer--;
148                 continue;
149             }
150             if (tc == 'l') {
151                 /* 'l' is a type modifier. */
152                 outMsgBuffer--;
153                 continue;
154             }
155             /* otherwise, we've finally gotten to the type-describing
156              * character.  Make sure there's a type descriptor, and then
157              * check the type descriptor.
158              */
159             inPercent = 0;
160             if (tix >= typeCount)
161                 return 0;       /* no more type descriptors left */
162             if (tc == 's') {
163                 if (typesp[tix] != 1)   /* not a string descriptor */
164                     return 0;
165                 outMsgBuffer--;
166                 *outMsgBuffer = (char)1;
167             }
168             if (tc == 'u' || tc == 'x' || tc == 'd' || tc == 'o') {
169                 if (typesp[tix] != 0)
170                     return 0;   /* not an integer descriptor */
171                 outMsgBuffer--;
172                 switch (tc) {
173                 case 'd':
174                     *outMsgBuffer = (char)2;
175                     break;
176                 case 'u':
177                     *outMsgBuffer = (char)3;
178                     break;
179                 case 'o':
180                     *outMsgBuffer = (char)4;
181                     break;
182                 case 'x':
183                 default:
184                     *outMsgBuffer = (char)5;
185                     break;
186                 }
187             }
188             /* otherwise we're fine, so eat this descriptor */
189             tix++;
190         }
191     }
192     /* not reached */
193 }
194 #else /* AFS_SGI61_ENV */
195 static int
196 CheckTypes(char *bufferp, int *typesp, int typeCount)
197 {
198     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)
210                 return 0;
211             else
212                 return 1;
213         }
214         if (tc == '%') {
215             inPercent = 1 - inPercent;
216             continue;
217         }
218         if (inPercent) {
219             if (tc >= '0' && tc <= '9')
220                 continue;       /* skip digits in % string */
221             /* otherwise, we've finally gotten to the type-describing
222              * character.  Make sure there's a type descriptor, and then
223              * check the type descriptor.
224              */
225             inPercent = 0;
226             if (tix >= typeCount)
227                 return 0;       /* no more type descriptors left */
228             if (tc == 's' && typesp[tix] != 1)  /* not a string descriptor */
229                 return 0;
230             if ((tc == 'u' || tc == 'l' || tc == 'x' || tc == 'd')
231                 && (typesp[tix] != 0))
232                 return 0;       /* not an integer descriptor */
233             /* otherwise we're fine, so eat this descriptor */
234             tix++;
235         }
236     }
237     /* not reached */
238 }
239 #endif /* AFS_SGI61_ENV */
240
241 /* display a single record.
242  * alp points at the first word in the array to be interpreted
243  * rsize gives the # of words in the array
244  */
245 #if defined(AFS_SGI61_ENV) && !defined(AFS_SGI62_ENV)
246 #define uint64_t long long
247 #endif
248 static void
249 DisplayRecord(FILE *outFilep, afs_int32 *alp, afs_int32 rsize)
250 {
251     char msgBuffer[1024];
252 #if defined(AFS_SGI61_ENV) || (defined(AFS_AIX51_ENV) && defined(AFS_64BIT_KERNEL))
253     char outMsgBuffer[1024];
254     uint64_t tempParam;
255     uint64_t printfParms[ICL_MAXEXPANSION * /* max parms */ 4];
256     char *printfStrings[ICL_MAXEXPANSION * /* max parms */ 4];
257 #else /* AFS_SGI61_ENV */
258     long printfParms[ICL_MAXEXPANSION * /* max parms */ 4];
259 #endif /* AFS_SGI61_ENV */
260     int printfTypes[ICL_MAXEXPANSION * 4];
261     int i;
262     afs_int32 done = 0;
263     afs_int32 temp;
264     int j;
265     int type;
266     int pix;                    /* index in alp */
267     int pfpix;                  /* index in printfParms */
268     int pftix;                  /* index in printfTypes */
269     int status;
270     int printed;                /* did we print the string yet? */
271     time_t tmv;
272
273     /* decode parameters */
274     temp = alp[0];              /* type encoded in low-order 24 bits, t0 high */
275     pix = 4;
276     pfpix = 0;
277     pftix = 0;
278     /* init things */
279
280     for (i = 0; i < 4 * ICL_MAXEXPANSION; i++)
281         printfParms[i] = 0;
282     /* decode each parameter, getting addrs for afs_hyper_t and strings */
283     for (i = 0; !done && i < 4; i++) {
284         type = (temp >> (18 - i * 6)) & 0x3f;
285         switch (type) {
286         case ICL_TYPE_NONE:
287             done = 1;
288             break;
289         case ICL_TYPE_LONG:
290         case ICL_TYPE_POINTER:
291             printfTypes[pftix++] = 0;
292 #if defined(AFS_SGI61_ENV) || (defined(AFS_AIX51_ENV) && defined(AFS_64BIT_KERNEL))
293             printfParms[pfpix] = alp[pix];
294             printfParms[pfpix] &= 0xffffffff;
295             if (afs_64bit_kernel) {
296                 printfParms[pfpix] <<= 32;
297                 printfParms[pfpix] |= alp[pix + 1];
298             }
299 #elif defined(AFS_OSF_ENV)
300             printfParms[pfpix] = alp[pix + 1];
301             printfParms[pfpix] |= (alp[pix] <<= 32);
302 #else /* !AFS_OSF_ENV && !AFS_SGI61_ENV */
303             printfParms[pfpix] = alp[pix];
304 #endif
305             pfpix++;
306             break;
307         case ICL_TYPE_INT32:
308             printfTypes[pftix++] = 0;
309             printfParms[pfpix++] = alp[pix];
310             break;
311         case ICL_TYPE_HYPER:
312         case ICL_TYPE_INT64:
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 #if defined(AFS_SGI61_ENV) || (defined(AFS_AIX51_ENV) && defined(AFS_64BIT_KERNEL))
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             tmv = alp[pix];
342             printfParms[pfpix++] = (long)ctime(&tmv);
343             break;
344         default:
345             printf("DisplayRecord: Bad type %d in decode switch.\n", type);
346             done = 1;
347             break;
348         }
349         if (done)
350             break;
351
352         pix += icl_GetSize(type, (char *)&alp[pix]);
353     }
354
355     /* next, try to decode the opcode into a printf string */
356     dce1_error_inq_text(alp[1], msgBuffer, &status);
357
358     /* if we got a string back, and it is compatible with the
359      * parms we've got, then print it.
360      */
361     printed = 0;
362     if (status == 0) {
363 #if defined(AFS_SGI61_ENV) || (defined(AFS_AIX51_ENV) && defined(AFS_64BIT_KERNEL))
364         if (CheckTypes(msgBuffer, printfTypes, pftix, outMsgBuffer)) {
365             /* we have a string to use, but it ends "(dfs / zcm)",
366              * so we remove the extra gunk.
367              */
368             j = strlen(outMsgBuffer);
369             if (j > 12) {
370                 outMsgBuffer[j - 11] = 0;
371                 j -= 11;
372             }
373             pfpix = 0;
374             fprintf(outFilep, "time %d.%06d, pid %u: ", alp[3] / 1000000,
375                     alp[3] % 1000000, alp[2]);
376             for (i = 0; i < j; i++) {
377                 if ((int)outMsgBuffer[i] > 5)
378                     fputc(outMsgBuffer[i], outFilep);
379                 else {
380                     switch (outMsgBuffer[i]) {
381                     case 0:     /* done */
382                         break;
383                     case 1:     /* string */
384                         fprintf(outFilep, "%s", printfStrings[pfpix++]);
385                         break;
386                     case 2:     /* signed integer */
387                         fprintf(outFilep, "%" AFS_INT64_FMT, printfParms[pfpix++]);
388                         break;
389                     case 3:     /* unsigned integer */
390                         fprintf(outFilep, "%llu", printfParms[pfpix++]);
391                         break;
392                     case 4:     /* octal integer */
393                         fprintf(outFilep, "%llo", printfParms[pfpix++]);
394                         break;
395                     case 5:     /* hex integer */
396                         fprintf(outFilep, "%llx", printfParms[pfpix++]);
397                         break;
398                     default:
399                         fprintf(outFilep,
400                                 "fstrace: Bad char %d in outMsgBuffer for parm %d\n",
401                                 outMsgBuffer[i], pfpix);
402                         fprintf(outFilep, "fstrace: msgBuffer='%s'\n",
403                                 msgBuffer);
404                         break;
405                     }
406                 }
407             }
408             fprintf(outFilep, "\n");
409             printed = 1;
410         }
411 #else /* AFS_SGI61_ENV */
412         if (CheckTypes(msgBuffer, printfTypes, pftix)) {
413             /* we have a string to use, but it ends "(dfs / zcm)",
414              * so we remove the extra gunk.
415              */
416             j = strlen(msgBuffer);
417             if (j > 12)
418                 msgBuffer[j - 11] = 0;
419             fprintf(outFilep, "time %d.%06d, pid %u: ", alp[3] / 1000000,
420                     alp[3] % 1000000, alp[2]);
421             fprintf(outFilep, msgBuffer, printfParms[0], printfParms[1],
422                     printfParms[2], printfParms[3], printfParms[4],
423                     printfParms[5], printfParms[6], printfParms[7],
424                     printfParms[8], printfParms[9], printfParms[10],
425                     printfParms[11], printfParms[12], printfParms[13],
426                     printfParms[14], printfParms[15]);
427             fprintf(outFilep, "\n");
428             printed = 1;
429         }
430 #endif /* AFS_SGI61_ENV */
431         else {
432             fprintf(outFilep, "Type mismatch, using raw print.\n");
433             fprintf(outFilep, "%s", msgBuffer);
434         }
435     }
436     if (!printed) {
437         if (alp[1] == ICL_INFO_TIMESTAMP) {
438             tmv = alp[4];
439             fprintf(outFilep, "time %d.%06d, pid %u: %s\n", alp[3] / 1000000,
440                     alp[3] % 1000000, alp[2], ctime(&tmv));
441         } else {
442             fprintf(outFilep, "raw op %d, time %d.%06d, pid %u\n", alp[1],
443                     alp[3] / 1000000, alp[3] % 1000000, alp[2]);
444             /* now decode each parameter and print it */
445             pix = 4;
446             done = 0;
447             for (i = 0; !done && i < 4; i++) {
448                 type = (temp >> (18 - i * 6)) & 0x3f;
449                 switch (type) {
450                 case ICL_TYPE_NONE:
451                     done = 1;
452                     break;
453                 case ICL_TYPE_INT32:
454                     fprintf(outFilep, "p%d:%d ", i, alp[pix]);
455                     break;
456                 case ICL_TYPE_LONG:
457 #ifdef AFS_SGI61_ENV
458                     tempParam = alp[pix];
459                     tempParam <<= 32;
460                     tempParam |= alp[pix + 1];
461                     fprintf(outFilep, "p%d:%" AFS_INT64_FMT " ", i, tempParam);
462 #else /* AFS_SGI61_ENV */
463                     fprintf(outFilep, "p%d:%d ", i, alp[pix]);
464 #endif /* AFS_SGI61_ENV */
465                     break;
466                 case ICL_TYPE_POINTER:
467 #ifdef AFS_SGI61_ENV
468                     tempParam = alp[pix];
469                     tempParam <<= 32;
470                     tempParam |= alp[pix + 1];
471                     fprintf(outFilep, "p%d:0x%llx ", i, tempParam);
472 #else /* AFS_SGI61_ENV */
473                     fprintf(outFilep, "p%d:0x%x ", i, alp[pix]);
474 #endif /* AFS_SGI61_ENV */
475                     break;
476                 case ICL_TYPE_HYPER:
477                 case ICL_TYPE_INT64:
478                     fprintf(outFilep, "p%d:%x.%x ", i, alp[pix],
479                             alp[pix + 1]);
480                     break;
481                 case ICL_TYPE_FID:
482                     fprintf(outFilep, "p%d:%d.%d.%d.%d ", i, alp[pix],
483                             alp[pix + 1], alp[pix + 2], alp[pix + 3]);
484                     break;
485                 case ICL_TYPE_STRING:
486                     fprintf(outFilep, "p%d:%s ", i, (char *)&alp[pix]);
487                     break;
488                 case ICL_TYPE_UNIXDATE:
489                     tmv = alp[pix];
490                     fprintf(outFilep, "p%d:%s ", i,
491                             ctime(&tmv));
492                     break;
493                 default:
494                     printf
495                         ("DisplayRecord: Bad type %d in raw print switch.\n",
496                          type);
497                     done = 1;
498                     break;
499                 }
500                 if (done)
501                     break;
502
503                 pix += icl_GetSize(type, (char *)&alp[pix]);
504             }
505         }
506         fprintf(outFilep, "\n");        /* done with line */
507     }
508 }
509
510
511
512 #include <locale.h>
513 #ifdef  AFS_OSF_ENV
514 #include <limits.h>
515 #endif
516 #include <nl_types.h>
517
518 #define FACILITY_CODE_MASK          0xF0000000
519 #define FACILITY_CODE_SHIFT         28
520
521 #define COMPONENT_CODE_MASK         0x0FFFF000
522 #define COMPONENT_CODE_SHIFT        12
523
524 #define STATUS_CODE_MASK            0x00000FFF
525 #define STATUS_CODE_SHIFT           0
526
527 #define NO_MESSAGE                  "THIS IS NOT A MESSAGE"
528
529 /*
530  * We use NLS message catalog functions to convert numbers to human-readable
531  * strings.  The message catalog will be in AFSDIR_DATA_DIR, which is
532  * ${datadir}/openafs with normal paths and /usr/vice/etc (for historical
533  * compatibility) for Transarc paths.
534  */
535
536 void
537 dce1_error_inq_text(afs_uint32 status_to_convert,
538                    char *error_text, int *status)
539 {
540     unsigned short facility_code;
541     unsigned short component_code;
542     unsigned short status_code;
543     unsigned short i;
544     nl_catd catd;
545     char component_name[4];
546     char *facility_name;
547     char filename_prefix[7];
548     char nls_filename[80];
549     char *message;
550     static char *facility_names[] = {
551         "xxx",
552         "afs"
553     };
554
555     /*
556      * set up output status for future error returns
557      */
558     if (status != NULL) {
559         *status = -1;
560     }
561     /*
562      * check for ok input status
563      */
564     if (status_to_convert == 0) {
565         if (status != NULL) {
566             *status = 0;
567         }
568         strcpy((char *)error_text, "successful completion");
569         return;
570     }
571
572     /*
573      * extract the component, facility and status codes
574      */
575     facility_code =
576         (status_to_convert & FACILITY_CODE_MASK) >> FACILITY_CODE_SHIFT;
577     component_code =
578         (status_to_convert & COMPONENT_CODE_MASK) >> COMPONENT_CODE_SHIFT;
579     status_code = (status_to_convert & STATUS_CODE_MASK) >> STATUS_CODE_SHIFT;
580
581     /*
582      * see if this is a recognized facility
583      */
584     if (facility_code == 0
585         || facility_code > sizeof(facility_names) / sizeof(char *)) {
586         sprintf((char *)error_text, "status %08x (unknown facility)",
587                 status_to_convert);
588         return;
589     }
590     facility_name = facility_names[facility_code - 1];
591     /*
592      * Convert component name from RAD-50 component code.  (Mapping is:
593      * 0 => 'a', ..., 25 => 'z', 26 => '{', 27 => '0', ..., 36 => '9'.)
594      */
595     component_name[3] = 0;
596     component_name[2] = component_code % 40;
597     component_code /= 40;
598     component_name[1] = component_code % 40;
599     component_name[0] = component_code / 40;
600     for (i = 0; i < 3; i++) {
601         component_name[i] += (component_name[i] <= 26) ? 'a' : ('0' - 27);
602     }
603     sprintf(filename_prefix, "%3s%3s", facility_name, component_name);
604
605     /*
606      * We do not use the normal NLS message catalog search path since our use
607      * message catalogs isn't a typical use.  It wouldn't make sense to
608      * install this special message catalog in with internationalization
609      * catalogs.
610      */
611     snprintf(nls_filename, sizeof(nls_filename), "%s/C/%s.cat",
612              AFSDIR_CLIENT_DATA_DIRPATH, filename_prefix);
613
614     catd = catopen(nls_filename, 0);
615     if (catd == (nl_catd) -1) {
616         sprintf((char *)error_text, "status %08x (%s / %s)",
617                 status_to_convert, facility_name, component_name);
618         return;
619     }
620     /*
621      * try to get the specified message from the file
622      */
623     message = (char *)catgets(catd, 1, status_code, NO_MESSAGE);
624     /*
625      * if everything went well, return the resulting message
626      */
627     if (strcmp(message, NO_MESSAGE) != 0) {
628         sprintf((char *)error_text, "%s (%s / %s)", message, facility_name,
629                 component_name);
630         if (status != NULL) {
631             *status = 0;
632         }
633     } else {
634         sprintf((char *)error_text, "status %08x (%s / %s)",
635                 status_to_convert, facility_name, component_name);
636     }
637     catclose(catd);
638 }
639
640 int
641 icl_DumpKernel(FILE *outFilep, char *setname)
642 {
643     afs_int32 bufferSize = 0;
644     afs_int32 *bufferp;
645     afs_int32 i;
646     afs_int32 code, retVal = 0;
647     char tname[64];
648     afs_int32 nwords;
649     afs_int32 ix;
650     afs_int32 rlength;
651     afs_int32 dummy, dummy2;
652     struct logInfo *lip;
653
654     /* first, enumerate the logs we're interested in */
655     if (setname) {
656         int found = 0;
657         /* dump logs for a particular set */
658         for (i = 0; i < ICL_LOGSPERSET; i++) {
659             code =
660                 afs_syscall(AFSCALL_ICL, ICL_OP_ENUMLOGSBYSET, (long)setname,
661                             i, (long)tname, sizeof(tname), 0, 0);
662             if (code) {
663                 if (errno == EBADF) {
664                     continue;   /* missing slot, nothing to worry about */
665                 }
666                 break;
667             }
668             code =
669                 afs_syscall(AFSCALL_ICL, ICL_OP_GETLOGINFO, (long)tname,
670                             (long)&dummy, (long)&dummy2, 0, 0, 0);
671             if (code)
672                 break;
673             found++;
674             if (dummy > bufferSize)     /* find biggest log */
675                 bufferSize = dummy;
676             lip = calloc(1, sizeof(struct logInfo));
677             lip->nextp = allInfo;
678             allInfo = lip;
679             lip->name = strdup(tname);
680         }
681         i = found;
682     } else {
683         /* dump all logs */
684         for (i = 0; i < 1000; i++) {
685             code =
686                 afs_syscall(AFSCALL_ICL, ICL_OP_ENUMLOGS, i, (long)tname,
687                             sizeof(tname), (long)&dummy, 0, 0);
688             if (code)
689                 break;
690             if (dummy > bufferSize)     /* find biggest log */
691                 bufferSize = dummy;
692             lip = calloc(1, sizeof(struct logInfo));
693             lip->nextp = allInfo;
694             allInfo = lip;
695             lip->name = strdup(tname);
696         }
697     }
698
699     if (bufferSize == 0)
700         return -1;
701     bufferp = malloc(sizeof(afs_int32) * bufferSize);
702     if (!bufferp)
703         return -1;
704
705     fprintf(outFilep, "Found %d logs.\n", i);
706
707     /* now print out the contents of each log */
708     for (lip = allInfo; lip; lip = lip->nextp) {
709         fprintf(outFilep, "\nContents of log %s:\n", lip->name);
710         /* read out everything first; gets a more consistent
711          * snapshot.
712          */
713         nwords = 0;             /* total words copied out */
714         for (i = 0;;) {
715             /* display all the entries in the log */
716             if (bufferSize - nwords <= 0)
717                 break;          /* filled whole buffer */
718             code =
719                 afs_syscall(AFSCALL_ICL, ICL_OP_COPYOUT, (long)lip->name,
720                             (long)(bufferp + nwords), bufferSize - nwords,
721                             (long)&i, 0, 0);
722             if (code < 0) {
723                 /* otherwise we've got an error */
724                 fprintf(outFilep, "Returned error %d dumping log.\n", errno);
725                 break;
726             }
727             /* otherwise, we have flags in the high order byte, and
728              * a length (in words) in the remainder.
729              */
730             if ((code >> 24) & ICL_COPYOUTF_MISSEDSOME)
731                 fprintf(outFilep, "Log wrapped; data missing.\n");
732             code &= 0xffffff;
733             if (code == 0) {
734                 /* we're done */
735                 break;
736             }
737             nwords += code;
738             i += code;
739         }                       /* for loop over all cookies */
740
741         /* otherwise we should display all of the log entries here.
742          * Note that a record may end in the middle, in which case
743          * we should start over with the cookie value of the start
744          * of that record.
745          */
746         for (ix = 0; ix < nwords;) {
747             /* start of a record */
748             rlength = (bufferp[ix] >> 24) & 0xff;
749             if (rlength <= 0) {
750                 fprintf(outFilep, "Internal error: 0 length record\n");
751                 retVal = -1;
752                 goto done;
753             }
754             /* ensure that entire record fits */
755             if (ix + rlength > nwords) {
756                 /* doesn't fit, adjust cookie and break */
757                 break;
758             }
759             /* print the record */
760             DisplayRecord(outFilep, &bufferp[ix], rlength);
761             ix += rlength;
762 #ifdef notdef
763             /* obsolete: read entire buffer first */
764             i += rlength;       /* update cookie value, too */
765 #endif
766         }                       /* for loop displaying buffer */
767     }                           /* for loop over all logs */
768
769   done:
770     free(bufferp);
771     return (retVal);
772 }
773
774 /* clear out log 'name' */
775 int
776 icl_ClearLog(char *name)
777 {
778     afs_int32 code;
779
780     code = afs_syscall(AFSCALL_ICL, ICL_OP_CLRLOG, (long)name, 0, 0, 0, 0, 0);
781     return code;
782 }
783
784 /* clear out set 'name' */
785 int
786 icl_ClearSet(char *name)
787 {
788     afs_int32 code;
789
790     code = afs_syscall(AFSCALL_ICL, ICL_OP_CLRSET, (long)name, 0, 0, 0, 0, 0);
791     return code;
792 }
793
794 /* clear out all logs */
795 int
796 icl_ClearAll(void)
797 {
798     afs_int32 code;
799
800     code = afs_syscall(AFSCALL_ICL, ICL_OP_CLRALL, 0, 0, 0, 0, 0, 0);
801     return code;
802 }
803
804 /* list out all available sets to outFileP */
805 int
806 icl_ListSets(FILE *outFileP)
807 {
808     int i;
809     afs_int32 code = 0;
810     afs_int32 states;
811     char tname[64];
812
813     for (i = 0; i < 1000; i++) {
814         code =
815             afs_syscall(AFSCALL_ICL, ICL_OP_ENUMSETS, i, (long)tname,
816                         sizeof(tname), (long)&states, 0, 0);
817         if (code)
818             break;
819         (void)fprintf(outFileP, "%s %s%s%s\n", tname,
820                       (states & ICL_SETF_ACTIVE) ? "active" : "inactive",
821                       (states & ICL_SETF_FREED) ? " (dormant)" : "",
822                       (states & ICL_SETF_PERSISTENT) ? " persistent" : "");
823     }
824
825     return 0;
826 }
827
828 /* list out all available logs to outFileP */
829 int
830 icl_ListLogs(FILE *outFileP, int int32flg)
831 {
832     int i;
833     int allocated;
834     afs_int32 code = 0;
835     afs_int32 logSize;
836     char tname[64];
837
838     for (i = 0; i < 1000; i++) {
839         code =
840             afs_syscall(AFSCALL_ICL, ICL_OP_ENUMLOGS, i, (long)tname,
841                         sizeof(tname), (long)&logSize, 0, 0);
842         if (code)
843             break;
844         if (int32flg) {
845             /* get more information on the log */
846             code =
847                 afs_syscall(AFSCALL_ICL, ICL_OP_GETLOGINFO, (long)tname,
848                             (long)&logSize, (long)&allocated, 0, 0, 0);
849             if (code)
850                 break;
851             (void)fprintf(outFileP, "%s : %d kbytes (%s)\n", tname,
852                           logSize / 1024,
853                           allocated ? "allocated" : "unallocated");
854         } else
855             (void)fprintf(outFileP, "%s\n", tname);
856     }
857
858     return 0;
859 }
860
861 /* list out all available logs to outFileP */
862 int
863 icl_ListLogsBySet(FILE *outFileP, char *setname, int int32flg)
864 {
865     int i;
866     afs_int32 code = 0;
867     afs_int32 logSize;
868     int allocated;
869     char tname[64];
870
871     for (i = 0; i < ICL_LOGSPERSET; i++) {
872         code =
873             afs_syscall(AFSCALL_ICL, ICL_OP_ENUMLOGSBYSET, (long)setname, i,
874                         (long)tname, sizeof(tname), 0, 0);
875         if (code) {
876             if (errno == EBADF) {
877                 code = 0;
878                 continue;       /* missing */
879             }
880             break;
881         }
882         if (int32flg) {
883             /* get more information on the log */
884             code =
885                 afs_syscall(AFSCALL_ICL, ICL_OP_GETLOGINFO, (long)tname,
886                             (long)&logSize, (long)&allocated, 0, 0, 0);
887             if (code)
888                 break;
889             (void)fprintf(outFileP, "%s : %d kbytes (%s)\n", tname,
890                           logSize / 1024,
891                           allocated ? "allocated" : "unallocated");
892         } else
893             (void)fprintf(outFileP, "%s\n", tname);
894     }
895
896     return code;
897 }
898
899 /* activate/deactivate/free specified set */
900 int
901 icl_ChangeSetState(char *name, afs_int32 op)
902 {
903     afs_int32 code;
904
905     code = afs_syscall(AFSCALL_ICL, ICL_OP_SETSTAT, (long)name, op, 0, 0, 0, 0);
906     return code;
907 }
908
909 /* activate/deactivate/free all sets */
910 int
911 icl_ChangeAllSetState(afs_int32 op)
912 {
913     afs_int32 code;
914
915     code = afs_syscall(AFSCALL_ICL, ICL_OP_SETSTATALL, op, 0, 0, 0, 0, 0);
916     return code;
917 }
918
919 /* set size if log */
920 int
921 icl_ChangeLogSize(char *name, afs_int32 logSize)
922 {
923     afs_int32 code;
924
925     code =
926         afs_syscall(AFSCALL_ICL, ICL_OP_SETLOGSIZE, (long)name, logSize, 0,
927                     0, 0, 0);
928     return code;
929 }
930
931 /* get logsize of specified log */
932 int
933 icl_GetLogsize(char *logname, afs_int32 *logSizeP, int *allocatedP)
934 {
935     afs_int32 code;
936     code =
937         afs_syscall(AFSCALL_ICL, ICL_OP_GETLOGINFO, (long)logname,
938                     (long)logSizeP, (long)allocatedP, 0, 0, 0);
939     return code;
940 }
941
942 /* get state of specified set */
943 int
944 icl_GetSetState(char *setname, afs_int32 *stateP)
945 {
946     afs_int32 code;
947     code =
948         afs_syscall(AFSCALL_ICL, ICL_OP_GETSETINFO, (long)setname,
949                     (long)stateP, 0, 0, 0, 0);
950     return code;
951 }
952
953 int
954 icl_TailKernel(FILE *outFilep, char *logname, afs_int32 waitTime)
955 {
956     afs_int32 bufferSize = 0;
957     afs_int32 newBufferSize;
958     afs_int32 *bufferp;
959     afs_int32 i;
960     afs_int32 code, retVal = 0;
961     afs_int32 nwords;
962     afs_int32 ix;
963     afs_int32 rlength;
964     int allocated;
965
966     /* get information about the specified log */
967     code =
968         afs_syscall(AFSCALL_ICL, ICL_OP_GETLOGINFO, (long)logname,
969                     (long)&bufferSize, (long)&allocated, 0, 0, 0);
970     if (code) {
971         if (errno == ENOENT)
972             (void)fprintf(stderr, "'%s' not found\n", logname);
973         else
974             (void)fprintf(stderr,
975                           "cannot get information on log '%s' (errno = %d)\n",
976                           logname, errno);
977         return -1;
978     }
979
980     if (!allocated) {
981         (void)fprintf(stderr, "'%s' not allocated\n", logname);
982         return 0;
983     }
984
985     if (bufferSize == 0)
986         return -1;
987     bufferp = malloc(sizeof(afs_int32) * bufferSize);
988     if (!bufferp) {
989         (void)fprintf(stderr, "cannot allocate %d words for buffer\n",
990                       bufferSize);
991         return -1;
992     }
993
994     /* start "infinite" loop */
995     for (;;) {
996         /* read out all that's currently there */
997         nwords = 0;             /* total words copied out */
998         i = 0;                  /* initialize cookie */
999         for (;;) {
1000             /* display all the entries in the log */
1001             if (bufferSize - nwords <= 0)
1002                 break;          /* filled whole buffer, clear when done */
1003             code =
1004                 afs_syscall(AFSCALL_ICL, ICL_OP_COPYOUTCLR, (long)logname,
1005                             (long)(bufferp + nwords), bufferSize - nwords,
1006                             (long)&i, 0, 0);
1007             if (code < 0) {
1008                 /* otherwise we've got an error */
1009                 fprintf(stderr, "returned error %d dumping log.\n", errno);
1010                 retVal = -1;
1011                 goto tail_done;
1012             }
1013             /* otherwise, we have flags in the high order byte, and
1014              * a length (in words) in the remainder.
1015              */
1016             code &= 0xffffff;
1017             if (code == 0) {
1018                 /* we're done */
1019                 break;
1020             }
1021             nwords += code;
1022             i += code;
1023         }                       /* for loop over all cookies */
1024
1025         /* otherwise we should display all of the log entries here.
1026          * Note that a record may end in the middle, in which case
1027          * we should start over with the cookie value of the start
1028          * of that record.
1029          */
1030         for (ix = 0; ix < nwords;) {
1031             /* start of a record */
1032             rlength = (bufferp[ix] >> 24) & 0xff;
1033             /* ensure that entire record fits */
1034             if (ix + rlength > nwords) {
1035                 /* doesn't fit, adjust cookie and break */
1036                 if (rlength <= 0) {
1037                     fprintf(stderr, "BOGUS: 0 length record\n");
1038                     retVal = -1;
1039                     goto tail_done;
1040                 }
1041                 break;
1042             }
1043             /* print the record */
1044             DisplayRecord(outFilep, &bufferp[ix], rlength);
1045             ix += rlength;
1046         }                       /* for loop displaying buffer */
1047
1048         if (waitTime)
1049             sleep(waitTime);
1050
1051         /* see if things have changed */
1052         code =
1053             afs_syscall(AFSCALL_ICL, ICL_OP_GETLOGINFO, (long)logname,
1054                         (long)&newBufferSize, (long)&allocated, 0, 0, 0);
1055         if (code) {
1056             if (errno == ENOENT)
1057                 (void)fprintf(stderr, "'%s' not found\n", logname);
1058             else
1059                 (void)fprintf(stderr,
1060                               "cannot get information on log '%s' (errno = %d)\n",
1061                               logname, errno);
1062             retVal = -1;
1063             goto tail_done;
1064         }
1065
1066         if (!allocated) {
1067             (void)fprintf(stderr, "'%s' no int32er allocated\n", logname);
1068             retVal = -1;
1069             goto tail_done;
1070         }
1071
1072         if (bufferSize == 0) {
1073             (void)fprintf(stderr, "buffer size has become 0\n");
1074             retVal = -1;
1075             goto tail_done;
1076         }
1077         if (bufferSize != newBufferSize) {
1078             /* have to reallocate a buffer */
1079             bufferSize = newBufferSize;
1080             free(bufferp);
1081             bufferp = malloc(sizeof(afs_int32) * bufferSize);
1082             if (!bufferp) {
1083                 (void)fprintf(stderr, "cannot allocate %d words for buffer\n",
1084                               bufferSize);
1085                 retVal = -1;
1086                 goto tail_done;
1087             }
1088         }
1089     }                           /* infinite loop */
1090
1091   tail_done:
1092     free(bufferp);
1093     return (retVal);
1094 }
1095
1096 #if !defined(AFS_SGI_ENV)
1097 int
1098 afs_syscall(long call, long parm0, long parm1, long parm2, long parm3,
1099             long parm4, long parm5, long parm6)
1100 {
1101     int code;
1102 #if defined(AFS_DARWIN80_ENV) || defined(AFS_LINUX20_ENV)
1103     int rval;
1104 #endif
1105 #ifdef AFS_LINUX20_ENV
1106 #if defined AFS_LINUX_64BIT_KERNEL
1107     long long eparm[4];
1108     /* don't want to sign extend it to 64bit, so using ulong */
1109     eparm[0] = (unsigned long)parm3;
1110     eparm[1] = (unsigned long)parm4;
1111     eparm[2] = (unsigned long)parm5;
1112     eparm[3] = (unsigned long)parm6;
1113 #else
1114     int eparm[4];
1115     eparm[0] = parm3;
1116     eparm[1] = parm4;
1117     eparm[2] = parm5;
1118     eparm[3] = parm6;
1119 #endif
1120     /* Linux can only handle 5 arguments in the actual syscall. */
1121     if (call == AFSCALL_ICL) {
1122         rval = proc_afs_syscall(call, parm0, parm1, parm2, (long)eparm, &code);
1123         if (rval) {
1124 #ifdef AFS_SYSCALL
1125             code = syscall(AFS_SYSCALL, call, parm0, parm1, parm2, eparm);
1126 #else
1127             code = -1;
1128 #endif
1129         }
1130     } else {
1131         rval = proc_afs_syscall(call, parm0, parm1, parm2, parm3, &code);
1132         if (rval) {
1133 #ifdef AFS_SYSCALL
1134             code = syscall(AFS_SYSCALL, call, parm0, parm1, parm2, parm3);
1135 #else
1136             code = -1;
1137 #endif
1138         }
1139     }
1140 #if defined(AFS_SPARC64_LINUX20_ENV) || defined(AFS_SPARC_LINUX20_ENV)
1141     /* on sparc this function returns none value, so do it myself */
1142     __asm__ __volatile__("mov   %o0, %i0; ret; restore");
1143 #endif
1144 #else
1145 #ifdef AFS_DARWIN80_ENV
1146     code = ioctl_afs_syscall(call, parm0, parm1, parm2, parm3, parm4, parm5, &rval);
1147     if (!code) code = rval;
1148 #else
1149 #if !defined(AFS_SGI_ENV) && !defined(AFS_AIX32_ENV)
1150 # if defined(AFS_SYSCALL)
1151     code = syscall(AFS_SYSCALL, call, parm0, parm1, parm2, parm3, parm4);
1152 # else
1153     code = -1;
1154 # endif
1155 #else
1156 #if defined(AFS_SGI_ENV)
1157     code = syscall(AFS_ICL, call, parm0, parm1, parm2, parm3, parm4);   /* XXX */
1158 #else
1159     code = syscall(AFSCALL_ICL, parm0, parm1, parm2, parm3, parm4);
1160 #endif
1161 #endif
1162 #endif
1163 #endif /* AFS_LINUX20_ENV */
1164     return code;
1165 }
1166 #endif
1167
1168
1169 int icl_inited = 0;
1170
1171 /* init function, called once, under icl_lock */
1172 int
1173 icl_Init(void)
1174 {
1175     icl_inited = 1;
1176
1177 #ifndef KERNEL
1178     /* setup signal handler, in user space */
1179 #endif /* KERNEL */
1180
1181     return 0;
1182 }
1183
1184 int
1185 icl_CreateSet(char *name, struct afs_icl_log *baseLogp,
1186               struct afs_icl_log *fatalLogp, struct afs_icl_set **outSetpp)
1187 {
1188     return icl_CreateSetWithFlags(name, baseLogp, fatalLogp, /*flags */ 0,
1189                                   outSetpp);
1190 }
1191
1192 /* create a set, given pointers to base and fatal logs, if any.
1193  * Logs are unlocked, but referenced, and *outSetpp is returned
1194  * referenced.  Function bumps reference count on logs, since it
1195  * addds references from the new icl_set.  When the set is destroyed,
1196  * those references will be released.
1197  */
1198 int
1199 icl_CreateSetWithFlags(char *name, struct afs_icl_log *baseLogp,
1200                        struct afs_icl_log *fatalLogp, afs_uint32 flags,
1201                        struct afs_icl_set **outSetpp)
1202 {
1203     struct afs_icl_set *setp;
1204     int i;
1205     afs_int32 states = ICL_DEFAULT_SET_STATES;
1206
1207     if (!icl_inited)
1208         icl_Init();
1209
1210     for (setp = icl_allSets; setp; setp = setp->nextp) {
1211         if (strcmp(setp->name, name) == 0) {
1212             setp->refCount++;
1213             *outSetpp = setp;
1214             if (flags & ICL_CRSET_FLAG_PERSISTENT) {
1215                 setp->states |= ICL_SETF_PERSISTENT;
1216             }
1217             return 0;
1218         }
1219     }
1220
1221     /* determine initial state */
1222     if (flags & ICL_CRSET_FLAG_DEFAULT_ON)
1223         states = ICL_SETF_ACTIVE;
1224     else if (flags & ICL_CRSET_FLAG_DEFAULT_OFF)
1225         states = ICL_SETF_FREED;
1226     if (flags & ICL_CRSET_FLAG_PERSISTENT)
1227         states |= ICL_SETF_PERSISTENT;
1228
1229     setp = osi_Alloc(sizeof(struct afs_icl_set));
1230     memset((caddr_t) setp, 0, sizeof(*setp));
1231     setp->refCount = 1;
1232     if (states & ICL_SETF_FREED)
1233         states &= ~ICL_SETF_ACTIVE;     /* if freed, can't be active */
1234     setp->states = states;
1235
1236     setp->name = osi_Alloc(strlen(name) + 1);
1237     strcpy(setp->name, name);
1238     setp->nevents = ICL_DEFAULTEVENTS;
1239     setp->eventFlags = osi_Alloc(ICL_DEFAULTEVENTS);
1240     for (i = 0; i < ICL_DEFAULTEVENTS; i++)
1241         setp->eventFlags[i] = 0xff;     /* default to enabled */
1242
1243     /* update this global info under the icl_lock */
1244     setp->nextp = icl_allSets;
1245     icl_allSets = setp;
1246
1247     /* set's basic lock is still held, so we can finish init */
1248     if (baseLogp) {
1249         setp->logs[0] = baseLogp;
1250         icl_LogHold(baseLogp);
1251         if (!(setp->states & ICL_SETF_FREED))
1252             icl_LogUse(baseLogp);       /* log is actually being used */
1253     }
1254     if (fatalLogp) {
1255         setp->logs[1] = fatalLogp;
1256         icl_LogHold(fatalLogp);
1257         if (!(setp->states & ICL_SETF_FREED))
1258             icl_LogUse(fatalLogp);      /* log is actually being used */
1259     }
1260
1261     *outSetpp = setp;
1262     return 0;
1263 }
1264
1265 /* function to change event enabling information for a particular set */
1266 int
1267 icl_SetEnable(struct afs_icl_set *setp, afs_int32 eventID, int setValue)
1268 {
1269     char *tp;
1270
1271     if (!ICL_EVENTOK(setp, eventID)) {
1272         return -1;
1273     }
1274     tp = &setp->eventFlags[ICL_EVENTBYTE(eventID)];
1275     if (setValue)
1276         *tp |= ICL_EVENTMASK(eventID);
1277     else
1278         *tp &= ~(ICL_EVENTMASK(eventID));
1279     return 0;
1280 }
1281
1282 /* return indication of whether a particular event ID is enabled
1283  * for tracing.  If *getValuep is set to 0, the event is disabled,
1284  * otherwise it is enabled.  All events start out enabled by default.
1285  */
1286 int
1287 icl_GetEnable(struct afs_icl_set *setp, afs_int32 eventID, int *getValuep)
1288 {
1289     if (!ICL_EVENTOK(setp, eventID)) {
1290         return -1;
1291     }
1292     if (setp->eventFlags[ICL_EVENTBYTE(eventID)] & ICL_EVENTMASK(eventID))
1293         *getValuep = 1;
1294     else
1295         *getValuep = 0;
1296     return 0;
1297 }
1298
1299 /* hold and release event sets */
1300 int
1301 icl_SetHold(struct afs_icl_set *setp)
1302 {
1303     setp->refCount++;
1304     return 0;
1305 }
1306
1307 /* free a set.  Called with icl_lock locked */
1308 int
1309 icl_ZapSet(struct afs_icl_set *setp)
1310 {
1311     struct afs_icl_set **lpp, *tp;
1312     int i;
1313     struct afs_icl_log *tlp;
1314
1315     for (lpp = &icl_allSets, tp = *lpp; tp; lpp = &tp->nextp, tp = *lpp) {
1316         if (tp == setp) {
1317             /* found the dude we want to remove */
1318             *lpp = setp->nextp;
1319             osi_Free(setp->name, 1 + strlen(setp->name));
1320             osi_Free(setp->eventFlags, ICL_EVENTBYTES(setp->nevents));
1321             for (i = 0; i < ICL_LOGSPERSET; i++) {
1322                 if ((tlp = setp->logs[i]))
1323                     icl_LogReleNL(tlp);
1324             }
1325             osi_Free(setp, sizeof(struct afs_icl_set));
1326             break;              /* won't find it twice */
1327         }
1328     }
1329     return 0;
1330 }
1331
1332 /* do the release, watching for deleted entries */
1333 int
1334 icl_SetRele(struct afs_icl_set *setp)
1335 {
1336     if (--setp->refCount == 0 && (setp->states & ICL_SETF_DELETED)) {
1337         icl_ZapSet(setp);       /* destroys setp's lock! */
1338     }
1339     return 0;
1340 }
1341
1342 /* free a set entry, dropping its reference count */
1343 int
1344 icl_SetFree(struct afs_icl_set *setp)
1345 {
1346     setp->states |= ICL_SETF_DELETED;
1347     icl_SetRele(setp);
1348     return 0;
1349 }
1350
1351 /* find a set by name, returning it held */
1352 struct afs_icl_set *
1353 icl_FindSet(char *name)
1354 {
1355     struct afs_icl_set *tp;
1356
1357     for (tp = icl_allSets; tp; tp = tp->nextp) {
1358         if (strcmp(tp->name, name) == 0) {
1359             /* this is the dude we want */
1360             tp->refCount++;
1361             break;
1362         }
1363     }
1364     return tp;
1365 }
1366
1367 /* zero out all the logs in the set */
1368 int
1369 icl_ZeroSet(struct afs_icl_set *setp)
1370 {
1371     int i;
1372     int code = 0;
1373     int tcode;
1374     struct afs_icl_log *logp;
1375
1376     for (i = 0; i < ICL_LOGSPERSET; i++) {
1377         logp = setp->logs[i];
1378         if (logp) {
1379             icl_LogHold(logp);
1380             tcode = icl_ZeroLog(logp);
1381             if (tcode != 0)
1382                 code = tcode;   /* save the last bad one */
1383             icl_LogRele(logp);
1384         }
1385     }
1386     return code;
1387 }
1388
1389 int
1390 icl_EnumerateSets(int (*aproc) (char *, void *, struct afs_icl_set *),
1391                   void *arock)
1392 {
1393     struct afs_icl_set *tp, *np;
1394     afs_int32 code;
1395
1396     code = 0;
1397     for (tp = icl_allSets; tp; tp = np) {
1398         tp->refCount++;         /* hold this guy */
1399         code = (*aproc) (tp->name, arock, tp);
1400         np = tp->nextp;         /* tp may disappear next, but not np */
1401         if (--tp->refCount == 0 && (tp->states & ICL_SETF_DELETED))
1402             icl_ZapSet(tp);
1403         if (code)
1404             break;
1405     }
1406     return code;
1407 }
1408
1409 int
1410 icl_AddLogToSet(struct afs_icl_set *setp, struct afs_icl_log *newlogp)
1411 {
1412     int i;
1413     int code = -1;
1414
1415     for (i = 0; i < ICL_LOGSPERSET; i++) {
1416         if (!setp->logs[i]) {
1417             setp->logs[i] = newlogp;
1418             code = i;
1419             icl_LogHold(newlogp);
1420             if (!(setp->states & ICL_SETF_FREED)) {
1421                 /* bump up the number of sets using the log */
1422                 icl_LogUse(newlogp);
1423             }
1424             break;
1425         }
1426     }
1427     return code;
1428 }
1429
1430 int
1431 icl_SetSetStat(struct afs_icl_set *setp, int op)
1432 {
1433     int i;
1434     afs_int32 code;
1435     struct afs_icl_log *logp;
1436
1437     switch (op) {
1438     case ICL_OP_SS_ACTIVATE:    /* activate a log */
1439         /*
1440          * If we are not already active, see if we have released
1441          * our demand that the log be allocated (FREED set).  If
1442          * we have, reassert our desire.
1443          */
1444         if (!(setp->states & ICL_SETF_ACTIVE)) {
1445             if (setp->states & ICL_SETF_FREED) {
1446                 /* have to reassert desire for logs */
1447                 for (i = 0; i < ICL_LOGSPERSET; i++) {
1448                     logp = setp->logs[i];
1449                     if (logp) {
1450                         icl_LogHold(logp);
1451                         icl_LogUse(logp);
1452                         icl_LogRele(logp);
1453                     }
1454                 }
1455                 setp->states &= ~ICL_SETF_FREED;
1456             }
1457             setp->states |= ICL_SETF_ACTIVE;
1458         }
1459         code = 0;
1460         break;
1461
1462     case ICL_OP_SS_DEACTIVATE:  /* deactivate a log */
1463         /* this doesn't require anything beyond clearing the ACTIVE flag */
1464         setp->states &= ~ICL_SETF_ACTIVE;
1465         code = 0;
1466         break;
1467
1468     case ICL_OP_SS_FREE:        /* deassert design for log */
1469         /*
1470          * if we are already in this state, do nothing; otherwise
1471          * deassert desire for log
1472          */
1473         if (setp->states & ICL_SETF_ACTIVE)
1474             code = EINVAL;
1475         else {
1476             if (!(setp->states & ICL_SETF_FREED)) {
1477                 for (i = 0; i < ICL_LOGSPERSET; i++) {
1478                     logp = setp->logs[i];
1479                     if (logp) {
1480                         icl_LogHold(logp);
1481                         icl_LogFreeUse(logp);
1482                         icl_LogRele(logp);
1483                     }
1484                 }
1485                 setp->states |= ICL_SETF_FREED;
1486             }
1487             code = 0;
1488         }
1489         break;
1490
1491     default:
1492         code = EINVAL;
1493     }
1494
1495     return code;
1496 }
1497
1498 struct afs_icl_log *afs_icl_allLogs = 0;
1499
1500 /* hold and release logs */
1501 int
1502 icl_LogHold(struct afs_icl_log *logp)
1503 {
1504     logp->refCount++;
1505     return 0;
1506 }
1507
1508 /* hold and release logs, called with lock already held */
1509 int
1510 icl_LogHoldNL(struct afs_icl_log *logp)
1511 {
1512     logp->refCount++;
1513     return 0;
1514 }
1515
1516 /* keep track of how many sets believe the log itself is allocated */
1517 int
1518 icl_LogUse(struct afs_icl_log *logp)
1519 {
1520     if (logp->setCount == 0) {
1521         /* this is the first set actually using the log -- allocate it */
1522         if (logp->logSize == 0) {
1523             /* we weren't passed in a hint and it wasn't set */
1524             logp->logSize = ICL_DEFAULT_LOGSIZE;
1525         }
1526         logp->datap = osi_Alloc(sizeof(afs_int32) * logp->logSize);
1527     }
1528     logp->setCount++;
1529     return 0;
1530 }
1531
1532 /* decrement the number of real users of the log, free if possible */
1533 int
1534 icl_LogFreeUse(struct afs_icl_log *logp)
1535 {
1536     if (--logp->setCount == 0) {
1537         /* no more users -- free it (but keep log structure around) */
1538         osi_Free(logp->datap, sizeof(afs_int32) * logp->logSize);
1539         logp->firstUsed = logp->firstFree = 0;
1540         logp->logElements = 0;
1541         logp->datap = NULL;
1542     }
1543     return 0;
1544 }
1545
1546 /* set the size of the log to 'logSize' */
1547 int
1548 icl_LogSetSize(struct afs_icl_log *logp, afs_int32 logSize)
1549 {
1550     if (!logp->datap) {
1551         /* nothing to worry about since it's not allocated */
1552         logp->logSize = logSize;
1553     } else {
1554         /* reset log */
1555         logp->firstUsed = logp->firstFree = 0;
1556         logp->logElements = 0;
1557
1558         /* free and allocate a new one */
1559         osi_Free(logp->datap, sizeof(afs_int32) * logp->logSize);
1560         logp->datap = osi_Alloc(sizeof(afs_int32) * logSize);
1561         logp->logSize = logSize;
1562     }
1563
1564     return 0;
1565 }
1566
1567 /* free a log.  Called with icl_lock locked. */
1568 int
1569 icl_ZapLog(struct afs_icl_log *logp)
1570 {
1571     struct afs_icl_log **lpp, *tp;
1572
1573     for (lpp = &afs_icl_allLogs, tp = *lpp; tp; lpp = &tp->nextp, tp = *lpp) {
1574         if (tp == logp) {
1575             /* found the dude we want to remove */
1576             *lpp = logp->nextp;
1577             osi_Free(logp->name, 1 + strlen(logp->name));
1578             osi_Free(logp->datap, logp->logSize * sizeof(afs_int32));
1579             osi_Free(logp, sizeof(struct icl_log));
1580             break;              /* won't find it twice */
1581         }
1582     }
1583     return 0;
1584 }
1585
1586 /* do the release, watching for deleted entries */
1587 int
1588 icl_LogRele(struct afs_icl_log *logp)
1589 {
1590     if (--logp->refCount == 0 && (logp->states & ICL_LOGF_DELETED)) {
1591         icl_ZapLog(logp);       /* destroys logp's lock! */
1592     }
1593     return 0;
1594 }
1595
1596 /* do the release, watching for deleted entries, log already held */
1597 int
1598 icl_LogReleNL(struct afs_icl_log *logp)
1599 {
1600     if (--logp->refCount == 0 && (logp->states & ICL_LOGF_DELETED)) {
1601         icl_ZapLog(logp);       /* destroys logp's lock! */
1602     }
1603     return 0;
1604 }
1605
1606 /* zero out the log */
1607 int
1608 icl_ZeroLog(struct afs_icl_log *logp)
1609 {
1610     logp->firstUsed = logp->firstFree = 0;
1611     logp->logElements = 0;
1612     return 0;
1613 }
1614
1615 /* free a log entry, and drop its reference count */
1616 int
1617 icl_LogFree(struct afs_icl_log *logp)
1618 {
1619     logp->states |= ICL_LOGF_DELETED;
1620     icl_LogRele(logp);
1621     return 0;
1622 }
1623
1624
1625 int
1626 icl_EnumerateLogs(int (*aproc)
1627                     (char *name, void *arock, struct afs_icl_log * tp),
1628                   void *arock)
1629 {
1630     struct afs_icl_log *tp, *np;
1631     afs_int32 code;
1632
1633     code = 0;
1634     for (tp = afs_icl_allLogs; tp; tp = np) {
1635         tp->refCount++;         /* hold this guy */
1636         np = tp->nextp;
1637         code = (*aproc) (tp->name, arock, tp);
1638         if (--tp->refCount == 0)
1639             icl_ZapLog(tp);
1640         if (code)
1641             break;
1642     }
1643     return code;
1644 }
1645
1646
1647 afs_icl_bulkSetinfo_t *
1648 GetBulkSetInfo(void)
1649 {
1650     unsigned int infoSize;
1651
1652     infoSize =
1653         sizeof(afs_icl_bulkSetinfo_t) + (ICL_RPC_MAX_SETS -
1654                                          1) * sizeof(afs_icl_setinfo_t);
1655     if (!setInfo) {
1656         setInfo = calloc(1, infoSize);
1657         if (!setInfo) {
1658             (void)fprintf(stderr,
1659                           "Could not allocate the memory for bulk set info structure\n");
1660             exit(1);
1661         }
1662     }
1663
1664     return setInfo;
1665 }
1666
1667 afs_icl_bulkLoginfo_t *
1668 GetBulkLogInfo(void)
1669 {
1670     unsigned int infoSize;
1671
1672     infoSize =
1673         sizeof(afs_icl_bulkLoginfo_t) + (ICL_RPC_MAX_LOGS -
1674                                          1) * sizeof(afs_icl_loginfo_t);
1675     if (!logInfo) {
1676         logInfo = calloc(1, infoSize);
1677         if (!logInfo) {
1678             (void)fprintf(stderr,
1679                           "Could not allocate the memory for bulk log info structure\n");
1680             exit(1);
1681         }
1682     }
1683
1684     return logInfo;
1685 }
1686
1687
1688 static int
1689 DoDump(struct cmd_syndesc *as, void *arock)
1690 {
1691     afs_int32 code = 0;
1692     afs_int32 tcode;
1693     afs_int32 waitTime = 10 /* seconds */ ;
1694     char *logname;
1695     FILE *outfp = stdout;
1696     time_t startTime;
1697     struct cmd_item *itemp;
1698
1699     if (geteuid() != 0) {
1700         printf("fstrace must be run as root\n");
1701         exit(1);
1702     }
1703
1704     if (as->parms[3].items) {
1705         if (!as->parms[1].items) {
1706             (void)fprintf(stderr, "-sleep can only be used with -follow\n");
1707             return 1;
1708         }
1709         waitTime = strtol(as->parms[3].items->data, NULL, 0);
1710     }
1711
1712     if (as->parms[2].items) {
1713         /* try to open the specified output file */
1714         if ((outfp = fopen(as->parms[2].items->data, "w")) == NULL) {
1715             (void)fprintf(stderr, "Cannot open file '%s' for writing\n",
1716                           as->parms[2].items->data);
1717             return 1;
1718         }
1719     }
1720 #ifdef AFS_SGI64_ENV
1721     startTime = time((time_t *) 0);
1722 #else
1723     startTime = time(0);
1724 #endif
1725     (void)fprintf(outfp, "AFS Trace Dump -\n\n   Date: %s\n",
1726                   ctime(&startTime));
1727
1728     if (as->parms[0].items) {
1729         for (itemp = as->parms[0].items; itemp; itemp = itemp->next) {
1730             tcode = icl_DumpKernel(outfp, itemp->data);
1731             if (tcode) {
1732                 (void)fprintf(stderr, "Unable to dump set %s (errno = %d)\n",
1733                               itemp->data, errno);
1734                 code = tcode;
1735             }
1736         }
1737     } else if (as->parms[1].items) {
1738         logname = as->parms[1].items->data;
1739         code = icl_TailKernel(outfp, logname, waitTime);
1740         if (code) {
1741             (void)fprintf(stderr,
1742                           "Error tailing kernel log '%s' (errno = %d)\n",
1743                           logname, errno);
1744         }
1745     } else
1746         code = icl_DumpKernel(outfp, NULL);
1747
1748     (void)fprintf(outfp, "\nAFS Trace Dump - %s\n",
1749                   code ? "FAILED" : "Completed");
1750
1751     if (outfp != stdout)
1752         (void)fclose(outfp);
1753
1754     return code;
1755 }
1756
1757 static void
1758 SetUpDump(void)
1759 {
1760     struct cmd_syndesc *dumpSyntax;
1761
1762     dumpSyntax =
1763         cmd_CreateSyntax("dump", DoDump, NULL, 0, "dump AFS trace logs");
1764     (void)cmd_AddParm(dumpSyntax, "-set", CMD_LIST, CMD_OPTIONAL,
1765                       "event set name");
1766     (void)cmd_AddParm(dumpSyntax, "-follow", CMD_SINGLE, CMD_OPTIONAL,
1767                       "trace log name");
1768     (void)cmd_AddParm(dumpSyntax, "-file", CMD_SINGLE, CMD_OPTIONAL,
1769                       "path to trace log file for writing");
1770     (void)cmd_AddParm(dumpSyntax, "-sleep", CMD_SINGLE, CMD_OPTIONAL,
1771                       "interval (secs) for writes when using -follow");
1772 }
1773
1774
1775 static int
1776 DoShowLog(struct cmd_syndesc *as, void *arock)
1777 {
1778     afs_int32 retVal = 0;
1779     afs_int32 code = 0;
1780     afs_int32 logSize;
1781     int allocated;
1782     int int32flg = 0;
1783     struct cmd_item *itemp;
1784
1785     if (geteuid() != 0) {
1786         printf("fstrace must be run as root\n");
1787         exit(1);
1788     }
1789     if (as->parms[2].items)
1790         int32flg = 1;
1791
1792     if (as->parms[0].items) {
1793         /* enumerate logs for the specified sets */
1794         for (itemp = as->parms[0].items; itemp; itemp = itemp->next) {
1795             (void)fprintf(stdout, "Logs for set '%s':\n", itemp->data);
1796             code = icl_ListLogsBySet(stdout, itemp->data, int32flg);
1797             if (code) {
1798                 (void)fprintf(stderr,
1799                               "Error in enumerating set %s (errno = %d)\n",
1800                               itemp->data, errno);
1801                 retVal = code;
1802             }
1803         }
1804     } else if (as->parms[1].items) {
1805         /* print out log information */
1806         for (itemp = as->parms[1].items; itemp; itemp = itemp->next) {
1807             code = icl_GetLogsize(itemp->data, &logSize, &allocated);
1808             if (!code)
1809                 (void)fprintf(stdout, "%s : %d kbytes (%s)\n", itemp->data,
1810                               logSize / 1024,
1811                               allocated ? "allocated" : "unallocated");
1812             else {
1813                 (void)fprintf(stderr,
1814                               "Could not find log '%s' (errno = %d)\n",
1815                               itemp->data, errno);
1816                 retVal = code;
1817             }
1818         }
1819     } else {
1820         /* show all logs */
1821         (void)fprintf(stdout, "Available logs:\n");
1822         code = icl_ListLogs(stdout, int32flg);
1823         if (code) {
1824             (void)fprintf(stderr, "Error in listing logs (errno = %d)\n",
1825                           errno);
1826             retVal = code;
1827         }
1828     }
1829
1830     return retVal;
1831 }
1832
1833 static void
1834 SetUpShowLog(void)
1835 {
1836     struct cmd_syndesc *showSyntax;
1837
1838     showSyntax =
1839         cmd_CreateSyntax("lslog", DoShowLog, NULL, 0,
1840                          "list available logs");
1841     (void)cmd_AddParm(showSyntax, "-set", CMD_LIST, CMD_OPTIONAL,
1842                       "event set name");
1843     (void)cmd_AddParm(showSyntax, "-log", CMD_LIST, CMD_OPTIONAL,
1844                       "trace log name");
1845     (void)cmd_AddParm(showSyntax, "-long", CMD_FLAG, CMD_OPTIONAL,
1846                       "show defined log size in kbytes & if it is allocated in kernel mem");
1847 }
1848
1849 static int
1850 DoShowSet(struct cmd_syndesc *as, void *arock)
1851 {
1852     afs_int32 retVal = 0;
1853     afs_int32 code = 0;
1854     afs_int32 state;
1855     struct cmd_item *itemp;
1856
1857     if (geteuid() != 0) {
1858         printf("fstrace must be run as root\n");
1859         exit(1);
1860     }
1861     if (as->parms[0].items) {
1862         /* print information on the specified sets */
1863         for (itemp = as->parms[0].items; itemp; itemp = itemp->next) {
1864             code = icl_GetSetState(itemp->data, &state);
1865             if (code) {
1866                 (void)fprintf(stderr,
1867                               "Error getting status on set %s (errno = %d)\n",
1868                               itemp->data, errno);
1869                 retVal = code;
1870             } else
1871                 (void)fprintf(stdout, "Set %s: %s%s%s\n", itemp->data,
1872                               (state & ICL_SETF_ACTIVE) ? "active" :
1873                               "inactive",
1874                               (state & ICL_SETF_FREED) ? " (dormant)" : "",
1875                               (state & ICL_SETF_PERSISTENT) ? " persistent" :
1876                               "");
1877         }
1878     } else {
1879         /* show all sets */
1880         (void)fprintf(stdout, "Available sets:\n");
1881         code = icl_ListSets(stdout);
1882         if (code) {
1883             (void)fprintf(stderr, "Error in listing sets (errno = %d)\n",
1884                           errno);
1885             retVal = code;
1886         }
1887     }
1888
1889     return retVal;
1890 }
1891
1892 static void
1893 SetUpShowSet(void)
1894 {
1895     struct cmd_syndesc *showSyntax;
1896
1897     showSyntax =
1898         cmd_CreateSyntax("lsset", DoShowSet, NULL, 0,
1899                          "list available event sets");
1900     (void)cmd_AddParm(showSyntax, "-set", CMD_LIST, CMD_OPTIONAL,
1901                       "event set name");
1902 }
1903
1904 static int
1905 DoClear(struct cmd_syndesc *as, void *arock)
1906 {
1907     afs_int32 retVal = 0;
1908     afs_int32 code = 0;
1909     struct cmd_item *itemp;
1910
1911     if (geteuid() != 0) {
1912         printf("fstrace must be run as root\n");
1913         exit(1);
1914     }
1915     if (as->parms[0].items) {
1916         /* clear logs for the specified sets */
1917         for (itemp = as->parms[0].items; itemp; itemp = itemp->next) {
1918             code = icl_ClearSet(itemp->data);
1919             if (code) {
1920                 (void)fprintf(stderr,
1921                               "Error in clearing set %s (errno = %d)\n",
1922                               itemp->data, errno);
1923                 retVal = code;
1924             }
1925         }
1926     } else if (as->parms[1].items) {
1927         /* clear specified log */
1928         for (itemp = as->parms[0].items; itemp; itemp = itemp->next) {
1929             code = icl_ClearLog(itemp->data);
1930             if (code) {
1931                 (void)fprintf(stderr,
1932                               "Error in clearing log %s (errno = %d)\n",
1933                               itemp->data, errno);
1934                 retVal = code;
1935             }
1936         }
1937     } else {
1938         /* clear all logs */
1939         code = icl_ClearAll();
1940         if (code) {
1941             (void)fprintf(stderr, "Error in clearing logs (errno = %d)\n",
1942                           errno);
1943             retVal = code;
1944         }
1945     }
1946
1947     return retVal;
1948 }
1949
1950 static void
1951 SetUpClear(void)
1952 {
1953     struct cmd_syndesc *clearSyntax;
1954
1955     clearSyntax =
1956         cmd_CreateSyntax("clear", DoClear, NULL, 0,
1957                          "clear logs by logname or by event set");
1958     (void)cmd_AddParm(clearSyntax, "-set", CMD_LIST, CMD_OPTIONAL,
1959                       "event set name");
1960     (void)cmd_AddParm(clearSyntax, "-log", CMD_LIST, CMD_OPTIONAL,
1961                       "trace log name");
1962 }
1963
1964 static int
1965 DoSet(struct cmd_syndesc *as, void *arock)
1966 {
1967     afs_int32 retVal = 0;
1968     afs_int32 code = 0;
1969     int op;
1970     int doFree = 0;
1971     char *operation;
1972     struct cmd_item *itemp;
1973
1974     if (geteuid() != 0) {
1975         printf("fstrace must be run as root\n");
1976         exit(1);
1977     }
1978     if (as->parms[1].items) {
1979         op = ICL_OP_SS_ACTIVATE;
1980         operation = "active";
1981     } else if (as->parms[2].items) {
1982         op = ICL_OP_SS_DEACTIVATE;
1983         operation = "inactive";
1984     } else if (as->parms[3].items) {
1985         op = ICL_OP_SS_DEACTIVATE;
1986         operation = "inactive";
1987         doFree = 1;
1988     } else {
1989         /* assume active" */
1990         op = ICL_OP_SS_ACTIVATE;
1991         operation = "active";
1992     }
1993
1994     if (as->parms[0].items) {
1995         /* activate specified sets */
1996         for (itemp = as->parms[0].items; itemp; itemp = itemp->next) {
1997             code = icl_ChangeSetState(itemp->data, op);
1998             if (code) {
1999                 (void)fprintf(stderr,
2000                               "cannot set state of %s to %s (errno = %d)\n",
2001                               itemp->data, operation, errno);
2002                 retVal = code;
2003             } else if (doFree) {
2004                 /* try to make it dormant as well */
2005                 code = icl_ChangeSetState(itemp->data, ICL_OP_SS_FREE);
2006                 if (code) {
2007                     (void)fprintf(stderr,
2008                                   "cannot set state of %s to dormant (errno = %d)\n",
2009                                   itemp->data, errno);
2010                     retVal = code;
2011                 }
2012             }
2013         }
2014     } else {
2015         /* show all sets */
2016         code = icl_ChangeAllSetState(op);
2017         if (code) {
2018             (void)fprintf(stderr,
2019                           "cannot set the state of all sets to %s (errno = %d)\n",
2020                           operation, errno);
2021             retVal = code;
2022         } else if (doFree) {
2023             /* try to make it dormant as well */
2024             code = icl_ChangeAllSetState(ICL_OP_SS_FREE);
2025             if (code) {
2026                 (void)fprintf(stderr,
2027                               "cannot set the state of all sets to dormant (errno = %d)\n",
2028                               errno);
2029                 retVal = code;
2030             }
2031         }
2032     }
2033
2034     return retVal;
2035 }
2036
2037 static void
2038 SetUpSet(void)
2039 {
2040     struct cmd_syndesc *setSyntax;
2041
2042     setSyntax =
2043         cmd_CreateSyntax("setset", DoSet, NULL, 0,
2044                          "set state of event sets");
2045     (void)cmd_AddParm(setSyntax, "-set", CMD_LIST, CMD_OPTIONAL,
2046                       "event set name");
2047     (void)cmd_AddParm(setSyntax, "-active", CMD_FLAG, CMD_OPTIONAL,
2048                       "enable tracing for event set & allocate kernel memory");
2049     (void)cmd_AddParm(setSyntax, "-inactive", CMD_FLAG, CMD_OPTIONAL,
2050                       "disables tracing for event set, keep kernel memory");
2051     (void)cmd_AddParm(setSyntax, "-dormant", CMD_FLAG, CMD_OPTIONAL,
2052                       "disable tracing for event set & free kernel memory");
2053 }
2054
2055 static int
2056 DoResize(struct cmd_syndesc *as, void *arock)
2057 {
2058     afs_int32 retVal = 0;
2059     afs_int32 code = 0;
2060     afs_int32 bufferSize;
2061     struct cmd_item *itemp;
2062
2063     if (geteuid() != 0) {
2064         printf("fstrace must be run as root\n");
2065         exit(1);
2066     }
2067     /* get buffer size */
2068     bufferSize = atoi(as->parms[1].items->data);
2069     bufferSize *= BUFFER_MULTIPLIER;
2070     if (bufferSize == 0)
2071         bufferSize = ICL_DEFAULT_LOGSIZE;
2072
2073     /* set the size of the specified logs */
2074     if ((itemp = as->parms[0].items)) {
2075         for (; itemp; itemp = itemp->next) {
2076             code = icl_ChangeLogSize(itemp->data, bufferSize);
2077             if (code) {
2078                 (void)fprintf(stderr,
2079                               "Error in changing log %s buffer size (errno = %d)\n",
2080                               itemp->data, errno);
2081                 retVal = code;
2082             }
2083         }
2084     } else {
2085         /* Use the only current support log, "cmfx" */
2086         code = icl_ChangeLogSize("cmfx", bufferSize);
2087         if (code) {
2088             (void)fprintf(stderr,
2089                           "Error in changing log cmfx buffer size (errno = %d)\n",
2090                           errno);
2091             retVal = code;
2092         }
2093     }
2094
2095     return retVal;
2096 }
2097
2098 static void
2099 SetUpResize(void)
2100 {
2101     struct cmd_syndesc *setsizeSyntax;
2102
2103     setsizeSyntax =
2104         cmd_CreateSyntax("setlog", DoResize, NULL, 0,
2105                          "set the size of a log");
2106     (void)cmd_AddParm(setsizeSyntax, "-log", CMD_LIST, CMD_OPTIONAL,
2107                       "trace log name");
2108     (void)cmd_AddParm(setsizeSyntax, "-buffersize", CMD_SINGLE, CMD_REQUIRED,
2109                       "# of 1-kbyte blocks to allocate for log");
2110 }
2111
2112 #include "AFS_component_version_number.c"
2113
2114 int
2115 main(int argc, char *argv[])
2116 {
2117     setlocale(LC_ALL, "");
2118 #ifdef AFS_SGI62_ENV
2119     set_kernel_sizeof_long();
2120 #endif
2121
2122     /* set up user interface then dispatch */
2123     SetUpDump();
2124     SetUpShowLog();
2125     SetUpShowSet();
2126     SetUpClear();
2127     SetUpSet();
2128     SetUpResize();
2129
2130     return (cmd_Dispatch(argc, argv));
2131 }