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