util: Don't cast returns from malloc()
[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                     code = 0;
665                     continue;   /* missing slot, nothing to worry about */
666                 }
667                 break;
668             }
669             code =
670                 afs_syscall(AFSCALL_ICL, ICL_OP_GETLOGINFO, (long)tname,
671                             (long)&dummy, (long)&dummy2, 0, 0, 0);
672             if (code)
673                 break;
674             found++;
675             if (dummy > bufferSize)     /* find biggest log */
676                 bufferSize = dummy;
677             lip = calloc(1, sizeof(struct logInfo));
678             lip->nextp = allInfo;
679             allInfo = lip;
680             lip->name = strdup(tname);
681         }
682         i = found;
683     } else {
684         /* dump all logs */
685         for (i = 0; i < 1000; i++) {
686             code =
687                 afs_syscall(AFSCALL_ICL, ICL_OP_ENUMLOGS, i, (long)tname,
688                             sizeof(tname), (long)&dummy, 0, 0);
689             if (code)
690                 break;
691             if (dummy > bufferSize)     /* find biggest log */
692                 bufferSize = dummy;
693             lip = calloc(1, sizeof(struct logInfo));
694             lip->nextp = allInfo;
695             allInfo = lip;
696             lip->name = strdup(tname);
697         }
698     }
699
700     if (bufferSize == 0)
701         return -1;
702     bufferp = (afs_int32 *) malloc(sizeof(afs_int32) * bufferSize);
703     if (!bufferp)
704         return -1;
705
706     fprintf(outFilep, "Found %d logs.\n", i);
707
708     /* now print out the contents of each log */
709     for (lip = allInfo; lip; lip = lip->nextp) {
710         fprintf(outFilep, "\nContents of log %s:\n", lip->name);
711         /* read out everything first; gets a more consistent
712          * snapshot.
713          */
714         nwords = 0;             /* total words copied out */
715         for (i = 0;;) {
716             /* display all the entries in the log */
717             if (bufferSize - nwords <= 0)
718                 break;          /* filled whole buffer */
719             code =
720                 afs_syscall(AFSCALL_ICL, ICL_OP_COPYOUT, (long)lip->name,
721                             (long)(bufferp + nwords), bufferSize - nwords,
722                             (long)&i, 0, 0);
723             if (code < 0) {
724                 /* otherwise we've got an error */
725                 fprintf(outFilep, "Returned error %d dumping log.\n", errno);
726                 break;
727             }
728             /* otherwise, we have flags in the high order byte, and
729              * a length (in words) in the remainder.
730              */
731             if ((code >> 24) & ICL_COPYOUTF_MISSEDSOME)
732                 fprintf(outFilep, "Log wrapped; data missing.\n");
733             code &= 0xffffff;
734             if (code == 0) {
735                 /* we're done */
736                 break;
737             }
738             nwords += code;
739             i += code;
740         }                       /* for loop over all cookies */
741
742         /* otherwise we should display all of the log entries here.
743          * Note that a record may end in the middle, in which case
744          * we should start over with the cookie value of the start
745          * of that record.
746          */
747         for (ix = 0; ix < nwords;) {
748             /* start of a record */
749             rlength = (bufferp[ix] >> 24) & 0xff;
750             if (rlength <= 0) {
751                 fprintf(outFilep, "Internal error: 0 length record\n");
752                 retVal = -1;
753                 goto done;
754             }
755             /* ensure that entire record fits */
756             if (ix + rlength > nwords) {
757                 /* doesn't fit, adjust cookie and break */
758                 break;
759             }
760             /* print the record */
761             DisplayRecord(outFilep, &bufferp[ix], rlength);
762             ix += rlength;
763 #ifdef notdef
764             /* obsolete: read entire buffer first */
765             i += rlength;       /* update cookie value, too */
766 #endif
767         }                       /* for loop displaying buffer */
768     }                           /* for loop over all logs */
769
770   done:
771     free(bufferp);
772     return (retVal);
773 }
774
775 /* clear out log 'name' */
776 int
777 icl_ClearLog(char *name)
778 {
779     afs_int32 code;
780
781     code = afs_syscall(AFSCALL_ICL, ICL_OP_CLRLOG, (long)name, 0, 0, 0, 0, 0);
782     return code;
783 }
784
785 /* clear out set 'name' */
786 int
787 icl_ClearSet(char *name)
788 {
789     afs_int32 code;
790
791     code = afs_syscall(AFSCALL_ICL, ICL_OP_CLRSET, (long)name, 0, 0, 0, 0, 0);
792     return code;
793 }
794
795 /* clear out all logs */
796 int
797 icl_ClearAll(void)
798 {
799     afs_int32 code;
800
801     code = afs_syscall(AFSCALL_ICL, ICL_OP_CLRALL, 0, 0, 0, 0, 0, 0);
802     return code;
803 }
804
805 /* list out all available sets to outFileP */
806 int
807 icl_ListSets(FILE *outFileP)
808 {
809     int i;
810     afs_int32 code = 0;
811     afs_int32 states;
812     char tname[64];
813
814     for (i = 0; i < 1000; i++) {
815         code =
816             afs_syscall(AFSCALL_ICL, ICL_OP_ENUMSETS, i, (long)tname,
817                         sizeof(tname), (long)&states, 0, 0);
818         if (code)
819             break;
820         (void)fprintf(outFileP, "%s %s%s%s\n", tname,
821                       (states & ICL_SETF_ACTIVE) ? "active" : "inactive",
822                       (states & ICL_SETF_FREED) ? " (dormant)" : "",
823                       (states & ICL_SETF_PERSISTENT) ? " persistent" : "");
824     }
825
826     return 0;
827 }
828
829 /* list out all available logs to outFileP */
830 int
831 icl_ListLogs(FILE *outFileP, int int32flg)
832 {
833     int i;
834     int allocated;
835     afs_int32 code = 0;
836     afs_int32 logSize;
837     char tname[64];
838
839     for (i = 0; i < 1000; i++) {
840         code =
841             afs_syscall(AFSCALL_ICL, ICL_OP_ENUMLOGS, i, (long)tname,
842                         sizeof(tname), (long)&logSize, 0, 0);
843         if (code)
844             break;
845         if (int32flg) {
846             /* get more information on the log */
847             code =
848                 afs_syscall(AFSCALL_ICL, ICL_OP_GETLOGINFO, (long)tname,
849                             (long)&logSize, (long)&allocated, 0, 0, 0);
850             if (code)
851                 break;
852             (void)fprintf(outFileP, "%s : %d kbytes (%s)\n", tname,
853                           logSize / 1024,
854                           allocated ? "allocated" : "unallocated");
855         } else
856             (void)fprintf(outFileP, "%s\n", tname);
857     }
858
859     return 0;
860 }
861
862 /* list out all available logs to outFileP */
863 int
864 icl_ListLogsBySet(FILE *outFileP, char *setname, int int32flg)
865 {
866     int i;
867     afs_int32 code = 0;
868     afs_int32 logSize;
869     int allocated;
870     char tname[64];
871
872     for (i = 0; i < ICL_LOGSPERSET; i++) {
873         code =
874             afs_syscall(AFSCALL_ICL, ICL_OP_ENUMLOGSBYSET, (long)setname, i,
875                         (long)tname, sizeof(tname), 0, 0);
876         if (code) {
877             if (errno == EBADF) {
878                 code = 0;
879                 continue;       /* missing */
880             }
881             break;
882         }
883         if (int32flg) {
884             /* get more information on the log */
885             code =
886                 afs_syscall(AFSCALL_ICL, ICL_OP_GETLOGINFO, (long)tname,
887                             (long)&logSize, (long)&allocated, 0, 0, 0);
888             if (code)
889                 break;
890             (void)fprintf(outFileP, "%s : %d kbytes (%s)\n", tname,
891                           logSize / 1024,
892                           allocated ? "allocated" : "unallocated");
893         } else
894             (void)fprintf(outFileP, "%s\n", tname);
895     }
896
897     return code;
898 }
899
900 /* activate/deactivate/free specified set */
901 int
902 icl_ChangeSetState(char *name, afs_int32 op)
903 {
904     afs_int32 code;
905
906     code = afs_syscall(AFSCALL_ICL, ICL_OP_SETSTAT, (long)name, op, 0, 0, 0, 0);
907     return code;
908 }
909
910 /* activate/deactivate/free all sets */
911 int
912 icl_ChangeAllSetState(afs_int32 op)
913 {
914     afs_int32 code;
915
916     code = afs_syscall(AFSCALL_ICL, ICL_OP_SETSTATALL, op, 0, 0, 0, 0, 0);
917     return code;
918 }
919
920 /* set size if log */
921 int
922 icl_ChangeLogSize(char *name, afs_int32 logSize)
923 {
924     afs_int32 code;
925
926     code =
927         afs_syscall(AFSCALL_ICL, ICL_OP_SETLOGSIZE, (long)name, logSize, 0,
928                     0, 0, 0);
929     return code;
930 }
931
932 /* get logsize of specified log */
933 int
934 icl_GetLogsize(char *logname, afs_int32 *logSizeP, int *allocatedP)
935 {
936     afs_int32 code;
937     code =
938         afs_syscall(AFSCALL_ICL, ICL_OP_GETLOGINFO, (long)logname,
939                     (long)logSizeP, (long)allocatedP, 0, 0, 0);
940     return code;
941 }
942
943 /* get state of specified set */
944 int
945 icl_GetSetState(char *setname, afs_int32 *stateP)
946 {
947     afs_int32 code;
948     code =
949         afs_syscall(AFSCALL_ICL, ICL_OP_GETSETINFO, (long)setname,
950                     (long)stateP, 0, 0, 0, 0);
951     return code;
952 }
953
954 int
955 icl_TailKernel(FILE *outFilep, char *logname, afs_int32 waitTime)
956 {
957     afs_int32 bufferSize = 0;
958     afs_int32 newBufferSize;
959     afs_int32 *bufferp;
960     afs_int32 i;
961     afs_int32 code, retVal = 0;
962     afs_int32 nwords;
963     afs_int32 ix;
964     afs_int32 rlength;
965     int allocated;
966
967     /* get information about the specified log */
968     code =
969         afs_syscall(AFSCALL_ICL, ICL_OP_GETLOGINFO, (long)logname,
970                     (long)&bufferSize, (long)&allocated, 0, 0, 0);
971     if (code) {
972         if (errno == ENOENT)
973             (void)fprintf(stderr, "'%s' not found\n", logname);
974         else
975             (void)fprintf(stderr,
976                           "cannot get information on log '%s' (errno = %d)\n",
977                           logname, errno);
978         return -1;
979     }
980
981     if (!allocated) {
982         (void)fprintf(stderr, "'%s' not allocated\n", logname);
983         return 0;
984     }
985
986     if (bufferSize == 0)
987         return -1;
988     bufferp = (afs_int32 *) malloc(sizeof(afs_int32) * bufferSize);
989     if (!bufferp) {
990         (void)fprintf(stderr, "cannot allocate %d words for buffer\n",
991                       bufferSize);
992         return -1;
993     }
994
995     /* start "infinite" loop */
996     for (;;) {
997         /* read out all that's currently there */
998         nwords = 0;             /* total words copied out */
999         i = 0;                  /* initialize cookie */
1000         for (;;) {
1001             /* display all the entries in the log */
1002             if (bufferSize - nwords <= 0)
1003                 break;          /* filled whole buffer, clear when done */
1004             code =
1005                 afs_syscall(AFSCALL_ICL, ICL_OP_COPYOUTCLR, (long)logname,
1006                             (long)(bufferp + nwords), bufferSize - nwords,
1007                             (long)&i, 0, 0);
1008             if (code < 0) {
1009                 /* otherwise we've got an error */
1010                 fprintf(stderr, "returned error %d dumping log.\n", errno);
1011                 retVal = -1;
1012                 goto tail_done;
1013             }
1014             /* otherwise, we have flags in the high order byte, and
1015              * a length (in words) in the remainder.
1016              */
1017             code &= 0xffffff;
1018             if (code == 0) {
1019                 /* we're done */
1020                 break;
1021             }
1022             nwords += code;
1023             i += code;
1024         }                       /* for loop over all cookies */
1025
1026         /* otherwise we should display all of the log entries here.
1027          * Note that a record may end in the middle, in which case
1028          * we should start over with the cookie value of the start
1029          * of that record.
1030          */
1031         for (ix = 0; ix < nwords;) {
1032             /* start of a record */
1033             rlength = (bufferp[ix] >> 24) & 0xff;
1034             /* ensure that entire record fits */
1035             if (ix + rlength > nwords) {
1036                 /* doesn't fit, adjust cookie and break */
1037                 if (rlength <= 0) {
1038                     fprintf(stderr, "BOGUS: 0 length record\n");
1039                     retVal = -1;
1040                     goto tail_done;
1041                 }
1042                 break;
1043             }
1044             /* print the record */
1045             DisplayRecord(outFilep, &bufferp[ix], rlength);
1046             ix += rlength;
1047         }                       /* for loop displaying buffer */
1048
1049         if (waitTime)
1050             sleep(waitTime);
1051
1052         /* see if things have changed */
1053         code =
1054             afs_syscall(AFSCALL_ICL, ICL_OP_GETLOGINFO, (long)logname,
1055                         (long)&newBufferSize, (long)&allocated, 0, 0, 0);
1056         if (code) {
1057             if (errno == ENOENT)
1058                 (void)fprintf(stderr, "'%s' not found\n", logname);
1059             else
1060                 (void)fprintf(stderr,
1061                               "cannot get information on log '%s' (errno = %d)\n",
1062                               logname, errno);
1063             retVal = -1;
1064             goto tail_done;
1065         }
1066
1067         if (!allocated) {
1068             (void)fprintf(stderr, "'%s' no int32er allocated\n", logname);
1069             retVal = -1;
1070             goto tail_done;
1071         }
1072
1073         if (bufferSize == 0) {
1074             (void)fprintf(stderr, "buffer size has become 0\n");
1075             retVal = -1;
1076             goto tail_done;
1077         }
1078         if (bufferSize != newBufferSize) {
1079             /* have to reallocate a buffer */
1080             bufferSize = newBufferSize;
1081             free(bufferp);
1082             bufferp = (afs_int32 *) malloc(sizeof(afs_int32) * bufferSize);
1083             if (!bufferp) {
1084                 (void)fprintf(stderr, "cannot allocate %d words for buffer\n",
1085                               bufferSize);
1086                 retVal = -1;
1087                 goto tail_done;
1088             }
1089         }
1090     }                           /* infinite loop */
1091
1092   tail_done:
1093     free(bufferp);
1094     return (retVal);
1095 }
1096
1097 #if !defined(AFS_SGI_ENV)
1098 int
1099 afs_syscall(long call, long parm0, long parm1, long parm2, long parm3,
1100             long parm4, long parm5, long parm6)
1101 {
1102     int code, rval;
1103 #ifdef AFS_LINUX20_ENV
1104 #if defined AFS_LINUX_64BIT_KERNEL
1105     long long eparm[4];
1106     /* don't want to sign extend it to 64bit, so using ulong */
1107     eparm[0] = (unsigned long)parm3;
1108     eparm[1] = (unsigned long)parm4;
1109     eparm[2] = (unsigned long)parm5;
1110     eparm[3] = (unsigned long)parm6;
1111 #else
1112     int eparm[4];
1113     eparm[0] = parm3;
1114     eparm[1] = parm4;
1115     eparm[2] = parm5;
1116     eparm[3] = parm6;
1117 #endif
1118     /* Linux can only handle 5 arguments in the actual syscall. */
1119     if (call == AFSCALL_ICL) {
1120         rval = proc_afs_syscall(call, parm0, parm1, parm2, (long)eparm, &code);
1121         if (rval)
1122             code = syscall(AFS_SYSCALL, call, parm0, parm1, parm2, eparm);
1123     } else {
1124         rval = proc_afs_syscall(call, parm0, parm1, parm2, parm3, &code);
1125         if (rval)
1126             code = syscall(AFS_SYSCALL, call, parm0, parm1, parm2, parm3);
1127     }
1128 #if defined(AFS_SPARC64_LINUX20_ENV) || defined(AFS_SPARC_LINUX20_ENV)
1129     /* on sparc this function returns none value, so do it myself */
1130     __asm__ __volatile__("mov   %o0, %i0; ret; restore");
1131 #endif
1132 #else
1133 #ifdef AFS_DARWIN80_ENV
1134     code = ioctl_afs_syscall(call, parm0, parm1, parm2, parm3, parm4, parm5, &rval);
1135     if (!code) code = rval;
1136 #else
1137 #if !defined(AFS_SGI_ENV) && !defined(AFS_AIX32_ENV)
1138     code = syscall(AFS_SYSCALL, call, parm0, parm1, parm2, parm3, parm4);
1139 #else
1140 #if defined(AFS_SGI_ENV)
1141     code = syscall(AFS_ICL, call, parm0, parm1, parm2, parm3, parm4);   /* XXX */
1142 #else
1143     code = syscall(AFSCALL_ICL, parm0, parm1, parm2, parm3, parm4);
1144 #endif
1145 #endif
1146 #endif
1147 #endif /* AFS_LINUX20_ENV */
1148     return code;
1149 }
1150 #endif
1151
1152
1153 int icl_inited = 0;
1154
1155 /* init function, called once, under icl_lock */
1156 int
1157 icl_Init(void)
1158 {
1159     icl_inited = 1;
1160
1161 #ifndef KERNEL
1162     /* setup signal handler, in user space */
1163 #endif /* KERNEL */
1164
1165     return 0;
1166 }
1167
1168 int
1169 icl_CreateSet(char *name, struct afs_icl_log *baseLogp,
1170               struct afs_icl_log *fatalLogp, struct afs_icl_set **outSetpp)
1171 {
1172     return icl_CreateSetWithFlags(name, baseLogp, fatalLogp, /*flags */ 0,
1173                                   outSetpp);
1174 }
1175
1176 /* create a set, given pointers to base and fatal logs, if any.
1177  * Logs are unlocked, but referenced, and *outSetpp is returned
1178  * referenced.  Function bumps reference count on logs, since it
1179  * addds references from the new icl_set.  When the set is destroyed,
1180  * those references will be released.
1181  */
1182 int
1183 icl_CreateSetWithFlags(char *name, struct afs_icl_log *baseLogp,
1184                        struct afs_icl_log *fatalLogp, afs_uint32 flags,
1185                        struct afs_icl_set **outSetpp)
1186 {
1187     struct afs_icl_set *setp;
1188     int i;
1189     afs_int32 states = ICL_DEFAULT_SET_STATES;
1190
1191     if (!icl_inited)
1192         icl_Init();
1193
1194     for (setp = icl_allSets; setp; setp = setp->nextp) {
1195         if (strcmp(setp->name, name) == 0) {
1196             setp->refCount++;
1197             *outSetpp = setp;
1198             if (flags & ICL_CRSET_FLAG_PERSISTENT) {
1199                 setp->states |= ICL_SETF_PERSISTENT;
1200             }
1201             return 0;
1202         }
1203     }
1204
1205     /* determine initial state */
1206     if (flags & ICL_CRSET_FLAG_DEFAULT_ON)
1207         states = ICL_SETF_ACTIVE;
1208     else if (flags & ICL_CRSET_FLAG_DEFAULT_OFF)
1209         states = ICL_SETF_FREED;
1210     if (flags & ICL_CRSET_FLAG_PERSISTENT)
1211         states |= ICL_SETF_PERSISTENT;
1212
1213     setp = (struct afs_icl_set *)osi_Alloc(sizeof(struct afs_icl_set));
1214     memset((caddr_t) setp, 0, sizeof(*setp));
1215     setp->refCount = 1;
1216     if (states & ICL_SETF_FREED)
1217         states &= ~ICL_SETF_ACTIVE;     /* if freed, can't be active */
1218     setp->states = states;
1219
1220     setp->name = (char *)osi_Alloc(strlen(name) + 1);
1221     strcpy(setp->name, name);
1222     setp->nevents = ICL_DEFAULTEVENTS;
1223     setp->eventFlags = (char *)osi_Alloc(ICL_DEFAULTEVENTS);
1224     for (i = 0; i < ICL_DEFAULTEVENTS; i++)
1225         setp->eventFlags[i] = 0xff;     /* default to enabled */
1226
1227     /* update this global info under the icl_lock */
1228     setp->nextp = icl_allSets;
1229     icl_allSets = setp;
1230
1231     /* set's basic lock is still held, so we can finish init */
1232     if (baseLogp) {
1233         setp->logs[0] = baseLogp;
1234         icl_LogHold(baseLogp);
1235         if (!(setp->states & ICL_SETF_FREED))
1236             icl_LogUse(baseLogp);       /* log is actually being used */
1237     }
1238     if (fatalLogp) {
1239         setp->logs[1] = fatalLogp;
1240         icl_LogHold(fatalLogp);
1241         if (!(setp->states & ICL_SETF_FREED))
1242             icl_LogUse(fatalLogp);      /* log is actually being used */
1243     }
1244
1245     *outSetpp = setp;
1246     return 0;
1247 }
1248
1249 /* function to change event enabling information for a particular set */
1250 int
1251 icl_SetEnable(struct afs_icl_set *setp, afs_int32 eventID, int setValue)
1252 {
1253     char *tp;
1254
1255     if (!ICL_EVENTOK(setp, eventID)) {
1256         return -1;
1257     }
1258     tp = &setp->eventFlags[ICL_EVENTBYTE(eventID)];
1259     if (setValue)
1260         *tp |= ICL_EVENTMASK(eventID);
1261     else
1262         *tp &= ~(ICL_EVENTMASK(eventID));
1263     return 0;
1264 }
1265
1266 /* return indication of whether a particular event ID is enabled
1267  * for tracing.  If *getValuep is set to 0, the event is disabled,
1268  * otherwise it is enabled.  All events start out enabled by default.
1269  */
1270 int
1271 icl_GetEnable(struct afs_icl_set *setp, afs_int32 eventID, int *getValuep)
1272 {
1273     if (!ICL_EVENTOK(setp, eventID)) {
1274         return -1;
1275     }
1276     if (setp->eventFlags[ICL_EVENTBYTE(eventID)] & ICL_EVENTMASK(eventID))
1277         *getValuep = 1;
1278     else
1279         *getValuep = 0;
1280     return 0;
1281 }
1282
1283 /* hold and release event sets */
1284 int
1285 icl_SetHold(struct afs_icl_set *setp)
1286 {
1287     setp->refCount++;
1288     return 0;
1289 }
1290
1291 /* free a set.  Called with icl_lock locked */
1292 int
1293 icl_ZapSet(struct afs_icl_set *setp)
1294 {
1295     struct afs_icl_set **lpp, *tp;
1296     int i;
1297     struct afs_icl_log *tlp;
1298
1299     for (lpp = &icl_allSets, tp = *lpp; tp; lpp = &tp->nextp, tp = *lpp) {
1300         if (tp == setp) {
1301             /* found the dude we want to remove */
1302             *lpp = setp->nextp;
1303             osi_Free(setp->name, 1 + strlen(setp->name));
1304             osi_Free(setp->eventFlags, ICL_EVENTBYTES(setp->nevents));
1305             for (i = 0; i < ICL_LOGSPERSET; i++) {
1306                 if ((tlp = setp->logs[i]))
1307                     icl_LogReleNL(tlp);
1308             }
1309             osi_Free(setp, sizeof(struct afs_icl_set));
1310             break;              /* won't find it twice */
1311         }
1312     }
1313     return 0;
1314 }
1315
1316 /* do the release, watching for deleted entries */
1317 int
1318 icl_SetRele(struct afs_icl_set *setp)
1319 {
1320     if (--setp->refCount == 0 && (setp->states & ICL_SETF_DELETED)) {
1321         icl_ZapSet(setp);       /* destroys setp's lock! */
1322     }
1323     return 0;
1324 }
1325
1326 /* free a set entry, dropping its reference count */
1327 int
1328 icl_SetFree(struct afs_icl_set *setp)
1329 {
1330     setp->states |= ICL_SETF_DELETED;
1331     icl_SetRele(setp);
1332     return 0;
1333 }
1334
1335 /* find a set by name, returning it held */
1336 struct afs_icl_set *
1337 icl_FindSet(char *name)
1338 {
1339     struct afs_icl_set *tp;
1340
1341     for (tp = icl_allSets; tp; tp = tp->nextp) {
1342         if (strcmp(tp->name, name) == 0) {
1343             /* this is the dude we want */
1344             tp->refCount++;
1345             break;
1346         }
1347     }
1348     return tp;
1349 }
1350
1351 /* zero out all the logs in the set */
1352 int
1353 icl_ZeroSet(struct afs_icl_set *setp)
1354 {
1355     int i;
1356     int code = 0;
1357     int tcode;
1358     struct afs_icl_log *logp;
1359
1360     for (i = 0; i < ICL_LOGSPERSET; i++) {
1361         logp = setp->logs[i];
1362         if (logp) {
1363             icl_LogHold(logp);
1364             tcode = icl_ZeroLog(logp);
1365             if (tcode != 0)
1366                 code = tcode;   /* save the last bad one */
1367             icl_LogRele(logp);
1368         }
1369     }
1370     return code;
1371 }
1372
1373 int
1374 icl_EnumerateSets(int (*aproc) (char *, void *, struct afs_icl_set *),
1375                   void *arock)
1376 {
1377     struct afs_icl_set *tp, *np;
1378     afs_int32 code;
1379
1380     code = 0;
1381     for (tp = icl_allSets; tp; tp = np) {
1382         tp->refCount++;         /* hold this guy */
1383         code = (*aproc) (tp->name, arock, tp);
1384         np = tp->nextp;         /* tp may disappear next, but not np */
1385         if (--tp->refCount == 0 && (tp->states & ICL_SETF_DELETED))
1386             icl_ZapSet(tp);
1387         if (code)
1388             break;
1389     }
1390     return code;
1391 }
1392
1393 int
1394 icl_AddLogToSet(struct afs_icl_set *setp, struct afs_icl_log *newlogp)
1395 {
1396     int i;
1397     int code = -1;
1398
1399     for (i = 0; i < ICL_LOGSPERSET; i++) {
1400         if (!setp->logs[i]) {
1401             setp->logs[i] = newlogp;
1402             code = i;
1403             icl_LogHold(newlogp);
1404             if (!(setp->states & ICL_SETF_FREED)) {
1405                 /* bump up the number of sets using the log */
1406                 icl_LogUse(newlogp);
1407             }
1408             break;
1409         }
1410     }
1411     return code;
1412 }
1413
1414 int
1415 icl_SetSetStat(struct afs_icl_set *setp, int op)
1416 {
1417     int i;
1418     afs_int32 code;
1419     struct afs_icl_log *logp;
1420
1421     switch (op) {
1422     case ICL_OP_SS_ACTIVATE:    /* activate a log */
1423         /*
1424          * If we are not already active, see if we have released
1425          * our demand that the log be allocated (FREED set).  If
1426          * we have, reassert our desire.
1427          */
1428         if (!(setp->states & ICL_SETF_ACTIVE)) {
1429             if (setp->states & ICL_SETF_FREED) {
1430                 /* have to reassert desire for logs */
1431                 for (i = 0; i < ICL_LOGSPERSET; i++) {
1432                     logp = setp->logs[i];
1433                     if (logp) {
1434                         icl_LogHold(logp);
1435                         icl_LogUse(logp);
1436                         icl_LogRele(logp);
1437                     }
1438                 }
1439                 setp->states &= ~ICL_SETF_FREED;
1440             }
1441             setp->states |= ICL_SETF_ACTIVE;
1442         }
1443         code = 0;
1444         break;
1445
1446     case ICL_OP_SS_DEACTIVATE:  /* deactivate a log */
1447         /* this doesn't require anything beyond clearing the ACTIVE flag */
1448         setp->states &= ~ICL_SETF_ACTIVE;
1449         code = 0;
1450         break;
1451
1452     case ICL_OP_SS_FREE:        /* deassert design for log */
1453         /*
1454          * if we are already in this state, do nothing; otherwise
1455          * deassert desire for log
1456          */
1457         if (setp->states & ICL_SETF_ACTIVE)
1458             code = EINVAL;
1459         else {
1460             if (!(setp->states & ICL_SETF_FREED)) {
1461                 for (i = 0; i < ICL_LOGSPERSET; i++) {
1462                     logp = setp->logs[i];
1463                     if (logp) {
1464                         icl_LogHold(logp);
1465                         icl_LogFreeUse(logp);
1466                         icl_LogRele(logp);
1467                     }
1468                 }
1469                 setp->states |= ICL_SETF_FREED;
1470             }
1471             code = 0;
1472         }
1473         break;
1474
1475     default:
1476         code = EINVAL;
1477     }
1478
1479     return code;
1480 }
1481
1482 struct afs_icl_log *afs_icl_allLogs = 0;
1483
1484 /* hold and release logs */
1485 int
1486 icl_LogHold(struct afs_icl_log *logp)
1487 {
1488     logp->refCount++;
1489     return 0;
1490 }
1491
1492 /* hold and release logs, called with lock already held */
1493 int
1494 icl_LogHoldNL(struct afs_icl_log *logp)
1495 {
1496     logp->refCount++;
1497     return 0;
1498 }
1499
1500 /* keep track of how many sets believe the log itself is allocated */
1501 int
1502 icl_LogUse(struct afs_icl_log *logp)
1503 {
1504     if (logp->setCount == 0) {
1505         /* this is the first set actually using the log -- allocate it */
1506         if (logp->logSize == 0) {
1507             /* we weren't passed in a hint and it wasn't set */
1508             logp->logSize = ICL_DEFAULT_LOGSIZE;
1509         }
1510         logp->datap =
1511             (afs_int32 *) osi_Alloc(sizeof(afs_int32) * logp->logSize);
1512     }
1513     logp->setCount++;
1514     return 0;
1515 }
1516
1517 /* decrement the number of real users of the log, free if possible */
1518 int
1519 icl_LogFreeUse(struct afs_icl_log *logp)
1520 {
1521     if (--logp->setCount == 0) {
1522         /* no more users -- free it (but keep log structure around) */
1523         osi_Free(logp->datap, sizeof(afs_int32) * logp->logSize);
1524         logp->firstUsed = logp->firstFree = 0;
1525         logp->logElements = 0;
1526         logp->datap = NULL;
1527     }
1528     return 0;
1529 }
1530
1531 /* set the size of the log to 'logSize' */
1532 int
1533 icl_LogSetSize(struct afs_icl_log *logp, afs_int32 logSize)
1534 {
1535     if (!logp->datap) {
1536         /* nothing to worry about since it's not allocated */
1537         logp->logSize = logSize;
1538     } else {
1539         /* reset log */
1540         logp->firstUsed = logp->firstFree = 0;
1541         logp->logElements = 0;
1542
1543         /* free and allocate a new one */
1544         osi_Free(logp->datap, sizeof(afs_int32) * logp->logSize);
1545         logp->datap = (afs_int32 *) osi_Alloc(sizeof(afs_int32) * logSize);
1546         logp->logSize = logSize;
1547     }
1548
1549     return 0;
1550 }
1551
1552 /* free a log.  Called with icl_lock locked. */
1553 int
1554 icl_ZapLog(struct afs_icl_log *logp)
1555 {
1556     struct afs_icl_log **lpp, *tp;
1557
1558     for (lpp = &afs_icl_allLogs, tp = *lpp; tp; lpp = &tp->nextp, tp = *lpp) {
1559         if (tp == logp) {
1560             /* found the dude we want to remove */
1561             *lpp = logp->nextp;
1562             osi_Free(logp->name, 1 + strlen(logp->name));
1563             osi_Free(logp->datap, logp->logSize * sizeof(afs_int32));
1564             osi_Free(logp, sizeof(struct icl_log));
1565             break;              /* won't find it twice */
1566         }
1567     }
1568     return 0;
1569 }
1570
1571 /* do the release, watching for deleted entries */
1572 int
1573 icl_LogRele(struct afs_icl_log *logp)
1574 {
1575     if (--logp->refCount == 0 && (logp->states & ICL_LOGF_DELETED)) {
1576         icl_ZapLog(logp);       /* destroys logp's lock! */
1577     }
1578     return 0;
1579 }
1580
1581 /* do the release, watching for deleted entries, log already held */
1582 int
1583 icl_LogReleNL(struct afs_icl_log *logp)
1584 {
1585     if (--logp->refCount == 0 && (logp->states & ICL_LOGF_DELETED)) {
1586         icl_ZapLog(logp);       /* destroys logp's lock! */
1587     }
1588     return 0;
1589 }
1590
1591 /* zero out the log */
1592 int
1593 icl_ZeroLog(struct afs_icl_log *logp)
1594 {
1595     logp->firstUsed = logp->firstFree = 0;
1596     logp->logElements = 0;
1597     return 0;
1598 }
1599
1600 /* free a log entry, and drop its reference count */
1601 int
1602 icl_LogFree(struct afs_icl_log *logp)
1603 {
1604     logp->states |= ICL_LOGF_DELETED;
1605     icl_LogRele(logp);
1606     return 0;
1607 }
1608
1609
1610 int
1611 icl_EnumerateLogs(int (*aproc)
1612                     (char *name, void *arock, struct afs_icl_log * tp),
1613                   void *arock)
1614 {
1615     struct afs_icl_log *tp;
1616     afs_int32 code;
1617
1618     code = 0;
1619     for (tp = afs_icl_allLogs; tp; tp = tp->nextp) {
1620         tp->refCount++;         /* hold this guy */
1621         code = (*aproc) (tp->name, arock, tp);
1622         if (--tp->refCount == 0)
1623             icl_ZapLog(tp);
1624         if (code)
1625             break;
1626     }
1627     return code;
1628 }
1629
1630
1631 afs_icl_bulkSetinfo_t *
1632 GetBulkSetInfo(void)
1633 {
1634     unsigned int infoSize;
1635
1636     infoSize =
1637         sizeof(afs_icl_bulkSetinfo_t) + (ICL_RPC_MAX_SETS -
1638                                          1) * sizeof(afs_icl_setinfo_t);
1639     if (!setInfo) {
1640         setInfo = calloc(1, infoSize);
1641         if (!setInfo) {
1642             (void)fprintf(stderr,
1643                           "Could not allocate the memory for bulk set info structure\n");
1644             exit(1);
1645         }
1646     }
1647
1648     return setInfo;
1649 }
1650
1651 afs_icl_bulkLoginfo_t *
1652 GetBulkLogInfo(void)
1653 {
1654     unsigned int infoSize;
1655
1656     infoSize =
1657         sizeof(afs_icl_bulkLoginfo_t) + (ICL_RPC_MAX_LOGS -
1658                                          1) * sizeof(afs_icl_loginfo_t);
1659     if (!logInfo) {
1660         logInfo = calloc(1, infoSize);
1661         if (!logInfo) {
1662             (void)fprintf(stderr,
1663                           "Could not allocate the memory for bulk log info structure\n");
1664             exit(1);
1665         }
1666     }
1667
1668     return logInfo;
1669 }
1670
1671
1672 static int
1673 DoDump(struct cmd_syndesc *as, void *arock)
1674 {
1675     afs_int32 code = 0;
1676     afs_int32 tcode;
1677     afs_int32 waitTime = 10 /* seconds */ ;
1678     char *logname;
1679     FILE *outfp = stdout;
1680     time_t startTime;
1681     struct cmd_item *itemp;
1682
1683     if (geteuid() != 0) {
1684         printf("fstrace must be run as root\n");
1685         exit(1);
1686     }
1687
1688     if (as->parms[3].items) {
1689         if (!as->parms[1].items) {
1690             (void)fprintf(stderr, "-sleep can only be used with -follow\n");
1691             return 1;
1692         }
1693         waitTime = strtol(as->parms[3].items->data, NULL, 0);
1694     }
1695
1696     if (as->parms[2].items) {
1697         /* try to open the specified output file */
1698         if ((outfp = fopen(as->parms[2].items->data, "w")) == NULL) {
1699             (void)fprintf(stderr, "Cannot open file '%s' for writing\n",
1700                           as->parms[2].items->data);
1701             return 1;
1702         }
1703     }
1704 #ifdef AFS_SGI64_ENV
1705     startTime = time((time_t *) 0);
1706 #else
1707     startTime = time(0);
1708 #endif
1709     (void)fprintf(outfp, "AFS Trace Dump -\n\n   Date: %s\n",
1710                   ctime(&startTime));
1711
1712     if (as->parms[0].items) {
1713         for (itemp = as->parms[0].items; itemp; itemp = itemp->next) {
1714             tcode = icl_DumpKernel(outfp, itemp->data);
1715             if (tcode) {
1716                 (void)fprintf(stderr, "Unable to dump set %s (errno = %d)\n",
1717                               itemp->data, errno);
1718                 code = tcode;
1719             }
1720         }
1721     } else if (as->parms[1].items) {
1722         logname = as->parms[1].items->data;
1723         code = icl_TailKernel(outfp, logname, waitTime);
1724         if (code) {
1725             (void)fprintf(stderr,
1726                           "Error tailing kernel log '%s' (errno = %d)\n",
1727                           logname, errno);
1728         }
1729     } else
1730         code = icl_DumpKernel(outfp, NULL);
1731
1732     (void)fprintf(outfp, "\nAFS Trace Dump - %s\n",
1733                   code ? "FAILED" : "Completed");
1734
1735     if (outfp != stdout)
1736         (void)fclose(outfp);
1737
1738     return code;
1739 }
1740
1741 static void
1742 SetUpDump(void)
1743 {
1744     struct cmd_syndesc *dumpSyntax;
1745
1746     dumpSyntax =
1747         cmd_CreateSyntax("dump", DoDump, NULL, "dump AFS trace logs");
1748     (void)cmd_AddParm(dumpSyntax, "-set", CMD_LIST, CMD_OPTIONAL,
1749                       "event set name");
1750     (void)cmd_AddParm(dumpSyntax, "-follow", CMD_SINGLE, CMD_OPTIONAL,
1751                       "trace log name");
1752     (void)cmd_AddParm(dumpSyntax, "-file", CMD_SINGLE, CMD_OPTIONAL,
1753                       "path to trace log file for writing");
1754     (void)cmd_AddParm(dumpSyntax, "-sleep", CMD_SINGLE, CMD_OPTIONAL,
1755                       "interval (secs) for writes when using -follow");
1756 }
1757
1758
1759 static int
1760 DoShowLog(struct cmd_syndesc *as, void *arock)
1761 {
1762     afs_int32 retVal = 0;
1763     afs_int32 code = 0;
1764     afs_int32 logSize;
1765     int allocated;
1766     int int32flg = 0;
1767     struct cmd_item *itemp;
1768
1769     if (geteuid() != 0) {
1770         printf("fstrace must be run as root\n");
1771         exit(1);
1772     }
1773     if (as->parms[2].items)
1774         int32flg = 1;
1775
1776     if (as->parms[0].items) {
1777         /* enumerate logs for the specified sets */
1778         for (itemp = as->parms[0].items; itemp; itemp = itemp->next) {
1779             (void)fprintf(stdout, "Logs for set '%s':\n", itemp->data);
1780             code = icl_ListLogsBySet(stdout, itemp->data, int32flg);
1781             if (code) {
1782                 (void)fprintf(stderr,
1783                               "Error in enumerating set %s (errno = %d)\n",
1784                               itemp->data, errno);
1785                 retVal = code;
1786             }
1787         }
1788     } else if (as->parms[1].items) {
1789         /* print out log information */
1790         for (itemp = as->parms[1].items; itemp; itemp = itemp->next) {
1791             code = icl_GetLogsize(itemp->data, &logSize, &allocated);
1792             if (!code)
1793                 (void)fprintf(stdout, "%s : %d kbytes (%s)\n", itemp->data,
1794                               logSize / 1024,
1795                               allocated ? "allocated" : "unallocated");
1796             else {
1797                 (void)fprintf(stderr,
1798                               "Could not find log '%s' (errno = %d)\n",
1799                               itemp->data, errno);
1800                 retVal = code;
1801             }
1802         }
1803     } else {
1804         /* show all logs */
1805         (void)fprintf(stdout, "Available logs:\n");
1806         code = icl_ListLogs(stdout, int32flg);
1807         if (code) {
1808             (void)fprintf(stderr, "Error in listing logs (errno = %d)\n",
1809                           errno);
1810             retVal = code;
1811         }
1812     }
1813
1814     return retVal;
1815 }
1816
1817 static void
1818 SetUpShowLog(void)
1819 {
1820     struct cmd_syndesc *showSyntax;
1821
1822     showSyntax =
1823         cmd_CreateSyntax("lslog", DoShowLog, NULL,
1824                          "list available logs");
1825     (void)cmd_AddParm(showSyntax, "-set", CMD_LIST, CMD_OPTIONAL,
1826                       "event set name");
1827     (void)cmd_AddParm(showSyntax, "-log", CMD_LIST, CMD_OPTIONAL,
1828                       "trace log name");
1829     (void)cmd_AddParm(showSyntax, "-long", CMD_FLAG, CMD_OPTIONAL,
1830                       "show defined log size in kbytes & if it is allocated in kernel mem");
1831 }
1832
1833 static int
1834 DoShowSet(struct cmd_syndesc *as, void *arock)
1835 {
1836     afs_int32 retVal = 0;
1837     afs_int32 code = 0;
1838     afs_int32 state;
1839     struct cmd_item *itemp;
1840
1841     if (geteuid() != 0) {
1842         printf("fstrace must be run as root\n");
1843         exit(1);
1844     }
1845     if (as->parms[0].items) {
1846         /* print information on the specified sets */
1847         for (itemp = as->parms[0].items; itemp; itemp = itemp->next) {
1848             code = icl_GetSetState(itemp->data, &state);
1849             if (code) {
1850                 (void)fprintf(stderr,
1851                               "Error getting status on set %s (errno = %d)\n",
1852                               itemp->data, errno);
1853                 retVal = code;
1854             } else
1855                 (void)fprintf(stdout, "Set %s: %s%s%s\n", itemp->data,
1856                               (state & ICL_SETF_ACTIVE) ? "active" :
1857                               "inactive",
1858                               (state & ICL_SETF_FREED) ? " (dormant)" : "",
1859                               (state & ICL_SETF_PERSISTENT) ? " persistent" :
1860                               "");
1861         }
1862     } else {
1863         /* show all sets */
1864         (void)fprintf(stdout, "Available sets:\n");
1865         code = icl_ListSets(stdout);
1866         if (code) {
1867             (void)fprintf(stderr, "Error in listing sets (errno = %d)\n",
1868                           errno);
1869             retVal = code;
1870         }
1871     }
1872
1873     return retVal;
1874 }
1875
1876 static void
1877 SetUpShowSet(void)
1878 {
1879     struct cmd_syndesc *showSyntax;
1880
1881     showSyntax =
1882         cmd_CreateSyntax("lsset", DoShowSet, NULL,
1883                          "list available event sets");
1884     (void)cmd_AddParm(showSyntax, "-set", CMD_LIST, CMD_OPTIONAL,
1885                       "event set name");
1886 }
1887
1888 static int
1889 DoClear(struct cmd_syndesc *as, void *arock)
1890 {
1891     afs_int32 retVal = 0;
1892     afs_int32 code = 0;
1893     struct cmd_item *itemp;
1894
1895     if (geteuid() != 0) {
1896         printf("fstrace must be run as root\n");
1897         exit(1);
1898     }
1899     if (as->parms[0].items) {
1900         /* clear logs for the specified sets */
1901         for (itemp = as->parms[0].items; itemp; itemp = itemp->next) {
1902             code = icl_ClearSet(itemp->data);
1903             if (code) {
1904                 (void)fprintf(stderr,
1905                               "Error in clearing set %s (errno = %d)\n",
1906                               itemp->data, errno);
1907                 retVal = code;
1908             }
1909         }
1910     } else if (as->parms[1].items) {
1911         /* clear specified log */
1912         for (itemp = as->parms[0].items; itemp; itemp = itemp->next) {
1913             code = icl_ClearLog(itemp->data);
1914             if (code) {
1915                 (void)fprintf(stderr,
1916                               "Error in clearing log %s (errno = %d)\n",
1917                               itemp->data, errno);
1918                 retVal = code;
1919             }
1920         }
1921     } else {
1922         /* clear all logs */
1923         code = icl_ClearAll();
1924         if (code) {
1925             (void)fprintf(stderr, "Error in clearing logs (errno = %d)\n",
1926                           errno);
1927             retVal = code;
1928         }
1929     }
1930
1931     return retVal;
1932 }
1933
1934 static void
1935 SetUpClear(void)
1936 {
1937     struct cmd_syndesc *clearSyntax;
1938
1939     clearSyntax =
1940         cmd_CreateSyntax("clear", DoClear, NULL,
1941                          "clear logs by logname or by event set");
1942     (void)cmd_AddParm(clearSyntax, "-set", CMD_LIST, CMD_OPTIONAL,
1943                       "event set name");
1944     (void)cmd_AddParm(clearSyntax, "-log", CMD_LIST, CMD_OPTIONAL,
1945                       "trace log name");
1946 }
1947
1948 static int
1949 DoSet(struct cmd_syndesc *as, void *arock)
1950 {
1951     afs_int32 retVal = 0;
1952     afs_int32 code = 0;
1953     int op;
1954     int doFree = 0;
1955     char *operation;
1956     struct cmd_item *itemp;
1957
1958     if (geteuid() != 0) {
1959         printf("fstrace must be run as root\n");
1960         exit(1);
1961     }
1962     if (as->parms[1].items) {
1963         op = ICL_OP_SS_ACTIVATE;
1964         operation = "active";
1965     } else if (as->parms[2].items) {
1966         op = ICL_OP_SS_DEACTIVATE;
1967         operation = "inactive";
1968     } else if (as->parms[3].items) {
1969         op = ICL_OP_SS_DEACTIVATE;
1970         operation = "inactive";
1971         doFree = 1;
1972     } else {
1973         /* assume active" */
1974         op = ICL_OP_SS_ACTIVATE;
1975         operation = "active";
1976     }
1977
1978     if (as->parms[0].items) {
1979         /* activate specified sets */
1980         for (itemp = as->parms[0].items; itemp; itemp = itemp->next) {
1981             code = icl_ChangeSetState(itemp->data, op);
1982             if (code) {
1983                 (void)fprintf(stderr,
1984                               "cannot set state of %s to %s (errno = %d)\n",
1985                               itemp->data, operation, errno);
1986                 retVal = code;
1987             } else if (doFree) {
1988                 /* try to make it dormant as well */
1989                 code = icl_ChangeSetState(itemp->data, ICL_OP_SS_FREE);
1990                 if (code) {
1991                     (void)fprintf(stderr,
1992                                   "cannot set state of %s to dormant (errno = %d)\n",
1993                                   itemp->data, errno);
1994                     retVal = code;
1995                 }
1996             }
1997         }
1998     } else {
1999         /* show all sets */
2000         code = icl_ChangeAllSetState(op);
2001         if (code) {
2002             (void)fprintf(stderr,
2003                           "cannot set the state of all sets to %s (errno = %d)\n",
2004                           operation, errno);
2005             retVal = code;
2006         } else if (doFree) {
2007             /* try to make it dormant as well */
2008             code = icl_ChangeAllSetState(ICL_OP_SS_FREE);
2009             if (code) {
2010                 (void)fprintf(stderr,
2011                               "cannot set the state of all sets to dormant (errno = %d)\n",
2012                               errno);
2013                 retVal = code;
2014             }
2015         }
2016     }
2017
2018     return retVal;
2019 }
2020
2021 static void
2022 SetUpSet(void)
2023 {
2024     struct cmd_syndesc *setSyntax;
2025
2026     setSyntax =
2027         cmd_CreateSyntax("setset", DoSet, NULL,
2028                          "set state of event sets");
2029     (void)cmd_AddParm(setSyntax, "-set", CMD_LIST, CMD_OPTIONAL,
2030                       "event set name");
2031     (void)cmd_AddParm(setSyntax, "-active", CMD_FLAG, CMD_OPTIONAL,
2032                       "enable tracing for event set & allocate kernel memory");
2033     (void)cmd_AddParm(setSyntax, "-inactive", CMD_FLAG, CMD_OPTIONAL,
2034                       "disables tracing for event set, keep kernel memory");
2035     (void)cmd_AddParm(setSyntax, "-dormant", CMD_FLAG, CMD_OPTIONAL,
2036                       "disable tracing for event set & free kernel memory");
2037 }
2038
2039 static int
2040 DoResize(struct cmd_syndesc *as, void *arock)
2041 {
2042     afs_int32 retVal = 0;
2043     afs_int32 code = 0;
2044     afs_int32 bufferSize;
2045     struct cmd_item *itemp;
2046
2047     if (geteuid() != 0) {
2048         printf("fstrace must be run as root\n");
2049         exit(1);
2050     }
2051     /* get buffer size */
2052     bufferSize = atoi(as->parms[1].items->data);
2053     bufferSize *= BUFFER_MULTIPLIER;
2054     if (bufferSize == 0)
2055         bufferSize = ICL_DEFAULT_LOGSIZE;
2056
2057     /* set the size of the specified logs */
2058     if ((itemp = as->parms[0].items)) {
2059         for (; itemp; itemp = itemp->next) {
2060             code = icl_ChangeLogSize(itemp->data, bufferSize);
2061             if (code) {
2062                 (void)fprintf(stderr,
2063                               "Error in changing log %s buffer size (errno = %d)\n",
2064                               itemp->data, errno);
2065                 retVal = code;
2066             }
2067         }
2068     } else {
2069         /* Use the only current support log, "cmfx" */
2070         code = icl_ChangeLogSize("cmfx", bufferSize);
2071         if (code) {
2072             (void)fprintf(stderr,
2073                           "Error in changing log cmfx buffer size (errno = %d)\n",
2074                           errno);
2075             retVal = code;
2076         }
2077     }
2078
2079     return retVal;
2080 }
2081
2082 static void
2083 SetUpResize(void)
2084 {
2085     struct cmd_syndesc *setsizeSyntax;
2086
2087     setsizeSyntax =
2088         cmd_CreateSyntax("setlog", DoResize, NULL,
2089                          "set the size of a log");
2090     (void)cmd_AddParm(setsizeSyntax, "-log", CMD_LIST, CMD_OPTIONAL,
2091                       "trace log name");
2092     (void)cmd_AddParm(setsizeSyntax, "-buffersize", CMD_SINGLE, CMD_REQUIRED,
2093                       "# of 1-kbyte blocks to allocate for log");
2094 }
2095
2096 #include "AFS_component_version_number.c"
2097
2098 int
2099 main(int argc, char *argv[])
2100 {
2101     setlocale(LC_ALL, "");
2102 #ifdef AFS_SGI62_ENV
2103     set_kernel_sizeof_long();
2104 #endif
2105
2106     /* set up user interface then dispatch */
2107     SetUpDump();
2108     SetUpShowLog();
2109     SetUpShowSet();
2110     SetUpClear();
2111     SetUpSet();
2112     SetUpResize();
2113
2114     return (cmd_Dispatch(argc, argv));
2115 }