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