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