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