2 * Copyright 2000, International Business Machines Corporation and others.
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
11 * Afsmonitor: An AFS Performance Monitoring Tool
13 *-------------------------------------------------------------------------*/
22 #include <afs/param.h>
26 #include <sys/types.h>
27 #include <netinet/in.h>
29 #include <sys/socket.h>
33 #include <gtxwindows.h> /*Generic window package*/
34 #include <gtxobjects.h> /*Object definitions*/
36 #include <gtxtextobj.h> /*Text object interface*/
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*/
46 #include <afs/xstat_fs.h>
47 #include <afs/xstat_cm.h>
50 #include "afsmonitor.h"
53 /* command line parameter indices */
59 /* #define P_PACKAGE X */
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*/
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];
83 /* afsmonitor misc definitions */
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 */
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 */
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 ? */
102 /* THRESHOLD STRUCTURE DEFINITIONS */
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 */
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;
117 /* number of fileservers and cache managers to monitor */
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. */
133 /* FILE SERVER CIRCULAR BUFFER VARIABLES */
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;
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 */
146 /* buffer for FS probe results */
147 struct afsmon_fs_Results_CBuffer *afsmon_fs_ResultsCB;
149 int afsmon_fs_curr_CBindex = 0; /* current fs CB slot */
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
157 int afsmon_fs_curr_probeNum = 1; /* current fs probe number */
158 int afsmon_fs_prev_probeNum = 0; /* previous fs probe number */
161 /* CACHE MANAGER CIRCULAR BUFFER VARIABLES */
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;
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 */
174 /* buffer for CM probe results */
175 struct afsmon_cm_Results_CBuffer *afsmon_cm_ResultsCB;
177 int afsmon_cm_curr_CBindex = 0; /* current cm CB slot */
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
186 int afsmon_cm_curr_probeNum = 1; /* current cm probe number */
187 int afsmon_cm_prev_probeNum = 0; /* previous cm probe number */
190 /* Structures to hold FS & CM results in string format(suitable for display ) */
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;
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;
206 /* EXTERN DEFINITIONS */
208 extern struct hostent *hostutil_GetHostByName();
212 /* routines from afsmon-output.c */
213 extern int afsmon_fsOutput();
214 extern int afsmon_cmOutput();
216 /* file server and cache manager variable names (from afsmon_labels.h) */
217 extern char *fs_varNames[];
218 extern char *cm_varNames[];
220 /* GTX & MISC VARIABLES */
222 /* afsmonitor window */
223 extern struct gwin *afsmon_win;
225 /* current page number in the overview frame */
226 extern int ovw_currPage;
228 /* number of FS alerts and number of hosts on FS alerts */
230 int numHosts_onfs_alerts;
232 /* number of CM alerts and number of hosts on FS alerts */
234 int numHosts_oncm_alerts;
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;
241 extern int gtx_initialized; /* gtx initialized ? */
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 */
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 ? */
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 ? */
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 */
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 */
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 */
275 strcasestr(): Return first occurence of pattern s2 in s1, case
278 This routine is required since I made pattern matching of the
279 config file to be case insensitive.
282 char *strcasestr(s1,s2)
293 return ((char *)NULL);
297 while( len1 >= len2 && len1 > 0 ) {
298 if ( (strncasecmp(ptr,s2,len2)) == 0)
303 return ((char *)NULL);
307 struct hostent *GetHostByName(name)
313 he = gethostbyname(name);
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);
325 /*-----------------------------------------------------------------------
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().
338 * This function is called to execute a user handler only
339 * by a child process.
341 *----------------------------------------------------------------------*/
344 afsmon_Exit(a_exitVal)
345 int a_exitVal; /* exit code */
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;
363 fprintf(debugFD,"[ %s ] Called with exit code %d\n",rn, a_exitVal);
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);
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);
378 /* deallocate file server circular buffers */
379 if (numFS && num_bufSlots) {
381 fprintf(debugFD,"freeing FS circular buffers ");
385 for (bufslot=0; bufslot<num_bufSlots; bufslot++) {
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;
392 while ( tmp_fslist ) {
393 /* make sure we do not go astray */
396 fprintf(debugFD,"[ %s ] error in deallocating fs CB\n",
400 next_fslist = tmp_fslist->next;
401 tmp_xstat_fsPR = tmp_fslist->fsResults;
404 fprintf(debugFD,"%d ",numFS-j);
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);
411 /* free the fs list item */
413 tmp_fslist = next_fslist;
415 } /* while fs list items in this slot */
416 } /* if entries in this buffer slot */
417 } /* for each fs buffer slot */
419 fprintf(debugFD,"\n");
424 /* deallocate cache manager curcular buffers */
425 if (numCM && num_bufSlots) {
427 fprintf(debugFD,"freeing CM curcular buffers ");
428 for (bufslot=0; bufslot<num_bufSlots; bufslot++) {
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;
435 while ( tmp_cmlist ) {
436 /* make sure we do not go astray */
439 fprintf(debugFD,"[ %s ] error in deallocating cm CB\n",
443 next_cmlist = tmp_cmlist->next;
444 tmp_xstat_cmPR = tmp_cmlist->cmResults;
447 fprintf(debugFD,"%d ",numCM-j);
448 /* make sure data is ok */
449 /* Print_cm_FullPerfInfo(tmp_xstat_cmPR); */
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);
456 /* free the cm list item */
458 tmp_cmlist = next_cmlist;
460 } /* while cm list items in this slot */
461 } /* if entries in this buffer slot */
462 } /* for each cm buffer slot */
464 fprintf(debugFD,"\n");
468 /* deallocate FS & CM Print buffers */
469 if (curr_fsData != (struct fs_Display_Data *)0) {
471 fprintf(debugFD,"Deallocating FS Print Buffers .... curr");
474 if (prev_fsData != (struct fs_Display_Data *)0) {
476 fprintf(debugFD,", prev \n");
479 if (prev_cmData != (struct cm_Display_Data *)0) {
481 fprintf(debugFD,"Deallocating CM Print Buffers .... curr");
484 if (prev_cmData != (struct cm_Display_Data *)0) {
486 fprintf(debugFD,", prev \n");
490 /* deallocate hostEntry lists */
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);
501 fprintf(debugFD," %d",i);
502 curr_hostEntry = prev_hostEntry->next;
505 fprintf(debugFD,"\n");
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);
517 fprintf(debugFD," %d",i);
518 curr_hostEntry = prev_hostEntry->next;
521 fprintf(debugFD,"\n");
524 /* close debug file */
530 if (exec_fsThreshHandler) {
531 code = execvp(fsHandler_argv[0],fsHandler_argv);
533 fprintf(stderr,"execvp() of %s returned %d, errno %d\n",
534 fsHandler_argv[0], code, errno);
542 /*-----------------------------------------------------------------------
546 * Insert a hostname in the file server names list.
551 *----------------------------------------------------------------------*/
554 insert_FS( a_hostName )
555 char *a_hostName; /* name of cache manager to be inserted in list */
557 static char rn[] = "insert_FS"; /* routine name */
558 static struct afsmon_hostEntry *curr_item;
559 static struct afsmon_hostEntry *prev_item;
561 if ( *a_hostName == '\0')
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");
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;
575 if (FSnameList == (struct afsmon_hostEntry *)0)
576 FSnameList = curr_item;
578 prev_item->next = curr_item;
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;
588 /*-----------------------------------------------------------------------
593 * Prints the file server names linked list.
597 *----------------------------------------------------------------------*/
601 static char rn[] = "print_FS";
602 struct afsmon_hostEntry *tempFS;
603 struct Threshold *threshP;
607 fprintf(debugFD,"[ %s ] Called\n",rn);
613 fprintf(debugFD,"No of File Servers: %d\n",numFS);
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);
625 fprintf(debugFD,"\t\t-----End of List-----\n");
631 /*-----------------------------------------------------------------------
635 * Insert a hostname in the cache manager names list.
640 *----------------------------------------------------------------------*/
643 insert_CM( a_hostName )
644 char *a_hostName; /* name of cache manager to be inserted in list */
646 static char rn[] = "insert_CM"; /* routine name */
647 static struct afsmon_hostEntry *curr_item;
648 static struct afsmon_hostEntry *prev_item;
650 if ( *a_hostName == '\0')
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");
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;
664 if (CMnameList == (struct afsmon_hostEntry *)0)
665 CMnameList = curr_item;
667 prev_item->next = curr_item;
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;
678 /*-----------------------------------------------------------------------
683 * Prints the cache manager names linked list.
687 *----------------------------------------------------------------------*/
691 static char rn[] = "print_CM";
692 struct afsmon_hostEntry *tempCM;
693 struct Threshold *threshP;
697 fprintf(debugFD,"[ %s ] Called\n",rn);
703 fprintf(debugFD,"No of Cache Managers: %d\n",numCM);
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);
715 fprintf(debugFD,"\t\t-----End of List-----\n");
721 /*-----------------------------------------------------------------------
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.
737 *----------------------------------------------------------------------*/
740 parse_hostEntry(a_line)
742 { /* parse_hostEntry */
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 */
755 fprintf(debugFD,"[ %s ] Called, a_line = %s\n",rn, a_line);
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);
769 he = GetHostByName(arg1);
770 if ( he == (struct hostent *)0) {
771 fprintf(stderr,"[ %s ] Unable to resolve hostname %s\n",
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 */
782 /* threholds are not global anymore */
783 if (global_ThreshFlag) global_ThreshFlag = 0;
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 */
791 /* threholds are not global anymore */
792 if (global_ThreshFlag) global_ThreshFlag = 0;
800 /*-----------------------------------------------------------------------
801 * parse_threshEntry()
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.
814 *----------------------------------------------------------------------*/
817 parse_threshEntry(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 */
831 fprintf(debugFD,"[ %s ] Called, a_line = %s\n",rn, a_line);
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);
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);
844 if (strlen(arg3) > THRESH_VAR_LEN-2) {
845 fprintf(stderr,"[%s ] threshold value too long\n");
849 if ((strcasecmp(arg1,"fs")) == 0) {
850 switch (lastHostType) {
851 case 0: /* its a global threshold */
852 global_fsThreshCount++;
854 case 1: /* inc thresh count of last file server */
855 last_hostEntry->numThresh++;
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);
861 fprintf(stderr,"[ %s ] Programming error 1\n",rn);
864 } else if ((strcasecmp(arg1,"cm")) == 0) {
865 switch (lastHostType) {
866 case 0: /* its a global threshold */
867 global_cmThreshCount++;
869 case 2: /* inc thresh count of last cache manager */
870 last_hostEntry->numThresh++;
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);
876 fprintf(stderr,"[ %s ] Programming error 2\n",rn);
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);
885 } /* parse_threshEntry */
888 /*-----------------------------------------------------------------------
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
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.
909 *----------------------------------------------------------------------*/
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 */
918 { /* store_thresholds */
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 */
925 int index; /* index to fs_varNames or cm_varNames */
928 int srvCount; /* tmp count of host names */
929 int *global_TC; /* ptr to global_xxThreshCount */
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);
937 /* resolve the threshold variable name */
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) {
947 fprintf(stderr,"[ %s ] Unknown FS threshold variable name %s\n",
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) {
963 fprintf(stderr,"[ %s ] Unknown CM threshold variable name %s\n",
969 hostname = last_cmHost;
970 global_TC = &global_cmThreshCount;
976 /* if the global thresh count is not zero, place this threshold on
977 all the host entries */
981 for(i=0; i<srvCount; i++) {
982 threshP = tmp_host->thresh;
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;
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);
1002 tmp_host = tmp_host->next;
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 */
1011 if (*hostname == '\0') {
1012 fprintf(stderr,"[ %s ] Programming error 3\n",rn);
1016 /* get the hostEntry that this threshold belongs to */
1019 for(i=0; i < srvCount; i++) {
1020 if (strcasecmp(tmp_host->hostName,hostname) == 0) {
1024 tmp_host = tmp_host->next;
1027 fprintf(stderr,"[ %s ] Unable to find host %s in %s hostEntry list",
1028 rn,hostname,(a_type-1)?"CM":"FS");
1032 /* put this entry on the thresh list of this host, overwrite global value
1035 threshP = tmp_host->thresh;
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;
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);
1058 } /* store_thresholds */
1061 /*-----------------------------------------------------------------------
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.
1081 * Failure: -1 (invalid entry)
1082 * > -1 (programming error)
1083 *----------------------------------------------------------------------*/
1086 parse_showEntry(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 */
1099 int idx; /* index to fs_categories[] */
1105 fprintf(debugFD,"[ %s ] Called, a_line= %s\n",rn, a_line);
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);
1111 if (arg3[0] != '\0') {
1112 fprintf(stderr,"[ %s ] Extraneous characters at end of line\n",rn);
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);
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
1128 /* To handle duplicate "show" entries we keep track of what what we have
1129 already marked to show in the xx_showFlags[] */
1131 if (strcasecmp(arg1,"fs") == 0) { /* its a File Server entry */
1133 /* mark that we have to show only what the user wants */
1136 /* if it is a section/group name, find it in the fs_categories[] array */
1139 if ( strcasestr(arg2,"_section") != (char *)NULL ||
1140 strcasestr(arg2,"_group") != (char *)NULL ) {
1142 while(idx<FS_NUM_DATA_CATEGORIES) {
1143 sscanf(fs_categories[idx],"%s %d %d",catName, &fromIdx, &toIdx);
1145 if (strcasecmp(arg2, catName) == 0) {
1151 if (! found) { /* typo in section/group name */
1152 fprintf(stderr,"[ %s ] Could not find section/group name %s\n",rn,arg2);
1157 /* if it is a group name, read its start/end indices and fill in the
1158 fs_Display_map[]. */
1160 if (strcasestr(arg2,"_group") != (char *)NULL ) {
1162 if (fromIdx < 0 || toIdx < 0 || fromIdx > NUM_FS_STAT_ENTRIES ||
1163 toIdx > NUM_FS_STAT_ENTRIES)
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;
1171 if (fs_DisplayItems_count > NUM_FS_STAT_ENTRIES) {
1172 fprintf(stderr,"[ %s ] fs_DisplayItems_count ovf\n",rn);
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[] */
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);
1188 if (strcasestr(catName,"_group") != (char *)0) {
1189 if (fromIdx < 0 || toIdx < 0 || fromIdx > NUM_FS_STAT_ENTRIES ||
1190 toIdx > NUM_FS_STAT_ENTRIES)
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;
1198 if (fs_DisplayItems_count > NUM_FS_STAT_ENTRIES) {
1199 fprintf(stderr,"[ %s ] fs_DisplayItems_count ovf\n",rn);
1204 fprintf(stderr,"[ %s ] Error parsing groups for %s\n",rn,arg2);
1209 } /* for each group in section */
1212 } else { /* it is a variable name */
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;
1221 if (fs_DisplayItems_count >= NUM_FS_STAT_ENTRIES) {
1222 fprintf(stderr,"[ %s ] fs_DisplayItems_count ovf\n",rn);
1228 if (! found) { /* typo in section/group name */
1229 fprintf(stderr,"[ %s ] Could not find variable name %s\n",rn,arg2);
1232 } /* its a variable name */
1234 } /* it is an fs entry */
1237 if (strcasecmp(arg1,"cm") == 0) { /* its a Cache Manager entry */
1240 /* mark that we have to show only what the user wants */
1243 /* if it is a section/group name, find it in the cm_categories[] array */
1246 if ( strcasestr(arg2,"_section") != (char *)NULL ||
1247 strcasestr(arg2,"_group") != (char *)NULL ) {
1249 while(idx<CM_NUM_DATA_CATEGORIES) {
1250 sscanf(cm_categories[idx],"%s %d %d",catName, &fromIdx, &toIdx);
1252 if (strcasecmp(arg2, catName) == 0) {
1258 if (! found) { /* typo in section/group name */
1259 fprintf(stderr,"[ %s ] Could not find section/group name %s\n",rn,arg2);
1264 /* if it is a group name, read its start/end indices and fill in the
1265 cm_Display_map[]. */
1267 if (strcasestr(arg2,"_group") != (char *)NULL ) {
1269 if (fromIdx < 0 || toIdx < 0 || fromIdx > NUM_CM_STAT_ENTRIES ||
1270 toIdx > NUM_CM_STAT_ENTRIES)
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;
1278 if (cm_DisplayItems_count > NUM_CM_STAT_ENTRIES) {
1279 fprintf(stderr,"[ %s ] cm_DisplayItems_count ovf\n",rn);
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[] */
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);
1295 if (strcasestr(catName,"_group") != (char *)0) {
1296 if (fromIdx < 0 || toIdx < 0 || fromIdx > NUM_CM_STAT_ENTRIES ||
1297 toIdx > NUM_CM_STAT_ENTRIES)
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;
1305 if (cm_DisplayItems_count > NUM_CM_STAT_ENTRIES) {
1306 fprintf(stderr,"[ %s ] cm_DisplayItems_count ovf\n",rn);
1311 fprintf(stderr,"[ %s ] Error parsing groups for %s\n",rn,arg2);
1316 } /* for each group in section */
1323 } else { /* it is a variable name */
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;
1332 if (cm_DisplayItems_count >= NUM_CM_STAT_ENTRIES) {
1333 fprintf(stderr,"[ %s ] cm_DisplayItems_count ovf\n",rn);
1339 if (! found) { /* typo in section/group name */
1340 fprintf(stderr,"[ %s ] Could not find variable name %s\n",rn,arg2);
1343 } /* its a variable name */
1345 } /* it is an cm entry */
1350 } /* parse_showEntry */
1353 /*-----------------------------------------------------------------------
1354 * process_config_file()
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
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
1369 * Failure: Exits afsmonitor showing error and line.
1370 *----------------------------------------------------------------------*/
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 ?? */
1395 fprintf(debugFD,"[ %s ] Called, a_config_filename= %s\n",
1396 rn, a_config_filename);
1400 /* open config file */
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);
1406 fprintf(debugFD,"[ %s ] Failed to open config file %s \n",
1407 rn, a_config_filename);
1413 /* parse config file */
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.*/
1425 error_in_config = 0; /* flag to note if config file has syntax errors*/
1427 while ( (fgets(line,CFG_STR_LEN,configFD)) != NULL)
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);
1432 /* skip blank lines and comment lines */
1433 if ( (strlen(opcode) == 0) || line[0] == '#' ) continue;
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);
1442 fprintf(stderr,"[ %s ] Unknown opcode %s\n",rn,opcode);
1447 fprintf(stderr,"[ %s ] Error in line:\n %d: %s\n",
1449 error_in_config = 1;
1453 if (error_in_config)
1457 fprintf(debugFD,"Global FS thresholds count = %d\n",global_fsThreshCount);
1458 fprintf(debugFD,"Global CM thresholds count = %d\n",global_cmThreshCount);
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
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;
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;
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");
1492 fseek(configFD,0,0); /* seek to the beginning */
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);
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);
1509 bzero(curr_host->thresh,numBytes);
1511 curr_host = curr_host->next;;
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);
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);
1527 bzero(curr_host->thresh,numBytes);
1529 curr_host = curr_host->next;;
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';
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);
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);
1547 else if (strcasecmp(opcode,"cm") == 0) {
1548 he = GetHostByName(arg1);
1549 strncpy(last_cmHost,he->h_name,HOST_NAME_LEN);
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
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) )
1562 while(! isspace(*handlerPtr) )
1565 while( isspace(*handlerPtr) )
1567 /* we how have a pointer to the start of the handler
1570 handlerPtr = arg4; /* empty string */
1573 if (strcasecmp(arg1,"fs") == 0)
1574 code = store_threshold(1, /* 1 = fs*/
1575 arg2,arg3,handlerPtr);
1577 else if (strcasecmp(arg1,"cm") == 0)
1578 code = store_threshold(2, /* 2 = fs*/
1579 arg2,arg3,handlerPtr);
1582 fprintf(stderr,"[ %s ] Programming error 6\n");
1586 fprintf(stderr,"[ %s ] Failed to store threshold\n",
1588 fprintf(stderr,"[ %s ] Error processing line:\n%d: %s",
1600 /*-----------------------------------------------------------------------
1605 * Print the File Server circular buffer.
1609 *----------------------------------------------------------------------*/
1613 { /* Print_FS_CB() */
1615 struct afsmon_fs_Results_list *fslist;
1619 /* print valid info in the fs CB */
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);
1626 for(i=0; i<num_bufSlots; i++) {
1627 fprintf(debugFD,"\t--------- slot %d ----------\n",i);
1628 fslist = afsmon_fs_ResultsCB[i].list;
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");
1638 fprintf(debugFD,"\t %d) -- empty --\n",j);
1639 fslist = fslist->next;
1642 if (fslist != (struct afsmon_fs_Results_list *)0 )
1643 fprintf(debugFD,"dangling last next ptr fs CB\n");
1646 } /* Print_FS_CB() */
1648 /*-----------------------------------------------------------------------
1649 * save_FS_results_inCB()
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.
1662 * Failure: Exits afsmonitor.
1663 *----------------------------------------------------------------------*/
1665 save_FS_results_inCB(a_newProbeCycle)
1666 int a_newProbeCycle; /* start of a new probe cycle ? */
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 */
1676 fprintf(debugFD,"[ %s ] Called, a_newProbeCycle= %d\n",
1677 rn, a_newProbeCycle);
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() */
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;
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;
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);
1708 tmp_fsPR = tmp_fslist_item->fsResults;
1710 /* copy hostname and probe number and probe time and probe status.
1711 if the probe failed return now */
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;
1724 /* copy connection information */
1725 #ifdef AFS_LINUX20_ENV
1726 bcopy(&(xstat_fs_Results.connP->skt), &(tmp_fsPR->connP->skt),
1727 sizeof(struct sockaddr_in));
1729 bcopy(xstat_fs_Results.connP->skt, tmp_fsPR->connP->skt,
1730 sizeof(struct sockaddr_in));
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;
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));
1744 /* we have a valid results structure so mark the list item used */
1745 tmp_fslist_item->empty = 0;
1747 /* Print the fs circular buffer */
1751 } /* save_FS_results_inCB() */
1754 /*-----------------------------------------------------------------------
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().
1768 *----------------------------------------------------------------------*/
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 */
1776 static char rn[] = "fs_Results_ltoa"; /* routine name */
1778 struct fs_stats_FullPerfStats *fullPerfP;
1784 fprintf(debugFD,"[ %s ] Called, a_fsData= %d, a_fsResults= %d\n",
1785 rn, a_fsData, a_fsResults);
1789 fullPerfP = (struct fs_stats_FullPerfStats *)
1790 (a_fsResults->data.AFS_CollData_val);
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
1797 /* copy overall performance statistics */
1798 srcbuf = (afs_int32 *) &(fullPerfP->overall);
1800 for(i=0; i< NUM_XSTAT_FS_AFS_PERFSTATS_LONGS; i++) {
1801 sprintf(a_fsData->data[idx],"%d",*srcbuf);
1807 srcbuf = (afs_int32 *) &(fullPerfP->det.epoch);
1808 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* epoch */
1811 /* copy fs operation timing */
1813 srcbuf = (afs_int32 *) (fullPerfP->det.rpcOpTimes);
1815 for(i=0; i<FS_STATS_NUM_RPC_OPS; i++) {
1816 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* numOps*/
1818 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* numSuccesses */
1820 tmpbuf = srcbuf++; /* sum time */
1821 sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1823 tmpbuf = srcbuf++; /* sqr time */
1824 sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1826 tmpbuf = srcbuf++; /* min time */
1827 sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1829 tmpbuf = srcbuf++; /* max time */
1830 sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1834 /* copy fs transfer timings */
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*/
1840 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* numSuccesses */
1842 tmpbuf = srcbuf++; /* sum time */
1843 sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1845 tmpbuf = srcbuf++; /* sqr time */
1846 sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1848 tmpbuf = srcbuf++; /* min time */
1849 sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1851 tmpbuf = srcbuf++; /* max time */
1852 sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1854 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* sum bytes */
1856 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* min bytes */
1858 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* max bytes */
1860 for(j=0; j<FS_STATS_NUM_XFER_BUCKETS; j++) {
1861 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* bucket[j] */
1867 } /* fs_Results_ltoa */
1871 /*-----------------------------------------------------------------------
1872 * execute_thresh_handler()
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.
1882 * Failure: Afsmonitor exits if threshold handler has more than 20 args.
1883 *----------------------------------------------------------------------*/
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 */
1895 { /* execute_thresh_handler */
1897 static char rn[] = "execute_thresh_handler";
1898 char fileName[256]; /* file name to execute */
1903 int anotherArg; /* boolean used to flag if another arg is available */
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,
1913 /* get the filename to execute - the first argument */
1914 sscanf(a_handler,"%s",fileName);
1916 /* construct the contents of *argv[] */
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);
1931 /* we have already extracted the file name so skip to the 1st arg */
1932 while (isspace(*ch)) /* leading blanks */
1934 while (! isspace(*ch) && *ch != '\0') /* handler filename */
1937 while( *ch != '\0' ) {
1940 } else if (anotherArg) {
1942 sscanf(ch,"%s",fsHandler_args[argNum]);
1948 "Threshold handlers cannot have more than 20 arguments\n");
1954 fsHandler_argv[argNum] = (char *)0;
1955 for(i=0; i<argNum; i++)
1956 fsHandler_argv[i] = fsHandler_args[i];
1959 /* exec the threshold handler */
1962 exec_fsThreshHandler = 1;
1963 code = afsmon_Exit(60);
1967 } /* execute_thresh_handler */
1971 /*-----------------------------------------------------------------------
1972 * check_fs_thresholds()
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
1987 *----------------------------------------------------------------------*/
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 */
1994 { /* check_fs_thresholds */
1996 static char rn[] = "check_fs_thresholds";
1997 struct Threshold *threshP;
1998 double tValue; /* threshold value */
1999 double pValue; /* probe value */
2002 int count; /* number of thresholds exceeded */
2005 fprintf(debugFD,"[ %s ] Called, a_hostEntry= %d, a_Data= %d\n",
2006 rn, a_hostEntry, a_Data);
2010 if (a_hostEntry->numThresh == 0) {
2011 /* store in ovf count ?? */
2016 threshP = a_hostEntry->thresh;
2017 for(i=0; i < a_hostEntry->numThresh; i++) {
2018 if (threshP->itemName[0] == '\0') {
2019 threshP++; continue;
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) {
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]);
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! */
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') {
2040 fprintf(debugFD,"[ %s ] Calling ovf handler %s\n",
2041 rn, threshP->handler);
2044 execute_thresh_handler(threshP->handler,
2045 a_Data->hostName, FS, threshP->itemName,
2046 threshP->threshVal, a_Data->data[idx]);
2052 /* in case threshold was previously crossed, blank it out */
2053 a_Data->threshOvf[idx] = 0;
2056 /* store the overflow count */
2057 a_Data->ovfCount = count;
2060 } /* check_fs_thresholds */
2063 /*-----------------------------------------------------------------------
2064 * save_FS_data_forDisplay()
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
2077 * Failure: Exits afsmonitor.
2078 *----------------------------------------------------------------------*/
2081 save_FS_data_forDisplay(a_fsResults)
2082 struct xstat_fs_ProbeResults *a_fsResults;
2083 { /* save_FS_data_forDisplay */
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 */
2101 fprintf(debugFD,"[ %s ] Called, a_fsResults= %d\n",rn, a_fsResults);
2107 /* store results in the display array */
2110 curr_fsDataP = curr_fsData;
2111 for (i=0; i<numFS; i++) {
2112 if((strcasecmp(curr_fsDataP->hostName,a_fsResults->connP->hostName)) == 0) {
2120 fprintf(stderr,"[ %s ] Could not insert FS probe results for host %s in fs display array\n",rn, a_fsResults->connP->hostName);
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. */
2128 if (a_fsResults->probeOK) { /* 1 => notOK the xstat results */
2129 curr_fsDataP->probeOK = 0;
2131 /* print the probe status */
2133 fprintf(debugFD,"\n\t\t ----- fs display data ------\n");
2134 fprintf(debugFD,"HostName = %s PROBE FAILED \n",curr_fsDataP->hostName);
2138 } else { /* probe succeeded, update display data structures */
2139 curr_fsDataP->probeOK = 1;
2141 /* covert longs to strings and place them in curr_fsDataP */
2142 fs_Results_ltoa(curr_fsDataP, a_fsResults);
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 */
2148 /* locate the hostEntry for this host */
2150 curr_host = FSnameList;
2151 for(i=0; i<numFS; i++) {
2152 if(strcasecmp(curr_host->hostName,a_fsResults->connP->hostName) == 0) {
2156 curr_host = curr_host->next;;
2158 if (!done) afsmon_Exit(70);
2160 code = check_fs_thresholds(curr_host, curr_fsDataP);
2162 fprintf(stderr,"[ %s ] Error in checking thresholds\n",rn);
2169 /* print the info we just saved */
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)":"" );
2178 fprintf(debugFD,"\t\t--------------------------------\n\n");
2182 } /* the probe succeeded, so we store the data in the display structure */
2185 /* if we have received a reply from all the hosts for this probe cycle,
2186 it is time to display the data */
2189 if (probes_Received == numFS) {
2190 probes_Received = 0;
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);
2197 afsmon_fs_prev_probeNum++;
2199 /* backup the display data of the probe cycle that just completed -
2200 ie., store curr_fsData in prev_fsData */
2202 bcopy((char *)curr_fsData, (char *)prev_fsData,
2203 (numFS * sizeof(struct fs_Display_Data)) );
2206 /* initialize curr_fsData but retain the threshold flag information.
2207 The previous state of threshold flags is used in check_fs_thresholds()*/
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);
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 */
2223 prev_fsDataP = prev_fsData;
2225 numHosts_onfs_alerts = 0;
2226 for(i=0; i<numFS; i++) {
2227 if (! prev_fsDataP->probeOK ) { /* if probe failed */
2229 numHosts_onfs_alerts++;
2230 } if (prev_fsDataP->ovfCount) { /* overflows ?? */
2231 num_fs_alerts += prev_fsDataP->ovfCount;
2232 numHosts_onfs_alerts++;
2237 fprintf(debugFD,"Number of FS alerts = %d (on %d hosts)\n",
2238 num_fs_alerts, numHosts_onfs_alerts);
2240 /* flag that the data is now ready to be displayed */
2241 fs_Data_Available = 1;
2243 /* call the Overview frame update routine (update only FS info)*/
2244 ovw_refresh(ovw_currPage, OVW_UPDATE_FS);
2246 /* call the File Servers frame update routine */
2247 fs_refresh(fs_currPage, fs_curr_LCol);
2249 } /* display data */
2252 } /* save_FS_data_forDisplay */
2257 /*-----------------------------------------------------------------------
2258 * afsmon_FS_Handler()
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.
2267 * Failure: Exits afsmonitor.
2268 *----------------------------------------------------------------------*/
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 */
2279 fprintf(debugFD,"[ %s ] Called, hostName= %s, probeNum= %d, status=%s\n",
2281 xstat_fs_Results.connP->hostName,
2282 xstat_fs_Results.probeNum,
2283 xstat_fs_Results.probeOK? "FAILED":"OK");
2288 /* print the probe results to output file */
2289 if (afsmon_output) {
2290 code = afsmon_fsOutput(output_filename, afsmon_detOutput);
2292 fprintf(stderr,"[ %s ] output to file %s returned error code=%d\n",
2293 rn,output_filename,code);
2297 /* Update current probe number and circular buffer index. if current
2298 probenum changed make sure it is only by 1 */
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++;
2306 afsmon_fs_curr_CBindex=
2307 (afsmon_fs_curr_probeNum - 1) % num_bufSlots;
2310 fprintf(stderr,"[ %s ] probe number %d-1 missed\n",
2311 rn,xstat_fs_Results.probeNum);
2316 /* store the results of this probe in the FS circular buffer */
2318 save_FS_results_inCB(newProbeCycle);
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 */
2326 save_FS_data_forDisplay(&xstat_fs_Results);
2333 /*----------------------------------------------------------------------- *
2338 * Prints the Cache Manager circular buffer
2339 *----------------------------------------------------------------------*/
2343 { /* Print_CM_CB() */
2345 struct afsmon_cm_Results_list *cmlist;
2349 /* print valid info in the cm CB */
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);
2356 for(i=0; i<num_bufSlots; i++) {
2357 fprintf(debugFD,"\t--------- slot %d ----------\n",i);
2358 cmlist = afsmon_cm_ResultsCB[i].list;
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");
2368 fprintf(debugFD,"\t %d) -- empty --\n",j);
2369 cmlist = cmlist->next;
2372 if (cmlist != (struct afsmon_cm_Results_list *)0 )
2373 fprintf(debugFD,"dangling last next ptr cm CB\n");
2379 /*-----------------------------------------------------------------------
2380 * save_CM_results_inCB()
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.
2393 * Failure: Exits afsmonitor.
2394 *----------------------------------------------------------------------*/
2397 save_CM_results_inCB(a_newProbeCycle)
2398 int a_newProbeCycle; /* start of new probe cycle ? */
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 */
2409 fprintf(debugFD,"[ %s ] Called, a_newProbeCycle= %d\n",a_newProbeCycle);
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() */
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;
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;
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);
2439 tmp_cmPR = tmp_cmlist_item->cmResults;
2441 /* copy hostname and probe number and probe time and probe status.
2442 if the probe failed return now */
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;
2456 /* copy connection information */
2457 #ifdef AFS_LINUX20_ENV
2458 bcopy(&(xstat_cm_Results.connP->skt), &(tmp_cmPR->connP->skt),
2459 sizeof(struct sockaddr_in));
2461 bcopy(xstat_cm_Results.connP->skt, tmp_cmPR->connP->skt,
2462 sizeof(struct sockaddr_in));
2465 /**** NEED TO COPY rx_connection INFORMATION HERE ******/
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;
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));
2478 /* we have a valid results structure so mark the list item used */
2479 tmp_cmlist_item->empty = 0;
2481 /* print the stored info - to make sure we copied it right */
2482 /* Print_cm_FullPerfInfo(tmp_cmPR); */
2483 /* Print the cm circular buffer */
2486 } /* save_CM_results_inCB */
2490 /*-----------------------------------------------------------------------
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().
2504 *----------------------------------------------------------------------*/
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 */
2512 static char rn[] = "cm_Results_ltoa"; /* routine name */
2513 struct afs_stats_CMFullPerf *fullP; /* ptr to complete CM stats */
2521 fprintf(debugFD,"[ %s ] Called, a_cmData= %d, a_cmResults= %d\n",
2522 rn, a_cmData, a_cmResults);
2527 fullP = (struct afs_stats_CMFullPerf *)
2528 (xstat_cm_Results.data.AFSCB_CollData_val);
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
2539 /* copy overall performance statistics */
2540 srcbuf = (afs_int32 *) &(fullP->perf);
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++) {
2546 continue; /* skip ProtServerAddr */
2548 sprintf(a_cmData->data[idx], "%d", *srcbuf);
2553 /*printf("Ending index value = %d\n",idx-1);*/
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);
2565 /*printf("Ending index value = %d\n",idx-1);*/
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);
2576 /*printf("Ending index value = %d\n",idx-1);*/
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*/
2583 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* numSuccesses */
2585 tmpbuf = srcbuf++; /* sum time */
2586 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2588 tmpbuf = srcbuf++; /* sqr time */
2589 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2591 tmpbuf = srcbuf++; /* min time */
2592 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2594 tmpbuf = srcbuf++; /* max time */
2595 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2599 /*printf("Ending index value = %d\n",idx-1);*/
2601 /* copy CMs individual FS RPC errors info */
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 */
2607 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* network */
2609 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* prot */
2611 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* vol */
2613 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* busies */
2615 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* other */
2619 /*printf("Ending index value = %d\n",idx-1);*/
2621 /* copy CMs individual RPC transfers info */
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*/
2627 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* numSuccesses */
2629 tmpbuf = srcbuf++; /* sum time */
2630 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2632 tmpbuf = srcbuf++; /* sqr time */
2633 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2635 tmpbuf = srcbuf++; /* min time */
2636 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2638 tmpbuf = srcbuf++; /* max time */
2639 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2641 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* sum bytes */
2643 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* min bytes */
2645 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* max bytes */
2647 for(j=0; j<AFS_STATS_NUM_XFER_BUCKETS; j++) {
2648 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* bucket[j] */
2653 /*printf("Ending index value = %d\n",idx-1);*/
2655 /* copy CM operations timings */
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*/
2661 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* numSuccesses */
2663 tmpbuf = srcbuf++; /* sum time */
2664 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2666 tmpbuf = srcbuf++; /* sqr time */
2667 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2669 tmpbuf = srcbuf++; /* min time */
2670 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2672 tmpbuf = srcbuf++; /* max time */
2673 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2677 /*printf("Ending index value = %d\n",idx-1);*/
2679 /* copy authentication info */
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);
2688 /*printf("Ending index value = %d\n",idx-1);*/
2690 /* copy CM [un]replicated access info */
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);
2699 /*printf("Ending index value = %d\n",idx-1);*/
2702 } /* cm_Results_ltoa */
2705 /*-----------------------------------------------------------------------
2706 * Function: check_cm_thresholds()
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
2721 *----------------------------------------------------------------------*/
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 */
2728 { /* check_cm_thresholds */
2730 static char rn[] = "check_cm_thresholds";
2731 struct Threshold *threshP;
2732 double tValue; /* threshold value */
2733 double pValue; /* probe value */
2736 int count; /* number of thresholds exceeded */
2739 fprintf(debugFD,"[ %s ] Called, a_hostEntry= %d, a_Data= %d\n",
2740 rn, a_hostEntry, a_Data);
2744 if (a_hostEntry->numThresh == 0) {
2745 /* store in ovf count ?? */
2750 threshP = a_hostEntry->thresh;
2751 for(i=0; i < a_hostEntry->numThresh; i++) {
2752 if (threshP->itemName[0] == '\0') {
2753 threshP++; continue;
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) {
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]);
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! */
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') {
2775 fprintf(debugFD,"[ %s ] Calling ovf handler %s\n",
2776 rn, threshP->handler);
2779 execute_thresh_handler(threshP->handler,
2780 a_Data->hostName, CM, threshP->itemName,
2781 threshP->threshVal, a_Data->data[idx]);
2787 /* in case threshold was previously crossed, blank it out */
2788 a_Data->threshOvf[idx] = 0;
2791 /* store the overflow count */
2792 a_Data->ovfCount = count;
2795 } /* check_cm_thresholds */
2798 /*-----------------------------------------------------------------------
2799 * save_CM_data_forDisplay()
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
2812 * Failure: Exits afsmonitor.
2814 *----------------------------------------------------------------------*/
2817 save_CM_data_forDisplay(a_cmResults)
2818 struct xstat_cm_ProbeResults *a_cmResults;
2819 { /* save_CM_data_forDisplay */
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 */
2836 fprintf(debugFD,"[ %s ] Called, a_cmResults= %d\n",rn, a_cmResults);
2840 /* store results in the display array */
2843 curr_cmDataP = curr_cmData;
2844 for (i=0; i<numCM; i++) {
2845 if((strcasecmp(curr_cmDataP->hostName,a_cmResults->connP->hostName)) == 0) {
2853 fprintf(stderr,"[ %s ] Could not insert CM probe results for host %s in cm display array\n",rn, a_cmResults->connP->hostName);
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. */
2862 if (a_cmResults->probeOK) { /* 1 => notOK the xstat results */
2863 curr_cmDataP->probeOK = 0;
2865 /* print the probe status */
2867 fprintf(debugFD,"\n\t\t ----- cm display data ------\n");
2868 fprintf(debugFD,"HostName = %s PROBE FAILED \n",curr_cmDataP->hostName);
2872 } else { /* probe succeeded, update display data structures */
2873 curr_cmDataP->probeOK = 1;
2876 /* covert longs to strings and place them in curr_cmDataP */
2877 cm_Results_ltoa(curr_cmDataP, a_cmResults);
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 */
2883 /* locate the hostEntry for this host */
2885 curr_host = CMnameList;
2886 for(i=0; i<numCM; i++) {
2887 if (strcasecmp(curr_host->hostName,a_cmResults->connP->hostName) == 0) {
2891 curr_host = curr_host->next;
2893 if (!done) afsmon_Exit(100);
2895 code = check_cm_thresholds(curr_host, curr_cmDataP);
2897 fprintf(stderr,"[ %s ] Error in checking thresholds\n",rn);
2902 /* print the info we just saved */
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++) {
2908 case 0: fprintf(debugFD,"\t -- Overall Perf Info --\n");
2910 case 39: fprintf(debugFD,"\t -- File Server up/down stats - same cell --\n");
2912 case 64: fprintf(debugFD,"\t -- File Server up/down stats - diff cell --\n");
2914 case 89: fprintf(debugFD,"\t -- VL server up/down stats - same cell --\n");
2916 case 114: fprintf(debugFD,"\t -- VL server up/down stats - diff cell --\n");
2918 case 139: fprintf(debugFD,"\t -- FS Operation Timings --\n");
2920 case 279: fprintf(debugFD,"\t -- FS Error Info --\n");
2922 case 447: fprintf(debugFD,"\t -- FS Transfer Timings --\n");
2924 case 475: fprintf(debugFD,"\t -- CM Operations Timings --\n");
2926 case 510: fprintf(debugFD,"\t -- Authentication Info --\n");
2928 case 522: fprintf(debugFD,"\t -- Access Info --\n");
2933 fprintf(debugFD,"%20s %30s %s\n", curr_cmDataP->data[i],
2934 cm_varNames[i],curr_cmDataP->threshOvf[i] ? "(ovf)":"" );
2936 fprintf(debugFD,"\t\t--------------------------------\n\n");
2939 } /* if the probe succeeded, update the display data structures */
2941 /* if we have received a reply from all the hosts for this probe cycle,
2942 it is time to display the data */
2945 if (probes_Received == numCM) {
2946 probes_Received = 0;
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);
2953 afsmon_cm_prev_probeNum++;
2956 /* backup the display data of the probe cycle that just completed -
2957 ie., store curr_cmData in prev_cmData */
2959 bcopy((char *)curr_cmData, (char *)prev_cmData,
2960 (numCM * sizeof(struct cm_Display_Data)) );
2963 /* initialize curr_cmData but retain the threshold flag information.
2964 The previous state of threshold flags is used in check_cm_thresholds()*/
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);
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 */
2979 prev_cmDataP = prev_cmData;
2981 numHosts_oncm_alerts = 0;
2982 for(i=0; i<numCM; i++) {
2983 if (! prev_cmDataP->probeOK) { /* if probe failed */
2985 numHosts_oncm_alerts++;
2986 } else if (prev_cmDataP->ovfCount) { /* overflows ?? */
2987 num_cm_alerts += prev_cmDataP->ovfCount;
2988 numHosts_oncm_alerts++;
2993 fprintf(debugFD,"Number of CM alerts = %d (on %d hosts)\n",
2994 num_cm_alerts, numHosts_oncm_alerts);
2997 /* flag that the data is now ready to be displayed */
2998 cm_Data_Available = 1;
3000 /* update the Overview frame (only CM info)*/
3001 ovw_refresh(ovw_currPage, OVW_UPDATE_CM);
3003 /* update the Cache Managers frame */
3004 cm_refresh(cm_currPage, cm_curr_LCol);
3010 } /* save_CM_data_forDisplay */
3014 /*-----------------------------------------------------------------------
3015 * afsmon_CM_Handler()
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.
3024 * Failure: Exits afsmonitor.
3025 *----------------------------------------------------------------------*/
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 ? */
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");
3045 /* print the probe results to output file */
3046 if (afsmon_output) {
3047 code = afsmon_cmOutput(output_filename, afsmon_detOutput);
3049 fprintf(stderr,"[ %s ] output to file %s returned error code=%d\n",
3050 rn,output_filename,code);
3054 /* Update current probe number and circular buffer index. if current
3055 probenum changed make sure it is only by 1 */
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++;
3063 afsmon_cm_curr_CBindex=
3064 (afsmon_cm_curr_probeNum - 1) % num_bufSlots;
3067 fprintf(stderr,"[ %s ] probe number %d-1 missed\n",
3068 rn,xstat_cm_Results.probeNum);
3073 /* save the results of this probe in the CM buffer */
3075 save_CM_results_inCB(newProbeCycle);
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 */
3082 save_CM_data_forDisplay(&xstat_cm_Results);
3087 /*-----------------------------------------------------------------------
3091 * Allocate and Initialize circular buffers for file servers.
3095 * Failure to allocate memory: exits afsmonitor.
3096 *----------------------------------------------------------------------*/
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 */
3111 fprintf(debugFD,"[ %s ] Called\n",rn);
3115 /* allocate memory for the circular buffer of pointers */
3117 afsmon_fs_ResultsCB = (struct afsmon_fs_Results_CBuffer *) malloc(
3118 sizeof(struct afsmon_fs_Results_CBuffer) * num_bufSlots);
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;
3126 /* create a list of numFS items to store fs probe results for
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 */
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 */
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)
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);
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);
3159 /* >>> need to allocate rx connection info structure here <<< */
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);
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;
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;
3179 tmp_fslist_item = afsmon_fs_ResultsCB[ bufslot ].list;
3181 while(tmp_fslist_item != (struct afsmon_fs_Results_list *)0)
3183 if (tmp_fslist_item->next == (struct afsmon_fs_Results_list *)0)
3185 tmp_fslist_item = tmp_fslist_item->next;
3188 /* something goofed. exit */
3189 fprintf(stderr,"[ %s ] list creation error\n",rn);
3193 tmp_fslist_item->next = new_fslist_item;
3196 } /* while servers */
3197 } /* for each buffer slot */
3198 } /* if we have file servers to monitor */
3202 /*-----------------------------------------------------------------------
3206 * Allocate and Initialize circular buffers for cache managers.
3210 * Failure to allocate memory: exits afsmonitor.
3211 *----------------------------------------------------------------------*/
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 */
3225 fprintf(debugFD,"[ %s ] Called\n",rn);
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);
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;
3239 /* create a list of numCM items to store fs probe results for
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 */
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 */
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)
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);
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);
3272 /* >>> need to allocate rx connection info structure here <<< */
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);
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;
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;
3292 tmp_cmlist_item = afsmon_cm_ResultsCB[ bufslot ].list;
3294 while(tmp_cmlist_item != (struct afsmon_cm_Results_list *)0)
3296 if (tmp_cmlist_item->next == (struct afsmon_cm_Results_list *)0)
3298 tmp_cmlist_item = tmp_cmlist_item->next;
3301 /* something goofed. exit */
3302 fprintf(stderr,"[ %s ] list creation error\n",rn);
3306 tmp_cmlist_item->next = new_cmlist_item;
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 */
3316 } /* init_cm_buffers() */
3319 /*-------------------------------------------------------------------------
3320 * init_print_buffers()
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.
3330 *------------------------------------------------------------------------*/
3333 init_print_buffers()
3334 { /* init_print_buffers */
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;
3347 fprintf(debugFD,"[ %s ] Called\n",rn);
3351 /* allocate numFS blocks of the FS print structure. */
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 */
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);
3366 bzero(curr_fsData,numBytes);
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);
3374 bzero(prev_fsData,numBytes);
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);
3385 tmp_fsNames = tmp_fsNames->next;;
3388 } /* if file servers to monitor */
3390 /* allocate numCM blocks of the CM print structure */
3391 /* we need two instances of this structure for the same reasons as above*/
3394 numBytes = numCM * sizeof(struct cm_Display_Data);
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);
3401 bzero(curr_cmData,numBytes);
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);
3409 bzero(prev_cmData,numBytes);
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);
3420 tmp_cmNames = tmp_cmNames->next;;
3423 } /* if cache managers to monitor */
3427 } /* init_print_buffers */
3429 /*-----------------------------------------------------------------------
3433 * Trap the interrupt signal. This function is useful only until
3434 * gtx is initialized.
3435 *----------------------------------------------------------------------*/
3441 static char *rn = "quit_signal"; /* routine name */
3443 fprintf(stderr,"Received signal %d \n",sig);
3449 /*-----------------------------------------------------------------------
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.
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.
3463 *----------------------------------------------------------------------*/
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; /* num bytes in above */
3474 struct sockaddr_in *curr_skt; /* ptr to current socket*/
3475 struct afsmon_hostEntry *curr_FS; /* ptr to FS name list */
3476 struct afsmon_hostEntry *curr_CM; /* ptr to CM name list */
3477 struct hostent *he; /* host entry */
3478 afs_int32 *collIDP; /* ptr to collection ID */
3479 int numCollIDs; /* number of collection IDs */
3480 int FSinitFlags = 0; /* flags for xstat_fs_Init */
3481 int CMinitFlags = 0; /* flags for xstat_cm_Init */
3482 int code; /* function return code */
3483 struct timeval tv; /* time structure */
3487 fprintf(debugFD,"[ %s ] Called\n",rn);
3492 /* process file server entries */
3494 /* Allocate an array of sockets for each fileserver we monitor */
3496 FSsktbytes = numFS * sizeof(struct sockaddr_in);
3497 FSSktArray = (struct sockaddr_in *) malloc(FSsktbytes);
3498 if (FSSktArray == (struct sockaddr_in *)0) {
3499 fprintf(stderr,"[ %s ] cannot malloc %d sockaddr_ins for fileservers\n",
3504 bzero(FSSktArray, FSsktbytes);
3506 /* Fill in the socket information for each fileserve */
3508 curr_skt = FSSktArray;
3509 curr_FS = FSnameList; /* FS name list header */
3511 strncpy(fullhostname,curr_FS->hostName,sizeof(fullhostname));
3512 he = GetHostByName(fullhostname);
3513 if (he == (struct hostent *)0) {
3514 fprintf(stderr,"[ %s ] Cannot get host info for %s\n",fullhostname);
3517 strncpy(curr_FS->hostName,he->h_name,HOST_NAME_LEN); /* complete name*/
3518 bcopy(he->h_addr, &(curr_skt->sin_addr.s_addr), 4);
3519 curr_skt->sin_family = htons(AF_INET); /*Internet family*/
3520 curr_skt->sin_port = htons(7000); /*FileServer port*/
3522 /* get the next dude */
3524 curr_FS = curr_FS->next;
3527 /* initialize collection IDs. We need only one entry since we collect
3528 all the information from xstat */
3531 collIDP = (afs_int32 *) malloc (sizeof (afs_int32));
3532 if (collIDP == (afs_int32 *)0) {
3533 fprintf(stderr,"[ %s ] failed to allocate a measely afs_int32 word.Argh!\n");
3536 *collIDP = 2; /* USE A macro for this */
3539 if (afsmon_onceOnly) /* option not provided at this time */
3540 FSinitFlags |= XSTAT_FS_INITFLAG_ONE_SHOT;
3543 fprintf(debugFD,"[ %s ] Calling xstat_fs_Init \n",rn);
3547 code = xstat_fs_Init(numFS, /*Num servers*/
3548 FSSktArray, /*File Server socket array*/
3549 afsmon_probefreq, /*probe frequency*/
3550 afsmon_FS_Handler, /*Handler routine*/
3551 FSinitFlags, /*Initialization flags*/
3552 numCollIDs, /*Number of collection IDs*/
3553 collIDP); /*Ptr to collection ID */
3556 fprintf(stderr,"[ %s ] xstat_fs_init returned error\n",rn);
3560 } /* end of process fileserver entries */
3562 /* process cache manager entries */
3565 /* Allocate an array of sockets for each cache manager we monitor */
3567 CMsktbytes = numCM * sizeof(struct sockaddr_in);
3568 CMSktArray = (struct sockaddr_in *) malloc(CMsktbytes);
3569 if (CMSktArray == (struct sockaddr_in *)0) {
3570 fprintf(stderr,"[ %s ] cannot malloc %d sockaddr_ins for CM entries\n",
3575 bzero(CMSktArray, CMsktbytes);
3577 /* Fill in the socket information for each CM */
3579 curr_skt = CMSktArray;
3580 curr_CM = CMnameList; /* CM name list header */
3582 strncpy(fullhostname,curr_CM->hostName,sizeof(fullhostname));
3583 he = GetHostByName(fullhostname);
3584 if (he == (struct hostent *)0) {
3585 fprintf(stderr,"[ %s ] Cannot get host info for %s\n",fullhostname);
3588 strncpy(curr_CM->hostName,he->h_name,HOST_NAME_LEN); /* complete name*/
3589 bcopy(he->h_addr, &(curr_skt->sin_addr.s_addr), 4);
3590 curr_skt->sin_family = htons(AF_INET); /*Internet family*/
3591 curr_skt->sin_port = htons(7001); /*Cache Manager port*/
3593 /* get the next dude */
3595 curr_CM = curr_CM->next;
3598 /* initialize collection IDs. We need only one entry since we collect
3599 all the information from xstat */
3602 collIDP = (afs_int32 *) malloc (sizeof (afs_int32));
3603 if (collIDP == (afs_int32 *)0) {
3604 fprintf(stderr,"[ %s ] failed to allocate a measely long word.Argh!\n");
3607 *collIDP = 2; /* USE A macro for this */
3610 if (afsmon_onceOnly) /* once only ? */
3611 CMinitFlags |= XSTAT_CM_INITFLAG_ONE_SHOT;
3614 fprintf(debugFD,"[ %s ] Calling xstat_cm_Init \n",rn);
3618 code = xstat_cm_Init(numCM, /*Num servers*/
3619 CMSktArray, /*Cache Manager socket array*/
3620 afsmon_probefreq, /*probe frequency*/
3621 afsmon_CM_Handler, /*Handler routine*/
3622 CMinitFlags, /*Initialization flags*/
3623 numCollIDs, /*Number of collection IDs*/
3624 collIDP); /*Ptr to collection ID */
3627 fprintf(stderr,"[ %s ] xstat_cm_init returned error\n",rn);
3630 } /* end of process cache manager entries */
3633 /* if only one probe was required setup a waiting process for the
3634 termination signal */
3636 if (afsmon_onceOnly) {
3637 code = LWP_WaitProcess(&terminationEvent);
3640 fprintf(debugFD,"LWP_WaitProcess() returned error %d\n",code);
3647 /* start the gtx input server */
3648 code = gtx_InputServer(afsmon_win);
3650 fprintf(stderr,"[ %s ] Failed to start input server \n",rn);
3654 /* This part of the code is reached only if the input server is not started
3655 for debugging purposes */
3660 fprintf(stderr,"[ %s ] going to sleep ...\n",rn);
3662 code = IOMGR_Select( 0, /*Num fds*/
3663 0, /*Descriptors ready for reading*/
3664 0, /*Descriptors ready for writing*/
3665 0, /*Descriptors with exceptional conditions*/
3666 &tv); /*Timeout structure*/
3668 fprintf(stderr,"[ %s ] IOMGR_Select() returned non-zero value %d\n",
3676 /*-----------------------------------------------------------------------
3680 * Afsmonitor initialization routine.
3681 * - processes command line parameters
3682 * - call functions to:
3683 * - process config file
3684 * - initialize circular buffers and display buffers
3686 * - execute afsmonitor
3687 * - initialize the display maps [fs/cm]_Display_map[].
3690 * Success: Does not return from the call to afsmon_execute().
3691 * Failure: Exits afsmonitor.
3692 *----------------------------------------------------------------------*/
3696 struct cmd_syndesc *as;
3697 { /* afsmonInit() */
3699 static char rn[] = "afsmonInit"; /* Routine name */
3700 char *debug_filename; /* pointer to debug filename */
3701 char *config_filename; /* pointer to config filename */
3702 FILE *outputFD; /* output file descriptor */
3703 struct cmd_item *hostPtr; /* ptr to parse command line args */
3704 char buf[256]; /* buffer for processing hostnames */
3709 fprintf(debugFD,"[ %s ] Called, as= %d\n",rn, as);
3713 /* Open the debug file if -debug option is specified */
3714 if (as->parms[P_DEBUG].items != 0) {
3716 debug_filename = as->parms[P_DEBUG].items->data;
3717 debugFD = fopen(debug_filename, "w");
3718 if (debugFD == (FILE *)0) {
3719 printf("[ %s ] Failed to open debugging file %s for writing\n",
3727 fprintf(debugFD,"[ %s ] Called\n", rn);
3731 /* use curses always until we support other packages */
3733 wpkg_to_use = atoi(as->parms[P_PACKAGE].items->data);
3735 switch (wpkg_to_use) {
3736 case GATOR_WIN_CURSES:
3737 fprintf(stderr, "curses\n");
3739 case GATOR_WIN_DUMB:
3740 fprintf(stderr, "dumb terminal\n");
3743 fprintf(stderr, "X11\n");
3746 fprintf(stderr, "Illegal graphics package: %d\n", wpkg_to_use);
3748 } /*end switch (wpkg_to_use)*/
3751 wpkg_to_use = GATOR_WIN_CURSES;
3753 /* get probe frequency . We check for meaningful bounds on the frequency
3754 and reset to the default value if needed. The upper bound of 24
3755 hours looks ridiculous though! */
3757 afsmon_probefreq = 0;
3758 if (as->parms[P_FREQUENCY].items != 0)
3759 afsmon_probefreq = atoi(as->parms[P_FREQUENCY].items->data);
3761 afsmon_probefreq = DEFAULT_FREQUENCY;
3763 if (afsmon_probefreq <= 0 || afsmon_probefreq > 24*60*60) {
3764 afsmon_probefreq = DEFAULT_FREQUENCY;
3766 fprintf(debugFD,"[ %s ] Invalid probe frequency %s specified, resetting to default value %d seconds\n",
3767 rn, as->parms[P_FREQUENCY].items->data, afsmon_probefreq);
3770 fprintf(stderr,"Invalid probe frequency %s specified, resetting to default value %d seconds\n",
3771 as->parms[P_FREQUENCY].items->data, afsmon_probefreq);
3776 /* make sure output file is writable, else complain now */
3777 /* we will open and close it as needed after probes */
3779 if (as->parms[P_OUTPUT].items != 0) {
3780 afsmon_output = 1; /* output flag */
3781 strncpy (output_filename, as->parms[P_OUTPUT].items->data,80);
3782 outputFD = fopen(output_filename,"a");
3783 if (outputFD == (FILE *)0) {
3784 fprintf(stderr,"Failed to open output file %s \n",
3787 fprintf(debugFD,"[ %s ] Failed to open output file %s \n",
3788 rn, output_filename);
3793 fprintf(debugFD,"[ %s ] output file is %s\n",rn,output_filename);
3798 /* detailed statistics to storage file */
3799 if (as->parms[P_DETAILED].items !=0) {
3800 if (as->parms[P_OUTPUT].items == 0) {
3801 fprintf(stderr,"-detailed switch can be used only with -output\n");
3804 afsmon_detOutput = 1;
3807 /* Initialize host list headers */
3808 FSnameList = (struct afsmon_hostEntry *)0;
3809 CMnameList = (struct afsmon_hostEntry *)0;
3811 /* The -config option is mutually exclusive with the -fshosts,-cmhosts
3814 if (as->parms[P_CONFIG].items) {
3815 if (as->parms[P_FSHOSTS].items || as->parms[P_CMHOSTS].items) {
3816 fprintf(stderr,"Cannot use -config option with -fshosts or -cmhosts\n");
3820 if (! as->parms[P_FSHOSTS].items && ! as->parms[P_CMHOSTS].items) {
3821 fprintf(stderr,"Must specify either -config or (-fshosts and/or -cmhosts) options \n");
3827 /* If a file server host is specified on the command line we reuse
3828 parse_hostEntry() function . Just the pass the info as if it were
3829 read off the config file */
3831 if (as->parms[P_FSHOSTS].items) {
3832 hostPtr = as->parms[P_FSHOSTS].items;
3833 while( hostPtr != (struct cmd_item *)0) {
3834 sprintf(buf,"fs %s",hostPtr->data);
3835 code = parse_hostEntry(buf);
3837 fprintf(stderr,"Could not parse %s\n",hostPtr->data);
3841 hostPtr = hostPtr->next;
3845 /* same as above for -cmhosts */
3846 if (as->parms[P_CMHOSTS].items) {
3847 hostPtr = as->parms[P_CMHOSTS].items;
3848 while( hostPtr != (struct cmd_item *)0) {
3849 sprintf(buf,"cm %s",hostPtr->data);
3850 code = parse_hostEntry(buf);
3852 fprintf(stderr,"Could not parse %s\n",hostPtr->data);
3856 hostPtr = hostPtr->next;
3860 /* number of slots in circular buffers */
3861 if (as->parms[P_BUFFERS].items)
3862 num_bufSlots = atoi(as->parms[P_BUFFERS].items->data);
3864 num_bufSlots = DEFAULT_BUFSLOTS;
3866 /* Initialize xx_showFlags[]. This array is used solely for processing the
3867 "show" directives in the config file in parse_showEntries() */
3868 for(i=0; i<NUM_FS_STAT_ENTRIES; i++)
3869 fs_showFlags[i] = 0;
3870 for(i=0; i<NUM_CM_STAT_ENTRIES; i++)
3871 cm_showFlags[i] = 0;
3874 /* Process the configuration file if given. This initializes among other
3875 things, the list of FS & CM names in FSnameList and CMnameList */
3877 if (as->parms[P_CONFIG].items)
3878 process_config_file(as->parms[P_CONFIG].items->data);
3880 /* print out the FS and CM lists */
3881 print_FS(); print_CM();
3883 /* Initialize the FS results-to-screen map array if there were no "show fs"
3884 directives in the config file */
3885 if (fs_showDefault) {
3886 for(i=0; i < NUM_FS_STAT_ENTRIES; i++)
3887 fs_Display_map[i] = i;
3888 fs_DisplayItems_count = NUM_FS_STAT_ENTRIES;
3891 /* Initialize the CM results-to-screen map array if there were no "show cm"
3892 directives in the config file */
3893 if (cm_showDefault) {
3894 for(i=0; i < NUM_CM_STAT_ENTRIES; i++)
3895 cm_Display_map[i] = i;
3896 cm_DisplayItems_count = NUM_CM_STAT_ENTRIES;
3901 /* setup an interrupt signal handler; we ain't wanna leak core */
3902 /* this binding is useful only until gtx is initialized after which the
3903 keyboard input server takes over. */
3904 if ( (signal(SIGINT,quit_signal)) == SIG_ERR ) {
3905 perror("signal() failed.");
3910 /* init error message buffers. these will be used to print error messages
3911 once gtx is initialized and there is no access to stderr/stdout */
3912 errMsg[0] = '\0'; errMsg1[0] = '\0';
3916 /* initialize fs and cm circular buffers before initiating probes */
3918 code = init_fs_buffers();
3920 fprintf(stderr,"[ %s ] init_fs_buffers returned %d\n",rn,code);
3926 code = init_cm_buffers();
3928 fprintf(stderr,"[ %s ] init_cm_buffers returned %d\n",rn,code);
3934 /* allocate and initialize buffers for holding fs & cm results in ascii
3935 format suitable for updating the screen */
3936 code = init_print_buffers();
3938 fprintf(stderr,"[ %s ] init_print_buffers returned %d\n",rn,code);
3942 /* perform gtx initializations */
3943 code = gtx_initialize();
3945 fprintf(stderr,"[ %s ] gtx_initialize returned %d\n",rn,code);
3949 /* start xstat probes */
3952 return(0); /* will not return from the call to afsmon_execute() */
3954 } /* afsmonInit() */
3957 /*-----------------------------------------------------------------------
3959 ------------------------------------------------------------------------*/
3961 #include "AFS_component_version_number.c"
3968 static char rn[] = "main"; /* routine name */
3969 afs_int32 code; /*Return code*/
3970 struct cmd_syndesc *ts; /*Ptr to cmd line syntax descriptor*/
3972 #ifdef AFS_AIX32_ENV
3974 * The following signal action for AIX is necessary so that in case of a
3975 * crash (i.e. core is generated) we can include the user's data section
3976 * in the core dump. Unfortunately, by default, only a partial core is
3977 * generated which, in many cases, isn't too useful.
3979 struct sigaction nsa;
3981 sigemptyset(&nsa.sa_mask);
3982 nsa.sa_handler = SIG_DFL;
3983 nsa.sa_flags = SA_FULLDUMP;
3984 sigaction(SIGSEGV, &nsa, NULL);
3988 * Set up the commands we understand.
3990 ts = cmd_CreateSyntax("initcmd", afsmonInit, 0,
3991 "initialize the program");
3992 cmd_AddParm(ts, "-config", CMD_SINGLE, CMD_OPTIONAL,
3993 "configuration file");
3994 cmd_AddParm(ts, "-frequency", CMD_SINGLE, CMD_OPTIONAL,
3995 "poll frequency, in seconds");
3996 cmd_AddParm(ts, "-output", CMD_SINGLE, CMD_OPTIONAL,
3997 "storage file name");
3998 cmd_AddParm(ts, "-detailed", CMD_FLAG, CMD_OPTIONAL,
3999 "output detailed statistics to storage file");
4001 /* we hope to use this .... eventually! */
4002 cmd_AddParm(ts,"-package", CMD_SINGLE, CMD_REQUIRED,
4003 "Graphics Package to use");
4005 cmd_AddParm(ts, "-debug", CMD_SINGLE, CMD_OPTIONAL,
4006 "turn debugging output on to the named file");
4007 cmd_AddParm(ts, "-fshosts", CMD_LIST, CMD_OPTIONAL,
4008 "list of file servers to monitor");
4009 cmd_AddParm(ts, "-cmhosts", CMD_LIST, CMD_OPTIONAL,
4010 "list of cache managers to monitor");
4011 cmd_AddParm(ts,"-buffers", CMD_SINGLE, CMD_OPTIONAL,
4012 "number of buffer slots");
4015 * Parse command-line switches & execute afsmonitor
4018 code = cmd_Dispatch(argc, argv);