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