afsmonitor: avoid double free on exit
[openafs.git] / src / afsmonitor / afsmonitor.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  * Portions Copyright (c) 2003 Apple Computer, Inc.
10  */
11
12 /*
13  * Afsmonitor: An AFS Performance Monitoring Tool
14  *
15  *-------------------------------------------------------------------------*/
16
17
18 #include <afsconfig.h>
19 #include <afs/param.h>
20
21 #include <roken.h>
22
23 #include <math.h>
24 #include <ctype.h>
25
26 #include <afs/cmd.h>
27
28 #include <afs/gtxwindows.h>             /*Generic window package */
29 #include <afs/gtxobjects.h>             /*Object definitions */
30 #include <afs/gtxlightobj.h>    /*Light object interface */
31 #include <afs/gtxcurseswin.h>   /*Curses window package */
32 #include <afs/gtxdumbwin.h>             /*Dumb terminal window package */
33 #include <afs/gtxX11win.h>              /*X11 window package */
34 #include <afs/gtxframe.h>               /*Frame package */
35 #include <afs/gtxinput.h>
36
37 #include <afs/xstat_fs.h>
38 #include <afs/xstat_cm.h>
39
40 #include "afsmonitor.h"
41
42 /* command line parameter indices */
43
44 #define P_CONFIG        0
45 #define P_FREQUENCY     1
46 #define P_OUTPUT        2
47 #define P_DETAILED      3
48 /* #define P_PACKAGE    X */
49 #define P_DEBUG         4
50 #define P_FSHOSTS       5
51 #define P_CMHOSTS       6
52 #define P_BUFFERS       7
53
54
55 int afsmon_debug = 0;           /* debug info to file ? */
56 FILE *debugFD;                  /* debugging file descriptor */
57 static int afsmon_output = 0;   /* output to file ? */
58 static int afsmon_detOutput = 0;        /* detailed output ? */
59 int afsmon_probefreq;           /* probe frequency */
60 static int wpkg_to_use;         /* graphics package to use */
61 static char output_filename[80];        /* output filename */
62 char errMsg[256];               /* buffers used to print error messages after */
63 char errMsg1[256];              /* gtx is initialized (stderr/stdout gone !) */
64 int num_bufSlots = 0;           /* number of slots in fs & cm circular buffers */
65
66 /* Flags used to process "show" directives in config file */
67 short fs_showFlags[NUM_FS_STAT_ENTRIES];
68 short cm_showFlags[NUM_CM_STAT_ENTRIES];
69
70
71 /* afsmonitor misc definitions */
72
73 #define DEFAULT_FREQUENCY 60    /* default proble frequency in seconds */
74 #define DEFAULT_BUFSLOTS  0     /* default number of buffer slots */
75 #define CFG_STR_LEN     80      /* max length of config file fields */
76 #define FS 1                    /* for misc. use */
77 #define CM 2                    /* for misc. use */
78
79
80 #define NUM_XSTAT_FS_AFS_PERFSTATS_LONGS 70     /* number of fields from struct afs_PerfStats that we display */
81 #define NUM_AFS_STATS_CMPERF_LONGS 40   /* number of longs in struct afs_stats_CMPerf excluding up/down stats and fields we dont display */
82
83
84 /* variables used for exec'ing user provided threshold handlers */
85 char *fsHandler_argv[20];       /* *argv[] for the handler */
86 char fsHandler_args[20][256];   /* buffer space for arguments */
87 int exec_fsThreshHandler = 0;   /* execute fs threshold handler ? */
88
89
90 /* THRESHOLD STRUCTURE DEFINITIONS */
91
92 /* flag to indicate that threshold entries apply to all hosts. these will
93    be turned off when the first fs or cm host entry is processed */
94 static int global_ThreshFlag = 1;
95 static int global_fsThreshCount = 0;    /* number of global fs thresholds */
96 static int global_cmThreshCount = 0;    /* number of global cm thresholds */
97
98
99
100 /* Linked lists of file server and cache manager host names are made from
101 the entries in the config file. Head pointers to FS and CM server name lists. */
102 static struct afsmon_hostEntry *FSnameList;
103 static struct afsmon_hostEntry *CMnameList;
104
105 /* number of fileservers and cache managers to monitor */
106 int numFS = 0;
107 int numCM = 0;
108
109 /* number of xstat collection ids */
110 #define MAX_NUM_FS_COLLECTIONS 2
111 #define MAX_NUM_CM_COLLECTIONS 1
112 int num_fs_collections = 0;
113 int num_cm_collections = 0;
114
115 /* variables used for processing config file */
116 /* ptr to the hostEntry structure of the last "fs" or "cm" entry processed
117 in the config file */
118 static struct afsmon_hostEntry *last_hostEntry;
119 /* names of the last host processed in the config file */
120 static char last_fsHost[HOST_NAME_LEN];
121 static char last_cmHost[HOST_NAME_LEN];
122 static int lastHostType = 0;    /* 0 = no host entries processed
123                                  * 1 = last host was file server
124                                  * 2 = last host was cache manager. */
125
126
127 /* FILE SERVER CIRCULAR BUFFER VARIABLES  */
128
129 struct afsmon_fs_Results_list {
130     struct xstat_fs_ProbeResults *fsResults[MAX_NUM_FS_COLLECTIONS];
131     int empty[MAX_NUM_FS_COLLECTIONS];
132     struct afsmon_fs_Results_list *next;
133 };
134
135 struct afsmon_fs_Results_CBuffer {
136     int probeNum;               /* probe number of entries in this slot */
137     struct afsmon_fs_Results_list *list;        /* ptr to list of results */
138 };
139
140 int afsmon_fs_results_length[] =
141     { XSTAT_FS_FULLPERF_RESULTS_LEN, XSTAT_FS_CBSTATS_RESULTS_LEN };
142
143 /* buffer for FS probe results */
144 struct afsmon_fs_Results_CBuffer *afsmon_fs_ResultsCB;
145
146 int afsmon_fs_curr_CBindex = 0; /* current fs CB slot */
147
148 /* Probe number variables. The current probe number is incremented
149 when the first probe from a new probe cycle is received. The prev probe
150 number is incremented when the last probe of the current cycle is
151 received. This difference is because of the purpose for which these
152 counters are used */
153
154 int afsmon_fs_curr_probeNum = 1;        /* current fs probe number */
155 int afsmon_fs_prev_probeNum = 0;        /* previous fs probe number */
156
157
158 /* CACHE MANAGER CIRCULAR BUFFER VARIABLES  */
159
160 struct afsmon_cm_Results_list {
161     struct xstat_cm_ProbeResults *cmResults[MAX_NUM_CM_COLLECTIONS];
162     int empty[MAX_NUM_CM_COLLECTIONS];
163     struct afsmon_cm_Results_list *next;
164 };
165
166 struct afsmon_cm_Results_CBuffer {
167     int probeNum;               /* probe number of entries in this slot */
168     struct afsmon_cm_Results_list *list;        /* ptr to list of results */
169 };
170
171 int afsmon_cm_results_length[] = { XSTAT_CM_FULLPERF_RESULTS_LEN };
172
173 /* buffer for CM probe results */
174 struct afsmon_cm_Results_CBuffer *afsmon_cm_ResultsCB;
175
176 int afsmon_cm_curr_CBindex = 0; /* current cm CB slot */
177
178
179 /* Probe number variables. The current probe number is incremented
180 when the first probe from a new probe cycle is received. The prev probe
181 number is incremented when the last probe of the current cycle is
182 received. This difference is because of the purpose for which these
183 counters are used */
184
185 int afsmon_cm_curr_probeNum = 1;        /* current cm probe number */
186 int afsmon_cm_prev_probeNum = 0;        /* previous cm probe number */
187
188
189 /* Structures to hold FS & CM results in string format(suitable for display ) */
190
191 /* ptr to array holding the results of FS probes in ascii format */
192         /* for current probe cycle */
193 struct fs_Display_Data *curr_fsData = (struct fs_Display_Data *)0;
194         /* for previous probe cycle */
195 struct fs_Display_Data *prev_fsData = (struct fs_Display_Data *)0;
196
197
198 /* ptr to array holding the results of CM probes in ascii format */
199         /* for current probe cycle */
200 struct cm_Display_Data *curr_cmData = (struct cm_Display_Data *)0;
201         /* for previous probe cycle */
202 struct cm_Display_Data *prev_cmData = (struct cm_Display_Data *)0;
203
204 /* EXTERN DEFINITIONS */
205
206 /* file server and cache manager variable names (from afsmon_labels.h) */
207 extern char *fs_varNames[];
208 extern char *cm_varNames[];
209
210 /* GTX & MISC VARIABLES */
211
212 /* afsmonitor window */
213 extern struct gwin *afsmon_win;
214
215 /* current page number in the overview frame */
216 extern int ovw_currPage;
217
218 /* number of FS alerts and number of hosts on FS alerts */
219 int num_fs_alerts;
220 int numHosts_onfs_alerts;
221
222 /* number of CM alerts and number of hosts on FS alerts */
223 int num_cm_alerts;
224 int numHosts_oncm_alerts;
225
226 /* flag to indicate that atleast one probe cycle has completed and
227 data is available for updating the display */
228 extern int fs_Data_Available;
229 extern int cm_Data_Available;
230
231 extern int gtx_initialized;     /* gtx initialized ? */
232
233 /* This array contains the indices of the file server data items that
234 are to be displayed on the File Servers screen. For example, suppose the
235 user wishes to display only the vcache statistics then the following array
236 will contain indices 2 to 14 corresponding to the position of the
237 vcache data items in the fs_varNames[] array. If the config file contains
238 no "show fs .." directives, it will contain the indices of all the
239 items in the fs_varNames[] array */
240
241 short fs_Display_map[NUM_FS_STAT_ENTRIES];
242 int fs_DisplayItems_count = 0;  /* number of items to display */
243 int fs_showDefault = 1;         /* show all of FS data ? */
244
245
246 /* same use as above for Cache Managers  */
247 short cm_Display_map[NUM_CM_STAT_ENTRIES];
248 int cm_DisplayItems_count = 0;  /* number of items to display */
249 int cm_showDefault = 1;         /* show all of CM data ? */
250
251 extern int fs_currPage;         /* current page number in the File Servers frame */
252 extern int fs_curr_LCol;        /* current leftmost column on display on FS frame */
253
254 extern int cm_currPage;         /* current page number in the Cache Managers frame */
255 extern int cm_curr_LCol;        /* current leftmost column on display on CM frame */
256
257 /* File server and Cache manager data is classified into sections &
258 groups to help the user choose what he wants displayed */
259 extern char *fs_categories[];   /* file server data category names */
260 extern char *cm_categories[];   /* cache manager data category names */
261
262
263 static int fs_FullPerfs_ltoa(struct fs_Display_Data *a_fsData,
264                              struct xstat_fs_ProbeResults *a_fsResults);
265 static int fs_CallBackStats_ltoa(struct fs_Display_Data *a_fsData,
266                                  struct xstat_fs_ProbeResults *a_fsResults);
267
268 #ifdef HAVE_STRCASESTR
269 extern char * strcasestr(const char *, const char *);
270 #else
271 /*
272         strcasestr(): Return first occurence of pattern s2 in s1, case
273         insensitive.
274
275         This routine is required since I made pattern matching of the
276         config file to be case insensitive.
277 */
278
279 char *
280 strcasestr(s1, s2)
281      char *s1;
282      char *s2;
283 {
284     char *ptr;
285     int len1, len2;
286
287     len1 = strlen(s1);
288     len2 = strlen(s2);
289
290     if (len1 < len2)
291         return (NULL);
292
293     ptr = s1;
294
295     while (len1 >= len2 && len1 > 0) {
296         if ((strncasecmp(ptr, s2, len2)) == 0)
297             return (ptr);
298         ptr++;
299         len1--;
300     }
301     return (NULL);
302 }
303 #endif
304
305 struct hostent *
306 GetHostByName(char *name)
307 {
308     struct hostent *he;
309 #ifdef AFS_SUN5_ENV
310     char ip_addr[32];
311 #endif
312
313     he = gethostbyname(name);
314 #ifdef AFS_SUN5_ENV
315     /* On solaris the above does not resolve hostnames to full names */
316     if (he != NULL) {
317         memcpy(ip_addr, he->h_addr, he->h_length);
318         he = gethostbyaddr(ip_addr, he->h_length, he->h_addrtype);
319     }
320 #endif
321     return (he);
322 }
323
324
325 /*-----------------------------------------------------------------------
326  * afsmon_Exit()
327  *
328  * Description
329  *      Exit gracefully from the afsmonitor. Frees memory where appropriate,
330  *      cleans up after gtx and closes all open file descriptors. If a user
331  *      provided threshold handler is to be exec'ed then gtx cleanup is
332  *      not performed and an exec() is made instead of an exit().
333  *
334  * Returns
335  *      Nothing.
336  *
337  * Comments
338  *      This function is called to execute a user handler only
339  *      by a child process.
340  *
341  *----------------------------------------------------------------------*/
342
343 int
344 afsmon_Exit(int a_exitVal)      /* exit code */
345 {                               /* afsmon_Exit */
346     static char rn[] = "afsmon_Exit";
347     struct afsmon_fs_Results_list *tmp_fslist;
348     struct afsmon_fs_Results_list *next_fslist;
349     struct xstat_fs_ProbeResults *tmp_xstat_fsPR;
350     struct afsmon_cm_Results_list *tmp_cmlist;
351     struct afsmon_cm_Results_list *next_cmlist;
352     struct xstat_cm_ProbeResults *tmp_xstat_cmPR;
353     struct afsmon_hostEntry *curr_hostEntry;
354     struct afsmon_hostEntry *next_hostEntry;
355     int i;
356     int j;
357     int bufslot;
358     int code;
359
360     if (afsmon_debug) {
361         fprintf(debugFD, "[ %s ] Called with exit code %d\n", rn, a_exitVal);
362         fflush(debugFD);
363     }
364
365     /* get out of curses first, but not if we are here to exec a threshold
366      * handler. If we do, the screen gets messed up  */
367     if (gtx_initialized && !exec_fsThreshHandler)
368         gator_cursesgwin_cleanup(afsmon_win);
369
370     /* print the error message buffer */
371     if (errMsg[0] != '\0')
372         fprintf(stderr, "%s", errMsg);
373     if (errMsg1[0] != '\0')
374         fprintf(stderr, "%s", errMsg1);
375
376     /* deallocate file server circular buffers */
377     if (numFS && num_bufSlots) {
378         if (afsmon_debug) {
379             fprintf(debugFD, "freeing FS circular buffers ");
380             fflush(debugFD);
381         }
382
383         for (bufslot = 0; bufslot < num_bufSlots; bufslot++) {
384             if (afsmon_debug)
385                 fprintf(debugFD, " %d) ", bufslot);
386             if (afsmon_fs_ResultsCB[bufslot].list !=
387                 (struct afsmon_fs_Results_list *)0) {
388                 tmp_fslist = afsmon_fs_ResultsCB[bufslot].list;
389                 j = numFS;
390                 while (tmp_fslist) {
391                     /* make sure we do not go astray */
392                     if (--j < 0) {
393                         if (afsmon_debug)
394                             fprintf(debugFD,
395                                     "[ %s ] error in deallocating fs CB\n",
396                                     rn);
397                         break;
398                     }
399                     next_fslist = tmp_fslist->next;
400                     for (i = 0; i < MAX_NUM_FS_COLLECTIONS; i++) {
401                         tmp_xstat_fsPR = tmp_fslist->fsResults[i];
402
403                         if (afsmon_debug)
404                             fprintf(debugFD, "%d ", numFS - j);
405
406                         /* free xstat_fs_Results data */
407                         free(tmp_xstat_fsPR->data.AFS_CollData_val);
408                         free(tmp_xstat_fsPR->connP);
409                         free(tmp_xstat_fsPR);
410                     }
411
412                     /* free the fs list item */
413                     free(tmp_fslist);
414                     tmp_fslist = next_fslist;
415
416                 }               /* while fs list items in this slot */
417             }                   /* if entries in this buffer slot */
418         }                       /* for each fs buffer slot */
419         if (afsmon_debug)
420             fprintf(debugFD, "\n");
421     }
422
423     if (afsmon_debug)
424         fflush(debugFD);
425     /* deallocate cache manager curcular buffers */
426     if (numCM && num_bufSlots) {
427         if (afsmon_debug)
428             fprintf(debugFD, "freeing CM curcular buffers ");
429         for (bufslot = 0; bufslot < num_bufSlots; bufslot++) {
430             if (afsmon_debug)
431                 fprintf(debugFD, " %d) ", bufslot);
432             if (afsmon_cm_ResultsCB[bufslot].list !=
433                 (struct afsmon_cm_Results_list *)0) {
434                 tmp_cmlist = afsmon_cm_ResultsCB[bufslot].list;
435                 j = numCM;
436                 while (tmp_cmlist) {
437                     /* make sure we do not go astray */
438                     if (--j < 0) {
439                         if (afsmon_debug)
440                             fprintf(debugFD,
441                                     "[ %s ] error in deallocating cm CB\n",
442                                     rn);
443                         break;
444                     }
445                     next_cmlist = tmp_cmlist->next;
446                     for (i = 0; i < MAX_NUM_CM_COLLECTIONS; i++) {
447                         tmp_xstat_cmPR = tmp_cmlist->cmResults[i];
448
449                         if (afsmon_debug)
450                             fprintf(debugFD, "%d ", numCM - j);
451                         /* make sure data is ok */
452                         /* Print_cm_FullPerfInfo(tmp_xstat_cmPR); */
453
454                         /* free xstat_cm_Results data */
455                         free(tmp_xstat_cmPR->data.AFSCB_CollData_val);
456                         free(tmp_xstat_cmPR->connP);
457                         free(tmp_xstat_cmPR);
458                     }
459
460                     /* free the cm list item */
461                     free(tmp_cmlist);
462                     tmp_cmlist = next_cmlist;
463
464                 }               /* while cm list items in this slot */
465             }                   /* if entries in this buffer slot */
466         }                       /* for each cm buffer slot */
467         if (afsmon_debug)
468             fprintf(debugFD, "\n");
469     }
470
471
472     /* deallocate FS & CM Print buffers */
473     if (curr_fsData != NULL) {
474         if (afsmon_debug)
475             fprintf(debugFD, "Deallocating FS Print Buffers .... curr");
476         free(curr_fsData);
477     }
478     if (prev_fsData != NULL) {
479         if (afsmon_debug)
480             fprintf(debugFD, ", prev \n");
481         free(prev_fsData);
482     }
483     if (curr_cmData != NULL) {
484         if (afsmon_debug)
485             fprintf(debugFD, "Deallocating CM Print Buffers .... curr");
486         free(curr_cmData);
487     }
488     if (prev_cmData != NULL) {
489         if (afsmon_debug)
490             fprintf(debugFD, ", prev \n");
491         free(prev_cmData);
492     }
493
494     /* deallocate hostEntry lists */
495     if (numFS) {
496         if (afsmon_debug)
497             fprintf(debugFD, "Deallocating FS hostEntries ..");
498         curr_hostEntry = FSnameList;
499         while (curr_hostEntry) {
500             next_hostEntry = curr_hostEntry->next;
501             if (curr_hostEntry->thresh != NULL)
502                 free(curr_hostEntry->thresh);
503             free(curr_hostEntry);
504             curr_hostEntry = next_hostEntry;
505         }
506         if (afsmon_debug)
507             fprintf(debugFD, "\n");
508     }
509     if (numCM) {
510         if (afsmon_debug)
511             fprintf(debugFD, "Deallocating CM hostEntries ..");
512         curr_hostEntry = CMnameList;
513         while (curr_hostEntry) {
514             next_hostEntry = curr_hostEntry->next;
515             if (curr_hostEntry->thresh != NULL)
516                 free(curr_hostEntry->thresh);
517             free(curr_hostEntry);
518             curr_hostEntry = next_hostEntry;
519         }
520         if (afsmon_debug)
521             fprintf(debugFD, "\n");
522     }
523
524     /* close debug file */
525     if (afsmon_debug) {
526         fflush(debugFD);
527         fclose(debugFD);
528     }
529
530     if (exec_fsThreshHandler) {
531         code = execvp(fsHandler_argv[0], fsHandler_argv);
532         if (code == -1) {
533             fprintf(stderr, "execvp() of %s returned %d, errno %d\n",
534                     fsHandler_argv[0], code, errno);
535             exit(-1);
536         }
537     }
538
539     exit(a_exitVal);
540 }                               /* afsmon_Exit */
541
542 /*-----------------------------------------------------------------------
543  * insert_FS()
544  *
545  * Description:
546  *      Insert a hostname in the file server names list.
547  *
548  * Returns:
549  *      Success: 0
550  *      Failure: -1
551  *----------------------------------------------------------------------*/
552
553 int
554 insert_FS(char *a_hostName)             /* name of cache manager to be inserted in list */
555 {                               /* insert_FS() */
556     static struct afsmon_hostEntry *curr_item;
557     static struct afsmon_hostEntry *prev_item;
558
559     if (*a_hostName == '\0')
560         return (-1);
561     curr_item = malloc(sizeof(struct afsmon_hostEntry));
562     if (curr_item == (struct afsmon_hostEntry *)0) {
563         fprintf(stderr, "Failed to allocate space for FS nameList\n");
564         return (-1);
565     }
566
567     strncpy(curr_item->hostName, a_hostName, CFG_STR_LEN);
568     curr_item->next = (struct afsmon_hostEntry *)0;
569     curr_item->numThresh = 0;
570     curr_item->thresh = NULL;
571
572     if (FSnameList == (struct afsmon_hostEntry *)0)
573         FSnameList = curr_item;
574     else
575         prev_item->next = curr_item;
576
577     prev_item = curr_item;
578     /*  record the address of this entry so that its threshold
579      * count can be incremented during  the first pass of the config file */
580     last_hostEntry = curr_item;
581
582     return (0);
583 }
584
585 /*-----------------------------------------------------------------------
586  * print_FS()
587  *
588  * Description:
589  *      Debug routine.
590  *      Prints the file server names linked list.
591  *
592  * Returns:
593  *      Nothing.
594  *----------------------------------------------------------------------*/
595 void
596 print_FS(void)
597 {                               /* print_FS() */
598     static char rn[] = "print_FS";
599     struct afsmon_hostEntry *tempFS;
600     struct Threshold *threshP;
601     int i;
602
603     if (afsmon_debug) {
604         fprintf(debugFD, "[ %s ] Called\n", rn);
605         fflush(debugFD);
606     }
607
608     if (afsmon_debug) {
609         tempFS = FSnameList;
610         fprintf(debugFD, "No of File Servers: %d\n", numFS);
611         if (numFS) {
612             do {
613                 fprintf(debugFD, "\t %s threshCount = %d\n", tempFS->hostName,
614                         tempFS->numThresh);
615                 threshP = tempFS->thresh;
616                 for (i = 0; i < tempFS->numThresh; i++, threshP++)
617                     fprintf(debugFD, "\t thresh (%2d) %s %s %s\n",
618                             threshP->index, threshP->itemName,
619                             threshP->threshVal, threshP->handler);
620             } while ((tempFS = tempFS->next) != (struct afsmon_hostEntry *)0);
621         }
622         fprintf(debugFD, "\t\t-----End of List-----\n");
623         fflush(debugFD);
624     }
625
626 }
627
628 /*-----------------------------------------------------------------------
629  * insert_CM()
630  *
631  * Description:
632  *      Insert a hostname in the cache manager names list.
633  *
634  * Returns:
635  *      Success: 0
636  *      Failure: -1
637  *----------------------------------------------------------------------*/
638
639 int
640 insert_CM(char *a_hostName)             /* name of cache manager to be inserted in list */
641 {                               /* insert_CM */
642     static struct afsmon_hostEntry *curr_item;
643     static struct afsmon_hostEntry *prev_item;
644
645     if (*a_hostName == '\0')
646         return (-1);
647     curr_item = malloc(sizeof(struct afsmon_hostEntry));
648     if (curr_item == (struct afsmon_hostEntry *)0) {
649         fprintf(stderr, "Failed to allocate space for CM nameList\n");
650         return (-1);
651     }
652
653     strncpy(curr_item->hostName, a_hostName, CFG_STR_LEN);
654     curr_item->next = (struct afsmon_hostEntry *)0;
655     curr_item->numThresh = 0;
656     curr_item->thresh = NULL;
657
658     if (CMnameList == (struct afsmon_hostEntry *)0)
659         CMnameList = curr_item;
660     else
661         prev_item->next = curr_item;
662
663     prev_item = curr_item;
664     /* side effect. note the address of this entry so that its threshold
665      * count can be incremented during  the first pass of the config file */
666     last_hostEntry = curr_item;
667
668     return (0);
669 }
670
671
672 /*-----------------------------------------------------------------------
673  * print_CM()
674  *
675  * Description:
676  *      Debug routine.
677  *      Prints the cache manager names linked list.
678  *
679  * Returns:
680  *      Nothing.
681  *----------------------------------------------------------------------*/
682 int
683 print_CM(void)
684 {                               /* print_CM() */
685     static char rn[] = "print_CM";
686     struct afsmon_hostEntry *tempCM;
687     struct Threshold *threshP;
688     int i;
689
690     if (afsmon_debug) {
691         fprintf(debugFD, "[ %s ] Called\n", rn);
692         fflush(debugFD);
693     }
694
695     if (afsmon_debug) {
696         tempCM = CMnameList;
697         fprintf(debugFD, "No of Cache Managers: %d\n", numCM);
698         if (numCM) {
699             do {
700                 fprintf(debugFD, "\t %s threshCount = %d\n", tempCM->hostName,
701                         tempCM->numThresh);
702                 threshP = tempCM->thresh;
703                 for (i = 0; i < tempCM->numThresh; i++, threshP++)
704                     fprintf(debugFD, "\t thresh (%2d) %s %s %s\n",
705                             threshP->index, threshP->itemName,
706                             threshP->threshVal, threshP->handler);
707             } while ((tempCM = tempCM->next) != (struct afsmon_hostEntry *)0);
708         }
709         fprintf(debugFD, "\t\t-----End of List-----\n");
710     }
711     return (0);
712 }                               /* print_CM() */
713
714
715
716 /*-----------------------------------------------------------------------
717  * parse_hostEntry()
718  *
719  * Description:
720  *      Parse the host entry line in the config file. Check the syntax,
721  *      and inserts the host name in the FS ot CM linked list. Also
722  *      remember if this entry was an fs or cm & the ptr to its hostEntry
723  *      structure. The threshold entries in the config file are dependent
724  *      on their position relative to the hostname entries. Hence it is
725  *      required to remember the names of the last file server and cache
726  *      manager entries that were processed.
727  *
728  * Returns:
729  *      Success: 0
730  *      Failure: -1
731  *
732  *----------------------------------------------------------------------*/
733
734 int
735 parse_hostEntry(char *a_line)
736 {                               /* parse_hostEntry */
737
738     static char rn[] = "parse_hostEntry";       /* routine name */
739     char opcode[CFG_STR_LEN];   /* specifies type of config entry */
740     char arg1[CFG_STR_LEN];     /* hostname or qualifier (fs/cm?)  */
741     char arg2[CFG_STR_LEN];     /* threshold variable */
742     char arg3[CFG_STR_LEN];     /* threshold value */
743     char arg4[CFG_STR_LEN];     /* user's handler  */
744     struct hostent *he;         /* host entry */
745
746     if (afsmon_debug) {
747         fprintf(debugFD, "[ %s ] Called, a_line = %s\n", rn, a_line);
748         fflush(debugFD);
749     }
750
751     /* break it up */
752     opcode[0] = 0;
753     arg1[0] = 0;
754     arg2[0] = 0;
755     arg3[0] = 0;
756     arg4[0] = 0;
757     sscanf(a_line, "%s %s %s %s %s", opcode, arg1, arg2, arg3, arg4);
758     /* syntax is "opcode hostname" */
759     if ((strlen(arg2)) != 0) {
760         fprintf(stderr, "[ %s ] Extraneous characters at end of line\n", rn);
761         return (-1);
762     }
763
764     /* good host ? */
765     he = GetHostByName(arg1);
766     if (he == NULL) {
767         fprintf(stderr, "[ %s ] Unable to resolve hostname %s\n", rn, arg1);
768         return (-1);
769     }
770
771     if ((strcasecmp(opcode, "fs")) == 0) {
772         /* use the complete host name to insert in the file server names list */
773         insert_FS(he->h_name);
774         /* note that last host entry in the config file was fs */
775         lastHostType = 1;
776         numFS++;
777         /* threholds are not global anymore */
778         if (global_ThreshFlag)
779             global_ThreshFlag = 0;
780     } else if ((strcasecmp(opcode, "cm")) == 0) {
781         /* use the complete host name to insert in the CM names list */
782         insert_CM(he->h_name);
783         /* last host entry in the config file was cm */
784         lastHostType = 2;
785         numCM++;
786         /* threholds are not global anymore */
787         if (global_ThreshFlag)
788             global_ThreshFlag = 0;
789     } else
790         return (-1);
791
792     return (0);
793 }
794
795 /*-----------------------------------------------------------------------
796  * parse_threshEntry()
797  *
798  * Description
799  *      Parse the threshold entry line in the config file. This function is
800  *      called in the the first pass of the config file. It checks the syntax
801  *      of the config lines and verifies their positional validity - eg.,
802  *      a cm threshold cannot appear after a fs hostname entry, etc.
803  *      It also counts the thresholds applicable to each host.
804  *
805  * Returns
806  *      Success: 0
807  *      Failure: -1
808  *
809  *----------------------------------------------------------------------*/
810
811 int
812 parse_threshEntry(char *a_line)
813 {                               /* parse_threshEntry */
814     static char rn[] = "parse_threshEntry";     /* routine name */
815     char opcode[CFG_STR_LEN];   /* specifies type of config entry */
816     char arg1[CFG_STR_LEN];     /* hostname or qualifier (fs/cm?)  */
817     char arg2[CFG_STR_LEN];     /* threshold variable */
818     char arg3[CFG_STR_LEN];     /* threshold value */
819     char arg4[CFG_STR_LEN];     /* user's handler  */
820     char arg5[CFG_STR_LEN];     /* junk characters */
821
822     if (afsmon_debug) {
823         fprintf(debugFD, "[ %s ] Called, a_line = %s\n", rn, a_line);
824         fflush(debugFD);
825     }
826
827     /* break it up */
828     opcode[0] = 0;
829     arg1[0] = 0;
830     arg2[0] = 0;
831     arg3[0] = 0;
832     arg4[0] = 0;
833     arg5[0] = 0;
834     sscanf(a_line, "%s %s %s %s %s %s", opcode, arg1, arg2, arg3, arg4, arg5);
835
836     /* syntax is "thresh fs/cm variable_name threshold_value [handler] " */
837     if (((strlen(arg1)) == 0) || ((strlen(arg2)) == 0)
838         || ((strlen(arg3)) == 0)) {
839         fprintf(stderr, "[ %s ] Incomplete line\n", rn);
840         return (-1);
841     }
842     if (strlen(arg3) > THRESH_VAR_LEN - 2) {
843         fprintf(stderr, "[%s ] threshold value too long\n", rn);
844         return (-1);
845     }
846
847     if ((strcasecmp(arg1, "fs")) == 0) {
848         switch (lastHostType) {
849         case 0:         /* its a global threshold */
850             global_fsThreshCount++;
851             break;
852         case 1:         /* inc thresh count of last file server */
853             last_hostEntry->numThresh++;
854             break;
855         case 2:
856             fprintf(stderr,
857                     "[ %s ] A threshold for a File Server cannot be placed after a Cache Manager host entry in the config file \n",
858                     rn);
859             return (-1);
860         default:
861             fprintf(stderr, "[ %s ] Programming error 1\n", rn);
862             return (-1);
863         }
864     } else if ((strcasecmp(arg1, "cm")) == 0) {
865         switch (lastHostType) {
866         case 0:         /* its a global threshold */
867             global_cmThreshCount++;
868             break;
869         case 2:         /* inc thresh count of last cache manager */
870             last_hostEntry->numThresh++;
871             break;
872         case 1:
873             fprintf(stderr,
874                     "[ %s ] A threshold for a Cache Manager cannot be placed after a File Server host entry in the config file \n",
875                     rn);
876             return (-1);
877         default:
878             fprintf(stderr, "[ %s ] Programming error 2\n", rn);
879             return (-1);
880         }
881     } else {
882         fprintf(stderr,
883                 "[ %s ] Syntax error. Second argument should be \"fs\" or \"cm\" \n",
884                 rn);
885         return (-1);
886     }
887
888     return (0);
889 }                               /* parse_threshEntry */
890
891
892 /*-----------------------------------------------------------------------
893  * store_threshold()
894  *
895  * Description
896  *      The thresholds applicable to each host machine are stored in the
897  *      FSnameList and CMnameList. Threshold entries in the config file are
898  *      context sensitive. The host to which this threshold is applicable
899  *      is pointed to by last_fsHost (for file servers) and last_cmHost
900  *      for cache managers. For global thresholds the info is recorded for
901  *      all the hosts. This function is called in the second pass of the
902  *      config file. In the first pass a count of the number of global
903  *      thresholds is determined and this information is used in this
904  *      routine. If threshold entries are duplicated the first entry is
905  *      overwritten.
906  *      Each threshold entry also has an index field. This is a positional
907  *      index to the corresponding variable in the prev_[fs/cm]Data arrays.
908  *      This makes it easy to check the threshold for overflow.
909  *
910  * Returns:
911  *      Success: 0
912  *      Failure: -1
913  *----------------------------------------------------------------------*/
914
915 int
916 store_threshold(int a_type,             /* 1 = fs , 2 = cm */
917                 char *a_varName,        /* threshold name */
918                 char *a_value,          /* threshold value */
919                 char *a_handler)        /* threshold overflow handler */
920 {                               /* store_thresholds */
921
922     static char rn[] = "store_thresholds";      /* routine name */
923     struct afsmon_hostEntry *tmp_host;  /* tmp ptr to hostEntry */
924     struct afsmon_hostEntry *Header;    /* tmp ptr to hostEntry list header */
925     struct Threshold *threshP;  /* tmp ptr to threshold list */
926     char *hostname;
927     int index;                  /* index to fs_varNames or cm_varNames */
928     int found;
929     int done;
930     int srvCount;               /* tmp count of host names */
931     int *global_TC;             /* ptr to global_xxThreshCount */
932     int i, j;
933
934     if (afsmon_debug) {
935         fprintf(debugFD,
936                 "[ %s ] Called, a_type= %d, a_varName= %s, a_value= %s, a_handler=%s\n",
937                 rn, a_type, a_varName, a_value, a_handler);
938         fflush(debugFD);
939     }
940
941     /* resolve the threshold variable name */
942     found = 0;
943     if (a_type == 1) {          /* fs threshold */
944         for (index = 0; index < NUM_FS_STAT_ENTRIES; index++) {
945             if (strcasecmp(a_varName, fs_varNames[index]) == 0) {
946                 found = 1;
947                 break;
948             }
949         }
950         if (!found) {
951             fprintf(stderr, "[ %s ] Unknown FS threshold variable name %s\n",
952                     rn, a_varName);
953             return (-1);
954         }
955         Header = FSnameList;
956         srvCount = numFS;
957         hostname = last_fsHost;
958         global_TC = &global_fsThreshCount;
959     } else if (a_type == 2) {   /* cm threshold */
960         for (index = 0; index < NUM_CM_STAT_ENTRIES; index++) {
961             if (strcasecmp(a_varName, cm_varNames[index]) == 0) {
962                 found = 1;
963                 break;
964             }
965         }
966         if (!found) {
967             fprintf(stderr, "[ %s ] Unknown CM threshold variable name %s\n",
968                     rn, a_varName);
969             return (-1);
970         }
971         Header = CMnameList;
972         srvCount = numCM;
973         hostname = last_cmHost;
974         global_TC = &global_cmThreshCount;
975     } else
976         return (-1);
977
978
979
980     /* if the global thresh count is not zero, place this threshold on
981      * all the host entries  */
982
983     if (*global_TC) {
984         tmp_host = Header;
985         for (i = 0; i < srvCount; i++) {
986             threshP = tmp_host->thresh;
987             done = 0;
988             for (j = 0; j < tmp_host->numThresh; j++) {
989                 if ((threshP->itemName[0] == '\0')
990                     || (strcasecmp(threshP->itemName, a_varName) == 0)) {
991                     strlcpy(threshP->itemName, a_varName,
992                             sizeof(threshP->itemName));
993                     strlcpy(threshP->threshVal, a_value,
994                             sizeof(threshP->threshVal));
995                     strlcpy(threshP->handler, a_handler,
996                             sizeof(threshP->handler));
997                     threshP->index = index;
998                     done = 1;
999                     break;
1000                 }
1001                 threshP++;
1002             }
1003             if (!done) {
1004                 fprintf(stderr, "[ %s ] Could not insert threshold entry",
1005                         rn);
1006                 fprintf(stderr, "for %s in thresh list of host %s \n",
1007                         a_varName, tmp_host->hostName);
1008                 return (-1);
1009             }
1010             tmp_host = tmp_host->next;
1011         }
1012         (*global_TC)--;
1013         return (0);
1014     }
1015
1016     /* it is not a global threshold, insert it in the thresh list of this
1017      * host only. We overwrite the global threshold if it was alread set */
1018
1019     if (*hostname == '\0') {
1020         fprintf(stderr, "[ %s ] Programming error 3\n", rn);
1021         return (-1);
1022     }
1023
1024     /* get the hostEntry that this threshold belongs to */
1025     tmp_host = Header;
1026     found = 0;
1027     for (i = 0; i < srvCount; i++) {
1028         if (strcasecmp(tmp_host->hostName, hostname) == 0) {
1029             found = 1;
1030             break;
1031         }
1032         tmp_host = tmp_host->next;
1033     }
1034     if (!found) {
1035         fprintf(stderr, "[ %s ] Unable to find host %s in %s hostEntry list",
1036                 rn, hostname, (a_type - 1) ? "CM" : "FS");
1037         return (-1);
1038     }
1039
1040     /* put this entry on the thresh list of this host, overwrite global value
1041      * if needed */
1042
1043     threshP = tmp_host->thresh;
1044     done = 0;
1045     for (i = 0; i < tmp_host->numThresh; i++) {
1046         if ((threshP->itemName[0] == '\0')
1047             || (strcasecmp(threshP->itemName, a_varName) == 0)) {
1048             strlcpy(threshP->itemName, a_varName, sizeof(threshP->itemName));
1049             strlcpy(threshP->threshVal, a_value, sizeof(threshP->threshVal));
1050             strlcpy(threshP->handler, a_handler, sizeof(threshP->handler));
1051             threshP->index = index;
1052             done = 1;
1053             break;
1054         }
1055         threshP++;
1056     }
1057
1058     if (!done) {
1059         fprintf(stderr,
1060                 "[ %s ] Unable to insert threshold %s for %s host %s\n", rn,
1061                 a_varName, (a_type - 1) ? "CM" : "FS", tmp_host->hostName);
1062         return (-1);
1063     }
1064
1065     return (0);
1066
1067 }                               /* store_thresholds */
1068
1069
1070 /*-----------------------------------------------------------------------
1071  * parse_showEntry()
1072  *
1073  * Description:
1074  *      This function process a "show" entry in the config file. A "show"
1075  *      entry specifies what statistics the user wants to see. File
1076  *      server and Cache Manager data is divided into sections. Each section
1077  *      is made up of one or more groups. If a group name is specified only
1078  *      those statistics under that group are shown. If a section name is
1079  *      specified all the groups under this section are shown.
1080  *      Data as obtained from the xstat probes is considered to be ordered.
1081  *      This data is mapped to the screen thru fs_Display_map[] and
1082  *      cm_Display_map[]. This routine parses the "show" entry against the
1083  *      section/group names in the [fs/cm]_categories[] array. If there is
1084  *      no match it tries to match it against a variable name in
1085  *      [fs/cm]_varNames[] array. In each case the corresponding indices to
1086  *      the data is the [fs/cm]_displayInfo[] is recorded.
1087  *
1088  * Returns:
1089  *      Success: 0
1090  *      Failure: -1 (invalid entry)
1091  *               > -1 (programming error)
1092  *----------------------------------------------------------------------*/
1093
1094 int
1095 parse_showEntry(char *a_line)
1096 {                               /* parse_showEntry */
1097     static char rn[] = "parse_showEntry";
1098     char opcode[CFG_STR_LEN];   /* specifies type of config entry */
1099     char arg1[CFG_STR_LEN];     /* show fs or cm entry ? */
1100     char arg2[CFG_STR_LEN];     /* what we gotta show  */
1101     char arg3[CFG_STR_LEN];     /* junk */
1102     char catName[CFG_STR_LEN];  /* for category names */
1103     int numGroups;              /* number of groups in a section */
1104     int fromIdx;
1105     int toIdx;
1106     int found;
1107     int idx = 0;                /* index to fs_categories[] */
1108     int i;
1109     int j;
1110
1111
1112     if (afsmon_debug) {
1113         fprintf(debugFD, "[ %s ] Called, a_line= %s\n", rn, a_line);
1114         fflush(debugFD);
1115     }
1116     opcode[0] = 0;
1117     arg1[0] = 0;
1118     arg2[0] = 0;
1119     arg3[0] = 0;
1120     sscanf(a_line, "%s %s %s %s", opcode, arg1, arg2, arg3);
1121
1122     if (arg3[0] != '\0') {
1123         fprintf(stderr, "[ %s ] Extraneous characters at end of line\n", rn);
1124         return (-1);
1125     }
1126
1127     if ((strcasecmp(arg1, "fs") != 0) && (strcasecmp(arg1, "cm") != 0)) {
1128         fprintf(stderr,
1129                 "[ %s ] Second argument of \"show\" directive should be \"fs\" or \"cm\" \n",
1130                 rn);
1131         return (-1);
1132     }
1133
1134     /* Each entry can either be a variable name or a section/group name. Variable
1135      * names are listed in xx_varNames[] and section/group names in xx_categories[].
1136      * The section/group names in xx_categiries[] also give the starting/ending
1137      * indices of the variables belonging to that section/group. These indices
1138      * are stored in order in xx_Display_map[] and displayed to the screen in that
1139      * order. */
1140
1141     /* To handle duplicate "show" entries we keep track of what what we have
1142      * already marked to show in the xx_showFlags[] */
1143
1144     if (strcasecmp(arg1, "fs") == 0) {  /* its a File Server entry */
1145
1146         /* mark that we have to show only what the user wants */
1147         fs_showDefault = 0;
1148
1149         /* if it is a section/group name, find it in the fs_categories[] array */
1150
1151         found = 0;
1152         if (strcasestr(arg2, "_section") != NULL
1153             || strcasestr(arg2, "_group") != NULL) {
1154             idx = 0;
1155             while (idx < FS_NUM_DATA_CATEGORIES) {
1156                 sscanf(fs_categories[idx], "%s %d %d", catName, &fromIdx,
1157                        &toIdx);
1158                 idx++;
1159                 if (strcasecmp(arg2, catName) == 0) {
1160                     found = 1;
1161                     break;
1162                 }
1163             }
1164
1165             if (!found) {       /* typo in section/group name */
1166                 fprintf(stderr,
1167                         "[ %s ] Could not find section/group name %s\n", rn,
1168                         arg2);
1169                 return (-1);
1170             }
1171         }
1172
1173         /* if it is a group name, read its start/end indices and fill in the
1174          * fs_Display_map[]. */
1175
1176         if (strcasestr(arg2, "_group") != NULL) {
1177
1178             if (fromIdx < 0 || toIdx < 0 || fromIdx >= NUM_FS_STAT_ENTRIES
1179                 || toIdx >= NUM_FS_STAT_ENTRIES)
1180                 return (-2);
1181             for (j = fromIdx; j <= toIdx; j++) {
1182                 if (!fs_showFlags[j]) {
1183                     fs_Display_map[fs_DisplayItems_count] = j;
1184                     fs_DisplayItems_count++;
1185                     fs_showFlags[j] = 1;
1186                 }
1187                 if (fs_DisplayItems_count >= NUM_FS_STAT_ENTRIES) {
1188                     fprintf(stderr, "[ %s ] fs_DisplayItems_count ovf\n", rn);
1189                     return (-3);
1190                 }
1191             }
1192         } else
1193             /* if it is a section name, get the count of number of groups in it and
1194              * for each group fill in the start/end indices in the fs_Display_map[] */
1195
1196         if (strcasestr(arg2, "_section") != NULL) {
1197             /* fromIdx is actually the number of groups in thi section */
1198             numGroups = fromIdx;
1199             /* for each group in section */
1200             while (idx < FS_NUM_DATA_CATEGORIES && numGroups) {
1201                 sscanf(fs_categories[idx], "%s %d %d", catName, &fromIdx,
1202                        &toIdx);
1203
1204                 if (strcasestr(catName, "_group") != NULL) {
1205                     if (fromIdx < 0 || toIdx < 0
1206                         || fromIdx >= NUM_FS_STAT_ENTRIES
1207                         || toIdx >= NUM_FS_STAT_ENTRIES)
1208                         return (-4);
1209                     for (j = fromIdx; j <= toIdx; j++) {
1210                         if (!fs_showFlags[j]) {
1211                             fs_Display_map[fs_DisplayItems_count] = j;
1212                             fs_DisplayItems_count++;
1213                             fs_showFlags[j] = 1;
1214                         }
1215                         if (fs_DisplayItems_count >= NUM_FS_STAT_ENTRIES) {
1216                             fprintf(stderr,
1217                                     "[ %s ] fs_DisplayItems_count ovf\n", rn);
1218                             return (-5);
1219                         }
1220                     }
1221                 } else {
1222                     fprintf(stderr, "[ %s ] Error parsing groups for %s\n",
1223                             rn, arg2);
1224                     return (-6);
1225                 }
1226                 idx++;
1227                 numGroups--;
1228             }                   /* for each group in section */
1229
1230
1231         } else {                /* it is a variable name */
1232
1233             for (i = 0; i < NUM_FS_STAT_ENTRIES; i++) {
1234                 if (strcasecmp(arg2, fs_varNames[i]) == 0) {
1235                     if (!fs_showFlags[i]) {
1236                         fs_Display_map[fs_DisplayItems_count] = i;
1237                         fs_DisplayItems_count++;
1238                         fs_showFlags[i] = 1;
1239                     }
1240                     if (fs_DisplayItems_count >= NUM_FS_STAT_ENTRIES) {
1241                         fprintf(stderr, "[ %s ] fs_DisplayItems_count ovf\n",
1242                                 rn);
1243                         return (-25);
1244                     }
1245                     found = 1;
1246                 }
1247             }
1248             if (!found) {       /* typo in section/group name */
1249                 fprintf(stderr, "[ %s ] Could not find variable name %s\n",
1250                         rn, arg2);
1251                 return (-1);
1252             }
1253         }                       /* its a variable name */
1254
1255     }
1256
1257     /* it is an fs entry */
1258     if (strcasecmp(arg1, "cm") == 0) {  /* its a Cache Manager entry */
1259
1260
1261         /* mark that we have to show only what the user wants */
1262         cm_showDefault = 0;
1263
1264         /* if it is a section/group name, find it in the cm_categories[] array */
1265
1266         found = 0;
1267         if (strcasestr(arg2, "_section") != NULL
1268             || strcasestr(arg2, "_group") != NULL) {
1269             idx = 0;
1270             while (idx < CM_NUM_DATA_CATEGORIES) {
1271                 sscanf(cm_categories[idx], "%s %d %d", catName, &fromIdx,
1272                        &toIdx);
1273                 idx++;
1274                 if (strcasecmp(arg2, catName) == 0) {
1275                     found = 1;
1276                     break;
1277                 }
1278             }
1279
1280             if (!found) {       /* typo in section/group name */
1281                 fprintf(stderr,
1282                         "[ %s ] Could not find section/group name %s\n", rn,
1283                         arg2);
1284                 return (-1);
1285             }
1286         }
1287
1288         /* if it is a group name, read its start/end indices and fill in the
1289          * cm_Display_map[]. */
1290
1291         if (strcasestr(arg2, "_group") != NULL) {
1292
1293             if (fromIdx < 0 || toIdx < 0 || fromIdx >= NUM_CM_STAT_ENTRIES
1294                 || toIdx >= NUM_CM_STAT_ENTRIES)
1295                 return (-10);
1296             for (j = fromIdx; j <= toIdx; j++) {
1297                 if (!cm_showFlags[j]) {
1298                     cm_Display_map[cm_DisplayItems_count] = j;
1299                     cm_DisplayItems_count++;
1300                     cm_showFlags[j] = 1;
1301                 }
1302                 if (cm_DisplayItems_count >= NUM_CM_STAT_ENTRIES) {
1303                     fprintf(stderr, "[ %s ] cm_DisplayItems_count ovf\n", rn);
1304                     return (-11);
1305                 }
1306             }
1307         } else
1308             /* if it is a section name, get the count of number of groups in it and
1309              * for each group fill in the start/end indices in the cm_Display_map[] */
1310
1311         if (strcasestr(arg2, "_section") != NULL) {
1312             /* fromIdx is actually the number of groups in thi section */
1313             numGroups = fromIdx;
1314             /* for each group in section */
1315             while (idx < CM_NUM_DATA_CATEGORIES && numGroups) {
1316                 sscanf(cm_categories[idx], "%s %d %d", catName, &fromIdx,
1317                        &toIdx);
1318
1319                 if (strcasestr(catName, "_group") != NULL) {
1320                     if (fromIdx < 0 || toIdx < 0
1321                         || fromIdx >= NUM_CM_STAT_ENTRIES
1322                         || toIdx >= NUM_CM_STAT_ENTRIES)
1323                         return (-12);
1324                     for (j = fromIdx; j <= toIdx; j++) {
1325                         if (!cm_showFlags[j]) {
1326                             cm_Display_map[cm_DisplayItems_count] = j;
1327                             cm_DisplayItems_count++;
1328                             cm_showFlags[j] = 1;
1329                         }
1330                         if (cm_DisplayItems_count >= NUM_CM_STAT_ENTRIES) {
1331                             fprintf(stderr,
1332                                     "[ %s ] cm_DisplayItems_count ovf\n", rn);
1333                             return (-13);
1334                         }
1335                     }
1336                 } else {
1337                     fprintf(stderr, "[ %s ] Error parsing groups for %s\n",
1338                             rn, arg2);
1339                     return (-15);
1340                 }
1341                 idx++;
1342                 numGroups--;
1343             }                   /* for each group in section */
1344         } else {                /* it is a variable name */
1345
1346             for (i = 0; i < NUM_CM_STAT_ENTRIES; i++) {
1347                 if (strcasecmp(arg2, cm_varNames[i]) == 0) {
1348                     if (!cm_showFlags[i]) {
1349                         cm_Display_map[cm_DisplayItems_count] = i;
1350                         cm_DisplayItems_count++;
1351                         cm_showFlags[i] = 1;
1352                     }
1353                     if (cm_DisplayItems_count >= NUM_CM_STAT_ENTRIES) {
1354                         fprintf(stderr, "[ %s ] cm_DisplayItems_count ovf\n",
1355                                 rn);
1356                         return (-20);
1357                     }
1358                     found = 1;
1359                 }
1360             }
1361             if (!found) {       /* typo in section/group name */
1362                 fprintf(stderr, "[ %s ] Could not find variable name %s\n",
1363                         rn, arg2);
1364                 return (-1);
1365             }
1366         }                       /* its a variable name */
1367
1368     }
1369     /* it is an cm entry */
1370     return (0);
1371 }                               /* parse_showEntry */
1372
1373
1374 /*-----------------------------------------------------------------------
1375  * process_config_file()
1376  *
1377  * Description:
1378  *      Parse config file entries in two passes. In the first pass:
1379  *              - the syntax of all the entries is checked
1380  *              - host names are noted and the FSnamesList and CMnamesList
1381  *                constructed.
1382  *              - a count of the global thresholds and local thresholds of
1383  *                each host are counted.
1384  *              - "show" entries are processed.
1385  *      In the second pass:
1386  *              - thresholds are stored
1387  *
1388  * Returns:
1389  *      Success: 0
1390  *      Failure: Exits afsmonitor showing error and line.
1391  *----------------------------------------------------------------------*/
1392
1393 int
1394 process_config_file(char *a_config_filename)
1395 {                               /* process_config_file() */
1396     static char rn[] = "process_config_file";   /* routine name */
1397     FILE *configFD;             /* config file descriptor */
1398     char line[4 * CFG_STR_LEN]; /* a line of config file */
1399     char opcode[CFG_STR_LEN];   /* specifies type of config entry */
1400     char arg1[CFG_STR_LEN];     /* hostname or qualifier (fs/cm?)  */
1401     char arg2[CFG_STR_LEN];     /* threshold variable */
1402     char arg3[CFG_STR_LEN];     /* threshold value */
1403     char arg4[CFG_STR_LEN];     /* user's handler  */
1404     struct afsmon_hostEntry *curr_host;
1405     struct hostent *he;         /* hostentry to resolve host name */
1406     char *handlerPtr;           /* ptr to pass theresh handler string */
1407     int code = 0;               /* error code */
1408     int linenum = 0;            /* config file line number */
1409     int error_in_config;        /* syntax errors in config file  ?? */
1410     int i;
1411     int numBytes;
1412
1413     if (afsmon_debug) {
1414         fprintf(debugFD, "[ %s ] Called, a_config_filename= %s\n", rn,
1415                 a_config_filename);
1416         fflush(debugFD);
1417     }
1418
1419     /* open config file */
1420
1421     configFD = fopen(a_config_filename, "r");
1422     if (configFD == (FILE *) 0) {
1423         fprintf(stderr, "Failed to open config file %s \n",
1424                 a_config_filename);
1425         if (afsmon_debug) {
1426             fprintf(debugFD, "[ %s ] Failed to open config file %s \n", rn,
1427                     a_config_filename);
1428         }
1429         afsmon_Exit(5);
1430     }
1431
1432
1433     /* parse config file */
1434
1435     /* We process the config file in two passes. In the first pass we check
1436      * for correct syntax and for valid entries and also keep count of the
1437      * number of servers and thresholds to monitor. This the data strctures
1438      * can be arrays instead of link lists since we would know their sizes. */
1439
1440     /* First Pass */
1441
1442     numFS = 0;
1443     numCM = 0;
1444     error_in_config = 0;        /* flag to note if config file has syntax errors */
1445
1446     while ((fgets(line, CFG_STR_LEN, configFD)) != NULL) {
1447         opcode[0] = 0;
1448         arg1[0] = 0;
1449         arg2[0] = 0;
1450         arg3[0] = 0;
1451         arg4[0] = 0;
1452         sscanf(line, "%s %s %s %s %s", opcode, arg1, arg2, arg3, arg4);
1453         linenum++;
1454         /* skip blank lines and comment lines */
1455         if ((strlen(opcode) == 0) || line[0] == '#')
1456             continue;
1457
1458         if ((strcasecmp(opcode, "fs") == 0)
1459             || (strcasecmp(opcode, "cm")) == 0) {
1460             code = parse_hostEntry(line);
1461         } else if ((strcasecmp(opcode, "thresh")) == 0) {
1462             code = parse_threshEntry(line);
1463         } else if ((strcasecmp(opcode, "show")) == 0) {
1464             code = parse_showEntry(line);
1465         } else {
1466             fprintf(stderr, "[ %s ] Unknown opcode %s\n", rn, opcode);
1467             code = 1;
1468         }
1469
1470         if (code) {
1471             fprintf(stderr, "[ %s ] Error in line:\n %d: %s\n", rn, linenum,
1472                     line);
1473             error_in_config = 1;
1474         }
1475     }
1476
1477     if (error_in_config)
1478         afsmon_Exit(10);
1479
1480     if (afsmon_debug) {
1481         fprintf(debugFD, "Global FS thresholds count = %d\n",
1482                 global_fsThreshCount);
1483         fprintf(debugFD, "Global CM thresholds count = %d\n",
1484                 global_cmThreshCount);
1485         fflush(debugFD);
1486     }
1487
1488     /* the threshold count of all hosts in increased by 1 for each global
1489      * threshold. If one of the hosts has a local threshold for the same
1490      * variable it would end up being counted twice. whats a few bytes of memory
1491      * wasted anyway ? */
1492
1493     if (global_fsThreshCount) {
1494         curr_host = FSnameList;
1495         for (i = 0; i < numFS; i++) {
1496             curr_host->numThresh += global_fsThreshCount;
1497             curr_host = curr_host->next;
1498         }
1499     }
1500     if (global_cmThreshCount) {
1501         curr_host = CMnameList;
1502         for (i = 0; i < numCM; i++) {
1503             curr_host->numThresh += global_cmThreshCount;
1504             curr_host = curr_host->next;
1505         }
1506     }
1507
1508
1509     /* make sure we have something to monitor */
1510     if (numFS == 0 && numCM == 0) {
1511         fprintf(stderr,
1512                 "\nConfig file must specify atleast one File Server or Cache Manager host to monitor.\n");
1513         fclose(configFD);
1514         afsmon_Exit(15);
1515     }
1516
1517     /* Second Pass */
1518
1519     fseek(configFD, 0, 0);      /* seek to the beginning */
1520
1521
1522     /* allocate memory for threshold lists */
1523     curr_host = FSnameList;
1524     for (i = 0; i < numFS; i++) {
1525         if (curr_host->hostName[0] == '\0') {
1526             fprintf(stderr, "[ %s ] Programming error 4\n", rn);
1527             afsmon_Exit(20);
1528         }
1529         if (curr_host->numThresh) {
1530             numBytes = curr_host->numThresh * sizeof(struct Threshold);
1531             curr_host->thresh = malloc(numBytes);
1532             if (curr_host->thresh == NULL) {
1533                 fprintf(stderr, "[ %s ] Memory Allocation error 1", rn);
1534                 afsmon_Exit(25);
1535             }
1536             memset(curr_host->thresh, 0, numBytes);
1537         }
1538         curr_host = curr_host->next;;
1539     }
1540
1541     curr_host = CMnameList;
1542     for (i = 0; i < numCM; i++) {
1543         if (curr_host->hostName[0] == '\0') {
1544             fprintf(stderr, "[ %s ] Programming error 5\n", rn);
1545             afsmon_Exit(30);
1546         }
1547         if (curr_host->numThresh) {
1548             numBytes = curr_host->numThresh * sizeof(struct Threshold);
1549             curr_host->thresh = malloc(numBytes);
1550             if (curr_host->thresh == NULL) {
1551                 fprintf(stderr, "[ %s ] Memory Allocation error 2", rn);
1552                 afsmon_Exit(35);
1553             }
1554             memset(curr_host->thresh, 0, numBytes);
1555         }
1556         curr_host = curr_host->next;;
1557     }
1558
1559
1560     opcode[0] = 0;
1561     arg1[0] = 0;
1562     arg2[0] = 0;
1563     arg3[0] = 0;
1564     arg4[0] = 0;
1565     last_fsHost[0] = '\0';
1566     last_cmHost[0] = '\0';
1567     linenum = 0;
1568     while ((fgets(line, CFG_STR_LEN, configFD)) != NULL) {
1569         opcode[0] = 0;
1570         arg1[0] = 0;
1571         arg2[0] = 0;
1572         arg3[0] = 0;
1573         arg4[0] = 0;
1574         sscanf(line, "%s %s %s %s %s", opcode, arg1, arg2, arg3, arg4);
1575         linenum++;
1576
1577         /* if we have a host entry, remember the host name */
1578         if (strcasecmp(opcode, "fs") == 0) {
1579             he = GetHostByName(arg1);
1580             strncpy(last_fsHost, he->h_name, HOST_NAME_LEN);
1581         } else if (strcasecmp(opcode, "cm") == 0) {
1582             he = GetHostByName(arg1);
1583             strncpy(last_cmHost, he->h_name, HOST_NAME_LEN);
1584         } else if (strcasecmp(opcode, "thresh") == 0) {
1585             /* if we have a threshold handler it may have arguments
1586              * and the sscanf() above would not get them, so do the
1587              * following */
1588             if (strlen(arg4)) {
1589                 handlerPtr = line;
1590                 /* now skip over 4 words - this is done by first
1591                  * skipping leading blanks then skipping a word */
1592                 for (i = 0; i < 4; i++) {
1593                     while (isspace(*handlerPtr))
1594                         handlerPtr++;
1595                     while (!isspace(*handlerPtr))
1596                         handlerPtr++;
1597                 }
1598                 while (isspace(*handlerPtr))
1599                     handlerPtr++;
1600                 /* we how have a pointer to the start of the handler
1601                  * name & args */
1602             } else
1603                 handlerPtr = arg4;      /* empty string */
1604
1605
1606             if (strcasecmp(arg1, "fs") == 0)
1607                 code = store_threshold(1,       /* 1 = fs */
1608                                        arg2, arg3, handlerPtr);
1609
1610             else if (strcasecmp(arg1, "cm") == 0)
1611                 code = store_threshold(2,       /* 2 = fs */
1612                                        arg2, arg3, handlerPtr);
1613
1614             else {
1615                 fprintf(stderr, "[ %s ] Programming error 6\n", rn);
1616                 afsmon_Exit(40);
1617             }
1618             if (code) {
1619                 fprintf(stderr, "[ %s ] Failed to store threshold\n", rn);
1620                 fprintf(stderr, "[ %s ] Error processing line:\n%d: %s", rn,
1621                         linenum, line);
1622                 afsmon_Exit(45);
1623             }
1624         }
1625     }
1626
1627
1628     fclose(configFD);
1629     return (0);
1630 }
1631
1632 /*-----------------------------------------------------------------------
1633  * Print_FS_CB
1634  *
1635  * Description:
1636  *      Debug routine.
1637  *      Print the File Server circular buffer.
1638  *
1639  * Returns:
1640  *      Nothing.
1641  *----------------------------------------------------------------------*/
1642
1643 void
1644 Print_FS_CB(void)
1645 {                               /* Print_FS_CB() */
1646
1647     struct afsmon_fs_Results_list *fslist;
1648     int i;
1649     int j;
1650     int k;
1651
1652     /* print valid info in the fs CB */
1653
1654     if (afsmon_debug) {
1655         fprintf(debugFD,
1656                 "==================== FS Buffer ========================\n");
1657         fprintf(debugFD, "afsmon_fs_curr_CBindex = %d\n",
1658                 afsmon_fs_curr_CBindex);
1659         fprintf(debugFD, "afsmon_fs_curr_probeNum = %d\n\n",
1660                 afsmon_fs_curr_probeNum);
1661
1662         for (i = 0; i < num_bufSlots; i++) {
1663             fprintf(debugFD, "\t--------- slot %d ----------\n", i);
1664             fslist = afsmon_fs_ResultsCB[i].list;
1665             j = 0;
1666             while (j < numFS) {
1667                 for (k = 0; k < MAX_NUM_FS_COLLECTIONS; k++) {
1668                     if (!(fslist->empty[k])) {
1669                         fprintf(debugFD, "\t %d) probeNum = %d host = %s cn = %d",
1670                                 j,
1671                                 fslist->fsResults[k]->probeNum,
1672                                 fslist->fsResults[k]->connP->hostName,
1673                                 fslist->fsResults[k]->collectionNumber);
1674                         if (fslist->fsResults[k]->probeOK)
1675                             fprintf(debugFD, " NOTOK\n");
1676                         else
1677                             fprintf(debugFD, " OK\n");
1678                     } else
1679                         fprintf(debugFD, "\t %d) -- empty --\n", j);
1680                 }
1681                 fslist = fslist->next;
1682                 j++;
1683             }
1684             if (fslist != (struct afsmon_fs_Results_list *)0)
1685                 fprintf(debugFD, "dangling last next ptr fs CB\n");
1686         }
1687     }
1688 }                               /* Print_FS_CB() */
1689
1690 /*-----------------------------------------------------------------------
1691  * save_FS_results_inCB()
1692  *
1693  * Description:
1694  *      Saves the results of the latest FS probe in the fs circular
1695  *      buffers. If the current probe cycle is in progress the contents
1696  *      of xstat_fs_Results are copied to the end of the list of results
1697  *      in the current slot (pointed to by afsmon_fs_curr_CBindex). If
1698  *      a new probe cycle has started the next slot in the circular buffer
1699  *      is initialized and the results copied. Note that the Rx related
1700  *      information available in xstat_fs_Results is not copied.
1701  *
1702  * Returns:
1703  *      Success: 0
1704  *      Failure: Exits afsmonitor.
1705  *----------------------------------------------------------------------*/
1706 int
1707 save_FS_results_inCB(int a_newProbeCycle)       /* start of a new probe cycle ? */
1708 {                               /* save_FS_results_inCB() */
1709     static char rn[] = "save_FS_results_inCB";  /* routine name */
1710     struct afsmon_fs_Results_list *tmp_fslist_item;     /* temp fs list item */
1711     struct xstat_fs_ProbeResults *tmp_fsPR;     /* temp ptr */
1712     int i;
1713     int index;
1714
1715     if (afsmon_debug) {
1716         fprintf(debugFD, "[ %s ] Called, a_newProbeCycle= %d\n", rn,
1717                 a_newProbeCycle);
1718         fflush(debugFD);
1719     }
1720
1721     switch (xstat_fs_Results.collectionNumber) {
1722     case AFS_XSTATSCOLL_FULL_PERF_INFO:
1723         index = 0;
1724         break;
1725     case AFS_XSTATSCOLL_CBSTATS:
1726         index = 1;
1727         break;
1728     default:
1729         fprintf(stderr, "[ %s ] collection number %d is out of range.\n",
1730                 rn, xstat_fs_Results.collectionNumber);
1731         afsmon_Exit(51);
1732     }
1733
1734     /* If a new probe cycle started, mark the list in the current buffer
1735      * slot empty for resuse. Note that afsmon_fs_curr_CBindex was appropriately
1736      * incremented in afsmon_FS_Handler() */
1737
1738     if (a_newProbeCycle) {
1739         tmp_fslist_item = afsmon_fs_ResultsCB[afsmon_fs_curr_CBindex].list;
1740         for (i = 0; i < numFS; i++) {
1741             tmp_fslist_item->empty[index] = 1;
1742             tmp_fslist_item = tmp_fslist_item->next;
1743         }
1744     }
1745
1746     /* locate last unused item in list */
1747     tmp_fslist_item = afsmon_fs_ResultsCB[afsmon_fs_curr_CBindex].list;
1748     for (i = 0; i < numFS; i++) {
1749         if (tmp_fslist_item->empty[index])
1750             break;
1751         tmp_fslist_item = tmp_fslist_item->next;
1752     }
1753
1754     /* if we could not find one we have an inconsistent list */
1755     if (!tmp_fslist_item->empty[index]) {
1756         fprintf(stderr,
1757                 "[ %s ] list inconsistency 1. unable to find an empty slot to store results of probenum %d of %s\n",
1758                 rn, xstat_fs_Results.probeNum,
1759                 xstat_fs_Results.connP->hostName);
1760         afsmon_Exit(50);
1761     }
1762
1763     tmp_fsPR = tmp_fslist_item->fsResults[index];
1764
1765     /* copy hostname and probe number and probe time and probe status.
1766      * if the probe failed return now */
1767
1768     memcpy(tmp_fsPR->connP->hostName, xstat_fs_Results.connP->hostName,
1769            sizeof(xstat_fs_Results.connP->hostName));
1770     tmp_fsPR->probeNum = xstat_fs_Results.probeNum;
1771     tmp_fsPR->probeTime = xstat_fs_Results.probeTime;
1772     tmp_fsPR->probeOK = xstat_fs_Results.probeOK;
1773     if (xstat_fs_Results.probeOK) {     /* probeOK = 1 => notOK */
1774         /* we have a nonempty results structure so mark the list item used */
1775         tmp_fslist_item->empty[index] = 0;
1776         return (0);
1777     }
1778
1779     /* copy connection information */
1780     memcpy(&(tmp_fsPR->connP->skt), &(xstat_fs_Results.connP->skt),
1781            sizeof(struct sockaddr_in));
1782
1783     memcpy(tmp_fsPR->connP->hostName, xstat_fs_Results.connP->hostName,
1784            sizeof(xstat_fs_Results.connP->hostName));
1785     tmp_fsPR->collectionNumber = xstat_fs_Results.collectionNumber;
1786
1787     /* copy the probe data information */
1788     tmp_fsPR->data.AFS_CollData_len =
1789         min(xstat_fs_Results.data.AFS_CollData_len,
1790             afsmon_fs_results_length[index]);
1791     memcpy(tmp_fsPR->data.AFS_CollData_val,
1792            xstat_fs_Results.data.AFS_CollData_val,
1793            tmp_fsPR->data.AFS_CollData_len * sizeof(afs_int32));
1794
1795
1796     /* we have a valid results structure so mark the list item used */
1797     tmp_fslist_item->empty[index] = 0;
1798
1799     /* Print the fs circular buffer */
1800     Print_FS_CB();
1801
1802     return (0);
1803 }                               /* save_FS_results_inCB() */
1804
1805
1806 /*-----------------------------------------------------------------------
1807  * fs_Results_ltoa()
1808  *
1809  * Description:
1810  *      The results of xstat probes are stored in a string format in
1811  *      the arrays curr_fsData and prev_fsData. The information stored in
1812  *      prev_fsData is copied to the screen.
1813  *      This function converts xstat FS results from longs to strings and
1814  *      place them in the given buffer (a pointer to an item in curr_fsData).
1815  *      When a probe cycle completes, curr_fsData is copied to prev_fsData
1816  *      in afsmon_FS_Hnadler().
1817  *
1818  * Returns:
1819  *      Always returns 0.
1820  *----------------------------------------------------------------------*/
1821
1822 int
1823 fs_Results_ltoa(struct fs_Display_Data *a_fsData,       /* target buffer */
1824                 struct xstat_fs_ProbeResults *a_fsResults)      /* ptr to xstat fs Results */
1825 {                               /* fs_Results_ltoa */
1826
1827     static char rn[] = "fs_Results_ltoa";       /* routine name */
1828
1829     if (afsmon_debug) {
1830         fprintf(debugFD, "[ %s ] Called, a_fsData= %p, a_fsResults= %p\n", rn,
1831                 a_fsData, a_fsResults);
1832         fflush(debugFD);
1833     }
1834
1835     switch (a_fsResults->collectionNumber) {
1836     case AFS_XSTATSCOLL_FULL_PERF_INFO:
1837         fs_FullPerfs_ltoa(a_fsData, a_fsResults);
1838         break;
1839     case AFS_XSTATSCOLL_CBSTATS:
1840         fs_CallBackStats_ltoa(a_fsData, a_fsResults);
1841         break;
1842     default:
1843         if (afsmon_debug) {
1844             fprintf(debugFD, "[ %s ] Unexpected collection id %d\n",
1845                     rn, a_fsResults->collectionNumber);
1846         }
1847     }
1848
1849     return (0);
1850 }                               /* fs_Results_ltoa */
1851
1852 /*-----------------------------------------------------------------------
1853  * fs_FullPerfs_ltoa()
1854  *
1855  * Description:
1856  *      Convert the full perf xstat collection from int32s to strings.
1857  *
1858  * Returns:
1859  *      Always returns 0.
1860  *----------------------------------------------------------------------*/
1861 static int
1862 fs_FullPerfs_ltoa(struct fs_Display_Data *a_fsData,
1863                 struct xstat_fs_ProbeResults *a_fsResults)
1864 {
1865     afs_int32 *srcbuf;
1866     struct fs_stats_FullPerfStats *fullPerfP;
1867     struct fs_stats_FullPerfStats buffer;
1868     int idx;
1869     int i, j;
1870     afs_int32 *tmpbuf;
1871     int code;
1872     int large_time;
1873
1874     /* there are two parts to the xstat FS statistics
1875      * - fullPerfP->overall which give the overall performance statistics, and
1876      * - fullPerfP->det which gives detailed info about file server operation
1877      * execution times */
1878
1879     code = xstat_fs_DecodeFullPerfStats(&fullPerfP,
1880                                         a_fsResults->data.AFS_CollData_val,
1881                                         a_fsResults->data.AFS_CollData_len,
1882                                         &buffer);
1883     if (code) {
1884         /* Not able to decode the full perf stats. Avoid displaying garbage. */
1885         for (i = 0; i < NUM_FS_STAT_ENTRIES; i++) {
1886             sprintf(a_fsData->data[i], "%s", "--");
1887         }
1888         return 0;
1889     }
1890
1891     /* copy overall performance statistics */
1892     srcbuf = (afs_int32 *) & (fullPerfP->overall);
1893     idx = 0;
1894     for (i = 0; i < NUM_XSTAT_FS_AFS_PERFSTATS_LONGS; i++) {
1895         sprintf(a_fsData->data[idx], "%d", *srcbuf);
1896         idx++;
1897         srcbuf++;
1898     }
1899
1900     /* copy epoch */
1901     srcbuf = (afs_int32 *) & (fullPerfP->det.epoch);
1902     sprintf(a_fsData->data[idx], "%d", *srcbuf);        /* epoch */
1903     idx++;
1904
1905     /* copy fs operation timing */
1906
1907     srcbuf = (afs_int32 *) (fullPerfP->det.rpcOpTimes);
1908
1909     /*
1910      * For every time value below, we'll have to skip an additional
1911      * 64 bits of input if struct timeval uses 64-bit values
1912      */
1913     if (sizeof(struct timeval) == 16)
1914         large_time = 1;
1915     else
1916         large_time = 0;
1917
1918     for (i = 0; i < FS_STATS_NUM_RPC_OPS; i++) {
1919         sprintf(a_fsData->data[idx], "%d", *srcbuf);    /* numOps */
1920         idx++;
1921         srcbuf++;
1922         sprintf(a_fsData->data[idx], "%d", *srcbuf);    /* numSuccesses */
1923         idx++;
1924         srcbuf++;
1925         tmpbuf = srcbuf++;      /* sum time */
1926         sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1927         idx++;
1928         srcbuf++;
1929         if (large_time)
1930             srcbuf += 2;
1931         tmpbuf = srcbuf++;      /* sqr time */
1932         sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1933         idx++;
1934         srcbuf++;
1935         if (large_time)
1936             srcbuf += 2;
1937         tmpbuf = srcbuf++;      /* min time */
1938         sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1939         idx++;
1940         srcbuf++;
1941         if (large_time)
1942             srcbuf += 2;
1943         tmpbuf = srcbuf++;      /* max time */
1944         sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1945         idx++;
1946         srcbuf++;
1947         if (large_time)
1948             srcbuf += 2;
1949     }
1950
1951     /* copy fs transfer timings */
1952
1953     srcbuf = (afs_int32 *) (fullPerfP->det.xferOpTimes);
1954     for (i = 0; i < FS_STATS_NUM_XFER_OPS; i++) {
1955         sprintf(a_fsData->data[idx], "%d", *srcbuf);    /* numOps */
1956         idx++;
1957         srcbuf++;
1958         sprintf(a_fsData->data[idx], "%d", *srcbuf);    /* numSuccesses */
1959         idx++;
1960         srcbuf++;
1961         tmpbuf = srcbuf++;      /* sum time */
1962         sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1963         idx++;
1964         srcbuf++;
1965         if (large_time)
1966             srcbuf += 2;
1967         tmpbuf = srcbuf++;      /* sqr time */
1968         sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1969         idx++;
1970         srcbuf++;
1971         if (large_time)
1972             srcbuf += 2;
1973         tmpbuf = srcbuf++;      /* min time */
1974         sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1975         idx++;
1976         srcbuf++;
1977         if (large_time)
1978             srcbuf += 2;
1979         tmpbuf = srcbuf++;      /* max time */
1980         sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1981         idx++;
1982         srcbuf++;
1983         if (large_time)
1984             srcbuf += 2;
1985         sprintf(a_fsData->data[idx], "%d", *srcbuf);    /* sum bytes */
1986         idx++;
1987         srcbuf++;
1988         sprintf(a_fsData->data[idx], "%d", *srcbuf);    /* min bytes */
1989         idx++;
1990         srcbuf++;
1991         sprintf(a_fsData->data[idx], "%d", *srcbuf);    /* max bytes */
1992         idx++;
1993         srcbuf++;
1994         for (j = 0; j < FS_STATS_NUM_XFER_BUCKETS; j++) {
1995             sprintf(a_fsData->data[idx], "%d", *srcbuf);        /* bucket[j] */
1996             idx++;
1997             srcbuf++;
1998         }
1999     }
2000
2001     return (0);
2002 }
2003
2004 /*-----------------------------------------------------------------------
2005  * fs_CallBackStats_ltoa()
2006  *
2007  * Description:
2008  *      Convert the callback counter xstat collection from
2009  *      int32s to strings.
2010  *
2011  * Returns:
2012  *      Always returns 0.
2013  *----------------------------------------------------------------------*/
2014
2015 static int
2016 fs_CallBackStats_ltoa(struct fs_Display_Data *a_fsData,
2017                       struct xstat_fs_ProbeResults *a_fsResults)
2018 {
2019     int idx;
2020     int i;
2021     int len = a_fsResults->data.AFS_CollData_len;
2022     afs_int32 *val = a_fsResults->data.AFS_CollData_val;
2023
2024     /* place callback stats after the full perf stats */
2025     idx = NUM_FS_FULLPERF_ENTRIES;
2026     for (i=0; i < len && i < NUM_FS_CB_ENTRIES; i++) {
2027         sprintf(a_fsData->data[idx++], "%u", val[i]);
2028     }
2029     return 0;
2030 }
2031
2032 /*-----------------------------------------------------------------------
2033  * execute_thresh_handler()
2034  *
2035  * Description:
2036  *      Execute a threshold handler. An agrv[] array of pointers is
2037  *      constructed from the given data. A child process is forked
2038  *      which immediately calls afsmon_Exit() with indication that a
2039  *      threshold handler is to be exec'ed insted of exiting.
2040  *
2041  * Returns:
2042  *      Success: 0
2043  *      Failure: Afsmonitor exits if threshold handler has more than 20 args.
2044  *----------------------------------------------------------------------*/
2045
2046 int
2047 execute_thresh_handler(char *a_handler,         /* ptr to handler function + args */
2048                        char *a_hostName,        /* host name for which threshold crossed */
2049                        int a_hostType,          /* fs or cm ? */
2050                        char *a_threshName,      /* threshold variable name */
2051                        char *a_threshValue,     /* threshold value */
2052                        char *a_actValue)        /* actual value */
2053 {                               /* execute_thresh_handler */
2054
2055     static char rn[] = "execute_thresh_handler";
2056     char fileName[256];         /* file name to execute */
2057     int i;
2058     char *ch;
2059     int argNum;
2060     int anotherArg;             /* boolean used to flag if another arg is available */
2061
2062     if (afsmon_debug) {
2063         fprintf(debugFD,
2064                 "[ %s ] Called, a_handler= %s, a_hostName= %s, a_hostType= %d, a_threshName= %s, a_threshValue= %s, a_actValue= %s\n",
2065                 rn, a_handler, a_hostName, a_hostType, a_threshName,
2066                 a_threshValue, a_actValue);
2067         fflush(debugFD);
2068     }
2069
2070
2071     /* get the filename to execute - the first argument */
2072     sscanf(a_handler, "%s", fileName);
2073
2074     /* construct the contents of *argv[] */
2075
2076     strncpy(fsHandler_args[0], fileName, 256);
2077     strncpy(fsHandler_args[1], a_hostName, HOST_NAME_LEN);
2078     if (a_hostType == FS)
2079         strcpy(fsHandler_args[2], "fs");
2080     else
2081         strcpy(fsHandler_args[2], "cm");
2082     strncpy(fsHandler_args[3], a_threshName, THRESH_VAR_NAME_LEN);
2083     strncpy(fsHandler_args[4], a_threshValue, THRESH_VAR_LEN);
2084     strncpy(fsHandler_args[5], a_actValue, THRESH_VAR_LEN);
2085
2086
2087     argNum = 6;
2088     anotherArg = 1;
2089     ch = a_handler;
2090
2091     /* we have already extracted the file name so skip to the 1st arg */
2092     while (isspace(*ch))        /* leading blanks */
2093         ch++;
2094     while (!isspace(*ch) && *ch != '\0')        /* handler filename */
2095         ch++;
2096
2097     while (*ch != '\0') {
2098         if (isspace(*ch)) {
2099             anotherArg = 1;
2100         } else if (anotherArg) {
2101             anotherArg = 0;
2102             sscanf(ch, "%s", fsHandler_args[argNum]);
2103             argNum++;
2104         }
2105         ch++;
2106         if (argNum >= 20) {
2107             sprintf(errMsg,
2108                     "Threshold handlers cannot have more than 20 arguments\n");
2109             afsmon_Exit(55);
2110         }
2111
2112     }
2113
2114     fsHandler_argv[argNum] = NULL;
2115     for (i = 0; i < argNum; i++)
2116         fsHandler_argv[i] = fsHandler_args[i];
2117
2118
2119     /* exec the threshold handler */
2120
2121     if (fork() == 0) {
2122         exec_fsThreshHandler = 1;
2123         afsmon_Exit(60);
2124     }
2125
2126     return (0);
2127 }                               /* execute_thresh_handler */
2128
2129
2130
2131 /*-----------------------------------------------------------------------
2132  * check_fs_thresholds()
2133  *
2134  * Description:
2135  *      Checks the thresholds and sets the overflow flag. Recall that the
2136  *      thresholds for each host are stored in the hostEntry lists
2137  *      [fs/cm]nameList arrays. The probe results are passed to this
2138  *      function in the display-ready format - ie., as strings. Though
2139  *      this looks stupid the overhead incurred in converting the strings
2140  *      back to floats and comparing them is insignificant and
2141  *      programming is easier this way.
2142  *      The threshold flags are a part of the display structures
2143  *      curr_[fs/cm]Data.
2144  *
2145  * Returns:
2146  *      0
2147  *----------------------------------------------------------------------*/
2148
2149 int
2150 check_fs_thresholds(struct afsmon_hostEntry *a_hostEntry, /* ptr to hostEntry */
2151                     struct fs_Display_Data *a_Data)       /* ptr to fs data to be displayed */
2152 {                               /* check_fs_thresholds */
2153
2154     static char rn[] = "check_fs_thresholds";
2155     struct Threshold *threshP;
2156     double tValue;              /* threshold value */
2157     double pValue;              /* probe value */
2158     int i;
2159     int idx;
2160     int count;                  /* number of thresholds exceeded */
2161
2162     if (afsmon_debug) {
2163         fprintf(debugFD, "[ %s ] Called, a_hostEntry= %p, a_Data= %p\n", rn,
2164                 a_hostEntry, a_Data);
2165         fflush(debugFD);
2166     }
2167
2168     if (a_hostEntry->numThresh == 0) {
2169         /* store in ovf count ?? */
2170         return (0);
2171     }
2172
2173     count = 0;
2174     threshP = a_hostEntry->thresh;
2175     for (i = 0; i < a_hostEntry->numThresh; i++) {
2176         if (threshP->itemName[0] == '\0') {
2177             threshP++;
2178             continue;
2179         }
2180         idx = threshP->index;   /* positional index to the data array */
2181         tValue = atof(threshP->threshVal);      /* threshold value */
2182         pValue = atof(a_Data->data[idx]);       /* probe value */
2183         if (pValue > tValue) {
2184
2185             if (afsmon_debug) {
2186                 fprintf(debugFD,
2187                         "[ %s ] fs = %s, thresh ovf for %s, threshold= %s, probevalue= %s\n",
2188                         rn, a_hostEntry->hostName, threshP->itemName,
2189                         threshP->threshVal, a_Data->data[idx]);
2190                 fflush(debugFD);
2191             }
2192             /* if the threshold is crossed, call the handler function
2193              * only if this was a transition -ie, if the threshold was
2194              * crossed in the last probe too just count & keep quite! */
2195
2196             if (!a_Data->threshOvf[idx]) {
2197                 a_Data->threshOvf[idx] = 1;
2198                 /* call the threshold handler if provided */
2199                 if (threshP->handler[0] != '\0') {
2200                     if (afsmon_debug) {
2201                         fprintf(debugFD, "[ %s ] Calling ovf handler %s\n",
2202                                 rn, threshP->handler);
2203                         fflush(debugFD);
2204                     }
2205                     execute_thresh_handler(threshP->handler, a_Data->hostName,
2206                                            FS, threshP->itemName,
2207                                            threshP->threshVal,
2208                                            a_Data->data[idx]);
2209                 }
2210             }
2211
2212             count++;
2213         } else
2214             /* in case threshold was previously crossed, blank it out */
2215             a_Data->threshOvf[idx] = 0;
2216         threshP++;
2217     }
2218     /* store the overflow count */
2219     a_Data->ovfCount = count;
2220
2221     return (0);
2222 }                               /* check_fs_thresholds */
2223
2224
2225 /*-----------------------------------------------------------------------
2226  * save_FS_data_forDisplay()
2227  *
2228  * Description:
2229  *      Does the following:
2230  *      - if the probe number changed (ie, a cycle completed) curr_fsData
2231  *      is copied to prev_fsData, curr_fsData zeroed and refresh the
2232  *      overview screen and file server screen with the new data.
2233  *      - store the results of the current probe from xstat_fs_Results into
2234  *      curr_fsData. ie., convert longs to strings.
2235  *      - check the thresholds
2236  *
2237  * Returns:
2238  *      Success: 0
2239  *      Failure: Exits afsmonitor.
2240  *----------------------------------------------------------------------*/
2241
2242 int
2243 save_FS_data_forDisplay(struct xstat_fs_ProbeResults *a_fsResults)
2244 {                               /* save_FS_data_forDisplay */
2245
2246     static char rn[] = "save_FS_data_forDisplay";       /* routine name */
2247     struct fs_Display_Data *curr_fsDataP;       /* tmp ptr to curr_fsData */
2248     struct fs_Display_Data *prev_fsDataP;       /* tmp ptr to prev_fsData */
2249     struct afsmon_hostEntry *curr_host;
2250     static int results_Received = 0;    /* number of probes reveived in
2251                                          * the current cycle. If this is equal to numFS we got all
2252                                          * the data we want in this cycle and can now display it */
2253     int numBytes;
2254     int okay;
2255     int i;
2256     int code;
2257     int done;
2258
2259
2260     if (afsmon_debug) {
2261         fprintf(debugFD, "[ %s ] Called, a_fsResults= %p\n", rn, a_fsResults);
2262         fflush(debugFD);
2263     }
2264
2265     /* store results in the display array */
2266
2267     okay = 0;
2268     curr_fsDataP = curr_fsData;
2269     for (i = 0; i < numFS; i++) {
2270         if ((strcasecmp(curr_fsDataP->hostName, a_fsResults->connP->hostName))
2271             == 0) {
2272             okay = 1;
2273             break;
2274         }
2275         curr_fsDataP++;
2276     }
2277
2278     if (!okay) {
2279         fprintf(stderr,
2280                 "[ %s ] Could not insert FS probe results for host %s in fs display array\n",
2281                 rn, a_fsResults->connP->hostName);
2282         afsmon_Exit(65);
2283     }
2284
2285     /*  Check the status of the probe. If it succeeded, we store its
2286      * results in the display data structure. If it failed we only mark
2287      * the failed status in the display data structure. */
2288
2289     if (a_fsResults->probeOK) { /* 1 => notOK the xstat results */
2290         curr_fsDataP->probeOK = 0;
2291
2292         /* print the probe status */
2293         if (afsmon_debug) {
2294             fprintf(debugFD, "\n\t\t ----- fs display data ------\n");
2295             fprintf(debugFD, "HostName = %s  PROBE FAILED \n",
2296                     curr_fsDataP->hostName);
2297             fflush(debugFD);
2298         }
2299
2300     } else {                    /* probe succeeded, update display data structures */
2301         curr_fsDataP->probeOK = 1;
2302
2303         /* convert longs to strings and place them in curr_fsDataP */
2304         fs_Results_ltoa(curr_fsDataP, a_fsResults);
2305
2306         /* compare with thresholds and set the overflow flags.
2307          * note that the threshold information is in the hostEntry structure and
2308          * each threshold item has a positional index associated with it */
2309
2310         /* locate the hostEntry for this host */
2311         done = 0;
2312         curr_host = FSnameList;
2313         for (i = 0; i < numFS; i++) {
2314             if (strcasecmp(curr_host->hostName, a_fsResults->connP->hostName)
2315                 == 0) {
2316                 done = 1;
2317                 break;
2318             }
2319             curr_host = curr_host->next;;
2320         }
2321         if (!done)
2322             afsmon_Exit(70);
2323
2324         code = check_fs_thresholds(curr_host, curr_fsDataP);
2325         if (code) {
2326             fprintf(stderr, "[ %s ] Error in checking thresholds\n", rn);
2327             afsmon_Exit(75);
2328         }
2329
2330         /* print the info we just saved */
2331
2332         if (afsmon_debug) {
2333             fprintf(debugFD, "\n\t\t ----- fs display data ------\n");
2334             fprintf(debugFD, "HostName = %s\n", curr_fsDataP->hostName);
2335             for (i = 0; i < NUM_FS_STAT_ENTRIES; i++)
2336                 fprintf(debugFD, "%20s  %30s  %s\n", curr_fsDataP->data[i],
2337                         fs_varNames[i],
2338                         curr_fsDataP->threshOvf[i] ? "(ovf)" : "");
2339
2340             fprintf(debugFD, "\t\t--------------------------------\n\n");
2341             fflush(debugFD);
2342         }
2343
2344     }                           /* the probe succeeded, so we store the data in the display structure */
2345
2346
2347     /* if we have received a reply from all the hosts for this probe cycle,
2348      * it is time to display the data */
2349
2350     results_Received++;
2351     if (results_Received == numFS * num_fs_collections) {
2352         results_Received = 0;
2353
2354         if (afsmon_fs_curr_probeNum != afsmon_fs_prev_probeNum + 1) {
2355             sprintf(errMsg, "[ %s ] Probe number %d missed! \n", rn,
2356                     afsmon_fs_prev_probeNum + 1);
2357             afsmon_Exit(80);
2358         } else
2359             afsmon_fs_prev_probeNum++;
2360
2361         /* backup the display data of the probe cycle that just completed -
2362          * ie., store curr_fsData in prev_fsData */
2363
2364         memcpy((char *)prev_fsData, (char *)curr_fsData,
2365                (numFS * sizeof(struct fs_Display_Data)));
2366
2367
2368         /* initialize curr_fsData but retain the threshold flag information.
2369          * The previous state of threshold flags is used in check_fs_thresholds() */
2370
2371         numBytes = NUM_FS_STAT_ENTRIES * FS_STAT_STRING_LEN;
2372         curr_fsDataP = curr_fsData;
2373         for (i = 0; i < numFS; i++) {
2374             curr_fsDataP->probeOK = 0;
2375             curr_fsDataP->ovfCount = 0;
2376             memset(curr_fsDataP->data, 0, numBytes);
2377             curr_fsDataP++;
2378         }
2379
2380
2381         /* prev_fsData now contains all the information for the probe cycle
2382          * that just completed. Now count the number of threshold overflows for
2383          * use in the overview screen */
2384
2385         prev_fsDataP = prev_fsData;
2386         num_fs_alerts = 0;
2387         numHosts_onfs_alerts = 0;
2388         for (i = 0; i < numFS; i++) {
2389             if (!prev_fsDataP->probeOK) {       /* if probe failed */
2390                 num_fs_alerts++;
2391                 numHosts_onfs_alerts++;
2392             }
2393             if (prev_fsDataP->ovfCount) {       /* overflows ?? */
2394                 num_fs_alerts += prev_fsDataP->ovfCount;
2395                 numHosts_onfs_alerts++;
2396             }
2397             prev_fsDataP++;
2398         }
2399         if (afsmon_debug)
2400             fprintf(debugFD, "Number of FS alerts = %d (on %d hosts)\n",
2401                     num_fs_alerts, numHosts_onfs_alerts);
2402
2403         /* flag that the data is now ready to be displayed */
2404         fs_Data_Available = 1;
2405
2406         /* call the Overview frame update routine (update only FS info) */
2407         ovw_refresh(ovw_currPage, OVW_UPDATE_FS);
2408
2409         /* call the File Servers frame update routine */
2410         fs_refresh(fs_currPage, fs_curr_LCol);
2411
2412     }
2413     /* display data */
2414     return (0);
2415 }                               /* save_FS_data_forDisplay */
2416
2417
2418
2419
2420 /*-----------------------------------------------------------------------
2421  * afsmon_FS_Handler()
2422  *
2423  * Description:
2424  *      This is the File Server probe Handler. It updates the afsmonitor
2425  *      probe counts, fs circular buffer indices and calls the functions
2426  *      to process the results of this probe.
2427  *
2428  * Returns:
2429  *      Success: 0
2430  *      Failure: Exits afsmonitor.
2431  *----------------------------------------------------------------------*/
2432
2433 int
2434 afsmon_FS_Handler(void)
2435 {                               /* afsmon_FS_Handler() */
2436     static char rn[] = "afsmon_FS_Handler";     /* routine name */
2437     int newProbeCycle;          /* start of new probe cycle ? */
2438     int code;                   /* return status */
2439
2440
2441     if (afsmon_debug) {
2442         fprintf(debugFD,
2443                 "[ %s ] Called, hostName= %s, probeNum= %d, status=%s, collection=%d\n", rn,
2444                 xstat_fs_Results.connP->hostName, xstat_fs_Results.probeNum,
2445                 xstat_fs_Results.probeOK ? "FAILED" : "OK",
2446                 xstat_fs_Results.collectionNumber);
2447         fflush(debugFD);
2448     }
2449
2450
2451     /* print the probe results to output file */
2452     if (afsmon_output) {
2453         code = afsmon_fsOutput(output_filename, afsmon_detOutput);
2454         if (code) {
2455             fprintf(stderr,
2456                     "[ %s ] output to file %s returned error code=%d\n", rn,
2457                     output_filename, code);
2458         }
2459     }
2460
2461     /* Update current probe number and circular buffer index. if current
2462      * probenum changed make sure it is only by 1 */
2463
2464     newProbeCycle = 0;
2465     if (xstat_fs_Results.probeNum != afsmon_fs_curr_probeNum) {
2466         if (xstat_fs_Results.probeNum == afsmon_fs_curr_probeNum + 1) {
2467             afsmon_fs_curr_probeNum++;
2468             newProbeCycle = 1;
2469             if (num_bufSlots)
2470                 afsmon_fs_curr_CBindex =
2471                     (afsmon_fs_curr_probeNum - 1) % num_bufSlots;
2472         } else {
2473             fprintf(stderr, "[ %s ] probe number %d-1 missed\n", rn,
2474                     xstat_fs_Results.probeNum);
2475             afsmon_Exit(85);
2476         }
2477     }
2478
2479
2480     /* store the results of this probe in the FS circular buffer */
2481     if (num_bufSlots)
2482         save_FS_results_inCB(newProbeCycle);
2483
2484
2485     /* store the results of the current probe in the fs data display structure.
2486      * if the current probe number changed, swap the current and previous display
2487      * structures. note that the display screen is updated from these structures
2488      * and should start showing the data of the just completed probe cycle */
2489
2490     save_FS_data_forDisplay(&xstat_fs_Results);
2491
2492     return (0);
2493 }
2494
2495
2496
2497 /*----------------------------------------------------------------------- *
2498  * Print_CM_CB()
2499  *
2500  * Description:
2501  *      Debug routine.
2502  *      Prints the  Cache Manager circular buffer
2503  *----------------------------------------------------------------------*/
2504
2505 void
2506 Print_CM_CB(void)
2507 {                               /* Print_CM_CB() */
2508
2509     struct afsmon_cm_Results_list *cmlist;
2510     int i;
2511     int j;
2512     int k;
2513
2514     /* print valid info in the cm CB */
2515
2516     if (afsmon_debug) {
2517         fprintf(debugFD,
2518                 "==================== CM Buffer ========================\n");
2519         fprintf(debugFD, "afsmon_cm_curr_CBindex = %d\n",
2520                 afsmon_cm_curr_CBindex);
2521         fprintf(debugFD, "afsmon_cm_curr_probeNum = %d\n\n",
2522                 afsmon_cm_curr_probeNum);
2523
2524         for (i = 0; i < num_bufSlots; i++) {
2525             fprintf(debugFD, "\t--------- slot %d ----------\n", i);
2526             cmlist = afsmon_cm_ResultsCB[i].list;
2527             j = 0;
2528             while (j < numCM) {
2529                 for (k = 0; k < MAX_NUM_CM_COLLECTIONS; k++) {
2530                     if (!cmlist->empty[k]) {
2531                         fprintf(debugFD,
2532                                 "\t %d) probeNum = %d host = %s cn = %d",
2533                                 j,
2534                                 cmlist->cmResults[k]->probeNum,
2535                                 cmlist->cmResults[k]->connP->hostName,
2536                                 cmlist->cmResults[k]->collectionNumber);
2537                         if (cmlist->cmResults[k]->probeOK)
2538                             fprintf(debugFD, " NOTOK\n");
2539                         else
2540                             fprintf(debugFD, " OK\n");
2541                     } else
2542                         fprintf(debugFD, "\t %d) -- empty --\n", j);
2543                 }
2544                 cmlist = cmlist->next;
2545                 j++;
2546             }
2547             if (cmlist != (struct afsmon_cm_Results_list *)0)
2548                 fprintf(debugFD, "dangling last next ptr cm CB\n");
2549         }
2550     }
2551 }
2552
2553
2554 /*-----------------------------------------------------------------------
2555  * save_CM_results_inCB()
2556  *
2557  * Description:
2558  *      Saves the results of the latest CM probe in the cm circular
2559  *      buffers. If the current probe cycle is in progress the contents
2560  *      of xstat_cm_Results are copied to the end of the list of results
2561  *      in the current slot (pointed to by afsmon_cm_curr_CBindex). If
2562  *      a new probe cycle has started the next slot in the circular buffer
2563  *      is initialized and the results copied. Note that the Rx related
2564  *      information available in xstat_cm_Results is not copied.
2565  *
2566  * Returns:
2567  *      Success: 0
2568  *      Failure: Exits afsmonitor.
2569  *----------------------------------------------------------------------*/
2570
2571 int
2572 save_CM_results_inCB(int a_newProbeCycle)       /* start of new probe cycle ? */
2573 {                               /* save_CM_results_inCB() */
2574     static char rn[] = "save_CM_results_inCB";  /* routine name */
2575     struct afsmon_cm_Results_list *tmp_cmlist_item;     /* temp cm list item */
2576     struct xstat_cm_ProbeResults *tmp_cmPR;     /* temp ptr */
2577     int i;
2578     int index;
2579
2580
2581     if (afsmon_debug) {
2582         fprintf(debugFD, "[ %s ] Called, a_newProbeCycle= %d\n", rn,
2583                 a_newProbeCycle);
2584         fflush(debugFD);
2585     }
2586
2587     if (xstat_cm_Results.collectionNumber == AFSCB_XSTATSCOLL_FULL_PERF_INFO) {
2588         index = 0;
2589     } else {
2590         fprintf(stderr, "[ %s ] collection number %d is out of range.\n",
2591                 rn, xstat_cm_Results.collectionNumber);
2592         afsmon_Exit(91);
2593     }
2594
2595     /* If a new probe cycle started, mark the list in the current buffer
2596      * slot empty for resuse. Note that afsmon_cm_curr_CBindex was appropriately
2597      * incremented in afsmon_CM_Handler() */
2598
2599     if (a_newProbeCycle) {
2600         tmp_cmlist_item = afsmon_cm_ResultsCB[afsmon_cm_curr_CBindex].list;
2601         for (i = 0; i < numCM; i++) {
2602             tmp_cmlist_item->empty[index] = 1;
2603             tmp_cmlist_item = tmp_cmlist_item->next;
2604         }
2605     }
2606
2607     /* locate last unused item in list */
2608     tmp_cmlist_item = afsmon_cm_ResultsCB[afsmon_cm_curr_CBindex].list;
2609     for (i = 0; i < numCM; i++) {
2610         if (tmp_cmlist_item->empty[index])
2611             break;
2612         tmp_cmlist_item = tmp_cmlist_item->next;
2613     }
2614
2615     /* if we could not find one we have an inconsistent list */
2616     if (!tmp_cmlist_item->empty[index]) {
2617         fprintf(stderr,
2618                 "[ %s ] list inconsistency 1. unable to find an empty slot to store results of probenum %d of %s\n",
2619                 rn, xstat_cm_Results.probeNum,
2620                 xstat_cm_Results.connP->hostName);
2621         afsmon_Exit(90);
2622     }
2623
2624     tmp_cmPR = tmp_cmlist_item->cmResults[index];
2625
2626     /* copy hostname and probe number and probe time and probe status.
2627      * if the probe failed return now */
2628
2629     memcpy(tmp_cmPR->connP->hostName, xstat_cm_Results.connP->hostName,
2630            sizeof(xstat_cm_Results.connP->hostName));
2631     tmp_cmPR->probeNum = xstat_cm_Results.probeNum;
2632     tmp_cmPR->probeTime = xstat_cm_Results.probeTime;
2633     tmp_cmPR->probeOK = xstat_cm_Results.probeOK;
2634     if (xstat_cm_Results.probeOK) {     /* probeOK = 1 => notOK */
2635         /* we have a nonempty results structure so mark the list item used */
2636         tmp_cmlist_item->empty[index] = 0;
2637         return (0);
2638     }
2639
2640
2641     /* copy connection information */
2642     memcpy(&(tmp_cmPR->connP->skt), &(xstat_cm_Results.connP->skt),
2643            sizeof(struct sockaddr_in));
2644
2645    /**** NEED TO COPY rx_connection INFORMATION HERE ******/
2646
2647     memcpy(tmp_cmPR->connP->hostName, xstat_cm_Results.connP->hostName,
2648            sizeof(xstat_cm_Results.connP->hostName));
2649     tmp_cmPR->collectionNumber = xstat_cm_Results.collectionNumber;
2650
2651     /* copy the probe data information */
2652     tmp_cmPR->data.AFSCB_CollData_len =
2653         min(xstat_cm_Results.data.AFSCB_CollData_len,
2654             afsmon_cm_results_length[index]);
2655     memcpy(tmp_cmPR->data.AFSCB_CollData_val,
2656            xstat_cm_Results.data.AFSCB_CollData_val,
2657            tmp_cmPR->data.AFSCB_CollData_len * sizeof(afs_int32));
2658
2659
2660     /* we have a valid results structure so mark the list item used */
2661     tmp_cmlist_item->empty[index] = 0;
2662
2663     /* print the stored info - to make sure we copied it right */
2664     /*   Print_cm_FullPerfInfo(tmp_cmPR);        */
2665     /* Print the cm circular buffer */
2666     Print_CM_CB();
2667     return (0);
2668 }                               /* save_CM_results_inCB */
2669
2670
2671
2672 /*-----------------------------------------------------------------------
2673  * cm_Results_ltoa()
2674  *
2675  * Description:
2676  *      The results of xstat probes are stored in a string format in
2677  *      the arrays curr_cmData and prev_cmData. The information stored in
2678  *      prev_cmData is copied to the screen.
2679  *      This function converts xstat FS results from longs to strings and
2680  *      places them in the given buffer (a pointer to an item in curr_cmData).
2681  *      When a probe cycle completes, curr_cmData is copied to prev_cmData
2682  *      in afsmon_CM_Handler().
2683  *
2684  * Returns:
2685  *      Always returns 0.
2686  *----------------------------------------------------------------------*/
2687
2688 int
2689 cm_Results_ltoa(struct cm_Display_Data *a_cmData,       /* target buffer */
2690                 struct xstat_cm_ProbeResults *a_cmResults)      /* ptr to xstat cm Results */
2691 {                               /* cm_Results_ltoa */
2692
2693     static char rn[] = "cm_Results_ltoa";       /* routine name */
2694     struct afs_stats_CMFullPerf *fullP; /* ptr to complete CM stats */
2695     afs_int32 *srcbuf;
2696     afs_int32 *tmpbuf;
2697     int i, j;
2698     int idx;
2699     afs_int32 numLongs;
2700
2701     if (afsmon_debug) {
2702         fprintf(debugFD, "[ %s ] Called, a_cmData= %p, a_cmResults= %p\n", rn,
2703                 a_cmData, a_cmResults);
2704         fflush(debugFD);
2705     }
2706
2707
2708     fullP = (struct afs_stats_CMFullPerf *)
2709         (a_cmResults->data.AFSCB_CollData_val);
2710
2711     /* There are 4 parts to CM statistics
2712      * - Overall performance statistics (including up/down statistics)
2713      * - This CMs FS RPC operations info
2714      * - This CMs FS RPC errors info
2715      * - This CMs FS transfers info
2716      * - Authentication info
2717      * - [Un]Replicated access info
2718      */
2719
2720     /* copy overall performance statistics */
2721     srcbuf = (afs_int32 *) & (fullP->perf);
2722     idx = 0;
2723     /* we skip the 19 entry, ProtServAddr, so the index must account for this */
2724     for (i = 0; i < NUM_AFS_STATS_CMPERF_LONGS + 1; i++) {
2725         if (i == 19) {
2726             srcbuf++;
2727             continue;           /* skip ProtServerAddr */
2728         }
2729         sprintf(a_cmData->data[idx], "%d", *srcbuf);
2730         idx++;
2731         srcbuf++;
2732     }
2733
2734     /*printf("Ending index value = %d\n",idx-1); */
2735
2736     /* server up/down statistics */
2737     /* copy file server up/down stats */
2738     srcbuf = (afs_int32 *) (fullP->perf.fs_UpDown);
2739     numLongs =
2740         2 * (sizeof(struct afs_stats_SrvUpDownInfo) / sizeof(afs_int32));
2741     for (i = 0; i < numLongs; i++) {
2742         sprintf(a_cmData->data[idx], "%d", *srcbuf);
2743         idx++;
2744         srcbuf++;
2745     }
2746
2747     /*printf("Ending index value = %d\n",idx-1); */
2748
2749     /* copy volume location  server up/down stats */
2750     srcbuf = (afs_int32 *) (fullP->perf.vl_UpDown);
2751     numLongs =
2752         2 * (sizeof(struct afs_stats_SrvUpDownInfo) / sizeof(afs_int32));
2753     for (i = 0; i < numLongs; i++) {
2754         sprintf(a_cmData->data[idx], "%d", *srcbuf);
2755         idx++;
2756         srcbuf++;
2757     }
2758
2759     /*printf("Ending index value = %d\n",idx-1); */
2760
2761     /* copy CMs individual FS RPC operations info */
2762     srcbuf = (afs_int32 *) (fullP->rpc.fsRPCTimes);
2763     for (i = 0; i < AFS_STATS_NUM_FS_RPC_OPS; i++) {
2764         sprintf(a_cmData->data[idx], "%d", *srcbuf);    /* numOps */
2765         idx++;
2766         srcbuf++;
2767         sprintf(a_cmData->data[idx], "%d", *srcbuf);    /* numSuccesses */
2768         idx++;
2769         srcbuf++;
2770         tmpbuf = srcbuf++;      /* sum time */
2771         sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2772         idx++;
2773         srcbuf++;
2774         tmpbuf = srcbuf++;      /* sqr time */
2775         sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2776         idx++;
2777         srcbuf++;
2778         tmpbuf = srcbuf++;      /* min time */
2779         sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2780         idx++;
2781         srcbuf++;
2782         tmpbuf = srcbuf++;      /* max time */
2783         sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2784         idx++;
2785         srcbuf++;
2786     }
2787
2788     /*printf("Ending index value = %d\n",idx-1); */
2789
2790     /* copy CMs individual FS RPC errors info */
2791
2792     srcbuf = (afs_int32 *) (fullP->rpc.fsRPCErrors);
2793     for (i = 0; i < AFS_STATS_NUM_FS_RPC_OPS; i++) {
2794         sprintf(a_cmData->data[idx], "%d", *srcbuf);    /* server */
2795         idx++;
2796         srcbuf++;
2797         sprintf(a_cmData->data[idx], "%d", *srcbuf);    /* network */
2798         idx++;
2799         srcbuf++;
2800         sprintf(a_cmData->data[idx], "%d", *srcbuf);    /* prot */
2801         idx++;
2802         srcbuf++;
2803         sprintf(a_cmData->data[idx], "%d", *srcbuf);    /* vol */
2804         idx++;
2805         srcbuf++;
2806         sprintf(a_cmData->data[idx], "%d", *srcbuf);    /* busies */
2807         idx++;
2808         srcbuf++;
2809         sprintf(a_cmData->data[idx], "%d", *srcbuf);    /* other */
2810         idx++;
2811         srcbuf++;
2812     }
2813
2814     /*printf("Ending index value = %d\n",idx-1); */
2815
2816     /* copy CMs individual RPC transfers info */
2817
2818     srcbuf = (afs_int32 *) (fullP->rpc.fsXferTimes);
2819     for (i = 0; i < AFS_STATS_NUM_FS_XFER_OPS; i++) {
2820         sprintf(a_cmData->data[idx], "%d", *srcbuf);    /* numOps */
2821         idx++;
2822         srcbuf++;
2823         sprintf(a_cmData->data[idx], "%d", *srcbuf);    /* numSuccesses */
2824         idx++;
2825         srcbuf++;
2826         tmpbuf = srcbuf++;      /* sum time */
2827         sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2828         idx++;
2829         srcbuf++;
2830         tmpbuf = srcbuf++;      /* sqr time */
2831         sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2832         idx++;
2833         srcbuf++;
2834         tmpbuf = srcbuf++;      /* min time */
2835         sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2836         idx++;
2837         srcbuf++;
2838         tmpbuf = srcbuf++;      /* max time */
2839         sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2840         idx++;
2841         srcbuf++;
2842         sprintf(a_cmData->data[idx], "%d", *srcbuf);    /* sum bytes */
2843         idx++;
2844         srcbuf++;
2845         sprintf(a_cmData->data[idx], "%d", *srcbuf);    /* min bytes */
2846         idx++;
2847         srcbuf++;
2848         sprintf(a_cmData->data[idx], "%d", *srcbuf);    /* max bytes */
2849         idx++;
2850         srcbuf++;
2851         for (j = 0; j < AFS_STATS_NUM_XFER_BUCKETS; j++) {
2852             sprintf(a_cmData->data[idx], "%d", *srcbuf);        /* bucket[j] */
2853             idx++;
2854             srcbuf++;
2855         }
2856     }
2857
2858     /*printf("Ending index value = %d\n",idx-1); */
2859
2860     /* copy CM operations timings */
2861
2862     srcbuf = (afs_int32 *) (fullP->rpc.cmRPCTimes);
2863     for (i = 0; i < AFS_STATS_NUM_CM_RPC_OPS; i++) {
2864         sprintf(a_cmData->data[idx], "%d", *srcbuf);    /* numOps */
2865         idx++;
2866         srcbuf++;
2867         sprintf(a_cmData->data[idx], "%d", *srcbuf);    /* numSuccesses */
2868         idx++;
2869         srcbuf++;
2870         tmpbuf = srcbuf++;      /* sum time */
2871         sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2872         idx++;
2873         srcbuf++;
2874         tmpbuf = srcbuf++;      /* sqr time */
2875         sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2876         idx++;
2877         srcbuf++;
2878         tmpbuf = srcbuf++;      /* min time */
2879         sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2880         idx++;
2881         srcbuf++;
2882         tmpbuf = srcbuf++;      /* max time */
2883         sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2884         idx++;
2885         srcbuf++;
2886     }
2887
2888     /*printf("Ending index value = %d\n",idx-1); */
2889
2890     /* copy authentication info */
2891
2892     srcbuf = (afs_int32 *) & (fullP->authent);
2893     numLongs = sizeof(struct afs_stats_AuthentInfo) / sizeof(afs_int32);
2894     for (i = 0; i < numLongs; i++) {
2895         sprintf(a_cmData->data[idx], "%d", *srcbuf);
2896         idx++;
2897         srcbuf++;
2898     }
2899
2900     /*printf("Ending index value = %d\n",idx-1); */
2901
2902     /* copy CM [un]replicated access info */
2903
2904     srcbuf = (afs_int32 *) & (fullP->accessinf);
2905     numLongs = sizeof(struct afs_stats_AccessInfo) / sizeof(afs_int32);
2906     for (i = 0; i < numLongs; i++) {
2907         sprintf(a_cmData->data[idx], "%d", *srcbuf);
2908         idx++;
2909         srcbuf++;
2910     }
2911
2912     /*printf("Ending index value = %d\n",idx-1); */
2913     return (0);
2914
2915 }                               /* cm_Results_ltoa */
2916
2917
2918 /*-----------------------------------------------------------------------
2919  * Function:    check_cm_thresholds()
2920  *
2921  * Description:
2922  *      Checks the thresholds and sets the overflow flag. Recall that the
2923  *      thresholds for each host are stored in the hostEntry lists
2924  *      [fs/cm]nameList arrays. The probe results are passed to this
2925  *      function in the display-ready format - ie., as strings. Though
2926  *      this looks stupid the overhead incurred in converting the strings
2927  *      back to floats and comparing them is insignificant and
2928  *      programming is easier this way.
2929  *      The threshold flags are a part of the display structures
2930  *      curr_[fs/cm]Data.
2931  *
2932  * Returns:
2933  *      0
2934  *----------------------------------------------------------------------*/
2935
2936 int
2937 check_cm_thresholds(struct afsmon_hostEntry *a_hostEntry,       /* ptr to hostEntry */
2938                     struct cm_Display_Data *a_Data)             /* ptr to cm data to be displayed */
2939 {                               /* check_cm_thresholds */
2940
2941     static char rn[] = "check_cm_thresholds";
2942     struct Threshold *threshP;
2943     double tValue;              /* threshold value */
2944     double pValue;              /* probe value */
2945     int i;
2946     int idx;
2947     int count;                  /* number of thresholds exceeded */
2948
2949     if (afsmon_debug) {
2950         fprintf(debugFD, "[ %s ] Called, a_hostEntry= %p, a_Data= %p\n", rn,
2951                 a_hostEntry, a_Data);
2952         fflush(debugFD);
2953     }
2954
2955     if (a_hostEntry->numThresh == 0) {
2956         /* store in ovf count ?? */
2957         return (0);
2958     }
2959
2960     count = 0;
2961     threshP = a_hostEntry->thresh;
2962     for (i = 0; i < a_hostEntry->numThresh; i++) {
2963         if (threshP->itemName[0] == '\0') {
2964             threshP++;
2965             continue;
2966         }
2967         idx = threshP->index;   /* positional index to the data array */
2968         tValue = atof(threshP->threshVal);      /* threshold value */
2969         pValue = atof(a_Data->data[idx]);       /* probe value */
2970         if (pValue > tValue) {
2971
2972             if (afsmon_debug) {
2973                 fprintf(debugFD,
2974                         "[ %s ] cm = %s, thresh ovf for %s, threshold= %s, probevalue= %s\n",
2975                         rn, a_hostEntry->hostName, threshP->itemName,
2976                         threshP->threshVal, a_Data->data[idx]);
2977                 fflush(debugFD);
2978             }
2979
2980             /* if the threshold is crossed, call the handler function
2981              * only if this was a transition -ie, if the threshold was
2982              * crossed in the last probe too just count & keep quite! */
2983
2984             if (!a_Data->threshOvf[idx]) {
2985                 a_Data->threshOvf[idx] = 1;
2986                 /* call the threshold handler if provided */
2987                 if (threshP->handler[0] != '\0') {
2988                     if (afsmon_debug) {
2989                         fprintf(debugFD, "[ %s ] Calling ovf handler %s\n",
2990                                 rn, threshP->handler);
2991                         fflush(debugFD);
2992                     }
2993                     execute_thresh_handler(threshP->handler, a_Data->hostName,
2994                                            CM, threshP->itemName,
2995                                            threshP->threshVal,
2996                                            a_Data->data[idx]);
2997                 }
2998             }
2999
3000             count++;
3001         } else
3002             /* in case threshold was previously crossed, blank it out */
3003             a_Data->threshOvf[idx] = 0;
3004         threshP++;
3005     }
3006     /* store the overflow count */
3007     a_Data->ovfCount = count;
3008
3009     return (0);
3010 }                               /* check_cm_thresholds */
3011
3012
3013 /*-----------------------------------------------------------------------
3014  * save_CM_data_forDisplay()
3015  *
3016  * Description:
3017  *      Does the following:
3018  *      - if the probe number changed (ie, a cycle completed) curr_cmData
3019  *      is copied to prev_cmData, curr_cmData zeroed and refresh the
3020  *      overview screen and file server screen with the new data.
3021  *      - store the results of the current probe from xstat_cm_Results into
3022  *      curr_cmData. ie., convert longs to strings.
3023  *      - check the thresholds
3024  *
3025  * Returns:
3026  *      Success: 0
3027  *      Failure: Exits afsmonitor.
3028  *
3029  *----------------------------------------------------------------------*/
3030
3031 int
3032 save_CM_data_forDisplay(struct xstat_cm_ProbeResults *a_cmResults)
3033 {                               /* save_CM_data_forDisplay */
3034
3035     static char rn[] = "save_CM_data_forDisplay";       /* routine name */
3036     struct cm_Display_Data *curr_cmDataP;
3037     struct cm_Display_Data *prev_cmDataP;
3038     struct afsmon_hostEntry *curr_host;
3039     static int results_Received = 0;    /* number of probes reveived in
3040                                          * the current cycle. If this is equal to numFS we got all
3041                                          * the data we want in this cycle and can now display it */
3042     int numBytes;
3043     int done;
3044     int code;
3045     int okay;
3046     int i;
3047
3048     if (afsmon_debug) {
3049         fprintf(debugFD, "[ %s ] Called, a_cmResults= %p\n", rn, a_cmResults);
3050         fflush(debugFD);
3051     }
3052
3053     /* store results in the display array */
3054
3055     okay = 0;
3056     curr_cmDataP = curr_cmData;
3057     for (i = 0; i < numCM; i++) {
3058         if ((strcasecmp(curr_cmDataP->hostName, a_cmResults->connP->hostName))
3059             == 0) {
3060             okay = 1;
3061             break;
3062         }
3063         curr_cmDataP++;
3064     }
3065
3066     if (!okay) {
3067         fprintf(stderr,
3068                 "[ %s ] Could not insert CM probe results for host %s in cm display array\n",
3069                 rn, a_cmResults->connP->hostName);
3070         afsmon_Exit(95);
3071     }
3072
3073     /*  Check the status of the probe. If it succeeded, we store its
3074      * results in the display data structure. If it failed we only mark
3075      * the failed status in the display data structure. */
3076
3077
3078     if (a_cmResults->probeOK) { /* 1 => notOK the xstat results */
3079         curr_cmDataP->probeOK = 0;
3080
3081         /* print the probe status */
3082         if (afsmon_debug) {
3083             fprintf(debugFD, "\n\t\t ----- cm display data ------\n");
3084             fprintf(debugFD, "HostName = %s  PROBE FAILED \n",
3085                     curr_cmDataP->hostName);
3086             fflush(debugFD);
3087         }
3088
3089     } else {                    /* probe succeeded, update display data structures */
3090         curr_cmDataP->probeOK = 1;
3091
3092
3093         /* covert longs to strings and place them in curr_cmDataP */
3094         cm_Results_ltoa(curr_cmDataP, a_cmResults);
3095
3096         /* compare with thresholds and set the overflow flags.
3097          * note that the threshold information is in the hostEntry structure and
3098          * each threshold item has a positional index associated with it */
3099
3100         /* locate the hostEntry for this host */
3101         done = 0;
3102         curr_host = CMnameList;
3103         for (i = 0; i < numCM; i++) {
3104             if (strcasecmp(curr_host->hostName, a_cmResults->connP->hostName)
3105                 == 0) {
3106                 done = 1;
3107                 break;
3108             }
3109             curr_host = curr_host->next;
3110         }
3111         if (!done)
3112             afsmon_Exit(100);
3113
3114         code = check_cm_thresholds(curr_host, curr_cmDataP);
3115         if (code) {
3116             fprintf(stderr, "[ %s ] Error in checking thresholds\n", rn);
3117             afsmon_Exit(105);
3118         }
3119
3120         /* print the info we just saved */
3121         if (afsmon_debug) {
3122             fprintf(debugFD, "\n\t\t ----- CM display data ------\n");
3123             fprintf(debugFD, "HostName = %s\n", curr_cmDataP->hostName);
3124             for (i = 0; i < NUM_CM_STAT_ENTRIES; i++) {
3125                 switch (i) {
3126                 case 0:
3127                     fprintf(debugFD, "\t -- Overall Perf Info --\n");
3128                     break;
3129                 case 39:
3130                     fprintf(debugFD,
3131                             "\t -- File Server up/down stats - same cell --\n");
3132                     break;
3133                 case 64:
3134                     fprintf(debugFD,
3135                             "\t -- File Server up/down stats - diff cell --\n");
3136                     break;
3137                 case 89:
3138                     fprintf(debugFD,
3139                             "\t -- VL server up/down stats - same cell --\n");
3140                     break;
3141                 case 114:
3142                     fprintf(debugFD,
3143                             "\t -- VL server up/down stats - diff cell --\n");
3144                     break;
3145                 case 139:
3146                     fprintf(debugFD, "\t -- FS Operation Timings --\n");
3147                     break;
3148                 case 279:
3149                     fprintf(debugFD, "\t -- FS Error Info --\n");
3150                     break;
3151                 case 447:
3152                     fprintf(debugFD, "\t -- FS Transfer Timings --\n");
3153                     break;
3154                 case 475:
3155                     fprintf(debugFD, "\t -- CM Operations Timings --\n");
3156                     break;
3157                 case 510:
3158                     fprintf(debugFD, "\t -- Authentication Info --\n");
3159                     break;
3160                 case 522:
3161                     fprintf(debugFD, "\t -- Access Info --\n");
3162                     break;
3163                 default:
3164                     break;
3165                 }
3166
3167                 fprintf(debugFD, "%20s  %30s %s\n", curr_cmDataP->data[i],
3168                         cm_varNames[i],
3169                         curr_cmDataP->threshOvf[i] ? "(ovf)" : "");
3170             }
3171             fprintf(debugFD, "\t\t--------------------------------\n\n");
3172         }
3173
3174     }                           /* if the probe succeeded, update the display data structures */
3175
3176     /* if we have received a reply from all the hosts for this probe cycle,
3177      * it is time to display the data */
3178
3179     results_Received++;
3180     if (results_Received == numCM * num_cm_collections) {
3181         results_Received = 0;
3182
3183         if (afsmon_cm_curr_probeNum != afsmon_cm_prev_probeNum + 1) {
3184             sprintf(errMsg, "[ %s ] Probe number %d missed! \n", rn,
3185                     afsmon_cm_prev_probeNum + 1);
3186             afsmon_Exit(110);
3187         } else
3188             afsmon_cm_prev_probeNum++;
3189
3190
3191         /* backup the display data of the probe cycle that just completed -
3192          * ie., store curr_cmData in prev_cmData */
3193
3194         memcpy((char *)prev_cmData, (char *)curr_cmData,
3195                (numCM * sizeof(struct cm_Display_Data)));
3196
3197
3198         /* initialize curr_cmData but retain the threshold flag information.
3199          * The previous state of threshold flags is used in check_cm_thresholds() */
3200
3201         curr_cmDataP = curr_cmData;
3202         numBytes = NUM_CM_STAT_ENTRIES * CM_STAT_STRING_LEN;
3203         for (i = 0; i < numCM; i++) {
3204             curr_cmDataP->probeOK = 0;
3205             curr_cmDataP->ovfCount = 0;
3206             memset(curr_cmDataP->data, 0, numBytes);
3207             curr_cmDataP++;
3208         }
3209
3210         /* prev_cmData now contains all the information for the probe cycle
3211          * that just completed. Now count the number of threshold overflows for
3212          * use in the overview screen */
3213
3214         prev_cmDataP = prev_cmData;
3215         num_cm_alerts = 0;
3216         numHosts_oncm_alerts = 0;
3217         for (i = 0; i < numCM; i++) {
3218             if (!prev_cmDataP->probeOK) {       /* if probe failed */
3219                 num_cm_alerts++;
3220                 numHosts_oncm_alerts++;
3221             } else if (prev_cmDataP->ovfCount) {        /* overflows ?? */
3222                 num_cm_alerts += prev_cmDataP->ovfCount;
3223                 numHosts_oncm_alerts++;
3224             }
3225             prev_cmDataP++;
3226         }
3227         if (afsmon_debug)
3228             fprintf(debugFD, "Number of CM alerts = %d (on %d hosts)\n",
3229                     num_cm_alerts, numHosts_oncm_alerts);
3230
3231
3232         /* flag that the data is now ready to be displayed */
3233         cm_Data_Available = 1;
3234
3235         /* update the Overview frame (only CM info) */
3236         ovw_refresh(ovw_currPage, OVW_UPDATE_CM);
3237
3238         /* update the Cache Managers frame */
3239         cm_refresh(cm_currPage, cm_curr_LCol);
3240
3241     }
3242
3243
3244     return (0);
3245 }                               /* save_CM_data_forDisplay */
3246
3247
3248
3249 /*-----------------------------------------------------------------------
3250  * afsmon_CM_Handler()
3251  *
3252  * Description:
3253  *      This is the Cache Manager probe Handler. It updates the afsmonitor
3254  *      probe counts, cm circular buffer indices and calls the functions
3255  *      to process the results of this probe.
3256  *
3257  * Returns:
3258  *      Success: 0
3259  *      Failure: Exits afsmonitor.
3260  *----------------------------------------------------------------------*/
3261
3262 int
3263 afsmon_CM_Handler(void)
3264 {                               /* afsmon_CM_Handler() */
3265     static char rn[] = "afsmon_CM_Handler";     /* routine name */
3266     int code;                   /* return status */
3267     int newProbeCycle;          /* start of new probe cycle ? */
3268
3269     if (afsmon_debug) {
3270         fprintf(debugFD,
3271                 "[ %s ] Called, hostName= %s, probeNum= %d, status= %s\n", rn,
3272                 xstat_cm_Results.connP->hostName, xstat_cm_Results.probeNum,
3273                 xstat_cm_Results.probeOK ? "FAILED" : "OK");
3274         fflush(debugFD);
3275     }
3276
3277
3278     /* print the probe results to output file */
3279     if (afsmon_output) {
3280         code = afsmon_cmOutput(output_filename, afsmon_detOutput);
3281         if (code) {
3282             fprintf(stderr,
3283                     "[ %s ] output to file %s returned error code=%d\n", rn,
3284                     output_filename, code);
3285         }
3286     }
3287
3288     /* Update current probe number and circular buffer index. if current
3289      * probenum changed make sure it is only by 1 */
3290
3291     newProbeCycle = 0;
3292     if (xstat_cm_Results.probeNum != afsmon_cm_curr_probeNum) {
3293         if (xstat_cm_Results.probeNum == afsmon_cm_curr_probeNum + 1) {
3294             afsmon_cm_curr_probeNum++;
3295             newProbeCycle = 1;
3296             if (num_bufSlots)
3297                 afsmon_cm_curr_CBindex =
3298                     (afsmon_cm_curr_probeNum - 1) % num_bufSlots;
3299         } else {
3300             fprintf(stderr, "[ %s ] probe number %d-1 missed\n", rn,
3301                     xstat_cm_Results.probeNum);
3302             afsmon_Exit(115);
3303         }
3304     }
3305
3306     /* save the results of this probe in the CM buffer */
3307     if (num_bufSlots)
3308         save_CM_results_inCB(newProbeCycle);
3309
3310     /* store the results of the current probe in the cm data display structure.
3311      * if the current probe number changed, swap the current and previous display
3312      * structures. note that the display screen is updated from these structures
3313      * and should start showing the data of the just completed probe cycle */
3314
3315     save_CM_data_forDisplay(&xstat_cm_Results);
3316
3317     return (0);
3318 }
3319
3320 /*-----------------------------------------------------------------------
3321  * init_fs_buffers()
3322  *
3323  * Description:
3324  *      Allocate and Initialize circular buffers for file servers.
3325  *
3326  * Returns:
3327  *      Success: 0
3328  *      Failure to allocate memory: exits afsmonitor.
3329  *----------------------------------------------------------------------*/
3330
3331 int
3332 init_fs_buffers(void)
3333 {                               /* init_fs_buffers() */
3334     static char rn[] = "init_fs_buffers";       /* routine name */
3335     struct afsmon_fs_Results_list *new_fslist_item;     /* ptr for new struct */
3336     struct afsmon_fs_Results_list *tmp_fslist_item;     /* temp ptr */
3337     struct xstat_fs_ProbeResults *new_fsPR;     /* ptr for new struct  */
3338     int i, j;
3339     int bufslot;
3340     int numfs;
3341
3342
3343     if (afsmon_debug) {
3344         fprintf(debugFD, "[ %s ] Called\n", rn);
3345         fflush(debugFD);
3346     }
3347
3348     /* allocate memory for the circular buffer of pointers */
3349
3350     afsmon_fs_ResultsCB = (struct afsmon_fs_Results_CBuffer *)
3351         malloc(sizeof(struct afsmon_fs_Results_CBuffer) * num_bufSlots);
3352
3353     /* initialize the fs circular buffer */
3354     for (i = 0; i < num_bufSlots; i++) {
3355         afsmon_fs_ResultsCB[i].list = (struct afsmon_fs_Results_list *)0;
3356         afsmon_fs_ResultsCB[i].probeNum = 0;
3357     }
3358
3359     /* create  a list of numFS items to store fs probe results for
3360      * each slot in CB */
3361
3362     if (numFS) {                /* if we have file servers to monitor */
3363         for (bufslot = 0; bufslot < num_bufSlots; bufslot++) {
3364             numfs = numFS;      /* get the number of servers */
3365             while (numfs--) {
3366
3367                 /* if any of these mallocs fail we only need to free the memory we
3368                  * have allocated in this iteration. the rest of it which is in a
3369                  * proper linked list will be freed in afsmon_Exit */
3370
3371                 /* allocate memory for an fs list item */
3372                 new_fslist_item = (struct afsmon_fs_Results_list *)
3373                     malloc(sizeof(struct afsmon_fs_Results_list));
3374                 if (new_fslist_item == (struct afsmon_fs_Results_list *)0)
3375                     return (-1);
3376
3377                 for (i = 0; i < MAX_NUM_FS_COLLECTIONS; i++) {
3378                     /* allocate memory to store xstat_fs_Results */
3379                     new_fsPR = (struct xstat_fs_ProbeResults *)
3380                         malloc(sizeof(struct xstat_fs_ProbeResults));
3381                     if (!new_fsPR) {
3382                         free(new_fslist_item);
3383                         return (-1);
3384                     }
3385
3386                     new_fsPR->connP = (struct xstat_fs_ConnectionInfo *)
3387                         malloc(sizeof(struct xstat_fs_ConnectionInfo));
3388                     if (new_fsPR->connP == (struct xstat_fs_ConnectionInfo *)0) {
3389                         free(new_fslist_item);
3390                         free(new_fsPR);
3391                         return (-1);
3392                     }
3393
3394                     /* >>>  need to allocate rx connection info structure here <<< */
3395                     new_fsPR->data.AFS_CollData_val = (afs_int32 *)
3396                        malloc(afsmon_fs_results_length[i] * sizeof(afs_int32));
3397                     if (new_fsPR->data.AFS_CollData_val == NULL) {
3398                        free(new_fslist_item);
3399                        free(new_fsPR->connP);
3400                        free(new_fsPR);
3401                        return (-1);
3402                     }
3403                     new_fslist_item->fsResults[i] = new_fsPR;
3404                     new_fslist_item->empty[i] = 1;
3405                 }
3406
3407                 /* initialize this list entry */
3408                 new_fslist_item->next = (struct afsmon_fs_Results_list *)0;
3409
3410                 /* store it at the end of the fs list in the current CB slot */
3411                 if (afsmon_fs_ResultsCB[bufslot].list ==
3412                     (struct afsmon_fs_Results_list *)0)
3413                     afsmon_fs_ResultsCB[bufslot].list = new_fslist_item;
3414                 else {
3415                     tmp_fslist_item = afsmon_fs_ResultsCB[bufslot].list;
3416                     j = 0;
3417                     while (tmp_fslist_item !=
3418                            (struct afsmon_fs_Results_list *)0) {
3419                         if (tmp_fslist_item->next ==
3420                             (struct afsmon_fs_Results_list *)0)
3421                             break;
3422                         tmp_fslist_item = tmp_fslist_item->next;
3423                         if (++j > numFS) {
3424                             /* something goofed. exit */
3425                             fprintf(stderr, "[ %s ] list creation error\n",
3426                                     rn);
3427                             return (-1);
3428                         }
3429                     }
3430                     tmp_fslist_item->next = new_fslist_item;
3431                 }
3432
3433             }                   /* while servers */
3434         }                       /* for each buffer slot */
3435     }                           /* if we have file servers to monitor */
3436     return (0);
3437 }
3438
3439 /*-----------------------------------------------------------------------
3440  * init_cm_buffers()
3441  *
3442  * Description:
3443  *      Allocate and Initialize circular buffers for cache managers.
3444  *
3445  * Returns:
3446  *      Success: 0
3447  *      Failure to allocate memory: exits afsmonitor.
3448  *----------------------------------------------------------------------*/
3449
3450 int
3451 init_cm_buffers(void)
3452 {                               /* init_cm_buffers() */
3453     static char rn[] = "init_cm_buffers";       /* routine name */
3454     struct afsmon_cm_Results_list *new_cmlist_item;     /* ptr for new struct */
3455     struct afsmon_cm_Results_list *tmp_cmlist_item;     /* temp ptr */
3456     struct xstat_cm_ProbeResults *new_cmPR;     /* ptr for new struct  */
3457     int i, j;
3458     int bufslot;
3459     int numcm;
3460
3461     if (afsmon_debug) {
3462         fprintf(debugFD, "[ %s ] Called\n", rn);
3463         fflush(debugFD);
3464     }
3465
3466     /* allocate memory for the circular buffer of pointers */
3467     afsmon_cm_ResultsCB = (struct afsmon_cm_Results_CBuffer *)
3468         malloc(sizeof(struct afsmon_cm_Results_CBuffer) * num_bufSlots);
3469
3470     /* initialize the fs circular buffer */
3471     for (i = 0; i < num_bufSlots; i++) {
3472         afsmon_cm_ResultsCB[i].list = (struct afsmon_cm_Results_list *)0;
3473         afsmon_cm_ResultsCB[i].probeNum = 0;
3474     }
3475
3476     /* create  a list of numCM items to store fs probe results for
3477      * each slot in CB */
3478
3479     if (numCM) {                /* if we have file servers to monitor */
3480         for (bufslot = 0; bufslot < num_bufSlots; bufslot++) {
3481             numcm = numCM;      /* get the number of servers */
3482             while (numcm--) {
3483
3484                 /* if any of these mallocs fail we only need to free the memory we
3485                  * have allocated in this iteration. the rest of it which is in a
3486                  * proper linked list will be freed in afsmon_Exit */
3487
3488                 /* allocate memory for an fs list item */
3489                 new_cmlist_item = (struct afsmon_cm_Results_list *)
3490                     malloc(sizeof(struct afsmon_cm_Results_list));
3491                 if (new_cmlist_item == (struct afsmon_cm_Results_list *)0)
3492                     return (-1);
3493
3494                 for (i = 0; i < MAX_NUM_CM_COLLECTIONS; i++) {
3495                     /* allocate memory to store xstat_cm_Results */
3496                     new_cmPR = (struct xstat_cm_ProbeResults *)
3497                         malloc(sizeof(struct xstat_cm_ProbeResults));
3498                     if (!new_cmPR) {
3499                         free(new_cmlist_item);
3500                         return (-1);
3501                     }
3502                     new_cmPR->connP = (struct xstat_cm_ConnectionInfo *)
3503                         malloc(sizeof(struct xstat_cm_ConnectionInfo));
3504                     if (!new_cmPR->connP) {
3505                         free(new_cmlist_item);
3506                         free(new_cmPR);
3507                         return (-1);
3508                     }
3509
3510                     /* >>>  need to allocate rx connection info structure here <<< */
3511
3512                     new_cmPR->data.AFSCB_CollData_val =
3513                         malloc(XSTAT_CM_FULLPERF_RESULTS_LEN
3514                                *sizeof(afs_int32));
3515                     if (new_cmPR->data.AFSCB_CollData_val == NULL) {
3516                         free(new_cmlist_item);
3517                         free(new_cmPR->connP);
3518                         free(new_cmPR);
3519                         return (-1);
3520                     }
3521
3522                     new_cmlist_item->cmResults[i] = new_cmPR;
3523                     new_cmlist_item->empty[i] = 1;
3524                 }
3525
3526                 /* initialize this list entry */
3527                 new_cmlist_item->next = (struct afsmon_cm_Results_list *)0;
3528
3529                 /* store it at the end of the cm list in the current CB slot */
3530                 if (afsmon_cm_ResultsCB[bufslot].list ==
3531                     (struct afsmon_cm_Results_list *)0)
3532                     afsmon_cm_ResultsCB[bufslot].list = new_cmlist_item;
3533                 else {
3534                     tmp_cmlist_item = afsmon_cm_ResultsCB[bufslot].list;
3535                     j = 0;
3536                     while (tmp_cmlist_item !=
3537                            (struct afsmon_cm_Results_list *)0) {
3538                         if (tmp_cmlist_item->next ==
3539                             (struct afsmon_cm_Results_list *)0)
3540                             break;
3541                         tmp_cmlist_item = tmp_cmlist_item->next;
3542                         if (++j > numCM) {
3543                             /* something goofed. exit */
3544                             fprintf(stderr, "[ %s ] list creation error\n",
3545                                     rn);
3546                             return (-1);
3547                         }
3548                     }
3549                     tmp_cmlist_item->next = new_cmlist_item;
3550                 }
3551
3552             }                   /* while servers */
3553         }                       /* for each buffer slot */
3554     }
3555     /* if we have file servers to monitor */
3556     /* print the CB to make sure it is right */
3557     Print_CM_CB();
3558
3559     return (0);
3560 }                               /* init_cm_buffers() */
3561
3562
3563 /*-------------------------------------------------------------------------
3564  * init_print_buffers()
3565  *
3566  * Description:
3567  *      Allocate and initialize the buffers used for printing results
3568  *      to the display screen. These buffers store the current and
3569  *      previous probe results in ascii format.
3570  *
3571  * Returns:
3572  *      Success: 0
3573  *      Failure: < 0
3574  *------------------------------------------------------------------------*/
3575
3576 int
3577 init_print_buffers(void)
3578 {                               /* init_print_buffers */
3579
3580     static char rn[] = "init_print_buffers";    /* routine name */
3581     struct fs_Display_Data *tmp_fsData1;        /* temp pointers */
3582     struct fs_Display_Data *tmp_fsData2;
3583     struct cm_Display_Data *tmp_cmData1;
3584     struct cm_Display_Data *tmp_cmData2;
3585     struct afsmon_hostEntry *tmp_fsNames;
3586     struct afsmon_hostEntry *tmp_cmNames;
3587     int i;
3588     int numBytes;
3589
3590     if (afsmon_debug) {
3591         fprintf(debugFD, "[ %s ] Called\n", rn);
3592         fflush(debugFD);
3593     }
3594
3595     /* allocate numFS blocks of the FS print structure. */
3596
3597     /* we need two instances of this structure - one (curr_fsData) for storing
3598      * the results of the fs probes currently in progress and another (prev_fsData)
3599      * for the last completed probe. The display is updated from the contents of
3600      * prev_fsData. The pointers curr_fsData & prev_fsData are switched whenever
3601      * the probe number changes */
3602
3603     if (numFS) {
3604         numBytes = numFS * sizeof(struct fs_Display_Data);
3605         curr_fsData = malloc(numBytes);
3606         if (curr_fsData == (struct fs_Display_Data *)0) {
3607             fprintf(stderr, "[ %s ] Memory allocation failure\n", rn);
3608             return (-1);
3609         }
3610         memset(curr_fsData, 0, numBytes);
3611
3612         numBytes = numFS * sizeof(struct fs_Display_Data);
3613         prev_fsData = malloc(numBytes);
3614         if (prev_fsData == (struct fs_Display_Data *)0) {
3615             fprintf(stderr, "[ %s ] Memory allocation failure\n", rn);
3616             return (-5);
3617         }
3618         memset(prev_fsData, 0, numBytes);
3619
3620         /* fill in the host names */
3621         tmp_fsData1 = curr_fsData;
3622         tmp_fsData2 = curr_fsData;
3623         tmp_fsNames = FSnameList;
3624         for (i = 0; i < numFS; i++) {
3625             strncpy(tmp_fsData1->hostName, tmp_fsNames->hostName,
3626                     HOST_NAME_LEN);
3627             strncpy(tmp_fsData2->hostName, tmp_fsNames->hostName,
3628                     HOST_NAME_LEN);
3629             tmp_fsData1++;
3630             tmp_fsData2++;
3631             tmp_fsNames = tmp_fsNames->next;;
3632         }
3633
3634     }
3635
3636     /* if file servers to monitor */
3637     /* allocate numCM blocks of the CM print structure */
3638     /* we need two instances of this structure for the same reasons as above */
3639     if (numCM) {
3640         numBytes = numCM * sizeof(struct cm_Display_Data);
3641
3642         curr_cmData = malloc(numBytes);
3643         if (curr_cmData == (struct cm_Display_Data *)0) {
3644             fprintf(stderr, "[ %s ] Memory allocation failure\n", rn);
3645             return (-10);
3646         }
3647         memset(curr_cmData, 0, numBytes);
3648
3649         numBytes = numCM * sizeof(struct cm_Display_Data);
3650         prev_cmData = malloc(numBytes);
3651         if (prev_cmData == (struct cm_Display_Data *)0) {
3652             fprintf(stderr, "[ %s ] Memory allocation failure\n", rn);
3653             return (-15);
3654         }
3655         memset(prev_cmData, 0, numBytes);
3656
3657         /* fill in the host names */
3658         tmp_cmData1 = curr_cmData;
3659         tmp_cmData2 = curr_cmData;
3660         tmp_cmNames = CMnameList;
3661         for (i = 0; i < numCM; i++) {
3662             strncpy(tmp_cmData1->hostName, tmp_cmNames->hostName,
3663                     HOST_NAME_LEN);
3664             strncpy(tmp_cmData2->hostName, tmp_cmNames->hostName,
3665                     HOST_NAME_LEN);
3666             tmp_cmData1++;
3667             tmp_cmData2++;
3668             tmp_cmNames = tmp_cmNames->next;;
3669         }
3670
3671     }
3672     /* if cache managers to monitor */
3673     return (0);
3674
3675 }                               /* init_print_buffers */
3676
3677 /*-----------------------------------------------------------------------
3678  * quit_signal()
3679  *
3680  * Description:
3681  *      Trap the interrupt signal. This function is useful only until
3682  *      gtx is initialized.
3683  *----------------------------------------------------------------------*/
3684
3685 void
3686 quit_signal(int sig)
3687 {                               /* quit_signal */
3688     fprintf(stderr, "Received signal %d \n", sig);
3689     afsmon_Exit(120);
3690 }                               /* quit_signal */
3691
3692
3693
3694 /*-----------------------------------------------------------------------
3695  * afsmon_execute()
3696  *
3697  * Description:
3698  *      This is where we start it all. Initialize an array of sockets for
3699  *      file servers and cache cache managers and call the xstat_[fs/cm]_Init
3700  *      routines. The last step is to call the gtx input server which
3701  *      grabs control of the keyboard.
3702  *
3703  * Returns:
3704  *      Does not return. Control is periodically returned to the afsmonitor
3705  *      thru afsmon_[FS/CM]_Handler() routines and also through the gtx
3706  *      keyboard handler calls.
3707  *
3708  *----------------------------------------------------------------------*/
3709
3710 int
3711 afsmon_execute(void)
3712 {                               /* afsmon_execute() */
3713     static char rn[] = "afsmon_execute";        /* routine name */
3714     static char fullhostname[128];      /* full host name */
3715     struct sockaddr_in *FSSktArray;     /* fs socket array */
3716     int FSsktbytes;             /* num bytes in above */
3717     struct sockaddr_in *CMSktArray;     /* cm socket array */
3718     int CMsktbytes;             /* num bytes in above */
3719     struct sockaddr_in *curr_skt;       /* ptr to current socket */
3720     struct afsmon_hostEntry *curr_FS;   /* ptr to FS name list */
3721     struct afsmon_hostEntry *curr_CM;   /* ptr to CM name list */
3722     struct hostent *he;         /* host entry */
3723     int FSinitFlags = 0;        /* flags for xstat_fs_Init */
3724     int CMinitFlags = 0;        /* flags for xstat_cm_Init */
3725     int code;                   /* function return code */
3726     int i;
3727     short index;
3728
3729     if (afsmon_debug) {
3730         fprintf(debugFD, "[ %s ] Called\n", rn);
3731         fflush(debugFD);
3732     }
3733
3734
3735     /* process file server entries */
3736     if (numFS) {
3737         afs_int32 collIDs[MAX_NUM_FS_COLLECTIONS];
3738
3739         /* Allocate an array of sockets for each fileserver we monitor */
3740
3741         FSsktbytes = numFS * sizeof(struct sockaddr_in);
3742         FSSktArray = malloc(FSsktbytes);
3743         if (FSSktArray == (struct sockaddr_in *)0) {
3744             fprintf(stderr,
3745                     "[ %s ] cannot malloc %d sockaddr_ins for fileservers\n",
3746                     rn, numFS);
3747             return (-1);
3748         }
3749
3750         memset(FSSktArray, 0, FSsktbytes);
3751
3752         /* Fill in the socket information for each fileserve */
3753
3754         curr_skt = FSSktArray;
3755         curr_FS = FSnameList;   /* FS name list header */
3756         while (curr_FS) {
3757             strncpy(fullhostname, curr_FS->hostName, sizeof(fullhostname));
3758             he = GetHostByName(fullhostname);
3759             if (he == NULL) {
3760                 fprintf(stderr, "[ %s ] Cannot get host info for %s\n", rn,
3761                         fullhostname);
3762                 return (-1);
3763             }
3764             strncpy(curr_FS->hostName, he->h_name, HOST_NAME_LEN);      /* complete name */
3765             memcpy(&(curr_skt->sin_addr.s_addr), he->h_addr, 4);
3766             curr_skt->sin_family = AF_INET;             /*Internet family */
3767             curr_skt->sin_port = htons(7000);   /*FileServer port */
3768 #ifdef STRUCT_SOCKADDR_HAS_SA_LEN
3769             curr_skt->sin_len = sizeof(struct sockaddr_in);
3770 #endif
3771
3772             /* get the next dude */
3773             curr_skt++;
3774             curr_FS = curr_FS->next;
3775         }
3776
3777         /* Initialize collection IDs, depending on the data requested. */
3778         num_fs_collections = 0;
3779         for (i = 0; i < fs_DisplayItems_count; i++) {
3780             index = fs_Display_map[i];
3781             if (FS_FULLPERF_ENTRY_START <= index && index <= FS_FULLPERF_ENTRY_END) {
3782                 collIDs[num_fs_collections++] = AFS_XSTATSCOLL_FULL_PERF_INFO;
3783                 break;
3784             }
3785         }
3786         for (i = 0; i < fs_DisplayItems_count; i++) {
3787             index = fs_Display_map[i];
3788             if (FS_CB_ENTRY_START <= index && index <= FS_CB_ENTRY_END) {
3789                 collIDs[num_fs_collections++] = AFS_XSTATSCOLL_CBSTATS;
3790                 break;
3791             }
3792         }
3793
3794         FSinitFlags = 0;
3795
3796         if (afsmon_debug) {
3797             fprintf(debugFD, "[ %s ] Calling xstat_fs_Init \n", rn);
3798             fflush(debugFD);
3799         }
3800
3801         code = xstat_fs_Init(numFS,     /*Num servers */
3802                              FSSktArray,        /*File Server socket array */
3803                              afsmon_probefreq,  /*probe frequency */
3804                              afsmon_FS_Handler, /*Handler routine */
3805                              FSinitFlags,       /*Initialization flags */
3806                              num_fs_collections,        /*Number of collection IDs */
3807                              collIDs);  /*Ptr to collection ID */
3808
3809         if (code) {
3810             fprintf(stderr, "[ %s ] xstat_fs_init returned error\n", rn);
3811             afsmon_Exit(125);
3812         }
3813
3814     }
3815
3816
3817     /* end of process fileserver entries */
3818     /* process cache manager entries */
3819     if (numCM) {
3820         afs_int32 collIDs[MAX_NUM_CM_COLLECTIONS];
3821
3822         /* Allocate an array of sockets for each cache manager we monitor */
3823
3824         CMsktbytes = numCM * sizeof(struct sockaddr_in);
3825         CMSktArray = malloc(CMsktbytes);
3826         if (CMSktArray == (struct sockaddr_in *)0) {
3827             fprintf(stderr,
3828                     "[ %s ] cannot malloc %d sockaddr_ins for CM entries\n",
3829                     rn, numCM);
3830             return (-1);
3831         }
3832
3833         memset(CMSktArray, 0, CMsktbytes);
3834
3835         /* Fill in the socket information for each CM        */
3836
3837         curr_skt = CMSktArray;
3838         curr_CM = CMnameList;   /* CM name list header */
3839         while (curr_CM) {
3840             strncpy(fullhostname, curr_CM->hostName, sizeof(fullhostname));
3841             he = GetHostByName(fullhostname);
3842             if (he == NULL) {
3843                 fprintf(stderr, "[ %s ] Cannot get host info for %s\n", rn,
3844                         fullhostname);
3845                 return (-1);
3846             }
3847             strncpy(curr_CM->hostName, he->h_name, HOST_NAME_LEN);      /* complete name */
3848             memcpy(&(curr_skt->sin_addr.s_addr), he->h_addr, 4);
3849             curr_skt->sin_family = AF_INET;
3850             curr_skt->sin_port = htons(7001);   /* Cache Manager port */
3851 #ifdef STRUCT_SOCKADDR_HAS_SA_LEN
3852             curr_skt->sin_len = sizeof(struct sockaddr_in);
3853 #endif
3854
3855             /* get the next dude */
3856             curr_skt++;
3857             curr_CM = curr_CM->next;
3858         }
3859
3860         /* initialize collection IDs. We need only one entry since we collect
3861          * all the information from xstat */
3862         num_cm_collections = 0;
3863         collIDs[num_cm_collections++] = AFSCB_XSTATSCOLL_FULL_PERF_INFO;
3864
3865         CMinitFlags = 0;
3866
3867         if (afsmon_debug) {
3868             fprintf(debugFD, "[ %s ] Calling xstat_cm_Init \n", rn);
3869             fflush(debugFD);
3870         }
3871
3872         code = xstat_cm_Init(numCM,     /*Num servers */
3873                              CMSktArray,        /*Cache Manager  socket array */
3874                              afsmon_probefreq,  /*probe frequency */
3875                              afsmon_CM_Handler, /*Handler routine */
3876                              CMinitFlags,       /*Initialization flags */
3877                              num_cm_collections,        /*Number of collection IDs */
3878                              collIDs);  /*Ptr to collection ID */
3879
3880         if (code) {
3881             fprintf(stderr, "[ %s ] xstat_cm_init returned error\n", rn);
3882             afsmon_Exit(130);
3883         }
3884     }
3885
3886
3887
3888     /* end of process cache manager entries */
3889
3890     /* start the gtx input server */
3891     code = (intptr_t)gtx_InputServer(afsmon_win);
3892     if (code) {
3893         fprintf(stderr, "[ %s ] Failed to start input server \n", rn);
3894         afsmon_Exit(140);
3895     }
3896
3897     /* This part of the code is reached only if the input server is not started
3898      * for debugging purposes */
3899     xstat_cm_Wait(0); /* sleep forever */
3900     return 0;
3901 }
3902
3903
3904 /*-----------------------------------------------------------------------
3905  * afsmonInit()
3906  *
3907  * Description:
3908  *      Afsmonitor initialization routine.
3909  *      - processes command line parameters
3910  *      - call functions to:
3911  *              - process config file
3912  *              - initialize circular buffers and display buffers
3913  *              - initialize gtx
3914  *              - execute afsmonitor
3915  *      - initialize the display maps [fs/cm]_Display_map[].
3916  *
3917  * Returns:
3918  *      Success: Does not return from the call to afsmon_execute().
3919  *      Failure: Exits afsmonitor.
3920  *----------------------------------------------------------------------*/
3921
3922 int
3923 afsmonInit(struct cmd_syndesc *as, void *arock)
3924 {                               /* afsmonInit() */
3925
3926     static char rn[] = "afsmonInit";    /* Routine name */
3927     char *debug_filename;       /* pointer to debug filename */
3928     FILE *outputFD;             /* output file descriptor */
3929     struct cmd_item *hostPtr;   /* ptr to parse command line args */
3930     char buf[256];              /* buffer for processing hostnames */
3931     int code;
3932     int i;
3933
3934     if (afsmon_debug) {
3935         fprintf(debugFD, "[ %s ] Called, as= %p\n", rn, as);
3936         fflush(debugFD);
3937     }
3938
3939     /* Open  the debug file if -debug option is specified */
3940     if (as->parms[P_DEBUG].items != 0) {
3941         afsmon_debug = 1;
3942         debug_filename = as->parms[P_DEBUG].items->data;
3943         debugFD = fopen(debug_filename, "w");
3944         if (debugFD == (FILE *) 0) {
3945             printf("[ %s ] Failed to open debugging file %s for writing\n",
3946                    rn, "log");
3947             afsmon_debug = 0;
3948             afsmon_Exit(150);
3949         }
3950     }
3951
3952     if (afsmon_debug) {
3953         fprintf(debugFD, "[ %s ] Called\n", rn);
3954     }
3955
3956
3957     /* use curses always until we support other packages */
3958 #ifdef notdef
3959     wpkg_to_use = atoi(as->parms[P_PACKAGE].items->data);
3960
3961     switch (wpkg_to_use) {
3962     case GATOR_WIN_CURSES:
3963         fprintf(stderr, "curses\n");
3964         break;
3965     case GATOR_WIN_DUMB:
3966         fprintf(stderr, "dumb terminal\n");
3967         break;
3968     case GATOR_WIN_X11:
3969         fprintf(stderr, "X11\n");
3970         break;
3971     default:
3972         fprintf(stderr, "Illegal graphics package: %d\n", wpkg_to_use);
3973         afsmon_Exit(155);
3974     }                           /*end switch (wpkg_to_use) */
3975 #endif
3976
3977     wpkg_to_use = GATOR_WIN_CURSES;
3978
3979     /* get probe frequency . We check for meaningful bounds on the frequency
3980      * and reset to the default value if needed. The upper bound of 24
3981      * hours looks ridiculous though! */
3982
3983     afsmon_probefreq = 0;
3984     if (as->parms[P_FREQUENCY].items != 0)
3985         afsmon_probefreq = atoi(as->parms[P_FREQUENCY].items->data);
3986     else
3987         afsmon_probefreq = DEFAULT_FREQUENCY;
3988
3989     if (afsmon_probefreq <= 0 || afsmon_probefreq > 24 * 60 * 60) {
3990         afsmon_probefreq = DEFAULT_FREQUENCY;
3991         if (afsmon_debug) {
3992             fprintf(debugFD,
3993                     "[ %s ] Invalid probe frequency %s specified, resetting to default value %d seconds\n",
3994                     rn, as->parms[P_FREQUENCY].items->data, afsmon_probefreq);
3995             fflush(debugFD);
3996         }
3997         fprintf(stderr,
3998                 "Invalid probe frequency %s specified, resetting to default value %d seconds\n",
3999                 as->parms[P_FREQUENCY].items->data, afsmon_probefreq);
4000         sleep(3);
4001     }
4002
4003
4004     /* make sure output file is writable, else complain now */
4005     /* we will open and close it as needed after probes */
4006
4007     if (as->parms[P_OUTPUT].items != 0) {
4008         afsmon_output = 1;      /* output flag */
4009         strncpy(output_filename, as->parms[P_OUTPUT].items->data, 80);
4010         outputFD = fopen(output_filename, "a");
4011         if (outputFD == (FILE *) 0) {
4012             fprintf(stderr, "Failed to open output file %s \n",
4013                     output_filename);
4014             if (afsmon_debug) {
4015                 fprintf(debugFD, "[ %s ] Failed to open output file %s \n",
4016                         rn, output_filename);
4017                 afsmon_Exit(160);
4018             }
4019         }
4020         if (afsmon_debug) {
4021             fprintf(debugFD, "[ %s ] output file is %s\n", rn,
4022                     output_filename);
4023         }
4024         fclose(outputFD);
4025     }
4026
4027     /* detailed statistics to storage file */
4028     if (as->parms[P_DETAILED].items != 0) {
4029         if (as->parms[P_OUTPUT].items == 0) {
4030             fprintf(stderr,
4031                     "-detailed switch can be used only with -output\n");
4032             afsmon_Exit(165);
4033         }
4034         afsmon_detOutput = 1;
4035     }
4036
4037     /* Initialize host list headers */
4038     FSnameList = (struct afsmon_hostEntry *)0;
4039     CMnameList = (struct afsmon_hostEntry *)0;
4040
4041     /* The -config option is mutually exclusive with the -fshosts,-cmhosts
4042      * options */
4043
4044     if (as->parms[P_CONFIG].items) {
4045         if (as->parms[P_FSHOSTS].items || as->parms[P_CMHOSTS].items) {
4046             fprintf(stderr,
4047                     "Cannot use -config option with -fshosts or -cmhosts\n");
4048             afsmon_Exit(170);
4049         }
4050     } else {
4051         if (!as->parms[P_FSHOSTS].items && !as->parms[P_CMHOSTS].items) {
4052             fprintf(stderr,
4053                     "Must specify either -config or (-fshosts and/or -cmhosts) options \n");
4054             afsmon_Exit(175);
4055         }
4056     }
4057
4058
4059     /* If a file server host is specified on the command line we reuse
4060      * parse_hostEntry() function . Just the pass the info as if it were
4061      * read off the config file */
4062
4063     if (as->parms[P_FSHOSTS].items) {
4064         hostPtr = as->parms[P_FSHOSTS].items;
4065         while (hostPtr != (struct cmd_item *)0) {
4066             sprintf(buf, "fs %s", hostPtr->data);
4067             code = parse_hostEntry(buf);
4068             if (code) {
4069                 fprintf(stderr, "Could not parse %s\n", hostPtr->data);
4070                 afsmon_Exit(180);
4071             }
4072
4073             hostPtr = hostPtr->next;
4074         }
4075     }
4076
4077     /* same as above for -cmhosts */
4078     if (as->parms[P_CMHOSTS].items) {
4079         hostPtr = as->parms[P_CMHOSTS].items;
4080         while (hostPtr != (struct cmd_item *)0) {
4081             sprintf(buf, "cm %s", hostPtr->data);
4082             code = parse_hostEntry(buf);
4083             if (code) {
4084                 fprintf(stderr, "Could not parse %s\n", hostPtr->data);
4085                 afsmon_Exit(185);
4086             }
4087
4088             hostPtr = hostPtr->next;
4089         }
4090     }
4091
4092     /* number of slots in circular buffers */
4093     if (as->parms[P_BUFFERS].items)
4094         num_bufSlots = atoi(as->parms[P_BUFFERS].items->data);
4095     else
4096         num_bufSlots = DEFAULT_BUFSLOTS;
4097
4098     /* Initialize xx_showFlags[]. This array is used solely for processing the
4099      * "show" directives in the config file in parse_showEntries()  */
4100     for (i = 0; i < NUM_FS_STAT_ENTRIES; i++)
4101         fs_showFlags[i] = 0;
4102     for (i = 0; i < NUM_CM_STAT_ENTRIES; i++)
4103         cm_showFlags[i] = 0;
4104
4105
4106     /* Process the configuration file if given. This initializes among other
4107      * things, the list of FS & CM names in FSnameList and CMnameList */
4108
4109     if (as->parms[P_CONFIG].items)
4110         process_config_file(as->parms[P_CONFIG].items->data);
4111
4112     /* print out the FS and CM lists */
4113     print_FS();
4114     print_CM();
4115
4116     /* Initialize the FS results-to-screen map array if there were no "show fs"
4117      * directives in the config file */
4118     if (fs_showDefault) {
4119         for (i = 0; i < NUM_FS_STAT_ENTRIES; i++)
4120             fs_Display_map[i] = i;
4121         fs_DisplayItems_count = NUM_FS_STAT_ENTRIES;
4122     }
4123
4124     /* Initialize the CM results-to-screen map array if there were no "show cm"
4125      * directives in the config file */
4126     if (cm_showDefault) {
4127         for (i = 0; i < NUM_CM_STAT_ENTRIES; i++)
4128             cm_Display_map[i] = i;
4129         cm_DisplayItems_count = NUM_CM_STAT_ENTRIES;
4130     }
4131
4132
4133
4134     /* setup an interrupt signal handler; we ain't wanna leak core  */
4135     /* this binding is useful only until gtx is initialized after which the
4136      * keyboard input server takes over. */
4137     if ((signal(SIGINT, quit_signal)) == SIG_ERR) {
4138         perror("signal() failed.");
4139         afsmon_Exit(190);
4140     }
4141
4142
4143     /* init error message buffers. these will be used to print error messages
4144      * once gtx is initialized and there is no access to stderr/stdout */
4145     errMsg[0] = '\0';
4146     errMsg1[0] = '\0';
4147
4148     if (num_bufSlots) {
4149
4150         /* initialize fs and cm circular buffers before initiating probes */
4151         if (numFS) {
4152             code = init_fs_buffers();
4153             if (code) {
4154                 fprintf(stderr, "[ %s ] init_fs_buffers returned %d\n", rn,
4155                         code);
4156                 afsmon_Exit(195);
4157             }
4158         }
4159
4160         if (numCM) {
4161             code = init_cm_buffers();
4162             if (code) {
4163                 fprintf(stderr, "[ %s ] init_cm_buffers returned %d\n", rn,
4164                         code);
4165                 afsmon_Exit(200);
4166             }
4167         }
4168     }
4169
4170     /* allocate and initialize buffers for holding fs & cm results in ascii
4171      * format suitable for updating the screen */
4172     code = init_print_buffers();
4173     if (code) {
4174         fprintf(stderr, "[ %s ] init_print_buffers returned %d\n", rn, code);
4175         afsmon_Exit(205);
4176     }
4177
4178     /* perform gtx initializations */
4179     code = gtx_initialize();
4180     if (code) {
4181         fprintf(stderr, "[ %s ] gtx_initialize returned %d\n", rn, code);
4182         afsmon_Exit(210);
4183     }
4184
4185     /* start xstat probes */
4186     afsmon_execute();
4187
4188     return (0);                 /* will not return from the call to afsmon_execute() */
4189
4190 }                               /* afsmonInit() */
4191
4192
4193 /*-----------------------------------------------------------------------
4194  * Function:    main()
4195  ------------------------------------------------------------------------*/
4196
4197 #include "AFS_component_version_number.c"
4198
4199 int
4200 main(int argc, char **argv)
4201 {                               /* main() */
4202     afs_int32 code;             /*Return code */
4203     struct cmd_syndesc *ts;     /*Ptr to cmd line syntax descriptor */
4204
4205 #ifdef  AFS_AIX32_ENV
4206     /*
4207      * The following signal action for AIX is necessary so that in case of a
4208      * crash (i.e. core is generated) we can include the user's data section
4209      * in the core dump. Unfortunately, by default, only a partial core is
4210      * generated which, in many cases, isn't too useful.
4211      */
4212     struct sigaction nsa;
4213
4214     sigemptyset(&nsa.sa_mask);
4215     nsa.sa_handler = SIG_DFL;
4216     nsa.sa_flags = SA_FULLDUMP;
4217     sigaction(SIGSEGV, &nsa, NULL);
4218 #endif
4219
4220     /*
4221      * Set up the commands we understand.
4222      */
4223     ts = cmd_CreateSyntax("initcmd", afsmonInit, NULL, 0, "initialize the program");
4224     cmd_AddParm(ts, "-config", CMD_SINGLE, CMD_OPTIONAL,
4225                 "configuration file");
4226     cmd_AddParm(ts, "-frequency", CMD_SINGLE, CMD_OPTIONAL,
4227                 "poll frequency, in seconds");
4228     cmd_AddParm(ts, "-output", CMD_SINGLE, CMD_OPTIONAL, "storage file name");
4229     cmd_AddParm(ts, "-detailed", CMD_FLAG, CMD_OPTIONAL,
4230                 "output detailed statistics to storage file");
4231 #ifdef notdef
4232     /* we hope to use this .... eventually! */
4233     cmd_AddParm(ts, "-package", CMD_SINGLE, CMD_REQUIRED,
4234                 "Graphics Package to use");
4235 #endif
4236     cmd_AddParm(ts, "-debug", CMD_SINGLE, CMD_OPTIONAL,
4237                 "turn debugging output on to the named file");
4238     cmd_AddParm(ts, "-fshosts", CMD_LIST, CMD_OPTIONAL,
4239                 "list of file servers to monitor");
4240     cmd_AddParm(ts, "-cmhosts", CMD_LIST, CMD_OPTIONAL,
4241                 "list of cache managers to monitor");
4242     cmd_AddParm(ts, "-buffers", CMD_SINGLE, CMD_OPTIONAL,
4243                 "number of buffer slots");
4244
4245     /*
4246      * Parse command-line switches & execute afsmonitor
4247      */
4248
4249     code = cmd_Dispatch(argc, argv);
4250     if (code)
4251         afsmon_Exit(1);
4252     else
4253         afsmon_Exit(2);
4254
4255     exit(0);                    /* redundant, but gets rid of warning */
4256 }                               /*main */