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