2 * Copyright 2000, International Business Machines Corporation and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
11 * Afsmonitor: An AFS Performance Monitoring Tool
13 *-------------------------------------------------------------------------*/
22 #include <afs/param.h>
23 #include <afsconfig.h>
27 #include <sys/types.h>
28 #include <netinet/in.h>
30 #include <sys/socket.h>
35 #include <gtxwindows.h> /*Generic window package*/
36 #include <gtxobjects.h> /*Object definitions*/
38 #include <gtxtextobj.h> /*Text object interface*/
40 #include <gtxlightobj.h> /*Light object interface*/
41 #include <gtxcurseswin.h> /*Curses window package*/
42 #include <gtxdumbwin.h> /*Dumb terminal window package*/
43 #include <gtxX11win.h> /*X11 window package*/
44 #include <gtxframe.h> /*Frame package*/
48 #include <afs/xstat_fs.h>
49 #include <afs/xstat_cm.h>
52 #include "afsmonitor.h"
55 /* command line parameter indices */
61 /* #define P_PACKAGE X */
68 int afsmon_debug = 0; /* debug info to file ? */
69 FILE *debugFD; /* debugging file descriptor */
70 static int afsmon_output = 0; /* output to file ? */
71 static int afsmon_detOutput = 0; /* detailed output ? */
72 static int afsmon_onceOnly = 0; /* probe once only ? (not implemented) */
73 int afsmon_probefreq; /* probe frequency */
74 static int wpkg_to_use; /* graphics package to use */
75 static char output_filename[80];/* output filename */
76 char errMsg[256]; /* buffers used to print error messages after*/
77 char errMsg1[256]; /* gtx is initialized (stderr/stdout gone !) */
78 int num_bufSlots = 0; /* number of slots in fs & cm circular buffers*/
80 /* Flags used to process "show" directives in config file */
81 short fs_showFlags[NUM_FS_STAT_ENTRIES];
82 short cm_showFlags[NUM_CM_STAT_ENTRIES];
85 /* afsmonitor misc definitions */
87 #define DEFAULT_FREQUENCY 60 /* default proble frequency in seconds */
88 #define DEFAULT_BUFSLOTS 0 /* default number of buffer slots */
89 #define CFG_STR_LEN 80 /* max length of config file fields */
90 #define FS 1 /* for misc. use */
91 #define CM 2 /* for misc. use */
94 #define NUM_XSTAT_FS_AFS_PERFSTATS_LONGS 66 /* number of fields (longs) in struct afs_PerfStats that we display */
95 #define NUM_AFS_STATS_CMPERF_LONGS 40 /* number of longs in struct afs_stats_CMPerf excluding up/down stats and fields we dont display */
98 /* variables used for exec'ing user provided threshold handlers */
99 char *fsHandler_argv[20]; /* *argv[] for the handler */
100 char fsHandler_args[20][256]; /* buffer space for arguments */
101 int exec_fsThreshHandler = 0; /* execute fs threshold handler ? */
104 /* THRESHOLD STRUCTURE DEFINITIONS */
106 /* flag to indicate that threshold entries apply to all hosts. these will
107 be turned off when the first fs or cm host entry is processed */
108 static int global_ThreshFlag = 1;
109 static int global_fsThreshCount = 0; /* number of global fs thresholds */
110 static int global_cmThreshCount = 0; /* number of global cm thresholds */
114 /* Linked lists of file server and cache manager host names are made from
115 the entries in the config file. Head pointers to FS and CM server name lists. */
116 static struct afsmon_hostEntry *FSnameList;
117 static struct afsmon_hostEntry *CMnameList;
119 /* number of fileservers and cache managers to monitor */
123 /* variables used for processing config file */
124 /* ptr to the hostEntry structure of the last "fs" or "cm" entry processed
125 in the config file */
126 static struct afsmon_hostEntry *last_hostEntry;
127 /* names of the last host processed in the config file */
128 static char last_fsHost[HOST_NAME_LEN];
129 static char last_cmHost[HOST_NAME_LEN];
130 static lastHostType = 0; /* 0 = no host entries processed
131 1 = last host was file server
132 2 = last host was cache manager. */
135 /* FILE SERVER CIRCULAR BUFFER VARIABLES */
137 struct afsmon_fs_Results_list {
138 struct xstat_fs_ProbeResults *fsResults; /* ptr to results struct*/
139 int empty; /* fsResults empty ? */
140 struct afsmon_fs_Results_list *next;
143 struct afsmon_fs_Results_CBuffer {
144 int probeNum; /* probe number of entries in this slot */
145 struct afsmon_fs_Results_list *list; /* ptr to list of results */
148 /* buffer for FS probe results */
149 struct afsmon_fs_Results_CBuffer *afsmon_fs_ResultsCB;
151 int afsmon_fs_curr_CBindex = 0; /* current fs CB slot */
153 /* Probe number variables. The current probe number is incremented
154 when the first probe from a new probe cycle is received. The prev probe
155 number is incremented when the last probe of the current cycle is
156 received. This difference is because of the purpose for which these
159 int afsmon_fs_curr_probeNum = 1; /* current fs probe number */
160 int afsmon_fs_prev_probeNum = 0; /* previous fs probe number */
163 /* CACHE MANAGER CIRCULAR BUFFER VARIABLES */
165 struct afsmon_cm_Results_list {
166 struct xstat_cm_ProbeResults *cmResults; /* ptr to results struct*/
167 int empty; /* cmResults empty ? */
168 struct afsmon_cm_Results_list *next;
171 struct afsmon_cm_Results_CBuffer {
172 int probeNum; /* probe number of entries in this slot */
173 struct afsmon_cm_Results_list *list; /* ptr to list of results */
176 /* buffer for CM probe results */
177 struct afsmon_cm_Results_CBuffer *afsmon_cm_ResultsCB;
179 int afsmon_cm_curr_CBindex = 0; /* current cm CB slot */
182 /* Probe number variables. The current probe number is incremented
183 when the first probe from a new probe cycle is received. The prev probe
184 number is incremented when the last probe of the current cycle is
185 received. This difference is because of the purpose for which these
188 int afsmon_cm_curr_probeNum = 1; /* current cm probe number */
189 int afsmon_cm_prev_probeNum = 0; /* previous cm probe number */
192 /* Structures to hold FS & CM results in string format(suitable for display ) */
194 /* ptr to array holding the results of FS probes in ascii format */
195 /* for current probe cycle */
196 struct fs_Display_Data *curr_fsData = (struct fs_Display_Data *)0;
197 /* for previous probe cycle */
198 struct fs_Display_Data *prev_fsData = (struct fs_Display_Data *)0;
201 /* ptr to array holding the results of CM probes in ascii format */
202 /* for current probe cycle */
203 struct cm_Display_Data *curr_cmData = (struct cm_Display_Data *)0;
204 /* for previous probe cycle */
205 struct cm_Display_Data *prev_cmData = (struct cm_Display_Data *)0;
208 /* EXTERN DEFINITIONS */
210 extern struct hostent *hostutil_GetHostByName();
214 /* routines from afsmon-output.c */
215 extern int afsmon_fsOutput();
216 extern int afsmon_cmOutput();
218 /* file server and cache manager variable names (from afsmon_labels.h) */
219 extern char *fs_varNames[];
220 extern char *cm_varNames[];
222 /* GTX & MISC VARIABLES */
224 /* afsmonitor window */
225 extern struct gwin *afsmon_win;
227 /* current page number in the overview frame */
228 extern int ovw_currPage;
230 /* number of FS alerts and number of hosts on FS alerts */
232 int numHosts_onfs_alerts;
234 /* number of CM alerts and number of hosts on FS alerts */
236 int numHosts_oncm_alerts;
238 /* flag to indicate that atleast one probe cycle has completed and
239 data is available for updating the display */
240 extern fs_Data_Available;
241 extern cm_Data_Available;
243 extern int gtx_initialized; /* gtx initialized ? */
245 /* This array contains the indices of the file server data items that
246 are to be displayed on the File Servers screen. For example, suppose the
247 user wishes to display only the vcache statistics then the following array
248 will contain indices 2 to 14 corresponding to the position of the
249 vcache data items in the fs_varNames[] array. If the config file contains
250 no "show fs .." directives, it will contain the indices of all the
251 items in the fs_varNames[] array */
253 short fs_Display_map[XSTAT_FS_FULLPERF_RESULTS_LEN];
254 int fs_DisplayItems_count = 0; /* number of items to display */
255 int fs_showDefault = 1; /* show all of FS data ? */
258 /* same use as above for Cache Managers */
259 short cm_Display_map[XSTAT_CM_FULLPERF_RESULTS_LEN];
260 int cm_DisplayItems_count = 0; /* number of items to display */
261 int cm_showDefault = 1; /* show all of CM data ? */
263 extern int fs_currPage; /* current page number in the File Servers frame */
264 extern int fs_curr_LCol; /* current leftmost column on display on FS frame */
266 extern int cm_currPage; /* current page number in the Cache Managers frame */
267 extern int cm_curr_LCol; /* current leftmost column on display on CM frame */
269 /* File server and Cache manager data is classified into sections &
270 groups to help the user choose what he wants displayed */
271 extern char *fs_categories[]; /* file server data category names */
272 extern char *cm_categories[]; /* cache manager data category names */
277 strcasestr(): Return first occurence of pattern s2 in s1, case
280 This routine is required since I made pattern matching of the
281 config file to be case insensitive.
284 char *strcasestr(s1,s2)
295 return ((char *)NULL);
299 while( len1 >= len2 && len1 > 0 ) {
300 if ( (strncasecmp(ptr,s2,len2)) == 0)
305 return ((char *)NULL);
309 struct hostent *GetHostByName(name)
317 he = gethostbyname(name);
319 /* On solaris the above does not resolve hostnames to full names */
320 if (he != (struct hostent *)0) {
321 bcopy(he->h_addr, ip_addr, he->h_length);
322 he = gethostbyaddr(ip_addr, he->h_length, he->h_addrtype);
329 /*-----------------------------------------------------------------------
333 * Exit gracefully from the afsmonitor. Frees memory where appropriate,
334 * cleans up after gtx and closes all open file descriptors. If a user
335 * provided threshold handler is to be exec'ed then gtx cleanup is
336 * not performed and an exec() is made instead of an exit().
342 * This function is called to execute a user handler only
343 * by a child process.
345 *----------------------------------------------------------------------*/
348 afsmon_Exit(a_exitVal)
349 int a_exitVal; /* exit code */
351 static char rn[] = "afsmon_Exit";
352 struct afsmon_fs_Results_list *tmp_fslist;
353 struct afsmon_fs_Results_list *next_fslist;
354 struct xstat_fs_ProbeResults *tmp_xstat_fsPR;
355 struct afsmon_cm_Results_list *tmp_cmlist;
356 struct afsmon_cm_Results_list *next_cmlist;
357 struct xstat_cm_ProbeResults *tmp_xstat_cmPR;
358 struct afsmon_hostEntry *curr_hostEntry;
359 struct afsmon_hostEntry *prev_hostEntry;
366 fprintf(debugFD,"[ %s ] Called with exit code %d\n",rn, a_exitVal);
370 /* get out of curses first, but not if we are here to exec a threshold
371 handler. If we do, the screen gets messed up */
372 if (gtx_initialized && ! exec_fsThreshHandler)
373 gator_cursesgwin_cleanup(afsmon_win);
375 /* print the error message buffer */
376 if (errMsg[0] != '\0')
377 fprintf(stderr,"%s",errMsg);
378 if (errMsg1[0] != '\0')
379 fprintf(stderr,"%s",errMsg1);
381 /* deallocate file server circular buffers */
382 if (numFS && num_bufSlots) {
384 fprintf(debugFD,"freeing FS circular buffers ");
388 for (bufslot=0; bufslot<num_bufSlots; bufslot++) {
390 fprintf(debugFD," %d) ",bufslot);
391 if (afsmon_fs_ResultsCB[bufslot].list !=
392 (struct afsmon_fs_Results_list *)0 ) {
393 tmp_fslist = afsmon_fs_ResultsCB[bufslot].list;
395 while ( tmp_fslist ) {
396 /* make sure we do not go astray */
399 fprintf(debugFD,"[ %s ] error in deallocating fs CB\n",
403 next_fslist = tmp_fslist->next;
404 tmp_xstat_fsPR = tmp_fslist->fsResults;
407 fprintf(debugFD,"%d ",numFS-j);
409 /* free xstat_fs_Results data */
410 free(tmp_xstat_fsPR->data.AFS_CollData_val);
411 free(tmp_xstat_fsPR->connP);
412 free(tmp_xstat_fsPR);
414 /* free the fs list item */
416 tmp_fslist = next_fslist;
418 } /* while fs list items in this slot */
419 } /* if entries in this buffer slot */
420 } /* for each fs buffer slot */
422 fprintf(debugFD,"\n");
427 /* deallocate cache manager curcular buffers */
428 if (numCM && num_bufSlots) {
430 fprintf(debugFD,"freeing CM curcular buffers ");
431 for (bufslot=0; bufslot<num_bufSlots; bufslot++) {
433 fprintf(debugFD," %d) ",bufslot);
434 if (afsmon_cm_ResultsCB[bufslot].list !=
435 (struct afsmon_cm_Results_list *)0 ) {
436 tmp_cmlist = afsmon_cm_ResultsCB[bufslot].list;
438 while ( tmp_cmlist ) {
439 /* make sure we do not go astray */
442 fprintf(debugFD,"[ %s ] error in deallocating cm CB\n",
446 next_cmlist = tmp_cmlist->next;
447 tmp_xstat_cmPR = tmp_cmlist->cmResults;
450 fprintf(debugFD,"%d ",numCM-j);
451 /* make sure data is ok */
452 /* Print_cm_FullPerfInfo(tmp_xstat_cmPR); */
454 /* free xstat_cm_Results data */
455 free(tmp_xstat_cmPR->data.AFSCB_CollData_val);
456 free(tmp_xstat_cmPR->connP);
457 free(tmp_xstat_cmPR);
459 /* free the cm list item */
461 tmp_cmlist = next_cmlist;
463 } /* while cm list items in this slot */
464 } /* if entries in this buffer slot */
465 } /* for each cm buffer slot */
467 fprintf(debugFD,"\n");
471 /* deallocate FS & CM Print buffers */
472 if (curr_fsData != (struct fs_Display_Data *)0) {
474 fprintf(debugFD,"Deallocating FS Print Buffers .... curr");
477 if (prev_fsData != (struct fs_Display_Data *)0) {
479 fprintf(debugFD,", prev \n");
482 if (prev_cmData != (struct cm_Display_Data *)0) {
484 fprintf(debugFD,"Deallocating CM Print Buffers .... curr");
487 if (prev_cmData != (struct cm_Display_Data *)0) {
489 fprintf(debugFD,", prev \n");
493 /* deallocate hostEntry lists */
496 fprintf(debugFD,"Deallocating FS hostEntries ..");
497 curr_hostEntry = FSnameList;
498 for(i=0; i<numFS; i++) {
499 prev_hostEntry = curr_hostEntry;
500 if (curr_hostEntry->thresh != (struct Threshold *)0)
501 free(curr_hostEntry->thresh);
502 free(curr_hostEntry);
504 fprintf(debugFD," %d",i);
505 curr_hostEntry = prev_hostEntry->next;
508 fprintf(debugFD,"\n");
512 fprintf(debugFD,"Deallocating CM hostEntries ..");
513 curr_hostEntry = CMnameList;
514 for(i=0; i<numCM; i++) {
515 prev_hostEntry = curr_hostEntry;
516 if (curr_hostEntry->thresh != (struct Threshold *)0)
517 free(curr_hostEntry->thresh);
518 free(curr_hostEntry);
520 fprintf(debugFD," %d",i);
521 curr_hostEntry = prev_hostEntry->next;
524 fprintf(debugFD,"\n");
527 /* close debug file */
533 if (exec_fsThreshHandler) {
534 code = execvp(fsHandler_argv[0],fsHandler_argv);
536 fprintf(stderr,"execvp() of %s returned %d, errno %d\n",
537 fsHandler_argv[0], code, errno);
545 /*-----------------------------------------------------------------------
549 * Insert a hostname in the file server names list.
554 *----------------------------------------------------------------------*/
557 insert_FS( a_hostName )
558 char *a_hostName; /* name of cache manager to be inserted in list */
560 static char rn[] = "insert_FS"; /* routine name */
561 static struct afsmon_hostEntry *curr_item;
562 static struct afsmon_hostEntry *prev_item;
564 if ( *a_hostName == '\0')
566 curr_item = (struct afsmon_hostEntry *)
567 malloc(sizeof(struct afsmon_hostEntry));
568 if (curr_item == (struct afsmon_hostEntry *)0) {
569 fprintf(stderr,"Failed to allocate space for FS nameList\n");
573 strncpy(curr_item->hostName,a_hostName,CFG_STR_LEN);
574 curr_item->next = (struct afsmon_hostEntry *)0;
575 curr_item->numThresh = 0;
576 curr_item->thresh = (struct Threshold *)0;
578 if (FSnameList == (struct afsmon_hostEntry *)0)
579 FSnameList = curr_item;
581 prev_item->next = curr_item;
583 prev_item = curr_item;
584 /* record the address of this entry so that its threshold
585 count can be incremented during the first pass of the config file */
586 last_hostEntry = curr_item;
591 /*-----------------------------------------------------------------------
596 * Prints the file server names linked list.
600 *----------------------------------------------------------------------*/
604 static char rn[] = "print_FS";
605 struct afsmon_hostEntry *tempFS;
606 struct Threshold *threshP;
610 fprintf(debugFD,"[ %s ] Called\n",rn);
616 fprintf(debugFD,"No of File Servers: %d\n",numFS);
619 fprintf(debugFD,"\t %s threshCount = %d\n",
620 tempFS->hostName,tempFS->numThresh);
621 threshP = tempFS->thresh;
622 for(i=0; i<tempFS->numThresh; i++,threshP++)
623 fprintf(debugFD,"\t thresh (%2d) %s %s %s\n",
624 threshP->index, threshP->itemName,
625 threshP->threshVal,threshP->handler);
626 } while ( (tempFS = tempFS->next) != (struct afsmon_hostEntry *)0);
628 fprintf(debugFD,"\t\t-----End of List-----\n");
634 /*-----------------------------------------------------------------------
638 * Insert a hostname in the cache manager names list.
643 *----------------------------------------------------------------------*/
646 insert_CM( a_hostName )
647 char *a_hostName; /* name of cache manager to be inserted in list */
649 static char rn[] = "insert_CM"; /* routine name */
650 static struct afsmon_hostEntry *curr_item;
651 static struct afsmon_hostEntry *prev_item;
653 if ( *a_hostName == '\0')
655 curr_item = (struct afsmon_hostEntry *)
656 malloc(sizeof(struct afsmon_hostEntry));
657 if (curr_item == (struct afsmon_hostEntry *)0) {
658 fprintf(stderr,"Failed to allocate space for CM nameList\n");
662 strncpy(curr_item->hostName,a_hostName,CFG_STR_LEN);
663 curr_item->next = (struct afsmon_hostEntry *)0;
664 curr_item->numThresh = 0;
665 curr_item->thresh = (struct Threshold *)0;
667 if (CMnameList == (struct afsmon_hostEntry *)0)
668 CMnameList = curr_item;
670 prev_item->next = curr_item;
672 prev_item = curr_item;
673 /* side effect. note the address of this entry so that its threshold
674 count can be incremented during the first pass of the config file */
675 last_hostEntry = curr_item;
681 /*-----------------------------------------------------------------------
686 * Prints the cache manager names linked list.
690 *----------------------------------------------------------------------*/
694 static char rn[] = "print_CM";
695 struct afsmon_hostEntry *tempCM;
696 struct Threshold *threshP;
700 fprintf(debugFD,"[ %s ] Called\n",rn);
706 fprintf(debugFD,"No of Cache Managers: %d\n",numCM);
709 fprintf(debugFD,"\t %s threshCount = %d\n",
710 tempCM->hostName,tempCM->numThresh);
711 threshP = tempCM->thresh;
712 for(i=0; i<tempCM->numThresh; i++,threshP++)
713 fprintf(debugFD,"\t thresh (%2d) %s %s %s\n",
714 threshP->index, threshP->itemName,
715 threshP->threshVal,threshP->handler);
716 } while ( (tempCM = tempCM->next) != (struct afsmon_hostEntry *)0);
718 fprintf(debugFD,"\t\t-----End of List-----\n");
725 /*-----------------------------------------------------------------------
729 * Parse the host entry line in the config file. Check the syntax,
730 * and inserts the host name in the FS ot CM linked list. Also
731 * remember if this entry was an fs or cm & the ptr to its hostEntry
732 * structure. The threshold entries in the config file are dependent
733 * on their position relative to the hostname entries. Hence it is
734 * required to remember the names of the last file server and cache
735 * manager entries that were processed.
741 *----------------------------------------------------------------------*/
744 parse_hostEntry(a_line)
746 { /* parse_hostEntry */
748 static char rn[] = "parse_hostEntry"; /* routine name */
749 char opcode[CFG_STR_LEN]; /* specifies type of config entry */
750 char arg1[CFG_STR_LEN]; /* hostname or qualifier (fs/cm?) */
751 char arg2[CFG_STR_LEN]; /* threshold variable */
752 char arg3[CFG_STR_LEN]; /* threshold value */
753 char arg4[CFG_STR_LEN]; /* user's handler */
754 struct hostent *he; /* host entry */
757 fprintf(debugFD,"[ %s ] Called, a_line = %s\n",rn, a_line);
762 opcode[0] = 0;arg1[0] = 0;arg2[0] = 0;arg3[0] = 0;arg4[0] = 0;
763 sscanf(a_line,"%s %s %s %s %s",opcode,arg1,arg2,arg3,arg4);
764 /* syntax is "opcode hostname" */
765 if ((strlen(arg2)) != 0) {
766 fprintf(stderr,"[ %s ] Extraneous characters at end of line\n", rn);
771 he = GetHostByName(arg1);
772 if ( he == (struct hostent *)0) {
773 fprintf(stderr,"[ %s ] Unable to resolve hostname %s\n",
778 if ((strcasecmp(opcode,"fs")) == 0) {
779 /* use the complete host name to insert in the file server names list */
780 insert_FS(he->h_name);
781 /* note that last host entry in the config file was fs */
784 /* threholds are not global anymore */
785 if (global_ThreshFlag) global_ThreshFlag = 0;
787 else if ((strcasecmp(opcode,"cm")) == 0) {
788 /* use the complete host name to insert in the CM names list */
789 insert_CM(he->h_name);
790 /* last host entry in the config file was cm */
793 /* threholds are not global anymore */
794 if (global_ThreshFlag) global_ThreshFlag = 0;
802 /*-----------------------------------------------------------------------
803 * parse_threshEntry()
806 * Parse the threshold entry line in the config file. This function is
807 * called in the the first pass of the config file. It checks the syntax
808 * of the config lines and verifies their positional validity - eg.,
809 * a cm threshold cannot appear after a fs hostname entry, etc.
810 * It also counts the thresholds applicable to each host.
816 *----------------------------------------------------------------------*/
819 parse_threshEntry(a_line)
821 { /* parse_threshEntry */
822 static char rn[] = "parse_threshEntry"; /* routine name */
823 char opcode[CFG_STR_LEN]; /* specifies type of config entry */
824 char arg1[CFG_STR_LEN]; /* hostname or qualifier (fs/cm?) */
825 char arg2[CFG_STR_LEN]; /* threshold variable */
826 char arg3[CFG_STR_LEN]; /* threshold value */
827 char arg4[CFG_STR_LEN]; /* user's handler */
828 char arg5[CFG_STR_LEN]; /* junk characters */
831 fprintf(debugFD,"[ %s ] Called, a_line = %s\n",rn, a_line);
836 opcode[0] = 0;arg1[0] = 0;arg2[0] = 0;arg3[0] = 0;arg4[0] = 0;arg5[0] = 0;
837 sscanf(a_line,"%s %s %s %s %s %s",opcode,arg1,arg2,arg3,arg4,arg5);
839 /* syntax is "thresh fs/cm variable_name threshold_value [handler] " */
840 if (((strlen(arg1)) == 0)||((strlen(arg2)) == 0)||((strlen(arg3)) == 0)) {
841 fprintf(stderr,"[ %s ] Incomplete line\n", rn);
844 if (strlen(arg3) > THRESH_VAR_LEN-2) {
845 fprintf(stderr,"[%s ] threshold value too long\n", rn);
849 if ((strcasecmp(arg1,"fs")) == 0) {
850 switch (lastHostType) {
851 case 0: /* its a global threshold */
852 global_fsThreshCount++;
854 case 1: /* inc thresh count of last file server */
855 last_hostEntry->numThresh++;
858 fprintf(stderr,"[ %s ] A threshold for a File Server cannot be placed after a Cache Manager host entry in the config file \n",rn);
861 fprintf(stderr,"[ %s ] Programming error 1\n",rn);
864 } else if ((strcasecmp(arg1,"cm")) == 0) {
865 switch (lastHostType) {
866 case 0: /* its a global threshold */
867 global_cmThreshCount++;
869 case 2: /* inc thresh count of last cache manager */
870 last_hostEntry->numThresh++;
873 fprintf(stderr,"[ %s ] A threshold for a Cache Manager cannot be placed after a File Server host entry in the config file \n",rn);
876 fprintf(stderr,"[ %s ] Programming error 2\n",rn);
879 } else if ((strcasecmp(arg1,"cm")) != 0 && (strcasecmp(arg1,"cm")) != 0 ) {
880 fprintf(stderr,"[ %s ] Syntax error. Second argument should be \"fs\" or \"cm\" \n",rn);
885 } /* parse_threshEntry */
888 /*-----------------------------------------------------------------------
892 * The thresholds applicable to each host machine are stored in the
893 * FSnameList and CMnameList. Threshold entries in the config file are
894 * context sensitive. The host to which this threshold is applicable
895 * is pointed to by last_fsHost (for file servers) and last_cmHost
896 * for cache managers. For global thresholds the info is recorded for
897 * all the hosts. This function is called in the second pass of the
898 * config file. In the first pass a count of the number of global
899 * thresholds is determined and this information is used in this
900 * routine. If threshold entries are duplicated the first entry is
902 * Each threshold entry also has an index field. This is a positional
903 * index to the corresponding variable in the prev_[fs/cm]Data arrays.
904 * This makes it easy to check the threshold for overflow.
909 *----------------------------------------------------------------------*/
912 store_threshold(a_type,a_varName,a_value,a_handler)
913 int a_type; /* 1 = fs , 2 = cm */
914 char *a_varName; /* threshold name */
915 char *a_value; /* threshold value */
916 char *a_handler; /* threshold overflow handler */
918 { /* store_thresholds */
920 static char rn[] = "store_thresholds"; /* routine name */
921 struct afsmon_hostEntry *tmp_host; /* tmp ptr to hostEntry */
922 struct afsmon_hostEntry *Header; /* tmp ptr to hostEntry list header*/
923 struct Threshold *threshP; /* tmp ptr to threshold list */
925 int index; /* index to fs_varNames or cm_varNames */
928 int srvCount; /* tmp count of host names */
929 int *global_TC; /* ptr to global_xxThreshCount */
933 fprintf(debugFD,"[ %s ] Called, a_type= %d, a_varName= %s, a_value= %s, a_handler=%s\n",rn, a_type, a_varName, a_value, a_handler);
937 /* resolve the threshold variable name */
939 if (a_type == 1) { /* fs threshold */
940 for(index=0; index < NUM_FS_STAT_ENTRIES ; index++) {
941 if (strcasecmp(a_varName,fs_varNames[index]) == 0) {
947 fprintf(stderr,"[ %s ] Unknown FS threshold variable name %s\n",
953 hostname = last_fsHost;
954 global_TC = &global_fsThreshCount;
955 } else if (a_type == 2) { /* cm threshold */
956 for(index=0; index < NUM_CM_STAT_ENTRIES; index++) {
957 if (strcasecmp(a_varName,cm_varNames[index]) == 0) {
963 fprintf(stderr,"[ %s ] Unknown CM threshold variable name %s\n",
969 hostname = last_cmHost;
970 global_TC = &global_cmThreshCount;
976 /* if the global thresh count is not zero, place this threshold on
977 all the host entries */
981 for(i=0; i<srvCount; i++) {
982 threshP = tmp_host->thresh;
984 for(j=0; j<tmp_host->numThresh; j++) {
985 if ( (threshP->itemName[0] == '\0') ||
986 (strcasecmp(threshP->itemName,a_varName) == 0) ) {
987 strncpy(threshP->itemName,a_varName,THRESH_VAR_NAME_LEN);
988 strncpy(threshP->threshVal,a_value,THRESH_VAR_LEN);
989 strcpy(threshP->handler,a_handler);
990 threshP->index = index;
997 fprintf(stderr,"[ %s ] Could not insert threshold entry",rn);
998 fprintf(stderr,"for %s in thresh list of host %s \n",
999 a_varName,tmp_host->hostName);
1002 tmp_host = tmp_host->next;
1008 /* it is not a global threshold, insert it in the thresh list of this
1009 host only. We overwrite the global threshold if it was alread set */
1011 if (*hostname == '\0') {
1012 fprintf(stderr,"[ %s ] Programming error 3\n",rn);
1016 /* get the hostEntry that this threshold belongs to */
1019 for(i=0; i < srvCount; i++) {
1020 if (strcasecmp(tmp_host->hostName,hostname) == 0) {
1024 tmp_host = tmp_host->next;
1027 fprintf(stderr,"[ %s ] Unable to find host %s in %s hostEntry list",
1028 rn,hostname,(a_type-1)?"CM":"FS");
1032 /* put this entry on the thresh list of this host, overwrite global value
1035 threshP = tmp_host->thresh;
1037 for(i=0; i < tmp_host->numThresh; i++) {
1038 if ( (threshP->itemName[0] == '\0') ||
1039 (strcasecmp(threshP->itemName,a_varName) == 0) ) {
1040 strncpy(threshP->itemName,a_varName,THRESH_VAR_NAME_LEN);
1041 strncpy(threshP->threshVal,a_value,THRESH_VAR_LEN);
1042 strcpy(threshP->handler,a_handler);
1043 threshP->index = index;
1051 fprintf(stderr,"[ %s ] Unable to insert threshold %s for %s host %s\n",
1052 rn, a_varName, (a_type -1)?"CM":"FS", tmp_host->hostName);
1058 } /* store_thresholds */
1061 /*-----------------------------------------------------------------------
1065 * This function process a "show" entry in the config file. A "show"
1066 * entry specifies what statistics the user wants to see. File
1067 * server and Cache Manager data is divided into sections. Each section
1068 * is made up of one or more groups. If a group name is specified only
1069 * those statistics under that group are shown. If a section name is
1070 * specified all the groups under this section are shown.
1071 * Data as obtained from the xstat probes is considered to be ordered.
1072 * This data is mapped to the screen thru fs_Display_map[] and
1073 * cm_Display_map[]. This routine parses the "show" entry against the
1074 * section/group names in the [fs/cm]_categories[] array. If there is
1075 * no match it tries to match it against a variable name in
1076 * [fs/cm]_varNames[] array. In each case the corresponding indices to
1077 * the data is the [fs/cm]_displayInfo[] is recorded.
1081 * Failure: -1 (invalid entry)
1082 * > -1 (programming error)
1083 *----------------------------------------------------------------------*/
1086 parse_showEntry(a_line)
1088 { /* parse_showEntry */
1089 static char rn[] = "parse_showEntry";
1090 char opcode[CFG_STR_LEN]; /* specifies type of config entry */
1091 char arg1[CFG_STR_LEN]; /* show fs or cm entry ? */
1092 char arg2[CFG_STR_LEN]; /* what we gotta show */
1093 char arg3[CFG_STR_LEN]; /* junk */
1094 char catName[CFG_STR_LEN]; /* for category names */
1095 int numGroups; /* number of groups in a section */
1099 int idx = 0; /* index to fs_categories[] */
1105 fprintf(debugFD,"[ %s ] Called, a_line= %s\n",rn, a_line);
1108 opcode[0] = 0; arg1[0] = 0; arg2[0] = 0; arg3[0] = 0;
1109 sscanf(a_line,"%s %s %s %s", opcode, arg1, arg2, arg3);
1111 if (arg3[0] != '\0') {
1112 fprintf(stderr,"[ %s ] Extraneous characters at end of line\n",rn);
1116 if ((strcasecmp(arg1,"fs") != 0) && (strcasecmp(arg1,"cm") != 0)) {
1117 fprintf(stderr,"[ %s ] Second argument of \"show\" directive should be \"fs\" or \"cm\" \n",rn);
1121 /* Each entry can either be a variable name or a section/group name. Variable
1122 names are listed in xx_varNames[] and section/group names in xx_categories[].
1123 The section/group names in xx_categiries[] also give the starting/ending
1124 indices of the variables belonging to that section/group. These indices
1125 are stored in order in xx_Display_map[] and displayed to the screen in that
1128 /* To handle duplicate "show" entries we keep track of what what we have
1129 already marked to show in the xx_showFlags[] */
1131 if (strcasecmp(arg1,"fs") == 0) { /* its a File Server entry */
1133 /* mark that we have to show only what the user wants */
1136 /* if it is a section/group name, find it in the fs_categories[] array */
1139 if ( strcasestr(arg2,"_section") != (char *)NULL ||
1140 strcasestr(arg2,"_group") != (char *)NULL ) {
1142 while(idx<FS_NUM_DATA_CATEGORIES) {
1143 sscanf(fs_categories[idx],"%s %d %d",catName, &fromIdx, &toIdx);
1145 if (strcasecmp(arg2, catName) == 0) {
1151 if (! found) { /* typo in section/group name */
1152 fprintf(stderr,"[ %s ] Could not find section/group name %s\n",rn,arg2);
1157 /* if it is a group name, read its start/end indices and fill in the
1158 fs_Display_map[]. */
1160 if (strcasestr(arg2,"_group") != (char *)NULL ) {
1162 if (fromIdx < 0 || toIdx < 0 || fromIdx > NUM_FS_STAT_ENTRIES ||
1163 toIdx > NUM_FS_STAT_ENTRIES)
1165 for(j=fromIdx; j<=toIdx; j++) {
1166 if (! fs_showFlags[j]) {
1167 fs_Display_map[fs_DisplayItems_count] = j;
1168 fs_DisplayItems_count++;
1169 fs_showFlags[j] = 1;
1171 if (fs_DisplayItems_count > NUM_FS_STAT_ENTRIES) {
1172 fprintf(stderr,"[ %s ] fs_DisplayItems_count ovf\n",rn);
1178 /* if it is a section name, get the count of number of groups in it and
1179 for each group fill in the start/end indices in the fs_Display_map[] */
1181 if (strcasestr(arg2,"_section") != (char *)NULL ) {
1182 /* fromIdx is actually the number of groups in thi section */
1183 numGroups = fromIdx;
1184 /* for each group in section */
1185 while(idx < FS_NUM_DATA_CATEGORIES && numGroups) {
1186 sscanf(fs_categories[idx],"%s %d %d",catName, &fromIdx, &toIdx);
1188 if (strcasestr(catName,"_group") != (char *)0) {
1189 if (fromIdx < 0 || toIdx < 0 || fromIdx > NUM_FS_STAT_ENTRIES ||
1190 toIdx > NUM_FS_STAT_ENTRIES)
1192 for(j=fromIdx; j<=toIdx; j++) {
1193 if (! fs_showFlags[j]) {
1194 fs_Display_map[fs_DisplayItems_count] = j;
1195 fs_DisplayItems_count++;
1196 fs_showFlags[j] = 1;
1198 if (fs_DisplayItems_count > NUM_FS_STAT_ENTRIES) {
1199 fprintf(stderr,"[ %s ] fs_DisplayItems_count ovf\n",rn);
1204 fprintf(stderr,"[ %s ] Error parsing groups for %s\n",rn,arg2);
1209 } /* for each group in section */
1212 } else { /* it is a variable name */
1214 for(i=0; i<NUM_FS_STAT_ENTRIES; i++) {
1215 if (strcasecmp(arg2, fs_varNames[i]) == 0) {
1216 if (! fs_showFlags[i]) {
1217 fs_Display_map[fs_DisplayItems_count] = i;
1218 fs_DisplayItems_count++;
1219 fs_showFlags[i] = 1;
1221 if (fs_DisplayItems_count >= NUM_FS_STAT_ENTRIES) {
1222 fprintf(stderr,"[ %s ] fs_DisplayItems_count ovf\n",rn);
1228 if (! found) { /* typo in section/group name */
1229 fprintf(stderr,"[ %s ] Could not find variable name %s\n",rn,arg2);
1232 } /* its a variable name */
1234 } /* it is an fs entry */
1237 if (strcasecmp(arg1,"cm") == 0) { /* its a Cache Manager entry */
1240 /* mark that we have to show only what the user wants */
1243 /* if it is a section/group name, find it in the cm_categories[] array */
1246 if ( strcasestr(arg2,"_section") != (char *)NULL ||
1247 strcasestr(arg2,"_group") != (char *)NULL ) {
1249 while(idx<CM_NUM_DATA_CATEGORIES) {
1250 sscanf(cm_categories[idx],"%s %d %d",catName, &fromIdx, &toIdx);
1252 if (strcasecmp(arg2, catName) == 0) {
1258 if (! found) { /* typo in section/group name */
1259 fprintf(stderr,"[ %s ] Could not find section/group name %s\n",rn,arg2);
1264 /* if it is a group name, read its start/end indices and fill in the
1265 cm_Display_map[]. */
1267 if (strcasestr(arg2,"_group") != (char *)NULL ) {
1269 if (fromIdx < 0 || toIdx < 0 || fromIdx > NUM_CM_STAT_ENTRIES ||
1270 toIdx > NUM_CM_STAT_ENTRIES)
1272 for(j=fromIdx; j<=toIdx; j++) {
1273 if (! cm_showFlags[j]) {
1274 cm_Display_map[cm_DisplayItems_count] = j;
1275 cm_DisplayItems_count++;
1276 cm_showFlags[j] = 1;
1278 if (cm_DisplayItems_count > NUM_CM_STAT_ENTRIES) {
1279 fprintf(stderr,"[ %s ] cm_DisplayItems_count ovf\n",rn);
1285 /* if it is a section name, get the count of number of groups in it and
1286 for each group fill in the start/end indices in the cm_Display_map[] */
1288 if (strcasestr(arg2,"_section") != (char *)NULL ) {
1289 /* fromIdx is actually the number of groups in thi section */
1290 numGroups = fromIdx;
1291 /* for each group in section */
1292 while(idx < CM_NUM_DATA_CATEGORIES && numGroups) {
1293 sscanf(cm_categories[idx],"%s %d %d",catName, &fromIdx, &toIdx);
1295 if (strcasestr(catName,"_group") != (char *)0) {
1296 if (fromIdx < 0 || toIdx < 0 || fromIdx > NUM_CM_STAT_ENTRIES ||
1297 toIdx > NUM_CM_STAT_ENTRIES)
1299 for(j=fromIdx; j<=toIdx; j++) {
1300 if (! cm_showFlags[j]) {
1301 cm_Display_map[cm_DisplayItems_count] = j;
1302 cm_DisplayItems_count++;
1303 cm_showFlags[j] = 1;
1305 if (cm_DisplayItems_count > NUM_CM_STAT_ENTRIES) {
1306 fprintf(stderr,"[ %s ] cm_DisplayItems_count ovf\n",rn);
1311 fprintf(stderr,"[ %s ] Error parsing groups for %s\n",rn,arg2);
1316 } /* for each group in section */
1323 } else { /* it is a variable name */
1325 for(i=0; i<NUM_CM_STAT_ENTRIES; i++) {
1326 if (strcasecmp(arg2, cm_varNames[i]) == 0) {
1327 if (! cm_showFlags[i]) {
1328 cm_Display_map[cm_DisplayItems_count] = i;
1329 cm_DisplayItems_count++;
1330 cm_showFlags[i] = 1;
1332 if (cm_DisplayItems_count >= NUM_CM_STAT_ENTRIES) {
1333 fprintf(stderr,"[ %s ] cm_DisplayItems_count ovf\n",rn);
1339 if (! found) { /* typo in section/group name */
1340 fprintf(stderr,"[ %s ] Could not find variable name %s\n",rn,arg2);
1343 } /* its a variable name */
1345 } /* it is an cm entry */
1350 } /* parse_showEntry */
1353 /*-----------------------------------------------------------------------
1354 * process_config_file()
1357 * Parse config file entries in two passes. In the first pass:
1358 * - the syntax of all the entries is checked
1359 * - host names are noted and the FSnamesList and CMnamesList
1361 * - a count of the global thresholds and local thresholds of
1362 * each host are counted.
1363 * - "show" entries are processed.
1364 * In the second pass:
1365 * - thresholds are stored
1369 * Failure: Exits afsmonitor showing error and line.
1370 *----------------------------------------------------------------------*/
1373 process_config_file(a_config_filename)
1374 char *a_config_filename;
1375 { /* process_config_file() */
1376 static char rn[] = "process_config_file"; /* routine name */
1377 FILE *configFD; /* config file descriptor */
1378 char line[4*CFG_STR_LEN]; /* a line of config file */
1379 char opcode[CFG_STR_LEN]; /* specifies type of config entry */
1380 char arg1[CFG_STR_LEN]; /* hostname or qualifier (fs/cm?) */
1381 char arg2[CFG_STR_LEN]; /* threshold variable */
1382 char arg3[CFG_STR_LEN]; /* threshold value */
1383 char arg4[CFG_STR_LEN]; /* user's handler */
1384 struct afsmon_hostEntry *curr_host;
1385 struct hostent *he; /* hostentry to resolve host name*/
1386 char *handlerPtr; /* ptr to pass theresh handler string */
1387 int code = 0; /* error code */
1388 int linenum = 0; /* config file line number */
1389 int threshCount; /* count of thresholds for each server */
1390 int error_in_config; /* syntax errors in config file ?? */
1395 fprintf(debugFD,"[ %s ] Called, a_config_filename= %s\n",
1396 rn, a_config_filename);
1400 /* open config file */
1402 configFD = fopen(a_config_filename,"r");
1403 if (configFD == (FILE *)0) {
1404 fprintf(stderr,"Failed to open config file %s \n",a_config_filename);
1406 fprintf(debugFD,"[ %s ] Failed to open config file %s \n",
1407 rn, a_config_filename);
1413 /* parse config file */
1415 /* We process the config file in two passes. In the first pass we check
1416 for correct syntax and for valid entries and also keep count of the
1417 number of servers and thresholds to monitor. This the data strctures
1418 can be arrays instead of link lists since we would know their sizes.*/
1425 error_in_config = 0; /* flag to note if config file has syntax errors*/
1427 while ( (fgets(line,CFG_STR_LEN,configFD)) != NULL)
1429 opcode[0] = 0; arg1[0] = 0; arg2[0] = 0; arg3[0] = 0; arg4[0] = 0;
1430 sscanf(line,"%s %s %s %s %s", opcode, arg1, arg2, arg3, arg4);
1432 /* skip blank lines and comment lines */
1433 if ( (strlen(opcode) == 0) || line[0] == '#' ) continue;
1435 if ( (strcasecmp(opcode,"fs") == 0) || (strcasecmp(opcode,"cm")) == 0) {
1436 code = parse_hostEntry(line);
1437 } else if ((strcasecmp(opcode,"thresh")) == 0) {
1438 code = parse_threshEntry(line);
1439 } else if ((strcasecmp(opcode,"show")) == 0) {
1440 code = parse_showEntry(line);
1442 fprintf(stderr,"[ %s ] Unknown opcode %s\n",rn,opcode);
1447 fprintf(stderr,"[ %s ] Error in line:\n %d: %s\n",
1449 error_in_config = 1;
1453 if (error_in_config)
1457 fprintf(debugFD,"Global FS thresholds count = %d\n",global_fsThreshCount);
1458 fprintf(debugFD,"Global CM thresholds count = %d\n",global_cmThreshCount);
1462 /* the threshold count of all hosts in increased by 1 for each global
1463 threshold. If one of the hosts has a local threshold for the same
1464 variable it would end up being counted twice. whats a few bytes of memory
1467 if (global_fsThreshCount) {
1468 curr_host = FSnameList;
1469 for(i=0; i<numFS; i++) {
1470 curr_host->numThresh += global_fsThreshCount;
1471 curr_host = curr_host->next;
1474 if (global_cmThreshCount) {
1475 curr_host = CMnameList;
1476 for(i=0; i<numCM; i++) {
1477 curr_host->numThresh += global_cmThreshCount;
1478 curr_host = curr_host->next;
1483 /* make sure we have something to monitor */
1484 if (numFS == 0 && numCM == 0) {
1485 fprintf(stderr,"\nConfig file must specify atleast one File Server or Cache Manager host to monitor.\n");
1492 fseek(configFD,0,0); /* seek to the beginning */
1495 /* allocate memory for threshold lists */
1496 curr_host = FSnameList;
1497 for(i=0; i<numFS; i++) {
1498 if (curr_host->hostName[0] == '\0') {
1499 fprintf(stderr,"[ %s ] Programming error 4\n",rn);
1502 if (curr_host->numThresh) {
1503 numBytes = curr_host->numThresh * sizeof(struct Threshold);
1504 curr_host->thresh = (struct Threshold *) malloc(numBytes);
1505 if (curr_host->thresh == (struct Threshold *)0) {
1506 fprintf(stderr,"[ %s ] Memory Allocation error 1",rn);
1509 bzero(curr_host->thresh,numBytes);
1511 curr_host = curr_host->next;;
1514 curr_host = CMnameList;
1515 for(i=0; i<numCM; i++) {
1516 if (curr_host->hostName[0] == '\0') {
1517 fprintf(stderr,"[ %s ] Programming error 5\n",rn);
1520 if (curr_host->numThresh) {
1521 numBytes = curr_host->numThresh * sizeof(struct Threshold);
1522 curr_host->thresh = (struct Threshold *) malloc(numBytes);
1523 if (curr_host->thresh == (struct Threshold *)0) {
1524 fprintf(stderr,"[ %s ] Memory Allocation error 2",rn);
1527 bzero(curr_host->thresh,numBytes);
1529 curr_host = curr_host->next;;
1533 opcode[0] = 0; arg1[0] = 0; arg2[0] = 0; arg3[0] = 0; arg4[0] = 0;
1534 last_fsHost[0] = '\0';
1535 last_cmHost[0] = '\0';
1537 while ( (fgets(line,CFG_STR_LEN,configFD)) != NULL) {
1538 opcode[0] = 0; arg1[0] = 0; arg2[0] = 0; arg3[0] = 0; arg4[0] = 0;
1539 sscanf(line,"%s %s %s %s %s", opcode, arg1, arg2, arg3, arg4);
1542 /* if we have a host entry, remember the host name */
1543 if (strcasecmp(opcode,"fs") == 0) {
1544 he = GetHostByName(arg1);
1545 strncpy(last_fsHost,he->h_name,HOST_NAME_LEN);
1547 else if (strcasecmp(opcode,"cm") == 0) {
1548 he = GetHostByName(arg1);
1549 strncpy(last_cmHost,he->h_name,HOST_NAME_LEN);
1551 else if (strcasecmp(opcode,"thresh") == 0) {
1552 /* if we have a threshold handler it may have arguments
1553 and the sscanf() above would not get them, so do the
1557 /* now skip over 4 words - this is done by first
1558 skipping leading blanks then skipping a word */
1559 for(i=0; i<4; i++) {
1560 while( isspace(*handlerPtr) )
1562 while(! isspace(*handlerPtr) )
1565 while( isspace(*handlerPtr) )
1567 /* we how have a pointer to the start of the handler
1570 handlerPtr = arg4; /* empty string */
1573 if (strcasecmp(arg1,"fs") == 0)
1574 code = store_threshold(1, /* 1 = fs*/
1575 arg2,arg3,handlerPtr);
1577 else if (strcasecmp(arg1,"cm") == 0)
1578 code = store_threshold(2, /* 2 = fs*/
1579 arg2,arg3,handlerPtr);
1582 fprintf(stderr,"[ %s ] Programming error 6\n", rn);
1586 fprintf(stderr,"[ %s ] Failed to store threshold\n",
1588 fprintf(stderr,"[ %s ] Error processing line:\n%d: %s",
1600 /*-----------------------------------------------------------------------
1605 * Print the File Server circular buffer.
1609 *----------------------------------------------------------------------*/
1613 { /* Print_FS_CB() */
1615 struct afsmon_fs_Results_list *fslist;
1619 /* print valid info in the fs CB */
1622 fprintf(debugFD,"==================== FS Buffer ========================\n");
1623 fprintf(debugFD,"afsmon_fs_curr_CBindex = %d\n",afsmon_fs_curr_CBindex);
1624 fprintf(debugFD,"afsmon_fs_curr_probeNum = %d\n\n",afsmon_fs_curr_probeNum);
1626 for(i=0; i<num_bufSlots; i++) {
1627 fprintf(debugFD,"\t--------- slot %d ----------\n",i);
1628 fslist = afsmon_fs_ResultsCB[i].list;
1630 while( j < numFS ) {
1631 if (! fslist->empty) {
1632 fprintf(debugFD,"\t %d) probeNum = %d host = %s",
1633 j,fslist->fsResults->probeNum,
1634 fslist-> fsResults->connP->hostName);
1635 if (fslist->fsResults->probeOK) fprintf(debugFD," NOTOK\n");
1636 else fprintf(debugFD," OK\n");
1638 fprintf(debugFD,"\t %d) -- empty --\n",j);
1639 fslist = fslist->next;
1642 if (fslist != (struct afsmon_fs_Results_list *)0 )
1643 fprintf(debugFD,"dangling last next ptr fs CB\n");
1646 } /* Print_FS_CB() */
1648 /*-----------------------------------------------------------------------
1649 * save_FS_results_inCB()
1652 * Saves the results of the latest FS probe in the fs circular
1653 * buffers. If the current probe cycle is in progress the contents
1654 * of xstat_fs_Results are copied to the end of the list of results
1655 * in the current slot (pointed to by afsmon_fs_curr_CBindex). If
1656 * a new probe cycle has started the next slot in the circular buffer
1657 * is initialized and the results copied. Note that the Rx related
1658 * information available in xstat_fs_Results is not copied.
1662 * Failure: Exits afsmonitor.
1663 *----------------------------------------------------------------------*/
1665 save_FS_results_inCB(a_newProbeCycle)
1666 int a_newProbeCycle; /* start of a new probe cycle ? */
1668 { /* save_FS_results_inCB() */
1669 static char rn[] = "save_FS_results_inCB"; /* routine name */
1670 struct afsmon_fs_Results_list *tmp_fslist_item; /* temp fs list item */
1671 struct xstat_fs_ProbeResults *tmp_fsPR; /* temp ptr */
1675 fprintf(debugFD,"[ %s ] Called, a_newProbeCycle= %d\n",
1676 rn, a_newProbeCycle);
1681 /* If a new probe cycle started, mark the list in the current buffer
1682 slot empty for resuse. Note that afsmon_fs_curr_CBindex was appropriately
1683 incremented in afsmon_FS_Handler() */
1685 if (a_newProbeCycle) {
1686 tmp_fslist_item = afsmon_fs_ResultsCB[afsmon_fs_curr_CBindex].list;
1687 for(i=0; i<numFS; i++) {
1688 tmp_fslist_item->empty = 1;
1689 tmp_fslist_item = tmp_fslist_item->next;
1693 /* locate last unused item in list */
1694 tmp_fslist_item = afsmon_fs_ResultsCB[afsmon_fs_curr_CBindex].list;
1695 for(i=0; i<numFS; i++) {
1696 if (tmp_fslist_item->empty) break;
1697 tmp_fslist_item = tmp_fslist_item->next;
1700 /* if we could not find one we have an inconsistent list */
1701 if ( ! tmp_fslist_item->empty ) {
1702 fprintf(stderr,"[ %s ] list inconsistency 1. unable to find an empty slot to store results of probenum %d of %s\n",rn,
1703 xstat_fs_Results.probeNum,xstat_fs_Results.connP->hostName);
1707 tmp_fsPR = tmp_fslist_item->fsResults;
1709 /* copy hostname and probe number and probe time and probe status.
1710 if the probe failed return now */
1712 bcopy(xstat_fs_Results.connP->hostName, tmp_fsPR->connP->hostName,
1713 sizeof(xstat_fs_Results.connP->hostName));
1714 tmp_fsPR->probeNum = xstat_fs_Results.probeNum;
1715 tmp_fsPR->probeTime = xstat_fs_Results.probeTime;
1716 tmp_fsPR->probeOK = xstat_fs_Results.probeOK;
1717 if (xstat_fs_Results.probeOK) { /* probeOK = 1 => notOK */
1718 /* we have a nonempty results structure so mark the list item used */
1719 tmp_fslist_item->empty = 0;
1723 /* copy connection information */
1724 #if defined(AFS_LINUX20_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
1725 bcopy(&(xstat_fs_Results.connP->skt), &(tmp_fsPR->connP->skt),
1726 sizeof(struct sockaddr_in));
1728 bcopy(xstat_fs_Results.connP->skt, tmp_fsPR->connP->skt,
1729 sizeof(struct sockaddr_in));
1732 bcopy(xstat_fs_Results.connP->hostName, tmp_fsPR->connP->hostName,
1733 sizeof(xstat_fs_Results.connP->hostName));
1734 tmp_fsPR->collectionNumber = xstat_fs_Results.collectionNumber;
1736 /* copy the probe data information */
1737 tmp_fsPR->data.AFS_CollData_len = xstat_fs_Results.data.AFS_CollData_len;
1738 bcopy(xstat_fs_Results.data.AFS_CollData_val,
1739 tmp_fsPR->data.AFS_CollData_val,
1740 xstat_fs_Results.data.AFS_CollData_len * sizeof(afs_int32));
1743 /* we have a valid results structure so mark the list item used */
1744 tmp_fslist_item->empty = 0;
1746 /* Print the fs circular buffer */
1750 } /* save_FS_results_inCB() */
1753 /*-----------------------------------------------------------------------
1757 * The results of xstat probes are stored in a string format in
1758 * the arrays curr_fsData and prev_fsData. The information stored in
1759 * prev_fsData is copied to the screen.
1760 * This function converts xstat FS results from longs to strings and
1761 * place them in the given buffer (a pointer to an item in curr_fsData).
1762 * When a probe cycle completes, curr_fsData is copied to prev_fsData
1763 * in afsmon_FS_Hnadler().
1767 *----------------------------------------------------------------------*/
1770 fs_Results_ltoa(a_fsData,a_fsResults)
1771 struct fs_Display_Data *a_fsData; /* target buffer */
1772 struct xstat_fs_ProbeResults *a_fsResults; /* ptr to xstat fs Results */
1773 { /* fs_Results_ltoa */
1775 static char rn[] = "fs_Results_ltoa"; /* routine name */
1777 struct fs_stats_FullPerfStats *fullPerfP;
1783 fprintf(debugFD,"[ %s ] Called, a_fsData= %d, a_fsResults= %d\n",
1784 rn, a_fsData, a_fsResults);
1788 fullPerfP = (struct fs_stats_FullPerfStats *)
1789 (a_fsResults->data.AFS_CollData_val);
1791 /* there are two parts to the xstat FS statistics
1792 - fullPerfP->overall which give the overall performance statistics, and
1793 - fullPerfP->det which gives detailed info about file server operation
1796 /* copy overall performance statistics */
1797 srcbuf = (afs_int32 *) &(fullPerfP->overall);
1799 for(i=0; i< NUM_XSTAT_FS_AFS_PERFSTATS_LONGS; i++) {
1800 sprintf(a_fsData->data[idx],"%d",*srcbuf);
1806 srcbuf = (afs_int32 *) &(fullPerfP->det.epoch);
1807 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* epoch */
1810 /* copy fs operation timing */
1812 srcbuf = (afs_int32 *) (fullPerfP->det.rpcOpTimes);
1814 for(i=0; i<FS_STATS_NUM_RPC_OPS; i++) {
1815 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* numOps*/
1817 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* numSuccesses */
1819 tmpbuf = srcbuf++; /* sum time */
1820 sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1822 tmpbuf = srcbuf++; /* sqr time */
1823 sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1825 tmpbuf = srcbuf++; /* min time */
1826 sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1828 tmpbuf = srcbuf++; /* max time */
1829 sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1833 /* copy fs transfer timings */
1835 srcbuf = (afs_int32 *) (fullPerfP->det.xferOpTimes);
1836 for(i=0; i<FS_STATS_NUM_XFER_OPS; i++) {
1837 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* numOps*/
1839 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* numSuccesses */
1841 tmpbuf = srcbuf++; /* sum time */
1842 sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1844 tmpbuf = srcbuf++; /* sqr time */
1845 sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1847 tmpbuf = srcbuf++; /* min time */
1848 sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1850 tmpbuf = srcbuf++; /* max time */
1851 sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1853 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* sum bytes */
1855 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* min bytes */
1857 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* max bytes */
1859 for(j=0; j<FS_STATS_NUM_XFER_BUCKETS; j++) {
1860 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* bucket[j] */
1866 } /* fs_Results_ltoa */
1870 /*-----------------------------------------------------------------------
1871 * execute_thresh_handler()
1874 * Execute a threshold handler. An agrv[] array of pointers is
1875 * constructed from the given data. A child process is forked
1876 * which immediately calls afsmon_Exit() with indication that a
1877 * threshold handler is to be exec'ed insted of exiting.
1881 * Failure: Afsmonitor exits if threshold handler has more than 20 args.
1882 *----------------------------------------------------------------------*/
1885 execute_thresh_handler(a_handler, a_hostName, a_hostType,
1886 a_threshName,a_threshValue, a_actValue)
1887 char *a_handler; /* ptr to handler function + args */
1888 char *a_hostName; /* host name for which threshold crossed */
1889 int a_hostType; /* fs or cm ? */
1890 char *a_threshName; /* threshold variable name */
1891 char *a_threshValue; /* threshold value */
1892 char *a_actValue; /* actual value */
1894 { /* execute_thresh_handler */
1896 static char rn[] = "execute_thresh_handler";
1897 char fileName[256]; /* file name to execute */
1902 int anotherArg; /* boolean used to flag if another arg is available */
1905 fprintf(debugFD,"[ %s ] Called, a_handler= %s, a_hostName= %s, a_hostType= %d, a_threshName= %s, a_threshValue= %s, a_actValue= %s\n",
1906 rn, a_handler, a_hostName, a_hostType, a_threshName, a_threshValue,
1912 /* get the filename to execute - the first argument */
1913 sscanf(a_handler,"%s",fileName);
1915 /* construct the contents of *argv[] */
1917 strncpy(fsHandler_args[0], fileName,256);
1918 strncpy(fsHandler_args[1], a_hostName, HOST_NAME_LEN);
1919 if (a_hostType == FS) strcpy(fsHandler_args[2], "fs");
1920 else strcpy(fsHandler_args[2], "cm");
1921 strncpy(fsHandler_args[3], a_threshName, THRESH_VAR_NAME_LEN);
1922 strncpy(fsHandler_args[4], a_threshValue, THRESH_VAR_LEN);
1923 strncpy(fsHandler_args[5], a_actValue, THRESH_VAR_LEN);
1930 /* we have already extracted the file name so skip to the 1st arg */
1931 while (isspace(*ch)) /* leading blanks */
1933 while (! isspace(*ch) && *ch != '\0') /* handler filename */
1936 while( *ch != '\0' ) {
1939 } else if (anotherArg) {
1941 sscanf(ch,"%s",fsHandler_args[argNum]);
1947 "Threshold handlers cannot have more than 20 arguments\n");
1953 fsHandler_argv[argNum] = (char *)0;
1954 for(i=0; i<argNum; i++)
1955 fsHandler_argv[i] = fsHandler_args[i];
1958 /* exec the threshold handler */
1961 exec_fsThreshHandler = 1;
1962 code = afsmon_Exit(60);
1966 } /* execute_thresh_handler */
1970 /*-----------------------------------------------------------------------
1971 * check_fs_thresholds()
1974 * Checks the thresholds and sets the overflow flag. Recall that the
1975 * thresholds for each host are stored in the hostEntry lists
1976 * [fs/cm]nameList arrays. The probe results are passed to this
1977 * function in the display-ready format - ie., as strings. Though
1978 * this looks stupid the overhead incurred in converting the strings
1979 * back to floats and comparing them is insignificant and
1980 * programming is easier this way.
1981 * The threshold flags are a part of the display structures
1986 *----------------------------------------------------------------------*/
1989 check_fs_thresholds(a_hostEntry, a_Data)
1990 struct afsmon_hostEntry *a_hostEntry; /* ptr to hostEntry */
1991 struct fs_Display_Data *a_Data; /* ptr to fs data to be displayed */
1993 { /* check_fs_thresholds */
1995 static char rn[] = "check_fs_thresholds";
1996 struct Threshold *threshP;
1997 double tValue; /* threshold value */
1998 double pValue; /* probe value */
2001 int count; /* number of thresholds exceeded */
2004 fprintf(debugFD,"[ %s ] Called, a_hostEntry= %d, a_Data= %d\n",
2005 rn, a_hostEntry, a_Data);
2009 if (a_hostEntry->numThresh == 0) {
2010 /* store in ovf count ?? */
2015 threshP = a_hostEntry->thresh;
2016 for(i=0; i < a_hostEntry->numThresh; i++) {
2017 if (threshP->itemName[0] == '\0') {
2018 threshP++; continue;
2020 idx = threshP->index; /* positional index to the data array */
2021 tValue = atof(threshP->threshVal); /* threshold value */
2022 pValue = atof(a_Data->data[idx]); /* probe value */
2023 if (pValue > tValue) {
2026 fprintf(debugFD,"[ %s ] fs = %s, thresh ovf for %s, threshold= %s, probevalue= %s\n",
2027 rn, a_hostEntry->hostName, threshP->itemName, threshP->threshVal, a_Data->data[idx]);
2030 /* if the threshold is crossed, call the handler function
2031 only if this was a transition -ie, if the threshold was
2032 crossed in the last probe too just count & keep quite! */
2034 if (! a_Data->threshOvf[idx]) {
2035 a_Data->threshOvf[idx] = 1;
2036 /* call the threshold handler if provided */
2037 if (threshP->handler[0] != '\0') {
2039 fprintf(debugFD,"[ %s ] Calling ovf handler %s\n",
2040 rn, threshP->handler);
2043 execute_thresh_handler(threshP->handler,
2044 a_Data->hostName, FS, threshP->itemName,
2045 threshP->threshVal, a_Data->data[idx]);
2051 /* in case threshold was previously crossed, blank it out */
2052 a_Data->threshOvf[idx] = 0;
2055 /* store the overflow count */
2056 a_Data->ovfCount = count;
2059 } /* check_fs_thresholds */
2062 /*-----------------------------------------------------------------------
2063 * save_FS_data_forDisplay()
2066 * Does the following:
2067 * - if the probe number changed (ie, a cycle completed) curr_fsData
2068 * is copied to prev_fsData, curr_fsData zeroed and refresh the
2069 * overview screen and file server screen with the new data.
2070 * - store the results of the current probe from xstat_fs_Results into
2071 * curr_fsData. ie., convert longs to strings.
2072 * - check the thresholds
2076 * Failure: Exits afsmonitor.
2077 *----------------------------------------------------------------------*/
2080 save_FS_data_forDisplay(a_fsResults)
2081 struct xstat_fs_ProbeResults *a_fsResults;
2082 { /* save_FS_data_forDisplay */
2084 static char rn[] = "save_FS_data_forDisplay"; /* routine name */
2085 struct fs_Display_Data *curr_fsDataP; /* tmp ptr to curr_fsData*/
2086 struct fs_Display_Data *prev_fsDataP; /* tmp ptr to prev_fsData*/
2087 struct afsmon_hostEntry *curr_host;
2088 static int probes_Received = 0; /* number of probes reveived in
2089 the current cycle. If this is equal to numFS we got all
2090 the data we want in this cycle and can now display it */
2099 fprintf(debugFD,"[ %s ] Called, a_fsResults= %d\n",rn, a_fsResults);
2105 /* store results in the display array */
2108 curr_fsDataP = curr_fsData;
2109 for (i=0; i<numFS; i++) {
2110 if((strcasecmp(curr_fsDataP->hostName,a_fsResults->connP->hostName)) == 0) {
2118 fprintf(stderr,"[ %s ] Could not insert FS probe results for host %s in fs display array\n",rn, a_fsResults->connP->hostName);
2122 /* Check the status of the probe. If it succeeded, we store its
2123 results in the display data structure. If it failed we only mark
2124 the failed status in the display data structure. */
2126 if (a_fsResults->probeOK) { /* 1 => notOK the xstat results */
2127 curr_fsDataP->probeOK = 0;
2129 /* print the probe status */
2131 fprintf(debugFD,"\n\t\t ----- fs display data ------\n");
2132 fprintf(debugFD,"HostName = %s PROBE FAILED \n",curr_fsDataP->hostName);
2136 } else { /* probe succeeded, update display data structures */
2137 curr_fsDataP->probeOK = 1;
2139 /* covert longs to strings and place them in curr_fsDataP */
2140 fs_Results_ltoa(curr_fsDataP, a_fsResults);
2142 /* compare with thresholds and set the overflow flags.
2143 note that the threshold information is in the hostEntry structure and
2144 each threshold item has a positional index associated with it */
2146 /* locate the hostEntry for this host */
2148 curr_host = FSnameList;
2149 for(i=0; i<numFS; i++) {
2150 if(strcasecmp(curr_host->hostName,a_fsResults->connP->hostName) == 0) {
2154 curr_host = curr_host->next;;
2156 if (!done) afsmon_Exit(70);
2158 code = check_fs_thresholds(curr_host, curr_fsDataP);
2160 fprintf(stderr,"[ %s ] Error in checking thresholds\n",rn);
2167 /* print the info we just saved */
2170 fprintf(debugFD,"\n\t\t ----- fs display data ------\n");
2171 fprintf(debugFD,"HostName = %s\n",curr_fsDataP->hostName);
2172 for(i=0; i<NUM_FS_STAT_ENTRIES; i++)
2173 fprintf(debugFD,"%20s %30s %s\n", curr_fsDataP->data[i],
2174 fs_varNames[i], curr_fsDataP->threshOvf[i] ? "(ovf)":"" );
2176 fprintf(debugFD,"\t\t--------------------------------\n\n");
2180 } /* the probe succeeded, so we store the data in the display structure */
2183 /* if we have received a reply from all the hosts for this probe cycle,
2184 it is time to display the data */
2187 if (probes_Received == numFS) {
2188 probes_Received = 0;
2190 if (afsmon_fs_curr_probeNum != afsmon_fs_prev_probeNum + 1) {
2191 sprintf(errMsg,"[ %s ] Probe number %d missed! \n",
2192 rn, afsmon_fs_prev_probeNum +1);
2195 afsmon_fs_prev_probeNum++;
2197 /* backup the display data of the probe cycle that just completed -
2198 ie., store curr_fsData in prev_fsData */
2200 bcopy((char *)curr_fsData, (char *)prev_fsData,
2201 (numFS * sizeof(struct fs_Display_Data)) );
2204 /* initialize curr_fsData but retain the threshold flag information.
2205 The previous state of threshold flags is used in check_fs_thresholds()*/
2207 numBytes = NUM_FS_STAT_ENTRIES * CM_STAT_STRING_LEN;
2208 curr_fsDataP = curr_fsData;
2209 for(i=0; i<numFS; i++) {
2210 curr_fsDataP->probeOK = 0;
2211 curr_fsDataP->ovfCount = 0;
2212 bzero((char *)curr_fsDataP->data, numBytes);
2217 /* prev_fsData now contains all the information for the probe cycle
2218 that just completed. Now count the number of threshold overflows for
2219 use in the overview screen */
2221 prev_fsDataP = prev_fsData;
2223 numHosts_onfs_alerts = 0;
2224 for(i=0; i<numFS; i++) {
2225 if (! prev_fsDataP->probeOK ) { /* if probe failed */
2227 numHosts_onfs_alerts++;
2228 } if (prev_fsDataP->ovfCount) { /* overflows ?? */
2229 num_fs_alerts += prev_fsDataP->ovfCount;
2230 numHosts_onfs_alerts++;
2235 fprintf(debugFD,"Number of FS alerts = %d (on %d hosts)\n",
2236 num_fs_alerts, numHosts_onfs_alerts);
2238 /* flag that the data is now ready to be displayed */
2239 fs_Data_Available = 1;
2241 /* call the Overview frame update routine (update only FS info)*/
2242 ovw_refresh(ovw_currPage, OVW_UPDATE_FS);
2244 /* call the File Servers frame update routine */
2245 fs_refresh(fs_currPage, fs_curr_LCol);
2247 } /* display data */
2250 } /* save_FS_data_forDisplay */
2255 /*-----------------------------------------------------------------------
2256 * afsmon_FS_Handler()
2259 * This is the File Server probe Handler. It updates the afsmonitor
2260 * probe counts, fs circular buffer indices and calls the functions
2261 * to process the results of this probe.
2265 * Failure: Exits afsmonitor.
2266 *----------------------------------------------------------------------*/
2270 { /* afsmon_FS_Handler() */
2271 static char rn[] = "afsmon_FS_Handler"; /* routine name */
2272 int newProbeCycle; /* start of new probe cycle ? */
2273 int code; /* return status */
2277 fprintf(debugFD,"[ %s ] Called, hostName= %s, probeNum= %d, status=%s\n",
2279 xstat_fs_Results.connP->hostName,
2280 xstat_fs_Results.probeNum,
2281 xstat_fs_Results.probeOK? "FAILED":"OK");
2286 /* print the probe results to output file */
2287 if (afsmon_output) {
2288 code = afsmon_fsOutput(output_filename, afsmon_detOutput);
2290 fprintf(stderr,"[ %s ] output to file %s returned error code=%d\n",
2291 rn,output_filename,code);
2295 /* Update current probe number and circular buffer index. if current
2296 probenum changed make sure it is only by 1 */
2299 if (xstat_fs_Results.probeNum != afsmon_fs_curr_probeNum) {
2300 if (xstat_fs_Results.probeNum == afsmon_fs_curr_probeNum + 1) {
2301 afsmon_fs_curr_probeNum++;
2304 afsmon_fs_curr_CBindex=
2305 (afsmon_fs_curr_probeNum - 1) % num_bufSlots;
2308 fprintf(stderr,"[ %s ] probe number %d-1 missed\n",
2309 rn,xstat_fs_Results.probeNum);
2314 /* store the results of this probe in the FS circular buffer */
2316 save_FS_results_inCB(newProbeCycle);
2319 /* store the results of the current probe in the fs data display structure.
2320 if the current probe number changed, swap the current and previous display
2321 structures. note that the display screen is updated from these structures
2322 and should start showing the data of the just completed probe cycle */
2324 save_FS_data_forDisplay(&xstat_fs_Results);
2331 /*----------------------------------------------------------------------- *
2336 * Prints the Cache Manager circular buffer
2337 *----------------------------------------------------------------------*/
2341 { /* Print_CM_CB() */
2343 struct afsmon_cm_Results_list *cmlist;
2347 /* print valid info in the cm CB */
2350 fprintf(debugFD,"==================== CM Buffer ========================\n");
2351 fprintf(debugFD,"afsmon_cm_curr_CBindex = %d\n",afsmon_cm_curr_CBindex);
2352 fprintf(debugFD,"afsmon_cm_curr_probeNum = %d\n\n",afsmon_cm_curr_probeNum);
2354 for(i=0; i<num_bufSlots; i++) {
2355 fprintf(debugFD,"\t--------- slot %d ----------\n",i);
2356 cmlist = afsmon_cm_ResultsCB[i].list;
2358 while( j < numCM ) {
2359 if (! cmlist->empty) {
2360 fprintf(debugFD,"\t %d) probeNum = %d host = %s",
2361 j,cmlist->cmResults->probeNum,
2362 cmlist-> cmResults->connP->hostName);
2363 if (cmlist->cmResults->probeOK) fprintf(debugFD," NOTOK\n");
2364 else fprintf(debugFD," OK\n");
2366 fprintf(debugFD,"\t %d) -- empty --\n",j);
2367 cmlist = cmlist->next;
2370 if (cmlist != (struct afsmon_cm_Results_list *)0 )
2371 fprintf(debugFD,"dangling last next ptr cm CB\n");
2377 /*-----------------------------------------------------------------------
2378 * save_CM_results_inCB()
2381 * Saves the results of the latest CM probe in the cm circular
2382 * buffers. If the current probe cycle is in progress the contents
2383 * of xstat_cm_Results are copied to the end of the list of results
2384 * in the current slot (pointed to by afsmon_cm_curr_CBindex). If
2385 * a new probe cycle has started the next slot in the circular buffer
2386 * is initialized and the results copied. Note that the Rx related
2387 * information available in xstat_cm_Results is not copied.
2391 * Failure: Exits afsmonitor.
2392 *----------------------------------------------------------------------*/
2395 save_CM_results_inCB(a_newProbeCycle)
2396 int a_newProbeCycle; /* start of new probe cycle ? */
2398 { /* save_CM_results_inCB() */
2399 static char rn[] = "save_CM_results_inCB"; /* routine name */
2400 struct afsmon_cm_Results_list *tmp_cmlist_item; /* temp cm list item */
2401 struct xstat_cm_ProbeResults *tmp_cmPR; /* temp ptr */
2406 fprintf(debugFD,"[ %s ] Called, a_newProbeCycle= %d\n",rn, a_newProbeCycle);
2410 /* If a new probe cycle started, mark the list in the current buffer
2411 slot empty for resuse. Note that afsmon_cm_curr_CBindex was appropriately
2412 incremented in afsmon_CM_Handler() */
2414 if (a_newProbeCycle) {
2415 tmp_cmlist_item = afsmon_cm_ResultsCB[afsmon_cm_curr_CBindex].list;
2416 for(i=0; i<numCM; i++) {
2417 tmp_cmlist_item->empty = 1;
2418 tmp_cmlist_item = tmp_cmlist_item->next;
2422 /* locate last unused item in list */
2423 tmp_cmlist_item = afsmon_cm_ResultsCB[afsmon_cm_curr_CBindex].list;
2424 for(i=0; i<numCM; i++) {
2425 if (tmp_cmlist_item->empty) break;
2426 tmp_cmlist_item = tmp_cmlist_item->next;
2429 /* if we could not find one we have an inconsistent list */
2430 if ( ! tmp_cmlist_item->empty ) {
2431 fprintf(stderr,"[ %s ] list inconsistency 1. unable to find an empty slot to store results of probenum %d of %s\n",rn,
2432 xstat_cm_Results.probeNum,xstat_cm_Results.connP->hostName);
2436 tmp_cmPR = tmp_cmlist_item->cmResults;
2438 /* copy hostname and probe number and probe time and probe status.
2439 if the probe failed return now */
2441 bcopy(xstat_cm_Results.connP->hostName, tmp_cmPR->connP->hostName,
2442 sizeof(xstat_cm_Results.connP->hostName));
2443 tmp_cmPR->probeNum = xstat_cm_Results.probeNum;
2444 tmp_cmPR->probeTime = xstat_cm_Results.probeTime;
2445 tmp_cmPR->probeOK = xstat_cm_Results.probeOK;
2446 if (xstat_cm_Results.probeOK) { /* probeOK = 1 => notOK */
2447 /* we have a nonempty results structure so mark the list item used */
2448 tmp_cmlist_item->empty = 0;
2453 /* copy connection information */
2454 #if defined(AFS_LINUX20_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
2455 bcopy(&(xstat_cm_Results.connP->skt), &(tmp_cmPR->connP->skt),
2456 sizeof(struct sockaddr_in));
2458 bcopy(xstat_cm_Results.connP->skt, tmp_cmPR->connP->skt,
2459 sizeof(struct sockaddr_in));
2462 /**** NEED TO COPY rx_connection INFORMATION HERE ******/
2464 bcopy(xstat_cm_Results.connP->hostName, tmp_cmPR->connP->hostName,
2465 sizeof(xstat_cm_Results.connP->hostName));
2466 tmp_cmPR->collectionNumber = xstat_cm_Results.collectionNumber;
2468 /* copy the probe data information */
2469 tmp_cmPR->data.AFSCB_CollData_len = xstat_cm_Results.data.AFSCB_CollData_len;
2470 bcopy(xstat_cm_Results.data.AFSCB_CollData_val,
2471 tmp_cmPR->data.AFSCB_CollData_val,
2472 xstat_cm_Results.data.AFSCB_CollData_len * sizeof(afs_int32));
2475 /* we have a valid results structure so mark the list item used */
2476 tmp_cmlist_item->empty = 0;
2478 /* print the stored info - to make sure we copied it right */
2479 /* Print_cm_FullPerfInfo(tmp_cmPR); */
2480 /* Print the cm circular buffer */
2483 } /* save_CM_results_inCB */
2487 /*-----------------------------------------------------------------------
2491 * The results of xstat probes are stored in a string format in
2492 * the arrays curr_cmData and prev_cmData. The information stored in
2493 * prev_cmData is copied to the screen.
2494 * This function converts xstat FS results from longs to strings and
2495 * places them in the given buffer (a pointer to an item in curr_cmData).
2496 * When a probe cycle completes, curr_cmData is copied to prev_cmData
2497 * in afsmon_CM_Handler().
2501 *----------------------------------------------------------------------*/
2504 cm_Results_ltoa(a_cmData,a_cmResults)
2505 struct cm_Display_Data *a_cmData; /* target buffer */
2506 struct xstat_cm_ProbeResults *a_cmResults; /* ptr to xstat cm Results */
2507 { /* cm_Results_ltoa */
2509 static char rn[] = "cm_Results_ltoa"; /* routine name */
2510 struct afs_stats_CMFullPerf *fullP; /* ptr to complete CM stats */
2518 fprintf(debugFD,"[ %s ] Called, a_cmData= %d, a_cmResults= %d\n",
2519 rn, a_cmData, a_cmResults);
2524 fullP = (struct afs_stats_CMFullPerf *)
2525 (xstat_cm_Results.data.AFSCB_CollData_val);
2527 /* There are 4 parts to CM statistics
2528 - Overall performance statistics (including up/down statistics)
2529 - This CMs FS RPC operations info
2530 - This CMs FS RPC errors info
2531 - This CMs FS transfers info
2532 - Authentication info
2533 - [Un]Replicated access info
2536 /* copy overall performance statistics */
2537 srcbuf = (afs_int32 *) &(fullP->perf);
2539 /* we skip the 19 entry, ProtServAddr, so the index must account for this */
2540 for(i=0 ; i<NUM_AFS_STATS_CMPERF_LONGS+1; i++) {
2543 continue; /* skip ProtServerAddr */
2545 sprintf(a_cmData->data[idx], "%d", *srcbuf);
2550 /*printf("Ending index value = %d\n",idx-1);*/
2552 /* server up/down statistics */
2553 /* copy file server up/down stats */
2554 srcbuf = (afs_int32 *) (fullP->perf.fs_UpDown);
2555 numLongs = 2 * (sizeof(struct afs_stats_SrvUpDownInfo) / sizeof(afs_int32));
2556 for(i=0 ; i<numLongs; i++) {
2557 sprintf(a_cmData->data[idx], "%d", *srcbuf);
2562 /*printf("Ending index value = %d\n",idx-1);*/
2564 /* copy volume location server up/down stats */
2565 srcbuf = (afs_int32 *) (fullP->perf.vl_UpDown);
2566 numLongs = 2 * (sizeof(struct afs_stats_SrvUpDownInfo) / sizeof(afs_int32));
2567 for(i=0 ; i<numLongs; i++) {
2568 sprintf(a_cmData->data[idx], "%d", *srcbuf);
2573 /*printf("Ending index value = %d\n",idx-1);*/
2575 /* copy CMs individual FS RPC operations info */
2576 srcbuf = (afs_int32 *) (fullP->rpc.fsRPCTimes);
2577 for(i=0; i<AFS_STATS_NUM_FS_RPC_OPS; i++) {
2578 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* numOps*/
2580 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* numSuccesses */
2582 tmpbuf = srcbuf++; /* sum time */
2583 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2585 tmpbuf = srcbuf++; /* sqr time */
2586 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2588 tmpbuf = srcbuf++; /* min time */
2589 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2591 tmpbuf = srcbuf++; /* max time */
2592 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2596 /*printf("Ending index value = %d\n",idx-1);*/
2598 /* copy CMs individual FS RPC errors info */
2600 srcbuf = (afs_int32 *) (fullP->rpc.fsRPCErrors);
2601 for(i=0; i<AFS_STATS_NUM_FS_RPC_OPS; i++) {
2602 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* server */
2604 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* network */
2606 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* prot */
2608 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* vol */
2610 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* busies */
2612 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* other */
2616 /*printf("Ending index value = %d\n",idx-1);*/
2618 /* copy CMs individual RPC transfers info */
2620 srcbuf = (afs_int32 *) (fullP->rpc.fsXferTimes);
2621 for(i=0; i<AFS_STATS_NUM_FS_XFER_OPS; i++) {
2622 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* numOps*/
2624 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* numSuccesses */
2626 tmpbuf = srcbuf++; /* sum time */
2627 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2629 tmpbuf = srcbuf++; /* sqr time */
2630 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2632 tmpbuf = srcbuf++; /* min time */
2633 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2635 tmpbuf = srcbuf++; /* max time */
2636 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2638 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* sum bytes */
2640 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* min bytes */
2642 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* max bytes */
2644 for(j=0; j<AFS_STATS_NUM_XFER_BUCKETS; j++) {
2645 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* bucket[j] */
2650 /*printf("Ending index value = %d\n",idx-1);*/
2652 /* copy CM operations timings */
2654 srcbuf = (afs_int32 *) (fullP->rpc.cmRPCTimes);
2655 for(i=0; i<AFS_STATS_NUM_CM_RPC_OPS; i++) {
2656 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* numOps*/
2658 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* numSuccesses */
2660 tmpbuf = srcbuf++; /* sum time */
2661 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2663 tmpbuf = srcbuf++; /* sqr time */
2664 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2666 tmpbuf = srcbuf++; /* min time */
2667 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2669 tmpbuf = srcbuf++; /* max time */
2670 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2674 /*printf("Ending index value = %d\n",idx-1);*/
2676 /* copy authentication info */
2678 srcbuf = (afs_int32 *) &(fullP->authent);
2679 numLongs = sizeof(struct afs_stats_AuthentInfo) / sizeof(afs_int32);
2680 for(i=0; i<numLongs; i++) {
2681 sprintf(a_cmData->data[idx], "%d", *srcbuf);
2685 /*printf("Ending index value = %d\n",idx-1);*/
2687 /* copy CM [un]replicated access info */
2689 srcbuf = (afs_int32 *) &(fullP->accessinf);
2690 numLongs = sizeof(struct afs_stats_AccessInfo) / sizeof(afs_int32);
2691 for(i=0; i<numLongs; i++) {
2692 sprintf(a_cmData->data[idx], "%d", *srcbuf);
2696 /*printf("Ending index value = %d\n",idx-1);*/
2699 } /* cm_Results_ltoa */
2702 /*-----------------------------------------------------------------------
2703 * Function: check_cm_thresholds()
2706 * Checks the thresholds and sets the overflow flag. Recall that the
2707 * thresholds for each host are stored in the hostEntry lists
2708 * [fs/cm]nameList arrays. The probe results are passed to this
2709 * function in the display-ready format - ie., as strings. Though
2710 * this looks stupid the overhead incurred in converting the strings
2711 * back to floats and comparing them is insignificant and
2712 * programming is easier this way.
2713 * The threshold flags are a part of the display structures
2718 *----------------------------------------------------------------------*/
2721 check_cm_thresholds(a_hostEntry, a_Data)
2722 struct afsmon_hostEntry *a_hostEntry; /* ptr to hostEntry */
2723 struct cm_Display_Data *a_Data; /* ptr to cm data to be displayed */
2725 { /* check_cm_thresholds */
2727 static char rn[] = "check_cm_thresholds";
2728 struct Threshold *threshP;
2729 double tValue; /* threshold value */
2730 double pValue; /* probe value */
2733 int count; /* number of thresholds exceeded */
2736 fprintf(debugFD,"[ %s ] Called, a_hostEntry= %d, a_Data= %d\n",
2737 rn, a_hostEntry, a_Data);
2741 if (a_hostEntry->numThresh == 0) {
2742 /* store in ovf count ?? */
2747 threshP = a_hostEntry->thresh;
2748 for(i=0; i < a_hostEntry->numThresh; i++) {
2749 if (threshP->itemName[0] == '\0') {
2750 threshP++; continue;
2752 idx = threshP->index; /* positional index to the data array */
2753 tValue = atof(threshP->threshVal); /* threshold value */
2754 pValue = atof(a_Data->data[idx]); /* probe value */
2755 if (pValue > tValue) {
2758 fprintf(debugFD,"[ %s ] cm = %s, thresh ovf for %s, threshold= %s, probevalue= %s\n",
2759 rn, a_hostEntry->hostName, threshP->itemName, threshP->threshVal , a_Data->data[idx]);
2763 /* if the threshold is crossed, call the handler function
2764 only if this was a transition -ie, if the threshold was
2765 crossed in the last probe too just count & keep quite! */
2767 if (! a_Data->threshOvf[idx]) {
2768 a_Data->threshOvf[idx] = 1;
2769 /* call the threshold handler if provided */
2770 if (threshP->handler[0] != '\0') {
2772 fprintf(debugFD,"[ %s ] Calling ovf handler %s\n",
2773 rn, threshP->handler);
2776 execute_thresh_handler(threshP->handler,
2777 a_Data->hostName, CM, threshP->itemName,
2778 threshP->threshVal, a_Data->data[idx]);
2784 /* in case threshold was previously crossed, blank it out */
2785 a_Data->threshOvf[idx] = 0;
2788 /* store the overflow count */
2789 a_Data->ovfCount = count;
2792 } /* check_cm_thresholds */
2795 /*-----------------------------------------------------------------------
2796 * save_CM_data_forDisplay()
2799 * Does the following:
2800 * - if the probe number changed (ie, a cycle completed) curr_cmData
2801 * is copied to prev_cmData, curr_cmData zeroed and refresh the
2802 * overview screen and file server screen with the new data.
2803 * - store the results of the current probe from xstat_cm_Results into
2804 * curr_cmData. ie., convert longs to strings.
2805 * - check the thresholds
2809 * Failure: Exits afsmonitor.
2811 *----------------------------------------------------------------------*/
2814 save_CM_data_forDisplay(a_cmResults)
2815 struct xstat_cm_ProbeResults *a_cmResults;
2816 { /* save_CM_data_forDisplay */
2818 static char rn[] = "save_CM_data_forDisplay"; /* routine name */
2819 struct cm_Display_Data *curr_cmDataP;
2820 struct cm_Display_Data *prev_cmDataP;
2821 struct afsmon_hostEntry *curr_host;
2822 static int probes_Received = 0; /* number of probes reveived in
2823 the current cycle. If this is equal to numFS we got all
2824 the data we want in this cycle and can now display it */
2832 fprintf(debugFD,"[ %s ] Called, a_cmResults= %d\n",rn, a_cmResults);
2836 /* store results in the display array */
2839 curr_cmDataP = curr_cmData;
2840 for (i=0; i<numCM; i++) {
2841 if((strcasecmp(curr_cmDataP->hostName,a_cmResults->connP->hostName)) == 0) {
2849 fprintf(stderr,"[ %s ] Could not insert CM probe results for host %s in cm display array\n",rn, a_cmResults->connP->hostName);
2853 /* Check the status of the probe. If it succeeded, we store its
2854 results in the display data structure. If it failed we only mark
2855 the failed status in the display data structure. */
2858 if (a_cmResults->probeOK) { /* 1 => notOK the xstat results */
2859 curr_cmDataP->probeOK = 0;
2861 /* print the probe status */
2863 fprintf(debugFD,"\n\t\t ----- cm display data ------\n");
2864 fprintf(debugFD,"HostName = %s PROBE FAILED \n",curr_cmDataP->hostName);
2868 } else { /* probe succeeded, update display data structures */
2869 curr_cmDataP->probeOK = 1;
2872 /* covert longs to strings and place them in curr_cmDataP */
2873 cm_Results_ltoa(curr_cmDataP, a_cmResults);
2875 /* compare with thresholds and set the overflow flags.
2876 note that the threshold information is in the hostEntry structure and
2877 each threshold item has a positional index associated with it */
2879 /* locate the hostEntry for this host */
2881 curr_host = CMnameList;
2882 for(i=0; i<numCM; i++) {
2883 if (strcasecmp(curr_host->hostName,a_cmResults->connP->hostName) == 0) {
2887 curr_host = curr_host->next;
2889 if (!done) afsmon_Exit(100);
2891 code = check_cm_thresholds(curr_host, curr_cmDataP);
2893 fprintf(stderr,"[ %s ] Error in checking thresholds\n",rn);
2898 /* print the info we just saved */
2900 fprintf(debugFD,"\n\t\t ----- CM display data ------\n");
2901 fprintf(debugFD,"HostName = %s\n",curr_cmDataP->hostName);
2902 for(i=0; i<NUM_CM_STAT_ENTRIES; i++) {
2904 case 0: fprintf(debugFD,"\t -- Overall Perf Info --\n");
2906 case 39: fprintf(debugFD,"\t -- File Server up/down stats - same cell --\n");
2908 case 64: fprintf(debugFD,"\t -- File Server up/down stats - diff cell --\n");
2910 case 89: fprintf(debugFD,"\t -- VL server up/down stats - same cell --\n");
2912 case 114: fprintf(debugFD,"\t -- VL server up/down stats - diff cell --\n");
2914 case 139: fprintf(debugFD,"\t -- FS Operation Timings --\n");
2916 case 279: fprintf(debugFD,"\t -- FS Error Info --\n");
2918 case 447: fprintf(debugFD,"\t -- FS Transfer Timings --\n");
2920 case 475: fprintf(debugFD,"\t -- CM Operations Timings --\n");
2922 case 510: fprintf(debugFD,"\t -- Authentication Info --\n");
2924 case 522: fprintf(debugFD,"\t -- Access Info --\n");
2929 fprintf(debugFD,"%20s %30s %s\n", curr_cmDataP->data[i],
2930 cm_varNames[i],curr_cmDataP->threshOvf[i] ? "(ovf)":"" );
2932 fprintf(debugFD,"\t\t--------------------------------\n\n");
2935 } /* if the probe succeeded, update the display data structures */
2937 /* if we have received a reply from all the hosts for this probe cycle,
2938 it is time to display the data */
2941 if (probes_Received == numCM) {
2942 probes_Received = 0;
2944 if (afsmon_cm_curr_probeNum != afsmon_cm_prev_probeNum + 1) {
2945 sprintf(errMsg,"[ %s ] Probe number %d missed! \n",
2946 rn, afsmon_cm_prev_probeNum +1);
2949 afsmon_cm_prev_probeNum++;
2952 /* backup the display data of the probe cycle that just completed -
2953 ie., store curr_cmData in prev_cmData */
2955 bcopy((char *)curr_cmData, (char *)prev_cmData,
2956 (numCM * sizeof(struct cm_Display_Data)) );
2959 /* initialize curr_cmData but retain the threshold flag information.
2960 The previous state of threshold flags is used in check_cm_thresholds()*/
2962 curr_cmDataP = curr_cmData;
2963 numBytes = NUM_CM_STAT_ENTRIES * CM_STAT_STRING_LEN;
2964 for(i=0; i<numCM; i++) {
2965 curr_cmDataP->probeOK = 0;
2966 curr_cmDataP->ovfCount = 0;
2967 bzero((char *)curr_cmDataP->data, numBytes);
2971 /* prev_cmData now contains all the information for the probe cycle
2972 that just completed. Now count the number of threshold overflows for
2973 use in the overview screen */
2975 prev_cmDataP = prev_cmData;
2977 numHosts_oncm_alerts = 0;
2978 for(i=0; i<numCM; i++) {
2979 if (! prev_cmDataP->probeOK) { /* if probe failed */
2981 numHosts_oncm_alerts++;
2982 } else if (prev_cmDataP->ovfCount) { /* overflows ?? */
2983 num_cm_alerts += prev_cmDataP->ovfCount;
2984 numHosts_oncm_alerts++;
2989 fprintf(debugFD,"Number of CM alerts = %d (on %d hosts)\n",
2990 num_cm_alerts, numHosts_oncm_alerts);
2993 /* flag that the data is now ready to be displayed */
2994 cm_Data_Available = 1;
2996 /* update the Overview frame (only CM info)*/
2997 ovw_refresh(ovw_currPage, OVW_UPDATE_CM);
2999 /* update the Cache Managers frame */
3000 cm_refresh(cm_currPage, cm_curr_LCol);
3006 } /* save_CM_data_forDisplay */
3010 /*-----------------------------------------------------------------------
3011 * afsmon_CM_Handler()
3014 * This is the Cache Manager probe Handler. It updates the afsmonitor
3015 * probe counts, cm circular buffer indices and calls the functions
3016 * to process the results of this probe.
3020 * Failure: Exits afsmonitor.
3021 *----------------------------------------------------------------------*/
3025 { /* afsmon_CM_Handler() */
3026 static char rn[] = "afsmon_CM_Handler"; /* routine name */
3027 int code; /* return status */
3028 int newProbeCycle; /* start of new probe cycle ? */
3032 "[ %s ] Called, hostName= %s, probeNum= %d, status= %s\n", rn,
3033 xstat_cm_Results.connP->hostName,
3034 xstat_cm_Results.probeNum,
3035 xstat_cm_Results.probeOK? "FAILED":"OK");
3040 /* print the probe results to output file */
3041 if (afsmon_output) {
3042 code = afsmon_cmOutput(output_filename, afsmon_detOutput);
3044 fprintf(stderr,"[ %s ] output to file %s returned error code=%d\n",
3045 rn,output_filename,code);
3049 /* Update current probe number and circular buffer index. if current
3050 probenum changed make sure it is only by 1 */
3053 if (xstat_cm_Results.probeNum != afsmon_cm_curr_probeNum) {
3054 if (xstat_cm_Results.probeNum == afsmon_cm_curr_probeNum + 1) {
3055 afsmon_cm_curr_probeNum++;
3058 afsmon_cm_curr_CBindex=
3059 (afsmon_cm_curr_probeNum - 1) % num_bufSlots;
3062 fprintf(stderr,"[ %s ] probe number %d-1 missed\n",
3063 rn,xstat_cm_Results.probeNum);
3068 /* save the results of this probe in the CM buffer */
3070 save_CM_results_inCB(newProbeCycle);
3072 /* store the results of the current probe in the cm data display structure.
3073 if the current probe number changed, swap the current and previous display
3074 structures. note that the display screen is updated from these structures
3075 and should start showing the data of the just completed probe cycle */
3077 save_CM_data_forDisplay(&xstat_cm_Results);
3082 /*-----------------------------------------------------------------------
3086 * Allocate and Initialize circular buffers for file servers.
3090 * Failure to allocate memory: exits afsmonitor.
3091 *----------------------------------------------------------------------*/
3095 { /* init_fs_buffers() */
3096 static char rn[] = "init_fs_buffers"; /* routine name */
3097 struct afsmon_fs_Results_list *new_fslist_item; /* ptr for new struct */
3098 struct afsmon_fs_Results_list *tmp_fslist_item; /* temp ptr */
3099 struct xstat_fs_ProbeResults *new_fsPR; /* ptr for new struct */
3106 fprintf(debugFD,"[ %s ] Called\n",rn);
3110 /* allocate memory for the circular buffer of pointers */
3112 afsmon_fs_ResultsCB = (struct afsmon_fs_Results_CBuffer *) malloc(
3113 sizeof(struct afsmon_fs_Results_CBuffer) * num_bufSlots);
3115 /* initialize the fs circular buffer */
3116 for (i=0; i<num_bufSlots; i++) {
3117 afsmon_fs_ResultsCB[i].list = (struct afsmon_fs_Results_list *)0;
3118 afsmon_fs_ResultsCB[i].probeNum = 0;
3121 /* create a list of numFS items to store fs probe results for
3124 if (numFS) { /* if we have file servers to monitor */
3125 for(bufslot=0; bufslot<num_bufSlots; bufslot++) {
3126 numfs = numFS; /* get the number of servers */
3129 /* if any of these mallocs fail we only need to free the memory we
3130 have allocated in this iteration. the rest of it which is in a
3131 proper linked list will be freed in afsmon_Exit */
3133 /* allocate memory for an fs list item */
3134 new_fslist_item = (struct afsmon_fs_Results_list *) malloc (
3135 sizeof(struct afsmon_fs_Results_list));
3136 if (new_fslist_item == (struct afsmon_fs_Results_list *)0)
3139 /* allocate memory to store xstat_fs_Results */
3140 new_fsPR = (struct xstat_fs_ProbeResults *) malloc(
3141 sizeof(struct xstat_fs_ProbeResults));
3142 if (new_fsPR == (struct xstat_fs_ProbeResults *)0) {
3143 free(new_fslist_item);
3146 new_fsPR->connP = (struct xstat_fs_ConnectionInfo *) malloc(
3147 sizeof(struct xstat_fs_ConnectionInfo));
3148 if (new_fsPR->connP == (struct xstat_fs_ConnectionInfo *)0 ) {
3149 free(new_fslist_item);
3154 /* >>> need to allocate rx connection info structure here <<< */
3156 new_fsPR->data.AFS_CollData_val = (afs_int32 *) malloc(
3157 XSTAT_FS_FULLPERF_RESULTS_LEN * sizeof(afs_int32));
3158 if (new_fsPR->data.AFS_CollData_val == (afs_int32 *)0) {
3159 free(new_fslist_item);
3160 free(new_fsPR->connP);
3165 /* initialize this list entry */
3166 new_fslist_item->fsResults = new_fsPR;
3167 new_fslist_item->empty = 1;
3168 new_fslist_item->next = (struct afsmon_fs_Results_list *)0;
3170 /* store it at the end of the fs list in the current CB slot */
3171 if (afsmon_fs_ResultsCB[bufslot].list == (struct afsmon_fs_Results_list *)0)
3172 afsmon_fs_ResultsCB[ bufslot ].list = new_fslist_item;
3174 tmp_fslist_item = afsmon_fs_ResultsCB[ bufslot ].list;
3176 while(tmp_fslist_item != (struct afsmon_fs_Results_list *)0)
3178 if (tmp_fslist_item->next == (struct afsmon_fs_Results_list *)0)
3180 tmp_fslist_item = tmp_fslist_item->next;
3183 /* something goofed. exit */
3184 fprintf(stderr,"[ %s ] list creation error\n",rn);
3188 tmp_fslist_item->next = new_fslist_item;
3191 } /* while servers */
3192 } /* for each buffer slot */
3193 } /* if we have file servers to monitor */
3197 /*-----------------------------------------------------------------------
3201 * Allocate and Initialize circular buffers for cache managers.
3205 * Failure to allocate memory: exits afsmonitor.
3206 *----------------------------------------------------------------------*/
3210 { /* init_cm_buffers() */
3211 static char rn[] = "init_cm_buffers"; /* routine name */
3212 struct afsmon_cm_Results_list *new_cmlist_item; /* ptr for new struct */
3213 struct afsmon_cm_Results_list *tmp_cmlist_item; /* temp ptr */
3214 struct xstat_cm_ProbeResults *new_cmPR; /* ptr for new struct */
3220 fprintf(debugFD,"[ %s ] Called\n",rn);
3224 /* allocate memory for the circular buffer of pointers */
3225 afsmon_cm_ResultsCB = (struct afsmon_cm_Results_CBuffer *) malloc(
3226 sizeof(struct afsmon_cm_Results_CBuffer) * num_bufSlots);
3228 /* initialize the fs circular buffer */
3229 for (i=0; i<num_bufSlots; i++) {
3230 afsmon_cm_ResultsCB[i].list = (struct afsmon_cm_Results_list *)0;
3231 afsmon_cm_ResultsCB[i].probeNum = 0;
3234 /* create a list of numCM items to store fs probe results for
3237 if (numCM) { /* if we have file servers to monitor */
3238 for(bufslot=0; bufslot<num_bufSlots; bufslot++) {
3239 numcm = numCM; /* get the number of servers */
3242 /* if any of these mallocs fail we only need to free the memory we
3243 have allocated in this iteration. the rest of it which is in a
3244 proper linked list will be freed in afsmon_Exit */
3246 /* allocate memory for an fs list item */
3247 new_cmlist_item = (struct afsmon_cm_Results_list *) malloc (
3248 sizeof(struct afsmon_cm_Results_list));
3249 if (new_cmlist_item == (struct afsmon_cm_Results_list *)0)
3252 /* allocate memory to store xstat_cm_Results */
3253 new_cmPR = (struct xstat_cm_ProbeResults *) malloc(
3254 sizeof(struct xstat_cm_ProbeResults));
3255 if (new_cmPR == (struct xstat_cm_ProbeResults *)0) {
3256 free(new_cmlist_item);
3259 new_cmPR->connP = (struct xstat_cm_ConnectionInfo *) malloc(
3260 sizeof(struct xstat_cm_ConnectionInfo));
3261 if (new_cmPR->connP == (struct xstat_cm_ConnectionInfo *)0 ) {
3262 free(new_cmlist_item);
3267 /* >>> need to allocate rx connection info structure here <<< */
3269 new_cmPR->data.AFSCB_CollData_val = (afs_int32 *) malloc(
3270 XSTAT_CM_FULLPERF_RESULTS_LEN * sizeof(afs_int32));
3271 if (new_cmPR->data.AFSCB_CollData_val == (afs_int32 *)0) {
3272 free(new_cmlist_item);
3273 free(new_cmPR->connP);
3278 /* initialize this list entry */
3279 new_cmlist_item->cmResults = new_cmPR;
3280 new_cmlist_item->empty = 1;
3281 new_cmlist_item->next = (struct afsmon_cm_Results_list *)0;
3283 /* store it at the end of the cm list in the current CB slot */
3284 if (afsmon_cm_ResultsCB[bufslot].list == (struct afsmon_cm_Results_list *)0)
3285 afsmon_cm_ResultsCB[ bufslot ].list = new_cmlist_item;
3287 tmp_cmlist_item = afsmon_cm_ResultsCB[ bufslot ].list;
3289 while(tmp_cmlist_item != (struct afsmon_cm_Results_list *)0)
3291 if (tmp_cmlist_item->next == (struct afsmon_cm_Results_list *)0)
3293 tmp_cmlist_item = tmp_cmlist_item->next;
3296 /* something goofed. exit */
3297 fprintf(stderr,"[ %s ] list creation error\n",rn);
3301 tmp_cmlist_item->next = new_cmlist_item;
3304 } /* while servers */
3305 } /* for each buffer slot */
3306 } /* if we have file servers to monitor */
3307 /* print the CB to make sure it is right */
3311 } /* init_cm_buffers() */
3314 /*-------------------------------------------------------------------------
3315 * init_print_buffers()
3318 * Allocate and initialize the buffers used for printing results
3319 * to the display screen. These buffers store the current and
3320 * previous probe results in ascii format.
3325 *------------------------------------------------------------------------*/
3328 init_print_buffers()
3329 { /* init_print_buffers */
3331 static char rn[] = "init_print_buffers"; /* routine name */
3332 struct fs_Display_Data *tmp_fsData1; /* temp pointers */
3333 struct fs_Display_Data *tmp_fsData2;
3334 struct cm_Display_Data *tmp_cmData1;
3335 struct cm_Display_Data *tmp_cmData2;
3336 struct afsmon_hostEntry *tmp_fsNames;
3337 struct afsmon_hostEntry *tmp_cmNames;
3342 fprintf(debugFD,"[ %s ] Called\n",rn);
3346 /* allocate numFS blocks of the FS print structure. */
3348 /* we need two instances of this structure - one (curr_fsData) for storing
3349 the results of the fs probes currently in progress and another (prev_fsData)
3350 for the last completed probe. The display is updated from the contents of
3351 prev_fsData. The pointers curr_fsData & prev_fsData are switched whenever
3352 the probe number changes */
3355 numBytes = numFS * sizeof(struct fs_Display_Data);
3356 curr_fsData = (struct fs_Display_Data *) malloc(numBytes);
3357 if (curr_fsData == (struct fs_Display_Data *)0) {
3358 fprintf(stderr,"[ %s ] Memory allocation failure\n",rn);
3361 bzero(curr_fsData,numBytes);
3363 numBytes = numFS * sizeof(struct fs_Display_Data);
3364 prev_fsData = (struct fs_Display_Data *) malloc(numBytes);
3365 if (prev_fsData == (struct fs_Display_Data *)0) {
3366 fprintf(stderr,"[ %s ] Memory allocation failure\n",rn);
3369 bzero(prev_fsData,numBytes);
3371 /* fill in the host names */
3372 tmp_fsData1 = curr_fsData;
3373 tmp_fsData2 = curr_fsData;
3374 tmp_fsNames = FSnameList;
3375 for(i=0; i<numFS; i++) {
3376 strncpy(tmp_fsData1->hostName, tmp_fsNames->hostName, HOST_NAME_LEN);
3377 strncpy(tmp_fsData2->hostName, tmp_fsNames->hostName, HOST_NAME_LEN);
3380 tmp_fsNames = tmp_fsNames->next;;
3383 } /* if file servers to monitor */
3385 /* allocate numCM blocks of the CM print structure */
3386 /* we need two instances of this structure for the same reasons as above*/
3389 numBytes = numCM * sizeof(struct cm_Display_Data);
3391 curr_cmData = (struct cm_Display_Data *) malloc(numBytes);
3392 if (curr_cmData == (struct cm_Display_Data *)0) {
3393 fprintf(stderr,"[ %s ] Memory allocation failure\n",rn);
3396 bzero(curr_cmData,numBytes);
3398 numBytes = numCM * sizeof(struct cm_Display_Data);
3399 prev_cmData = (struct cm_Display_Data *) malloc(numBytes);
3400 if (prev_cmData == (struct cm_Display_Data *)0) {
3401 fprintf(stderr,"[ %s ] Memory allocation failure\n",rn);
3404 bzero(prev_cmData,numBytes);
3406 /* fill in the host names */
3407 tmp_cmData1 = curr_cmData;
3408 tmp_cmData2 = curr_cmData;
3409 tmp_cmNames = CMnameList;
3410 for(i=0; i<numCM; i++) {
3411 strncpy(tmp_cmData1->hostName, tmp_cmNames->hostName, HOST_NAME_LEN);
3412 strncpy(tmp_cmData2->hostName, tmp_cmNames->hostName, HOST_NAME_LEN);
3415 tmp_cmNames = tmp_cmNames->next;;
3418 } /* if cache managers to monitor */
3422 } /* init_print_buffers */
3424 /*-----------------------------------------------------------------------
3428 * Trap the interrupt signal. This function is useful only until
3429 * gtx is initialized.
3430 *----------------------------------------------------------------------*/
3436 static char *rn = "quit_signal"; /* routine name */
3438 fprintf(stderr,"Received signal %d \n",sig);
3444 /*-----------------------------------------------------------------------
3448 * This is where we start it all. Initialize an array of sockets for
3449 * file servers and cache cache managers and call the xstat_[fs/cm]_Init
3450 * routines. The last step is to call the gtx input server which
3451 * grabs control of the keyboard.
3454 * Does not return. Control is periodically returned to the afsmonitor
3455 * thru afsmon_[FS/CM]_Handler() routines and also through the gtx
3456 * keyboard handler calls.
3458 *----------------------------------------------------------------------*/
3462 { /* afsmon_execute() */
3463 static char rn[] = "afsmon_execute"; /* routine name */
3464 static char fullhostname[128]; /* full host name */
3465 struct sockaddr_in *FSSktArray; /* fs socket array */
3466 int FSsktbytes; /* num bytes in above */
3467 struct sockaddr_in *CMSktArray; /* cm socket array */
3468 int CMsktbytes; /* num bytes in above */
3469 struct sockaddr_in *curr_skt; /* ptr to current socket*/
3470 struct afsmon_hostEntry *curr_FS; /* ptr to FS name list */
3471 struct afsmon_hostEntry *curr_CM; /* ptr to CM name list */
3472 struct hostent *he; /* host entry */
3473 afs_int32 *collIDP; /* ptr to collection ID */
3474 int numCollIDs; /* number of collection IDs */
3475 int FSinitFlags = 0; /* flags for xstat_fs_Init */
3476 int CMinitFlags = 0; /* flags for xstat_cm_Init */
3477 int code; /* function return code */
3478 struct timeval tv; /* time structure */
3481 fprintf(debugFD,"[ %s ] Called\n",rn);
3486 /* process file server entries */
3488 /* Allocate an array of sockets for each fileserver we monitor */
3490 FSsktbytes = numFS * sizeof(struct sockaddr_in);
3491 FSSktArray = (struct sockaddr_in *) malloc(FSsktbytes);
3492 if (FSSktArray == (struct sockaddr_in *)0) {
3493 fprintf(stderr,"[ %s ] cannot malloc %d sockaddr_ins for fileservers\n",
3498 bzero(FSSktArray, FSsktbytes);
3500 /* Fill in the socket information for each fileserve */
3502 curr_skt = FSSktArray;
3503 curr_FS = FSnameList; /* FS name list header */
3505 strncpy(fullhostname,curr_FS->hostName,sizeof(fullhostname));
3506 he = GetHostByName(fullhostname);
3507 if (he == (struct hostent *)0) {
3508 fprintf(stderr,"[ %s ] Cannot get host info for %s\n",rn, fullhostname);
3511 strncpy(curr_FS->hostName,he->h_name,HOST_NAME_LEN); /* complete name*/
3512 bcopy(he->h_addr, &(curr_skt->sin_addr.s_addr), 4);
3513 curr_skt->sin_family = htons(AF_INET); /*Internet family*/
3514 curr_skt->sin_port = htons(7000); /*FileServer port*/
3516 /* get the next dude */
3518 curr_FS = curr_FS->next;
3521 /* initialize collection IDs. We need only one entry since we collect
3522 all the information from xstat */
3525 collIDP = (afs_int32 *) malloc (sizeof (afs_int32));
3526 if (collIDP == (afs_int32 *)0) {
3527 fprintf(stderr,"[ %s ] failed to allocate a measely afs_int32 word.Argh!\n", rn);
3530 *collIDP = 2; /* USE A macro for this */
3533 if (afsmon_onceOnly) /* option not provided at this time */
3534 FSinitFlags |= XSTAT_FS_INITFLAG_ONE_SHOT;
3537 fprintf(debugFD,"[ %s ] Calling xstat_fs_Init \n",rn);
3541 code = xstat_fs_Init(numFS, /*Num servers*/
3542 FSSktArray, /*File Server socket array*/
3543 afsmon_probefreq, /*probe frequency*/
3544 afsmon_FS_Handler, /*Handler routine*/
3545 FSinitFlags, /*Initialization flags*/
3546 numCollIDs, /*Number of collection IDs*/
3547 collIDP); /*Ptr to collection ID */
3550 fprintf(stderr,"[ %s ] xstat_fs_init returned error\n",rn);
3554 } /* end of process fileserver entries */
3556 /* process cache manager entries */
3559 /* Allocate an array of sockets for each cache manager we monitor */
3561 CMsktbytes = numCM * sizeof(struct sockaddr_in);
3562 CMSktArray = (struct sockaddr_in *) malloc(CMsktbytes);
3563 if (CMSktArray == (struct sockaddr_in *)0) {
3564 fprintf(stderr,"[ %s ] cannot malloc %d sockaddr_ins for CM entries\n",
3569 bzero(CMSktArray, CMsktbytes);
3571 /* Fill in the socket information for each CM */
3573 curr_skt = CMSktArray;
3574 curr_CM = CMnameList; /* CM name list header */
3576 strncpy(fullhostname,curr_CM->hostName,sizeof(fullhostname));
3577 he = GetHostByName(fullhostname);
3578 if (he == (struct hostent *)0) {
3579 fprintf(stderr,"[ %s ] Cannot get host info for %s\n",rn, fullhostname);
3582 strncpy(curr_CM->hostName,he->h_name,HOST_NAME_LEN); /* complete name*/
3583 bcopy(he->h_addr, &(curr_skt->sin_addr.s_addr), 4);
3584 curr_skt->sin_family = htons(AF_INET); /*Internet family*/
3585 curr_skt->sin_port = htons(7001); /*Cache Manager port*/
3587 /* get the next dude */
3589 curr_CM = curr_CM->next;
3592 /* initialize collection IDs. We need only one entry since we collect
3593 all the information from xstat */
3596 collIDP = (afs_int32 *) malloc (sizeof (afs_int32));
3597 if (collIDP == (afs_int32 *)0) {
3598 fprintf(stderr,"[ %s ] failed to allocate a measely long word.Argh!\n", rn);
3601 *collIDP = 2; /* USE A macro for this */
3604 if (afsmon_onceOnly) /* once only ? */
3605 CMinitFlags |= XSTAT_CM_INITFLAG_ONE_SHOT;
3608 fprintf(debugFD,"[ %s ] Calling xstat_cm_Init \n",rn);
3612 code = xstat_cm_Init(numCM, /*Num servers*/
3613 CMSktArray, /*Cache Manager socket array*/
3614 afsmon_probefreq, /*probe frequency*/
3615 afsmon_CM_Handler, /*Handler routine*/
3616 CMinitFlags, /*Initialization flags*/
3617 numCollIDs, /*Number of collection IDs*/
3618 collIDP); /*Ptr to collection ID */
3621 fprintf(stderr,"[ %s ] xstat_cm_init returned error\n",rn);
3624 } /* end of process cache manager entries */
3627 /* if only one probe was required setup a waiting process for the
3628 termination signal */
3630 if (afsmon_onceOnly) {
3631 code = LWP_WaitProcess(&terminationEvent);
3634 fprintf(debugFD,"LWP_WaitProcess() returned error %d\n",code);
3641 /* start the gtx input server */
3642 code = gtx_InputServer(afsmon_win);
3644 fprintf(stderr,"[ %s ] Failed to start input server \n",rn);
3648 /* This part of the code is reached only if the input server is not started
3649 for debugging purposes */
3654 fprintf(stderr,"[ %s ] going to sleep ...\n",rn);
3656 code = IOMGR_Select( 0, /*Num fds*/
3657 0, /*Descriptors ready for reading*/
3658 0, /*Descriptors ready for writing*/
3659 0, /*Descriptors with exceptional conditions*/
3660 &tv); /*Timeout structure*/
3662 fprintf(stderr,"[ %s ] IOMGR_Select() returned non-zero value %d\n",
3670 /*-----------------------------------------------------------------------
3674 * Afsmonitor initialization routine.
3675 * - processes command line parameters
3676 * - call functions to:
3677 * - process config file
3678 * - initialize circular buffers and display buffers
3680 * - execute afsmonitor
3681 * - initialize the display maps [fs/cm]_Display_map[].
3684 * Success: Does not return from the call to afsmon_execute().
3685 * Failure: Exits afsmonitor.
3686 *----------------------------------------------------------------------*/
3690 struct cmd_syndesc *as;
3691 { /* afsmonInit() */
3693 static char rn[] = "afsmonInit"; /* Routine name */
3694 char *debug_filename; /* pointer to debug filename */
3695 FILE *outputFD; /* output file descriptor */
3696 struct cmd_item *hostPtr; /* ptr to parse command line args */
3697 char buf[256]; /* buffer for processing hostnames */
3702 fprintf(debugFD,"[ %s ] Called, as= %d\n",rn, as);
3706 /* Open the debug file if -debug option is specified */
3707 if (as->parms[P_DEBUG].items != 0) {
3709 debug_filename = as->parms[P_DEBUG].items->data;
3710 debugFD = fopen(debug_filename, "w");
3711 if (debugFD == (FILE *)0) {
3712 printf("[ %s ] Failed to open debugging file %s for writing\n",
3720 fprintf(debugFD,"[ %s ] Called\n", rn);
3724 /* use curses always until we support other packages */
3726 wpkg_to_use = atoi(as->parms[P_PACKAGE].items->data);
3728 switch (wpkg_to_use) {
3729 case GATOR_WIN_CURSES:
3730 fprintf(stderr, "curses\n");
3732 case GATOR_WIN_DUMB:
3733 fprintf(stderr, "dumb terminal\n");
3736 fprintf(stderr, "X11\n");
3739 fprintf(stderr, "Illegal graphics package: %d\n", wpkg_to_use);
3741 } /*end switch (wpkg_to_use)*/
3744 wpkg_to_use = GATOR_WIN_CURSES;
3746 /* get probe frequency . We check for meaningful bounds on the frequency
3747 and reset to the default value if needed. The upper bound of 24
3748 hours looks ridiculous though! */
3750 afsmon_probefreq = 0;
3751 if (as->parms[P_FREQUENCY].items != 0)
3752 afsmon_probefreq = atoi(as->parms[P_FREQUENCY].items->data);
3754 afsmon_probefreq = DEFAULT_FREQUENCY;
3756 if (afsmon_probefreq <= 0 || afsmon_probefreq > 24*60*60) {
3757 afsmon_probefreq = DEFAULT_FREQUENCY;
3759 fprintf(debugFD,"[ %s ] Invalid probe frequency %s specified, resetting to default value %d seconds\n",
3760 rn, as->parms[P_FREQUENCY].items->data, afsmon_probefreq);
3763 fprintf(stderr,"Invalid probe frequency %s specified, resetting to default value %d seconds\n",
3764 as->parms[P_FREQUENCY].items->data, afsmon_probefreq);
3769 /* make sure output file is writable, else complain now */
3770 /* we will open and close it as needed after probes */
3772 if (as->parms[P_OUTPUT].items != 0) {
3773 afsmon_output = 1; /* output flag */
3774 strncpy (output_filename, as->parms[P_OUTPUT].items->data,80);
3775 outputFD = fopen(output_filename,"a");
3776 if (outputFD == (FILE *)0) {
3777 fprintf(stderr,"Failed to open output file %s \n",
3780 fprintf(debugFD,"[ %s ] Failed to open output file %s \n",
3781 rn, output_filename);
3786 fprintf(debugFD,"[ %s ] output file is %s\n",rn,output_filename);
3791 /* detailed statistics to storage file */
3792 if (as->parms[P_DETAILED].items !=0) {
3793 if (as->parms[P_OUTPUT].items == 0) {
3794 fprintf(stderr,"-detailed switch can be used only with -output\n");
3797 afsmon_detOutput = 1;
3800 /* Initialize host list headers */
3801 FSnameList = (struct afsmon_hostEntry *)0;
3802 CMnameList = (struct afsmon_hostEntry *)0;
3804 /* The -config option is mutually exclusive with the -fshosts,-cmhosts
3807 if (as->parms[P_CONFIG].items) {
3808 if (as->parms[P_FSHOSTS].items || as->parms[P_CMHOSTS].items) {
3809 fprintf(stderr,"Cannot use -config option with -fshosts or -cmhosts\n");
3813 if (! as->parms[P_FSHOSTS].items && ! as->parms[P_CMHOSTS].items) {
3814 fprintf(stderr,"Must specify either -config or (-fshosts and/or -cmhosts) options \n");
3820 /* If a file server host is specified on the command line we reuse
3821 parse_hostEntry() function . Just the pass the info as if it were
3822 read off the config file */
3824 if (as->parms[P_FSHOSTS].items) {
3825 hostPtr = as->parms[P_FSHOSTS].items;
3826 while( hostPtr != (struct cmd_item *)0) {
3827 sprintf(buf,"fs %s",hostPtr->data);
3828 code = parse_hostEntry(buf);
3830 fprintf(stderr,"Could not parse %s\n",hostPtr->data);
3834 hostPtr = hostPtr->next;
3838 /* same as above for -cmhosts */
3839 if (as->parms[P_CMHOSTS].items) {
3840 hostPtr = as->parms[P_CMHOSTS].items;
3841 while( hostPtr != (struct cmd_item *)0) {
3842 sprintf(buf,"cm %s",hostPtr->data);
3843 code = parse_hostEntry(buf);
3845 fprintf(stderr,"Could not parse %s\n",hostPtr->data);
3849 hostPtr = hostPtr->next;
3853 /* number of slots in circular buffers */
3854 if (as->parms[P_BUFFERS].items)
3855 num_bufSlots = atoi(as->parms[P_BUFFERS].items->data);
3857 num_bufSlots = DEFAULT_BUFSLOTS;
3859 /* Initialize xx_showFlags[]. This array is used solely for processing the
3860 "show" directives in the config file in parse_showEntries() */
3861 for(i=0; i<NUM_FS_STAT_ENTRIES; i++)
3862 fs_showFlags[i] = 0;
3863 for(i=0; i<NUM_CM_STAT_ENTRIES; i++)
3864 cm_showFlags[i] = 0;
3867 /* Process the configuration file if given. This initializes among other
3868 things, the list of FS & CM names in FSnameList and CMnameList */
3870 if (as->parms[P_CONFIG].items)
3871 process_config_file(as->parms[P_CONFIG].items->data);
3873 /* print out the FS and CM lists */
3874 print_FS(); print_CM();
3876 /* Initialize the FS results-to-screen map array if there were no "show fs"
3877 directives in the config file */
3878 if (fs_showDefault) {
3879 for(i=0; i < NUM_FS_STAT_ENTRIES; i++)
3880 fs_Display_map[i] = i;
3881 fs_DisplayItems_count = NUM_FS_STAT_ENTRIES;
3884 /* Initialize the CM results-to-screen map array if there were no "show cm"
3885 directives in the config file */
3886 if (cm_showDefault) {
3887 for(i=0; i < NUM_CM_STAT_ENTRIES; i++)
3888 cm_Display_map[i] = i;
3889 cm_DisplayItems_count = NUM_CM_STAT_ENTRIES;
3894 /* setup an interrupt signal handler; we ain't wanna leak core */
3895 /* this binding is useful only until gtx is initialized after which the
3896 keyboard input server takes over. */
3897 if ( (signal(SIGINT,quit_signal)) == SIG_ERR ) {
3898 perror("signal() failed.");
3903 /* init error message buffers. these will be used to print error messages
3904 once gtx is initialized and there is no access to stderr/stdout */
3905 errMsg[0] = '\0'; errMsg1[0] = '\0';
3909 /* initialize fs and cm circular buffers before initiating probes */
3911 code = init_fs_buffers();
3913 fprintf(stderr,"[ %s ] init_fs_buffers returned %d\n",rn,code);
3919 code = init_cm_buffers();
3921 fprintf(stderr,"[ %s ] init_cm_buffers returned %d\n",rn,code);
3927 /* allocate and initialize buffers for holding fs & cm results in ascii
3928 format suitable for updating the screen */
3929 code = init_print_buffers();
3931 fprintf(stderr,"[ %s ] init_print_buffers returned %d\n",rn,code);
3935 /* perform gtx initializations */
3936 code = gtx_initialize();
3938 fprintf(stderr,"[ %s ] gtx_initialize returned %d\n",rn,code);
3942 /* start xstat probes */
3945 return(0); /* will not return from the call to afsmon_execute() */
3947 } /* afsmonInit() */
3950 /*-----------------------------------------------------------------------
3952 ------------------------------------------------------------------------*/
3954 #include "AFS_component_version_number.c"
3956 int main(argc, argv)
3961 static char rn[] = "main"; /* routine name */
3962 afs_int32 code; /*Return code*/
3963 struct cmd_syndesc *ts; /*Ptr to cmd line syntax descriptor*/
3965 #ifdef AFS_AIX32_ENV
3967 * The following signal action for AIX is necessary so that in case of a
3968 * crash (i.e. core is generated) we can include the user's data section
3969 * in the core dump. Unfortunately, by default, only a partial core is
3970 * generated which, in many cases, isn't too useful.
3972 struct sigaction nsa;
3974 sigemptyset(&nsa.sa_mask);
3975 nsa.sa_handler = SIG_DFL;
3976 nsa.sa_flags = SA_FULLDUMP;
3977 sigaction(SIGSEGV, &nsa, NULL);
3981 * Set up the commands we understand.
3983 ts = cmd_CreateSyntax("initcmd", afsmonInit, 0,
3984 "initialize the program");
3985 cmd_AddParm(ts, "-config", CMD_SINGLE, CMD_OPTIONAL,
3986 "configuration file");
3987 cmd_AddParm(ts, "-frequency", CMD_SINGLE, CMD_OPTIONAL,
3988 "poll frequency, in seconds");
3989 cmd_AddParm(ts, "-output", CMD_SINGLE, CMD_OPTIONAL,
3990 "storage file name");
3991 cmd_AddParm(ts, "-detailed", CMD_FLAG, CMD_OPTIONAL,
3992 "output detailed statistics to storage file");
3994 /* we hope to use this .... eventually! */
3995 cmd_AddParm(ts,"-package", CMD_SINGLE, CMD_REQUIRED,
3996 "Graphics Package to use");
3998 cmd_AddParm(ts, "-debug", CMD_SINGLE, CMD_OPTIONAL,
3999 "turn debugging output on to the named file");
4000 cmd_AddParm(ts, "-fshosts", CMD_LIST, CMD_OPTIONAL,
4001 "list of file servers to monitor");
4002 cmd_AddParm(ts, "-cmhosts", CMD_LIST, CMD_OPTIONAL,
4003 "list of cache managers to monitor");
4004 cmd_AddParm(ts,"-buffers", CMD_SINGLE, CMD_OPTIONAL,
4005 "number of buffer slots");
4008 * Parse command-line switches & execute afsmonitor
4011 code = cmd_Dispatch(argc, argv);
4017 exit(0); /* redundant, but gets rid of warning */