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