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