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