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