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