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