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