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