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