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 *-------------------------------------------------------------------------*/
16 #include <afsconfig.h>
17 #include <afs/param.h>
28 #include <sys/types.h>
29 #include <netinet/in.h>
31 #include <sys/socket.h>
36 #include <gtxwindows.h> /*Generic window package*/
37 #include <gtxobjects.h> /*Object definitions*/
39 #include <gtxtextobj.h> /*Text object interface*/
41 #include <gtxlightobj.h> /*Light object interface*/
42 #include <gtxcurseswin.h> /*Curses window package*/
43 #include <gtxdumbwin.h> /*Dumb terminal window package*/
44 #include <gtxX11win.h> /*X11 window package*/
45 #include <gtxframe.h> /*Frame package*/
49 #include <afs/xstat_fs.h>
50 #include <afs/xstat_cm.h>
53 #include "afsmonitor.h"
56 /* command line parameter indices */
62 /* #define P_PACKAGE X */
69 int afsmon_debug = 0; /* debug info to file ? */
70 FILE *debugFD; /* debugging file descriptor */
71 static int afsmon_output = 0; /* output to file ? */
72 static int afsmon_detOutput = 0; /* detailed output ? */
73 static int afsmon_onceOnly = 0; /* probe once only ? (not implemented) */
74 int afsmon_probefreq; /* probe frequency */
75 static int wpkg_to_use; /* graphics package to use */
76 static char output_filename[80];/* output filename */
77 char errMsg[256]; /* buffers used to print error messages after*/
78 char errMsg1[256]; /* gtx is initialized (stderr/stdout gone !) */
79 int num_bufSlots = 0; /* number of slots in fs & cm circular buffers*/
81 /* Flags used to process "show" directives in config file */
82 short fs_showFlags[NUM_FS_STAT_ENTRIES];
83 short cm_showFlags[NUM_CM_STAT_ENTRIES];
86 /* afsmonitor misc definitions */
88 #define DEFAULT_FREQUENCY 60 /* default proble frequency in seconds */
89 #define DEFAULT_BUFSLOTS 0 /* default number of buffer slots */
90 #define CFG_STR_LEN 80 /* max length of config file fields */
91 #define FS 1 /* for misc. use */
92 #define CM 2 /* for misc. use */
95 #define NUM_XSTAT_FS_AFS_PERFSTATS_LONGS 66 /* number of fields (longs) in struct afs_PerfStats that we display */
96 #define NUM_AFS_STATS_CMPERF_LONGS 40 /* number of longs in struct afs_stats_CMPerf excluding up/down stats and fields we dont display */
99 /* variables used for exec'ing user provided threshold handlers */
100 char *fsHandler_argv[20]; /* *argv[] for the handler */
101 char fsHandler_args[20][256]; /* buffer space for arguments */
102 int exec_fsThreshHandler = 0; /* execute fs threshold handler ? */
105 /* THRESHOLD STRUCTURE DEFINITIONS */
107 /* flag to indicate that threshold entries apply to all hosts. these will
108 be turned off when the first fs or cm host entry is processed */
109 static int global_ThreshFlag = 1;
110 static int global_fsThreshCount = 0; /* number of global fs thresholds */
111 static int global_cmThreshCount = 0; /* number of global cm thresholds */
115 /* Linked lists of file server and cache manager host names are made from
116 the entries in the config file. Head pointers to FS and CM server name lists. */
117 static struct afsmon_hostEntry *FSnameList;
118 static struct afsmon_hostEntry *CMnameList;
120 /* number of fileservers and cache managers to monitor */
124 /* variables used for processing config file */
125 /* ptr to the hostEntry structure of the last "fs" or "cm" entry processed
126 in the config file */
127 static struct afsmon_hostEntry *last_hostEntry;
128 /* names of the last host processed in the config file */
129 static char last_fsHost[HOST_NAME_LEN];
130 static char last_cmHost[HOST_NAME_LEN];
131 static lastHostType = 0; /* 0 = no host entries processed
132 1 = last host was file server
133 2 = last host was cache manager. */
136 /* FILE SERVER CIRCULAR BUFFER VARIABLES */
138 struct afsmon_fs_Results_list {
139 struct xstat_fs_ProbeResults *fsResults; /* ptr to results struct*/
140 int empty; /* fsResults empty ? */
141 struct afsmon_fs_Results_list *next;
144 struct afsmon_fs_Results_CBuffer {
145 int probeNum; /* probe number of entries in this slot */
146 struct afsmon_fs_Results_list *list; /* ptr to list of results */
149 /* buffer for FS probe results */
150 struct afsmon_fs_Results_CBuffer *afsmon_fs_ResultsCB;
152 int afsmon_fs_curr_CBindex = 0; /* current fs CB slot */
154 /* Probe number variables. The current probe number is incremented
155 when the first probe from a new probe cycle is received. The prev probe
156 number is incremented when the last probe of the current cycle is
157 received. This difference is because of the purpose for which these
160 int afsmon_fs_curr_probeNum = 1; /* current fs probe number */
161 int afsmon_fs_prev_probeNum = 0; /* previous fs probe number */
164 /* CACHE MANAGER CIRCULAR BUFFER VARIABLES */
166 struct afsmon_cm_Results_list {
167 struct xstat_cm_ProbeResults *cmResults; /* ptr to results struct*/
168 int empty; /* cmResults empty ? */
169 struct afsmon_cm_Results_list *next;
172 struct afsmon_cm_Results_CBuffer {
173 int probeNum; /* probe number of entries in this slot */
174 struct afsmon_cm_Results_list *list; /* ptr to list of results */
177 /* buffer for CM probe results */
178 struct afsmon_cm_Results_CBuffer *afsmon_cm_ResultsCB;
180 int afsmon_cm_curr_CBindex = 0; /* current cm CB slot */
183 /* Probe number variables. The current probe number is incremented
184 when the first probe from a new probe cycle is received. The prev probe
185 number is incremented when the last probe of the current cycle is
186 received. This difference is because of the purpose for which these
189 int afsmon_cm_curr_probeNum = 1; /* current cm probe number */
190 int afsmon_cm_prev_probeNum = 0; /* previous cm probe number */
193 /* Structures to hold FS & CM results in string format(suitable for display ) */
195 /* ptr to array holding the results of FS probes in ascii format */
196 /* for current probe cycle */
197 struct fs_Display_Data *curr_fsData = (struct fs_Display_Data *)0;
198 /* for previous probe cycle */
199 struct fs_Display_Data *prev_fsData = (struct fs_Display_Data *)0;
202 /* ptr to array holding the results of CM probes in ascii format */
203 /* for current probe cycle */
204 struct cm_Display_Data *curr_cmData = (struct cm_Display_Data *)0;
205 /* for previous probe cycle */
206 struct cm_Display_Data *prev_cmData = (struct cm_Display_Data *)0;
209 /* EXTERN DEFINITIONS */
211 extern struct hostent *hostutil_GetHostByName();
215 /* routines from afsmon-output.c */
216 extern int afsmon_fsOutput();
217 extern int afsmon_cmOutput();
219 /* file server and cache manager variable names (from afsmon_labels.h) */
220 extern char *fs_varNames[];
221 extern char *cm_varNames[];
223 /* GTX & MISC VARIABLES */
225 /* afsmonitor window */
226 extern struct gwin *afsmon_win;
228 /* current page number in the overview frame */
229 extern int ovw_currPage;
231 /* number of FS alerts and number of hosts on FS alerts */
233 int numHosts_onfs_alerts;
235 /* number of CM alerts and number of hosts on FS alerts */
237 int numHosts_oncm_alerts;
239 /* flag to indicate that atleast one probe cycle has completed and
240 data is available for updating the display */
241 extern fs_Data_Available;
242 extern cm_Data_Available;
244 extern int gtx_initialized; /* gtx initialized ? */
246 /* This array contains the indices of the file server data items that
247 are to be displayed on the File Servers screen. For example, suppose the
248 user wishes to display only the vcache statistics then the following array
249 will contain indices 2 to 14 corresponding to the position of the
250 vcache data items in the fs_varNames[] array. If the config file contains
251 no "show fs .." directives, it will contain the indices of all the
252 items in the fs_varNames[] array */
254 short fs_Display_map[XSTAT_FS_FULLPERF_RESULTS_LEN];
255 int fs_DisplayItems_count = 0; /* number of items to display */
256 int fs_showDefault = 1; /* show all of FS data ? */
259 /* same use as above for Cache Managers */
260 short cm_Display_map[XSTAT_CM_FULLPERF_RESULTS_LEN];
261 int cm_DisplayItems_count = 0; /* number of items to display */
262 int cm_showDefault = 1; /* show all of CM data ? */
264 extern int fs_currPage; /* current page number in the File Servers frame */
265 extern int fs_curr_LCol; /* current leftmost column on display on FS frame */
267 extern int cm_currPage; /* current page number in the Cache Managers frame */
268 extern int cm_curr_LCol; /* current leftmost column on display on CM frame */
270 /* File server and Cache manager data is classified into sections &
271 groups to help the user choose what he wants displayed */
272 extern char *fs_categories[]; /* file server data category names */
273 extern char *cm_categories[]; /* cache manager data category names */
278 strcasestr(): Return first occurence of pattern s2 in s1, case
281 This routine is required since I made pattern matching of the
282 config file to be case insensitive.
285 char *strcasestr(s1,s2)
296 return ((char *)NULL);
300 while( len1 >= len2 && len1 > 0 ) {
301 if ( (strncasecmp(ptr,s2,len2)) == 0)
306 return ((char *)NULL);
310 struct hostent *GetHostByName(name)
318 he = gethostbyname(name);
320 /* On solaris the above does not resolve hostnames to full names */
321 if (he != (struct hostent *)0) {
322 memcpy(ip_addr, he->h_addr, he->h_length);
323 he = gethostbyaddr(ip_addr, he->h_length, he->h_addrtype);
330 /*-----------------------------------------------------------------------
334 * Exit gracefully from the afsmonitor. Frees memory where appropriate,
335 * cleans up after gtx and closes all open file descriptors. If a user
336 * provided threshold handler is to be exec'ed then gtx cleanup is
337 * not performed and an exec() is made instead of an exit().
343 * This function is called to execute a user handler only
344 * by a child process.
346 *----------------------------------------------------------------------*/
349 afsmon_Exit(a_exitVal)
350 int a_exitVal; /* exit code */
352 static char rn[] = "afsmon_Exit";
353 struct afsmon_fs_Results_list *tmp_fslist;
354 struct afsmon_fs_Results_list *next_fslist;
355 struct xstat_fs_ProbeResults *tmp_xstat_fsPR;
356 struct afsmon_cm_Results_list *tmp_cmlist;
357 struct afsmon_cm_Results_list *next_cmlist;
358 struct xstat_cm_ProbeResults *tmp_xstat_cmPR;
359 struct afsmon_hostEntry *curr_hostEntry;
360 struct afsmon_hostEntry *prev_hostEntry;
367 fprintf(debugFD,"[ %s ] Called with exit code %d\n",rn, a_exitVal);
371 /* get out of curses first, but not if we are here to exec a threshold
372 handler. If we do, the screen gets messed up */
373 if (gtx_initialized && ! exec_fsThreshHandler)
374 gator_cursesgwin_cleanup(afsmon_win);
376 /* print the error message buffer */
377 if (errMsg[0] != '\0')
378 fprintf(stderr,"%s",errMsg);
379 if (errMsg1[0] != '\0')
380 fprintf(stderr,"%s",errMsg1);
382 /* deallocate file server circular buffers */
383 if (numFS && num_bufSlots) {
385 fprintf(debugFD,"freeing FS circular buffers ");
389 for (bufslot=0; bufslot<num_bufSlots; bufslot++) {
391 fprintf(debugFD," %d) ",bufslot);
392 if (afsmon_fs_ResultsCB[bufslot].list !=
393 (struct afsmon_fs_Results_list *)0 ) {
394 tmp_fslist = afsmon_fs_ResultsCB[bufslot].list;
396 while ( tmp_fslist ) {
397 /* make sure we do not go astray */
400 fprintf(debugFD,"[ %s ] error in deallocating fs CB\n",
404 next_fslist = tmp_fslist->next;
405 tmp_xstat_fsPR = tmp_fslist->fsResults;
408 fprintf(debugFD,"%d ",numFS-j);
410 /* free xstat_fs_Results data */
411 free(tmp_xstat_fsPR->data.AFS_CollData_val);
412 free(tmp_xstat_fsPR->connP);
413 free(tmp_xstat_fsPR);
415 /* free the fs list item */
417 tmp_fslist = next_fslist;
419 } /* while fs list items in this slot */
420 } /* if entries in this buffer slot */
421 } /* for each fs buffer slot */
423 fprintf(debugFD,"\n");
428 /* deallocate cache manager curcular buffers */
429 if (numCM && num_bufSlots) {
431 fprintf(debugFD,"freeing CM curcular buffers ");
432 for (bufslot=0; bufslot<num_bufSlots; bufslot++) {
434 fprintf(debugFD," %d) ",bufslot);
435 if (afsmon_cm_ResultsCB[bufslot].list !=
436 (struct afsmon_cm_Results_list *)0 ) {
437 tmp_cmlist = afsmon_cm_ResultsCB[bufslot].list;
439 while ( tmp_cmlist ) {
440 /* make sure we do not go astray */
443 fprintf(debugFD,"[ %s ] error in deallocating cm CB\n",
447 next_cmlist = tmp_cmlist->next;
448 tmp_xstat_cmPR = tmp_cmlist->cmResults;
451 fprintf(debugFD,"%d ",numCM-j);
452 /* make sure data is ok */
453 /* Print_cm_FullPerfInfo(tmp_xstat_cmPR); */
455 /* free xstat_cm_Results data */
456 free(tmp_xstat_cmPR->data.AFSCB_CollData_val);
457 free(tmp_xstat_cmPR->connP);
458 free(tmp_xstat_cmPR);
460 /* free the cm list item */
462 tmp_cmlist = next_cmlist;
464 } /* while cm list items in this slot */
465 } /* if entries in this buffer slot */
466 } /* for each cm buffer slot */
468 fprintf(debugFD,"\n");
472 /* deallocate FS & CM Print buffers */
473 if (curr_fsData != (struct fs_Display_Data *)0) {
475 fprintf(debugFD,"Deallocating FS Print Buffers .... curr");
478 if (prev_fsData != (struct fs_Display_Data *)0) {
480 fprintf(debugFD,", prev \n");
483 if (prev_cmData != (struct cm_Display_Data *)0) {
485 fprintf(debugFD,"Deallocating CM Print Buffers .... curr");
488 if (prev_cmData != (struct cm_Display_Data *)0) {
490 fprintf(debugFD,", prev \n");
494 /* deallocate hostEntry lists */
497 fprintf(debugFD,"Deallocating FS hostEntries ..");
498 curr_hostEntry = FSnameList;
499 for(i=0; i<numFS; i++) {
500 prev_hostEntry = curr_hostEntry;
501 if (curr_hostEntry->thresh != (struct Threshold *)0)
502 free(curr_hostEntry->thresh);
503 free(curr_hostEntry);
505 fprintf(debugFD," %d",i);
506 curr_hostEntry = prev_hostEntry->next;
509 fprintf(debugFD,"\n");
513 fprintf(debugFD,"Deallocating CM hostEntries ..");
514 curr_hostEntry = CMnameList;
515 for(i=0; i<numCM; i++) {
516 prev_hostEntry = curr_hostEntry;
517 if (curr_hostEntry->thresh != (struct Threshold *)0)
518 free(curr_hostEntry->thresh);
519 free(curr_hostEntry);
521 fprintf(debugFD," %d",i);
522 curr_hostEntry = prev_hostEntry->next;
525 fprintf(debugFD,"\n");
528 /* close debug file */
534 if (exec_fsThreshHandler) {
535 code = execvp(fsHandler_argv[0],fsHandler_argv);
537 fprintf(stderr,"execvp() of %s returned %d, errno %d\n",
538 fsHandler_argv[0], code, errno);
546 /*-----------------------------------------------------------------------
550 * Insert a hostname in the file server names list.
555 *----------------------------------------------------------------------*/
558 insert_FS( a_hostName )
559 char *a_hostName; /* name of cache manager to be inserted in list */
561 static char rn[] = "insert_FS"; /* routine name */
562 static struct afsmon_hostEntry *curr_item;
563 static struct afsmon_hostEntry *prev_item;
565 if ( *a_hostName == '\0')
567 curr_item = (struct afsmon_hostEntry *)
568 malloc(sizeof(struct afsmon_hostEntry));
569 if (curr_item == (struct afsmon_hostEntry *)0) {
570 fprintf(stderr,"Failed to allocate space for FS nameList\n");
574 strncpy(curr_item->hostName,a_hostName,CFG_STR_LEN);
575 curr_item->next = (struct afsmon_hostEntry *)0;
576 curr_item->numThresh = 0;
577 curr_item->thresh = (struct Threshold *)0;
579 if (FSnameList == (struct afsmon_hostEntry *)0)
580 FSnameList = curr_item;
582 prev_item->next = curr_item;
584 prev_item = curr_item;
585 /* record the address of this entry so that its threshold
586 count can be incremented during the first pass of the config file */
587 last_hostEntry = curr_item;
592 /*-----------------------------------------------------------------------
597 * Prints the file server names linked list.
601 *----------------------------------------------------------------------*/
605 static char rn[] = "print_FS";
606 struct afsmon_hostEntry *tempFS;
607 struct Threshold *threshP;
611 fprintf(debugFD,"[ %s ] Called\n",rn);
617 fprintf(debugFD,"No of File Servers: %d\n",numFS);
620 fprintf(debugFD,"\t %s threshCount = %d\n",
621 tempFS->hostName,tempFS->numThresh);
622 threshP = tempFS->thresh;
623 for(i=0; i<tempFS->numThresh; i++,threshP++)
624 fprintf(debugFD,"\t thresh (%2d) %s %s %s\n",
625 threshP->index, threshP->itemName,
626 threshP->threshVal,threshP->handler);
627 } while ( (tempFS = tempFS->next) != (struct afsmon_hostEntry *)0);
629 fprintf(debugFD,"\t\t-----End of List-----\n");
635 /*-----------------------------------------------------------------------
639 * Insert a hostname in the cache manager names list.
644 *----------------------------------------------------------------------*/
647 insert_CM( a_hostName )
648 char *a_hostName; /* name of cache manager to be inserted in list */
650 static char rn[] = "insert_CM"; /* routine name */
651 static struct afsmon_hostEntry *curr_item;
652 static struct afsmon_hostEntry *prev_item;
654 if ( *a_hostName == '\0')
656 curr_item = (struct afsmon_hostEntry *)
657 malloc(sizeof(struct afsmon_hostEntry));
658 if (curr_item == (struct afsmon_hostEntry *)0) {
659 fprintf(stderr,"Failed to allocate space for CM nameList\n");
663 strncpy(curr_item->hostName,a_hostName,CFG_STR_LEN);
664 curr_item->next = (struct afsmon_hostEntry *)0;
665 curr_item->numThresh = 0;
666 curr_item->thresh = (struct Threshold *)0;
668 if (CMnameList == (struct afsmon_hostEntry *)0)
669 CMnameList = curr_item;
671 prev_item->next = curr_item;
673 prev_item = curr_item;
674 /* side effect. note the address of this entry so that its threshold
675 count can be incremented during the first pass of the config file */
676 last_hostEntry = curr_item;
682 /*-----------------------------------------------------------------------
687 * Prints the cache manager names linked list.
691 *----------------------------------------------------------------------*/
695 static char rn[] = "print_CM";
696 struct afsmon_hostEntry *tempCM;
697 struct Threshold *threshP;
701 fprintf(debugFD,"[ %s ] Called\n",rn);
707 fprintf(debugFD,"No of Cache Managers: %d\n",numCM);
710 fprintf(debugFD,"\t %s threshCount = %d\n",
711 tempCM->hostName,tempCM->numThresh);
712 threshP = tempCM->thresh;
713 for(i=0; i<tempCM->numThresh; i++,threshP++)
714 fprintf(debugFD,"\t thresh (%2d) %s %s %s\n",
715 threshP->index, threshP->itemName,
716 threshP->threshVal,threshP->handler);
717 } while ( (tempCM = tempCM->next) != (struct afsmon_hostEntry *)0);
719 fprintf(debugFD,"\t\t-----End of List-----\n");
726 /*-----------------------------------------------------------------------
730 * Parse the host entry line in the config file. Check the syntax,
731 * and inserts the host name in the FS ot CM linked list. Also
732 * remember if this entry was an fs or cm & the ptr to its hostEntry
733 * structure. The threshold entries in the config file are dependent
734 * on their position relative to the hostname entries. Hence it is
735 * required to remember the names of the last file server and cache
736 * manager entries that were processed.
742 *----------------------------------------------------------------------*/
745 parse_hostEntry(a_line)
747 { /* parse_hostEntry */
749 static char rn[] = "parse_hostEntry"; /* routine name */
750 char opcode[CFG_STR_LEN]; /* specifies type of config entry */
751 char arg1[CFG_STR_LEN]; /* hostname or qualifier (fs/cm?) */
752 char arg2[CFG_STR_LEN]; /* threshold variable */
753 char arg3[CFG_STR_LEN]; /* threshold value */
754 char arg4[CFG_STR_LEN]; /* user's handler */
755 struct hostent *he; /* host entry */
758 fprintf(debugFD,"[ %s ] Called, a_line = %s\n",rn, a_line);
763 opcode[0] = 0;arg1[0] = 0;arg2[0] = 0;arg3[0] = 0;arg4[0] = 0;
764 sscanf(a_line,"%s %s %s %s %s",opcode,arg1,arg2,arg3,arg4);
765 /* syntax is "opcode hostname" */
766 if ((strlen(arg2)) != 0) {
767 fprintf(stderr,"[ %s ] Extraneous characters at end of line\n", rn);
772 he = GetHostByName(arg1);
773 if ( he == (struct hostent *)0) {
774 fprintf(stderr,"[ %s ] Unable to resolve hostname %s\n",
779 if ((strcasecmp(opcode,"fs")) == 0) {
780 /* use the complete host name to insert in the file server names list */
781 insert_FS(he->h_name);
782 /* note that last host entry in the config file was fs */
785 /* threholds are not global anymore */
786 if (global_ThreshFlag) global_ThreshFlag = 0;
788 else if ((strcasecmp(opcode,"cm")) == 0) {
789 /* use the complete host name to insert in the CM names list */
790 insert_CM(he->h_name);
791 /* last host entry in the config file was cm */
794 /* threholds are not global anymore */
795 if (global_ThreshFlag) global_ThreshFlag = 0;
803 /*-----------------------------------------------------------------------
804 * parse_threshEntry()
807 * Parse the threshold entry line in the config file. This function is
808 * called in the the first pass of the config file. It checks the syntax
809 * of the config lines and verifies their positional validity - eg.,
810 * a cm threshold cannot appear after a fs hostname entry, etc.
811 * It also counts the thresholds applicable to each host.
817 *----------------------------------------------------------------------*/
820 parse_threshEntry(a_line)
822 { /* parse_threshEntry */
823 static char rn[] = "parse_threshEntry"; /* routine name */
824 char opcode[CFG_STR_LEN]; /* specifies type of config entry */
825 char arg1[CFG_STR_LEN]; /* hostname or qualifier (fs/cm?) */
826 char arg2[CFG_STR_LEN]; /* threshold variable */
827 char arg3[CFG_STR_LEN]; /* threshold value */
828 char arg4[CFG_STR_LEN]; /* user's handler */
829 char arg5[CFG_STR_LEN]; /* junk characters */
832 fprintf(debugFD,"[ %s ] Called, a_line = %s\n",rn, a_line);
837 opcode[0] = 0;arg1[0] = 0;arg2[0] = 0;arg3[0] = 0;arg4[0] = 0;arg5[0] = 0;
838 sscanf(a_line,"%s %s %s %s %s %s",opcode,arg1,arg2,arg3,arg4,arg5);
840 /* syntax is "thresh fs/cm variable_name threshold_value [handler] " */
841 if (((strlen(arg1)) == 0)||((strlen(arg2)) == 0)||((strlen(arg3)) == 0)) {
842 fprintf(stderr,"[ %s ] Incomplete line\n", rn);
845 if (strlen(arg3) > THRESH_VAR_LEN-2) {
846 fprintf(stderr,"[%s ] threshold value too long\n", rn);
850 if ((strcasecmp(arg1,"fs")) == 0) {
851 switch (lastHostType) {
852 case 0: /* its a global threshold */
853 global_fsThreshCount++;
855 case 1: /* inc thresh count of last file server */
856 last_hostEntry->numThresh++;
859 fprintf(stderr,"[ %s ] A threshold for a File Server cannot be placed after a Cache Manager host entry in the config file \n",rn);
862 fprintf(stderr,"[ %s ] Programming error 1\n",rn);
865 } else if ((strcasecmp(arg1,"cm")) == 0) {
866 switch (lastHostType) {
867 case 0: /* its a global threshold */
868 global_cmThreshCount++;
870 case 2: /* inc thresh count of last cache manager */
871 last_hostEntry->numThresh++;
874 fprintf(stderr,"[ %s ] A threshold for a Cache Manager cannot be placed after a File Server host entry in the config file \n",rn);
877 fprintf(stderr,"[ %s ] Programming error 2\n",rn);
880 } else if ((strcasecmp(arg1,"cm")) != 0 && (strcasecmp(arg1,"cm")) != 0 ) {
881 fprintf(stderr,"[ %s ] Syntax error. Second argument should be \"fs\" or \"cm\" \n",rn);
886 } /* parse_threshEntry */
889 /*-----------------------------------------------------------------------
893 * The thresholds applicable to each host machine are stored in the
894 * FSnameList and CMnameList. Threshold entries in the config file are
895 * context sensitive. The host to which this threshold is applicable
896 * is pointed to by last_fsHost (for file servers) and last_cmHost
897 * for cache managers. For global thresholds the info is recorded for
898 * all the hosts. This function is called in the second pass of the
899 * config file. In the first pass a count of the number of global
900 * thresholds is determined and this information is used in this
901 * routine. If threshold entries are duplicated the first entry is
903 * Each threshold entry also has an index field. This is a positional
904 * index to the corresponding variable in the prev_[fs/cm]Data arrays.
905 * This makes it easy to check the threshold for overflow.
910 *----------------------------------------------------------------------*/
913 store_threshold(a_type,a_varName,a_value,a_handler)
914 int a_type; /* 1 = fs , 2 = cm */
915 char *a_varName; /* threshold name */
916 char *a_value; /* threshold value */
917 char *a_handler; /* threshold overflow handler */
919 { /* store_thresholds */
921 static char rn[] = "store_thresholds"; /* routine name */
922 struct afsmon_hostEntry *tmp_host; /* tmp ptr to hostEntry */
923 struct afsmon_hostEntry *Header; /* tmp ptr to hostEntry list header*/
924 struct Threshold *threshP; /* tmp ptr to threshold list */
926 int index; /* index to fs_varNames or cm_varNames */
929 int srvCount; /* tmp count of host names */
930 int *global_TC; /* ptr to global_xxThreshCount */
934 fprintf(debugFD,"[ %s ] Called, a_type= %d, a_varName= %s, a_value= %s, a_handler=%s\n",rn, a_type, a_varName, a_value, a_handler);
938 /* resolve the threshold variable name */
940 if (a_type == 1) { /* fs threshold */
941 for(index=0; index < NUM_FS_STAT_ENTRIES ; index++) {
942 if (strcasecmp(a_varName,fs_varNames[index]) == 0) {
948 fprintf(stderr,"[ %s ] Unknown FS threshold variable name %s\n",
954 hostname = last_fsHost;
955 global_TC = &global_fsThreshCount;
956 } else if (a_type == 2) { /* cm threshold */
957 for(index=0; index < NUM_CM_STAT_ENTRIES; index++) {
958 if (strcasecmp(a_varName,cm_varNames[index]) == 0) {
964 fprintf(stderr,"[ %s ] Unknown CM threshold variable name %s\n",
970 hostname = last_cmHost;
971 global_TC = &global_cmThreshCount;
977 /* if the global thresh count is not zero, place this threshold on
978 all the host entries */
982 for(i=0; i<srvCount; i++) {
983 threshP = tmp_host->thresh;
985 for(j=0; j<tmp_host->numThresh; j++) {
986 if ( (threshP->itemName[0] == '\0') ||
987 (strcasecmp(threshP->itemName,a_varName) == 0) ) {
988 strncpy(threshP->itemName,a_varName,THRESH_VAR_NAME_LEN);
989 strncpy(threshP->threshVal,a_value,THRESH_VAR_LEN);
990 strcpy(threshP->handler,a_handler);
991 threshP->index = index;
998 fprintf(stderr,"[ %s ] Could not insert threshold entry",rn);
999 fprintf(stderr,"for %s in thresh list of host %s \n",
1000 a_varName,tmp_host->hostName);
1003 tmp_host = tmp_host->next;
1009 /* it is not a global threshold, insert it in the thresh list of this
1010 host only. We overwrite the global threshold if it was alread set */
1012 if (*hostname == '\0') {
1013 fprintf(stderr,"[ %s ] Programming error 3\n",rn);
1017 /* get the hostEntry that this threshold belongs to */
1020 for(i=0; i < srvCount; i++) {
1021 if (strcasecmp(tmp_host->hostName,hostname) == 0) {
1025 tmp_host = tmp_host->next;
1028 fprintf(stderr,"[ %s ] Unable to find host %s in %s hostEntry list",
1029 rn,hostname,(a_type-1)?"CM":"FS");
1033 /* put this entry on the thresh list of this host, overwrite global value
1036 threshP = tmp_host->thresh;
1038 for(i=0; i < tmp_host->numThresh; i++) {
1039 if ( (threshP->itemName[0] == '\0') ||
1040 (strcasecmp(threshP->itemName,a_varName) == 0) ) {
1041 strncpy(threshP->itemName,a_varName,THRESH_VAR_NAME_LEN);
1042 strncpy(threshP->threshVal,a_value,THRESH_VAR_LEN);
1043 strcpy(threshP->handler,a_handler);
1044 threshP->index = index;
1052 fprintf(stderr,"[ %s ] Unable to insert threshold %s for %s host %s\n",
1053 rn, a_varName, (a_type -1)?"CM":"FS", tmp_host->hostName);
1059 } /* store_thresholds */
1062 /*-----------------------------------------------------------------------
1066 * This function process a "show" entry in the config file. A "show"
1067 * entry specifies what statistics the user wants to see. File
1068 * server and Cache Manager data is divided into sections. Each section
1069 * is made up of one or more groups. If a group name is specified only
1070 * those statistics under that group are shown. If a section name is
1071 * specified all the groups under this section are shown.
1072 * Data as obtained from the xstat probes is considered to be ordered.
1073 * This data is mapped to the screen thru fs_Display_map[] and
1074 * cm_Display_map[]. This routine parses the "show" entry against the
1075 * section/group names in the [fs/cm]_categories[] array. If there is
1076 * no match it tries to match it against a variable name in
1077 * [fs/cm]_varNames[] array. In each case the corresponding indices to
1078 * the data is the [fs/cm]_displayInfo[] is recorded.
1082 * Failure: -1 (invalid entry)
1083 * > -1 (programming error)
1084 *----------------------------------------------------------------------*/
1087 parse_showEntry(a_line)
1089 { /* parse_showEntry */
1090 static char rn[] = "parse_showEntry";
1091 char opcode[CFG_STR_LEN]; /* specifies type of config entry */
1092 char arg1[CFG_STR_LEN]; /* show fs or cm entry ? */
1093 char arg2[CFG_STR_LEN]; /* what we gotta show */
1094 char arg3[CFG_STR_LEN]; /* junk */
1095 char catName[CFG_STR_LEN]; /* for category names */
1096 int numGroups; /* number of groups in a section */
1100 int idx = 0; /* index to fs_categories[] */
1106 fprintf(debugFD,"[ %s ] Called, a_line= %s\n",rn, a_line);
1109 opcode[0] = 0; arg1[0] = 0; arg2[0] = 0; arg3[0] = 0;
1110 sscanf(a_line,"%s %s %s %s", opcode, arg1, arg2, arg3);
1112 if (arg3[0] != '\0') {
1113 fprintf(stderr,"[ %s ] Extraneous characters at end of line\n",rn);
1117 if ((strcasecmp(arg1,"fs") != 0) && (strcasecmp(arg1,"cm") != 0)) {
1118 fprintf(stderr,"[ %s ] Second argument of \"show\" directive should be \"fs\" or \"cm\" \n",rn);
1122 /* Each entry can either be a variable name or a section/group name. Variable
1123 names are listed in xx_varNames[] and section/group names in xx_categories[].
1124 The section/group names in xx_categiries[] also give the starting/ending
1125 indices of the variables belonging to that section/group. These indices
1126 are stored in order in xx_Display_map[] and displayed to the screen in that
1129 /* To handle duplicate "show" entries we keep track of what what we have
1130 already marked to show in the xx_showFlags[] */
1132 if (strcasecmp(arg1,"fs") == 0) { /* its a File Server entry */
1134 /* mark that we have to show only what the user wants */
1137 /* if it is a section/group name, find it in the fs_categories[] array */
1140 if ( strcasestr(arg2,"_section") != (char *)NULL ||
1141 strcasestr(arg2,"_group") != (char *)NULL ) {
1143 while(idx<FS_NUM_DATA_CATEGORIES) {
1144 sscanf(fs_categories[idx],"%s %d %d",catName, &fromIdx, &toIdx);
1146 if (strcasecmp(arg2, catName) == 0) {
1152 if (! found) { /* typo in section/group name */
1153 fprintf(stderr,"[ %s ] Could not find section/group name %s\n",rn,arg2);
1158 /* if it is a group name, read its start/end indices and fill in the
1159 fs_Display_map[]. */
1161 if (strcasestr(arg2,"_group") != (char *)NULL ) {
1163 if (fromIdx < 0 || toIdx < 0 || fromIdx > NUM_FS_STAT_ENTRIES ||
1164 toIdx > NUM_FS_STAT_ENTRIES)
1166 for(j=fromIdx; j<=toIdx; j++) {
1167 if (! fs_showFlags[j]) {
1168 fs_Display_map[fs_DisplayItems_count] = j;
1169 fs_DisplayItems_count++;
1170 fs_showFlags[j] = 1;
1172 if (fs_DisplayItems_count > NUM_FS_STAT_ENTRIES) {
1173 fprintf(stderr,"[ %s ] fs_DisplayItems_count ovf\n",rn);
1179 /* if it is a section name, get the count of number of groups in it and
1180 for each group fill in the start/end indices in the fs_Display_map[] */
1182 if (strcasestr(arg2,"_section") != (char *)NULL ) {
1183 /* fromIdx is actually the number of groups in thi section */
1184 numGroups = fromIdx;
1185 /* for each group in section */
1186 while(idx < FS_NUM_DATA_CATEGORIES && numGroups) {
1187 sscanf(fs_categories[idx],"%s %d %d",catName, &fromIdx, &toIdx);
1189 if (strcasestr(catName,"_group") != (char *)0) {
1190 if (fromIdx < 0 || toIdx < 0 || fromIdx > NUM_FS_STAT_ENTRIES ||
1191 toIdx > NUM_FS_STAT_ENTRIES)
1193 for(j=fromIdx; j<=toIdx; j++) {
1194 if (! fs_showFlags[j]) {
1195 fs_Display_map[fs_DisplayItems_count] = j;
1196 fs_DisplayItems_count++;
1197 fs_showFlags[j] = 1;
1199 if (fs_DisplayItems_count > NUM_FS_STAT_ENTRIES) {
1200 fprintf(stderr,"[ %s ] fs_DisplayItems_count ovf\n",rn);
1205 fprintf(stderr,"[ %s ] Error parsing groups for %s\n",rn,arg2);
1210 } /* for each group in section */
1213 } else { /* it is a variable name */
1215 for(i=0; i<NUM_FS_STAT_ENTRIES; i++) {
1216 if (strcasecmp(arg2, fs_varNames[i]) == 0) {
1217 if (! fs_showFlags[i]) {
1218 fs_Display_map[fs_DisplayItems_count] = i;
1219 fs_DisplayItems_count++;
1220 fs_showFlags[i] = 1;
1222 if (fs_DisplayItems_count >= NUM_FS_STAT_ENTRIES) {
1223 fprintf(stderr,"[ %s ] fs_DisplayItems_count ovf\n",rn);
1229 if (! found) { /* typo in section/group name */
1230 fprintf(stderr,"[ %s ] Could not find variable name %s\n",rn,arg2);
1233 } /* its a variable name */
1235 } /* it is an fs entry */
1238 if (strcasecmp(arg1,"cm") == 0) { /* its a Cache Manager entry */
1241 /* mark that we have to show only what the user wants */
1244 /* if it is a section/group name, find it in the cm_categories[] array */
1247 if ( strcasestr(arg2,"_section") != (char *)NULL ||
1248 strcasestr(arg2,"_group") != (char *)NULL ) {
1250 while(idx<CM_NUM_DATA_CATEGORIES) {
1251 sscanf(cm_categories[idx],"%s %d %d",catName, &fromIdx, &toIdx);
1253 if (strcasecmp(arg2, catName) == 0) {
1259 if (! found) { /* typo in section/group name */
1260 fprintf(stderr,"[ %s ] Could not find section/group name %s\n",rn,arg2);
1265 /* if it is a group name, read its start/end indices and fill in the
1266 cm_Display_map[]. */
1268 if (strcasestr(arg2,"_group") != (char *)NULL ) {
1270 if (fromIdx < 0 || toIdx < 0 || fromIdx > NUM_CM_STAT_ENTRIES ||
1271 toIdx > NUM_CM_STAT_ENTRIES)
1273 for(j=fromIdx; j<=toIdx; j++) {
1274 if (! cm_showFlags[j]) {
1275 cm_Display_map[cm_DisplayItems_count] = j;
1276 cm_DisplayItems_count++;
1277 cm_showFlags[j] = 1;
1279 if (cm_DisplayItems_count > NUM_CM_STAT_ENTRIES) {
1280 fprintf(stderr,"[ %s ] cm_DisplayItems_count ovf\n",rn);
1286 /* if it is a section name, get the count of number of groups in it and
1287 for each group fill in the start/end indices in the cm_Display_map[] */
1289 if (strcasestr(arg2,"_section") != (char *)NULL ) {
1290 /* fromIdx is actually the number of groups in thi section */
1291 numGroups = fromIdx;
1292 /* for each group in section */
1293 while(idx < CM_NUM_DATA_CATEGORIES && numGroups) {
1294 sscanf(cm_categories[idx],"%s %d %d",catName, &fromIdx, &toIdx);
1296 if (strcasestr(catName,"_group") != (char *)0) {
1297 if (fromIdx < 0 || toIdx < 0 || fromIdx > NUM_CM_STAT_ENTRIES ||
1298 toIdx > NUM_CM_STAT_ENTRIES)
1300 for(j=fromIdx; j<=toIdx; j++) {
1301 if (! cm_showFlags[j]) {
1302 cm_Display_map[cm_DisplayItems_count] = j;
1303 cm_DisplayItems_count++;
1304 cm_showFlags[j] = 1;
1306 if (cm_DisplayItems_count > NUM_CM_STAT_ENTRIES) {
1307 fprintf(stderr,"[ %s ] cm_DisplayItems_count ovf\n",rn);
1312 fprintf(stderr,"[ %s ] Error parsing groups for %s\n",rn,arg2);
1317 } /* for each group in section */
1324 } else { /* it is a variable name */
1326 for(i=0; i<NUM_CM_STAT_ENTRIES; i++) {
1327 if (strcasecmp(arg2, cm_varNames[i]) == 0) {
1328 if (! cm_showFlags[i]) {
1329 cm_Display_map[cm_DisplayItems_count] = i;
1330 cm_DisplayItems_count++;
1331 cm_showFlags[i] = 1;
1333 if (cm_DisplayItems_count >= NUM_CM_STAT_ENTRIES) {
1334 fprintf(stderr,"[ %s ] cm_DisplayItems_count ovf\n",rn);
1340 if (! found) { /* typo in section/group name */
1341 fprintf(stderr,"[ %s ] Could not find variable name %s\n",rn,arg2);
1344 } /* its a variable name */
1346 } /* it is an cm entry */
1351 } /* parse_showEntry */
1354 /*-----------------------------------------------------------------------
1355 * process_config_file()
1358 * Parse config file entries in two passes. In the first pass:
1359 * - the syntax of all the entries is checked
1360 * - host names are noted and the FSnamesList and CMnamesList
1362 * - a count of the global thresholds and local thresholds of
1363 * each host are counted.
1364 * - "show" entries are processed.
1365 * In the second pass:
1366 * - thresholds are stored
1370 * Failure: Exits afsmonitor showing error and line.
1371 *----------------------------------------------------------------------*/
1374 process_config_file(a_config_filename)
1375 char *a_config_filename;
1376 { /* process_config_file() */
1377 static char rn[] = "process_config_file"; /* routine name */
1378 FILE *configFD; /* config file descriptor */
1379 char line[4*CFG_STR_LEN]; /* a line of config file */
1380 char opcode[CFG_STR_LEN]; /* specifies type of config entry */
1381 char arg1[CFG_STR_LEN]; /* hostname or qualifier (fs/cm?) */
1382 char arg2[CFG_STR_LEN]; /* threshold variable */
1383 char arg3[CFG_STR_LEN]; /* threshold value */
1384 char arg4[CFG_STR_LEN]; /* user's handler */
1385 struct afsmon_hostEntry *curr_host;
1386 struct hostent *he; /* hostentry to resolve host name*/
1387 char *handlerPtr; /* ptr to pass theresh handler string */
1388 int code = 0; /* error code */
1389 int linenum = 0; /* config file line number */
1390 int threshCount; /* count of thresholds for each server */
1391 int error_in_config; /* syntax errors in config file ?? */
1396 fprintf(debugFD,"[ %s ] Called, a_config_filename= %s\n",
1397 rn, a_config_filename);
1401 /* open config file */
1403 configFD = fopen(a_config_filename,"r");
1404 if (configFD == (FILE *)0) {
1405 fprintf(stderr,"Failed to open config file %s \n",a_config_filename);
1407 fprintf(debugFD,"[ %s ] Failed to open config file %s \n",
1408 rn, a_config_filename);
1414 /* parse config file */
1416 /* We process the config file in two passes. In the first pass we check
1417 for correct syntax and for valid entries and also keep count of the
1418 number of servers and thresholds to monitor. This the data strctures
1419 can be arrays instead of link lists since we would know their sizes.*/
1426 error_in_config = 0; /* flag to note if config file has syntax errors*/
1428 while ( (fgets(line,CFG_STR_LEN,configFD)) != NULL)
1430 opcode[0] = 0; arg1[0] = 0; arg2[0] = 0; arg3[0] = 0; arg4[0] = 0;
1431 sscanf(line,"%s %s %s %s %s", opcode, arg1, arg2, arg3, arg4);
1433 /* skip blank lines and comment lines */
1434 if ( (strlen(opcode) == 0) || line[0] == '#' ) continue;
1436 if ( (strcasecmp(opcode,"fs") == 0) || (strcasecmp(opcode,"cm")) == 0) {
1437 code = parse_hostEntry(line);
1438 } else if ((strcasecmp(opcode,"thresh")) == 0) {
1439 code = parse_threshEntry(line);
1440 } else if ((strcasecmp(opcode,"show")) == 0) {
1441 code = parse_showEntry(line);
1443 fprintf(stderr,"[ %s ] Unknown opcode %s\n",rn,opcode);
1448 fprintf(stderr,"[ %s ] Error in line:\n %d: %s\n",
1450 error_in_config = 1;
1454 if (error_in_config)
1458 fprintf(debugFD,"Global FS thresholds count = %d\n",global_fsThreshCount);
1459 fprintf(debugFD,"Global CM thresholds count = %d\n",global_cmThreshCount);
1463 /* the threshold count of all hosts in increased by 1 for each global
1464 threshold. If one of the hosts has a local threshold for the same
1465 variable it would end up being counted twice. whats a few bytes of memory
1468 if (global_fsThreshCount) {
1469 curr_host = FSnameList;
1470 for(i=0; i<numFS; i++) {
1471 curr_host->numThresh += global_fsThreshCount;
1472 curr_host = curr_host->next;
1475 if (global_cmThreshCount) {
1476 curr_host = CMnameList;
1477 for(i=0; i<numCM; i++) {
1478 curr_host->numThresh += global_cmThreshCount;
1479 curr_host = curr_host->next;
1484 /* make sure we have something to monitor */
1485 if (numFS == 0 && numCM == 0) {
1486 fprintf(stderr,"\nConfig file must specify atleast one File Server or Cache Manager host to monitor.\n");
1493 fseek(configFD,0,0); /* seek to the beginning */
1496 /* allocate memory for threshold lists */
1497 curr_host = FSnameList;
1498 for(i=0; i<numFS; i++) {
1499 if (curr_host->hostName[0] == '\0') {
1500 fprintf(stderr,"[ %s ] Programming error 4\n",rn);
1503 if (curr_host->numThresh) {
1504 numBytes = curr_host->numThresh * sizeof(struct Threshold);
1505 curr_host->thresh = (struct Threshold *) malloc(numBytes);
1506 if (curr_host->thresh == (struct Threshold *)0) {
1507 fprintf(stderr,"[ %s ] Memory Allocation error 1",rn);
1510 memset(curr_host->thresh, 0, numBytes);
1512 curr_host = curr_host->next;;
1515 curr_host = CMnameList;
1516 for(i=0; i<numCM; i++) {
1517 if (curr_host->hostName[0] == '\0') {
1518 fprintf(stderr,"[ %s ] Programming error 5\n",rn);
1521 if (curr_host->numThresh) {
1522 numBytes = curr_host->numThresh * sizeof(struct Threshold);
1523 curr_host->thresh = (struct Threshold *) malloc(numBytes);
1524 if (curr_host->thresh == (struct Threshold *)0) {
1525 fprintf(stderr,"[ %s ] Memory Allocation error 2",rn);
1528 memset(curr_host->thresh, 0, numBytes);
1530 curr_host = curr_host->next;;
1534 opcode[0] = 0; arg1[0] = 0; arg2[0] = 0; arg3[0] = 0; arg4[0] = 0;
1535 last_fsHost[0] = '\0';
1536 last_cmHost[0] = '\0';
1538 while ( (fgets(line,CFG_STR_LEN,configFD)) != NULL) {
1539 opcode[0] = 0; arg1[0] = 0; arg2[0] = 0; arg3[0] = 0; arg4[0] = 0;
1540 sscanf(line,"%s %s %s %s %s", opcode, arg1, arg2, arg3, arg4);
1543 /* if we have a host entry, remember the host name */
1544 if (strcasecmp(opcode,"fs") == 0) {
1545 he = GetHostByName(arg1);
1546 strncpy(last_fsHost,he->h_name,HOST_NAME_LEN);
1548 else if (strcasecmp(opcode,"cm") == 0) {
1549 he = GetHostByName(arg1);
1550 strncpy(last_cmHost,he->h_name,HOST_NAME_LEN);
1552 else if (strcasecmp(opcode,"thresh") == 0) {
1553 /* if we have a threshold handler it may have arguments
1554 and the sscanf() above would not get them, so do the
1558 /* now skip over 4 words - this is done by first
1559 skipping leading blanks then skipping a word */
1560 for(i=0; i<4; i++) {
1561 while( isspace(*handlerPtr) )
1563 while(! isspace(*handlerPtr) )
1566 while( isspace(*handlerPtr) )
1568 /* we how have a pointer to the start of the handler
1571 handlerPtr = arg4; /* empty string */
1574 if (strcasecmp(arg1,"fs") == 0)
1575 code = store_threshold(1, /* 1 = fs*/
1576 arg2,arg3,handlerPtr);
1578 else if (strcasecmp(arg1,"cm") == 0)
1579 code = store_threshold(2, /* 2 = fs*/
1580 arg2,arg3,handlerPtr);
1583 fprintf(stderr,"[ %s ] Programming error 6\n", rn);
1587 fprintf(stderr,"[ %s ] Failed to store threshold\n",
1589 fprintf(stderr,"[ %s ] Error processing line:\n%d: %s",
1601 /*-----------------------------------------------------------------------
1606 * Print the File Server circular buffer.
1610 *----------------------------------------------------------------------*/
1614 { /* Print_FS_CB() */
1616 struct afsmon_fs_Results_list *fslist;
1620 /* print valid info in the fs CB */
1623 fprintf(debugFD,"==================== FS Buffer ========================\n");
1624 fprintf(debugFD,"afsmon_fs_curr_CBindex = %d\n",afsmon_fs_curr_CBindex);
1625 fprintf(debugFD,"afsmon_fs_curr_probeNum = %d\n\n",afsmon_fs_curr_probeNum);
1627 for(i=0; i<num_bufSlots; i++) {
1628 fprintf(debugFD,"\t--------- slot %d ----------\n",i);
1629 fslist = afsmon_fs_ResultsCB[i].list;
1631 while( j < numFS ) {
1632 if (! fslist->empty) {
1633 fprintf(debugFD,"\t %d) probeNum = %d host = %s",
1634 j,fslist->fsResults->probeNum,
1635 fslist-> fsResults->connP->hostName);
1636 if (fslist->fsResults->probeOK) fprintf(debugFD," NOTOK\n");
1637 else fprintf(debugFD," OK\n");
1639 fprintf(debugFD,"\t %d) -- empty --\n",j);
1640 fslist = fslist->next;
1643 if (fslist != (struct afsmon_fs_Results_list *)0 )
1644 fprintf(debugFD,"dangling last next ptr fs CB\n");
1647 } /* Print_FS_CB() */
1649 /*-----------------------------------------------------------------------
1650 * save_FS_results_inCB()
1653 * Saves the results of the latest FS probe in the fs circular
1654 * buffers. If the current probe cycle is in progress the contents
1655 * of xstat_fs_Results are copied to the end of the list of results
1656 * in the current slot (pointed to by afsmon_fs_curr_CBindex). If
1657 * a new probe cycle has started the next slot in the circular buffer
1658 * is initialized and the results copied. Note that the Rx related
1659 * information available in xstat_fs_Results is not copied.
1663 * Failure: Exits afsmonitor.
1664 *----------------------------------------------------------------------*/
1666 save_FS_results_inCB(a_newProbeCycle)
1667 int a_newProbeCycle; /* start of a new probe cycle ? */
1669 { /* save_FS_results_inCB() */
1670 static char rn[] = "save_FS_results_inCB"; /* routine name */
1671 struct afsmon_fs_Results_list *tmp_fslist_item; /* temp fs list item */
1672 struct xstat_fs_ProbeResults *tmp_fsPR; /* temp ptr */
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 memcpy(tmp_fsPR->connP->hostName, xstat_fs_Results.connP->hostName, sizeof(xstat_fs_Results.connP->hostName));
1714 tmp_fsPR->probeNum = xstat_fs_Results.probeNum;
1715 tmp_fsPR->probeTime = xstat_fs_Results.probeTime;
1716 tmp_fsPR->probeOK = xstat_fs_Results.probeOK;
1717 if (xstat_fs_Results.probeOK) { /* probeOK = 1 => notOK */
1718 /* we have a nonempty results structure so mark the list item used */
1719 tmp_fslist_item->empty = 0;
1723 /* copy connection information */
1724 memcpy(&(tmp_fsPR->connP->skt), &(xstat_fs_Results.connP->skt), sizeof(struct sockaddr_in));
1726 memcpy(tmp_fsPR->connP->hostName, xstat_fs_Results.connP->hostName, sizeof(xstat_fs_Results.connP->hostName));
1727 tmp_fsPR->collectionNumber = xstat_fs_Results.collectionNumber;
1729 /* copy the probe data information */
1730 tmp_fsPR->data.AFS_CollData_len = xstat_fs_Results.data.AFS_CollData_len;
1731 memcpy(tmp_fsPR->data.AFS_CollData_val, xstat_fs_Results.data.AFS_CollData_val, xstat_fs_Results.data.AFS_CollData_len * sizeof(afs_int32));
1734 /* we have a valid results structure so mark the list item used */
1735 tmp_fslist_item->empty = 0;
1737 /* Print the fs circular buffer */
1741 } /* save_FS_results_inCB() */
1744 /*-----------------------------------------------------------------------
1748 * The results of xstat probes are stored in a string format in
1749 * the arrays curr_fsData and prev_fsData. The information stored in
1750 * prev_fsData is copied to the screen.
1751 * This function converts xstat FS results from longs to strings and
1752 * place them in the given buffer (a pointer to an item in curr_fsData).
1753 * When a probe cycle completes, curr_fsData is copied to prev_fsData
1754 * in afsmon_FS_Hnadler().
1758 *----------------------------------------------------------------------*/
1761 fs_Results_ltoa(a_fsData,a_fsResults)
1762 struct fs_Display_Data *a_fsData; /* target buffer */
1763 struct xstat_fs_ProbeResults *a_fsResults; /* ptr to xstat fs Results */
1764 { /* fs_Results_ltoa */
1766 static char rn[] = "fs_Results_ltoa"; /* routine name */
1768 struct fs_stats_FullPerfStats *fullPerfP;
1774 fprintf(debugFD,"[ %s ] Called, a_fsData= %d, a_fsResults= %d\n",
1775 rn, a_fsData, a_fsResults);
1779 fullPerfP = (struct fs_stats_FullPerfStats *)
1780 (a_fsResults->data.AFS_CollData_val);
1782 /* there are two parts to the xstat FS statistics
1783 - fullPerfP->overall which give the overall performance statistics, and
1784 - fullPerfP->det which gives detailed info about file server operation
1787 /* copy overall performance statistics */
1788 srcbuf = (afs_int32 *) &(fullPerfP->overall);
1790 for(i=0; i< NUM_XSTAT_FS_AFS_PERFSTATS_LONGS; i++) {
1791 sprintf(a_fsData->data[idx],"%d",*srcbuf);
1797 srcbuf = (afs_int32 *) &(fullPerfP->det.epoch);
1798 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* epoch */
1801 /* copy fs operation timing */
1803 srcbuf = (afs_int32 *) (fullPerfP->det.rpcOpTimes);
1805 for(i=0; i<FS_STATS_NUM_RPC_OPS; i++) {
1806 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* numOps*/
1808 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* numSuccesses */
1810 tmpbuf = srcbuf++; /* sum time */
1811 sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1813 tmpbuf = srcbuf++; /* sqr time */
1814 sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1816 tmpbuf = srcbuf++; /* min time */
1817 sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1819 tmpbuf = srcbuf++; /* max time */
1820 sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1824 /* copy fs transfer timings */
1826 srcbuf = (afs_int32 *) (fullPerfP->det.xferOpTimes);
1827 for(i=0; i<FS_STATS_NUM_XFER_OPS; i++) {
1828 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* numOps*/
1830 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* numSuccesses */
1832 tmpbuf = srcbuf++; /* sum time */
1833 sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1835 tmpbuf = srcbuf++; /* sqr time */
1836 sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1838 tmpbuf = srcbuf++; /* min time */
1839 sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1841 tmpbuf = srcbuf++; /* max time */
1842 sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1844 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* sum bytes */
1846 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* min bytes */
1848 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* max bytes */
1850 for(j=0; j<FS_STATS_NUM_XFER_BUCKETS; j++) {
1851 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* bucket[j] */
1857 } /* fs_Results_ltoa */
1861 /*-----------------------------------------------------------------------
1862 * execute_thresh_handler()
1865 * Execute a threshold handler. An agrv[] array of pointers is
1866 * constructed from the given data. A child process is forked
1867 * which immediately calls afsmon_Exit() with indication that a
1868 * threshold handler is to be exec'ed insted of exiting.
1872 * Failure: Afsmonitor exits if threshold handler has more than 20 args.
1873 *----------------------------------------------------------------------*/
1876 execute_thresh_handler(a_handler, a_hostName, a_hostType,
1877 a_threshName,a_threshValue, a_actValue)
1878 char *a_handler; /* ptr to handler function + args */
1879 char *a_hostName; /* host name for which threshold crossed */
1880 int a_hostType; /* fs or cm ? */
1881 char *a_threshName; /* threshold variable name */
1882 char *a_threshValue; /* threshold value */
1883 char *a_actValue; /* actual value */
1885 { /* execute_thresh_handler */
1887 static char rn[] = "execute_thresh_handler";
1888 char fileName[256]; /* file name to execute */
1893 int anotherArg; /* boolean used to flag if another arg is available */
1896 fprintf(debugFD,"[ %s ] Called, a_handler= %s, a_hostName= %s, a_hostType= %d, a_threshName= %s, a_threshValue= %s, a_actValue= %s\n",
1897 rn, a_handler, a_hostName, a_hostType, a_threshName, a_threshValue,
1903 /* get the filename to execute - the first argument */
1904 sscanf(a_handler,"%s",fileName);
1906 /* construct the contents of *argv[] */
1908 strncpy(fsHandler_args[0], fileName,256);
1909 strncpy(fsHandler_args[1], a_hostName, HOST_NAME_LEN);
1910 if (a_hostType == FS) strcpy(fsHandler_args[2], "fs");
1911 else strcpy(fsHandler_args[2], "cm");
1912 strncpy(fsHandler_args[3], a_threshName, THRESH_VAR_NAME_LEN);
1913 strncpy(fsHandler_args[4], a_threshValue, THRESH_VAR_LEN);
1914 strncpy(fsHandler_args[5], a_actValue, THRESH_VAR_LEN);
1921 /* we have already extracted the file name so skip to the 1st arg */
1922 while (isspace(*ch)) /* leading blanks */
1924 while (! isspace(*ch) && *ch != '\0') /* handler filename */
1927 while( *ch != '\0' ) {
1930 } else if (anotherArg) {
1932 sscanf(ch,"%s",fsHandler_args[argNum]);
1938 "Threshold handlers cannot have more than 20 arguments\n");
1944 fsHandler_argv[argNum] = (char *)0;
1945 for(i=0; i<argNum; i++)
1946 fsHandler_argv[i] = fsHandler_args[i];
1949 /* exec the threshold handler */
1952 exec_fsThreshHandler = 1;
1953 code = afsmon_Exit(60);
1957 } /* execute_thresh_handler */
1961 /*-----------------------------------------------------------------------
1962 * check_fs_thresholds()
1965 * Checks the thresholds and sets the overflow flag. Recall that the
1966 * thresholds for each host are stored in the hostEntry lists
1967 * [fs/cm]nameList arrays. The probe results are passed to this
1968 * function in the display-ready format - ie., as strings. Though
1969 * this looks stupid the overhead incurred in converting the strings
1970 * back to floats and comparing them is insignificant and
1971 * programming is easier this way.
1972 * The threshold flags are a part of the display structures
1977 *----------------------------------------------------------------------*/
1980 check_fs_thresholds(a_hostEntry, a_Data)
1981 struct afsmon_hostEntry *a_hostEntry; /* ptr to hostEntry */
1982 struct fs_Display_Data *a_Data; /* ptr to fs data to be displayed */
1984 { /* check_fs_thresholds */
1986 static char rn[] = "check_fs_thresholds";
1987 struct Threshold *threshP;
1988 double tValue; /* threshold value */
1989 double pValue; /* probe value */
1992 int count; /* number of thresholds exceeded */
1995 fprintf(debugFD,"[ %s ] Called, a_hostEntry= %d, a_Data= %d\n",
1996 rn, a_hostEntry, a_Data);
2000 if (a_hostEntry->numThresh == 0) {
2001 /* store in ovf count ?? */
2006 threshP = a_hostEntry->thresh;
2007 for(i=0; i < a_hostEntry->numThresh; i++) {
2008 if (threshP->itemName[0] == '\0') {
2009 threshP++; continue;
2011 idx = threshP->index; /* positional index to the data array */
2012 tValue = atof(threshP->threshVal); /* threshold value */
2013 pValue = atof(a_Data->data[idx]); /* probe value */
2014 if (pValue > tValue) {
2017 fprintf(debugFD,"[ %s ] fs = %s, thresh ovf for %s, threshold= %s, probevalue= %s\n",
2018 rn, a_hostEntry->hostName, threshP->itemName, threshP->threshVal, a_Data->data[idx]);
2021 /* if the threshold is crossed, call the handler function
2022 only if this was a transition -ie, if the threshold was
2023 crossed in the last probe too just count & keep quite! */
2025 if (! a_Data->threshOvf[idx]) {
2026 a_Data->threshOvf[idx] = 1;
2027 /* call the threshold handler if provided */
2028 if (threshP->handler[0] != '\0') {
2030 fprintf(debugFD,"[ %s ] Calling ovf handler %s\n",
2031 rn, threshP->handler);
2034 execute_thresh_handler(threshP->handler,
2035 a_Data->hostName, FS, threshP->itemName,
2036 threshP->threshVal, a_Data->data[idx]);
2042 /* in case threshold was previously crossed, blank it out */
2043 a_Data->threshOvf[idx] = 0;
2046 /* store the overflow count */
2047 a_Data->ovfCount = count;
2050 } /* check_fs_thresholds */
2053 /*-----------------------------------------------------------------------
2054 * save_FS_data_forDisplay()
2057 * Does the following:
2058 * - if the probe number changed (ie, a cycle completed) curr_fsData
2059 * is copied to prev_fsData, curr_fsData zeroed and refresh the
2060 * overview screen and file server screen with the new data.
2061 * - store the results of the current probe from xstat_fs_Results into
2062 * curr_fsData. ie., convert longs to strings.
2063 * - check the thresholds
2067 * Failure: Exits afsmonitor.
2068 *----------------------------------------------------------------------*/
2071 save_FS_data_forDisplay(a_fsResults)
2072 struct xstat_fs_ProbeResults *a_fsResults;
2073 { /* save_FS_data_forDisplay */
2075 static char rn[] = "save_FS_data_forDisplay"; /* routine name */
2076 struct fs_Display_Data *curr_fsDataP; /* tmp ptr to curr_fsData*/
2077 struct fs_Display_Data *prev_fsDataP; /* tmp ptr to prev_fsData*/
2078 struct afsmon_hostEntry *curr_host;
2079 static int probes_Received = 0; /* number of probes reveived in
2080 the current cycle. If this is equal to numFS we got all
2081 the data we want in this cycle and can now display it */
2090 fprintf(debugFD,"[ %s ] Called, a_fsResults= %d\n",rn, a_fsResults);
2096 /* store results in the display array */
2099 curr_fsDataP = curr_fsData;
2100 for (i=0; i<numFS; i++) {
2101 if((strcasecmp(curr_fsDataP->hostName,a_fsResults->connP->hostName)) == 0) {
2109 fprintf(stderr,"[ %s ] Could not insert FS probe results for host %s in fs display array\n",rn, a_fsResults->connP->hostName);
2113 /* Check the status of the probe. If it succeeded, we store its
2114 results in the display data structure. If it failed we only mark
2115 the failed status in the display data structure. */
2117 if (a_fsResults->probeOK) { /* 1 => notOK the xstat results */
2118 curr_fsDataP->probeOK = 0;
2120 /* print the probe status */
2122 fprintf(debugFD,"\n\t\t ----- fs display data ------\n");
2123 fprintf(debugFD,"HostName = %s PROBE FAILED \n",curr_fsDataP->hostName);
2127 } else { /* probe succeeded, update display data structures */
2128 curr_fsDataP->probeOK = 1;
2130 /* covert longs to strings and place them in curr_fsDataP */
2131 fs_Results_ltoa(curr_fsDataP, a_fsResults);
2133 /* compare with thresholds and set the overflow flags.
2134 note that the threshold information is in the hostEntry structure and
2135 each threshold item has a positional index associated with it */
2137 /* locate the hostEntry for this host */
2139 curr_host = FSnameList;
2140 for(i=0; i<numFS; i++) {
2141 if(strcasecmp(curr_host->hostName,a_fsResults->connP->hostName) == 0) {
2145 curr_host = curr_host->next;;
2147 if (!done) afsmon_Exit(70);
2149 code = check_fs_thresholds(curr_host, curr_fsDataP);
2151 fprintf(stderr,"[ %s ] Error in checking thresholds\n",rn);
2158 /* print the info we just saved */
2161 fprintf(debugFD,"\n\t\t ----- fs display data ------\n");
2162 fprintf(debugFD,"HostName = %s\n",curr_fsDataP->hostName);
2163 for(i=0; i<NUM_FS_STAT_ENTRIES; i++)
2164 fprintf(debugFD,"%20s %30s %s\n", curr_fsDataP->data[i],
2165 fs_varNames[i], curr_fsDataP->threshOvf[i] ? "(ovf)":"" );
2167 fprintf(debugFD,"\t\t--------------------------------\n\n");
2171 } /* the probe succeeded, so we store the data in the display structure */
2174 /* if we have received a reply from all the hosts for this probe cycle,
2175 it is time to display the data */
2178 if (probes_Received == numFS) {
2179 probes_Received = 0;
2181 if (afsmon_fs_curr_probeNum != afsmon_fs_prev_probeNum + 1) {
2182 sprintf(errMsg,"[ %s ] Probe number %d missed! \n",
2183 rn, afsmon_fs_prev_probeNum +1);
2186 afsmon_fs_prev_probeNum++;
2188 /* backup the display data of the probe cycle that just completed -
2189 ie., store curr_fsData in prev_fsData */
2191 memcpy((char *)prev_fsData, (char *)curr_fsData, (numFS * sizeof(struct fs_Display_Data)) );
2194 /* initialize curr_fsData but retain the threshold flag information.
2195 The previous state of threshold flags is used in check_fs_thresholds()*/
2197 numBytes = NUM_FS_STAT_ENTRIES * CM_STAT_STRING_LEN;
2198 curr_fsDataP = curr_fsData;
2199 for(i=0; i<numFS; i++) {
2200 curr_fsDataP->probeOK = 0;
2201 curr_fsDataP->ovfCount = 0;
2202 memset((char *)curr_fsDataP->data, 0, numBytes);
2207 /* prev_fsData now contains all the information for the probe cycle
2208 that just completed. Now count the number of threshold overflows for
2209 use in the overview screen */
2211 prev_fsDataP = prev_fsData;
2213 numHosts_onfs_alerts = 0;
2214 for(i=0; i<numFS; i++) {
2215 if (! prev_fsDataP->probeOK ) { /* if probe failed */
2217 numHosts_onfs_alerts++;
2218 } if (prev_fsDataP->ovfCount) { /* overflows ?? */
2219 num_fs_alerts += prev_fsDataP->ovfCount;
2220 numHosts_onfs_alerts++;
2225 fprintf(debugFD,"Number of FS alerts = %d (on %d hosts)\n",
2226 num_fs_alerts, numHosts_onfs_alerts);
2228 /* flag that the data is now ready to be displayed */
2229 fs_Data_Available = 1;
2231 /* call the Overview frame update routine (update only FS info)*/
2232 ovw_refresh(ovw_currPage, OVW_UPDATE_FS);
2234 /* call the File Servers frame update routine */
2235 fs_refresh(fs_currPage, fs_curr_LCol);
2237 } /* display data */
2240 } /* save_FS_data_forDisplay */
2245 /*-----------------------------------------------------------------------
2246 * afsmon_FS_Handler()
2249 * This is the File Server probe Handler. It updates the afsmonitor
2250 * probe counts, fs circular buffer indices and calls the functions
2251 * to process the results of this probe.
2255 * Failure: Exits afsmonitor.
2256 *----------------------------------------------------------------------*/
2260 { /* afsmon_FS_Handler() */
2261 static char rn[] = "afsmon_FS_Handler"; /* routine name */
2262 int newProbeCycle; /* start of new probe cycle ? */
2263 int code; /* return status */
2267 fprintf(debugFD,"[ %s ] Called, hostName= %s, probeNum= %d, status=%s\n",
2269 xstat_fs_Results.connP->hostName,
2270 xstat_fs_Results.probeNum,
2271 xstat_fs_Results.probeOK? "FAILED":"OK");
2276 /* print the probe results to output file */
2277 if (afsmon_output) {
2278 code = afsmon_fsOutput(output_filename, afsmon_detOutput);
2280 fprintf(stderr,"[ %s ] output to file %s returned error code=%d\n",
2281 rn,output_filename,code);
2285 /* Update current probe number and circular buffer index. if current
2286 probenum changed make sure it is only by 1 */
2289 if (xstat_fs_Results.probeNum != afsmon_fs_curr_probeNum) {
2290 if (xstat_fs_Results.probeNum == afsmon_fs_curr_probeNum + 1) {
2291 afsmon_fs_curr_probeNum++;
2294 afsmon_fs_curr_CBindex=
2295 (afsmon_fs_curr_probeNum - 1) % num_bufSlots;
2298 fprintf(stderr,"[ %s ] probe number %d-1 missed\n",
2299 rn,xstat_fs_Results.probeNum);
2304 /* store the results of this probe in the FS circular buffer */
2306 save_FS_results_inCB(newProbeCycle);
2309 /* store the results of the current probe in the fs data display structure.
2310 if the current probe number changed, swap the current and previous display
2311 structures. note that the display screen is updated from these structures
2312 and should start showing the data of the just completed probe cycle */
2314 save_FS_data_forDisplay(&xstat_fs_Results);
2321 /*----------------------------------------------------------------------- *
2326 * Prints the Cache Manager circular buffer
2327 *----------------------------------------------------------------------*/
2331 { /* Print_CM_CB() */
2333 struct afsmon_cm_Results_list *cmlist;
2337 /* print valid info in the cm CB */
2340 fprintf(debugFD,"==================== CM Buffer ========================\n");
2341 fprintf(debugFD,"afsmon_cm_curr_CBindex = %d\n",afsmon_cm_curr_CBindex);
2342 fprintf(debugFD,"afsmon_cm_curr_probeNum = %d\n\n",afsmon_cm_curr_probeNum);
2344 for(i=0; i<num_bufSlots; i++) {
2345 fprintf(debugFD,"\t--------- slot %d ----------\n",i);
2346 cmlist = afsmon_cm_ResultsCB[i].list;
2348 while( j < numCM ) {
2349 if (! cmlist->empty) {
2350 fprintf(debugFD,"\t %d) probeNum = %d host = %s",
2351 j,cmlist->cmResults->probeNum,
2352 cmlist-> cmResults->connP->hostName);
2353 if (cmlist->cmResults->probeOK) fprintf(debugFD," NOTOK\n");
2354 else fprintf(debugFD," OK\n");
2356 fprintf(debugFD,"\t %d) -- empty --\n",j);
2357 cmlist = cmlist->next;
2360 if (cmlist != (struct afsmon_cm_Results_list *)0 )
2361 fprintf(debugFD,"dangling last next ptr cm CB\n");
2367 /*-----------------------------------------------------------------------
2368 * save_CM_results_inCB()
2371 * Saves the results of the latest CM probe in the cm circular
2372 * buffers. If the current probe cycle is in progress the contents
2373 * of xstat_cm_Results are copied to the end of the list of results
2374 * in the current slot (pointed to by afsmon_cm_curr_CBindex). If
2375 * a new probe cycle has started the next slot in the circular buffer
2376 * is initialized and the results copied. Note that the Rx related
2377 * information available in xstat_cm_Results is not copied.
2381 * Failure: Exits afsmonitor.
2382 *----------------------------------------------------------------------*/
2385 save_CM_results_inCB(a_newProbeCycle)
2386 int a_newProbeCycle; /* start of new probe cycle ? */
2388 { /* save_CM_results_inCB() */
2389 static char rn[] = "save_CM_results_inCB"; /* routine name */
2390 struct afsmon_cm_Results_list *tmp_cmlist_item; /* temp cm list item */
2391 struct xstat_cm_ProbeResults *tmp_cmPR; /* temp ptr */
2396 fprintf(debugFD,"[ %s ] Called, a_newProbeCycle= %d\n",rn, a_newProbeCycle);
2400 /* If a new probe cycle started, mark the list in the current buffer
2401 slot empty for resuse. Note that afsmon_cm_curr_CBindex was appropriately
2402 incremented in afsmon_CM_Handler() */
2404 if (a_newProbeCycle) {
2405 tmp_cmlist_item = afsmon_cm_ResultsCB[afsmon_cm_curr_CBindex].list;
2406 for(i=0; i<numCM; i++) {
2407 tmp_cmlist_item->empty = 1;
2408 tmp_cmlist_item = tmp_cmlist_item->next;
2412 /* locate last unused item in list */
2413 tmp_cmlist_item = afsmon_cm_ResultsCB[afsmon_cm_curr_CBindex].list;
2414 for(i=0; i<numCM; i++) {
2415 if (tmp_cmlist_item->empty) break;
2416 tmp_cmlist_item = tmp_cmlist_item->next;
2419 /* if we could not find one we have an inconsistent list */
2420 if ( ! tmp_cmlist_item->empty ) {
2421 fprintf(stderr,"[ %s ] list inconsistency 1. unable to find an empty slot to store results of probenum %d of %s\n",rn,
2422 xstat_cm_Results.probeNum,xstat_cm_Results.connP->hostName);
2426 tmp_cmPR = tmp_cmlist_item->cmResults;
2428 /* copy hostname and probe number and probe time and probe status.
2429 if the probe failed return now */
2431 memcpy(tmp_cmPR->connP->hostName, xstat_cm_Results.connP->hostName, sizeof(xstat_cm_Results.connP->hostName));
2432 tmp_cmPR->probeNum = xstat_cm_Results.probeNum;
2433 tmp_cmPR->probeTime = xstat_cm_Results.probeTime;
2434 tmp_cmPR->probeOK = xstat_cm_Results.probeOK;
2435 if (xstat_cm_Results.probeOK) { /* probeOK = 1 => notOK */
2436 /* we have a nonempty results structure so mark the list item used */
2437 tmp_cmlist_item->empty = 0;
2442 /* copy connection information */
2443 memcpy(&(tmp_cmPR->connP->skt), &(xstat_cm_Results.connP->skt), sizeof(struct sockaddr_in));
2445 /**** NEED TO COPY rx_connection INFORMATION HERE ******/
2447 memcpy(tmp_cmPR->connP->hostName, xstat_cm_Results.connP->hostName, sizeof(xstat_cm_Results.connP->hostName));
2448 tmp_cmPR->collectionNumber = xstat_cm_Results.collectionNumber;
2450 /* copy the probe data information */
2451 tmp_cmPR->data.AFSCB_CollData_len = xstat_cm_Results.data.AFSCB_CollData_len;
2452 memcpy(tmp_cmPR->data.AFSCB_CollData_val, xstat_cm_Results.data.AFSCB_CollData_val, xstat_cm_Results.data.AFSCB_CollData_len * sizeof(afs_int32));
2455 /* we have a valid results structure so mark the list item used */
2456 tmp_cmlist_item->empty = 0;
2458 /* print the stored info - to make sure we copied it right */
2459 /* Print_cm_FullPerfInfo(tmp_cmPR); */
2460 /* Print the cm circular buffer */
2463 } /* save_CM_results_inCB */
2467 /*-----------------------------------------------------------------------
2471 * The results of xstat probes are stored in a string format in
2472 * the arrays curr_cmData and prev_cmData. The information stored in
2473 * prev_cmData is copied to the screen.
2474 * This function converts xstat FS results from longs to strings and
2475 * places them in the given buffer (a pointer to an item in curr_cmData).
2476 * When a probe cycle completes, curr_cmData is copied to prev_cmData
2477 * in afsmon_CM_Handler().
2481 *----------------------------------------------------------------------*/
2484 cm_Results_ltoa(a_cmData,a_cmResults)
2485 struct cm_Display_Data *a_cmData; /* target buffer */
2486 struct xstat_cm_ProbeResults *a_cmResults; /* ptr to xstat cm Results */
2487 { /* cm_Results_ltoa */
2489 static char rn[] = "cm_Results_ltoa"; /* routine name */
2490 struct afs_stats_CMFullPerf *fullP; /* ptr to complete CM stats */
2498 fprintf(debugFD,"[ %s ] Called, a_cmData= %d, a_cmResults= %d\n",
2499 rn, a_cmData, a_cmResults);
2504 fullP = (struct afs_stats_CMFullPerf *)
2505 (xstat_cm_Results.data.AFSCB_CollData_val);
2507 /* There are 4 parts to CM statistics
2508 - Overall performance statistics (including up/down statistics)
2509 - This CMs FS RPC operations info
2510 - This CMs FS RPC errors info
2511 - This CMs FS transfers info
2512 - Authentication info
2513 - [Un]Replicated access info
2516 /* copy overall performance statistics */
2517 srcbuf = (afs_int32 *) &(fullP->perf);
2519 /* we skip the 19 entry, ProtServAddr, so the index must account for this */
2520 for(i=0 ; i<NUM_AFS_STATS_CMPERF_LONGS+1; i++) {
2523 continue; /* skip ProtServerAddr */
2525 sprintf(a_cmData->data[idx], "%d", *srcbuf);
2530 /*printf("Ending index value = %d\n",idx-1);*/
2532 /* server up/down statistics */
2533 /* copy file server up/down stats */
2534 srcbuf = (afs_int32 *) (fullP->perf.fs_UpDown);
2535 numLongs = 2 * (sizeof(struct afs_stats_SrvUpDownInfo) / sizeof(afs_int32));
2536 for(i=0 ; i<numLongs; i++) {
2537 sprintf(a_cmData->data[idx], "%d", *srcbuf);
2542 /*printf("Ending index value = %d\n",idx-1);*/
2544 /* copy volume location server up/down stats */
2545 srcbuf = (afs_int32 *) (fullP->perf.vl_UpDown);
2546 numLongs = 2 * (sizeof(struct afs_stats_SrvUpDownInfo) / sizeof(afs_int32));
2547 for(i=0 ; i<numLongs; i++) {
2548 sprintf(a_cmData->data[idx], "%d", *srcbuf);
2553 /*printf("Ending index value = %d\n",idx-1);*/
2555 /* copy CMs individual FS RPC operations info */
2556 srcbuf = (afs_int32 *) (fullP->rpc.fsRPCTimes);
2557 for(i=0; i<AFS_STATS_NUM_FS_RPC_OPS; i++) {
2558 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* numOps*/
2560 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* numSuccesses */
2562 tmpbuf = srcbuf++; /* sum time */
2563 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2565 tmpbuf = srcbuf++; /* sqr time */
2566 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2568 tmpbuf = srcbuf++; /* min time */
2569 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2571 tmpbuf = srcbuf++; /* max time */
2572 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2576 /*printf("Ending index value = %d\n",idx-1);*/
2578 /* copy CMs individual FS RPC errors info */
2580 srcbuf = (afs_int32 *) (fullP->rpc.fsRPCErrors);
2581 for(i=0; i<AFS_STATS_NUM_FS_RPC_OPS; i++) {
2582 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* server */
2584 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* network */
2586 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* prot */
2588 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* vol */
2590 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* busies */
2592 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* other */
2596 /*printf("Ending index value = %d\n",idx-1);*/
2598 /* copy CMs individual RPC transfers info */
2600 srcbuf = (afs_int32 *) (fullP->rpc.fsXferTimes);
2601 for(i=0; i<AFS_STATS_NUM_FS_XFER_OPS; i++) {
2602 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* numOps*/
2604 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* numSuccesses */
2606 tmpbuf = srcbuf++; /* sum time */
2607 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2609 tmpbuf = srcbuf++; /* sqr time */
2610 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2612 tmpbuf = srcbuf++; /* min time */
2613 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2615 tmpbuf = srcbuf++; /* max time */
2616 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2618 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* sum bytes */
2620 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* min bytes */
2622 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* max bytes */
2624 for(j=0; j<AFS_STATS_NUM_XFER_BUCKETS; j++) {
2625 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* bucket[j] */
2630 /*printf("Ending index value = %d\n",idx-1);*/
2632 /* copy CM operations timings */
2634 srcbuf = (afs_int32 *) (fullP->rpc.cmRPCTimes);
2635 for(i=0; i<AFS_STATS_NUM_CM_RPC_OPS; i++) {
2636 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* numOps*/
2638 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* numSuccesses */
2640 tmpbuf = srcbuf++; /* sum time */
2641 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2643 tmpbuf = srcbuf++; /* sqr time */
2644 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2646 tmpbuf = srcbuf++; /* min time */
2647 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2649 tmpbuf = srcbuf++; /* max time */
2650 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2654 /*printf("Ending index value = %d\n",idx-1);*/
2656 /* copy authentication info */
2658 srcbuf = (afs_int32 *) &(fullP->authent);
2659 numLongs = sizeof(struct afs_stats_AuthentInfo) / sizeof(afs_int32);
2660 for(i=0; i<numLongs; i++) {
2661 sprintf(a_cmData->data[idx], "%d", *srcbuf);
2665 /*printf("Ending index value = %d\n",idx-1);*/
2667 /* copy CM [un]replicated access info */
2669 srcbuf = (afs_int32 *) &(fullP->accessinf);
2670 numLongs = sizeof(struct afs_stats_AccessInfo) / sizeof(afs_int32);
2671 for(i=0; i<numLongs; i++) {
2672 sprintf(a_cmData->data[idx], "%d", *srcbuf);
2676 /*printf("Ending index value = %d\n",idx-1);*/
2679 } /* cm_Results_ltoa */
2682 /*-----------------------------------------------------------------------
2683 * Function: check_cm_thresholds()
2686 * Checks the thresholds and sets the overflow flag. Recall that the
2687 * thresholds for each host are stored in the hostEntry lists
2688 * [fs/cm]nameList arrays. The probe results are passed to this
2689 * function in the display-ready format - ie., as strings. Though
2690 * this looks stupid the overhead incurred in converting the strings
2691 * back to floats and comparing them is insignificant and
2692 * programming is easier this way.
2693 * The threshold flags are a part of the display structures
2698 *----------------------------------------------------------------------*/
2701 check_cm_thresholds(a_hostEntry, a_Data)
2702 struct afsmon_hostEntry *a_hostEntry; /* ptr to hostEntry */
2703 struct cm_Display_Data *a_Data; /* ptr to cm data to be displayed */
2705 { /* check_cm_thresholds */
2707 static char rn[] = "check_cm_thresholds";
2708 struct Threshold *threshP;
2709 double tValue; /* threshold value */
2710 double pValue; /* probe value */
2713 int count; /* number of thresholds exceeded */
2716 fprintf(debugFD,"[ %s ] Called, a_hostEntry= %d, a_Data= %d\n",
2717 rn, a_hostEntry, a_Data);
2721 if (a_hostEntry->numThresh == 0) {
2722 /* store in ovf count ?? */
2727 threshP = a_hostEntry->thresh;
2728 for(i=0; i < a_hostEntry->numThresh; i++) {
2729 if (threshP->itemName[0] == '\0') {
2730 threshP++; continue;
2732 idx = threshP->index; /* positional index to the data array */
2733 tValue = atof(threshP->threshVal); /* threshold value */
2734 pValue = atof(a_Data->data[idx]); /* probe value */
2735 if (pValue > tValue) {
2738 fprintf(debugFD,"[ %s ] cm = %s, thresh ovf for %s, threshold= %s, probevalue= %s\n",
2739 rn, a_hostEntry->hostName, threshP->itemName, threshP->threshVal , a_Data->data[idx]);
2743 /* if the threshold is crossed, call the handler function
2744 only if this was a transition -ie, if the threshold was
2745 crossed in the last probe too just count & keep quite! */
2747 if (! a_Data->threshOvf[idx]) {
2748 a_Data->threshOvf[idx] = 1;
2749 /* call the threshold handler if provided */
2750 if (threshP->handler[0] != '\0') {
2752 fprintf(debugFD,"[ %s ] Calling ovf handler %s\n",
2753 rn, threshP->handler);
2756 execute_thresh_handler(threshP->handler,
2757 a_Data->hostName, CM, threshP->itemName,
2758 threshP->threshVal, a_Data->data[idx]);
2764 /* in case threshold was previously crossed, blank it out */
2765 a_Data->threshOvf[idx] = 0;
2768 /* store the overflow count */
2769 a_Data->ovfCount = count;
2772 } /* check_cm_thresholds */
2775 /*-----------------------------------------------------------------------
2776 * save_CM_data_forDisplay()
2779 * Does the following:
2780 * - if the probe number changed (ie, a cycle completed) curr_cmData
2781 * is copied to prev_cmData, curr_cmData zeroed and refresh the
2782 * overview screen and file server screen with the new data.
2783 * - store the results of the current probe from xstat_cm_Results into
2784 * curr_cmData. ie., convert longs to strings.
2785 * - check the thresholds
2789 * Failure: Exits afsmonitor.
2791 *----------------------------------------------------------------------*/
2794 save_CM_data_forDisplay(a_cmResults)
2795 struct xstat_cm_ProbeResults *a_cmResults;
2796 { /* save_CM_data_forDisplay */
2798 static char rn[] = "save_CM_data_forDisplay"; /* routine name */
2799 struct cm_Display_Data *curr_cmDataP;
2800 struct cm_Display_Data *prev_cmDataP;
2801 struct afsmon_hostEntry *curr_host;
2802 static int probes_Received = 0; /* number of probes reveived in
2803 the current cycle. If this is equal to numFS we got all
2804 the data we want in this cycle and can now display it */
2812 fprintf(debugFD,"[ %s ] Called, a_cmResults= %d\n",rn, a_cmResults);
2816 /* store results in the display array */
2819 curr_cmDataP = curr_cmData;
2820 for (i=0; i<numCM; i++) {
2821 if((strcasecmp(curr_cmDataP->hostName,a_cmResults->connP->hostName)) == 0) {
2829 fprintf(stderr,"[ %s ] Could not insert CM probe results for host %s in cm display array\n",rn, a_cmResults->connP->hostName);
2833 /* Check the status of the probe. If it succeeded, we store its
2834 results in the display data structure. If it failed we only mark
2835 the failed status in the display data structure. */
2838 if (a_cmResults->probeOK) { /* 1 => notOK the xstat results */
2839 curr_cmDataP->probeOK = 0;
2841 /* print the probe status */
2843 fprintf(debugFD,"\n\t\t ----- cm display data ------\n");
2844 fprintf(debugFD,"HostName = %s PROBE FAILED \n",curr_cmDataP->hostName);
2848 } else { /* probe succeeded, update display data structures */
2849 curr_cmDataP->probeOK = 1;
2852 /* covert longs to strings and place them in curr_cmDataP */
2853 cm_Results_ltoa(curr_cmDataP, a_cmResults);
2855 /* compare with thresholds and set the overflow flags.
2856 note that the threshold information is in the hostEntry structure and
2857 each threshold item has a positional index associated with it */
2859 /* locate the hostEntry for this host */
2861 curr_host = CMnameList;
2862 for(i=0; i<numCM; i++) {
2863 if (strcasecmp(curr_host->hostName,a_cmResults->connP->hostName) == 0) {
2867 curr_host = curr_host->next;
2869 if (!done) afsmon_Exit(100);
2871 code = check_cm_thresholds(curr_host, curr_cmDataP);
2873 fprintf(stderr,"[ %s ] Error in checking thresholds\n",rn);
2878 /* print the info we just saved */
2880 fprintf(debugFD,"\n\t\t ----- CM display data ------\n");
2881 fprintf(debugFD,"HostName = %s\n",curr_cmDataP->hostName);
2882 for(i=0; i<NUM_CM_STAT_ENTRIES; i++) {
2884 case 0: fprintf(debugFD,"\t -- Overall Perf Info --\n");
2886 case 39: fprintf(debugFD,"\t -- File Server up/down stats - same cell --\n");
2888 case 64: fprintf(debugFD,"\t -- File Server up/down stats - diff cell --\n");
2890 case 89: fprintf(debugFD,"\t -- VL server up/down stats - same cell --\n");
2892 case 114: fprintf(debugFD,"\t -- VL server up/down stats - diff cell --\n");
2894 case 139: fprintf(debugFD,"\t -- FS Operation Timings --\n");
2896 case 279: fprintf(debugFD,"\t -- FS Error Info --\n");
2898 case 447: fprintf(debugFD,"\t -- FS Transfer Timings --\n");
2900 case 475: fprintf(debugFD,"\t -- CM Operations Timings --\n");
2902 case 510: fprintf(debugFD,"\t -- Authentication Info --\n");
2904 case 522: fprintf(debugFD,"\t -- Access Info --\n");
2909 fprintf(debugFD,"%20s %30s %s\n", curr_cmDataP->data[i],
2910 cm_varNames[i],curr_cmDataP->threshOvf[i] ? "(ovf)":"" );
2912 fprintf(debugFD,"\t\t--------------------------------\n\n");
2915 } /* if the probe succeeded, update the display data structures */
2917 /* if we have received a reply from all the hosts for this probe cycle,
2918 it is time to display the data */
2921 if (probes_Received == numCM) {
2922 probes_Received = 0;
2924 if (afsmon_cm_curr_probeNum != afsmon_cm_prev_probeNum + 1) {
2925 sprintf(errMsg,"[ %s ] Probe number %d missed! \n",
2926 rn, afsmon_cm_prev_probeNum +1);
2929 afsmon_cm_prev_probeNum++;
2932 /* backup the display data of the probe cycle that just completed -
2933 ie., store curr_cmData in prev_cmData */
2935 memcpy((char *)prev_cmData, (char *)curr_cmData, (numCM * sizeof(struct cm_Display_Data)) );
2938 /* initialize curr_cmData but retain the threshold flag information.
2939 The previous state of threshold flags is used in check_cm_thresholds()*/
2941 curr_cmDataP = curr_cmData;
2942 numBytes = NUM_CM_STAT_ENTRIES * CM_STAT_STRING_LEN;
2943 for(i=0; i<numCM; i++) {
2944 curr_cmDataP->probeOK = 0;
2945 curr_cmDataP->ovfCount = 0;
2946 memset((char *)curr_cmDataP->data, 0, numBytes);
2950 /* prev_cmData now contains all the information for the probe cycle
2951 that just completed. Now count the number of threshold overflows for
2952 use in the overview screen */
2954 prev_cmDataP = prev_cmData;
2956 numHosts_oncm_alerts = 0;
2957 for(i=0; i<numCM; i++) {
2958 if (! prev_cmDataP->probeOK) { /* if probe failed */
2960 numHosts_oncm_alerts++;
2961 } else if (prev_cmDataP->ovfCount) { /* overflows ?? */
2962 num_cm_alerts += prev_cmDataP->ovfCount;
2963 numHosts_oncm_alerts++;
2968 fprintf(debugFD,"Number of CM alerts = %d (on %d hosts)\n",
2969 num_cm_alerts, numHosts_oncm_alerts);
2972 /* flag that the data is now ready to be displayed */
2973 cm_Data_Available = 1;
2975 /* update the Overview frame (only CM info)*/
2976 ovw_refresh(ovw_currPage, OVW_UPDATE_CM);
2978 /* update the Cache Managers frame */
2979 cm_refresh(cm_currPage, cm_curr_LCol);
2985 } /* save_CM_data_forDisplay */
2989 /*-----------------------------------------------------------------------
2990 * afsmon_CM_Handler()
2993 * This is the Cache Manager probe Handler. It updates the afsmonitor
2994 * probe counts, cm circular buffer indices and calls the functions
2995 * to process the results of this probe.
2999 * Failure: Exits afsmonitor.
3000 *----------------------------------------------------------------------*/
3004 { /* afsmon_CM_Handler() */
3005 static char rn[] = "afsmon_CM_Handler"; /* routine name */
3006 int code; /* return status */
3007 int newProbeCycle; /* start of new probe cycle ? */
3011 "[ %s ] Called, hostName= %s, probeNum= %d, status= %s\n", rn,
3012 xstat_cm_Results.connP->hostName,
3013 xstat_cm_Results.probeNum,
3014 xstat_cm_Results.probeOK? "FAILED":"OK");
3019 /* print the probe results to output file */
3020 if (afsmon_output) {
3021 code = afsmon_cmOutput(output_filename, afsmon_detOutput);
3023 fprintf(stderr,"[ %s ] output to file %s returned error code=%d\n",
3024 rn,output_filename,code);
3028 /* Update current probe number and circular buffer index. if current
3029 probenum changed make sure it is only by 1 */
3032 if (xstat_cm_Results.probeNum != afsmon_cm_curr_probeNum) {
3033 if (xstat_cm_Results.probeNum == afsmon_cm_curr_probeNum + 1) {
3034 afsmon_cm_curr_probeNum++;
3037 afsmon_cm_curr_CBindex=
3038 (afsmon_cm_curr_probeNum - 1) % num_bufSlots;
3041 fprintf(stderr,"[ %s ] probe number %d-1 missed\n",
3042 rn,xstat_cm_Results.probeNum);
3047 /* save the results of this probe in the CM buffer */
3049 save_CM_results_inCB(newProbeCycle);
3051 /* store the results of the current probe in the cm data display structure.
3052 if the current probe number changed, swap the current and previous display
3053 structures. note that the display screen is updated from these structures
3054 and should start showing the data of the just completed probe cycle */
3056 save_CM_data_forDisplay(&xstat_cm_Results);
3061 /*-----------------------------------------------------------------------
3065 * Allocate and Initialize circular buffers for file servers.
3069 * Failure to allocate memory: exits afsmonitor.
3070 *----------------------------------------------------------------------*/
3074 { /* init_fs_buffers() */
3075 static char rn[] = "init_fs_buffers"; /* routine name */
3076 struct afsmon_fs_Results_list *new_fslist_item; /* ptr for new struct */
3077 struct afsmon_fs_Results_list *tmp_fslist_item; /* temp ptr */
3078 struct xstat_fs_ProbeResults *new_fsPR; /* ptr for new struct */
3085 fprintf(debugFD,"[ %s ] Called\n",rn);
3089 /* allocate memory for the circular buffer of pointers */
3091 afsmon_fs_ResultsCB = (struct afsmon_fs_Results_CBuffer *) malloc(
3092 sizeof(struct afsmon_fs_Results_CBuffer) * num_bufSlots);
3094 /* initialize the fs circular buffer */
3095 for (i=0; i<num_bufSlots; i++) {
3096 afsmon_fs_ResultsCB[i].list = (struct afsmon_fs_Results_list *)0;
3097 afsmon_fs_ResultsCB[i].probeNum = 0;
3100 /* create a list of numFS items to store fs probe results for
3103 if (numFS) { /* if we have file servers to monitor */
3104 for(bufslot=0; bufslot<num_bufSlots; bufslot++) {
3105 numfs = numFS; /* get the number of servers */
3108 /* if any of these mallocs fail we only need to free the memory we
3109 have allocated in this iteration. the rest of it which is in a
3110 proper linked list will be freed in afsmon_Exit */
3112 /* allocate memory for an fs list item */
3113 new_fslist_item = (struct afsmon_fs_Results_list *) malloc (
3114 sizeof(struct afsmon_fs_Results_list));
3115 if (new_fslist_item == (struct afsmon_fs_Results_list *)0)
3118 /* allocate memory to store xstat_fs_Results */
3119 new_fsPR = (struct xstat_fs_ProbeResults *) malloc(
3120 sizeof(struct xstat_fs_ProbeResults));
3121 if (new_fsPR == (struct xstat_fs_ProbeResults *)0) {
3122 free(new_fslist_item);
3125 new_fsPR->connP = (struct xstat_fs_ConnectionInfo *) malloc(
3126 sizeof(struct xstat_fs_ConnectionInfo));
3127 if (new_fsPR->connP == (struct xstat_fs_ConnectionInfo *)0 ) {
3128 free(new_fslist_item);
3133 /* >>> need to allocate rx connection info structure here <<< */
3135 new_fsPR->data.AFS_CollData_val = (afs_int32 *) malloc(
3136 XSTAT_FS_FULLPERF_RESULTS_LEN * sizeof(afs_int32));
3137 if (new_fsPR->data.AFS_CollData_val == (afs_int32 *)0) {
3138 free(new_fslist_item);
3139 free(new_fsPR->connP);
3144 /* initialize this list entry */
3145 new_fslist_item->fsResults = new_fsPR;
3146 new_fslist_item->empty = 1;
3147 new_fslist_item->next = (struct afsmon_fs_Results_list *)0;
3149 /* store it at the end of the fs list in the current CB slot */
3150 if (afsmon_fs_ResultsCB[bufslot].list == (struct afsmon_fs_Results_list *)0)
3151 afsmon_fs_ResultsCB[ bufslot ].list = new_fslist_item;
3153 tmp_fslist_item = afsmon_fs_ResultsCB[ bufslot ].list;
3155 while(tmp_fslist_item != (struct afsmon_fs_Results_list *)0)
3157 if (tmp_fslist_item->next == (struct afsmon_fs_Results_list *)0)
3159 tmp_fslist_item = tmp_fslist_item->next;
3162 /* something goofed. exit */
3163 fprintf(stderr,"[ %s ] list creation error\n",rn);
3167 tmp_fslist_item->next = new_fslist_item;
3170 } /* while servers */
3171 } /* for each buffer slot */
3172 } /* if we have file servers to monitor */
3176 /*-----------------------------------------------------------------------
3180 * Allocate and Initialize circular buffers for cache managers.
3184 * Failure to allocate memory: exits afsmonitor.
3185 *----------------------------------------------------------------------*/
3189 { /* init_cm_buffers() */
3190 static char rn[] = "init_cm_buffers"; /* routine name */
3191 struct afsmon_cm_Results_list *new_cmlist_item; /* ptr for new struct */
3192 struct afsmon_cm_Results_list *tmp_cmlist_item; /* temp ptr */
3193 struct xstat_cm_ProbeResults *new_cmPR; /* ptr for new struct */
3199 fprintf(debugFD,"[ %s ] Called\n",rn);
3203 /* allocate memory for the circular buffer of pointers */
3204 afsmon_cm_ResultsCB = (struct afsmon_cm_Results_CBuffer *) malloc(
3205 sizeof(struct afsmon_cm_Results_CBuffer) * num_bufSlots);
3207 /* initialize the fs circular buffer */
3208 for (i=0; i<num_bufSlots; i++) {
3209 afsmon_cm_ResultsCB[i].list = (struct afsmon_cm_Results_list *)0;
3210 afsmon_cm_ResultsCB[i].probeNum = 0;
3213 /* create a list of numCM items to store fs probe results for
3216 if (numCM) { /* if we have file servers to monitor */
3217 for(bufslot=0; bufslot<num_bufSlots; bufslot++) {
3218 numcm = numCM; /* get the number of servers */
3221 /* if any of these mallocs fail we only need to free the memory we
3222 have allocated in this iteration. the rest of it which is in a
3223 proper linked list will be freed in afsmon_Exit */
3225 /* allocate memory for an fs list item */
3226 new_cmlist_item = (struct afsmon_cm_Results_list *) malloc (
3227 sizeof(struct afsmon_cm_Results_list));
3228 if (new_cmlist_item == (struct afsmon_cm_Results_list *)0)
3231 /* allocate memory to store xstat_cm_Results */
3232 new_cmPR = (struct xstat_cm_ProbeResults *) malloc(
3233 sizeof(struct xstat_cm_ProbeResults));
3234 if (new_cmPR == (struct xstat_cm_ProbeResults *)0) {
3235 free(new_cmlist_item);
3238 new_cmPR->connP = (struct xstat_cm_ConnectionInfo *) malloc(
3239 sizeof(struct xstat_cm_ConnectionInfo));
3240 if (new_cmPR->connP == (struct xstat_cm_ConnectionInfo *)0 ) {
3241 free(new_cmlist_item);
3246 /* >>> need to allocate rx connection info structure here <<< */
3248 new_cmPR->data.AFSCB_CollData_val = (afs_int32 *) malloc(
3249 XSTAT_CM_FULLPERF_RESULTS_LEN * sizeof(afs_int32));
3250 if (new_cmPR->data.AFSCB_CollData_val == (afs_int32 *)0) {
3251 free(new_cmlist_item);
3252 free(new_cmPR->connP);
3257 /* initialize this list entry */
3258 new_cmlist_item->cmResults = new_cmPR;
3259 new_cmlist_item->empty = 1;
3260 new_cmlist_item->next = (struct afsmon_cm_Results_list *)0;
3262 /* store it at the end of the cm list in the current CB slot */
3263 if (afsmon_cm_ResultsCB[bufslot].list == (struct afsmon_cm_Results_list *)0)
3264 afsmon_cm_ResultsCB[ bufslot ].list = new_cmlist_item;
3266 tmp_cmlist_item = afsmon_cm_ResultsCB[ bufslot ].list;
3268 while(tmp_cmlist_item != (struct afsmon_cm_Results_list *)0)
3270 if (tmp_cmlist_item->next == (struct afsmon_cm_Results_list *)0)
3272 tmp_cmlist_item = tmp_cmlist_item->next;
3275 /* something goofed. exit */
3276 fprintf(stderr,"[ %s ] list creation error\n",rn);
3280 tmp_cmlist_item->next = new_cmlist_item;
3283 } /* while servers */
3284 } /* for each buffer slot */
3285 } /* if we have file servers to monitor */
3286 /* print the CB to make sure it is right */
3290 } /* init_cm_buffers() */
3293 /*-------------------------------------------------------------------------
3294 * init_print_buffers()
3297 * Allocate and initialize the buffers used for printing results
3298 * to the display screen. These buffers store the current and
3299 * previous probe results in ascii format.
3304 *------------------------------------------------------------------------*/
3307 init_print_buffers()
3308 { /* init_print_buffers */
3310 static char rn[] = "init_print_buffers"; /* routine name */
3311 struct fs_Display_Data *tmp_fsData1; /* temp pointers */
3312 struct fs_Display_Data *tmp_fsData2;
3313 struct cm_Display_Data *tmp_cmData1;
3314 struct cm_Display_Data *tmp_cmData2;
3315 struct afsmon_hostEntry *tmp_fsNames;
3316 struct afsmon_hostEntry *tmp_cmNames;
3321 fprintf(debugFD,"[ %s ] Called\n",rn);
3325 /* allocate numFS blocks of the FS print structure. */
3327 /* we need two instances of this structure - one (curr_fsData) for storing
3328 the results of the fs probes currently in progress and another (prev_fsData)
3329 for the last completed probe. The display is updated from the contents of
3330 prev_fsData. The pointers curr_fsData & prev_fsData are switched whenever
3331 the probe number changes */
3334 numBytes = numFS * sizeof(struct fs_Display_Data);
3335 curr_fsData = (struct fs_Display_Data *) malloc(numBytes);
3336 if (curr_fsData == (struct fs_Display_Data *)0) {
3337 fprintf(stderr,"[ %s ] Memory allocation failure\n",rn);
3340 memset(curr_fsData, 0, numBytes);
3342 numBytes = numFS * sizeof(struct fs_Display_Data);
3343 prev_fsData = (struct fs_Display_Data *) malloc(numBytes);
3344 if (prev_fsData == (struct fs_Display_Data *)0) {
3345 fprintf(stderr,"[ %s ] Memory allocation failure\n",rn);
3348 memset(prev_fsData, 0, numBytes);
3350 /* fill in the host names */
3351 tmp_fsData1 = curr_fsData;
3352 tmp_fsData2 = curr_fsData;
3353 tmp_fsNames = FSnameList;
3354 for(i=0; i<numFS; i++) {
3355 strncpy(tmp_fsData1->hostName, tmp_fsNames->hostName, HOST_NAME_LEN);
3356 strncpy(tmp_fsData2->hostName, tmp_fsNames->hostName, HOST_NAME_LEN);
3359 tmp_fsNames = tmp_fsNames->next;;
3362 } /* if file servers to monitor */
3364 /* allocate numCM blocks of the CM print structure */
3365 /* we need two instances of this structure for the same reasons as above*/
3368 numBytes = numCM * sizeof(struct cm_Display_Data);
3370 curr_cmData = (struct cm_Display_Data *) malloc(numBytes);
3371 if (curr_cmData == (struct cm_Display_Data *)0) {
3372 fprintf(stderr,"[ %s ] Memory allocation failure\n",rn);
3375 memset(curr_cmData, 0, numBytes);
3377 numBytes = numCM * sizeof(struct cm_Display_Data);
3378 prev_cmData = (struct cm_Display_Data *) malloc(numBytes);
3379 if (prev_cmData == (struct cm_Display_Data *)0) {
3380 fprintf(stderr,"[ %s ] Memory allocation failure\n",rn);
3383 memset(prev_cmData, 0, numBytes);
3385 /* fill in the host names */
3386 tmp_cmData1 = curr_cmData;
3387 tmp_cmData2 = curr_cmData;
3388 tmp_cmNames = CMnameList;
3389 for(i=0; i<numCM; i++) {
3390 strncpy(tmp_cmData1->hostName, tmp_cmNames->hostName, HOST_NAME_LEN);
3391 strncpy(tmp_cmData2->hostName, tmp_cmNames->hostName, HOST_NAME_LEN);
3394 tmp_cmNames = tmp_cmNames->next;;
3397 } /* if cache managers to monitor */
3401 } /* init_print_buffers */
3403 /*-----------------------------------------------------------------------
3407 * Trap the interrupt signal. This function is useful only until
3408 * gtx is initialized.
3409 *----------------------------------------------------------------------*/
3415 static char *rn = "quit_signal"; /* routine name */
3417 fprintf(stderr,"Received signal %d \n",sig);
3423 /*-----------------------------------------------------------------------
3427 * This is where we start it all. Initialize an array of sockets for
3428 * file servers and cache cache managers and call the xstat_[fs/cm]_Init
3429 * routines. The last step is to call the gtx input server which
3430 * grabs control of the keyboard.
3433 * Does not return. Control is periodically returned to the afsmonitor
3434 * thru afsmon_[FS/CM]_Handler() routines and also through the gtx
3435 * keyboard handler calls.
3437 *----------------------------------------------------------------------*/
3441 { /* afsmon_execute() */
3442 static char rn[] = "afsmon_execute"; /* routine name */
3443 static char fullhostname[128]; /* full host name */
3444 struct sockaddr_in *FSSktArray; /* fs socket array */
3445 int FSsktbytes; /* num bytes in above */
3446 struct sockaddr_in *CMSktArray; /* cm socket array */
3447 int CMsktbytes; /* num bytes in above */
3448 struct sockaddr_in *curr_skt; /* ptr to current socket*/
3449 struct afsmon_hostEntry *curr_FS; /* ptr to FS name list */
3450 struct afsmon_hostEntry *curr_CM; /* ptr to CM name list */
3451 struct hostent *he; /* host entry */
3452 afs_int32 *collIDP; /* ptr to collection ID */
3453 int numCollIDs; /* number of collection IDs */
3454 int FSinitFlags = 0; /* flags for xstat_fs_Init */
3455 int CMinitFlags = 0; /* flags for xstat_cm_Init */
3456 int code; /* function return code */
3457 struct timeval tv; /* time structure */
3460 fprintf(debugFD,"[ %s ] Called\n",rn);
3465 /* process file server entries */
3467 /* Allocate an array of sockets for each fileserver we monitor */
3469 FSsktbytes = numFS * sizeof(struct sockaddr_in);
3470 FSSktArray = (struct sockaddr_in *) malloc(FSsktbytes);
3471 if (FSSktArray == (struct sockaddr_in *)0) {
3472 fprintf(stderr,"[ %s ] cannot malloc %d sockaddr_ins for fileservers\n",
3477 memset(FSSktArray, 0, FSsktbytes);
3479 /* Fill in the socket information for each fileserve */
3481 curr_skt = FSSktArray;
3482 curr_FS = FSnameList; /* FS name list header */
3484 strncpy(fullhostname,curr_FS->hostName,sizeof(fullhostname));
3485 he = GetHostByName(fullhostname);
3486 if (he == (struct hostent *)0) {
3487 fprintf(stderr,"[ %s ] Cannot get host info for %s\n",rn, fullhostname);
3490 strncpy(curr_FS->hostName,he->h_name,HOST_NAME_LEN); /* complete name*/
3491 memcpy(&(curr_skt->sin_addr.s_addr), he->h_addr, 4);
3492 curr_skt->sin_family = htons(AF_INET); /*Internet family*/
3493 curr_skt->sin_port = htons(7000); /*FileServer port*/
3495 /* get the next dude */
3497 curr_FS = curr_FS->next;
3500 /* initialize collection IDs. We need only one entry since we collect
3501 all the information from xstat */
3504 collIDP = (afs_int32 *) malloc (sizeof (afs_int32));
3505 if (collIDP == (afs_int32 *)0) {
3506 fprintf(stderr,"[ %s ] failed to allocate a measely afs_int32 word.Argh!\n", rn);
3509 *collIDP = 2; /* USE A macro for this */
3512 if (afsmon_onceOnly) /* option not provided at this time */
3513 FSinitFlags |= XSTAT_FS_INITFLAG_ONE_SHOT;
3516 fprintf(debugFD,"[ %s ] Calling xstat_fs_Init \n",rn);
3520 code = xstat_fs_Init(numFS, /*Num servers*/
3521 FSSktArray, /*File Server socket array*/
3522 afsmon_probefreq, /*probe frequency*/
3523 afsmon_FS_Handler, /*Handler routine*/
3524 FSinitFlags, /*Initialization flags*/
3525 numCollIDs, /*Number of collection IDs*/
3526 collIDP); /*Ptr to collection ID */
3529 fprintf(stderr,"[ %s ] xstat_fs_init returned error\n",rn);
3533 } /* end of process fileserver entries */
3535 /* process cache manager entries */
3538 /* Allocate an array of sockets for each cache manager we monitor */
3540 CMsktbytes = numCM * sizeof(struct sockaddr_in);
3541 CMSktArray = (struct sockaddr_in *) malloc(CMsktbytes);
3542 if (CMSktArray == (struct sockaddr_in *)0) {
3543 fprintf(stderr,"[ %s ] cannot malloc %d sockaddr_ins for CM entries\n",
3548 memset(CMSktArray, 0, CMsktbytes);
3550 /* Fill in the socket information for each CM */
3552 curr_skt = CMSktArray;
3553 curr_CM = CMnameList; /* CM name list header */
3555 strncpy(fullhostname,curr_CM->hostName,sizeof(fullhostname));
3556 he = GetHostByName(fullhostname);
3557 if (he == (struct hostent *)0) {
3558 fprintf(stderr,"[ %s ] Cannot get host info for %s\n",rn, fullhostname);
3561 strncpy(curr_CM->hostName,he->h_name,HOST_NAME_LEN); /* complete name*/
3562 memcpy(&(curr_skt->sin_addr.s_addr), he->h_addr, 4);
3563 curr_skt->sin_family = htons(AF_INET); /*Internet family*/
3564 curr_skt->sin_port = htons(7001); /*Cache Manager port*/
3566 /* get the next dude */
3568 curr_CM = curr_CM->next;
3571 /* initialize collection IDs. We need only one entry since we collect
3572 all the information from xstat */
3575 collIDP = (afs_int32 *) malloc (sizeof (afs_int32));
3576 if (collIDP == (afs_int32 *)0) {
3577 fprintf(stderr,"[ %s ] failed to allocate a measely long word.Argh!\n", rn);
3580 *collIDP = 2; /* USE A macro for this */
3583 if (afsmon_onceOnly) /* once only ? */
3584 CMinitFlags |= XSTAT_CM_INITFLAG_ONE_SHOT;
3587 fprintf(debugFD,"[ %s ] Calling xstat_cm_Init \n",rn);
3591 code = xstat_cm_Init(numCM, /*Num servers*/
3592 CMSktArray, /*Cache Manager socket array*/
3593 afsmon_probefreq, /*probe frequency*/
3594 afsmon_CM_Handler, /*Handler routine*/
3595 CMinitFlags, /*Initialization flags*/
3596 numCollIDs, /*Number of collection IDs*/
3597 collIDP); /*Ptr to collection ID */
3600 fprintf(stderr,"[ %s ] xstat_cm_init returned error\n",rn);
3603 } /* end of process cache manager entries */
3606 /* if only one probe was required setup a waiting process for the
3607 termination signal */
3609 if (afsmon_onceOnly) {
3610 code = LWP_WaitProcess(&terminationEvent);
3613 fprintf(debugFD,"LWP_WaitProcess() returned error %d\n",code);
3620 /* start the gtx input server */
3621 code = gtx_InputServer(afsmon_win);
3623 fprintf(stderr,"[ %s ] Failed to start input server \n",rn);
3627 /* This part of the code is reached only if the input server is not started
3628 for debugging purposes */
3633 fprintf(stderr,"[ %s ] going to sleep ...\n",rn);
3635 code = IOMGR_Select( 0, /*Num fds*/
3636 0, /*Descriptors ready for reading*/
3637 0, /*Descriptors ready for writing*/
3638 0, /*Descriptors with exceptional conditions*/
3639 &tv); /*Timeout structure*/
3641 fprintf(stderr,"[ %s ] IOMGR_Select() returned non-zero value %d\n",
3649 /*-----------------------------------------------------------------------
3653 * Afsmonitor initialization routine.
3654 * - processes command line parameters
3655 * - call functions to:
3656 * - process config file
3657 * - initialize circular buffers and display buffers
3659 * - execute afsmonitor
3660 * - initialize the display maps [fs/cm]_Display_map[].
3663 * Success: Does not return from the call to afsmon_execute().
3664 * Failure: Exits afsmonitor.
3665 *----------------------------------------------------------------------*/
3669 struct cmd_syndesc *as;
3670 { /* afsmonInit() */
3672 static char rn[] = "afsmonInit"; /* Routine name */
3673 char *debug_filename; /* pointer to debug filename */
3674 FILE *outputFD; /* output file descriptor */
3675 struct cmd_item *hostPtr; /* ptr to parse command line args */
3676 char buf[256]; /* buffer for processing hostnames */
3681 fprintf(debugFD,"[ %s ] Called, as= %d\n",rn, as);
3685 /* Open the debug file if -debug option is specified */
3686 if (as->parms[P_DEBUG].items != 0) {
3688 debug_filename = as->parms[P_DEBUG].items->data;
3689 debugFD = fopen(debug_filename, "w");
3690 if (debugFD == (FILE *)0) {
3691 printf("[ %s ] Failed to open debugging file %s for writing\n",
3699 fprintf(debugFD,"[ %s ] Called\n", rn);
3703 /* use curses always until we support other packages */
3705 wpkg_to_use = atoi(as->parms[P_PACKAGE].items->data);
3707 switch (wpkg_to_use) {
3708 case GATOR_WIN_CURSES:
3709 fprintf(stderr, "curses\n");
3711 case GATOR_WIN_DUMB:
3712 fprintf(stderr, "dumb terminal\n");
3715 fprintf(stderr, "X11\n");
3718 fprintf(stderr, "Illegal graphics package: %d\n", wpkg_to_use);
3720 } /*end switch (wpkg_to_use)*/
3723 wpkg_to_use = GATOR_WIN_CURSES;
3725 /* get probe frequency . We check for meaningful bounds on the frequency
3726 and reset to the default value if needed. The upper bound of 24
3727 hours looks ridiculous though! */
3729 afsmon_probefreq = 0;
3730 if (as->parms[P_FREQUENCY].items != 0)
3731 afsmon_probefreq = atoi(as->parms[P_FREQUENCY].items->data);
3733 afsmon_probefreq = DEFAULT_FREQUENCY;
3735 if (afsmon_probefreq <= 0 || afsmon_probefreq > 24*60*60) {
3736 afsmon_probefreq = DEFAULT_FREQUENCY;
3738 fprintf(debugFD,"[ %s ] Invalid probe frequency %s specified, resetting to default value %d seconds\n",
3739 rn, as->parms[P_FREQUENCY].items->data, afsmon_probefreq);
3742 fprintf(stderr,"Invalid probe frequency %s specified, resetting to default value %d seconds\n",
3743 as->parms[P_FREQUENCY].items->data, afsmon_probefreq);
3748 /* make sure output file is writable, else complain now */
3749 /* we will open and close it as needed after probes */
3751 if (as->parms[P_OUTPUT].items != 0) {
3752 afsmon_output = 1; /* output flag */
3753 strncpy (output_filename, as->parms[P_OUTPUT].items->data,80);
3754 outputFD = fopen(output_filename,"a");
3755 if (outputFD == (FILE *)0) {
3756 fprintf(stderr,"Failed to open output file %s \n",
3759 fprintf(debugFD,"[ %s ] Failed to open output file %s \n",
3760 rn, output_filename);
3765 fprintf(debugFD,"[ %s ] output file is %s\n",rn,output_filename);
3770 /* detailed statistics to storage file */
3771 if (as->parms[P_DETAILED].items !=0) {
3772 if (as->parms[P_OUTPUT].items == 0) {
3773 fprintf(stderr,"-detailed switch can be used only with -output\n");
3776 afsmon_detOutput = 1;
3779 /* Initialize host list headers */
3780 FSnameList = (struct afsmon_hostEntry *)0;
3781 CMnameList = (struct afsmon_hostEntry *)0;
3783 /* The -config option is mutually exclusive with the -fshosts,-cmhosts
3786 if (as->parms[P_CONFIG].items) {
3787 if (as->parms[P_FSHOSTS].items || as->parms[P_CMHOSTS].items) {
3788 fprintf(stderr,"Cannot use -config option with -fshosts or -cmhosts\n");
3792 if (! as->parms[P_FSHOSTS].items && ! as->parms[P_CMHOSTS].items) {
3793 fprintf(stderr,"Must specify either -config or (-fshosts and/or -cmhosts) options \n");
3799 /* If a file server host is specified on the command line we reuse
3800 parse_hostEntry() function . Just the pass the info as if it were
3801 read off the config file */
3803 if (as->parms[P_FSHOSTS].items) {
3804 hostPtr = as->parms[P_FSHOSTS].items;
3805 while( hostPtr != (struct cmd_item *)0) {
3806 sprintf(buf,"fs %s",hostPtr->data);
3807 code = parse_hostEntry(buf);
3809 fprintf(stderr,"Could not parse %s\n",hostPtr->data);
3813 hostPtr = hostPtr->next;
3817 /* same as above for -cmhosts */
3818 if (as->parms[P_CMHOSTS].items) {
3819 hostPtr = as->parms[P_CMHOSTS].items;
3820 while( hostPtr != (struct cmd_item *)0) {
3821 sprintf(buf,"cm %s",hostPtr->data);
3822 code = parse_hostEntry(buf);
3824 fprintf(stderr,"Could not parse %s\n",hostPtr->data);
3828 hostPtr = hostPtr->next;
3832 /* number of slots in circular buffers */
3833 if (as->parms[P_BUFFERS].items)
3834 num_bufSlots = atoi(as->parms[P_BUFFERS].items->data);
3836 num_bufSlots = DEFAULT_BUFSLOTS;
3838 /* Initialize xx_showFlags[]. This array is used solely for processing the
3839 "show" directives in the config file in parse_showEntries() */
3840 for(i=0; i<NUM_FS_STAT_ENTRIES; i++)
3841 fs_showFlags[i] = 0;
3842 for(i=0; i<NUM_CM_STAT_ENTRIES; i++)
3843 cm_showFlags[i] = 0;
3846 /* Process the configuration file if given. This initializes among other
3847 things, the list of FS & CM names in FSnameList and CMnameList */
3849 if (as->parms[P_CONFIG].items)
3850 process_config_file(as->parms[P_CONFIG].items->data);
3852 /* print out the FS and CM lists */
3853 print_FS(); print_CM();
3855 /* Initialize the FS results-to-screen map array if there were no "show fs"
3856 directives in the config file */
3857 if (fs_showDefault) {
3858 for(i=0; i < NUM_FS_STAT_ENTRIES; i++)
3859 fs_Display_map[i] = i;
3860 fs_DisplayItems_count = NUM_FS_STAT_ENTRIES;
3863 /* Initialize the CM results-to-screen map array if there were no "show cm"
3864 directives in the config file */
3865 if (cm_showDefault) {
3866 for(i=0; i < NUM_CM_STAT_ENTRIES; i++)
3867 cm_Display_map[i] = i;
3868 cm_DisplayItems_count = NUM_CM_STAT_ENTRIES;
3873 /* setup an interrupt signal handler; we ain't wanna leak core */
3874 /* this binding is useful only until gtx is initialized after which the
3875 keyboard input server takes over. */
3876 if ( (signal(SIGINT,quit_signal)) == SIG_ERR ) {
3877 perror("signal() failed.");
3882 /* init error message buffers. these will be used to print error messages
3883 once gtx is initialized and there is no access to stderr/stdout */
3884 errMsg[0] = '\0'; errMsg1[0] = '\0';
3888 /* initialize fs and cm circular buffers before initiating probes */
3890 code = init_fs_buffers();
3892 fprintf(stderr,"[ %s ] init_fs_buffers returned %d\n",rn,code);
3898 code = init_cm_buffers();
3900 fprintf(stderr,"[ %s ] init_cm_buffers returned %d\n",rn,code);
3906 /* allocate and initialize buffers for holding fs & cm results in ascii
3907 format suitable for updating the screen */
3908 code = init_print_buffers();
3910 fprintf(stderr,"[ %s ] init_print_buffers returned %d\n",rn,code);
3914 /* perform gtx initializations */
3915 code = gtx_initialize();
3917 fprintf(stderr,"[ %s ] gtx_initialize returned %d\n",rn,code);
3921 /* start xstat probes */
3924 return(0); /* will not return from the call to afsmon_execute() */
3926 } /* afsmonInit() */
3929 /*-----------------------------------------------------------------------
3931 ------------------------------------------------------------------------*/
3933 #include "AFS_component_version_number.c"
3935 int main(argc, argv)
3940 static char rn[] = "main"; /* routine name */
3941 afs_int32 code; /*Return code*/
3942 struct cmd_syndesc *ts; /*Ptr to cmd line syntax descriptor*/
3944 #ifdef AFS_AIX32_ENV
3946 * The following signal action for AIX is necessary so that in case of a
3947 * crash (i.e. core is generated) we can include the user's data section
3948 * in the core dump. Unfortunately, by default, only a partial core is
3949 * generated which, in many cases, isn't too useful.
3951 struct sigaction nsa;
3953 sigemptyset(&nsa.sa_mask);
3954 nsa.sa_handler = SIG_DFL;
3955 nsa.sa_flags = SA_FULLDUMP;
3956 sigaction(SIGSEGV, &nsa, NULL);
3960 * Set up the commands we understand.
3962 ts = cmd_CreateSyntax("initcmd", afsmonInit, 0,
3963 "initialize the program");
3964 cmd_AddParm(ts, "-config", CMD_SINGLE, CMD_OPTIONAL,
3965 "configuration file");
3966 cmd_AddParm(ts, "-frequency", CMD_SINGLE, CMD_OPTIONAL,
3967 "poll frequency, in seconds");
3968 cmd_AddParm(ts, "-output", CMD_SINGLE, CMD_OPTIONAL,
3969 "storage file name");
3970 cmd_AddParm(ts, "-detailed", CMD_FLAG, CMD_OPTIONAL,
3971 "output detailed statistics to storage file");
3973 /* we hope to use this .... eventually! */
3974 cmd_AddParm(ts,"-package", CMD_SINGLE, CMD_REQUIRED,
3975 "Graphics Package to use");
3977 cmd_AddParm(ts, "-debug", CMD_SINGLE, CMD_OPTIONAL,
3978 "turn debugging output on to the named file");
3979 cmd_AddParm(ts, "-fshosts", CMD_LIST, CMD_OPTIONAL,
3980 "list of file servers to monitor");
3981 cmd_AddParm(ts, "-cmhosts", CMD_LIST, CMD_OPTIONAL,
3982 "list of cache managers to monitor");
3983 cmd_AddParm(ts,"-buffers", CMD_SINGLE, CMD_OPTIONAL,
3984 "number of buffer slots");
3987 * Parse command-line switches & execute afsmonitor
3990 code = cmd_Dispatch(argc, argv);
3996 exit(0); /* redundant, but gets rid of warning */