2 * Copyright 2000, International Business Machines Corporation and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
11 * Afsmonitor: An AFS Performance Monitoring Tool
13 *-------------------------------------------------------------------------*/
16 #include <afsconfig.h>
17 #include <afs/param.h>
29 #include <sys/types.h>
30 #include <netinet/in.h>
32 #include <sys/socket.h>
37 #include <gtxwindows.h> /*Generic window package */
38 #include <gtxobjects.h> /*Object definitions */
40 #include <gtxtextobj.h> /*Text object interface */
42 #include <gtxlightobj.h> /*Light object interface */
43 #include <gtxcurseswin.h> /*Curses window package */
44 #include <gtxdumbwin.h> /*Dumb terminal window package */
45 #include <gtxX11win.h> /*X11 window package */
46 #include <gtxframe.h> /*Frame package */
50 #include <afs/xstat_fs.h>
51 #include <afs/xstat_cm.h>
54 #include "afsmonitor.h"
57 /* command line parameter indices */
63 /* #define P_PACKAGE X */
70 int afsmon_debug = 0; /* debug info to file ? */
71 FILE *debugFD; /* debugging file descriptor */
72 static int afsmon_output = 0; /* output to file ? */
73 static int afsmon_detOutput = 0; /* detailed output ? */
74 static int afsmon_onceOnly = 0; /* probe once only ? (not implemented) */
75 int afsmon_probefreq; /* probe frequency */
76 static int wpkg_to_use; /* graphics package to use */
77 static char output_filename[80]; /* output filename */
78 char errMsg[256]; /* buffers used to print error messages after */
79 char errMsg1[256]; /* gtx is initialized (stderr/stdout gone !) */
80 int num_bufSlots = 0; /* number of slots in fs & cm circular buffers */
82 /* Flags used to process "show" directives in config file */
83 short fs_showFlags[NUM_FS_STAT_ENTRIES];
84 short cm_showFlags[NUM_CM_STAT_ENTRIES];
87 /* afsmonitor misc definitions */
89 #define DEFAULT_FREQUENCY 60 /* default proble frequency in seconds */
90 #define DEFAULT_BUFSLOTS 0 /* default number of buffer slots */
91 #define CFG_STR_LEN 80 /* max length of config file fields */
92 #define FS 1 /* for misc. use */
93 #define CM 2 /* for misc. use */
96 #define NUM_XSTAT_FS_AFS_PERFSTATS_LONGS 66 /* number of fields (longs) in struct afs_PerfStats that we display */
97 #define NUM_AFS_STATS_CMPERF_LONGS 40 /* number of longs in struct afs_stats_CMPerf excluding up/down stats and fields we dont display */
100 /* variables used for exec'ing user provided threshold handlers */
101 char *fsHandler_argv[20]; /* *argv[] for the handler */
102 char fsHandler_args[20][256]; /* buffer space for arguments */
103 int exec_fsThreshHandler = 0; /* execute fs threshold handler ? */
106 /* THRESHOLD STRUCTURE DEFINITIONS */
108 /* flag to indicate that threshold entries apply to all hosts. these will
109 be turned off when the first fs or cm host entry is processed */
110 static int global_ThreshFlag = 1;
111 static int global_fsThreshCount = 0; /* number of global fs thresholds */
112 static int global_cmThreshCount = 0; /* number of global cm thresholds */
116 /* Linked lists of file server and cache manager host names are made from
117 the entries in the config file. Head pointers to FS and CM server name lists. */
118 static struct afsmon_hostEntry *FSnameList;
119 static struct afsmon_hostEntry *CMnameList;
121 /* number of fileservers and cache managers to monitor */
125 /* variables used for processing config file */
126 /* ptr to the hostEntry structure of the last "fs" or "cm" entry processed
127 in the config file */
128 static struct afsmon_hostEntry *last_hostEntry;
129 /* names of the last host processed in the config file */
130 static char last_fsHost[HOST_NAME_LEN];
131 static char last_cmHost[HOST_NAME_LEN];
132 static lastHostType = 0; /* 0 = no host entries processed
133 * 1 = last host was file server
134 * 2 = last host was cache manager. */
137 /* FILE SERVER CIRCULAR BUFFER VARIABLES */
139 struct afsmon_fs_Results_list {
140 struct xstat_fs_ProbeResults *fsResults; /* ptr to results struct */
141 int empty; /* fsResults empty ? */
142 struct afsmon_fs_Results_list *next;
145 struct afsmon_fs_Results_CBuffer {
146 int probeNum; /* probe number of entries in this slot */
147 struct afsmon_fs_Results_list *list; /* ptr to list of results */
150 /* buffer for FS probe results */
151 struct afsmon_fs_Results_CBuffer *afsmon_fs_ResultsCB;
153 int afsmon_fs_curr_CBindex = 0; /* current fs CB slot */
155 /* Probe number variables. The current probe number is incremented
156 when the first probe from a new probe cycle is received. The prev probe
157 number is incremented when the last probe of the current cycle is
158 received. This difference is because of the purpose for which these
161 int afsmon_fs_curr_probeNum = 1; /* current fs probe number */
162 int afsmon_fs_prev_probeNum = 0; /* previous fs probe number */
165 /* CACHE MANAGER CIRCULAR BUFFER VARIABLES */
167 struct afsmon_cm_Results_list {
168 struct xstat_cm_ProbeResults *cmResults; /* ptr to results struct */
169 int empty; /* cmResults empty ? */
170 struct afsmon_cm_Results_list *next;
173 struct afsmon_cm_Results_CBuffer {
174 int probeNum; /* probe number of entries in this slot */
175 struct afsmon_cm_Results_list *list; /* ptr to list of results */
178 /* buffer for CM probe results */
179 struct afsmon_cm_Results_CBuffer *afsmon_cm_ResultsCB;
181 int afsmon_cm_curr_CBindex = 0; /* current cm CB slot */
184 /* Probe number variables. The current probe number is incremented
185 when the first probe from a new probe cycle is received. The prev probe
186 number is incremented when the last probe of the current cycle is
187 received. This difference is because of the purpose for which these
190 int afsmon_cm_curr_probeNum = 1; /* current cm probe number */
191 int afsmon_cm_prev_probeNum = 0; /* previous cm probe number */
194 /* Structures to hold FS & CM results in string format(suitable for display ) */
196 /* ptr to array holding the results of FS probes in ascii format */
197 /* for current probe cycle */
198 struct fs_Display_Data *curr_fsData = (struct fs_Display_Data *)0;
199 /* for previous probe cycle */
200 struct fs_Display_Data *prev_fsData = (struct fs_Display_Data *)0;
203 /* ptr to array holding the results of CM probes in ascii format */
204 /* for current probe cycle */
205 struct cm_Display_Data *curr_cmData = (struct cm_Display_Data *)0;
206 /* for previous probe cycle */
207 struct cm_Display_Data *prev_cmData = (struct cm_Display_Data *)0;
210 /* EXTERN DEFINITIONS */
212 extern struct hostent *hostutil_GetHostByName();
216 /* routines from afsmon-output.c */
217 extern int afsmon_fsOutput();
218 extern int afsmon_cmOutput();
220 /* file server and cache manager variable names (from afsmon_labels.h) */
221 extern char *fs_varNames[];
222 extern char *cm_varNames[];
224 /* GTX & MISC VARIABLES */
226 /* afsmonitor window */
227 extern struct gwin *afsmon_win;
229 /* current page number in the overview frame */
230 extern int ovw_currPage;
232 /* number of FS alerts and number of hosts on FS alerts */
234 int numHosts_onfs_alerts;
236 /* number of CM alerts and number of hosts on FS alerts */
238 int numHosts_oncm_alerts;
240 /* flag to indicate that atleast one probe cycle has completed and
241 data is available for updating the display */
242 extern fs_Data_Available;
243 extern cm_Data_Available;
245 extern int gtx_initialized; /* gtx initialized ? */
247 /* This array contains the indices of the file server data items that
248 are to be displayed on the File Servers screen. For example, suppose the
249 user wishes to display only the vcache statistics then the following array
250 will contain indices 2 to 14 corresponding to the position of the
251 vcache data items in the fs_varNames[] array. If the config file contains
252 no "show fs .." directives, it will contain the indices of all the
253 items in the fs_varNames[] array */
255 short fs_Display_map[XSTAT_FS_FULLPERF_RESULTS_LEN];
256 int fs_DisplayItems_count = 0; /* number of items to display */
257 int fs_showDefault = 1; /* show all of FS data ? */
260 /* same use as above for Cache Managers */
261 short cm_Display_map[XSTAT_CM_FULLPERF_RESULTS_LEN];
262 int cm_DisplayItems_count = 0; /* number of items to display */
263 int cm_showDefault = 1; /* show all of CM data ? */
265 extern int fs_currPage; /* current page number in the File Servers frame */
266 extern int fs_curr_LCol; /* current leftmost column on display on FS frame */
268 extern int cm_currPage; /* current page number in the Cache Managers frame */
269 extern int cm_curr_LCol; /* current leftmost column on display on CM frame */
271 /* File server and Cache manager data is classified into sections &
272 groups to help the user choose what he wants displayed */
273 extern char *fs_categories[]; /* file server data category names */
274 extern char *cm_categories[]; /* cache manager data category names */
280 strcasestr(): Return first occurence of pattern s2 in s1, case
283 This routine is required since I made pattern matching of the
284 config file to be case insensitive.
299 return ((char *)NULL);
303 while (len1 >= len2 && len1 > 0) {
304 if ((strncasecmp(ptr, s2, len2)) == 0)
309 return ((char *)NULL);
322 he = gethostbyname(name);
324 /* On solaris the above does not resolve hostnames to full names */
326 memcpy(ip_addr, he->h_addr, he->h_length);
327 he = gethostbyaddr(ip_addr, he->h_length, he->h_addrtype);
334 /*-----------------------------------------------------------------------
338 * Exit gracefully from the afsmonitor. Frees memory where appropriate,
339 * cleans up after gtx and closes all open file descriptors. If a user
340 * provided threshold handler is to be exec'ed then gtx cleanup is
341 * not performed and an exec() is made instead of an exit().
347 * This function is called to execute a user handler only
348 * by a child process.
350 *----------------------------------------------------------------------*/
353 afsmon_Exit(a_exitVal)
354 int a_exitVal; /* exit code */
356 static char rn[] = "afsmon_Exit";
357 struct afsmon_fs_Results_list *tmp_fslist;
358 struct afsmon_fs_Results_list *next_fslist;
359 struct xstat_fs_ProbeResults *tmp_xstat_fsPR;
360 struct afsmon_cm_Results_list *tmp_cmlist;
361 struct afsmon_cm_Results_list *next_cmlist;
362 struct xstat_cm_ProbeResults *tmp_xstat_cmPR;
363 struct afsmon_hostEntry *curr_hostEntry;
364 struct afsmon_hostEntry *prev_hostEntry;
371 fprintf(debugFD, "[ %s ] Called with exit code %d\n", rn, a_exitVal);
375 /* get out of curses first, but not if we are here to exec a threshold
376 * handler. If we do, the screen gets messed up */
377 if (gtx_initialized && !exec_fsThreshHandler)
378 gator_cursesgwin_cleanup(afsmon_win);
380 /* print the error message buffer */
381 if (errMsg[0] != '\0')
382 fprintf(stderr, "%s", errMsg);
383 if (errMsg1[0] != '\0')
384 fprintf(stderr, "%s", errMsg1);
386 /* deallocate file server circular buffers */
387 if (numFS && num_bufSlots) {
389 fprintf(debugFD, "freeing FS circular buffers ");
393 for (bufslot = 0; bufslot < num_bufSlots; bufslot++) {
395 fprintf(debugFD, " %d) ", bufslot);
396 if (afsmon_fs_ResultsCB[bufslot].list !=
397 (struct afsmon_fs_Results_list *)0) {
398 tmp_fslist = afsmon_fs_ResultsCB[bufslot].list;
401 /* make sure we do not go astray */
405 "[ %s ] error in deallocating fs CB\n",
409 next_fslist = tmp_fslist->next;
410 tmp_xstat_fsPR = tmp_fslist->fsResults;
413 fprintf(debugFD, "%d ", numFS - j);
415 /* free xstat_fs_Results data */
416 free(tmp_xstat_fsPR->data.AFS_CollData_val);
417 free(tmp_xstat_fsPR->connP);
418 free(tmp_xstat_fsPR);
420 /* free the fs list item */
422 tmp_fslist = next_fslist;
424 } /* while fs list items in this slot */
425 } /* if entries in this buffer slot */
426 } /* for each fs buffer slot */
428 fprintf(debugFD, "\n");
433 /* deallocate cache manager curcular buffers */
434 if (numCM && num_bufSlots) {
436 fprintf(debugFD, "freeing CM curcular buffers ");
437 for (bufslot = 0; bufslot < num_bufSlots; bufslot++) {
439 fprintf(debugFD, " %d) ", bufslot);
440 if (afsmon_cm_ResultsCB[bufslot].list !=
441 (struct afsmon_cm_Results_list *)0) {
442 tmp_cmlist = afsmon_cm_ResultsCB[bufslot].list;
445 /* make sure we do not go astray */
449 "[ %s ] error in deallocating cm CB\n",
453 next_cmlist = tmp_cmlist->next;
454 tmp_xstat_cmPR = tmp_cmlist->cmResults;
457 fprintf(debugFD, "%d ", numCM - j);
458 /* make sure data is ok */
459 /* Print_cm_FullPerfInfo(tmp_xstat_cmPR); */
461 /* free xstat_cm_Results data */
462 free(tmp_xstat_cmPR->data.AFSCB_CollData_val);
463 free(tmp_xstat_cmPR->connP);
464 free(tmp_xstat_cmPR);
466 /* free the cm list item */
468 tmp_cmlist = next_cmlist;
470 } /* while cm list items in this slot */
471 } /* if entries in this buffer slot */
472 } /* for each cm buffer slot */
474 fprintf(debugFD, "\n");
478 /* deallocate FS & CM Print buffers */
479 if (curr_fsData != (struct fs_Display_Data *)0) {
481 fprintf(debugFD, "Deallocating FS Print Buffers .... curr");
484 if (prev_fsData != (struct fs_Display_Data *)0) {
486 fprintf(debugFD, ", prev \n");
489 if (prev_cmData != (struct cm_Display_Data *)0) {
491 fprintf(debugFD, "Deallocating CM Print Buffers .... curr");
494 if (prev_cmData != (struct cm_Display_Data *)0) {
496 fprintf(debugFD, ", prev \n");
500 /* deallocate hostEntry lists */
503 fprintf(debugFD, "Deallocating FS hostEntries ..");
504 curr_hostEntry = FSnameList;
505 for (i = 0; i < numFS; i++) {
506 prev_hostEntry = curr_hostEntry;
507 if (curr_hostEntry->thresh != NULL)
508 free(curr_hostEntry->thresh);
509 free(curr_hostEntry);
511 fprintf(debugFD, " %d", i);
512 curr_hostEntry = prev_hostEntry->next;
515 fprintf(debugFD, "\n");
519 fprintf(debugFD, "Deallocating CM hostEntries ..");
520 curr_hostEntry = CMnameList;
521 for (i = 0; i < numCM; i++) {
522 prev_hostEntry = curr_hostEntry;
523 if (curr_hostEntry->thresh != NULL)
524 free(curr_hostEntry->thresh);
525 free(curr_hostEntry);
527 fprintf(debugFD, " %d", i);
528 curr_hostEntry = prev_hostEntry->next;
531 fprintf(debugFD, "\n");
534 /* close debug file */
540 if (exec_fsThreshHandler) {
541 code = execvp(fsHandler_argv[0], fsHandler_argv);
543 fprintf(stderr, "execvp() of %s returned %d, errno %d\n",
544 fsHandler_argv[0], code, errno);
552 /*-----------------------------------------------------------------------
556 * Insert a hostname in the file server names list.
561 *----------------------------------------------------------------------*/
564 insert_FS(a_hostName)
565 char *a_hostName; /* name of cache manager to be inserted in list */
567 static char rn[] = "insert_FS"; /* routine name */
568 static struct afsmon_hostEntry *curr_item;
569 static struct afsmon_hostEntry *prev_item;
571 if (*a_hostName == '\0')
573 curr_item = (struct afsmon_hostEntry *)
574 malloc(sizeof(struct afsmon_hostEntry));
575 if (curr_item == (struct afsmon_hostEntry *)0) {
576 fprintf(stderr, "Failed to allocate space for FS nameList\n");
580 strncpy(curr_item->hostName, a_hostName, CFG_STR_LEN);
581 curr_item->next = (struct afsmon_hostEntry *)0;
582 curr_item->numThresh = 0;
583 curr_item->thresh = NULL;
585 if (FSnameList == (struct afsmon_hostEntry *)0)
586 FSnameList = curr_item;
588 prev_item->next = curr_item;
590 prev_item = curr_item;
591 /* record the address of this entry so that its threshold
592 * count can be incremented during the first pass of the config file */
593 last_hostEntry = curr_item;
598 /*-----------------------------------------------------------------------
603 * Prints the file server names linked list.
607 *----------------------------------------------------------------------*/
611 static char rn[] = "print_FS";
612 struct afsmon_hostEntry *tempFS;
613 struct Threshold *threshP;
617 fprintf(debugFD, "[ %s ] Called\n", rn);
623 fprintf(debugFD, "No of File Servers: %d\n", numFS);
626 fprintf(debugFD, "\t %s threshCount = %d\n", tempFS->hostName,
628 threshP = tempFS->thresh;
629 for (i = 0; i < tempFS->numThresh; i++, threshP++)
630 fprintf(debugFD, "\t thresh (%2d) %s %s %s\n",
631 threshP->index, threshP->itemName,
632 threshP->threshVal, threshP->handler);
633 } while ((tempFS = tempFS->next) != (struct afsmon_hostEntry *)0);
635 fprintf(debugFD, "\t\t-----End of List-----\n");
641 /*-----------------------------------------------------------------------
645 * Insert a hostname in the cache manager names list.
650 *----------------------------------------------------------------------*/
653 insert_CM(a_hostName)
654 char *a_hostName; /* name of cache manager to be inserted in list */
656 static char rn[] = "insert_CM"; /* routine name */
657 static struct afsmon_hostEntry *curr_item;
658 static struct afsmon_hostEntry *prev_item;
660 if (*a_hostName == '\0')
662 curr_item = (struct afsmon_hostEntry *)
663 malloc(sizeof(struct afsmon_hostEntry));
664 if (curr_item == (struct afsmon_hostEntry *)0) {
665 fprintf(stderr, "Failed to allocate space for CM nameList\n");
669 strncpy(curr_item->hostName, a_hostName, CFG_STR_LEN);
670 curr_item->next = (struct afsmon_hostEntry *)0;
671 curr_item->numThresh = 0;
672 curr_item->thresh = NULL;
674 if (CMnameList == (struct afsmon_hostEntry *)0)
675 CMnameList = curr_item;
677 prev_item->next = curr_item;
679 prev_item = curr_item;
680 /* side effect. note the address of this entry so that its threshold
681 * count can be incremented during the first pass of the config file */
682 last_hostEntry = curr_item;
688 /*-----------------------------------------------------------------------
693 * Prints the cache manager names linked list.
697 *----------------------------------------------------------------------*/
701 static char rn[] = "print_CM";
702 struct afsmon_hostEntry *tempCM;
703 struct Threshold *threshP;
707 fprintf(debugFD, "[ %s ] Called\n", rn);
713 fprintf(debugFD, "No of Cache Managers: %d\n", numCM);
716 fprintf(debugFD, "\t %s threshCount = %d\n", tempCM->hostName,
718 threshP = tempCM->thresh;
719 for (i = 0; i < tempCM->numThresh; i++, threshP++)
720 fprintf(debugFD, "\t thresh (%2d) %s %s %s\n",
721 threshP->index, threshP->itemName,
722 threshP->threshVal, threshP->handler);
723 } while ((tempCM = tempCM->next) != (struct afsmon_hostEntry *)0);
725 fprintf(debugFD, "\t\t-----End of List-----\n");
732 /*-----------------------------------------------------------------------
736 * Parse the host entry line in the config file. Check the syntax,
737 * and inserts the host name in the FS ot CM linked list. Also
738 * remember if this entry was an fs or cm & the ptr to its hostEntry
739 * structure. The threshold entries in the config file are dependent
740 * on their position relative to the hostname entries. Hence it is
741 * required to remember the names of the last file server and cache
742 * manager entries that were processed.
748 *----------------------------------------------------------------------*/
751 parse_hostEntry(a_line)
753 { /* parse_hostEntry */
755 static char rn[] = "parse_hostEntry"; /* routine name */
756 char opcode[CFG_STR_LEN]; /* specifies type of config entry */
757 char arg1[CFG_STR_LEN]; /* hostname or qualifier (fs/cm?) */
758 char arg2[CFG_STR_LEN]; /* threshold variable */
759 char arg3[CFG_STR_LEN]; /* threshold value */
760 char arg4[CFG_STR_LEN]; /* user's handler */
761 struct hostent *he; /* host entry */
764 fprintf(debugFD, "[ %s ] Called, a_line = %s\n", rn, a_line);
774 sscanf(a_line, "%s %s %s %s %s", opcode, arg1, arg2, arg3, arg4);
775 /* syntax is "opcode hostname" */
776 if ((strlen(arg2)) != 0) {
777 fprintf(stderr, "[ %s ] Extraneous characters at end of line\n", rn);
782 he = GetHostByName(arg1);
784 fprintf(stderr, "[ %s ] Unable to resolve hostname %s\n", rn, arg1);
788 if ((strcasecmp(opcode, "fs")) == 0) {
789 /* use the complete host name to insert in the file server names list */
790 insert_FS(he->h_name);
791 /* note that last host entry in the config file was fs */
794 /* threholds are not global anymore */
795 if (global_ThreshFlag)
796 global_ThreshFlag = 0;
797 } else if ((strcasecmp(opcode, "cm")) == 0) {
798 /* use the complete host name to insert in the CM names list */
799 insert_CM(he->h_name);
800 /* last host entry in the config file was cm */
803 /* threholds are not global anymore */
804 if (global_ThreshFlag)
805 global_ThreshFlag = 0;
812 /*-----------------------------------------------------------------------
813 * parse_threshEntry()
816 * Parse the threshold entry line in the config file. This function is
817 * called in the the first pass of the config file. It checks the syntax
818 * of the config lines and verifies their positional validity - eg.,
819 * a cm threshold cannot appear after a fs hostname entry, etc.
820 * It also counts the thresholds applicable to each host.
826 *----------------------------------------------------------------------*/
829 parse_threshEntry(a_line)
831 { /* parse_threshEntry */
832 static char rn[] = "parse_threshEntry"; /* routine name */
833 char opcode[CFG_STR_LEN]; /* specifies type of config entry */
834 char arg1[CFG_STR_LEN]; /* hostname or qualifier (fs/cm?) */
835 char arg2[CFG_STR_LEN]; /* threshold variable */
836 char arg3[CFG_STR_LEN]; /* threshold value */
837 char arg4[CFG_STR_LEN]; /* user's handler */
838 char arg5[CFG_STR_LEN]; /* junk characters */
841 fprintf(debugFD, "[ %s ] Called, a_line = %s\n", rn, a_line);
852 sscanf(a_line, "%s %s %s %s %s %s", opcode, arg1, arg2, arg3, arg4, arg5);
854 /* syntax is "thresh fs/cm variable_name threshold_value [handler] " */
855 if (((strlen(arg1)) == 0) || ((strlen(arg2)) == 0)
856 || ((strlen(arg3)) == 0)) {
857 fprintf(stderr, "[ %s ] Incomplete line\n", rn);
860 if (strlen(arg3) > THRESH_VAR_LEN - 2) {
861 fprintf(stderr, "[%s ] threshold value too long\n", rn);
865 if ((strcasecmp(arg1, "fs")) == 0) {
866 switch (lastHostType) {
867 case 0: /* its a global threshold */
868 global_fsThreshCount++;
870 case 1: /* inc thresh count of last file server */
871 last_hostEntry->numThresh++;
875 "[ %s ] A threshold for a File Server cannot be placed after a Cache Manager host entry in the config file \n",
879 fprintf(stderr, "[ %s ] Programming error 1\n", rn);
882 } else if ((strcasecmp(arg1, "cm")) == 0) {
883 switch (lastHostType) {
884 case 0: /* its a global threshold */
885 global_cmThreshCount++;
887 case 2: /* inc thresh count of last cache manager */
888 last_hostEntry->numThresh++;
892 "[ %s ] A threshold for a Cache Manager cannot be placed after a File Server host entry in the config file \n",
896 fprintf(stderr, "[ %s ] Programming error 2\n", rn);
899 } else if ((strcasecmp(arg1, "cm")) != 0 && (strcasecmp(arg1, "cm")) != 0) {
901 "[ %s ] Syntax error. Second argument should be \"fs\" or \"cm\" \n",
907 } /* parse_threshEntry */
910 /*-----------------------------------------------------------------------
914 * The thresholds applicable to each host machine are stored in the
915 * FSnameList and CMnameList. Threshold entries in the config file are
916 * context sensitive. The host to which this threshold is applicable
917 * is pointed to by last_fsHost (for file servers) and last_cmHost
918 * for cache managers. For global thresholds the info is recorded for
919 * all the hosts. This function is called in the second pass of the
920 * config file. In the first pass a count of the number of global
921 * thresholds is determined and this information is used in this
922 * routine. If threshold entries are duplicated the first entry is
924 * Each threshold entry also has an index field. This is a positional
925 * index to the corresponding variable in the prev_[fs/cm]Data arrays.
926 * This makes it easy to check the threshold for overflow.
931 *----------------------------------------------------------------------*/
934 store_threshold(a_type, a_varName, a_value, a_handler)
935 int a_type; /* 1 = fs , 2 = cm */
936 char *a_varName; /* threshold name */
937 char *a_value; /* threshold value */
938 char *a_handler; /* threshold overflow handler */
940 { /* store_thresholds */
942 static char rn[] = "store_thresholds"; /* routine name */
943 struct afsmon_hostEntry *tmp_host; /* tmp ptr to hostEntry */
944 struct afsmon_hostEntry *Header; /* tmp ptr to hostEntry list header */
945 struct Threshold *threshP; /* tmp ptr to threshold list */
947 int index; /* index to fs_varNames or cm_varNames */
950 int srvCount; /* tmp count of host names */
951 int *global_TC; /* ptr to global_xxThreshCount */
956 "[ %s ] Called, a_type= %d, a_varName= %s, a_value= %s, a_handler=%s\n",
957 rn, a_type, a_varName, a_value, a_handler);
961 /* resolve the threshold variable name */
963 if (a_type == 1) { /* fs threshold */
964 for (index = 0; index < NUM_FS_STAT_ENTRIES; index++) {
965 if (strcasecmp(a_varName, fs_varNames[index]) == 0) {
971 fprintf(stderr, "[ %s ] Unknown FS threshold variable name %s\n",
977 hostname = last_fsHost;
978 global_TC = &global_fsThreshCount;
979 } else if (a_type == 2) { /* cm threshold */
980 for (index = 0; index < NUM_CM_STAT_ENTRIES; index++) {
981 if (strcasecmp(a_varName, cm_varNames[index]) == 0) {
987 fprintf(stderr, "[ %s ] Unknown CM threshold variable name %s\n",
993 hostname = last_cmHost;
994 global_TC = &global_cmThreshCount;
1000 /* if the global thresh count is not zero, place this threshold on
1001 * all the host entries */
1005 for (i = 0; i < srvCount; i++) {
1006 threshP = tmp_host->thresh;
1008 for (j = 0; j < tmp_host->numThresh; j++) {
1009 if ((threshP->itemName[0] == '\0')
1010 || (strcasecmp(threshP->itemName, a_varName) == 0)) {
1011 strncpy(threshP->itemName, a_varName,
1012 THRESH_VAR_NAME_LEN);
1013 strncpy(threshP->threshVal, a_value, THRESH_VAR_LEN);
1014 strcpy(threshP->handler, a_handler);
1015 threshP->index = index;
1022 fprintf(stderr, "[ %s ] Could not insert threshold entry",
1024 fprintf(stderr, "for %s in thresh list of host %s \n",
1025 a_varName, tmp_host->hostName);
1028 tmp_host = tmp_host->next;
1034 /* it is not a global threshold, insert it in the thresh list of this
1035 * host only. We overwrite the global threshold if it was alread set */
1037 if (*hostname == '\0') {
1038 fprintf(stderr, "[ %s ] Programming error 3\n", rn);
1042 /* get the hostEntry that this threshold belongs to */
1045 for (i = 0; i < srvCount; i++) {
1046 if (strcasecmp(tmp_host->hostName, hostname) == 0) {
1050 tmp_host = tmp_host->next;
1053 fprintf(stderr, "[ %s ] Unable to find host %s in %s hostEntry list",
1054 rn, hostname, (a_type - 1) ? "CM" : "FS");
1058 /* put this entry on the thresh list of this host, overwrite global value
1061 threshP = tmp_host->thresh;
1063 for (i = 0; i < tmp_host->numThresh; i++) {
1064 if ((threshP->itemName[0] == '\0')
1065 || (strcasecmp(threshP->itemName, a_varName) == 0)) {
1066 strncpy(threshP->itemName, a_varName, THRESH_VAR_NAME_LEN);
1067 strncpy(threshP->threshVal, a_value, THRESH_VAR_LEN);
1068 strcpy(threshP->handler, a_handler);
1069 threshP->index = index;
1078 "[ %s ] Unable to insert threshold %s for %s host %s\n", rn,
1079 a_varName, (a_type - 1) ? "CM" : "FS", tmp_host->hostName);
1085 } /* store_thresholds */
1088 /*-----------------------------------------------------------------------
1092 * This function process a "show" entry in the config file. A "show"
1093 * entry specifies what statistics the user wants to see. File
1094 * server and Cache Manager data is divided into sections. Each section
1095 * is made up of one or more groups. If a group name is specified only
1096 * those statistics under that group are shown. If a section name is
1097 * specified all the groups under this section are shown.
1098 * Data as obtained from the xstat probes is considered to be ordered.
1099 * This data is mapped to the screen thru fs_Display_map[] and
1100 * cm_Display_map[]. This routine parses the "show" entry against the
1101 * section/group names in the [fs/cm]_categories[] array. If there is
1102 * no match it tries to match it against a variable name in
1103 * [fs/cm]_varNames[] array. In each case the corresponding indices to
1104 * the data is the [fs/cm]_displayInfo[] is recorded.
1108 * Failure: -1 (invalid entry)
1109 * > -1 (programming error)
1110 *----------------------------------------------------------------------*/
1113 parse_showEntry(a_line)
1115 { /* parse_showEntry */
1116 static char rn[] = "parse_showEntry";
1117 char opcode[CFG_STR_LEN]; /* specifies type of config entry */
1118 char arg1[CFG_STR_LEN]; /* show fs or cm entry ? */
1119 char arg2[CFG_STR_LEN]; /* what we gotta show */
1120 char arg3[CFG_STR_LEN]; /* junk */
1121 char catName[CFG_STR_LEN]; /* for category names */
1122 int numGroups; /* number of groups in a section */
1126 int idx = 0; /* index to fs_categories[] */
1132 fprintf(debugFD, "[ %s ] Called, a_line= %s\n", rn, a_line);
1139 sscanf(a_line, "%s %s %s %s", opcode, arg1, arg2, arg3);
1141 if (arg3[0] != '\0') {
1142 fprintf(stderr, "[ %s ] Extraneous characters at end of line\n", rn);
1146 if ((strcasecmp(arg1, "fs") != 0) && (strcasecmp(arg1, "cm") != 0)) {
1148 "[ %s ] Second argument of \"show\" directive should be \"fs\" or \"cm\" \n",
1153 /* Each entry can either be a variable name or a section/group name. Variable
1154 * names are listed in xx_varNames[] and section/group names in xx_categories[].
1155 * The section/group names in xx_categiries[] also give the starting/ending
1156 * indices of the variables belonging to that section/group. These indices
1157 * are stored in order in xx_Display_map[] and displayed to the screen in that
1160 /* To handle duplicate "show" entries we keep track of what what we have
1161 * already marked to show in the xx_showFlags[] */
1163 if (strcasecmp(arg1, "fs") == 0) { /* its a File Server entry */
1165 /* mark that we have to show only what the user wants */
1168 /* if it is a section/group name, find it in the fs_categories[] array */
1171 if (strcasestr(arg2, "_section") != (char *)NULL
1172 || strcasestr(arg2, "_group") != (char *)NULL) {
1174 while (idx < FS_NUM_DATA_CATEGORIES) {
1175 sscanf(fs_categories[idx], "%s %d %d", catName, &fromIdx,
1178 if (strcasecmp(arg2, catName) == 0) {
1184 if (!found) { /* typo in section/group name */
1186 "[ %s ] Could not find section/group name %s\n", rn,
1192 /* if it is a group name, read its start/end indices and fill in the
1193 * fs_Display_map[]. */
1195 if (strcasestr(arg2, "_group") != (char *)NULL) {
1197 if (fromIdx < 0 || toIdx < 0 || fromIdx > NUM_FS_STAT_ENTRIES
1198 || toIdx > NUM_FS_STAT_ENTRIES)
1200 for (j = fromIdx; j <= toIdx; j++) {
1201 if (!fs_showFlags[j]) {
1202 fs_Display_map[fs_DisplayItems_count] = j;
1203 fs_DisplayItems_count++;
1204 fs_showFlags[j] = 1;
1206 if (fs_DisplayItems_count > NUM_FS_STAT_ENTRIES) {
1207 fprintf(stderr, "[ %s ] fs_DisplayItems_count ovf\n", rn);
1212 /* if it is a section name, get the count of number of groups in it and
1213 * for each group fill in the start/end indices in the fs_Display_map[] */
1215 if (strcasestr(arg2, "_section") != (char *)NULL) {
1216 /* fromIdx is actually the number of groups in thi section */
1217 numGroups = fromIdx;
1218 /* for each group in section */
1219 while (idx < FS_NUM_DATA_CATEGORIES && numGroups) {
1220 sscanf(fs_categories[idx], "%s %d %d", catName, &fromIdx,
1223 if (strcasestr(catName, "_group") != NULL) {
1224 if (fromIdx < 0 || toIdx < 0
1225 || fromIdx > NUM_FS_STAT_ENTRIES
1226 || toIdx > NUM_FS_STAT_ENTRIES)
1228 for (j = fromIdx; j <= toIdx; j++) {
1229 if (!fs_showFlags[j]) {
1230 fs_Display_map[fs_DisplayItems_count] = j;
1231 fs_DisplayItems_count++;
1232 fs_showFlags[j] = 1;
1234 if (fs_DisplayItems_count > NUM_FS_STAT_ENTRIES) {
1236 "[ %s ] fs_DisplayItems_count ovf\n", rn);
1241 fprintf(stderr, "[ %s ] Error parsing groups for %s\n",
1247 } /* for each group in section */
1250 } else { /* it is a variable name */
1252 for (i = 0; i < NUM_FS_STAT_ENTRIES; i++) {
1253 if (strcasecmp(arg2, fs_varNames[i]) == 0) {
1254 if (!fs_showFlags[i]) {
1255 fs_Display_map[fs_DisplayItems_count] = i;
1256 fs_DisplayItems_count++;
1257 fs_showFlags[i] = 1;
1259 if (fs_DisplayItems_count >= NUM_FS_STAT_ENTRIES) {
1260 fprintf(stderr, "[ %s ] fs_DisplayItems_count ovf\n",
1267 if (!found) { /* typo in section/group name */
1268 fprintf(stderr, "[ %s ] Could not find variable name %s\n",
1272 } /* its a variable name */
1276 /* it is an fs entry */
1277 if (strcasecmp(arg1, "cm") == 0) { /* its a Cache Manager entry */
1280 /* mark that we have to show only what the user wants */
1283 /* if it is a section/group name, find it in the cm_categories[] array */
1286 if (strcasestr(arg2, "_section") != (char *)NULL
1287 || strcasestr(arg2, "_group") != (char *)NULL) {
1289 while (idx < CM_NUM_DATA_CATEGORIES) {
1290 sscanf(cm_categories[idx], "%s %d %d", catName, &fromIdx,
1293 if (strcasecmp(arg2, catName) == 0) {
1299 if (!found) { /* typo in section/group name */
1301 "[ %s ] Could not find section/group name %s\n", rn,
1307 /* if it is a group name, read its start/end indices and fill in the
1308 * cm_Display_map[]. */
1310 if (strcasestr(arg2, "_group") != (char *)NULL) {
1312 if (fromIdx < 0 || toIdx < 0 || fromIdx > NUM_CM_STAT_ENTRIES
1313 || toIdx > NUM_CM_STAT_ENTRIES)
1315 for (j = fromIdx; j <= toIdx; j++) {
1316 if (!cm_showFlags[j]) {
1317 cm_Display_map[cm_DisplayItems_count] = j;
1318 cm_DisplayItems_count++;
1319 cm_showFlags[j] = 1;
1321 if (cm_DisplayItems_count > NUM_CM_STAT_ENTRIES) {
1322 fprintf(stderr, "[ %s ] cm_DisplayItems_count ovf\n", rn);
1327 /* if it is a section name, get the count of number of groups in it and
1328 * for each group fill in the start/end indices in the cm_Display_map[] */
1330 if (strcasestr(arg2, "_section") != (char *)NULL) {
1331 /* fromIdx is actually the number of groups in thi section */
1332 numGroups = fromIdx;
1333 /* for each group in section */
1334 while (idx < CM_NUM_DATA_CATEGORIES && numGroups) {
1335 sscanf(cm_categories[idx], "%s %d %d", catName, &fromIdx,
1338 if (strcasestr(catName, "_group") != NULL) {
1339 if (fromIdx < 0 || toIdx < 0
1340 || fromIdx > NUM_CM_STAT_ENTRIES
1341 || toIdx > NUM_CM_STAT_ENTRIES)
1343 for (j = fromIdx; j <= toIdx; j++) {
1344 if (!cm_showFlags[j]) {
1345 cm_Display_map[cm_DisplayItems_count] = j;
1346 cm_DisplayItems_count++;
1347 cm_showFlags[j] = 1;
1349 if (cm_DisplayItems_count > NUM_CM_STAT_ENTRIES) {
1351 "[ %s ] cm_DisplayItems_count ovf\n", rn);
1356 fprintf(stderr, "[ %s ] Error parsing groups for %s\n",
1362 } /* for each group in section */
1369 } else { /* it is a variable name */
1371 for (i = 0; i < NUM_CM_STAT_ENTRIES; i++) {
1372 if (strcasecmp(arg2, cm_varNames[i]) == 0) {
1373 if (!cm_showFlags[i]) {
1374 cm_Display_map[cm_DisplayItems_count] = i;
1375 cm_DisplayItems_count++;
1376 cm_showFlags[i] = 1;
1378 if (cm_DisplayItems_count >= NUM_CM_STAT_ENTRIES) {
1379 fprintf(stderr, "[ %s ] cm_DisplayItems_count ovf\n",
1386 if (!found) { /* typo in section/group name */
1387 fprintf(stderr, "[ %s ] Could not find variable name %s\n",
1391 } /* its a variable name */
1394 /* it is an cm entry */
1398 } /* parse_showEntry */
1401 /*-----------------------------------------------------------------------
1402 * process_config_file()
1405 * Parse config file entries in two passes. In the first pass:
1406 * - the syntax of all the entries is checked
1407 * - host names are noted and the FSnamesList and CMnamesList
1409 * - a count of the global thresholds and local thresholds of
1410 * each host are counted.
1411 * - "show" entries are processed.
1412 * In the second pass:
1413 * - thresholds are stored
1417 * Failure: Exits afsmonitor showing error and line.
1418 *----------------------------------------------------------------------*/
1421 process_config_file(a_config_filename)
1422 char *a_config_filename;
1423 { /* process_config_file() */
1424 static char rn[] = "process_config_file"; /* routine name */
1425 FILE *configFD; /* config file descriptor */
1426 char line[4 * CFG_STR_LEN]; /* a line of config file */
1427 char opcode[CFG_STR_LEN]; /* specifies type of config entry */
1428 char arg1[CFG_STR_LEN]; /* hostname or qualifier (fs/cm?) */
1429 char arg2[CFG_STR_LEN]; /* threshold variable */
1430 char arg3[CFG_STR_LEN]; /* threshold value */
1431 char arg4[CFG_STR_LEN]; /* user's handler */
1432 struct afsmon_hostEntry *curr_host;
1433 struct hostent *he; /* hostentry to resolve host name */
1434 char *handlerPtr; /* ptr to pass theresh handler string */
1435 int code = 0; /* error code */
1436 int linenum = 0; /* config file line number */
1437 int threshCount; /* count of thresholds for each server */
1438 int error_in_config; /* syntax errors in config file ?? */
1443 fprintf(debugFD, "[ %s ] Called, a_config_filename= %s\n", rn,
1448 /* open config file */
1450 configFD = fopen(a_config_filename, "r");
1451 if (configFD == (FILE *) 0) {
1452 fprintf(stderr, "Failed to open config file %s \n",
1455 fprintf(debugFD, "[ %s ] Failed to open config file %s \n", rn,
1462 /* parse config file */
1464 /* We process the config file in two passes. In the first pass we check
1465 * for correct syntax and for valid entries and also keep count of the
1466 * number of servers and thresholds to monitor. This the data strctures
1467 * can be arrays instead of link lists since we would know their sizes. */
1474 error_in_config = 0; /* flag to note if config file has syntax errors */
1476 while ((fgets(line, CFG_STR_LEN, configFD)) != NULL) {
1482 sscanf(line, "%s %s %s %s %s", opcode, arg1, arg2, arg3, arg4);
1484 /* skip blank lines and comment lines */
1485 if ((strlen(opcode) == 0) || line[0] == '#')
1488 if ((strcasecmp(opcode, "fs") == 0)
1489 || (strcasecmp(opcode, "cm")) == 0) {
1490 code = parse_hostEntry(line);
1491 } else if ((strcasecmp(opcode, "thresh")) == 0) {
1492 code = parse_threshEntry(line);
1493 } else if ((strcasecmp(opcode, "show")) == 0) {
1494 code = parse_showEntry(line);
1496 fprintf(stderr, "[ %s ] Unknown opcode %s\n", rn, opcode);
1501 fprintf(stderr, "[ %s ] Error in line:\n %d: %s\n", rn, linenum,
1503 error_in_config = 1;
1507 if (error_in_config)
1511 fprintf(debugFD, "Global FS thresholds count = %d\n",
1512 global_fsThreshCount);
1513 fprintf(debugFD, "Global CM thresholds count = %d\n",
1514 global_cmThreshCount);
1518 /* the threshold count of all hosts in increased by 1 for each global
1519 * threshold. If one of the hosts has a local threshold for the same
1520 * variable it would end up being counted twice. whats a few bytes of memory
1521 * wasted anyway ? */
1523 if (global_fsThreshCount) {
1524 curr_host = FSnameList;
1525 for (i = 0; i < numFS; i++) {
1526 curr_host->numThresh += global_fsThreshCount;
1527 curr_host = curr_host->next;
1530 if (global_cmThreshCount) {
1531 curr_host = CMnameList;
1532 for (i = 0; i < numCM; i++) {
1533 curr_host->numThresh += global_cmThreshCount;
1534 curr_host = curr_host->next;
1539 /* make sure we have something to monitor */
1540 if (numFS == 0 && numCM == 0) {
1542 "\nConfig file must specify atleast one File Server or Cache Manager host to monitor.\n");
1549 fseek(configFD, 0, 0); /* seek to the beginning */
1552 /* allocate memory for threshold lists */
1553 curr_host = FSnameList;
1554 for (i = 0; i < numFS; i++) {
1555 if (curr_host->hostName[0] == '\0') {
1556 fprintf(stderr, "[ %s ] Programming error 4\n", rn);
1559 if (curr_host->numThresh) {
1560 numBytes = curr_host->numThresh * sizeof(struct Threshold);
1561 curr_host->thresh = (struct Threshold *)malloc(numBytes);
1562 if (curr_host->thresh == NULL) {
1563 fprintf(stderr, "[ %s ] Memory Allocation error 1", rn);
1566 memset(curr_host->thresh, 0, numBytes);
1568 curr_host = curr_host->next;;
1571 curr_host = CMnameList;
1572 for (i = 0; i < numCM; i++) {
1573 if (curr_host->hostName[0] == '\0') {
1574 fprintf(stderr, "[ %s ] Programming error 5\n", rn);
1577 if (curr_host->numThresh) {
1578 numBytes = curr_host->numThresh * sizeof(struct Threshold);
1579 curr_host->thresh = (struct Threshold *)malloc(numBytes);
1580 if (curr_host->thresh == NULL) {
1581 fprintf(stderr, "[ %s ] Memory Allocation error 2", rn);
1584 memset(curr_host->thresh, 0, numBytes);
1586 curr_host = curr_host->next;;
1595 last_fsHost[0] = '\0';
1596 last_cmHost[0] = '\0';
1598 while ((fgets(line, CFG_STR_LEN, configFD)) != NULL) {
1604 sscanf(line, "%s %s %s %s %s", opcode, arg1, arg2, arg3, arg4);
1607 /* if we have a host entry, remember the host name */
1608 if (strcasecmp(opcode, "fs") == 0) {
1609 he = GetHostByName(arg1);
1610 strncpy(last_fsHost, he->h_name, HOST_NAME_LEN);
1611 } else if (strcasecmp(opcode, "cm") == 0) {
1612 he = GetHostByName(arg1);
1613 strncpy(last_cmHost, he->h_name, HOST_NAME_LEN);
1614 } else if (strcasecmp(opcode, "thresh") == 0) {
1615 /* if we have a threshold handler it may have arguments
1616 * and the sscanf() above would not get them, so do the
1620 /* now skip over 4 words - this is done by first
1621 * skipping leading blanks then skipping a word */
1622 for (i = 0; i < 4; i++) {
1623 while (isspace(*handlerPtr))
1625 while (!isspace(*handlerPtr))
1628 while (isspace(*handlerPtr))
1630 /* we how have a pointer to the start of the handler
1633 handlerPtr = arg4; /* empty string */
1636 if (strcasecmp(arg1, "fs") == 0)
1637 code = store_threshold(1, /* 1 = fs */
1638 arg2, arg3, handlerPtr);
1640 else if (strcasecmp(arg1, "cm") == 0)
1641 code = store_threshold(2, /* 2 = fs */
1642 arg2, arg3, handlerPtr);
1645 fprintf(stderr, "[ %s ] Programming error 6\n", rn);
1649 fprintf(stderr, "[ %s ] Failed to store threshold\n", rn);
1650 fprintf(stderr, "[ %s ] Error processing line:\n%d: %s", rn,
1662 /*-----------------------------------------------------------------------
1667 * Print the File Server circular buffer.
1671 *----------------------------------------------------------------------*/
1675 { /* Print_FS_CB() */
1677 struct afsmon_fs_Results_list *fslist;
1681 /* print valid info in the fs CB */
1685 "==================== FS Buffer ========================\n");
1686 fprintf(debugFD, "afsmon_fs_curr_CBindex = %d\n",
1687 afsmon_fs_curr_CBindex);
1688 fprintf(debugFD, "afsmon_fs_curr_probeNum = %d\n\n",
1689 afsmon_fs_curr_probeNum);
1691 for (i = 0; i < num_bufSlots; i++) {
1692 fprintf(debugFD, "\t--------- slot %d ----------\n", i);
1693 fslist = afsmon_fs_ResultsCB[i].list;
1696 if (!fslist->empty) {
1697 fprintf(debugFD, "\t %d) probeNum = %d host = %s", j,
1698 fslist->fsResults->probeNum,
1699 fslist->fsResults->connP->hostName);
1700 if (fslist->fsResults->probeOK)
1701 fprintf(debugFD, " NOTOK\n");
1703 fprintf(debugFD, " OK\n");
1705 fprintf(debugFD, "\t %d) -- empty --\n", j);
1706 fslist = fslist->next;
1709 if (fslist != (struct afsmon_fs_Results_list *)0)
1710 fprintf(debugFD, "dangling last next ptr fs CB\n");
1713 } /* Print_FS_CB() */
1715 /*-----------------------------------------------------------------------
1716 * save_FS_results_inCB()
1719 * Saves the results of the latest FS probe in the fs circular
1720 * buffers. If the current probe cycle is in progress the contents
1721 * of xstat_fs_Results are copied to the end of the list of results
1722 * in the current slot (pointed to by afsmon_fs_curr_CBindex). If
1723 * a new probe cycle has started the next slot in the circular buffer
1724 * is initialized and the results copied. Note that the Rx related
1725 * information available in xstat_fs_Results is not copied.
1729 * Failure: Exits afsmonitor.
1730 *----------------------------------------------------------------------*/
1732 save_FS_results_inCB(a_newProbeCycle)
1733 int a_newProbeCycle; /* start of a new probe cycle ? */
1735 { /* save_FS_results_inCB() */
1736 static char rn[] = "save_FS_results_inCB"; /* routine name */
1737 struct afsmon_fs_Results_list *tmp_fslist_item; /* temp fs list item */
1738 struct xstat_fs_ProbeResults *tmp_fsPR; /* temp ptr */
1742 fprintf(debugFD, "[ %s ] Called, a_newProbeCycle= %d\n", rn,
1748 /* If a new probe cycle started, mark the list in the current buffer
1749 * slot empty for resuse. Note that afsmon_fs_curr_CBindex was appropriately
1750 * incremented in afsmon_FS_Handler() */
1752 if (a_newProbeCycle) {
1753 tmp_fslist_item = afsmon_fs_ResultsCB[afsmon_fs_curr_CBindex].list;
1754 for (i = 0; i < numFS; i++) {
1755 tmp_fslist_item->empty = 1;
1756 tmp_fslist_item = tmp_fslist_item->next;
1760 /* locate last unused item in list */
1761 tmp_fslist_item = afsmon_fs_ResultsCB[afsmon_fs_curr_CBindex].list;
1762 for (i = 0; i < numFS; i++) {
1763 if (tmp_fslist_item->empty)
1765 tmp_fslist_item = tmp_fslist_item->next;
1768 /* if we could not find one we have an inconsistent list */
1769 if (!tmp_fslist_item->empty) {
1771 "[ %s ] list inconsistency 1. unable to find an empty slot to store results of probenum %d of %s\n",
1772 rn, xstat_fs_Results.probeNum,
1773 xstat_fs_Results.connP->hostName);
1777 tmp_fsPR = tmp_fslist_item->fsResults;
1779 /* copy hostname and probe number and probe time and probe status.
1780 * if the probe failed return now */
1782 memcpy(tmp_fsPR->connP->hostName, xstat_fs_Results.connP->hostName,
1783 sizeof(xstat_fs_Results.connP->hostName));
1784 tmp_fsPR->probeNum = xstat_fs_Results.probeNum;
1785 tmp_fsPR->probeTime = xstat_fs_Results.probeTime;
1786 tmp_fsPR->probeOK = xstat_fs_Results.probeOK;
1787 if (xstat_fs_Results.probeOK) { /* probeOK = 1 => notOK */
1788 /* we have a nonempty results structure so mark the list item used */
1789 tmp_fslist_item->empty = 0;
1793 /* copy connection information */
1794 memcpy(&(tmp_fsPR->connP->skt), &(xstat_fs_Results.connP->skt),
1795 sizeof(struct sockaddr_in));
1797 memcpy(tmp_fsPR->connP->hostName, xstat_fs_Results.connP->hostName,
1798 sizeof(xstat_fs_Results.connP->hostName));
1799 tmp_fsPR->collectionNumber = xstat_fs_Results.collectionNumber;
1801 /* copy the probe data information */
1802 tmp_fsPR->data.AFS_CollData_len = xstat_fs_Results.data.AFS_CollData_len;
1803 memcpy(tmp_fsPR->data.AFS_CollData_val,
1804 xstat_fs_Results.data.AFS_CollData_val,
1805 xstat_fs_Results.data.AFS_CollData_len * sizeof(afs_int32));
1808 /* we have a valid results structure so mark the list item used */
1809 tmp_fslist_item->empty = 0;
1811 /* Print the fs circular buffer */
1815 } /* save_FS_results_inCB() */
1818 /*-----------------------------------------------------------------------
1822 * The results of xstat probes are stored in a string format in
1823 * the arrays curr_fsData and prev_fsData. The information stored in
1824 * prev_fsData is copied to the screen.
1825 * This function converts xstat FS results from longs to strings and
1826 * place them in the given buffer (a pointer to an item in curr_fsData).
1827 * When a probe cycle completes, curr_fsData is copied to prev_fsData
1828 * in afsmon_FS_Hnadler().
1832 *----------------------------------------------------------------------*/
1835 fs_Results_ltoa(a_fsData, a_fsResults)
1836 struct fs_Display_Data *a_fsData; /* target buffer */
1837 struct xstat_fs_ProbeResults *a_fsResults; /* ptr to xstat fs Results */
1838 { /* fs_Results_ltoa */
1840 static char rn[] = "fs_Results_ltoa"; /* routine name */
1842 struct fs_stats_FullPerfStats *fullPerfP;
1848 fprintf(debugFD, "[ %s ] Called, a_fsData= %d, a_fsResults= %d\n", rn,
1849 a_fsData, a_fsResults);
1853 fullPerfP = (struct fs_stats_FullPerfStats *)
1854 (a_fsResults->data.AFS_CollData_val);
1856 /* there are two parts to the xstat FS statistics
1857 * - fullPerfP->overall which give the overall performance statistics, and
1858 * - fullPerfP->det which gives detailed info about file server operation
1859 * execution times */
1861 /* copy overall performance statistics */
1862 srcbuf = (afs_int32 *) & (fullPerfP->overall);
1864 for (i = 0; i < NUM_XSTAT_FS_AFS_PERFSTATS_LONGS; i++) {
1865 sprintf(a_fsData->data[idx], "%d", *srcbuf);
1871 srcbuf = (afs_int32 *) & (fullPerfP->det.epoch);
1872 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* epoch */
1875 /* copy fs operation timing */
1877 srcbuf = (afs_int32 *) (fullPerfP->det.rpcOpTimes);
1879 for (i = 0; i < FS_STATS_NUM_RPC_OPS; i++) {
1880 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* numOps */
1883 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* numSuccesses */
1886 tmpbuf = srcbuf++; /* sum time */
1887 sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1890 tmpbuf = srcbuf++; /* sqr time */
1891 sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1894 tmpbuf = srcbuf++; /* min time */
1895 sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1898 tmpbuf = srcbuf++; /* max time */
1899 sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1904 /* copy fs transfer timings */
1906 srcbuf = (afs_int32 *) (fullPerfP->det.xferOpTimes);
1907 for (i = 0; i < FS_STATS_NUM_XFER_OPS; i++) {
1908 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* numOps */
1911 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* numSuccesses */
1914 tmpbuf = srcbuf++; /* sum time */
1915 sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1918 tmpbuf = srcbuf++; /* sqr time */
1919 sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1922 tmpbuf = srcbuf++; /* min time */
1923 sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1926 tmpbuf = srcbuf++; /* max time */
1927 sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1930 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* sum bytes */
1933 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* min bytes */
1936 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* max bytes */
1939 for (j = 0; j < FS_STATS_NUM_XFER_BUCKETS; j++) {
1940 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* bucket[j] */
1947 } /* fs_Results_ltoa */
1951 /*-----------------------------------------------------------------------
1952 * execute_thresh_handler()
1955 * Execute a threshold handler. An agrv[] array of pointers is
1956 * constructed from the given data. A child process is forked
1957 * which immediately calls afsmon_Exit() with indication that a
1958 * threshold handler is to be exec'ed insted of exiting.
1962 * Failure: Afsmonitor exits if threshold handler has more than 20 args.
1963 *----------------------------------------------------------------------*/
1966 execute_thresh_handler(a_handler, a_hostName, a_hostType, a_threshName,
1967 a_threshValue, a_actValue)
1968 char *a_handler; /* ptr to handler function + args */
1969 char *a_hostName; /* host name for which threshold crossed */
1970 int a_hostType; /* fs or cm ? */
1971 char *a_threshName; /* threshold variable name */
1972 char *a_threshValue; /* threshold value */
1973 char *a_actValue; /* actual value */
1975 { /* execute_thresh_handler */
1977 static char rn[] = "execute_thresh_handler";
1978 char fileName[256]; /* file name to execute */
1983 int anotherArg; /* boolean used to flag if another arg is available */
1987 "[ %s ] Called, a_handler= %s, a_hostName= %s, a_hostType= %d, a_threshName= %s, a_threshValue= %s, a_actValue= %s\n",
1988 rn, a_handler, a_hostName, a_hostType, a_threshName,
1989 a_threshValue, a_actValue);
1994 /* get the filename to execute - the first argument */
1995 sscanf(a_handler, "%s", fileName);
1997 /* construct the contents of *argv[] */
1999 strncpy(fsHandler_args[0], fileName, 256);
2000 strncpy(fsHandler_args[1], a_hostName, HOST_NAME_LEN);
2001 if (a_hostType == FS)
2002 strcpy(fsHandler_args[2], "fs");
2004 strcpy(fsHandler_args[2], "cm");
2005 strncpy(fsHandler_args[3], a_threshName, THRESH_VAR_NAME_LEN);
2006 strncpy(fsHandler_args[4], a_threshValue, THRESH_VAR_LEN);
2007 strncpy(fsHandler_args[5], a_actValue, THRESH_VAR_LEN);
2014 /* we have already extracted the file name so skip to the 1st arg */
2015 while (isspace(*ch)) /* leading blanks */
2017 while (!isspace(*ch) && *ch != '\0') /* handler filename */
2020 while (*ch != '\0') {
2023 } else if (anotherArg) {
2025 sscanf(ch, "%s", fsHandler_args[argNum]);
2031 "Threshold handlers cannot have more than 20 arguments\n");
2037 fsHandler_argv[argNum] = NULL;
2038 for (i = 0; i < argNum; i++)
2039 fsHandler_argv[i] = fsHandler_args[i];
2042 /* exec the threshold handler */
2045 exec_fsThreshHandler = 1;
2046 code = afsmon_Exit(60);
2050 } /* execute_thresh_handler */
2054 /*-----------------------------------------------------------------------
2055 * check_fs_thresholds()
2058 * Checks the thresholds and sets the overflow flag. Recall that the
2059 * thresholds for each host are stored in the hostEntry lists
2060 * [fs/cm]nameList arrays. The probe results are passed to this
2061 * function in the display-ready format - ie., as strings. Though
2062 * this looks stupid the overhead incurred in converting the strings
2063 * back to floats and comparing them is insignificant and
2064 * programming is easier this way.
2065 * The threshold flags are a part of the display structures
2070 *----------------------------------------------------------------------*/
2073 check_fs_thresholds(a_hostEntry, a_Data)
2074 struct afsmon_hostEntry *a_hostEntry; /* ptr to hostEntry */
2075 struct fs_Display_Data *a_Data; /* ptr to fs data to be displayed */
2077 { /* check_fs_thresholds */
2079 static char rn[] = "check_fs_thresholds";
2080 struct Threshold *threshP;
2081 double tValue; /* threshold value */
2082 double pValue; /* probe value */
2085 int count; /* number of thresholds exceeded */
2088 fprintf(debugFD, "[ %s ] Called, a_hostEntry= %d, a_Data= %d\n", rn,
2089 a_hostEntry, a_Data);
2093 if (a_hostEntry->numThresh == 0) {
2094 /* store in ovf count ?? */
2099 threshP = a_hostEntry->thresh;
2100 for (i = 0; i < a_hostEntry->numThresh; i++) {
2101 if (threshP->itemName[0] == '\0') {
2105 idx = threshP->index; /* positional index to the data array */
2106 tValue = atof(threshP->threshVal); /* threshold value */
2107 pValue = atof(a_Data->data[idx]); /* probe value */
2108 if (pValue > tValue) {
2112 "[ %s ] fs = %s, thresh ovf for %s, threshold= %s, probevalue= %s\n",
2113 rn, a_hostEntry->hostName, threshP->itemName,
2114 threshP->threshVal, a_Data->data[idx]);
2117 /* if the threshold is crossed, call the handler function
2118 * only if this was a transition -ie, if the threshold was
2119 * crossed in the last probe too just count & keep quite! */
2121 if (!a_Data->threshOvf[idx]) {
2122 a_Data->threshOvf[idx] = 1;
2123 /* call the threshold handler if provided */
2124 if (threshP->handler[0] != '\0') {
2126 fprintf(debugFD, "[ %s ] Calling ovf handler %s\n",
2127 rn, threshP->handler);
2130 execute_thresh_handler(threshP->handler, a_Data->hostName,
2131 FS, threshP->itemName,
2139 /* in case threshold was previously crossed, blank it out */
2140 a_Data->threshOvf[idx] = 0;
2143 /* store the overflow count */
2144 a_Data->ovfCount = count;
2147 } /* check_fs_thresholds */
2150 /*-----------------------------------------------------------------------
2151 * save_FS_data_forDisplay()
2154 * Does the following:
2155 * - if the probe number changed (ie, a cycle completed) curr_fsData
2156 * is copied to prev_fsData, curr_fsData zeroed and refresh the
2157 * overview screen and file server screen with the new data.
2158 * - store the results of the current probe from xstat_fs_Results into
2159 * curr_fsData. ie., convert longs to strings.
2160 * - check the thresholds
2164 * Failure: Exits afsmonitor.
2165 *----------------------------------------------------------------------*/
2168 save_FS_data_forDisplay(a_fsResults)
2169 struct xstat_fs_ProbeResults *a_fsResults;
2170 { /* save_FS_data_forDisplay */
2172 static char rn[] = "save_FS_data_forDisplay"; /* routine name */
2173 struct fs_Display_Data *curr_fsDataP; /* tmp ptr to curr_fsData */
2174 struct fs_Display_Data *prev_fsDataP; /* tmp ptr to prev_fsData */
2175 struct afsmon_hostEntry *curr_host;
2176 static int probes_Received = 0; /* number of probes reveived in
2177 * the current cycle. If this is equal to numFS we got all
2178 * the data we want in this cycle and can now display it */
2187 fprintf(debugFD, "[ %s ] Called, a_fsResults= %d\n", rn, a_fsResults);
2193 /* store results in the display array */
2196 curr_fsDataP = curr_fsData;
2197 for (i = 0; i < numFS; i++) {
2198 if ((strcasecmp(curr_fsDataP->hostName, a_fsResults->connP->hostName))
2208 "[ %s ] Could not insert FS probe results for host %s in fs display array\n",
2209 rn, a_fsResults->connP->hostName);
2213 /* Check the status of the probe. If it succeeded, we store its
2214 * results in the display data structure. If it failed we only mark
2215 * the failed status in the display data structure. */
2217 if (a_fsResults->probeOK) { /* 1 => notOK the xstat results */
2218 curr_fsDataP->probeOK = 0;
2220 /* print the probe status */
2222 fprintf(debugFD, "\n\t\t ----- fs display data ------\n");
2223 fprintf(debugFD, "HostName = %s PROBE FAILED \n",
2224 curr_fsDataP->hostName);
2228 } else { /* probe succeeded, update display data structures */
2229 curr_fsDataP->probeOK = 1;
2231 /* covert longs to strings and place them in curr_fsDataP */
2232 fs_Results_ltoa(curr_fsDataP, a_fsResults);
2234 /* compare with thresholds and set the overflow flags.
2235 * note that the threshold information is in the hostEntry structure and
2236 * each threshold item has a positional index associated with it */
2238 /* locate the hostEntry for this host */
2240 curr_host = FSnameList;
2241 for (i = 0; i < numFS; i++) {
2242 if (strcasecmp(curr_host->hostName, a_fsResults->connP->hostName)
2247 curr_host = curr_host->next;;
2252 code = check_fs_thresholds(curr_host, curr_fsDataP);
2254 fprintf(stderr, "[ %s ] Error in checking thresholds\n", rn);
2261 /* print the info we just saved */
2264 fprintf(debugFD, "\n\t\t ----- fs display data ------\n");
2265 fprintf(debugFD, "HostName = %s\n", curr_fsDataP->hostName);
2266 for (i = 0; i < NUM_FS_STAT_ENTRIES; i++)
2267 fprintf(debugFD, "%20s %30s %s\n", curr_fsDataP->data[i],
2269 curr_fsDataP->threshOvf[i] ? "(ovf)" : "");
2271 fprintf(debugFD, "\t\t--------------------------------\n\n");
2275 } /* the probe succeeded, so we store the data in the display structure */
2278 /* if we have received a reply from all the hosts for this probe cycle,
2279 * it is time to display the data */
2282 if (probes_Received == numFS) {
2283 probes_Received = 0;
2285 if (afsmon_fs_curr_probeNum != afsmon_fs_prev_probeNum + 1) {
2286 sprintf(errMsg, "[ %s ] Probe number %d missed! \n", rn,
2287 afsmon_fs_prev_probeNum + 1);
2290 afsmon_fs_prev_probeNum++;
2292 /* backup the display data of the probe cycle that just completed -
2293 * ie., store curr_fsData in prev_fsData */
2295 memcpy((char *)prev_fsData, (char *)curr_fsData,
2296 (numFS * sizeof(struct fs_Display_Data)));
2299 /* initialize curr_fsData but retain the threshold flag information.
2300 * The previous state of threshold flags is used in check_fs_thresholds() */
2302 numBytes = NUM_FS_STAT_ENTRIES * CM_STAT_STRING_LEN;
2303 curr_fsDataP = curr_fsData;
2304 for (i = 0; i < numFS; i++) {
2305 curr_fsDataP->probeOK = 0;
2306 curr_fsDataP->ovfCount = 0;
2307 memset((char *)curr_fsDataP->data, 0, numBytes);
2312 /* prev_fsData now contains all the information for the probe cycle
2313 * that just completed. Now count the number of threshold overflows for
2314 * use in the overview screen */
2316 prev_fsDataP = prev_fsData;
2318 numHosts_onfs_alerts = 0;
2319 for (i = 0; i < numFS; i++) {
2320 if (!prev_fsDataP->probeOK) { /* if probe failed */
2322 numHosts_onfs_alerts++;
2324 if (prev_fsDataP->ovfCount) { /* overflows ?? */
2325 num_fs_alerts += prev_fsDataP->ovfCount;
2326 numHosts_onfs_alerts++;
2331 fprintf(debugFD, "Number of FS alerts = %d (on %d hosts)\n",
2332 num_fs_alerts, numHosts_onfs_alerts);
2334 /* flag that the data is now ready to be displayed */
2335 fs_Data_Available = 1;
2337 /* call the Overview frame update routine (update only FS info) */
2338 ovw_refresh(ovw_currPage, OVW_UPDATE_FS);
2340 /* call the File Servers frame update routine */
2341 fs_refresh(fs_currPage, fs_curr_LCol);
2346 } /* save_FS_data_forDisplay */
2351 /*-----------------------------------------------------------------------
2352 * afsmon_FS_Handler()
2355 * This is the File Server probe Handler. It updates the afsmonitor
2356 * probe counts, fs circular buffer indices and calls the functions
2357 * to process the results of this probe.
2361 * Failure: Exits afsmonitor.
2362 *----------------------------------------------------------------------*/
2366 { /* afsmon_FS_Handler() */
2367 static char rn[] = "afsmon_FS_Handler"; /* routine name */
2368 int newProbeCycle; /* start of new probe cycle ? */
2369 int code; /* return status */
2374 "[ %s ] Called, hostName= %s, probeNum= %d, status=%s\n", rn,
2375 xstat_fs_Results.connP->hostName, xstat_fs_Results.probeNum,
2376 xstat_fs_Results.probeOK ? "FAILED" : "OK");
2381 /* print the probe results to output file */
2382 if (afsmon_output) {
2383 code = afsmon_fsOutput(output_filename, afsmon_detOutput);
2386 "[ %s ] output to file %s returned error code=%d\n", rn,
2387 output_filename, code);
2391 /* Update current probe number and circular buffer index. if current
2392 * probenum changed make sure it is only by 1 */
2395 if (xstat_fs_Results.probeNum != afsmon_fs_curr_probeNum) {
2396 if (xstat_fs_Results.probeNum == afsmon_fs_curr_probeNum + 1) {
2397 afsmon_fs_curr_probeNum++;
2400 afsmon_fs_curr_CBindex =
2401 (afsmon_fs_curr_probeNum - 1) % num_bufSlots;
2403 fprintf(stderr, "[ %s ] probe number %d-1 missed\n", rn,
2404 xstat_fs_Results.probeNum);
2409 /* store the results of this probe in the FS circular buffer */
2411 save_FS_results_inCB(newProbeCycle);
2414 /* store the results of the current probe in the fs data display structure.
2415 * if the current probe number changed, swap the current and previous display
2416 * structures. note that the display screen is updated from these structures
2417 * and should start showing the data of the just completed probe cycle */
2419 save_FS_data_forDisplay(&xstat_fs_Results);
2426 /*----------------------------------------------------------------------- *
2431 * Prints the Cache Manager circular buffer
2432 *----------------------------------------------------------------------*/
2436 { /* Print_CM_CB() */
2438 struct afsmon_cm_Results_list *cmlist;
2442 /* print valid info in the cm CB */
2446 "==================== CM Buffer ========================\n");
2447 fprintf(debugFD, "afsmon_cm_curr_CBindex = %d\n",
2448 afsmon_cm_curr_CBindex);
2449 fprintf(debugFD, "afsmon_cm_curr_probeNum = %d\n\n",
2450 afsmon_cm_curr_probeNum);
2452 for (i = 0; i < num_bufSlots; i++) {
2453 fprintf(debugFD, "\t--------- slot %d ----------\n", i);
2454 cmlist = afsmon_cm_ResultsCB[i].list;
2457 if (!cmlist->empty) {
2458 fprintf(debugFD, "\t %d) probeNum = %d host = %s", j,
2459 cmlist->cmResults->probeNum,
2460 cmlist->cmResults->connP->hostName);
2461 if (cmlist->cmResults->probeOK)
2462 fprintf(debugFD, " NOTOK\n");
2464 fprintf(debugFD, " OK\n");
2466 fprintf(debugFD, "\t %d) -- empty --\n", j);
2467 cmlist = cmlist->next;
2470 if (cmlist != (struct afsmon_cm_Results_list *)0)
2471 fprintf(debugFD, "dangling last next ptr cm CB\n");
2477 /*-----------------------------------------------------------------------
2478 * save_CM_results_inCB()
2481 * Saves the results of the latest CM probe in the cm circular
2482 * buffers. If the current probe cycle is in progress the contents
2483 * of xstat_cm_Results are copied to the end of the list of results
2484 * in the current slot (pointed to by afsmon_cm_curr_CBindex). If
2485 * a new probe cycle has started the next slot in the circular buffer
2486 * is initialized and the results copied. Note that the Rx related
2487 * information available in xstat_cm_Results is not copied.
2491 * Failure: Exits afsmonitor.
2492 *----------------------------------------------------------------------*/
2495 save_CM_results_inCB(a_newProbeCycle)
2496 int a_newProbeCycle; /* start of new probe cycle ? */
2498 { /* save_CM_results_inCB() */
2499 static char rn[] = "save_CM_results_inCB"; /* routine name */
2500 struct afsmon_cm_Results_list *tmp_cmlist_item; /* temp cm list item */
2501 struct xstat_cm_ProbeResults *tmp_cmPR; /* temp ptr */
2506 fprintf(debugFD, "[ %s ] Called, a_newProbeCycle= %d\n", rn,
2511 /* If a new probe cycle started, mark the list in the current buffer
2512 * slot empty for resuse. Note that afsmon_cm_curr_CBindex was appropriately
2513 * incremented in afsmon_CM_Handler() */
2515 if (a_newProbeCycle) {
2516 tmp_cmlist_item = afsmon_cm_ResultsCB[afsmon_cm_curr_CBindex].list;
2517 for (i = 0; i < numCM; i++) {
2518 tmp_cmlist_item->empty = 1;
2519 tmp_cmlist_item = tmp_cmlist_item->next;
2523 /* locate last unused item in list */
2524 tmp_cmlist_item = afsmon_cm_ResultsCB[afsmon_cm_curr_CBindex].list;
2525 for (i = 0; i < numCM; i++) {
2526 if (tmp_cmlist_item->empty)
2528 tmp_cmlist_item = tmp_cmlist_item->next;
2531 /* if we could not find one we have an inconsistent list */
2532 if (!tmp_cmlist_item->empty) {
2534 "[ %s ] list inconsistency 1. unable to find an empty slot to store results of probenum %d of %s\n",
2535 rn, xstat_cm_Results.probeNum,
2536 xstat_cm_Results.connP->hostName);
2540 tmp_cmPR = tmp_cmlist_item->cmResults;
2542 /* copy hostname and probe number and probe time and probe status.
2543 * if the probe failed return now */
2545 memcpy(tmp_cmPR->connP->hostName, xstat_cm_Results.connP->hostName,
2546 sizeof(xstat_cm_Results.connP->hostName));
2547 tmp_cmPR->probeNum = xstat_cm_Results.probeNum;
2548 tmp_cmPR->probeTime = xstat_cm_Results.probeTime;
2549 tmp_cmPR->probeOK = xstat_cm_Results.probeOK;
2550 if (xstat_cm_Results.probeOK) { /* probeOK = 1 => notOK */
2551 /* we have a nonempty results structure so mark the list item used */
2552 tmp_cmlist_item->empty = 0;
2557 /* copy connection information */
2558 memcpy(&(tmp_cmPR->connP->skt), &(xstat_cm_Results.connP->skt),
2559 sizeof(struct sockaddr_in));
2561 /**** NEED TO COPY rx_connection INFORMATION HERE ******/
2563 memcpy(tmp_cmPR->connP->hostName, xstat_cm_Results.connP->hostName,
2564 sizeof(xstat_cm_Results.connP->hostName));
2565 tmp_cmPR->collectionNumber = xstat_cm_Results.collectionNumber;
2567 /* copy the probe data information */
2568 tmp_cmPR->data.AFSCB_CollData_len =
2569 xstat_cm_Results.data.AFSCB_CollData_len;
2570 memcpy(tmp_cmPR->data.AFSCB_CollData_val,
2571 xstat_cm_Results.data.AFSCB_CollData_val,
2572 xstat_cm_Results.data.AFSCB_CollData_len * sizeof(afs_int32));
2575 /* we have a valid results structure so mark the list item used */
2576 tmp_cmlist_item->empty = 0;
2578 /* print the stored info - to make sure we copied it right */
2579 /* Print_cm_FullPerfInfo(tmp_cmPR); */
2580 /* Print the cm circular buffer */
2583 } /* save_CM_results_inCB */
2587 /*-----------------------------------------------------------------------
2591 * The results of xstat probes are stored in a string format in
2592 * the arrays curr_cmData and prev_cmData. The information stored in
2593 * prev_cmData is copied to the screen.
2594 * This function converts xstat FS results from longs to strings and
2595 * places them in the given buffer (a pointer to an item in curr_cmData).
2596 * When a probe cycle completes, curr_cmData is copied to prev_cmData
2597 * in afsmon_CM_Handler().
2601 *----------------------------------------------------------------------*/
2604 cm_Results_ltoa(a_cmData, a_cmResults)
2605 struct cm_Display_Data *a_cmData; /* target buffer */
2606 struct xstat_cm_ProbeResults *a_cmResults; /* ptr to xstat cm Results */
2607 { /* cm_Results_ltoa */
2609 static char rn[] = "cm_Results_ltoa"; /* routine name */
2610 struct afs_stats_CMFullPerf *fullP; /* ptr to complete CM stats */
2618 fprintf(debugFD, "[ %s ] Called, a_cmData= %d, a_cmResults= %d\n", rn,
2619 a_cmData, a_cmResults);
2624 fullP = (struct afs_stats_CMFullPerf *)
2625 (xstat_cm_Results.data.AFSCB_CollData_val);
2627 /* There are 4 parts to CM statistics
2628 * - Overall performance statistics (including up/down statistics)
2629 * - This CMs FS RPC operations info
2630 * - This CMs FS RPC errors info
2631 * - This CMs FS transfers info
2632 * - Authentication info
2633 * - [Un]Replicated access info
2636 /* copy overall performance statistics */
2637 srcbuf = (afs_int32 *) & (fullP->perf);
2639 /* we skip the 19 entry, ProtServAddr, so the index must account for this */
2640 for (i = 0; i < NUM_AFS_STATS_CMPERF_LONGS + 1; i++) {
2643 continue; /* skip ProtServerAddr */
2645 sprintf(a_cmData->data[idx], "%d", *srcbuf);
2650 /*printf("Ending index value = %d\n",idx-1); */
2652 /* server up/down statistics */
2653 /* copy file server up/down stats */
2654 srcbuf = (afs_int32 *) (fullP->perf.fs_UpDown);
2656 2 * (sizeof(struct afs_stats_SrvUpDownInfo) / sizeof(afs_int32));
2657 for (i = 0; i < numLongs; i++) {
2658 sprintf(a_cmData->data[idx], "%d", *srcbuf);
2663 /*printf("Ending index value = %d\n",idx-1); */
2665 /* copy volume location server up/down stats */
2666 srcbuf = (afs_int32 *) (fullP->perf.vl_UpDown);
2668 2 * (sizeof(struct afs_stats_SrvUpDownInfo) / sizeof(afs_int32));
2669 for (i = 0; i < numLongs; i++) {
2670 sprintf(a_cmData->data[idx], "%d", *srcbuf);
2675 /*printf("Ending index value = %d\n",idx-1); */
2677 /* copy CMs individual FS RPC operations info */
2678 srcbuf = (afs_int32 *) (fullP->rpc.fsRPCTimes);
2679 for (i = 0; i < AFS_STATS_NUM_FS_RPC_OPS; i++) {
2680 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* numOps */
2683 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* numSuccesses */
2686 tmpbuf = srcbuf++; /* sum time */
2687 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2690 tmpbuf = srcbuf++; /* sqr time */
2691 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2694 tmpbuf = srcbuf++; /* min time */
2695 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2698 tmpbuf = srcbuf++; /* max time */
2699 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2704 /*printf("Ending index value = %d\n",idx-1); */
2706 /* copy CMs individual FS RPC errors info */
2708 srcbuf = (afs_int32 *) (fullP->rpc.fsRPCErrors);
2709 for (i = 0; i < AFS_STATS_NUM_FS_RPC_OPS; i++) {
2710 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* server */
2713 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* network */
2716 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* prot */
2719 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* vol */
2722 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* busies */
2725 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* other */
2730 /*printf("Ending index value = %d\n",idx-1); */
2732 /* copy CMs individual RPC transfers info */
2734 srcbuf = (afs_int32 *) (fullP->rpc.fsXferTimes);
2735 for (i = 0; i < AFS_STATS_NUM_FS_XFER_OPS; i++) {
2736 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* numOps */
2739 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* numSuccesses */
2742 tmpbuf = srcbuf++; /* sum time */
2743 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2746 tmpbuf = srcbuf++; /* sqr time */
2747 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2750 tmpbuf = srcbuf++; /* min time */
2751 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2754 tmpbuf = srcbuf++; /* max time */
2755 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2758 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* sum bytes */
2761 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* min bytes */
2764 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* max bytes */
2767 for (j = 0; j < AFS_STATS_NUM_XFER_BUCKETS; j++) {
2768 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* bucket[j] */
2774 /*printf("Ending index value = %d\n",idx-1); */
2776 /* copy CM operations timings */
2778 srcbuf = (afs_int32 *) (fullP->rpc.cmRPCTimes);
2779 for (i = 0; i < AFS_STATS_NUM_CM_RPC_OPS; i++) {
2780 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* numOps */
2783 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* numSuccesses */
2786 tmpbuf = srcbuf++; /* sum time */
2787 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2790 tmpbuf = srcbuf++; /* sqr time */
2791 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2794 tmpbuf = srcbuf++; /* min time */
2795 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2798 tmpbuf = srcbuf++; /* max time */
2799 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2804 /*printf("Ending index value = %d\n",idx-1); */
2806 /* copy authentication info */
2808 srcbuf = (afs_int32 *) & (fullP->authent);
2809 numLongs = sizeof(struct afs_stats_AuthentInfo) / sizeof(afs_int32);
2810 for (i = 0; i < numLongs; i++) {
2811 sprintf(a_cmData->data[idx], "%d", *srcbuf);
2816 /*printf("Ending index value = %d\n",idx-1); */
2818 /* copy CM [un]replicated access info */
2820 srcbuf = (afs_int32 *) & (fullP->accessinf);
2821 numLongs = sizeof(struct afs_stats_AccessInfo) / sizeof(afs_int32);
2822 for (i = 0; i < numLongs; i++) {
2823 sprintf(a_cmData->data[idx], "%d", *srcbuf);
2828 /*printf("Ending index value = %d\n",idx-1); */
2831 } /* cm_Results_ltoa */
2834 /*-----------------------------------------------------------------------
2835 * Function: check_cm_thresholds()
2838 * Checks the thresholds and sets the overflow flag. Recall that the
2839 * thresholds for each host are stored in the hostEntry lists
2840 * [fs/cm]nameList arrays. The probe results are passed to this
2841 * function in the display-ready format - ie., as strings. Though
2842 * this looks stupid the overhead incurred in converting the strings
2843 * back to floats and comparing them is insignificant and
2844 * programming is easier this way.
2845 * The threshold flags are a part of the display structures
2850 *----------------------------------------------------------------------*/
2853 check_cm_thresholds(a_hostEntry, a_Data)
2854 struct afsmon_hostEntry *a_hostEntry; /* ptr to hostEntry */
2855 struct cm_Display_Data *a_Data; /* ptr to cm data to be displayed */
2857 { /* check_cm_thresholds */
2859 static char rn[] = "check_cm_thresholds";
2860 struct Threshold *threshP;
2861 double tValue; /* threshold value */
2862 double pValue; /* probe value */
2865 int count; /* number of thresholds exceeded */
2868 fprintf(debugFD, "[ %s ] Called, a_hostEntry= %d, a_Data= %d\n", rn,
2869 a_hostEntry, a_Data);
2873 if (a_hostEntry->numThresh == 0) {
2874 /* store in ovf count ?? */
2879 threshP = a_hostEntry->thresh;
2880 for (i = 0; i < a_hostEntry->numThresh; i++) {
2881 if (threshP->itemName[0] == '\0') {
2885 idx = threshP->index; /* positional index to the data array */
2886 tValue = atof(threshP->threshVal); /* threshold value */
2887 pValue = atof(a_Data->data[idx]); /* probe value */
2888 if (pValue > tValue) {
2892 "[ %s ] cm = %s, thresh ovf for %s, threshold= %s, probevalue= %s\n",
2893 rn, a_hostEntry->hostName, threshP->itemName,
2894 threshP->threshVal, a_Data->data[idx]);
2898 /* if the threshold is crossed, call the handler function
2899 * only if this was a transition -ie, if the threshold was
2900 * crossed in the last probe too just count & keep quite! */
2902 if (!a_Data->threshOvf[idx]) {
2903 a_Data->threshOvf[idx] = 1;
2904 /* call the threshold handler if provided */
2905 if (threshP->handler[0] != '\0') {
2907 fprintf(debugFD, "[ %s ] Calling ovf handler %s\n",
2908 rn, threshP->handler);
2911 execute_thresh_handler(threshP->handler, a_Data->hostName,
2912 CM, threshP->itemName,
2920 /* in case threshold was previously crossed, blank it out */
2921 a_Data->threshOvf[idx] = 0;
2924 /* store the overflow count */
2925 a_Data->ovfCount = count;
2928 } /* check_cm_thresholds */
2931 /*-----------------------------------------------------------------------
2932 * save_CM_data_forDisplay()
2935 * Does the following:
2936 * - if the probe number changed (ie, a cycle completed) curr_cmData
2937 * is copied to prev_cmData, curr_cmData zeroed and refresh the
2938 * overview screen and file server screen with the new data.
2939 * - store the results of the current probe from xstat_cm_Results into
2940 * curr_cmData. ie., convert longs to strings.
2941 * - check the thresholds
2945 * Failure: Exits afsmonitor.
2947 *----------------------------------------------------------------------*/
2950 save_CM_data_forDisplay(a_cmResults)
2951 struct xstat_cm_ProbeResults *a_cmResults;
2952 { /* save_CM_data_forDisplay */
2954 static char rn[] = "save_CM_data_forDisplay"; /* routine name */
2955 struct cm_Display_Data *curr_cmDataP;
2956 struct cm_Display_Data *prev_cmDataP;
2957 struct afsmon_hostEntry *curr_host;
2958 static int probes_Received = 0; /* number of probes reveived in
2959 * the current cycle. If this is equal to numFS we got all
2960 * the data we want in this cycle and can now display it */
2968 fprintf(debugFD, "[ %s ] Called, a_cmResults= %d\n", rn, a_cmResults);
2972 /* store results in the display array */
2975 curr_cmDataP = curr_cmData;
2976 for (i = 0; i < numCM; i++) {
2977 if ((strcasecmp(curr_cmDataP->hostName, a_cmResults->connP->hostName))
2987 "[ %s ] Could not insert CM probe results for host %s in cm display array\n",
2988 rn, a_cmResults->connP->hostName);
2992 /* Check the status of the probe. If it succeeded, we store its
2993 * results in the display data structure. If it failed we only mark
2994 * the failed status in the display data structure. */
2997 if (a_cmResults->probeOK) { /* 1 => notOK the xstat results */
2998 curr_cmDataP->probeOK = 0;
3000 /* print the probe status */
3002 fprintf(debugFD, "\n\t\t ----- cm display data ------\n");
3003 fprintf(debugFD, "HostName = %s PROBE FAILED \n",
3004 curr_cmDataP->hostName);
3008 } else { /* probe succeeded, update display data structures */
3009 curr_cmDataP->probeOK = 1;
3012 /* covert longs to strings and place them in curr_cmDataP */
3013 cm_Results_ltoa(curr_cmDataP, a_cmResults);
3015 /* compare with thresholds and set the overflow flags.
3016 * note that the threshold information is in the hostEntry structure and
3017 * each threshold item has a positional index associated with it */
3019 /* locate the hostEntry for this host */
3021 curr_host = CMnameList;
3022 for (i = 0; i < numCM; i++) {
3023 if (strcasecmp(curr_host->hostName, a_cmResults->connP->hostName)
3028 curr_host = curr_host->next;
3033 code = check_cm_thresholds(curr_host, curr_cmDataP);
3035 fprintf(stderr, "[ %s ] Error in checking thresholds\n", rn);
3040 /* print the info we just saved */
3042 fprintf(debugFD, "\n\t\t ----- CM display data ------\n");
3043 fprintf(debugFD, "HostName = %s\n", curr_cmDataP->hostName);
3044 for (i = 0; i < NUM_CM_STAT_ENTRIES; i++) {
3047 fprintf(debugFD, "\t -- Overall Perf Info --\n");
3051 "\t -- File Server up/down stats - same cell --\n");
3055 "\t -- File Server up/down stats - diff cell --\n");
3059 "\t -- VL server up/down stats - same cell --\n");
3063 "\t -- VL server up/down stats - diff cell --\n");
3066 fprintf(debugFD, "\t -- FS Operation Timings --\n");
3069 fprintf(debugFD, "\t -- FS Error Info --\n");
3072 fprintf(debugFD, "\t -- FS Transfer Timings --\n");
3075 fprintf(debugFD, "\t -- CM Operations Timings --\n");
3078 fprintf(debugFD, "\t -- Authentication Info --\n");
3081 fprintf(debugFD, "\t -- Access Info --\n");
3087 fprintf(debugFD, "%20s %30s %s\n", curr_cmDataP->data[i],
3089 curr_cmDataP->threshOvf[i] ? "(ovf)" : "");
3091 fprintf(debugFD, "\t\t--------------------------------\n\n");
3094 } /* if the probe succeeded, update the display data structures */
3096 /* if we have received a reply from all the hosts for this probe cycle,
3097 * it is time to display the data */
3100 if (probes_Received == numCM) {
3101 probes_Received = 0;
3103 if (afsmon_cm_curr_probeNum != afsmon_cm_prev_probeNum + 1) {
3104 sprintf(errMsg, "[ %s ] Probe number %d missed! \n", rn,
3105 afsmon_cm_prev_probeNum + 1);
3108 afsmon_cm_prev_probeNum++;
3111 /* backup the display data of the probe cycle that just completed -
3112 * ie., store curr_cmData in prev_cmData */
3114 memcpy((char *)prev_cmData, (char *)curr_cmData,
3115 (numCM * sizeof(struct cm_Display_Data)));
3118 /* initialize curr_cmData but retain the threshold flag information.
3119 * The previous state of threshold flags is used in check_cm_thresholds() */
3121 curr_cmDataP = curr_cmData;
3122 numBytes = NUM_CM_STAT_ENTRIES * CM_STAT_STRING_LEN;
3123 for (i = 0; i < numCM; i++) {
3124 curr_cmDataP->probeOK = 0;
3125 curr_cmDataP->ovfCount = 0;
3126 memset((char *)curr_cmDataP->data, 0, numBytes);
3130 /* prev_cmData now contains all the information for the probe cycle
3131 * that just completed. Now count the number of threshold overflows for
3132 * use in the overview screen */
3134 prev_cmDataP = prev_cmData;
3136 numHosts_oncm_alerts = 0;
3137 for (i = 0; i < numCM; i++) {
3138 if (!prev_cmDataP->probeOK) { /* if probe failed */
3140 numHosts_oncm_alerts++;
3141 } else if (prev_cmDataP->ovfCount) { /* overflows ?? */
3142 num_cm_alerts += prev_cmDataP->ovfCount;
3143 numHosts_oncm_alerts++;
3148 fprintf(debugFD, "Number of CM alerts = %d (on %d hosts)\n",
3149 num_cm_alerts, numHosts_oncm_alerts);
3152 /* flag that the data is now ready to be displayed */
3153 cm_Data_Available = 1;
3155 /* update the Overview frame (only CM info) */
3156 ovw_refresh(ovw_currPage, OVW_UPDATE_CM);
3158 /* update the Cache Managers frame */
3159 cm_refresh(cm_currPage, cm_curr_LCol);
3165 } /* save_CM_data_forDisplay */
3169 /*-----------------------------------------------------------------------
3170 * afsmon_CM_Handler()
3173 * This is the Cache Manager probe Handler. It updates the afsmonitor
3174 * probe counts, cm circular buffer indices and calls the functions
3175 * to process the results of this probe.
3179 * Failure: Exits afsmonitor.
3180 *----------------------------------------------------------------------*/
3184 { /* afsmon_CM_Handler() */
3185 static char rn[] = "afsmon_CM_Handler"; /* routine name */
3186 int code; /* return status */
3187 int newProbeCycle; /* start of new probe cycle ? */
3191 "[ %s ] Called, hostName= %s, probeNum= %d, status= %s\n", rn,
3192 xstat_cm_Results.connP->hostName, xstat_cm_Results.probeNum,
3193 xstat_cm_Results.probeOK ? "FAILED" : "OK");
3198 /* print the probe results to output file */
3199 if (afsmon_output) {
3200 code = afsmon_cmOutput(output_filename, afsmon_detOutput);
3203 "[ %s ] output to file %s returned error code=%d\n", rn,
3204 output_filename, code);
3208 /* Update current probe number and circular buffer index. if current
3209 * probenum changed make sure it is only by 1 */
3212 if (xstat_cm_Results.probeNum != afsmon_cm_curr_probeNum) {
3213 if (xstat_cm_Results.probeNum == afsmon_cm_curr_probeNum + 1) {
3214 afsmon_cm_curr_probeNum++;
3217 afsmon_cm_curr_CBindex =
3218 (afsmon_cm_curr_probeNum - 1) % num_bufSlots;
3220 fprintf(stderr, "[ %s ] probe number %d-1 missed\n", rn,
3221 xstat_cm_Results.probeNum);
3226 /* save the results of this probe in the CM buffer */
3228 save_CM_results_inCB(newProbeCycle);
3230 /* store the results of the current probe in the cm data display structure.
3231 * if the current probe number changed, swap the current and previous display
3232 * structures. note that the display screen is updated from these structures
3233 * and should start showing the data of the just completed probe cycle */
3235 save_CM_data_forDisplay(&xstat_cm_Results);
3240 /*-----------------------------------------------------------------------
3244 * Allocate and Initialize circular buffers for file servers.
3248 * Failure to allocate memory: exits afsmonitor.
3249 *----------------------------------------------------------------------*/
3253 { /* init_fs_buffers() */
3254 static char rn[] = "init_fs_buffers"; /* routine name */
3255 struct afsmon_fs_Results_list *new_fslist_item; /* ptr for new struct */
3256 struct afsmon_fs_Results_list *tmp_fslist_item; /* temp ptr */
3257 struct xstat_fs_ProbeResults *new_fsPR; /* ptr for new struct */
3264 fprintf(debugFD, "[ %s ] Called\n", rn);
3268 /* allocate memory for the circular buffer of pointers */
3270 afsmon_fs_ResultsCB = (struct afsmon_fs_Results_CBuffer *)
3271 malloc(sizeof(struct afsmon_fs_Results_CBuffer) * num_bufSlots);
3273 /* initialize the fs circular buffer */
3274 for (i = 0; i < num_bufSlots; i++) {
3275 afsmon_fs_ResultsCB[i].list = (struct afsmon_fs_Results_list *)0;
3276 afsmon_fs_ResultsCB[i].probeNum = 0;
3279 /* create a list of numFS items to store fs probe results for
3280 * each slot in CB */
3282 if (numFS) { /* if we have file servers to monitor */
3283 for (bufslot = 0; bufslot < num_bufSlots; bufslot++) {
3284 numfs = numFS; /* get the number of servers */
3287 /* if any of these mallocs fail we only need to free the memory we
3288 * have allocated in this iteration. the rest of it which is in a
3289 * proper linked list will be freed in afsmon_Exit */
3291 /* allocate memory for an fs list item */
3292 new_fslist_item = (struct afsmon_fs_Results_list *)
3293 malloc(sizeof(struct afsmon_fs_Results_list));
3294 if (new_fslist_item == (struct afsmon_fs_Results_list *)0)
3297 /* allocate memory to store xstat_fs_Results */
3298 new_fsPR = (struct xstat_fs_ProbeResults *)
3299 malloc(sizeof(struct xstat_fs_ProbeResults));
3300 if (new_fsPR == (struct xstat_fs_ProbeResults *)0) {
3301 free(new_fslist_item);
3304 new_fsPR->connP = (struct xstat_fs_ConnectionInfo *)
3305 malloc(sizeof(struct xstat_fs_ConnectionInfo));
3306 if (new_fsPR->connP == (struct xstat_fs_ConnectionInfo *)0) {
3307 free(new_fslist_item);
3312 /* >>> need to allocate rx connection info structure here <<< */
3314 new_fsPR->data.AFS_CollData_val =
3315 (afs_int32 *) malloc(XSTAT_FS_FULLPERF_RESULTS_LEN *
3317 if (new_fsPR->data.AFS_CollData_val == NULL) {
3318 free(new_fslist_item);
3319 free(new_fsPR->connP);
3324 /* initialize this list entry */
3325 new_fslist_item->fsResults = new_fsPR;
3326 new_fslist_item->empty = 1;
3327 new_fslist_item->next = (struct afsmon_fs_Results_list *)0;
3329 /* store it at the end of the fs list in the current CB slot */
3330 if (afsmon_fs_ResultsCB[bufslot].list ==
3331 (struct afsmon_fs_Results_list *)0)
3332 afsmon_fs_ResultsCB[bufslot].list = new_fslist_item;
3334 tmp_fslist_item = afsmon_fs_ResultsCB[bufslot].list;
3336 while (tmp_fslist_item !=
3337 (struct afsmon_fs_Results_list *)0) {
3338 if (tmp_fslist_item->next ==
3339 (struct afsmon_fs_Results_list *)0)
3341 tmp_fslist_item = tmp_fslist_item->next;
3343 /* something goofed. exit */
3344 fprintf(stderr, "[ %s ] list creation error\n",
3349 tmp_fslist_item->next = new_fslist_item;
3352 } /* while servers */
3353 } /* for each buffer slot */
3354 } /* if we have file servers to monitor */
3358 /*-----------------------------------------------------------------------
3362 * Allocate and Initialize circular buffers for cache managers.
3366 * Failure to allocate memory: exits afsmonitor.
3367 *----------------------------------------------------------------------*/
3371 { /* init_cm_buffers() */
3372 static char rn[] = "init_cm_buffers"; /* routine name */
3373 struct afsmon_cm_Results_list *new_cmlist_item; /* ptr for new struct */
3374 struct afsmon_cm_Results_list *tmp_cmlist_item; /* temp ptr */
3375 struct xstat_cm_ProbeResults *new_cmPR; /* ptr for new struct */
3381 fprintf(debugFD, "[ %s ] Called\n", rn);
3385 /* allocate memory for the circular buffer of pointers */
3386 afsmon_cm_ResultsCB = (struct afsmon_cm_Results_CBuffer *)
3387 malloc(sizeof(struct afsmon_cm_Results_CBuffer) * num_bufSlots);
3389 /* initialize the fs circular buffer */
3390 for (i = 0; i < num_bufSlots; i++) {
3391 afsmon_cm_ResultsCB[i].list = (struct afsmon_cm_Results_list *)0;
3392 afsmon_cm_ResultsCB[i].probeNum = 0;
3395 /* create a list of numCM items to store fs probe results for
3396 * each slot in CB */
3398 if (numCM) { /* if we have file servers to monitor */
3399 for (bufslot = 0; bufslot < num_bufSlots; bufslot++) {
3400 numcm = numCM; /* get the number of servers */
3403 /* if any of these mallocs fail we only need to free the memory we
3404 * have allocated in this iteration. the rest of it which is in a
3405 * proper linked list will be freed in afsmon_Exit */
3407 /* allocate memory for an fs list item */
3408 new_cmlist_item = (struct afsmon_cm_Results_list *)
3409 malloc(sizeof(struct afsmon_cm_Results_list));
3410 if (new_cmlist_item == (struct afsmon_cm_Results_list *)0)
3413 /* allocate memory to store xstat_cm_Results */
3414 new_cmPR = (struct xstat_cm_ProbeResults *)
3415 malloc(sizeof(struct xstat_cm_ProbeResults));
3416 if (new_cmPR == (struct xstat_cm_ProbeResults *)0) {
3417 free(new_cmlist_item);
3420 new_cmPR->connP = (struct xstat_cm_ConnectionInfo *)
3421 malloc(sizeof(struct xstat_cm_ConnectionInfo));
3422 if (new_cmPR->connP == (struct xstat_cm_ConnectionInfo *)0) {
3423 free(new_cmlist_item);
3428 /* >>> need to allocate rx connection info structure here <<< */
3430 new_cmPR->data.AFSCB_CollData_val =
3431 (afs_int32 *) malloc(XSTAT_CM_FULLPERF_RESULTS_LEN *
3433 if (new_cmPR->data.AFSCB_CollData_val == NULL) {
3434 free(new_cmlist_item);
3435 free(new_cmPR->connP);
3440 /* initialize this list entry */
3441 new_cmlist_item->cmResults = new_cmPR;
3442 new_cmlist_item->empty = 1;
3443 new_cmlist_item->next = (struct afsmon_cm_Results_list *)0;
3445 /* store it at the end of the cm list in the current CB slot */
3446 if (afsmon_cm_ResultsCB[bufslot].list ==
3447 (struct afsmon_cm_Results_list *)0)
3448 afsmon_cm_ResultsCB[bufslot].list = new_cmlist_item;
3450 tmp_cmlist_item = afsmon_cm_ResultsCB[bufslot].list;
3452 while (tmp_cmlist_item !=
3453 (struct afsmon_cm_Results_list *)0) {
3454 if (tmp_cmlist_item->next ==
3455 (struct afsmon_cm_Results_list *)0)
3457 tmp_cmlist_item = tmp_cmlist_item->next;
3459 /* something goofed. exit */
3460 fprintf(stderr, "[ %s ] list creation error\n",
3465 tmp_cmlist_item->next = new_cmlist_item;
3468 } /* while servers */
3469 } /* for each buffer slot */
3471 /* if we have file servers to monitor */
3472 /* print the CB to make sure it is right */
3476 } /* init_cm_buffers() */
3479 /*-------------------------------------------------------------------------
3480 * init_print_buffers()
3483 * Allocate and initialize the buffers used for printing results
3484 * to the display screen. These buffers store the current and
3485 * previous probe results in ascii format.
3490 *------------------------------------------------------------------------*/
3493 init_print_buffers()
3494 { /* init_print_buffers */
3496 static char rn[] = "init_print_buffers"; /* routine name */
3497 struct fs_Display_Data *tmp_fsData1; /* temp pointers */
3498 struct fs_Display_Data *tmp_fsData2;
3499 struct cm_Display_Data *tmp_cmData1;
3500 struct cm_Display_Data *tmp_cmData2;
3501 struct afsmon_hostEntry *tmp_fsNames;
3502 struct afsmon_hostEntry *tmp_cmNames;
3507 fprintf(debugFD, "[ %s ] Called\n", rn);
3511 /* allocate numFS blocks of the FS print structure. */
3513 /* we need two instances of this structure - one (curr_fsData) for storing
3514 * the results of the fs probes currently in progress and another (prev_fsData)
3515 * for the last completed probe. The display is updated from the contents of
3516 * prev_fsData. The pointers curr_fsData & prev_fsData are switched whenever
3517 * the probe number changes */
3520 numBytes = numFS * sizeof(struct fs_Display_Data);
3521 curr_fsData = (struct fs_Display_Data *)malloc(numBytes);
3522 if (curr_fsData == (struct fs_Display_Data *)0) {
3523 fprintf(stderr, "[ %s ] Memory allocation failure\n", rn);
3526 memset(curr_fsData, 0, numBytes);
3528 numBytes = numFS * sizeof(struct fs_Display_Data);
3529 prev_fsData = (struct fs_Display_Data *)malloc(numBytes);
3530 if (prev_fsData == (struct fs_Display_Data *)0) {
3531 fprintf(stderr, "[ %s ] Memory allocation failure\n", rn);
3534 memset(prev_fsData, 0, numBytes);
3536 /* fill in the host names */
3537 tmp_fsData1 = curr_fsData;
3538 tmp_fsData2 = curr_fsData;
3539 tmp_fsNames = FSnameList;
3540 for (i = 0; i < numFS; i++) {
3541 strncpy(tmp_fsData1->hostName, tmp_fsNames->hostName,
3543 strncpy(tmp_fsData2->hostName, tmp_fsNames->hostName,
3547 tmp_fsNames = tmp_fsNames->next;;
3554 /* if file servers to monitor */
3555 /* allocate numCM blocks of the CM print structure */
3556 /* we need two instances of this structure for the same reasons as above */
3558 numBytes = numCM * sizeof(struct cm_Display_Data);
3560 curr_cmData = (struct cm_Display_Data *)malloc(numBytes);
3561 if (curr_cmData == (struct cm_Display_Data *)0) {
3562 fprintf(stderr, "[ %s ] Memory allocation failure\n", rn);
3565 memset(curr_cmData, 0, numBytes);
3567 numBytes = numCM * sizeof(struct cm_Display_Data);
3568 prev_cmData = (struct cm_Display_Data *)malloc(numBytes);
3569 if (prev_cmData == (struct cm_Display_Data *)0) {
3570 fprintf(stderr, "[ %s ] Memory allocation failure\n", rn);
3573 memset(prev_cmData, 0, numBytes);
3575 /* fill in the host names */
3576 tmp_cmData1 = curr_cmData;
3577 tmp_cmData2 = curr_cmData;
3578 tmp_cmNames = CMnameList;
3579 for (i = 0; i < numCM; i++) {
3580 strncpy(tmp_cmData1->hostName, tmp_cmNames->hostName,
3582 strncpy(tmp_cmData2->hostName, tmp_cmNames->hostName,
3586 tmp_cmNames = tmp_cmNames->next;;
3590 /* if cache managers to monitor */
3593 } /* init_print_buffers */
3595 /*-----------------------------------------------------------------------
3599 * Trap the interrupt signal. This function is useful only until
3600 * gtx is initialized.
3601 *----------------------------------------------------------------------*/
3607 static char *rn = "quit_signal"; /* routine name */
3609 fprintf(stderr, "Received signal %d \n", sig);
3615 /*-----------------------------------------------------------------------
3619 * This is where we start it all. Initialize an array of sockets for
3620 * file servers and cache cache managers and call the xstat_[fs/cm]_Init
3621 * routines. The last step is to call the gtx input server which
3622 * grabs control of the keyboard.
3625 * Does not return. Control is periodically returned to the afsmonitor
3626 * thru afsmon_[FS/CM]_Handler() routines and also through the gtx
3627 * keyboard handler calls.
3629 *----------------------------------------------------------------------*/
3633 { /* afsmon_execute() */
3634 static char rn[] = "afsmon_execute"; /* routine name */
3635 static char fullhostname[128]; /* full host name */
3636 struct sockaddr_in *FSSktArray; /* fs socket array */
3637 int FSsktbytes; /* num bytes in above */
3638 struct sockaddr_in *CMSktArray; /* cm socket array */
3639 int CMsktbytes; /* num bytes in above */
3640 struct sockaddr_in *curr_skt; /* ptr to current socket */
3641 struct afsmon_hostEntry *curr_FS; /* ptr to FS name list */
3642 struct afsmon_hostEntry *curr_CM; /* ptr to CM name list */
3643 struct hostent *he; /* host entry */
3644 afs_int32 *collIDP; /* ptr to collection ID */
3645 int numCollIDs; /* number of collection IDs */
3646 int FSinitFlags = 0; /* flags for xstat_fs_Init */
3647 int CMinitFlags = 0; /* flags for xstat_cm_Init */
3648 int code; /* function return code */
3649 struct timeval tv; /* time structure */
3652 fprintf(debugFD, "[ %s ] Called\n", rn);
3657 /* process file server entries */
3659 /* Allocate an array of sockets for each fileserver we monitor */
3661 FSsktbytes = numFS * sizeof(struct sockaddr_in);
3662 FSSktArray = (struct sockaddr_in *)malloc(FSsktbytes);
3663 if (FSSktArray == (struct sockaddr_in *)0) {
3665 "[ %s ] cannot malloc %d sockaddr_ins for fileservers\n",
3670 memset(FSSktArray, 0, FSsktbytes);
3672 /* Fill in the socket information for each fileserve */
3674 curr_skt = FSSktArray;
3675 curr_FS = FSnameList; /* FS name list header */
3677 strncpy(fullhostname, curr_FS->hostName, sizeof(fullhostname));
3678 he = GetHostByName(fullhostname);
3680 fprintf(stderr, "[ %s ] Cannot get host info for %s\n", rn,
3684 strncpy(curr_FS->hostName, he->h_name, HOST_NAME_LEN); /* complete name */
3685 memcpy(&(curr_skt->sin_addr.s_addr), he->h_addr, 4);
3686 curr_skt->sin_family = htons(AF_INET); /*Internet family */
3687 curr_skt->sin_port = htons(7000); /*FileServer port */
3688 #ifdef STRUCT_SOCKADDR_HAS_SA_LEN
3689 curr_skt->sin_len = sizeof(struct sockaddr_in);
3692 /* get the next dude */
3694 curr_FS = curr_FS->next;
3697 /* initialize collection IDs. We need only one entry since we collect
3698 * all the information from xstat */
3701 collIDP = (afs_int32 *) malloc(sizeof(afs_int32));
3702 if (collIDP == NULL) {
3704 "[ %s ] failed to allocate a measely afs_int32 word.Argh!\n",
3708 *collIDP = 2; /* USE A macro for this */
3711 if (afsmon_onceOnly) /* option not provided at this time */
3712 FSinitFlags |= XSTAT_FS_INITFLAG_ONE_SHOT;
3715 fprintf(debugFD, "[ %s ] Calling xstat_fs_Init \n", rn);
3719 code = xstat_fs_Init(numFS, /*Num servers */
3720 FSSktArray, /*File Server socket array */
3721 afsmon_probefreq, /*probe frequency */
3722 afsmon_FS_Handler, /*Handler routine */
3723 FSinitFlags, /*Initialization flags */
3724 numCollIDs, /*Number of collection IDs */
3725 collIDP); /*Ptr to collection ID */
3728 fprintf(stderr, "[ %s ] xstat_fs_init returned error\n", rn);
3735 /* end of process fileserver entries */
3736 /* process cache manager entries */
3738 /* Allocate an array of sockets for each cache manager we monitor */
3740 CMsktbytes = numCM * sizeof(struct sockaddr_in);
3741 CMSktArray = (struct sockaddr_in *)malloc(CMsktbytes);
3742 if (CMSktArray == (struct sockaddr_in *)0) {
3744 "[ %s ] cannot malloc %d sockaddr_ins for CM entries\n",
3749 memset(CMSktArray, 0, CMsktbytes);
3751 /* Fill in the socket information for each CM */
3753 curr_skt = CMSktArray;
3754 curr_CM = CMnameList; /* CM name list header */
3756 strncpy(fullhostname, curr_CM->hostName, sizeof(fullhostname));
3757 he = GetHostByName(fullhostname);
3759 fprintf(stderr, "[ %s ] Cannot get host info for %s\n", rn,
3763 strncpy(curr_CM->hostName, he->h_name, HOST_NAME_LEN); /* complete name */
3764 memcpy(&(curr_skt->sin_addr.s_addr), he->h_addr, 4);
3765 curr_skt->sin_family = htons(AF_INET); /*Internet family */
3766 curr_skt->sin_port = htons(7001); /*Cache Manager port */
3767 #ifdef STRUCT_SOCKADDR_HAS_SA_LEN
3768 curr_skt->sin_len = sizeof(struct sockaddr_in);
3771 /* get the next dude */
3773 curr_CM = curr_CM->next;
3776 /* initialize collection IDs. We need only one entry since we collect
3777 * all the information from xstat */
3780 collIDP = (afs_int32 *) malloc(sizeof(afs_int32));
3781 if (collIDP == NULL) {
3783 "[ %s ] failed to allocate a measely long word.Argh!\n",
3787 *collIDP = 2; /* USE A macro for this */
3790 if (afsmon_onceOnly) /* once only ? */
3791 CMinitFlags |= XSTAT_CM_INITFLAG_ONE_SHOT;
3794 fprintf(debugFD, "[ %s ] Calling xstat_cm_Init \n", rn);
3798 code = xstat_cm_Init(numCM, /*Num servers */
3799 CMSktArray, /*Cache Manager socket array */
3800 afsmon_probefreq, /*probe frequency */
3801 afsmon_CM_Handler, /*Handler routine */
3802 CMinitFlags, /*Initialization flags */
3803 numCollIDs, /*Number of collection IDs */
3804 collIDP); /*Ptr to collection ID */
3807 fprintf(stderr, "[ %s ] xstat_cm_init returned error\n", rn);
3814 /* end of process cache manager entries */
3815 /* if only one probe was required setup a waiting process for the
3816 * termination signal */
3817 if (afsmon_onceOnly) {
3818 code = LWP_WaitProcess(&terminationEvent);
3821 fprintf(debugFD, "LWP_WaitProcess() returned error %d\n",
3829 /* start the gtx input server */
3830 code = gtx_InputServer(afsmon_win);
3832 fprintf(stderr, "[ %s ] Failed to start input server \n", rn);
3836 /* This part of the code is reached only if the input server is not started
3837 * for debugging purposes */
3840 tv.tv_sec = 24 * 60;
3842 fprintf(stderr, "[ %s ] going to sleep ...\n", rn);
3844 code = IOMGR_Select(0, /*Num fds */
3845 0, /*Descriptors ready for reading */
3846 0, /*Descriptors ready for writing */
3847 0, /*Descriptors with exceptional conditions */
3848 &tv); /*Timeout structure */
3851 "[ %s ] IOMGR_Select() returned non-zero value %d\n", rn,
3859 /*-----------------------------------------------------------------------
3863 * Afsmonitor initialization routine.
3864 * - processes command line parameters
3865 * - call functions to:
3866 * - process config file
3867 * - initialize circular buffers and display buffers
3869 * - execute afsmonitor
3870 * - initialize the display maps [fs/cm]_Display_map[].
3873 * Success: Does not return from the call to afsmon_execute().
3874 * Failure: Exits afsmonitor.
3875 *----------------------------------------------------------------------*/
3879 struct cmd_syndesc *as;
3880 { /* afsmonInit() */
3882 static char rn[] = "afsmonInit"; /* Routine name */
3883 char *debug_filename; /* pointer to debug filename */
3884 FILE *outputFD; /* output file descriptor */
3885 struct cmd_item *hostPtr; /* ptr to parse command line args */
3886 char buf[256]; /* buffer for processing hostnames */
3891 fprintf(debugFD, "[ %s ] Called, as= %d\n", rn, as);
3895 /* Open the debug file if -debug option is specified */
3896 if (as->parms[P_DEBUG].items != 0) {
3898 debug_filename = as->parms[P_DEBUG].items->data;
3899 debugFD = fopen(debug_filename, "w");
3900 if (debugFD == (FILE *) 0) {
3901 printf("[ %s ] Failed to open debugging file %s for writing\n",
3909 fprintf(debugFD, "[ %s ] Called\n", rn);
3913 /* use curses always until we support other packages */
3915 wpkg_to_use = atoi(as->parms[P_PACKAGE].items->data);
3917 switch (wpkg_to_use) {
3918 case GATOR_WIN_CURSES:
3919 fprintf(stderr, "curses\n");
3921 case GATOR_WIN_DUMB:
3922 fprintf(stderr, "dumb terminal\n");
3925 fprintf(stderr, "X11\n");
3928 fprintf(stderr, "Illegal graphics package: %d\n", wpkg_to_use);
3930 } /*end switch (wpkg_to_use) */
3933 wpkg_to_use = GATOR_WIN_CURSES;
3935 /* get probe frequency . We check for meaningful bounds on the frequency
3936 * and reset to the default value if needed. The upper bound of 24
3937 * hours looks ridiculous though! */
3939 afsmon_probefreq = 0;
3940 if (as->parms[P_FREQUENCY].items != 0)
3941 afsmon_probefreq = atoi(as->parms[P_FREQUENCY].items->data);
3943 afsmon_probefreq = DEFAULT_FREQUENCY;
3945 if (afsmon_probefreq <= 0 || afsmon_probefreq > 24 * 60 * 60) {
3946 afsmon_probefreq = DEFAULT_FREQUENCY;
3949 "[ %s ] Invalid probe frequency %s specified, resetting to default value %d seconds\n",
3950 rn, as->parms[P_FREQUENCY].items->data, afsmon_probefreq);
3954 "Invalid probe frequency %s specified, resetting to default value %d seconds\n",
3955 as->parms[P_FREQUENCY].items->data, afsmon_probefreq);
3960 /* make sure output file is writable, else complain now */
3961 /* we will open and close it as needed after probes */
3963 if (as->parms[P_OUTPUT].items != 0) {
3964 afsmon_output = 1; /* output flag */
3965 strncpy(output_filename, as->parms[P_OUTPUT].items->data, 80);
3966 outputFD = fopen(output_filename, "a");
3967 if (outputFD == (FILE *) 0) {
3968 fprintf(stderr, "Failed to open output file %s \n",
3971 fprintf(debugFD, "[ %s ] Failed to open output file %s \n",
3972 rn, output_filename);
3977 fprintf(debugFD, "[ %s ] output file is %s\n", rn,
3983 /* detailed statistics to storage file */
3984 if (as->parms[P_DETAILED].items != 0) {
3985 if (as->parms[P_OUTPUT].items == 0) {
3987 "-detailed switch can be used only with -output\n");
3990 afsmon_detOutput = 1;
3993 /* Initialize host list headers */
3994 FSnameList = (struct afsmon_hostEntry *)0;
3995 CMnameList = (struct afsmon_hostEntry *)0;
3997 /* The -config option is mutually exclusive with the -fshosts,-cmhosts
4000 if (as->parms[P_CONFIG].items) {
4001 if (as->parms[P_FSHOSTS].items || as->parms[P_CMHOSTS].items) {
4003 "Cannot use -config option with -fshosts or -cmhosts\n");
4007 if (!as->parms[P_FSHOSTS].items && !as->parms[P_CMHOSTS].items) {
4009 "Must specify either -config or (-fshosts and/or -cmhosts) options \n");
4015 /* If a file server host is specified on the command line we reuse
4016 * parse_hostEntry() function . Just the pass the info as if it were
4017 * read off the config file */
4019 if (as->parms[P_FSHOSTS].items) {
4020 hostPtr = as->parms[P_FSHOSTS].items;
4021 while (hostPtr != (struct cmd_item *)0) {
4022 sprintf(buf, "fs %s", hostPtr->data);
4023 code = parse_hostEntry(buf);
4025 fprintf(stderr, "Could not parse %s\n", hostPtr->data);
4029 hostPtr = hostPtr->next;
4033 /* same as above for -cmhosts */
4034 if (as->parms[P_CMHOSTS].items) {
4035 hostPtr = as->parms[P_CMHOSTS].items;
4036 while (hostPtr != (struct cmd_item *)0) {
4037 sprintf(buf, "cm %s", hostPtr->data);
4038 code = parse_hostEntry(buf);
4040 fprintf(stderr, "Could not parse %s\n", hostPtr->data);
4044 hostPtr = hostPtr->next;
4048 /* number of slots in circular buffers */
4049 if (as->parms[P_BUFFERS].items)
4050 num_bufSlots = atoi(as->parms[P_BUFFERS].items->data);
4052 num_bufSlots = DEFAULT_BUFSLOTS;
4054 /* Initialize xx_showFlags[]. This array is used solely for processing the
4055 * "show" directives in the config file in parse_showEntries() */
4056 for (i = 0; i < NUM_FS_STAT_ENTRIES; i++)
4057 fs_showFlags[i] = 0;
4058 for (i = 0; i < NUM_CM_STAT_ENTRIES; i++)
4059 cm_showFlags[i] = 0;
4062 /* Process the configuration file if given. This initializes among other
4063 * things, the list of FS & CM names in FSnameList and CMnameList */
4065 if (as->parms[P_CONFIG].items)
4066 process_config_file(as->parms[P_CONFIG].items->data);
4068 /* print out the FS and CM lists */
4072 /* Initialize the FS results-to-screen map array if there were no "show fs"
4073 * directives in the config file */
4074 if (fs_showDefault) {
4075 for (i = 0; i < NUM_FS_STAT_ENTRIES; i++)
4076 fs_Display_map[i] = i;
4077 fs_DisplayItems_count = NUM_FS_STAT_ENTRIES;
4080 /* Initialize the CM results-to-screen map array if there were no "show cm"
4081 * directives in the config file */
4082 if (cm_showDefault) {
4083 for (i = 0; i < NUM_CM_STAT_ENTRIES; i++)
4084 cm_Display_map[i] = i;
4085 cm_DisplayItems_count = NUM_CM_STAT_ENTRIES;
4090 /* setup an interrupt signal handler; we ain't wanna leak core */
4091 /* this binding is useful only until gtx is initialized after which the
4092 * keyboard input server takes over. */
4093 if ((signal(SIGINT, quit_signal)) == SIG_ERR) {
4094 perror("signal() failed.");
4099 /* init error message buffers. these will be used to print error messages
4100 * once gtx is initialized and there is no access to stderr/stdout */
4106 /* initialize fs and cm circular buffers before initiating probes */
4108 code = init_fs_buffers();
4110 fprintf(stderr, "[ %s ] init_fs_buffers returned %d\n", rn,
4117 code = init_cm_buffers();
4119 fprintf(stderr, "[ %s ] init_cm_buffers returned %d\n", rn,
4126 /* allocate and initialize buffers for holding fs & cm results in ascii
4127 * format suitable for updating the screen */
4128 code = init_print_buffers();
4130 fprintf(stderr, "[ %s ] init_print_buffers returned %d\n", rn, code);
4134 /* perform gtx initializations */
4135 code = gtx_initialize();
4137 fprintf(stderr, "[ %s ] gtx_initialize returned %d\n", rn, code);
4141 /* start xstat probes */
4144 return (0); /* will not return from the call to afsmon_execute() */
4146 } /* afsmonInit() */
4149 /*-----------------------------------------------------------------------
4151 ------------------------------------------------------------------------*/
4153 #include "AFS_component_version_number.c"
4161 static char rn[] = "main"; /* routine name */
4162 afs_int32 code; /*Return code */
4163 struct cmd_syndesc *ts; /*Ptr to cmd line syntax descriptor */
4165 #ifdef AFS_AIX32_ENV
4167 * The following signal action for AIX is necessary so that in case of a
4168 * crash (i.e. core is generated) we can include the user's data section
4169 * in the core dump. Unfortunately, by default, only a partial core is
4170 * generated which, in many cases, isn't too useful.
4172 struct sigaction nsa;
4174 sigemptyset(&nsa.sa_mask);
4175 nsa.sa_handler = SIG_DFL;
4176 nsa.sa_flags = SA_FULLDUMP;
4177 sigaction(SIGSEGV, &nsa, NULL);
4181 * Set up the commands we understand.
4183 ts = cmd_CreateSyntax("initcmd", afsmonInit, 0, "initialize the program");
4184 cmd_AddParm(ts, "-config", CMD_SINGLE, CMD_OPTIONAL,
4185 "configuration file");
4186 cmd_AddParm(ts, "-frequency", CMD_SINGLE, CMD_OPTIONAL,
4187 "poll frequency, in seconds");
4188 cmd_AddParm(ts, "-output", CMD_SINGLE, CMD_OPTIONAL, "storage file name");
4189 cmd_AddParm(ts, "-detailed", CMD_FLAG, CMD_OPTIONAL,
4190 "output detailed statistics to storage file");
4192 /* we hope to use this .... eventually! */
4193 cmd_AddParm(ts, "-package", CMD_SINGLE, CMD_REQUIRED,
4194 "Graphics Package to use");
4196 cmd_AddParm(ts, "-debug", CMD_SINGLE, CMD_OPTIONAL,
4197 "turn debugging output on to the named file");
4198 cmd_AddParm(ts, "-fshosts", CMD_LIST, CMD_OPTIONAL,
4199 "list of file servers to monitor");
4200 cmd_AddParm(ts, "-cmhosts", CMD_LIST, CMD_OPTIONAL,
4201 "list of cache managers to monitor");
4202 cmd_AddParm(ts, "-buffers", CMD_SINGLE, CMD_OPTIONAL,
4203 "number of buffer slots");
4206 * Parse command-line switches & execute afsmonitor
4209 code = cmd_Dispatch(argc, argv);
4215 exit(0); /* redundant, but gets rid of warning */