afsmonitor & gtx: Don't cast returns from malloc()
[openafs.git] / src / afsmonitor / afsmonitor.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  *
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  *
9  * Portions Copyright (c) 2003 Apple Computer, Inc.
10  */
11
12 /*
13  * Afsmonitor: An AFS Performance Monitoring Tool
14  *
15  *-------------------------------------------------------------------------*/
16
17
18 #include <afsconfig.h>
19 #include <afs/param.h>
20
21
22 #include <stdio.h>
23 #include <math.h>
24 #include <string.h>
25 #include <errno.h>
26 #include <afs/cmd.h>
27 #include <signal.h>
28 #undef IN
29 #include <sys/types.h>
30 #include <netinet/in.h>
31 #include <sys/socket.h>
32 #include <netdb.h>
33 #include <ctype.h>
34 #ifdef HAVE_STDINT_H
35 # include <stdint.h>
36 #endif
37
38 #include <afs/gtxwindows.h>             /*Generic window package */
39 #include <afs/gtxobjects.h>             /*Object definitions */
40 #include <afs/gtxlightobj.h>    /*Light object interface */
41 #include <afs/gtxcurseswin.h>   /*Curses window package */
42 #include <afs/gtxdumbwin.h>             /*Dumb terminal window package */
43 #include <afs/gtxX11win.h>              /*X11 window package */
44 #include <afs/gtxframe.h>               /*Frame package */
45 #include <afs/gtxinput.h>
46
47 #include <afs/xstat_fs.h>
48 #include <afs/xstat_cm.h>
49
50 #include "afsmonitor.h"
51
52 /* command line parameter indices */
53
54 #define P_CONFIG        0
55 #define P_FREQUENCY     1
56 #define P_OUTPUT        2
57 #define P_DETAILED      3
58 /* #define P_PACKAGE    X */
59 #define P_DEBUG         4
60 #define P_FSHOSTS       5
61 #define P_CMHOSTS       6
62 #define P_BUFFERS       7
63
64
65 int afsmon_debug = 0;           /* debug info to file ? */
66 FILE *debugFD;                  /* debugging file descriptor */
67 static int afsmon_output = 0;   /* output to file ? */
68 static int afsmon_detOutput = 0;        /* detailed output ? */
69 static int afsmon_onceOnly = 0; /* probe once only ? (not implemented) */
70 int afsmon_probefreq;           /* probe frequency */
71 static int wpkg_to_use;         /* graphics package to use */
72 static char output_filename[80];        /* output filename */
73 char errMsg[256];               /* buffers used to print error messages after */
74 char errMsg1[256];              /* gtx is initialized (stderr/stdout gone !) */
75 int num_bufSlots = 0;           /* number of slots in fs & cm circular buffers */
76
77 /* Flags used to process "show" directives in config file */
78 short fs_showFlags[NUM_FS_STAT_ENTRIES];
79 short cm_showFlags[NUM_CM_STAT_ENTRIES];
80
81
82 /* afsmonitor misc definitions */
83
84 #define DEFAULT_FREQUENCY 60    /* default proble frequency in seconds */
85 #define DEFAULT_BUFSLOTS  0     /* default number of buffer slots */
86 #define CFG_STR_LEN     80      /* max length of config file fields */
87 #define FS 1                    /* for misc. use */
88 #define CM 2                    /* for misc. use */
89
90
91 #define NUM_XSTAT_FS_AFS_PERFSTATS_LONGS 70     /* number of fields from struct afs_PerfStats that we display */
92 #define NUM_AFS_STATS_CMPERF_LONGS 40   /* number of longs in struct afs_stats_CMPerf excluding up/down stats and fields we dont display */
93
94
95 /* variables used for exec'ing user provided threshold handlers */
96 char *fsHandler_argv[20];       /* *argv[] for the handler */
97 char fsHandler_args[20][256];   /* buffer space for arguments */
98 int exec_fsThreshHandler = 0;   /* execute fs threshold handler ? */
99
100
101 /* THRESHOLD STRUCTURE DEFINITIONS */
102
103 /* flag to indicate that threshold entries apply to all hosts. these will
104    be turned off when the first fs or cm host entry is processed */
105 static int global_ThreshFlag = 1;
106 static int global_fsThreshCount = 0;    /* number of global fs thresholds */
107 static int global_cmThreshCount = 0;    /* number of global cm thresholds */
108
109
110
111 /* Linked lists of file server and cache manager host names are made from
112 the entries in the config file. Head pointers to FS and CM server name lists. */
113 static struct afsmon_hostEntry *FSnameList;
114 static struct afsmon_hostEntry *CMnameList;
115
116 /* number of fileservers and cache managers to monitor */
117 int numFS = 0;
118 int numCM = 0;
119
120 /* number of xstat collection ids */
121 #define MAX_NUM_FS_COLLECTIONS 2
122 #define MAX_NUM_CM_COLLECTIONS 1
123 int num_fs_collections = 0;
124 int num_cm_collections = 0;
125
126 /* variables used for processing config file */
127 /* ptr to the hostEntry structure of the last "fs" or "cm" entry processed
128 in the config file */
129 static struct afsmon_hostEntry *last_hostEntry;
130 /* names of the last host processed in the config file */
131 static char last_fsHost[HOST_NAME_LEN];
132 static char last_cmHost[HOST_NAME_LEN];
133 static int lastHostType = 0;    /* 0 = no host entries processed
134                                  * 1 = last host was file server
135                                  * 2 = last host was cache manager. */
136
137
138 /* FILE SERVER CIRCULAR BUFFER VARIABLES  */
139
140 struct afsmon_fs_Results_list {
141     struct xstat_fs_ProbeResults *fsResults[MAX_NUM_FS_COLLECTIONS];
142     int empty[MAX_NUM_FS_COLLECTIONS];
143     struct afsmon_fs_Results_list *next;
144 };
145
146 struct afsmon_fs_Results_CBuffer {
147     int probeNum;               /* probe number of entries in this slot */
148     struct afsmon_fs_Results_list *list;        /* ptr to list of results */
149 };
150
151 int afsmon_fs_results_length[] =
152     { XSTAT_FS_FULLPERF_RESULTS_LEN, XSTAT_FS_CBSTATS_RESULTS_LEN };
153
154 /* buffer for FS probe results */
155 struct afsmon_fs_Results_CBuffer *afsmon_fs_ResultsCB;
156
157 int afsmon_fs_curr_CBindex = 0; /* current fs CB slot */
158
159 /* Probe number variables. The current probe number is incremented
160 when the first probe from a new probe cycle is received. The prev probe
161 number is incremented when the last probe of the current cycle is
162 received. This difference is because of the purpose for which these
163 counters are used */
164
165 int afsmon_fs_curr_probeNum = 1;        /* current fs probe number */
166 int afsmon_fs_prev_probeNum = 0;        /* previous fs probe number */
167
168
169 /* CACHE MANAGER CIRCULAR BUFFER VARIABLES  */
170
171 struct afsmon_cm_Results_list {
172     struct xstat_cm_ProbeResults *cmResults[MAX_NUM_CM_COLLECTIONS];
173     int empty[MAX_NUM_CM_COLLECTIONS];
174     struct afsmon_cm_Results_list *next;
175 };
176
177 struct afsmon_cm_Results_CBuffer {
178     int probeNum;               /* probe number of entries in this slot */
179     struct afsmon_cm_Results_list *list;        /* ptr to list of results */
180 };
181
182 int afsmon_cm_results_length[] = { XSTAT_CM_FULLPERF_RESULTS_LEN };
183
184 /* buffer for CM probe results */
185 struct afsmon_cm_Results_CBuffer *afsmon_cm_ResultsCB;
186
187 int afsmon_cm_curr_CBindex = 0; /* current cm CB slot */
188
189
190 /* Probe number variables. The current probe number is incremented
191 when the first probe from a new probe cycle is received. The prev probe
192 number is incremented when the last probe of the current cycle is
193 received. This difference is because of the purpose for which these
194 counters are used */
195
196 int afsmon_cm_curr_probeNum = 1;        /* current cm probe number */
197 int afsmon_cm_prev_probeNum = 0;        /* previous cm probe number */
198
199
200 /* Structures to hold FS & CM results in string format(suitable for display ) */
201
202 /* ptr to array holding the results of FS probes in ascii format */
203         /* for current probe cycle */
204 struct fs_Display_Data *curr_fsData = (struct fs_Display_Data *)0;
205         /* for previous probe cycle */
206 struct fs_Display_Data *prev_fsData = (struct fs_Display_Data *)0;
207
208
209 /* ptr to array holding the results of CM probes in ascii format */
210         /* for current probe cycle */
211 struct cm_Display_Data *curr_cmData = (struct cm_Display_Data *)0;
212         /* for previous probe cycle */
213 struct cm_Display_Data *prev_cmData = (struct cm_Display_Data *)0;
214
215 /* EXTERN DEFINITIONS */
216
217 /* file server and cache manager variable names (from afsmon_labels.h) */
218 extern char *fs_varNames[];
219 extern char *cm_varNames[];
220
221 /* GTX & MISC VARIABLES */
222
223 /* afsmonitor window */
224 extern struct gwin *afsmon_win;
225
226 /* current page number in the overview frame */
227 extern int ovw_currPage;
228
229 /* number of FS alerts and number of hosts on FS alerts */
230 int num_fs_alerts;
231 int numHosts_onfs_alerts;
232
233 /* number of CM alerts and number of hosts on FS alerts */
234 int num_cm_alerts;
235 int numHosts_oncm_alerts;
236
237 /* flag to indicate that atleast one probe cycle has completed and
238 data is available for updating the display */
239 extern int fs_Data_Available;
240 extern int cm_Data_Available;
241
242 extern int gtx_initialized;     /* gtx initialized ? */
243
244 /* This array contains the indices of the file server data items that
245 are to be displayed on the File Servers screen. For example, suppose the
246 user wishes to display only the vcache statistics then the following array
247 will contain indices 2 to 14 corresponding to the position of the
248 vcache data items in the fs_varNames[] array. If the config file contains
249 no "show fs .." directives, it will contain the indices of all the
250 items in the fs_varNames[] array */
251
252 short fs_Display_map[NUM_FS_STAT_ENTRIES];
253 int fs_DisplayItems_count = 0;  /* number of items to display */
254 int fs_showDefault = 1;         /* show all of FS data ? */
255
256
257 /* same use as above for Cache Managers  */
258 short cm_Display_map[NUM_CM_STAT_ENTRIES];
259 int cm_DisplayItems_count = 0;  /* number of items to display */
260 int cm_showDefault = 1;         /* show all of CM data ? */
261
262 extern int fs_currPage;         /* current page number in the File Servers frame */
263 extern int fs_curr_LCol;        /* current leftmost column on display on FS frame */
264
265 extern int cm_currPage;         /* current page number in the Cache Managers frame */
266 extern int cm_curr_LCol;        /* current leftmost column on display on CM frame */
267
268 /* File server and Cache manager data is classified into sections &
269 groups to help the user choose what he wants displayed */
270 extern char *fs_categories[];   /* file server data category names */
271 extern char *cm_categories[];   /* cache manager data category names */
272
273
274 static int fs_FullPerfs_ltoa(struct fs_Display_Data *a_fsData,
275                              struct xstat_fs_ProbeResults *a_fsResults);
276 static int fs_CallBackStats_ltoa(struct fs_Display_Data *a_fsData,
277                                  struct xstat_fs_ProbeResults *a_fsResults);
278
279 #ifdef HAVE_STRCASESTR
280 extern char * strcasestr(const char *, const char *);
281 #else
282 /*
283         strcasestr(): Return first occurence of pattern s2 in s1, case
284         insensitive.
285
286         This routine is required since I made pattern matching of the
287         config file to be case insensitive.
288 */
289
290 char *
291 strcasestr(s1, s2)
292      char *s1;
293      char *s2;
294 {
295     char *ptr;
296     int len1, len2;
297
298     len1 = strlen(s1);
299     len2 = strlen(s2);
300
301     if (len1 < len2)
302         return ((char *)NULL);
303
304     ptr = s1;
305
306     while (len1 >= len2 && len1 > 0) {
307         if ((strncasecmp(ptr, s2, len2)) == 0)
308             return (ptr);
309         ptr++;
310         len1--;
311     }
312     return ((char *)NULL);
313 }
314 #endif
315
316 struct hostent *
317 GetHostByName(char *name)
318 {
319     struct hostent *he;
320 #ifdef AFS_SUN5_ENV
321     char ip_addr[32];
322 #endif
323
324     he = gethostbyname(name);
325 #ifdef AFS_SUN5_ENV
326     /* On solaris the above does not resolve hostnames to full names */
327     if (he != NULL) {
328         memcpy(ip_addr, he->h_addr, he->h_length);
329         he = gethostbyaddr(ip_addr, he->h_length, he->h_addrtype);
330     }
331 #endif
332     return (he);
333 }
334
335
336 /*-----------------------------------------------------------------------
337  * afsmon_Exit()
338  *
339  * Description
340  *      Exit gracefully from the afsmonitor. Frees memory where appropriate,
341  *      cleans up after gtx and closes all open file descriptors. If a user
342  *      provided threshold handler is to be exec'ed then gtx cleanup is
343  *      not performed and an exec() is made instead of an exit().
344  *
345  * Returns
346  *      Nothing.
347  *
348  * Comments
349  *      This function is called to execute a user handler only
350  *      by a child process.
351  *
352  *----------------------------------------------------------------------*/
353
354 int
355 afsmon_Exit(int a_exitVal)      /* exit code */
356 {                               /* afsmon_Exit */
357     static char rn[] = "afsmon_Exit";
358     struct afsmon_fs_Results_list *tmp_fslist;
359     struct afsmon_fs_Results_list *next_fslist;
360     struct xstat_fs_ProbeResults *tmp_xstat_fsPR;
361     struct afsmon_cm_Results_list *tmp_cmlist;
362     struct afsmon_cm_Results_list *next_cmlist;
363     struct xstat_cm_ProbeResults *tmp_xstat_cmPR;
364     struct afsmon_hostEntry *curr_hostEntry;
365     struct afsmon_hostEntry *next_hostEntry;
366     int i;
367     int j;
368     int bufslot;
369     int code;
370
371     if (afsmon_debug) {
372         fprintf(debugFD, "[ %s ] Called with exit code %d\n", rn, a_exitVal);
373         fflush(debugFD);
374     }
375
376     /* get out of curses first, but not if we are here to exec a threshold
377      * handler. If we do, the screen gets messed up  */
378     if (gtx_initialized && !exec_fsThreshHandler)
379         gator_cursesgwin_cleanup(afsmon_win);
380
381     /* print the error message buffer */
382     if (errMsg[0] != '\0')
383         fprintf(stderr, "%s", errMsg);
384     if (errMsg1[0] != '\0')
385         fprintf(stderr, "%s", errMsg1);
386
387     /* deallocate file server circular buffers */
388     if (numFS && num_bufSlots) {
389         if (afsmon_debug) {
390             fprintf(debugFD, "freeing FS circular buffers ");
391             fflush(debugFD);
392         }
393
394         for (bufslot = 0; bufslot < num_bufSlots; bufslot++) {
395             if (afsmon_debug)
396                 fprintf(debugFD, " %d) ", bufslot);
397             if (afsmon_fs_ResultsCB[bufslot].list !=
398                 (struct afsmon_fs_Results_list *)0) {
399                 tmp_fslist = afsmon_fs_ResultsCB[bufslot].list;
400                 j = numFS;
401                 while (tmp_fslist) {
402                     /* make sure we do not go astray */
403                     if (--j < 0) {
404                         if (afsmon_debug)
405                             fprintf(debugFD,
406                                     "[ %s ] error in deallocating fs CB\n",
407                                     rn);
408                         break;
409                     }
410                     next_fslist = tmp_fslist->next;
411                     for (i = 0; i < MAX_NUM_FS_COLLECTIONS; i++) {
412                         tmp_xstat_fsPR = tmp_fslist->fsResults[i];
413
414                         if (afsmon_debug)
415                             fprintf(debugFD, "%d ", numFS - j);
416
417                         /* free xstat_fs_Results data */
418                         free(tmp_xstat_fsPR->data.AFS_CollData_val);
419                         free(tmp_xstat_fsPR->connP);
420                         free(tmp_xstat_fsPR);
421                     }
422
423                     /* free the fs list item */
424                     free(tmp_fslist);
425                     tmp_fslist = next_fslist;
426
427                 }               /* while fs list items in this slot */
428             }                   /* if entries in this buffer slot */
429         }                       /* for each fs buffer slot */
430         if (afsmon_debug)
431             fprintf(debugFD, "\n");
432     }
433
434     if (afsmon_debug)
435         fflush(debugFD);
436     /* deallocate cache manager curcular buffers */
437     if (numCM && num_bufSlots) {
438         if (afsmon_debug)
439             fprintf(debugFD, "freeing CM curcular buffers ");
440         for (bufslot = 0; bufslot < num_bufSlots; bufslot++) {
441             if (afsmon_debug)
442                 fprintf(debugFD, " %d) ", bufslot);
443             if (afsmon_cm_ResultsCB[bufslot].list !=
444                 (struct afsmon_cm_Results_list *)0) {
445                 tmp_cmlist = afsmon_cm_ResultsCB[bufslot].list;
446                 j = numCM;
447                 while (tmp_cmlist) {
448                     /* make sure we do not go astray */
449                     if (--j < 0) {
450                         if (afsmon_debug)
451                             fprintf(debugFD,
452                                     "[ %s ] error in deallocating cm CB\n",
453                                     rn);
454                         break;
455                     }
456                     next_cmlist = tmp_cmlist->next;
457                     for (i = 0; i < MAX_NUM_CM_COLLECTIONS; i++) {
458                         tmp_xstat_cmPR = tmp_cmlist->cmResults[i];
459
460                         if (afsmon_debug)
461                             fprintf(debugFD, "%d ", numCM - j);
462                         /* make sure data is ok */
463                         /* Print_cm_FullPerfInfo(tmp_xstat_cmPR); */
464
465                         /* free xstat_cm_Results data */
466                         free(tmp_xstat_cmPR->data.AFSCB_CollData_val);
467                         free(tmp_xstat_cmPR->connP);
468                     }
469                     free(tmp_cmlist->cmResults);
470
471                     /* free the cm list item */
472                     free(tmp_cmlist);
473                     tmp_cmlist = next_cmlist;
474
475                 }               /* while cm list items in this slot */
476             }                   /* if entries in this buffer slot */
477         }                       /* for each cm buffer slot */
478         if (afsmon_debug)
479             fprintf(debugFD, "\n");
480     }
481
482
483     /* deallocate FS & CM Print buffers */
484     if (curr_fsData != (struct fs_Display_Data *)0) {
485         if (afsmon_debug)
486             fprintf(debugFD, "Deallocating FS Print Buffers .... curr");
487         free(curr_fsData);
488     }
489     if (prev_fsData != (struct fs_Display_Data *)0) {
490         if (afsmon_debug)
491             fprintf(debugFD, ", prev \n");
492         free(prev_fsData);
493     }
494     if (prev_cmData != (struct cm_Display_Data *)0) {
495         if (afsmon_debug)
496             fprintf(debugFD, "Deallocating CM Print Buffers .... curr");
497         free(curr_cmData);
498     }
499     if (prev_cmData != (struct cm_Display_Data *)0) {
500         if (afsmon_debug)
501             fprintf(debugFD, ", prev \n");
502         free(prev_cmData);
503     }
504
505     /* deallocate hostEntry lists */
506     if (numFS) {
507         if (afsmon_debug)
508             fprintf(debugFD, "Deallocating FS hostEntries ..");
509         curr_hostEntry = FSnameList;
510         while (curr_hostEntry) {
511             next_hostEntry = curr_hostEntry->next;
512             if (curr_hostEntry->thresh != NULL)
513                 free(curr_hostEntry->thresh);
514             free(curr_hostEntry);
515             curr_hostEntry = next_hostEntry;
516         }
517         if (afsmon_debug)
518             fprintf(debugFD, "\n");
519     }
520     if (numCM) {
521         if (afsmon_debug)
522             fprintf(debugFD, "Deallocating CM hostEntries ..");
523         curr_hostEntry = CMnameList;
524         while (curr_hostEntry) {
525             next_hostEntry = curr_hostEntry->next;
526             if (curr_hostEntry->thresh != NULL)
527                 free(curr_hostEntry->thresh);
528             free(curr_hostEntry);
529             curr_hostEntry = next_hostEntry;
530         }
531         if (afsmon_debug)
532             fprintf(debugFD, "\n");
533     }
534
535     /* close debug file */
536     if (afsmon_debug) {
537         fflush(debugFD);
538         fclose(debugFD);
539     }
540
541     if (exec_fsThreshHandler) {
542         code = execvp(fsHandler_argv[0], fsHandler_argv);
543         if (code == -1) {
544             fprintf(stderr, "execvp() of %s returned %d, errno %d\n",
545                     fsHandler_argv[0], code, errno);
546             exit(-1);
547         }
548     }
549
550     exit(a_exitVal);
551 }                               /* afsmon_Exit */
552
553 /*-----------------------------------------------------------------------
554  * insert_FS()
555  *
556  * Description:
557  *      Insert a hostname in the file server names list.
558  *
559  * Returns:
560  *      Success: 0
561  *      Failure: -1
562  *----------------------------------------------------------------------*/
563
564 int
565 insert_FS(char *a_hostName)             /* name of cache manager to be inserted in list */
566 {                               /* insert_FS() */
567     static struct afsmon_hostEntry *curr_item;
568     static struct afsmon_hostEntry *prev_item;
569
570     if (*a_hostName == '\0')
571         return (-1);
572     curr_item = 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") != (char *)NULL
1162             || strcasestr(arg2, "_group") != (char *)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") != (char *)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") != (char *)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") != (char *)NULL
1277             || strcasestr(arg2, "_group") != (char *)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") != (char *)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") != (char *)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     default:
1737         if (index < 0) {
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
1744     /* If a new probe cycle started, mark the list in the current buffer
1745      * slot empty for resuse. Note that afsmon_fs_curr_CBindex was appropriately
1746      * incremented in afsmon_FS_Handler() */
1747
1748     if (a_newProbeCycle) {
1749         tmp_fslist_item = afsmon_fs_ResultsCB[afsmon_fs_curr_CBindex].list;
1750         for (i = 0; i < numFS; i++) {
1751             tmp_fslist_item->empty[index] = 1;
1752             tmp_fslist_item = tmp_fslist_item->next;
1753         }
1754     }
1755
1756     /* locate last unused item in list */
1757     tmp_fslist_item = afsmon_fs_ResultsCB[afsmon_fs_curr_CBindex].list;
1758     for (i = 0; i < numFS; i++) {
1759         if (tmp_fslist_item->empty[index])
1760             break;
1761         tmp_fslist_item = tmp_fslist_item->next;
1762     }
1763
1764     /* if we could not find one we have an inconsistent list */
1765     if (!tmp_fslist_item->empty[index]) {
1766         fprintf(stderr,
1767                 "[ %s ] list inconsistency 1. unable to find an empty slot to store results of probenum %d of %s\n",
1768                 rn, xstat_fs_Results.probeNum,
1769                 xstat_fs_Results.connP->hostName);
1770         afsmon_Exit(50);
1771     }
1772
1773     tmp_fsPR = tmp_fslist_item->fsResults[index];
1774
1775     /* copy hostname and probe number and probe time and probe status.
1776      * if the probe failed return now */
1777
1778     memcpy(tmp_fsPR->connP->hostName, xstat_fs_Results.connP->hostName,
1779            sizeof(xstat_fs_Results.connP->hostName));
1780     tmp_fsPR->probeNum = xstat_fs_Results.probeNum;
1781     tmp_fsPR->probeTime = xstat_fs_Results.probeTime;
1782     tmp_fsPR->probeOK = xstat_fs_Results.probeOK;
1783     if (xstat_fs_Results.probeOK) {     /* probeOK = 1 => notOK */
1784         /* we have a nonempty results structure so mark the list item used */
1785         tmp_fslist_item->empty[index] = 0;
1786         return (0);
1787     }
1788
1789     /* copy connection information */
1790     memcpy(&(tmp_fsPR->connP->skt), &(xstat_fs_Results.connP->skt),
1791            sizeof(struct sockaddr_in));
1792
1793     memcpy(tmp_fsPR->connP->hostName, xstat_fs_Results.connP->hostName,
1794            sizeof(xstat_fs_Results.connP->hostName));
1795     tmp_fsPR->collectionNumber = xstat_fs_Results.collectionNumber;
1796
1797     /* copy the probe data information */
1798     tmp_fsPR->data.AFS_CollData_len =
1799         min(xstat_fs_Results.data.AFS_CollData_len,
1800             afsmon_fs_results_length[index]);
1801     memcpy(tmp_fsPR->data.AFS_CollData_val,
1802            xstat_fs_Results.data.AFS_CollData_val,
1803            tmp_fsPR->data.AFS_CollData_len * sizeof(afs_int32));
1804
1805
1806     /* we have a valid results structure so mark the list item used */
1807     tmp_fslist_item->empty[index] = 0;
1808
1809     /* Print the fs circular buffer */
1810     Print_FS_CB();
1811
1812     return (0);
1813 }                               /* save_FS_results_inCB() */
1814
1815
1816 /*-----------------------------------------------------------------------
1817  * fs_Results_ltoa()
1818  *
1819  * Description:
1820  *      The results of xstat probes are stored in a string format in
1821  *      the arrays curr_fsData and prev_fsData. The information stored in
1822  *      prev_fsData is copied to the screen.
1823  *      This function converts xstat FS results from longs to strings and
1824  *      place them in the given buffer (a pointer to an item in curr_fsData).
1825  *      When a probe cycle completes, curr_fsData is copied to prev_fsData
1826  *      in afsmon_FS_Hnadler().
1827  *
1828  * Returns:
1829  *      Always returns 0.
1830  *----------------------------------------------------------------------*/
1831
1832 int
1833 fs_Results_ltoa(struct fs_Display_Data *a_fsData,       /* target buffer */
1834                 struct xstat_fs_ProbeResults *a_fsResults)      /* ptr to xstat fs Results */
1835 {                               /* fs_Results_ltoa */
1836
1837     static char rn[] = "fs_Results_ltoa";       /* routine name */
1838
1839     if (afsmon_debug) {
1840         fprintf(debugFD, "[ %s ] Called, a_fsData= %p, a_fsResults= %p\n", rn,
1841                 a_fsData, a_fsResults);
1842         fflush(debugFD);
1843     }
1844
1845     switch (a_fsResults->collectionNumber) {
1846     case AFS_XSTATSCOLL_FULL_PERF_INFO:
1847         fs_FullPerfs_ltoa(a_fsData, a_fsResults);
1848         break;
1849     case AFS_XSTATSCOLL_CBSTATS:
1850         fs_CallBackStats_ltoa(a_fsData, a_fsResults);
1851         break;
1852     default:
1853         if (afsmon_debug) {
1854             fprintf(debugFD, "[ %s ] Unexpected collection id %d\n",
1855                     rn, a_fsResults->collectionNumber);
1856         }
1857     }
1858
1859     return (0);
1860 }                               /* fs_Results_ltoa */
1861
1862 /*-----------------------------------------------------------------------
1863  * fs_FullPerfs_ltoa()
1864  *
1865  * Description:
1866  *      Convert the full perf xstat collection from int32s to strings.
1867  *
1868  * Returns:
1869  *      Always returns 0.
1870  *----------------------------------------------------------------------*/
1871 static int
1872 fs_FullPerfs_ltoa(struct fs_Display_Data *a_fsData,
1873                 struct xstat_fs_ProbeResults *a_fsResults)
1874 {
1875     afs_int32 *srcbuf;
1876     struct fs_stats_FullPerfStats *fullPerfP;
1877     struct fs_stats_FullPerfStats buffer;
1878     int idx;
1879     int i, j;
1880     afs_int32 *tmpbuf;
1881     int code;
1882
1883     /* there are two parts to the xstat FS statistics
1884      * - fullPerfP->overall which give the overall performance statistics, and
1885      * - fullPerfP->det which gives detailed info about file server operation
1886      * execution times */
1887
1888     code = xstat_fs_DecodeFullPerfStats(&fullPerfP,
1889                                         a_fsResults->data.AFS_CollData_val,
1890                                         a_fsResults->data.AFS_CollData_len,
1891                                         &buffer);
1892     if (code) {
1893         /* Not able to decode the full perf stats. Avoid displaying garbage. */
1894         for (i = 0; i < NUM_FS_STAT_ENTRIES; i++) {
1895             sprintf(a_fsData->data[i], "%s", "--");
1896         }
1897         return 0;
1898     }
1899
1900     /* copy overall performance statistics */
1901     srcbuf = (afs_int32 *) & (fullPerfP->overall);
1902     idx = 0;
1903     for (i = 0; i < NUM_XSTAT_FS_AFS_PERFSTATS_LONGS; i++) {
1904         sprintf(a_fsData->data[idx], "%d", *srcbuf);
1905         idx++;
1906         srcbuf++;
1907     }
1908
1909     /* copy epoch */
1910     srcbuf = (afs_int32 *) & (fullPerfP->det.epoch);
1911     sprintf(a_fsData->data[idx], "%d", *srcbuf);        /* epoch */
1912     idx++;
1913
1914     /* copy fs operation timing */
1915
1916     srcbuf = (afs_int32 *) (fullPerfP->det.rpcOpTimes);
1917
1918     for (i = 0; i < FS_STATS_NUM_RPC_OPS; i++) {
1919         sprintf(a_fsData->data[idx], "%d", *srcbuf);    /* numOps */
1920         idx++;
1921         srcbuf++;
1922         sprintf(a_fsData->data[idx], "%d", *srcbuf);    /* numSuccesses */
1923         idx++;
1924         srcbuf++;
1925         tmpbuf = srcbuf++;      /* sum time */
1926         sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1927         idx++;
1928         srcbuf++;
1929         tmpbuf = srcbuf++;      /* sqr time */
1930         sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1931         idx++;
1932         srcbuf++;
1933         tmpbuf = srcbuf++;      /* min time */
1934         sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1935         idx++;
1936         srcbuf++;
1937         tmpbuf = srcbuf++;      /* max time */
1938         sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1939         idx++;
1940         srcbuf++;
1941     }
1942
1943     /* copy fs transfer timings */
1944
1945     srcbuf = (afs_int32 *) (fullPerfP->det.xferOpTimes);
1946     for (i = 0; i < FS_STATS_NUM_XFER_OPS; i++) {
1947         sprintf(a_fsData->data[idx], "%d", *srcbuf);    /* numOps */
1948         idx++;
1949         srcbuf++;
1950         sprintf(a_fsData->data[idx], "%d", *srcbuf);    /* numSuccesses */
1951         idx++;
1952         srcbuf++;
1953         tmpbuf = srcbuf++;      /* sum time */
1954         sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1955         idx++;
1956         srcbuf++;
1957         tmpbuf = srcbuf++;      /* sqr time */
1958         sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1959         idx++;
1960         srcbuf++;
1961         tmpbuf = srcbuf++;      /* min time */
1962         sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1963         idx++;
1964         srcbuf++;
1965         tmpbuf = srcbuf++;      /* max time */
1966         sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1967         idx++;
1968         srcbuf++;
1969         sprintf(a_fsData->data[idx], "%d", *srcbuf);    /* sum bytes */
1970         idx++;
1971         srcbuf++;
1972         sprintf(a_fsData->data[idx], "%d", *srcbuf);    /* min bytes */
1973         idx++;
1974         srcbuf++;
1975         sprintf(a_fsData->data[idx], "%d", *srcbuf);    /* max bytes */
1976         idx++;
1977         srcbuf++;
1978         for (j = 0; j < FS_STATS_NUM_XFER_BUCKETS; j++) {
1979             sprintf(a_fsData->data[idx], "%d", *srcbuf);        /* bucket[j] */
1980             idx++;
1981             srcbuf++;
1982         }
1983     }
1984
1985     return (0);
1986 }
1987
1988 /*-----------------------------------------------------------------------
1989  * fs_CallBackStats_ltoa()
1990  *
1991  * Description:
1992  *      Convert the callback counter xstat collection from
1993  *      int32s to strings.
1994  *
1995  * Returns:
1996  *      Always returns 0.
1997  *----------------------------------------------------------------------*/
1998
1999 static int
2000 fs_CallBackStats_ltoa(struct fs_Display_Data *a_fsData,
2001                       struct xstat_fs_ProbeResults *a_fsResults)
2002 {
2003     int idx;
2004     int i;
2005     int len = a_fsResults->data.AFS_CollData_len;
2006     afs_int32 *val = a_fsResults->data.AFS_CollData_val;
2007
2008     /* place callback stats after the full perf stats */
2009     idx = NUM_FS_FULLPERF_ENTRIES;
2010     for (i=0; i < len && i < NUM_FS_CB_ENTRIES; i++) {
2011         sprintf(a_fsData->data[idx++], "%u", val[i]);
2012     }
2013     return 0;
2014 }
2015
2016 /*-----------------------------------------------------------------------
2017  * execute_thresh_handler()
2018  *
2019  * Description:
2020  *      Execute a threshold handler. An agrv[] array of pointers is
2021  *      constructed from the given data. A child process is forked
2022  *      which immediately calls afsmon_Exit() with indication that a
2023  *      threshold handler is to be exec'ed insted of exiting.
2024  *
2025  * Returns:
2026  *      Success: 0
2027  *      Failure: Afsmonitor exits if threshold handler has more than 20 args.
2028  *----------------------------------------------------------------------*/
2029
2030 int
2031 execute_thresh_handler(char *a_handler,         /* ptr to handler function + args */
2032                        char *a_hostName,        /* host name for which threshold crossed */
2033                        int a_hostType,          /* fs or cm ? */
2034                        char *a_threshName,      /* threshold variable name */
2035                        char *a_threshValue,     /* threshold value */
2036                        char *a_actValue)        /* actual value */
2037 {                               /* execute_thresh_handler */
2038
2039     static char rn[] = "execute_thresh_handler";
2040     char fileName[256];         /* file name to execute */
2041     int i;
2042     char *ch;
2043     int argNum;
2044     int anotherArg;             /* boolean used to flag if another arg is available */
2045
2046     if (afsmon_debug) {
2047         fprintf(debugFD,
2048                 "[ %s ] Called, a_handler= %s, a_hostName= %s, a_hostType= %d, a_threshName= %s, a_threshValue= %s, a_actValue= %s\n",
2049                 rn, a_handler, a_hostName, a_hostType, a_threshName,
2050                 a_threshValue, a_actValue);
2051         fflush(debugFD);
2052     }
2053
2054
2055     /* get the filename to execute - the first argument */
2056     sscanf(a_handler, "%s", fileName);
2057
2058     /* construct the contents of *argv[] */
2059
2060     strncpy(fsHandler_args[0], fileName, 256);
2061     strncpy(fsHandler_args[1], a_hostName, HOST_NAME_LEN);
2062     if (a_hostType == FS)
2063         strcpy(fsHandler_args[2], "fs");
2064     else
2065         strcpy(fsHandler_args[2], "cm");
2066     strncpy(fsHandler_args[3], a_threshName, THRESH_VAR_NAME_LEN);
2067     strncpy(fsHandler_args[4], a_threshValue, THRESH_VAR_LEN);
2068     strncpy(fsHandler_args[5], a_actValue, THRESH_VAR_LEN);
2069
2070
2071     argNum = 6;
2072     anotherArg = 1;
2073     ch = a_handler;
2074
2075     /* we have already extracted the file name so skip to the 1st arg */
2076     while (isspace(*ch))        /* leading blanks */
2077         ch++;
2078     while (!isspace(*ch) && *ch != '\0')        /* handler filename */
2079         ch++;
2080
2081     while (*ch != '\0') {
2082         if (isspace(*ch)) {
2083             anotherArg = 1;
2084         } else if (anotherArg) {
2085             anotherArg = 0;
2086             sscanf(ch, "%s", fsHandler_args[argNum]);
2087             argNum++;
2088         }
2089         ch++;
2090         if (argNum >= 20) {
2091             sprintf(errMsg,
2092                     "Threshold handlers cannot have more than 20 arguments\n");
2093             afsmon_Exit(55);
2094         }
2095
2096     }
2097
2098     fsHandler_argv[argNum] = NULL;
2099     for (i = 0; i < argNum; i++)
2100         fsHandler_argv[i] = fsHandler_args[i];
2101
2102
2103     /* exec the threshold handler */
2104
2105     if (fork() == 0) {
2106         exec_fsThreshHandler = 1;
2107         afsmon_Exit(60);
2108     }
2109
2110     return (0);
2111 }                               /* execute_thresh_handler */
2112
2113
2114
2115 /*-----------------------------------------------------------------------
2116  * check_fs_thresholds()
2117  *
2118  * Description:
2119  *      Checks the thresholds and sets the overflow flag. Recall that the
2120  *      thresholds for each host are stored in the hostEntry lists
2121  *      [fs/cm]nameList arrays. The probe results are passed to this
2122  *      function in the display-ready format - ie., as strings. Though
2123  *      this looks stupid the overhead incurred in converting the strings
2124  *      back to floats and comparing them is insignificant and
2125  *      programming is easier this way.
2126  *      The threshold flags are a part of the display structures
2127  *      curr_[fs/cm]Data.
2128  *
2129  * Returns:
2130  *      0
2131  *----------------------------------------------------------------------*/
2132
2133 int
2134 check_fs_thresholds(struct afsmon_hostEntry *a_hostEntry, /* ptr to hostEntry */
2135                     struct fs_Display_Data *a_Data)       /* ptr to fs data to be displayed */
2136 {                               /* check_fs_thresholds */
2137
2138     static char rn[] = "check_fs_thresholds";
2139     struct Threshold *threshP;
2140     double tValue;              /* threshold value */
2141     double pValue;              /* probe value */
2142     int i;
2143     int idx;
2144     int count;                  /* number of thresholds exceeded */
2145
2146     if (afsmon_debug) {
2147         fprintf(debugFD, "[ %s ] Called, a_hostEntry= %p, a_Data= %p\n", rn,
2148                 a_hostEntry, a_Data);
2149         fflush(debugFD);
2150     }
2151
2152     if (a_hostEntry->numThresh == 0) {
2153         /* store in ovf count ?? */
2154         return (0);
2155     }
2156
2157     count = 0;
2158     threshP = a_hostEntry->thresh;
2159     for (i = 0; i < a_hostEntry->numThresh; i++) {
2160         if (threshP->itemName[0] == '\0') {
2161             threshP++;
2162             continue;
2163         }
2164         idx = threshP->index;   /* positional index to the data array */
2165         tValue = atof(threshP->threshVal);      /* threshold value */
2166         pValue = atof(a_Data->data[idx]);       /* probe value */
2167         if (pValue > tValue) {
2168
2169             if (afsmon_debug) {
2170                 fprintf(debugFD,
2171                         "[ %s ] fs = %s, thresh ovf for %s, threshold= %s, probevalue= %s\n",
2172                         rn, a_hostEntry->hostName, threshP->itemName,
2173                         threshP->threshVal, a_Data->data[idx]);
2174                 fflush(debugFD);
2175             }
2176             /* if the threshold is crossed, call the handler function
2177              * only if this was a transition -ie, if the threshold was
2178              * crossed in the last probe too just count & keep quite! */
2179
2180             if (!a_Data->threshOvf[idx]) {
2181                 a_Data->threshOvf[idx] = 1;
2182                 /* call the threshold handler if provided */
2183                 if (threshP->handler[0] != '\0') {
2184                     if (afsmon_debug) {
2185                         fprintf(debugFD, "[ %s ] Calling ovf handler %s\n",
2186                                 rn, threshP->handler);
2187                         fflush(debugFD);
2188                     }
2189                     execute_thresh_handler(threshP->handler, a_Data->hostName,
2190                                            FS, threshP->itemName,
2191                                            threshP->threshVal,
2192                                            a_Data->data[idx]);
2193                 }
2194             }
2195
2196             count++;
2197         } else
2198             /* in case threshold was previously crossed, blank it out */
2199             a_Data->threshOvf[idx] = 0;
2200         threshP++;
2201     }
2202     /* store the overflow count */
2203     a_Data->ovfCount = count;
2204
2205     return (0);
2206 }                               /* check_fs_thresholds */
2207
2208
2209 /*-----------------------------------------------------------------------
2210  * save_FS_data_forDisplay()
2211  *
2212  * Description:
2213  *      Does the following:
2214  *      - if the probe number changed (ie, a cycle completed) curr_fsData
2215  *      is copied to prev_fsData, curr_fsData zeroed and refresh the
2216  *      overview screen and file server screen with the new data.
2217  *      - store the results of the current probe from xstat_fs_Results into
2218  *      curr_fsData. ie., convert longs to strings.
2219  *      - check the thresholds
2220  *
2221  * Returns:
2222  *      Success: 0
2223  *      Failure: Exits afsmonitor.
2224  *----------------------------------------------------------------------*/
2225
2226 int
2227 save_FS_data_forDisplay(struct xstat_fs_ProbeResults *a_fsResults)
2228 {                               /* save_FS_data_forDisplay */
2229
2230     static char rn[] = "save_FS_data_forDisplay";       /* routine name */
2231     struct fs_Display_Data *curr_fsDataP;       /* tmp ptr to curr_fsData */
2232     struct fs_Display_Data *prev_fsDataP;       /* tmp ptr to prev_fsData */
2233     struct afsmon_hostEntry *curr_host;
2234     static int results_Received = 0;    /* number of probes reveived in
2235                                          * the current cycle. If this is equal to numFS we got all
2236                                          * the data we want in this cycle and can now display it */
2237     int numBytes;
2238     int okay;
2239     int i;
2240     int code;
2241     int done;
2242
2243
2244     if (afsmon_debug) {
2245         fprintf(debugFD, "[ %s ] Called, a_fsResults= %p\n", rn, a_fsResults);
2246         fflush(debugFD);
2247     }
2248
2249     /* store results in the display array */
2250
2251     okay = 0;
2252     curr_fsDataP = curr_fsData;
2253     for (i = 0; i < numFS; i++) {
2254         if ((strcasecmp(curr_fsDataP->hostName, a_fsResults->connP->hostName))
2255             == 0) {
2256             okay = 1;
2257             break;
2258         }
2259         curr_fsDataP++;
2260     }
2261
2262     if (!okay) {
2263         fprintf(stderr,
2264                 "[ %s ] Could not insert FS probe results for host %s in fs display array\n",
2265                 rn, a_fsResults->connP->hostName);
2266         afsmon_Exit(65);
2267     }
2268
2269     /*  Check the status of the probe. If it succeeded, we store its
2270      * results in the display data structure. If it failed we only mark
2271      * the failed status in the display data structure. */
2272
2273     if (a_fsResults->probeOK) { /* 1 => notOK the xstat results */
2274         curr_fsDataP->probeOK = 0;
2275
2276         /* print the probe status */
2277         if (afsmon_debug) {
2278             fprintf(debugFD, "\n\t\t ----- fs display data ------\n");
2279             fprintf(debugFD, "HostName = %s  PROBE FAILED \n",
2280                     curr_fsDataP->hostName);
2281             fflush(debugFD);
2282         }
2283
2284     } else {                    /* probe succeeded, update display data structures */
2285         curr_fsDataP->probeOK = 1;
2286
2287         /* convert longs to strings and place them in curr_fsDataP */
2288         fs_Results_ltoa(curr_fsDataP, a_fsResults);
2289
2290         /* compare with thresholds and set the overflow flags.
2291          * note that the threshold information is in the hostEntry structure and
2292          * each threshold item has a positional index associated with it */
2293
2294         /* locate the hostEntry for this host */
2295         done = 0;
2296         curr_host = FSnameList;
2297         for (i = 0; i < numFS; i++) {
2298             if (strcasecmp(curr_host->hostName, a_fsResults->connP->hostName)
2299                 == 0) {
2300                 done = 1;
2301                 break;
2302             }
2303             curr_host = curr_host->next;;
2304         }
2305         if (!done)
2306             afsmon_Exit(70);
2307
2308         code = check_fs_thresholds(curr_host, curr_fsDataP);
2309         if (code) {
2310             fprintf(stderr, "[ %s ] Error in checking thresholds\n", rn);
2311             afsmon_Exit(75);
2312         }
2313
2314         /* print the info we just saved */
2315
2316         if (afsmon_debug) {
2317             fprintf(debugFD, "\n\t\t ----- fs display data ------\n");
2318             fprintf(debugFD, "HostName = %s\n", curr_fsDataP->hostName);
2319             for (i = 0; i < NUM_FS_STAT_ENTRIES; i++)
2320                 fprintf(debugFD, "%20s  %30s  %s\n", curr_fsDataP->data[i],
2321                         fs_varNames[i],
2322                         curr_fsDataP->threshOvf[i] ? "(ovf)" : "");
2323
2324             fprintf(debugFD, "\t\t--------------------------------\n\n");
2325             fflush(debugFD);
2326         }
2327
2328     }                           /* the probe succeeded, so we store the data in the display structure */
2329
2330
2331     /* if we have received a reply from all the hosts for this probe cycle,
2332      * it is time to display the data */
2333
2334     results_Received++;
2335     if (results_Received == numFS * num_fs_collections) {
2336         results_Received = 0;
2337
2338         if (afsmon_fs_curr_probeNum != afsmon_fs_prev_probeNum + 1) {
2339             sprintf(errMsg, "[ %s ] Probe number %d missed! \n", rn,
2340                     afsmon_fs_prev_probeNum + 1);
2341             afsmon_Exit(80);
2342         } else
2343             afsmon_fs_prev_probeNum++;
2344
2345         /* backup the display data of the probe cycle that just completed -
2346          * ie., store curr_fsData in prev_fsData */
2347
2348         memcpy((char *)prev_fsData, (char *)curr_fsData,
2349                (numFS * sizeof(struct fs_Display_Data)));
2350
2351
2352         /* initialize curr_fsData but retain the threshold flag information.
2353          * The previous state of threshold flags is used in check_fs_thresholds() */
2354
2355         numBytes = NUM_FS_STAT_ENTRIES * FS_STAT_STRING_LEN;
2356         curr_fsDataP = curr_fsData;
2357         for (i = 0; i < numFS; i++) {
2358             curr_fsDataP->probeOK = 0;
2359             curr_fsDataP->ovfCount = 0;
2360             memset(curr_fsDataP->data, 0, numBytes);
2361             curr_fsDataP++;
2362         }
2363
2364
2365         /* prev_fsData now contains all the information for the probe cycle
2366          * that just completed. Now count the number of threshold overflows for
2367          * use in the overview screen */
2368
2369         prev_fsDataP = prev_fsData;
2370         num_fs_alerts = 0;
2371         numHosts_onfs_alerts = 0;
2372         for (i = 0; i < numFS; i++) {
2373             if (!prev_fsDataP->probeOK) {       /* if probe failed */
2374                 num_fs_alerts++;
2375                 numHosts_onfs_alerts++;
2376             }
2377             if (prev_fsDataP->ovfCount) {       /* overflows ?? */
2378                 num_fs_alerts += prev_fsDataP->ovfCount;
2379                 numHosts_onfs_alerts++;
2380             }
2381             prev_fsDataP++;
2382         }
2383         if (afsmon_debug)
2384             fprintf(debugFD, "Number of FS alerts = %d (on %d hosts)\n",
2385                     num_fs_alerts, numHosts_onfs_alerts);
2386
2387         /* flag that the data is now ready to be displayed */
2388         fs_Data_Available = 1;
2389
2390         /* call the Overview frame update routine (update only FS info) */
2391         ovw_refresh(ovw_currPage, OVW_UPDATE_FS);
2392
2393         /* call the File Servers frame update routine */
2394         fs_refresh(fs_currPage, fs_curr_LCol);
2395
2396     }
2397     /* display data */
2398     return (0);
2399 }                               /* save_FS_data_forDisplay */
2400
2401
2402
2403
2404 /*-----------------------------------------------------------------------
2405  * afsmon_FS_Handler()
2406  *
2407  * Description:
2408  *      This is the File Server probe Handler. It updates the afsmonitor
2409  *      probe counts, fs circular buffer indices and calls the functions
2410  *      to process the results of this probe.
2411  *
2412  * Returns:
2413  *      Success: 0
2414  *      Failure: Exits afsmonitor.
2415  *----------------------------------------------------------------------*/
2416
2417 int
2418 afsmon_FS_Handler(void)
2419 {                               /* afsmon_FS_Handler() */
2420     static char rn[] = "afsmon_FS_Handler";     /* routine name */
2421     int newProbeCycle;          /* start of new probe cycle ? */
2422     int code;                   /* return status */
2423
2424
2425     if (afsmon_debug) {
2426         fprintf(debugFD,
2427                 "[ %s ] Called, hostName= %s, probeNum= %d, status=%s, collection=%d\n", rn,
2428                 xstat_fs_Results.connP->hostName, xstat_fs_Results.probeNum,
2429                 xstat_fs_Results.probeOK ? "FAILED" : "OK",
2430                 xstat_fs_Results.collectionNumber);
2431         fflush(debugFD);
2432     }
2433
2434
2435     /* print the probe results to output file */
2436     if (afsmon_output) {
2437         code = afsmon_fsOutput(output_filename, afsmon_detOutput);
2438         if (code) {
2439             fprintf(stderr,
2440                     "[ %s ] output to file %s returned error code=%d\n", rn,
2441                     output_filename, code);
2442         }
2443     }
2444
2445     /* Update current probe number and circular buffer index. if current
2446      * probenum changed make sure it is only by 1 */
2447
2448     newProbeCycle = 0;
2449     if (xstat_fs_Results.probeNum != afsmon_fs_curr_probeNum) {
2450         if (xstat_fs_Results.probeNum == afsmon_fs_curr_probeNum + 1) {
2451             afsmon_fs_curr_probeNum++;
2452             newProbeCycle = 1;
2453             if (num_bufSlots)
2454                 afsmon_fs_curr_CBindex =
2455                     (afsmon_fs_curr_probeNum - 1) % num_bufSlots;
2456         } else {
2457             fprintf(stderr, "[ %s ] probe number %d-1 missed\n", rn,
2458                     xstat_fs_Results.probeNum);
2459             afsmon_Exit(85);
2460         }
2461     }
2462
2463
2464     /* store the results of this probe in the FS circular buffer */
2465     if (num_bufSlots)
2466         save_FS_results_inCB(newProbeCycle);
2467
2468
2469     /* store the results of the current probe in the fs data display structure.
2470      * if the current probe number changed, swap the current and previous display
2471      * structures. note that the display screen is updated from these structures
2472      * and should start showing the data of the just completed probe cycle */
2473
2474     save_FS_data_forDisplay(&xstat_fs_Results);
2475
2476     return (0);
2477 }
2478
2479
2480
2481 /*----------------------------------------------------------------------- *
2482  * Print_CM_CB()
2483  *
2484  * Description:
2485  *      Debug routine.
2486  *      Prints the  Cache Manager circular buffer
2487  *----------------------------------------------------------------------*/
2488
2489 void
2490 Print_CM_CB(void)
2491 {                               /* Print_CM_CB() */
2492
2493     struct afsmon_cm_Results_list *cmlist;
2494     int i;
2495     int j;
2496     int k;
2497
2498     /* print valid info in the cm CB */
2499
2500     if (afsmon_debug) {
2501         fprintf(debugFD,
2502                 "==================== CM Buffer ========================\n");
2503         fprintf(debugFD, "afsmon_cm_curr_CBindex = %d\n",
2504                 afsmon_cm_curr_CBindex);
2505         fprintf(debugFD, "afsmon_cm_curr_probeNum = %d\n\n",
2506                 afsmon_cm_curr_probeNum);
2507
2508         for (i = 0; i < num_bufSlots; i++) {
2509             fprintf(debugFD, "\t--------- slot %d ----------\n", i);
2510             cmlist = afsmon_cm_ResultsCB[i].list;
2511             j = 0;
2512             while (j < numCM) {
2513                 for (k = 0; k < MAX_NUM_CM_COLLECTIONS; k++) {
2514                     if (!cmlist->empty[k]) {
2515                         fprintf(debugFD,
2516                                 "\t %d) probeNum = %d host = %s cn = %d",
2517                                 j,
2518                                 cmlist->cmResults[k]->probeNum,
2519                                 cmlist->cmResults[k]->connP->hostName,
2520                                 cmlist->cmResults[k]->collectionNumber);
2521                         if (cmlist->cmResults[k]->probeOK)
2522                             fprintf(debugFD, " NOTOK\n");
2523                         else
2524                             fprintf(debugFD, " OK\n");
2525                     } else
2526                         fprintf(debugFD, "\t %d) -- empty --\n", j);
2527                 }
2528                 cmlist = cmlist->next;
2529                 j++;
2530             }
2531             if (cmlist != (struct afsmon_cm_Results_list *)0)
2532                 fprintf(debugFD, "dangling last next ptr cm CB\n");
2533         }
2534     }
2535 }
2536
2537
2538 /*-----------------------------------------------------------------------
2539  * save_CM_results_inCB()
2540  *
2541  * Description:
2542  *      Saves the results of the latest CM probe in the cm circular
2543  *      buffers. If the current probe cycle is in progress the contents
2544  *      of xstat_cm_Results are copied to the end of the list of results
2545  *      in the current slot (pointed to by afsmon_cm_curr_CBindex). If
2546  *      a new probe cycle has started the next slot in the circular buffer
2547  *      is initialized and the results copied. Note that the Rx related
2548  *      information available in xstat_cm_Results is not copied.
2549  *
2550  * Returns:
2551  *      Success: 0
2552  *      Failure: Exits afsmonitor.
2553  *----------------------------------------------------------------------*/
2554
2555 int
2556 save_CM_results_inCB(int a_newProbeCycle)       /* start of new probe cycle ? */
2557 {                               /* save_CM_results_inCB() */
2558     static char rn[] = "save_CM_results_inCB";  /* routine name */
2559     struct afsmon_cm_Results_list *tmp_cmlist_item;     /* temp cm list item */
2560     struct xstat_cm_ProbeResults *tmp_cmPR;     /* temp ptr */
2561     int i;
2562     int index;
2563
2564
2565     if (afsmon_debug) {
2566         fprintf(debugFD, "[ %s ] Called, a_newProbeCycle= %d\n", rn,
2567                 a_newProbeCycle);
2568         fflush(debugFD);
2569     }
2570
2571     if (xstat_cm_Results.collectionNumber == AFSCB_XSTATSCOLL_FULL_PERF_INFO) {
2572         index = 0;
2573     } else {
2574         fprintf(stderr, "[ %s ] collection number %d is out of range.\n",
2575                 rn, xstat_cm_Results.collectionNumber);
2576         afsmon_Exit(91);
2577     }
2578
2579     /* If a new probe cycle started, mark the list in the current buffer
2580      * slot empty for resuse. Note that afsmon_cm_curr_CBindex was appropriately
2581      * incremented in afsmon_CM_Handler() */
2582
2583     if (a_newProbeCycle) {
2584         tmp_cmlist_item = afsmon_cm_ResultsCB[afsmon_cm_curr_CBindex].list;
2585         for (i = 0; i < numCM; i++) {
2586             tmp_cmlist_item->empty[index] = 1;
2587             tmp_cmlist_item = tmp_cmlist_item->next;
2588         }
2589     }
2590
2591     /* locate last unused item in list */
2592     tmp_cmlist_item = afsmon_cm_ResultsCB[afsmon_cm_curr_CBindex].list;
2593     for (i = 0; i < numCM; i++) {
2594         if (tmp_cmlist_item->empty[index])
2595             break;
2596         tmp_cmlist_item = tmp_cmlist_item->next;
2597     }
2598
2599     /* if we could not find one we have an inconsistent list */
2600     if (!tmp_cmlist_item->empty[index]) {
2601         fprintf(stderr,
2602                 "[ %s ] list inconsistency 1. unable to find an empty slot to store results of probenum %d of %s\n",
2603                 rn, xstat_cm_Results.probeNum,
2604                 xstat_cm_Results.connP->hostName);
2605         afsmon_Exit(90);
2606     }
2607
2608     tmp_cmPR = tmp_cmlist_item->cmResults[index];
2609
2610     /* copy hostname and probe number and probe time and probe status.
2611      * if the probe failed return now */
2612
2613     memcpy(tmp_cmPR->connP->hostName, xstat_cm_Results.connP->hostName,
2614            sizeof(xstat_cm_Results.connP->hostName));
2615     tmp_cmPR->probeNum = xstat_cm_Results.probeNum;
2616     tmp_cmPR->probeTime = xstat_cm_Results.probeTime;
2617     tmp_cmPR->probeOK = xstat_cm_Results.probeOK;
2618     if (xstat_cm_Results.probeOK) {     /* probeOK = 1 => notOK */
2619         /* we have a nonempty results structure so mark the list item used */
2620         tmp_cmlist_item->empty[index] = 0;
2621         return (0);
2622     }
2623
2624
2625     /* copy connection information */
2626     memcpy(&(tmp_cmPR->connP->skt), &(xstat_cm_Results.connP->skt),
2627            sizeof(struct sockaddr_in));
2628
2629    /**** NEED TO COPY rx_connection INFORMATION HERE ******/
2630
2631     memcpy(tmp_cmPR->connP->hostName, xstat_cm_Results.connP->hostName,
2632            sizeof(xstat_cm_Results.connP->hostName));
2633     tmp_cmPR->collectionNumber = xstat_cm_Results.collectionNumber;
2634
2635     /* copy the probe data information */
2636     tmp_cmPR->data.AFSCB_CollData_len =
2637         min(xstat_cm_Results.data.AFSCB_CollData_len,
2638             afsmon_cm_results_length[index]);
2639     memcpy(tmp_cmPR->data.AFSCB_CollData_val,
2640            xstat_cm_Results.data.AFSCB_CollData_val,
2641            tmp_cmPR->data.AFSCB_CollData_len * sizeof(afs_int32));
2642
2643
2644     /* we have a valid results structure so mark the list item used */
2645     tmp_cmlist_item->empty[index] = 0;
2646
2647     /* print the stored info - to make sure we copied it right */
2648     /*   Print_cm_FullPerfInfo(tmp_cmPR);        */
2649     /* Print the cm circular buffer */
2650     Print_CM_CB();
2651     return (0);
2652 }                               /* save_CM_results_inCB */
2653
2654
2655
2656 /*-----------------------------------------------------------------------
2657  * cm_Results_ltoa()
2658  *
2659  * Description:
2660  *      The results of xstat probes are stored in a string format in
2661  *      the arrays curr_cmData and prev_cmData. The information stored in
2662  *      prev_cmData is copied to the screen.
2663  *      This function converts xstat FS results from longs to strings and
2664  *      places them in the given buffer (a pointer to an item in curr_cmData).
2665  *      When a probe cycle completes, curr_cmData is copied to prev_cmData
2666  *      in afsmon_CM_Handler().
2667  *
2668  * Returns:
2669  *      Always returns 0.
2670  *----------------------------------------------------------------------*/
2671
2672 int
2673 cm_Results_ltoa(struct cm_Display_Data *a_cmData,       /* target buffer */
2674                 struct xstat_cm_ProbeResults *a_cmResults)      /* ptr to xstat cm Results */
2675 {                               /* cm_Results_ltoa */
2676
2677     static char rn[] = "cm_Results_ltoa";       /* routine name */
2678     struct afs_stats_CMFullPerf *fullP; /* ptr to complete CM stats */
2679     afs_int32 *srcbuf;
2680     afs_int32 *tmpbuf;
2681     int i, j;
2682     int idx;
2683     afs_int32 numLongs;
2684
2685     if (afsmon_debug) {
2686         fprintf(debugFD, "[ %s ] Called, a_cmData= %p, a_cmResults= %p\n", rn,
2687                 a_cmData, a_cmResults);
2688         fflush(debugFD);
2689     }
2690
2691
2692     fullP = (struct afs_stats_CMFullPerf *)
2693         (a_cmResults->data.AFSCB_CollData_val);
2694
2695     /* There are 4 parts to CM statistics
2696      * - Overall performance statistics (including up/down statistics)
2697      * - This CMs FS RPC operations info
2698      * - This CMs FS RPC errors info
2699      * - This CMs FS transfers info
2700      * - Authentication info
2701      * - [Un]Replicated access info
2702      */
2703
2704     /* copy overall performance statistics */
2705     srcbuf = (afs_int32 *) & (fullP->perf);
2706     idx = 0;
2707     /* we skip the 19 entry, ProtServAddr, so the index must account for this */
2708     for (i = 0; i < NUM_AFS_STATS_CMPERF_LONGS + 1; i++) {
2709         if (i == 19) {
2710             srcbuf++;
2711             continue;           /* skip ProtServerAddr */
2712         }
2713         sprintf(a_cmData->data[idx], "%d", *srcbuf);
2714         idx++;
2715         srcbuf++;
2716     }
2717
2718     /*printf("Ending index value = %d\n",idx-1); */
2719
2720     /* server up/down statistics */
2721     /* copy file server up/down stats */
2722     srcbuf = (afs_int32 *) (fullP->perf.fs_UpDown);
2723     numLongs =
2724         2 * (sizeof(struct afs_stats_SrvUpDownInfo) / sizeof(afs_int32));
2725     for (i = 0; i < numLongs; i++) {
2726         sprintf(a_cmData->data[idx], "%d", *srcbuf);
2727         idx++;
2728         srcbuf++;
2729     }
2730
2731     /*printf("Ending index value = %d\n",idx-1); */
2732
2733     /* copy volume location  server up/down stats */
2734     srcbuf = (afs_int32 *) (fullP->perf.vl_UpDown);
2735     numLongs =
2736         2 * (sizeof(struct afs_stats_SrvUpDownInfo) / sizeof(afs_int32));
2737     for (i = 0; i < numLongs; i++) {
2738         sprintf(a_cmData->data[idx], "%d", *srcbuf);
2739         idx++;
2740         srcbuf++;
2741     }
2742
2743     /*printf("Ending index value = %d\n",idx-1); */
2744
2745     /* copy CMs individual FS RPC operations info */
2746     srcbuf = (afs_int32 *) (fullP->rpc.fsRPCTimes);
2747     for (i = 0; i < AFS_STATS_NUM_FS_RPC_OPS; i++) {
2748         sprintf(a_cmData->data[idx], "%d", *srcbuf);    /* numOps */
2749         idx++;
2750         srcbuf++;
2751         sprintf(a_cmData->data[idx], "%d", *srcbuf);    /* numSuccesses */
2752         idx++;
2753         srcbuf++;
2754         tmpbuf = srcbuf++;      /* sum time */
2755         sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2756         idx++;
2757         srcbuf++;
2758         tmpbuf = srcbuf++;      /* sqr time */
2759         sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2760         idx++;
2761         srcbuf++;
2762         tmpbuf = srcbuf++;      /* min time */
2763         sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2764         idx++;
2765         srcbuf++;
2766         tmpbuf = srcbuf++;      /* max time */
2767         sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2768         idx++;
2769         srcbuf++;
2770     }
2771
2772     /*printf("Ending index value = %d\n",idx-1); */
2773
2774     /* copy CMs individual FS RPC errors info */
2775
2776     srcbuf = (afs_int32 *) (fullP->rpc.fsRPCErrors);
2777     for (i = 0; i < AFS_STATS_NUM_FS_RPC_OPS; i++) {
2778         sprintf(a_cmData->data[idx], "%d", *srcbuf);    /* server */
2779         idx++;
2780         srcbuf++;
2781         sprintf(a_cmData->data[idx], "%d", *srcbuf);    /* network */
2782         idx++;
2783         srcbuf++;
2784         sprintf(a_cmData->data[idx], "%d", *srcbuf);    /* prot */
2785         idx++;
2786         srcbuf++;
2787         sprintf(a_cmData->data[idx], "%d", *srcbuf);    /* vol */
2788         idx++;
2789         srcbuf++;
2790         sprintf(a_cmData->data[idx], "%d", *srcbuf);    /* busies */
2791         idx++;
2792         srcbuf++;
2793         sprintf(a_cmData->data[idx], "%d", *srcbuf);    /* other */
2794         idx++;
2795         srcbuf++;
2796     }
2797
2798     /*printf("Ending index value = %d\n",idx-1); */
2799
2800     /* copy CMs individual RPC transfers info */
2801
2802     srcbuf = (afs_int32 *) (fullP->rpc.fsXferTimes);
2803     for (i = 0; i < AFS_STATS_NUM_FS_XFER_OPS; i++) {
2804         sprintf(a_cmData->data[idx], "%d", *srcbuf);    /* numOps */
2805         idx++;
2806         srcbuf++;
2807         sprintf(a_cmData->data[idx], "%d", *srcbuf);    /* numSuccesses */
2808         idx++;
2809         srcbuf++;
2810         tmpbuf = srcbuf++;      /* sum time */
2811         sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2812         idx++;
2813         srcbuf++;
2814         tmpbuf = srcbuf++;      /* sqr time */
2815         sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2816         idx++;
2817         srcbuf++;
2818         tmpbuf = srcbuf++;      /* min time */
2819         sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2820         idx++;
2821         srcbuf++;
2822         tmpbuf = srcbuf++;      /* max time */
2823         sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2824         idx++;
2825         srcbuf++;
2826         sprintf(a_cmData->data[idx], "%d", *srcbuf);    /* sum bytes */
2827         idx++;
2828         srcbuf++;
2829         sprintf(a_cmData->data[idx], "%d", *srcbuf);    /* min bytes */
2830         idx++;
2831         srcbuf++;
2832         sprintf(a_cmData->data[idx], "%d", *srcbuf);    /* max bytes */
2833         idx++;
2834         srcbuf++;
2835         for (j = 0; j < AFS_STATS_NUM_XFER_BUCKETS; j++) {
2836             sprintf(a_cmData->data[idx], "%d", *srcbuf);        /* bucket[j] */
2837             idx++;
2838             srcbuf++;
2839         }
2840     }
2841
2842     /*printf("Ending index value = %d\n",idx-1); */
2843
2844     /* copy CM operations timings */
2845
2846     srcbuf = (afs_int32 *) (fullP->rpc.cmRPCTimes);
2847     for (i = 0; i < AFS_STATS_NUM_CM_RPC_OPS; i++) {
2848         sprintf(a_cmData->data[idx], "%d", *srcbuf);    /* numOps */
2849         idx++;
2850         srcbuf++;
2851         sprintf(a_cmData->data[idx], "%d", *srcbuf);    /* numSuccesses */
2852         idx++;
2853         srcbuf++;
2854         tmpbuf = srcbuf++;      /* sum time */
2855         sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2856         idx++;
2857         srcbuf++;
2858         tmpbuf = srcbuf++;      /* sqr time */
2859         sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2860         idx++;
2861         srcbuf++;
2862         tmpbuf = srcbuf++;      /* min time */
2863         sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2864         idx++;
2865         srcbuf++;
2866         tmpbuf = srcbuf++;      /* max time */
2867         sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2868         idx++;
2869         srcbuf++;
2870     }
2871
2872     /*printf("Ending index value = %d\n",idx-1); */
2873
2874     /* copy authentication info */
2875
2876     srcbuf = (afs_int32 *) & (fullP->authent);
2877     numLongs = sizeof(struct afs_stats_AuthentInfo) / sizeof(afs_int32);
2878     for (i = 0; i < numLongs; i++) {
2879         sprintf(a_cmData->data[idx], "%d", *srcbuf);
2880         idx++;
2881         srcbuf++;
2882     }
2883
2884     /*printf("Ending index value = %d\n",idx-1); */
2885
2886     /* copy CM [un]replicated access info */
2887
2888     srcbuf = (afs_int32 *) & (fullP->accessinf);
2889     numLongs = sizeof(struct afs_stats_AccessInfo) / sizeof(afs_int32);
2890     for (i = 0; i < numLongs; i++) {
2891         sprintf(a_cmData->data[idx], "%d", *srcbuf);
2892         idx++;
2893         srcbuf++;
2894     }
2895
2896     /*printf("Ending index value = %d\n",idx-1); */
2897     return (0);
2898
2899 }                               /* cm_Results_ltoa */
2900
2901
2902 /*-----------------------------------------------------------------------
2903  * Function:    check_cm_thresholds()
2904  *
2905  * Description:
2906  *      Checks the thresholds and sets the overflow flag. Recall that the
2907  *      thresholds for each host are stored in the hostEntry lists
2908  *      [fs/cm]nameList arrays. The probe results are passed to this
2909  *      function in the display-ready format - ie., as strings. Though
2910  *      this looks stupid the overhead incurred in converting the strings
2911  *      back to floats and comparing them is insignificant and
2912  *      programming is easier this way.
2913  *      The threshold flags are a part of the display structures
2914  *      curr_[fs/cm]Data.
2915  *
2916  * Returns:
2917  *      0
2918  *----------------------------------------------------------------------*/
2919
2920 int
2921 check_cm_thresholds(struct afsmon_hostEntry *a_hostEntry,       /* ptr to hostEntry */
2922                     struct cm_Display_Data *a_Data)             /* ptr to cm data to be displayed */
2923 {                               /* check_cm_thresholds */
2924
2925     static char rn[] = "check_cm_thresholds";
2926     struct Threshold *threshP;
2927     double tValue;              /* threshold value */
2928     double pValue;              /* probe value */
2929     int i;
2930     int idx;
2931     int count;                  /* number of thresholds exceeded */
2932
2933     if (afsmon_debug) {
2934         fprintf(debugFD, "[ %s ] Called, a_hostEntry= %p, a_Data= %p\n", rn,
2935                 a_hostEntry, a_Data);
2936         fflush(debugFD);
2937     }
2938
2939     if (a_hostEntry->numThresh == 0) {
2940         /* store in ovf count ?? */
2941         return (0);
2942     }
2943
2944     count = 0;
2945     threshP = a_hostEntry->thresh;
2946     for (i = 0; i < a_hostEntry->numThresh; i++) {
2947         if (threshP->itemName[0] == '\0') {
2948             threshP++;
2949             continue;
2950         }
2951         idx = threshP->index;   /* positional index to the data array */
2952         tValue = atof(threshP->threshVal);      /* threshold value */
2953         pValue = atof(a_Data->data[idx]);       /* probe value */
2954         if (pValue > tValue) {
2955
2956             if (afsmon_debug) {
2957                 fprintf(debugFD,
2958                         "[ %s ] cm = %s, thresh ovf for %s, threshold= %s, probevalue= %s\n",
2959                         rn, a_hostEntry->hostName, threshP->itemName,
2960                         threshP->threshVal, a_Data->data[idx]);
2961                 fflush(debugFD);
2962             }
2963
2964             /* if the threshold is crossed, call the handler function
2965              * only if this was a transition -ie, if the threshold was
2966              * crossed in the last probe too just count & keep quite! */
2967
2968             if (!a_Data->threshOvf[idx]) {
2969                 a_Data->threshOvf[idx] = 1;
2970                 /* call the threshold handler if provided */
2971                 if (threshP->handler[0] != '\0') {
2972                     if (afsmon_debug) {
2973                         fprintf(debugFD, "[ %s ] Calling ovf handler %s\n",
2974                                 rn, threshP->handler);
2975                         fflush(debugFD);
2976                     }
2977                     execute_thresh_handler(threshP->handler, a_Data->hostName,
2978                                            CM, threshP->itemName,
2979                                            threshP->threshVal,
2980                                            a_Data->data[idx]);
2981                 }
2982             }
2983
2984             count++;
2985         } else
2986             /* in case threshold was previously crossed, blank it out */
2987             a_Data->threshOvf[idx] = 0;
2988         threshP++;
2989     }
2990     /* store the overflow count */
2991     a_Data->ovfCount = count;
2992
2993     return (0);
2994 }                               /* check_cm_thresholds */
2995
2996
2997 /*-----------------------------------------------------------------------
2998  * save_CM_data_forDisplay()
2999  *
3000  * Description:
3001  *      Does the following:
3002  *      - if the probe number changed (ie, a cycle completed) curr_cmData
3003  *      is copied to prev_cmData, curr_cmData zeroed and refresh the
3004  *      overview screen and file server screen with the new data.
3005  *      - store the results of the current probe from xstat_cm_Results into
3006  *      curr_cmData. ie., convert longs to strings.
3007  *      - check the thresholds
3008  *
3009  * Returns:
3010  *      Success: 0
3011  *      Failure: Exits afsmonitor.
3012  *
3013  *----------------------------------------------------------------------*/
3014
3015 int
3016 save_CM_data_forDisplay(struct xstat_cm_ProbeResults *a_cmResults)
3017 {                               /* save_CM_data_forDisplay */
3018
3019     static char rn[] = "save_CM_data_forDisplay";       /* routine name */
3020     struct cm_Display_Data *curr_cmDataP;
3021     struct cm_Display_Data *prev_cmDataP;
3022     struct afsmon_hostEntry *curr_host;
3023     static int results_Received = 0;    /* number of probes reveived in
3024                                          * the current cycle. If this is equal to numFS we got all
3025                                          * the data we want in this cycle and can now display it */
3026     int numBytes;
3027     int done;
3028     int code;
3029     int okay;
3030     int i;
3031
3032     if (afsmon_debug) {
3033         fprintf(debugFD, "[ %s ] Called, a_cmResults= %p\n", rn, a_cmResults);
3034         fflush(debugFD);
3035     }
3036
3037     /* store results in the display array */
3038
3039     okay = 0;
3040     curr_cmDataP = curr_cmData;
3041     for (i = 0; i < numCM; i++) {
3042         if ((strcasecmp(curr_cmDataP->hostName, a_cmResults->connP->hostName))
3043             == 0) {
3044             okay = 1;
3045             break;
3046         }
3047         curr_cmDataP++;
3048     }
3049
3050     if (!okay) {
3051         fprintf(stderr,
3052                 "[ %s ] Could not insert CM probe results for host %s in cm display array\n",
3053                 rn, a_cmResults->connP->hostName);
3054         afsmon_Exit(95);
3055     }
3056
3057     /*  Check the status of the probe. If it succeeded, we store its
3058      * results in the display data structure. If it failed we only mark
3059      * the failed status in the display data structure. */
3060
3061
3062     if (a_cmResults->probeOK) { /* 1 => notOK the xstat results */
3063         curr_cmDataP->probeOK = 0;
3064
3065         /* print the probe status */
3066         if (afsmon_debug) {
3067             fprintf(debugFD, "\n\t\t ----- cm display data ------\n");
3068             fprintf(debugFD, "HostName = %s  PROBE FAILED \n",
3069                     curr_cmDataP->hostName);
3070             fflush(debugFD);
3071         }
3072
3073     } else {                    /* probe succeeded, update display data structures */
3074         curr_cmDataP->probeOK = 1;
3075
3076
3077         /* covert longs to strings and place them in curr_cmDataP */
3078         cm_Results_ltoa(curr_cmDataP, a_cmResults);
3079
3080         /* compare with thresholds and set the overflow flags.
3081          * note that the threshold information is in the hostEntry structure and
3082          * each threshold item has a positional index associated with it */
3083
3084         /* locate the hostEntry for this host */
3085         done = 0;
3086         curr_host = CMnameList;
3087         for (i = 0; i < numCM; i++) {
3088             if (strcasecmp(curr_host->hostName, a_cmResults->connP->hostName)
3089                 == 0) {
3090                 done = 1;
3091                 break;
3092             }
3093             curr_host = curr_host->next;
3094         }
3095         if (!done)
3096             afsmon_Exit(100);
3097
3098         code = check_cm_thresholds(curr_host, curr_cmDataP);
3099         if (code) {
3100             fprintf(stderr, "[ %s ] Error in checking thresholds\n", rn);
3101             afsmon_Exit(105);
3102         }
3103
3104         /* print the info we just saved */
3105         if (afsmon_debug) {
3106             fprintf(debugFD, "\n\t\t ----- CM display data ------\n");
3107             fprintf(debugFD, "HostName = %s\n", curr_cmDataP->hostName);
3108             for (i = 0; i < NUM_CM_STAT_ENTRIES; i++) {
3109                 switch (i) {
3110                 case 0:
3111                     fprintf(debugFD, "\t -- Overall Perf Info --\n");
3112                     break;
3113                 case 39:
3114                     fprintf(debugFD,
3115                             "\t -- File Server up/down stats - same cell --\n");
3116                     break;
3117                 case 64:
3118                     fprintf(debugFD,
3119                             "\t -- File Server up/down stats - diff cell --\n");
3120                     break;
3121                 case 89:
3122                     fprintf(debugFD,
3123                             "\t -- VL server up/down stats - same cell --\n");
3124                     break;
3125                 case 114:
3126                     fprintf(debugFD,
3127                             "\t -- VL server up/down stats - diff cell --\n");
3128                     break;
3129                 case 139:
3130                     fprintf(debugFD, "\t -- FS Operation Timings --\n");
3131                     break;
3132                 case 279:
3133                     fprintf(debugFD, "\t -- FS Error Info --\n");
3134                     break;
3135                 case 447:
3136                     fprintf(debugFD, "\t -- FS Transfer Timings --\n");
3137                     break;
3138                 case 475:
3139                     fprintf(debugFD, "\t -- CM Operations Timings --\n");
3140                     break;
3141                 case 510:
3142                     fprintf(debugFD, "\t -- Authentication Info --\n");
3143                     break;
3144                 case 522:
3145                     fprintf(debugFD, "\t -- Access Info --\n");
3146                     break;
3147                 default:
3148                     break;
3149                 }
3150
3151                 fprintf(debugFD, "%20s  %30s %s\n", curr_cmDataP->data[i],
3152                         cm_varNames[i],
3153                         curr_cmDataP->threshOvf[i] ? "(ovf)" : "");
3154             }
3155             fprintf(debugFD, "\t\t--------------------------------\n\n");
3156         }
3157
3158     }                           /* if the probe succeeded, update the display data structures */
3159
3160     /* if we have received a reply from all the hosts for this probe cycle,
3161      * it is time to display the data */
3162
3163     results_Received++;
3164     if (results_Received == numCM * num_cm_collections) {
3165         results_Received = 0;
3166
3167         if (afsmon_cm_curr_probeNum != afsmon_cm_prev_probeNum + 1) {
3168             sprintf(errMsg, "[ %s ] Probe number %d missed! \n", rn,
3169                     afsmon_cm_prev_probeNum + 1);
3170             afsmon_Exit(110);
3171         } else
3172             afsmon_cm_prev_probeNum++;
3173
3174
3175         /* backup the display data of the probe cycle that just completed -
3176          * ie., store curr_cmData in prev_cmData */
3177
3178         memcpy((char *)prev_cmData, (char *)curr_cmData,
3179                (numCM * sizeof(struct cm_Display_Data)));
3180
3181
3182         /* initialize curr_cmData but retain the threshold flag information.
3183          * The previous state of threshold flags is used in check_cm_thresholds() */
3184
3185         curr_cmDataP = curr_cmData;
3186         numBytes = NUM_CM_STAT_ENTRIES * CM_STAT_STRING_LEN;
3187         for (i = 0; i < numCM; i++) {
3188             curr_cmDataP->probeOK = 0;
3189             curr_cmDataP->ovfCount = 0;
3190             memset(curr_cmDataP->data, 0, numBytes);
3191             curr_cmDataP++;
3192         }
3193
3194         /* prev_cmData now contains all the information for the probe cycle
3195          * that just completed. Now count the number of threshold overflows for
3196          * use in the overview screen */
3197
3198         prev_cmDataP = prev_cmData;
3199         num_cm_alerts = 0;
3200         numHosts_oncm_alerts = 0;
3201         for (i = 0; i < numCM; i++) {
3202             if (!prev_cmDataP->probeOK) {       /* if probe failed */
3203                 num_cm_alerts++;
3204                 numHosts_oncm_alerts++;
3205             } else if (prev_cmDataP->ovfCount) {        /* overflows ?? */
3206                 num_cm_alerts += prev_cmDataP->ovfCount;
3207                 numHosts_oncm_alerts++;
3208             }
3209             prev_cmDataP++;
3210         }
3211         if (afsmon_debug)
3212             fprintf(debugFD, "Number of CM alerts = %d (on %d hosts)\n",
3213                     num_cm_alerts, numHosts_oncm_alerts);
3214
3215
3216         /* flag that the data is now ready to be displayed */
3217         cm_Data_Available = 1;
3218
3219         /* update the Overview frame (only CM info) */
3220         ovw_refresh(ovw_currPage, OVW_UPDATE_CM);
3221
3222         /* update the Cache Managers frame */
3223         cm_refresh(cm_currPage, cm_curr_LCol);
3224
3225     }
3226
3227
3228     return (0);
3229 }                               /* save_CM_data_forDisplay */
3230
3231
3232
3233 /*-----------------------------------------------------------------------
3234  * afsmon_CM_Handler()
3235  *
3236  * Description:
3237  *      This is the Cache Manager probe Handler. It updates the afsmonitor
3238  *      probe counts, cm circular buffer indices and calls the functions
3239  *      to process the results of this probe.
3240  *
3241  * Returns:
3242  *      Success: 0
3243  *      Failure: Exits afsmonitor.
3244  *----------------------------------------------------------------------*/
3245
3246 int
3247 afsmon_CM_Handler(void)
3248 {                               /* afsmon_CM_Handler() */
3249     static char rn[] = "afsmon_CM_Handler";     /* routine name */
3250     int code;                   /* return status */
3251     int newProbeCycle;          /* start of new probe cycle ? */
3252
3253     if (afsmon_debug) {
3254         fprintf(debugFD,
3255                 "[ %s ] Called, hostName= %s, probeNum= %d, status= %s\n", rn,
3256                 xstat_cm_Results.connP->hostName, xstat_cm_Results.probeNum,
3257                 xstat_cm_Results.probeOK ? "FAILED" : "OK");
3258         fflush(debugFD);
3259     }
3260
3261
3262     /* print the probe results to output file */
3263     if (afsmon_output) {
3264         code = afsmon_cmOutput(output_filename, afsmon_detOutput);
3265         if (code) {
3266             fprintf(stderr,
3267                     "[ %s ] output to file %s returned error code=%d\n", rn,
3268                     output_filename, code);
3269         }
3270     }
3271
3272     /* Update current probe number and circular buffer index. if current
3273      * probenum changed make sure it is only by 1 */
3274
3275     newProbeCycle = 0;
3276     if (xstat_cm_Results.probeNum != afsmon_cm_curr_probeNum) {
3277         if (xstat_cm_Results.probeNum == afsmon_cm_curr_probeNum + 1) {
3278             afsmon_cm_curr_probeNum++;
3279             newProbeCycle = 1;
3280             if (num_bufSlots)
3281                 afsmon_cm_curr_CBindex =
3282                     (afsmon_cm_curr_probeNum - 1) % num_bufSlots;
3283         } else {
3284             fprintf(stderr, "[ %s ] probe number %d-1 missed\n", rn,
3285                     xstat_cm_Results.probeNum);
3286             afsmon_Exit(115);
3287         }
3288     }
3289
3290     /* save the results of this probe in the CM buffer */
3291     if (num_bufSlots)
3292         save_CM_results_inCB(newProbeCycle);
3293
3294     /* store the results of the current probe in the cm data display structure.
3295      * if the current probe number changed, swap the current and previous display
3296      * structures. note that the display screen is updated from these structures
3297      * and should start showing the data of the just completed probe cycle */
3298
3299     save_CM_data_forDisplay(&xstat_cm_Results);
3300
3301     return (0);
3302 }
3303
3304 /*-----------------------------------------------------------------------
3305  * init_fs_buffers()
3306  *
3307  * Description:
3308  *      Allocate and Initialize circular buffers for file servers.
3309  *
3310  * Returns:
3311  *      Success: 0
3312  *      Failure to allocate memory: exits afsmonitor.
3313  *----------------------------------------------------------------------*/
3314
3315 int
3316 init_fs_buffers(void)
3317 {                               /* init_fs_buffers() */
3318     static char rn[] = "init_fs_buffers";       /* routine name */
3319     struct afsmon_fs_Results_list *new_fslist_item;     /* ptr for new struct */
3320     struct afsmon_fs_Results_list *tmp_fslist_item;     /* temp ptr */
3321     struct xstat_fs_ProbeResults *new_fsPR;     /* ptr for new struct  */
3322     int i, j;
3323     int bufslot;
3324     int numfs;
3325
3326
3327     if (afsmon_debug) {
3328         fprintf(debugFD, "[ %s ] Called\n", rn);
3329         fflush(debugFD);
3330     }
3331
3332     /* allocate memory for the circular buffer of pointers */
3333
3334     afsmon_fs_ResultsCB = (struct afsmon_fs_Results_CBuffer *)
3335         malloc(sizeof(struct afsmon_fs_Results_CBuffer) * num_bufSlots);
3336
3337     /* initialize the fs circular buffer */
3338     for (i = 0; i < num_bufSlots; i++) {
3339         afsmon_fs_ResultsCB[i].list = (struct afsmon_fs_Results_list *)0;
3340         afsmon_fs_ResultsCB[i].probeNum = 0;
3341     }
3342
3343     /* create  a list of numFS items to store fs probe results for
3344      * each slot in CB */
3345
3346     if (numFS) {                /* if we have file servers to monitor */
3347         for (bufslot = 0; bufslot < num_bufSlots; bufslot++) {
3348             numfs = numFS;      /* get the number of servers */
3349             while (numfs--) {
3350
3351                 /* if any of these mallocs fail we only need to free the memory we
3352                  * have allocated in this iteration. the rest of it which is in a
3353                  * proper linked list will be freed in afsmon_Exit */
3354
3355                 /* allocate memory for an fs list item */
3356                 new_fslist_item = (struct afsmon_fs_Results_list *)
3357                     malloc(sizeof(struct afsmon_fs_Results_list));
3358                 if (new_fslist_item == (struct afsmon_fs_Results_list *)0)
3359                     return (-1);
3360
3361                 for (i = 0; i < MAX_NUM_FS_COLLECTIONS; i++) {
3362                     /* allocate memory to store xstat_fs_Results */
3363                     new_fsPR = (struct xstat_fs_ProbeResults *)
3364                         malloc(sizeof(struct xstat_fs_ProbeResults));
3365                     if (!new_fsPR) {
3366                         free(new_fslist_item);
3367                         return (-1);
3368                     }
3369
3370                     new_fsPR->connP = (struct xstat_fs_ConnectionInfo *)
3371                         malloc(sizeof(struct xstat_fs_ConnectionInfo));
3372                     if (new_fsPR->connP == (struct xstat_fs_ConnectionInfo *)0) {
3373                         free(new_fslist_item);
3374                         free(new_fsPR);
3375                         return (-1);
3376                     }
3377
3378                     /* >>>  need to allocate rx connection info structure here <<< */
3379                     new_fsPR->data.AFS_CollData_val = (afs_int32 *)
3380                        malloc(afsmon_fs_results_length[i] * sizeof(afs_int32));
3381                     if (new_fsPR->data.AFS_CollData_val == NULL) {
3382                        free(new_fslist_item);
3383                        free(new_fsPR->connP);
3384                        free(new_fsPR);
3385                        return (-1);
3386                     }
3387                     new_fslist_item->fsResults[i] = new_fsPR;
3388                     new_fslist_item->empty[i] = 1;
3389                 }
3390
3391                 /* initialize this list entry */
3392                 new_fslist_item->next = (struct afsmon_fs_Results_list *)0;
3393
3394                 /* store it at the end of the fs list in the current CB slot */
3395                 if (afsmon_fs_ResultsCB[bufslot].list ==
3396                     (struct afsmon_fs_Results_list *)0)
3397                     afsmon_fs_ResultsCB[bufslot].list = new_fslist_item;
3398                 else {
3399                     tmp_fslist_item = afsmon_fs_ResultsCB[bufslot].list;
3400                     j = 0;
3401                     while (tmp_fslist_item !=
3402                            (struct afsmon_fs_Results_list *)0) {
3403                         if (tmp_fslist_item->next ==
3404                             (struct afsmon_fs_Results_list *)0)
3405                             break;
3406                         tmp_fslist_item = tmp_fslist_item->next;
3407                         if (++j > numFS) {
3408                             /* something goofed. exit */
3409                             fprintf(stderr, "[ %s ] list creation error\n",
3410                                     rn);
3411                             return (-1);
3412                         }
3413                     }
3414                     tmp_fslist_item->next = new_fslist_item;
3415                 }
3416
3417             }                   /* while servers */
3418         }                       /* for each buffer slot */