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