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