fstrace: only declare 'rval' when it is used
[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             code = syscall(AFS_SYSCALL, call, parm0, parm1, parm2, eparm);
1125     } else {
1126         rval = proc_afs_syscall(call, parm0, parm1, parm2, parm3, &code);
1127         if (rval)
1128             code = syscall(AFS_SYSCALL, call, parm0, parm1, parm2, parm3);
1129     }
1130 #if defined(AFS_SPARC64_LINUX20_ENV) || defined(AFS_SPARC_LINUX20_ENV)
1131     /* on sparc this function returns none value, so do it myself */
1132     __asm__ __volatile__("mov   %o0, %i0; ret; restore");
1133 #endif
1134 #else
1135 #ifdef AFS_DARWIN80_ENV
1136     code = ioctl_afs_syscall(call, parm0, parm1, parm2, parm3, parm4, parm5, &rval);
1137     if (!code) code = rval;
1138 #else
1139 #if !defined(AFS_SGI_ENV) && !defined(AFS_AIX32_ENV)
1140     code = syscall(AFS_SYSCALL, call, parm0, parm1, parm2, parm3, parm4);
1141 #else
1142 #if defined(AFS_SGI_ENV)
1143     code = syscall(AFS_ICL, call, parm0, parm1, parm2, parm3, parm4);   /* XXX */
1144 #else
1145     code = syscall(AFSCALL_ICL, parm0, parm1, parm2, parm3, parm4);
1146 #endif
1147 #endif
1148 #endif
1149 #endif /* AFS_LINUX20_ENV */
1150     return code;
1151 }
1152 #endif
1153
1154
1155 int icl_inited = 0;
1156
1157 /* init function, called once, under icl_lock */
1158 int
1159 icl_Init(void)
1160 {
1161     icl_inited = 1;
1162
1163 #ifndef KERNEL
1164     /* setup signal handler, in user space */
1165 #endif /* KERNEL */
1166
1167     return 0;
1168 }
1169
1170 int
1171 icl_CreateSet(char *name, struct afs_icl_log *baseLogp,
1172               struct afs_icl_log *fatalLogp, struct afs_icl_set **outSetpp)
1173 {
1174     return icl_CreateSetWithFlags(name, baseLogp, fatalLogp, /*flags */ 0,
1175                                   outSetpp);
1176 }
1177
1178 /* create a set, given pointers to base and fatal logs, if any.
1179  * Logs are unlocked, but referenced, and *outSetpp is returned
1180  * referenced.  Function bumps reference count on logs, since it
1181  * addds references from the new icl_set.  When the set is destroyed,
1182  * those references will be released.
1183  */
1184 int
1185 icl_CreateSetWithFlags(char *name, struct afs_icl_log *baseLogp,
1186                        struct afs_icl_log *fatalLogp, afs_uint32 flags,
1187                        struct afs_icl_set **outSetpp)
1188 {
1189     struct afs_icl_set *setp;
1190     int i;
1191     afs_int32 states = ICL_DEFAULT_SET_STATES;
1192
1193     if (!icl_inited)
1194         icl_Init();
1195
1196     for (setp = icl_allSets; setp; setp = setp->nextp) {
1197         if (strcmp(setp->name, name) == 0) {
1198             setp->refCount++;
1199             *outSetpp = setp;
1200             if (flags & ICL_CRSET_FLAG_PERSISTENT) {
1201                 setp->states |= ICL_SETF_PERSISTENT;
1202             }
1203             return 0;
1204         }
1205     }
1206
1207     /* determine initial state */
1208     if (flags & ICL_CRSET_FLAG_DEFAULT_ON)
1209         states = ICL_SETF_ACTIVE;
1210     else if (flags & ICL_CRSET_FLAG_DEFAULT_OFF)
1211         states = ICL_SETF_FREED;
1212     if (flags & ICL_CRSET_FLAG_PERSISTENT)
1213         states |= ICL_SETF_PERSISTENT;
1214
1215     setp = osi_Alloc(sizeof(struct afs_icl_set));
1216     memset((caddr_t) setp, 0, sizeof(*setp));
1217     setp->refCount = 1;
1218     if (states & ICL_SETF_FREED)
1219         states &= ~ICL_SETF_ACTIVE;     /* if freed, can't be active */
1220     setp->states = states;
1221
1222     setp->name = osi_Alloc(strlen(name) + 1);
1223     strcpy(setp->name, name);
1224     setp->nevents = ICL_DEFAULTEVENTS;
1225     setp->eventFlags = osi_Alloc(ICL_DEFAULTEVENTS);
1226     for (i = 0; i < ICL_DEFAULTEVENTS; i++)
1227         setp->eventFlags[i] = 0xff;     /* default to enabled */
1228
1229     /* update this global info under the icl_lock */
1230     setp->nextp = icl_allSets;
1231     icl_allSets = setp;
1232
1233     /* set's basic lock is still held, so we can finish init */
1234     if (baseLogp) {
1235         setp->logs[0] = baseLogp;
1236         icl_LogHold(baseLogp);
1237         if (!(setp->states & ICL_SETF_FREED))
1238             icl_LogUse(baseLogp);       /* log is actually being used */
1239     }
1240     if (fatalLogp) {
1241         setp->logs[1] = fatalLogp;
1242         icl_LogHold(fatalLogp);
1243         if (!(setp->states & ICL_SETF_FREED))
1244             icl_LogUse(fatalLogp);      /* log is actually being used */
1245     }
1246
1247     *outSetpp = setp;
1248     return 0;
1249 }
1250
1251 /* function to change event enabling information for a particular set */
1252 int
1253 icl_SetEnable(struct afs_icl_set *setp, afs_int32 eventID, int setValue)
1254 {
1255     char *tp;
1256
1257     if (!ICL_EVENTOK(setp, eventID)) {
1258         return -1;
1259     }
1260     tp = &setp->eventFlags[ICL_EVENTBYTE(eventID)];
1261     if (setValue)
1262         *tp |= ICL_EVENTMASK(eventID);
1263     else
1264         *tp &= ~(ICL_EVENTMASK(eventID));
1265     return 0;
1266 }
1267
1268 /* return indication of whether a particular event ID is enabled
1269  * for tracing.  If *getValuep is set to 0, the event is disabled,
1270  * otherwise it is enabled.  All events start out enabled by default.
1271  */
1272 int
1273 icl_GetEnable(struct afs_icl_set *setp, afs_int32 eventID, int *getValuep)
1274 {
1275     if (!ICL_EVENTOK(setp, eventID)) {
1276         return -1;
1277     }
1278     if (setp->eventFlags[ICL_EVENTBYTE(eventID)] & ICL_EVENTMASK(eventID))
1279         *getValuep = 1;
1280     else
1281         *getValuep = 0;
1282     return 0;
1283 }
1284
1285 /* hold and release event sets */
1286 int
1287 icl_SetHold(struct afs_icl_set *setp)
1288 {
1289     setp->refCount++;
1290     return 0;
1291 }
1292
1293 /* free a set.  Called with icl_lock locked */
1294 int
1295 icl_ZapSet(struct afs_icl_set *setp)
1296 {
1297     struct afs_icl_set **lpp, *tp;
1298     int i;
1299     struct afs_icl_log *tlp;
1300
1301     for (lpp = &icl_allSets, tp = *lpp; tp; lpp = &tp->nextp, tp = *lpp) {
1302         if (tp == setp) {
1303             /* found the dude we want to remove */
1304             *lpp = setp->nextp;
1305             osi_Free(setp->name, 1 + strlen(setp->name));
1306             osi_Free(setp->eventFlags, ICL_EVENTBYTES(setp->nevents));
1307             for (i = 0; i < ICL_LOGSPERSET; i++) {
1308                 if ((tlp = setp->logs[i]))
1309                     icl_LogReleNL(tlp);
1310             }
1311             osi_Free(setp, sizeof(struct afs_icl_set));
1312             break;              /* won't find it twice */
1313         }
1314     }
1315     return 0;
1316 }
1317
1318 /* do the release, watching for deleted entries */
1319 int
1320 icl_SetRele(struct afs_icl_set *setp)
1321 {
1322     if (--setp->refCount == 0 && (setp->states & ICL_SETF_DELETED)) {
1323         icl_ZapSet(setp);       /* destroys setp's lock! */
1324     }
1325     return 0;
1326 }
1327
1328 /* free a set entry, dropping its reference count */
1329 int
1330 icl_SetFree(struct afs_icl_set *setp)
1331 {
1332     setp->states |= ICL_SETF_DELETED;
1333     icl_SetRele(setp);
1334     return 0;
1335 }
1336
1337 /* find a set by name, returning it held */
1338 struct afs_icl_set *
1339 icl_FindSet(char *name)
1340 {
1341     struct afs_icl_set *tp;
1342
1343     for (tp = icl_allSets; tp; tp = tp->nextp) {
1344         if (strcmp(tp->name, name) == 0) {
1345             /* this is the dude we want */
1346             tp->refCount++;
1347             break;
1348         }
1349     }
1350     return tp;
1351 }
1352
1353 /* zero out all the logs in the set */
1354 int
1355 icl_ZeroSet(struct afs_icl_set *setp)
1356 {
1357     int i;
1358     int code = 0;
1359     int tcode;
1360     struct afs_icl_log *logp;
1361
1362     for (i = 0; i < ICL_LOGSPERSET; i++) {
1363         logp = setp->logs[i];
1364         if (logp) {
1365             icl_LogHold(logp);
1366             tcode = icl_ZeroLog(logp);
1367             if (tcode != 0)
1368                 code = tcode;   /* save the last bad one */
1369             icl_LogRele(logp);
1370         }
1371     }
1372     return code;
1373 }
1374
1375 int
1376 icl_EnumerateSets(int (*aproc) (char *, void *, struct afs_icl_set *),
1377                   void *arock)
1378 {
1379     struct afs_icl_set *tp, *np;
1380     afs_int32 code;
1381
1382     code = 0;
1383     for (tp = icl_allSets; tp; tp = np) {
1384         tp->refCount++;         /* hold this guy */
1385         code = (*aproc) (tp->name, arock, tp);
1386         np = tp->nextp;         /* tp may disappear next, but not np */
1387         if (--tp->refCount == 0 && (tp->states & ICL_SETF_DELETED))
1388             icl_ZapSet(tp);
1389         if (code)
1390             break;
1391     }
1392     return code;
1393 }
1394
1395 int
1396 icl_AddLogToSet(struct afs_icl_set *setp, struct afs_icl_log *newlogp)
1397 {
1398     int i;
1399     int code = -1;
1400
1401     for (i = 0; i < ICL_LOGSPERSET; i++) {
1402         if (!setp->logs[i]) {
1403             setp->logs[i] = newlogp;
1404             code = i;
1405             icl_LogHold(newlogp);
1406             if (!(setp->states & ICL_SETF_FREED)) {
1407                 /* bump up the number of sets using the log */
1408                 icl_LogUse(newlogp);
1409             }
1410             break;
1411         }
1412     }
1413     return code;
1414 }
1415
1416 int
1417 icl_SetSetStat(struct afs_icl_set *setp, int op)
1418 {
1419     int i;
1420     afs_int32 code;
1421     struct afs_icl_log *logp;
1422
1423     switch (op) {
1424     case ICL_OP_SS_ACTIVATE:    /* activate a log */
1425         /*
1426          * If we are not already active, see if we have released
1427          * our demand that the log be allocated (FREED set).  If
1428          * we have, reassert our desire.
1429          */
1430         if (!(setp->states & ICL_SETF_ACTIVE)) {
1431             if (setp->states & ICL_SETF_FREED) {
1432                 /* have to reassert desire for logs */
1433                 for (i = 0; i < ICL_LOGSPERSET; i++) {
1434                     logp = setp->logs[i];
1435                     if (logp) {
1436                         icl_LogHold(logp);
1437                         icl_LogUse(logp);
1438                         icl_LogRele(logp);
1439                     }
1440                 }
1441                 setp->states &= ~ICL_SETF_FREED;
1442             }
1443             setp->states |= ICL_SETF_ACTIVE;
1444         }
1445         code = 0;
1446         break;
1447
1448     case ICL_OP_SS_DEACTIVATE:  /* deactivate a log */
1449         /* this doesn't require anything beyond clearing the ACTIVE flag */
1450         setp->states &= ~ICL_SETF_ACTIVE;
1451         code = 0;
1452         break;
1453
1454     case ICL_OP_SS_FREE:        /* deassert design for log */
1455         /*
1456          * if we are already in this state, do nothing; otherwise
1457          * deassert desire for log
1458          */
1459         if (setp->states & ICL_SETF_ACTIVE)
1460             code = EINVAL;
1461         else {
1462             if (!(setp->states & ICL_SETF_FREED)) {
1463                 for (i = 0; i < ICL_LOGSPERSET; i++) {
1464                     logp = setp->logs[i];
1465                     if (logp) {
1466                         icl_LogHold(logp);
1467                         icl_LogFreeUse(logp);
1468                         icl_LogRele(logp);
1469                     }
1470                 }
1471                 setp->states |= ICL_SETF_FREED;
1472             }
1473             code = 0;
1474         }
1475         break;
1476
1477     default:
1478         code = EINVAL;
1479     }
1480
1481     return code;
1482 }
1483
1484 struct afs_icl_log *afs_icl_allLogs = 0;
1485
1486 /* hold and release logs */
1487 int
1488 icl_LogHold(struct afs_icl_log *logp)
1489 {
1490     logp->refCount++;
1491     return 0;
1492 }
1493
1494 /* hold and release logs, called with lock already held */
1495 int
1496 icl_LogHoldNL(struct afs_icl_log *logp)
1497 {
1498     logp->refCount++;
1499     return 0;
1500 }
1501
1502 /* keep track of how many sets believe the log itself is allocated */
1503 int
1504 icl_LogUse(struct afs_icl_log *logp)
1505 {
1506     if (logp->setCount == 0) {
1507         /* this is the first set actually using the log -- allocate it */
1508         if (logp->logSize == 0) {
1509             /* we weren't passed in a hint and it wasn't set */
1510             logp->logSize = ICL_DEFAULT_LOGSIZE;
1511         }
1512         logp->datap = osi_Alloc(sizeof(afs_int32) * logp->logSize);
1513     }
1514     logp->setCount++;
1515     return 0;
1516 }
1517
1518 /* decrement the number of real users of the log, free if possible */
1519 int
1520 icl_LogFreeUse(struct afs_icl_log *logp)
1521 {
1522     if (--logp->setCount == 0) {
1523         /* no more users -- free it (but keep log structure around) */
1524         osi_Free(logp->datap, sizeof(afs_int32) * logp->logSize);
1525         logp->firstUsed = logp->firstFree = 0;
1526         logp->logElements = 0;
1527         logp->datap = NULL;
1528     }
1529     return 0;
1530 }
1531
1532 /* set the size of the log to 'logSize' */
1533 int
1534 icl_LogSetSize(struct afs_icl_log *logp, afs_int32 logSize)
1535 {
1536     if (!logp->datap) {
1537         /* nothing to worry about since it's not allocated */
1538         logp->logSize = logSize;
1539     } else {
1540         /* reset log */
1541         logp->firstUsed = logp->firstFree = 0;
1542         logp->logElements = 0;
1543
1544         /* free and allocate a new one */
1545         osi_Free(logp->datap, sizeof(afs_int32) * logp->logSize);
1546         logp->datap = osi_Alloc(sizeof(afs_int32) * logSize);
1547         logp->logSize = logSize;
1548     }
1549
1550     return 0;
1551 }
1552
1553 /* free a log.  Called with icl_lock locked. */
1554 int
1555 icl_ZapLog(struct afs_icl_log *logp)
1556 {
1557     struct afs_icl_log **lpp, *tp;
1558
1559     for (lpp = &afs_icl_allLogs, tp = *lpp; tp; lpp = &tp->nextp, tp = *lpp) {
1560         if (tp == logp) {
1561             /* found the dude we want to remove */
1562             *lpp = logp->nextp;
1563             osi_Free(logp->name, 1 + strlen(logp->name));
1564             osi_Free(logp->datap, logp->logSize * sizeof(afs_int32));
1565             osi_Free(logp, sizeof(struct icl_log));
1566             break;              /* won't find it twice */
1567         }
1568     }
1569     return 0;
1570 }
1571
1572 /* do the release, watching for deleted entries */
1573 int
1574 icl_LogRele(struct afs_icl_log *logp)
1575 {
1576     if (--logp->refCount == 0 && (logp->states & ICL_LOGF_DELETED)) {
1577         icl_ZapLog(logp);       /* destroys logp's lock! */
1578     }
1579     return 0;
1580 }
1581
1582 /* do the release, watching for deleted entries, log already held */
1583 int
1584 icl_LogReleNL(struct afs_icl_log *logp)
1585 {
1586     if (--logp->refCount == 0 && (logp->states & ICL_LOGF_DELETED)) {
1587         icl_ZapLog(logp);       /* destroys logp's lock! */
1588     }
1589     return 0;
1590 }
1591
1592 /* zero out the log */
1593 int
1594 icl_ZeroLog(struct afs_icl_log *logp)
1595 {
1596     logp->firstUsed = logp->firstFree = 0;
1597     logp->logElements = 0;
1598     return 0;
1599 }
1600
1601 /* free a log entry, and drop its reference count */
1602 int
1603 icl_LogFree(struct afs_icl_log *logp)
1604 {
1605     logp->states |= ICL_LOGF_DELETED;
1606     icl_LogRele(logp);
1607     return 0;
1608 }
1609
1610
1611 int
1612 icl_EnumerateLogs(int (*aproc)
1613                     (char *name, void *arock, struct afs_icl_log * tp),
1614                   void *arock)
1615 {
1616     struct afs_icl_log *tp, *np;
1617     afs_int32 code;
1618
1619     code = 0;
1620     for (tp = afs_icl_allLogs; tp; tp = np) {
1621         tp->refCount++;         /* hold this guy */
1622         np = tp->nextp;
1623         code = (*aproc) (tp->name, arock, tp);
1624         if (--tp->refCount == 0)
1625             icl_ZapLog(tp);
1626         if (code)
1627             break;
1628     }
1629     return code;
1630 }
1631
1632
1633 afs_icl_bulkSetinfo_t *
1634 GetBulkSetInfo(void)
1635 {
1636     unsigned int infoSize;
1637
1638     infoSize =
1639         sizeof(afs_icl_bulkSetinfo_t) + (ICL_RPC_MAX_SETS -
1640                                          1) * sizeof(afs_icl_setinfo_t);
1641     if (!setInfo) {
1642         setInfo = calloc(1, infoSize);
1643         if (!setInfo) {
1644             (void)fprintf(stderr,
1645                           "Could not allocate the memory for bulk set info structure\n");
1646             exit(1);
1647         }
1648     }
1649
1650     return setInfo;
1651 }
1652
1653 afs_icl_bulkLoginfo_t *
1654 GetBulkLogInfo(void)
1655 {
1656     unsigned int infoSize;
1657
1658     infoSize =
1659         sizeof(afs_icl_bulkLoginfo_t) + (ICL_RPC_MAX_LOGS -
1660                                          1) * sizeof(afs_icl_loginfo_t);
1661     if (!logInfo) {
1662         logInfo = calloc(1, infoSize);
1663         if (!logInfo) {
1664             (void)fprintf(stderr,
1665                           "Could not allocate the memory for bulk log info structure\n");
1666             exit(1);
1667         }
1668     }
1669
1670     return logInfo;
1671 }
1672
1673
1674 static int
1675 DoDump(struct cmd_syndesc *as, void *arock)
1676 {
1677     afs_int32 code = 0;
1678     afs_int32 tcode;
1679     afs_int32 waitTime = 10 /* seconds */ ;
1680     char *logname;
1681     FILE *outfp = stdout;
1682     time_t startTime;
1683     struct cmd_item *itemp;
1684
1685     if (geteuid() != 0) {
1686         printf("fstrace must be run as root\n");
1687         exit(1);
1688     }
1689
1690     if (as->parms[3].items) {
1691         if (!as->parms[1].items) {
1692             (void)fprintf(stderr, "-sleep can only be used with -follow\n");
1693             return 1;
1694         }
1695         waitTime = strtol(as->parms[3].items->data, NULL, 0);
1696     }
1697
1698     if (as->parms[2].items) {
1699         /* try to open the specified output file */
1700         if ((outfp = fopen(as->parms[2].items->data, "w")) == NULL) {
1701             (void)fprintf(stderr, "Cannot open file '%s' for writing\n",
1702                           as->parms[2].items->data);
1703             return 1;
1704         }
1705     }
1706 #ifdef AFS_SGI64_ENV
1707     startTime = time((time_t *) 0);
1708 #else
1709     startTime = time(0);
1710 #endif
1711     (void)fprintf(outfp, "AFS Trace Dump -\n\n   Date: %s\n",
1712                   ctime(&startTime));
1713
1714     if (as->parms[0].items) {
1715         for (itemp = as->parms[0].items; itemp; itemp = itemp->next) {
1716             tcode = icl_DumpKernel(outfp, itemp->data);
1717             if (tcode) {
1718                 (void)fprintf(stderr, "Unable to dump set %s (errno = %d)\n",
1719                               itemp->data, errno);
1720                 code = tcode;
1721             }
1722         }
1723     } else if (as->parms[1].items) {
1724         logname = as->parms[1].items->data;
1725         code = icl_TailKernel(outfp, logname, waitTime);
1726         if (code) {
1727             (void)fprintf(stderr,
1728                           "Error tailing kernel log '%s' (errno = %d)\n",
1729                           logname, errno);
1730         }
1731     } else
1732         code = icl_DumpKernel(outfp, NULL);
1733
1734     (void)fprintf(outfp, "\nAFS Trace Dump - %s\n",
1735                   code ? "FAILED" : "Completed");
1736
1737     if (outfp != stdout)
1738         (void)fclose(outfp);
1739
1740     return code;
1741 }
1742
1743 static void
1744 SetUpDump(void)
1745 {
1746     struct cmd_syndesc *dumpSyntax;
1747
1748     dumpSyntax =
1749         cmd_CreateSyntax("dump", DoDump, NULL, "dump AFS trace logs");
1750     (void)cmd_AddParm(dumpSyntax, "-set", CMD_LIST, CMD_OPTIONAL,
1751                       "event set name");
1752     (void)cmd_AddParm(dumpSyntax, "-follow", CMD_SINGLE, CMD_OPTIONAL,
1753                       "trace log name");
1754     (void)cmd_AddParm(dumpSyntax, "-file", CMD_SINGLE, CMD_OPTIONAL,
1755                       "path to trace log file for writing");
1756     (void)cmd_AddParm(dumpSyntax, "-sleep", CMD_SINGLE, CMD_OPTIONAL,
1757                       "interval (secs) for writes when using -follow");
1758 }
1759
1760
1761 static int
1762 DoShowLog(struct cmd_syndesc *as, void *arock)
1763 {
1764     afs_int32 retVal = 0;
1765     afs_int32 code = 0;
1766     afs_int32 logSize;
1767     int allocated;
1768     int int32flg = 0;
1769     struct cmd_item *itemp;
1770
1771     if (geteuid() != 0) {
1772         printf("fstrace must be run as root\n");
1773         exit(1);
1774     }
1775     if (as->parms[2].items)
1776         int32flg = 1;
1777
1778     if (as->parms[0].items) {
1779         /* enumerate logs for the specified sets */
1780         for (itemp = as->parms[0].items; itemp; itemp = itemp->next) {
1781             (void)fprintf(stdout, "Logs for set '%s':\n", itemp->data);
1782             code = icl_ListLogsBySet(stdout, itemp->data, int32flg);
1783             if (code) {
1784                 (void)fprintf(stderr,
1785                               "Error in enumerating set %s (errno = %d)\n",
1786                               itemp->data, errno);
1787                 retVal = code;
1788             }
1789         }
1790     } else if (as->parms[1].items) {
1791         /* print out log information */
1792         for (itemp = as->parms[1].items; itemp; itemp = itemp->next) {
1793             code = icl_GetLogsize(itemp->data, &logSize, &allocated);
1794             if (!code)
1795                 (void)fprintf(stdout, "%s : %d kbytes (%s)\n", itemp->data,
1796                               logSize / 1024,
1797                               allocated ? "allocated" : "unallocated");
1798             else {
1799                 (void)fprintf(stderr,
1800                               "Could not find log '%s' (errno = %d)\n",
1801                               itemp->data, errno);
1802                 retVal = code;
1803             }
1804         }
1805     } else {
1806         /* show all logs */
1807         (void)fprintf(stdout, "Available logs:\n");
1808         code = icl_ListLogs(stdout, int32flg);
1809         if (code) {
1810             (void)fprintf(stderr, "Error in listing logs (errno = %d)\n",
1811                           errno);
1812             retVal = code;
1813         }
1814     }
1815
1816     return retVal;
1817 }
1818
1819 static void
1820 SetUpShowLog(void)
1821 {
1822     struct cmd_syndesc *showSyntax;
1823
1824     showSyntax =
1825         cmd_CreateSyntax("lslog", DoShowLog, NULL,
1826                          "list available logs");
1827     (void)cmd_AddParm(showSyntax, "-set", CMD_LIST, CMD_OPTIONAL,
1828                       "event set name");
1829     (void)cmd_AddParm(showSyntax, "-log", CMD_LIST, CMD_OPTIONAL,
1830                       "trace log name");
1831     (void)cmd_AddParm(showSyntax, "-long", CMD_FLAG, CMD_OPTIONAL,
1832                       "show defined log size in kbytes & if it is allocated in kernel mem");
1833 }
1834
1835 static int
1836 DoShowSet(struct cmd_syndesc *as, void *arock)
1837 {
1838     afs_int32 retVal = 0;
1839     afs_int32 code = 0;
1840     afs_int32 state;
1841     struct cmd_item *itemp;
1842
1843     if (geteuid() != 0) {
1844         printf("fstrace must be run as root\n");
1845         exit(1);
1846     }
1847     if (as->parms[0].items) {
1848         /* print information on the specified sets */
1849         for (itemp = as->parms[0].items; itemp; itemp = itemp->next) {
1850             code = icl_GetSetState(itemp->data, &state);
1851             if (code) {
1852                 (void)fprintf(stderr,
1853                               "Error getting status on set %s (errno = %d)\n",
1854                               itemp->data, errno);
1855                 retVal = code;
1856             } else
1857                 (void)fprintf(stdout, "Set %s: %s%s%s\n", itemp->data,
1858                               (state & ICL_SETF_ACTIVE) ? "active" :
1859                               "inactive",
1860                               (state & ICL_SETF_FREED) ? " (dormant)" : "",
1861                               (state & ICL_SETF_PERSISTENT) ? " persistent" :
1862                               "");
1863         }
1864     } else {
1865         /* show all sets */
1866         (void)fprintf(stdout, "Available sets:\n");
1867         code = icl_ListSets(stdout);
1868         if (code) {
1869             (void)fprintf(stderr, "Error in listing sets (errno = %d)\n",
1870                           errno);
1871             retVal = code;
1872         }
1873     }
1874
1875     return retVal;
1876 }
1877
1878 static void
1879 SetUpShowSet(void)
1880 {
1881     struct cmd_syndesc *showSyntax;
1882
1883     showSyntax =
1884         cmd_CreateSyntax("lsset", DoShowSet, NULL,
1885                          "list available event sets");
1886     (void)cmd_AddParm(showSyntax, "-set", CMD_LIST, CMD_OPTIONAL,
1887                       "event set name");
1888 }
1889
1890 static int
1891 DoClear(struct cmd_syndesc *as, void *arock)
1892 {
1893     afs_int32 retVal = 0;
1894     afs_int32 code = 0;
1895     struct cmd_item *itemp;
1896
1897     if (geteuid() != 0) {
1898         printf("fstrace must be run as root\n");
1899         exit(1);
1900     }
1901     if (as->parms[0].items) {
1902         /* clear logs for the specified sets */
1903         for (itemp = as->parms[0].items; itemp; itemp = itemp->next) {
1904             code = icl_ClearSet(itemp->data);
1905             if (code) {
1906                 (void)fprintf(stderr,
1907                               "Error in clearing set %s (errno = %d)\n",
1908                               itemp->data, errno);
1909                 retVal = code;
1910             }
1911         }
1912     } else if (as->parms[1].items) {
1913         /* clear specified log */
1914         for (itemp = as->parms[0].items; itemp; itemp = itemp->next) {
1915             code = icl_ClearLog(itemp->data);
1916             if (code) {
1917                 (void)fprintf(stderr,
1918                               "Error in clearing log %s (errno = %d)\n",
1919                               itemp->data, errno);
1920                 retVal = code;
1921             }
1922         }
1923     } else {
1924         /* clear all logs */
1925         code = icl_ClearAll();
1926         if (code) {
1927             (void)fprintf(stderr, "Error in clearing logs (errno = %d)\n",
1928                           errno);
1929             retVal = code;
1930         }
1931     }
1932
1933     return retVal;
1934 }
1935
1936 static void
1937 SetUpClear(void)
1938 {
1939     struct cmd_syndesc *clearSyntax;
1940
1941     clearSyntax =
1942         cmd_CreateSyntax("clear", DoClear, NULL,
1943                          "clear logs by logname or by event set");
1944     (void)cmd_AddParm(clearSyntax, "-set", CMD_LIST, CMD_OPTIONAL,
1945                       "event set name");
1946     (void)cmd_AddParm(clearSyntax, "-log", CMD_LIST, CMD_OPTIONAL,
1947                       "trace log name");
1948 }
1949
1950 static int
1951 DoSet(struct cmd_syndesc *as, void *arock)
1952 {
1953     afs_int32 retVal = 0;
1954     afs_int32 code = 0;
1955     int op;
1956     int doFree = 0;
1957     char *operation;
1958     struct cmd_item *itemp;
1959
1960     if (geteuid() != 0) {
1961         printf("fstrace must be run as root\n");
1962         exit(1);
1963     }
1964     if (as->parms[1].items) {
1965         op = ICL_OP_SS_ACTIVATE;
1966         operation = "active";
1967     } else if (as->parms[2].items) {
1968         op = ICL_OP_SS_DEACTIVATE;
1969         operation = "inactive";
1970     } else if (as->parms[3].items) {
1971         op = ICL_OP_SS_DEACTIVATE;
1972         operation = "inactive";
1973         doFree = 1;
1974     } else {
1975         /* assume active" */
1976         op = ICL_OP_SS_ACTIVATE;
1977         operation = "active";
1978     }
1979
1980     if (as->parms[0].items) {
1981         /* activate specified sets */
1982         for (itemp = as->parms[0].items; itemp; itemp = itemp->next) {
1983             code = icl_ChangeSetState(itemp->data, op);
1984             if (code) {
1985                 (void)fprintf(stderr,
1986                               "cannot set state of %s to %s (errno = %d)\n",
1987                               itemp->data, operation, errno);
1988                 retVal = code;
1989             } else if (doFree) {
1990                 /* try to make it dormant as well */
1991                 code = icl_ChangeSetState(itemp->data, ICL_OP_SS_FREE);
1992                 if (code) {
1993                     (void)fprintf(stderr,
1994                                   "cannot set state of %s to dormant (errno = %d)\n",
1995                                   itemp->data, errno);
1996                     retVal = code;
1997                 }
1998             }
1999         }
2000     } else {
2001         /* show all sets */
2002         code = icl_ChangeAllSetState(op);
2003         if (code) {
2004             (void)fprintf(stderr,
2005                           "cannot set the state of all sets to %s (errno = %d)\n",
2006                           operation, errno);
2007             retVal = code;
2008         } else if (doFree) {
2009             /* try to make it dormant as well */
2010             code = icl_ChangeAllSetState(ICL_OP_SS_FREE);
2011             if (code) {
2012                 (void)fprintf(stderr,
2013                               "cannot set the state of all sets to dormant (errno = %d)\n",
2014                               errno);
2015                 retVal = code;
2016             }
2017         }
2018     }
2019
2020     return retVal;
2021 }
2022
2023 static void
2024 SetUpSet(void)
2025 {
2026     struct cmd_syndesc *setSyntax;
2027
2028     setSyntax =
2029         cmd_CreateSyntax("setset", DoSet, NULL,
2030                          "set state of event sets");
2031     (void)cmd_AddParm(setSyntax, "-set", CMD_LIST, CMD_OPTIONAL,
2032                       "event set name");
2033     (void)cmd_AddParm(setSyntax, "-active", CMD_FLAG, CMD_OPTIONAL,
2034                       "enable tracing for event set & allocate kernel memory");
2035     (void)cmd_AddParm(setSyntax, "-inactive", CMD_FLAG, CMD_OPTIONAL,
2036                       "disables tracing for event set, keep kernel memory");
2037     (void)cmd_AddParm(setSyntax, "-dormant", CMD_FLAG, CMD_OPTIONAL,
2038                       "disable tracing for event set & free kernel memory");
2039 }
2040
2041 static int
2042 DoResize(struct cmd_syndesc *as, void *arock)
2043 {
2044     afs_int32 retVal = 0;
2045     afs_int32 code = 0;
2046     afs_int32 bufferSize;
2047     struct cmd_item *itemp;
2048
2049     if (geteuid() != 0) {
2050         printf("fstrace must be run as root\n");
2051         exit(1);
2052     }
2053     /* get buffer size */
2054     bufferSize = atoi(as->parms[1].items->data);
2055     bufferSize *= BUFFER_MULTIPLIER;
2056     if (bufferSize == 0)
2057         bufferSize = ICL_DEFAULT_LOGSIZE;
2058
2059     /* set the size of the specified logs */
2060     if ((itemp = as->parms[0].items)) {
2061         for (; itemp; itemp = itemp->next) {
2062             code = icl_ChangeLogSize(itemp->data, bufferSize);
2063             if (code) {
2064                 (void)fprintf(stderr,
2065                               "Error in changing log %s buffer size (errno = %d)\n",
2066                               itemp->data, errno);
2067                 retVal = code;
2068             }
2069         }
2070     } else {
2071         /* Use the only current support log, "cmfx" */
2072         code = icl_ChangeLogSize("cmfx", bufferSize);
2073         if (code) {
2074             (void)fprintf(stderr,
2075                           "Error in changing log cmfx buffer size (errno = %d)\n",
2076                           errno);
2077             retVal = code;
2078         }
2079     }
2080
2081     return retVal;
2082 }
2083
2084 static void
2085 SetUpResize(void)
2086 {
2087     struct cmd_syndesc *setsizeSyntax;
2088
2089     setsizeSyntax =
2090         cmd_CreateSyntax("setlog", DoResize, NULL,
2091                          "set the size of a log");
2092     (void)cmd_AddParm(setsizeSyntax, "-log", CMD_LIST, CMD_OPTIONAL,
2093                       "trace log name");
2094     (void)cmd_AddParm(setsizeSyntax, "-buffersize", CMD_SINGLE, CMD_REQUIRED,
2095                       "# of 1-kbyte blocks to allocate for log");
2096 }
2097
2098 #include "AFS_component_version_number.c"
2099
2100 int
2101 main(int argc, char *argv[])
2102 {
2103     setlocale(LC_ALL, "");
2104 #ifdef AFS_SGI62_ENV
2105     set_kernel_sizeof_long();
2106 #endif
2107
2108     /* set up user interface then dispatch */
2109     SetUpDump();
2110     SetUpShowLog();
2111     SetUpShowSet();
2112     SetUpClear();
2113     SetUpSet();
2114     SetUpResize();
2115
2116     return (cmd_Dispatch(argc, argv));
2117 }