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
9 * Portions Copyright (c) 2003 Apple Computer, Inc.
13 * Afsmonitor: An AFS Performance Monitoring Tool
15 *-------------------------------------------------------------------------*/
18 #include <afsconfig.h>
19 #include <afs/param.h>
29 #include <sys/types.h>
30 #include <netinet/in.h>
31 #include <sys/socket.h>
38 #include <afs/gtxwindows.h> /*Generic window package */
39 #include <afs/gtxobjects.h> /*Object definitions */
40 #include <afs/gtxlightobj.h> /*Light object interface */
41 #include <afs/gtxcurseswin.h> /*Curses window package */
42 #include <afs/gtxdumbwin.h> /*Dumb terminal window package */
43 #include <afs/gtxX11win.h> /*X11 window package */
44 #include <afs/gtxframe.h> /*Frame package */
45 #include <afs/gtxinput.h>
47 #include <afs/xstat_fs.h>
48 #include <afs/xstat_cm.h>
50 #include "afsmonitor.h"
52 /* command line parameter indices */
58 /* #define P_PACKAGE X */
65 int afsmon_debug = 0; /* debug info to file ? */
66 FILE *debugFD; /* debugging file descriptor */
67 static int afsmon_output = 0; /* output to file ? */
68 static int afsmon_detOutput = 0; /* detailed output ? */
69 static int afsmon_onceOnly = 0; /* probe once only ? (not implemented) */
70 int afsmon_probefreq; /* probe frequency */
71 static int wpkg_to_use; /* graphics package to use */
72 static char output_filename[80]; /* output filename */
73 char errMsg[256]; /* buffers used to print error messages after */
74 char errMsg1[256]; /* gtx is initialized (stderr/stdout gone !) */
75 int num_bufSlots = 0; /* number of slots in fs & cm circular buffers */
77 /* Flags used to process "show" directives in config file */
78 short fs_showFlags[NUM_FS_STAT_ENTRIES];
79 short cm_showFlags[NUM_CM_STAT_ENTRIES];
82 /* afsmonitor misc definitions */
84 #define DEFAULT_FREQUENCY 60 /* default proble frequency in seconds */
85 #define DEFAULT_BUFSLOTS 0 /* default number of buffer slots */
86 #define CFG_STR_LEN 80 /* max length of config file fields */
87 #define FS 1 /* for misc. use */
88 #define CM 2 /* for misc. use */
91 #define NUM_XSTAT_FS_AFS_PERFSTATS_LONGS 70 /* number of fields from struct afs_PerfStats that we display */
92 #define NUM_AFS_STATS_CMPERF_LONGS 40 /* number of longs in struct afs_stats_CMPerf excluding up/down stats and fields we dont display */
95 /* variables used for exec'ing user provided threshold handlers */
96 char *fsHandler_argv[20]; /* *argv[] for the handler */
97 char fsHandler_args[20][256]; /* buffer space for arguments */
98 int exec_fsThreshHandler = 0; /* execute fs threshold handler ? */
101 /* THRESHOLD STRUCTURE DEFINITIONS */
103 /* flag to indicate that threshold entries apply to all hosts. these will
104 be turned off when the first fs or cm host entry is processed */
105 static int global_ThreshFlag = 1;
106 static int global_fsThreshCount = 0; /* number of global fs thresholds */
107 static int global_cmThreshCount = 0; /* number of global cm thresholds */
111 /* Linked lists of file server and cache manager host names are made from
112 the entries in the config file. Head pointers to FS and CM server name lists. */
113 static struct afsmon_hostEntry *FSnameList;
114 static struct afsmon_hostEntry *CMnameList;
116 /* number of fileservers and cache managers to monitor */
120 /* number of xstat collection ids */
121 #define MAX_NUM_FS_COLLECTIONS 2
122 #define MAX_NUM_CM_COLLECTIONS 1
123 int num_fs_collections = 0;
124 int num_cm_collections = 0;
126 /* variables used for processing config file */
127 /* ptr to the hostEntry structure of the last "fs" or "cm" entry processed
128 in the config file */
129 static struct afsmon_hostEntry *last_hostEntry;
130 /* names of the last host processed in the config file */
131 static char last_fsHost[HOST_NAME_LEN];
132 static char last_cmHost[HOST_NAME_LEN];
133 static int lastHostType = 0; /* 0 = no host entries processed
134 * 1 = last host was file server
135 * 2 = last host was cache manager. */
138 /* FILE SERVER CIRCULAR BUFFER VARIABLES */
140 struct afsmon_fs_Results_list {
141 struct xstat_fs_ProbeResults *fsResults[MAX_NUM_FS_COLLECTIONS];
142 int empty[MAX_NUM_FS_COLLECTIONS];
143 struct afsmon_fs_Results_list *next;
146 struct afsmon_fs_Results_CBuffer {
147 int probeNum; /* probe number of entries in this slot */
148 struct afsmon_fs_Results_list *list; /* ptr to list of results */
151 int afsmon_fs_results_length[] =
152 { XSTAT_FS_FULLPERF_RESULTS_LEN, XSTAT_FS_CBSTATS_RESULTS_LEN };
154 /* buffer for FS probe results */
155 struct afsmon_fs_Results_CBuffer *afsmon_fs_ResultsCB;
157 int afsmon_fs_curr_CBindex = 0; /* current fs CB slot */
159 /* Probe number variables. The current probe number is incremented
160 when the first probe from a new probe cycle is received. The prev probe
161 number is incremented when the last probe of the current cycle is
162 received. This difference is because of the purpose for which these
165 int afsmon_fs_curr_probeNum = 1; /* current fs probe number */
166 int afsmon_fs_prev_probeNum = 0; /* previous fs probe number */
169 /* CACHE MANAGER CIRCULAR BUFFER VARIABLES */
171 struct afsmon_cm_Results_list {
172 struct xstat_cm_ProbeResults *cmResults[MAX_NUM_CM_COLLECTIONS];
173 int empty[MAX_NUM_CM_COLLECTIONS];
174 struct afsmon_cm_Results_list *next;
177 struct afsmon_cm_Results_CBuffer {
178 int probeNum; /* probe number of entries in this slot */
179 struct afsmon_cm_Results_list *list; /* ptr to list of results */
182 int afsmon_cm_results_length[] = { XSTAT_CM_FULLPERF_RESULTS_LEN };
184 /* buffer for CM probe results */
185 struct afsmon_cm_Results_CBuffer *afsmon_cm_ResultsCB;
187 int afsmon_cm_curr_CBindex = 0; /* current cm CB slot */
190 /* Probe number variables. The current probe number is incremented
191 when the first probe from a new probe cycle is received. The prev probe
192 number is incremented when the last probe of the current cycle is
193 received. This difference is because of the purpose for which these
196 int afsmon_cm_curr_probeNum = 1; /* current cm probe number */
197 int afsmon_cm_prev_probeNum = 0; /* previous cm probe number */
200 /* Structures to hold FS & CM results in string format(suitable for display ) */
202 /* ptr to array holding the results of FS probes in ascii format */
203 /* for current probe cycle */
204 struct fs_Display_Data *curr_fsData = (struct fs_Display_Data *)0;
205 /* for previous probe cycle */
206 struct fs_Display_Data *prev_fsData = (struct fs_Display_Data *)0;
209 /* ptr to array holding the results of CM probes in ascii format */
210 /* for current probe cycle */
211 struct cm_Display_Data *curr_cmData = (struct cm_Display_Data *)0;
212 /* for previous probe cycle */
213 struct cm_Display_Data *prev_cmData = (struct cm_Display_Data *)0;
215 /* EXTERN DEFINITIONS */
217 /* file server and cache manager variable names (from afsmon_labels.h) */
218 extern char *fs_varNames[];
219 extern char *cm_varNames[];
221 /* GTX & MISC VARIABLES */
223 /* afsmonitor window */
224 extern struct gwin *afsmon_win;
226 /* current page number in the overview frame */
227 extern int ovw_currPage;
229 /* number of FS alerts and number of hosts on FS alerts */
231 int numHosts_onfs_alerts;
233 /* number of CM alerts and number of hosts on FS alerts */
235 int numHosts_oncm_alerts;
237 /* flag to indicate that atleast one probe cycle has completed and
238 data is available for updating the display */
239 extern int fs_Data_Available;
240 extern int cm_Data_Available;
242 extern int gtx_initialized; /* gtx initialized ? */
244 /* This array contains the indices of the file server data items that
245 are to be displayed on the File Servers screen. For example, suppose the
246 user wishes to display only the vcache statistics then the following array
247 will contain indices 2 to 14 corresponding to the position of the
248 vcache data items in the fs_varNames[] array. If the config file contains
249 no "show fs .." directives, it will contain the indices of all the
250 items in the fs_varNames[] array */
252 short fs_Display_map[NUM_FS_STAT_ENTRIES];
253 int fs_DisplayItems_count = 0; /* number of items to display */
254 int fs_showDefault = 1; /* show all of FS data ? */
257 /* same use as above for Cache Managers */
258 short cm_Display_map[NUM_CM_STAT_ENTRIES];
259 int cm_DisplayItems_count = 0; /* number of items to display */
260 int cm_showDefault = 1; /* show all of CM data ? */
262 extern int fs_currPage; /* current page number in the File Servers frame */
263 extern int fs_curr_LCol; /* current leftmost column on display on FS frame */
265 extern int cm_currPage; /* current page number in the Cache Managers frame */
266 extern int cm_curr_LCol; /* current leftmost column on display on CM frame */
268 /* File server and Cache manager data is classified into sections &
269 groups to help the user choose what he wants displayed */
270 extern char *fs_categories[]; /* file server data category names */
271 extern char *cm_categories[]; /* cache manager data category names */
274 static int fs_FullPerfs_ltoa(struct fs_Display_Data *a_fsData,
275 struct xstat_fs_ProbeResults *a_fsResults);
276 static int fs_CallBackStats_ltoa(struct fs_Display_Data *a_fsData,
277 struct xstat_fs_ProbeResults *a_fsResults);
279 #ifdef HAVE_STRCASESTR
280 extern char * strcasestr(const char *, const char *);
283 strcasestr(): Return first occurence of pattern s2 in s1, case
286 This routine is required since I made pattern matching of the
287 config file to be case insensitive.
302 return ((char *)NULL);
306 while (len1 >= len2 && len1 > 0) {
307 if ((strncasecmp(ptr, s2, len2)) == 0)
312 return ((char *)NULL);
317 GetHostByName(char *name)
324 he = gethostbyname(name);
326 /* On solaris the above does not resolve hostnames to full names */
328 memcpy(ip_addr, he->h_addr, he->h_length);
329 he = gethostbyaddr(ip_addr, he->h_length, he->h_addrtype);
336 /*-----------------------------------------------------------------------
340 * Exit gracefully from the afsmonitor. Frees memory where appropriate,
341 * cleans up after gtx and closes all open file descriptors. If a user
342 * provided threshold handler is to be exec'ed then gtx cleanup is
343 * not performed and an exec() is made instead of an exit().
349 * This function is called to execute a user handler only
350 * by a child process.
352 *----------------------------------------------------------------------*/
355 afsmon_Exit(int a_exitVal) /* exit code */
357 static char rn[] = "afsmon_Exit";
358 struct afsmon_fs_Results_list *tmp_fslist;
359 struct afsmon_fs_Results_list *next_fslist;
360 struct xstat_fs_ProbeResults *tmp_xstat_fsPR;
361 struct afsmon_cm_Results_list *tmp_cmlist;
362 struct afsmon_cm_Results_list *next_cmlist;
363 struct xstat_cm_ProbeResults *tmp_xstat_cmPR;
364 struct afsmon_hostEntry *curr_hostEntry;
365 struct afsmon_hostEntry *next_hostEntry;
372 fprintf(debugFD, "[ %s ] Called with exit code %d\n", rn, a_exitVal);
376 /* get out of curses first, but not if we are here to exec a threshold
377 * handler. If we do, the screen gets messed up */
378 if (gtx_initialized && !exec_fsThreshHandler)
379 gator_cursesgwin_cleanup(afsmon_win);
381 /* print the error message buffer */
382 if (errMsg[0] != '\0')
383 fprintf(stderr, "%s", errMsg);
384 if (errMsg1[0] != '\0')
385 fprintf(stderr, "%s", errMsg1);
387 /* deallocate file server circular buffers */
388 if (numFS && num_bufSlots) {
390 fprintf(debugFD, "freeing FS circular buffers ");
394 for (bufslot = 0; bufslot < num_bufSlots; bufslot++) {
396 fprintf(debugFD, " %d) ", bufslot);
397 if (afsmon_fs_ResultsCB[bufslot].list !=
398 (struct afsmon_fs_Results_list *)0) {
399 tmp_fslist = afsmon_fs_ResultsCB[bufslot].list;
402 /* make sure we do not go astray */
406 "[ %s ] error in deallocating fs CB\n",
410 next_fslist = tmp_fslist->next;
411 for (i = 0; i < MAX_NUM_FS_COLLECTIONS; i++) {
412 tmp_xstat_fsPR = tmp_fslist->fsResults[i];
415 fprintf(debugFD, "%d ", numFS - j);
417 /* free xstat_fs_Results data */
418 free(tmp_xstat_fsPR->data.AFS_CollData_val);
419 free(tmp_xstat_fsPR->connP);
420 free(tmp_xstat_fsPR);
423 /* free the fs list item */
425 tmp_fslist = next_fslist;
427 } /* while fs list items in this slot */
428 } /* if entries in this buffer slot */
429 } /* for each fs buffer slot */
431 fprintf(debugFD, "\n");
436 /* deallocate cache manager curcular buffers */
437 if (numCM && num_bufSlots) {
439 fprintf(debugFD, "freeing CM curcular buffers ");
440 for (bufslot = 0; bufslot < num_bufSlots; bufslot++) {
442 fprintf(debugFD, " %d) ", bufslot);
443 if (afsmon_cm_ResultsCB[bufslot].list !=
444 (struct afsmon_cm_Results_list *)0) {
445 tmp_cmlist = afsmon_cm_ResultsCB[bufslot].list;
448 /* make sure we do not go astray */
452 "[ %s ] error in deallocating cm CB\n",
456 next_cmlist = tmp_cmlist->next;
457 for (i = 0; i < MAX_NUM_CM_COLLECTIONS; i++) {
458 tmp_xstat_cmPR = tmp_cmlist->cmResults[i];
461 fprintf(debugFD, "%d ", numCM - j);
462 /* make sure data is ok */
463 /* Print_cm_FullPerfInfo(tmp_xstat_cmPR); */
465 /* free xstat_cm_Results data */
466 free(tmp_xstat_cmPR->data.AFSCB_CollData_val);
467 free(tmp_xstat_cmPR->connP);
469 free(tmp_cmlist->cmResults);
471 /* free the cm list item */
473 tmp_cmlist = next_cmlist;
475 } /* while cm list items in this slot */
476 } /* if entries in this buffer slot */
477 } /* for each cm buffer slot */
479 fprintf(debugFD, "\n");
483 /* deallocate FS & CM Print buffers */
484 if (curr_fsData != (struct fs_Display_Data *)0) {
486 fprintf(debugFD, "Deallocating FS Print Buffers .... curr");
489 if (prev_fsData != (struct fs_Display_Data *)0) {
491 fprintf(debugFD, ", prev \n");
494 if (prev_cmData != (struct cm_Display_Data *)0) {
496 fprintf(debugFD, "Deallocating CM Print Buffers .... curr");
499 if (prev_cmData != (struct cm_Display_Data *)0) {
501 fprintf(debugFD, ", prev \n");
505 /* deallocate hostEntry lists */
508 fprintf(debugFD, "Deallocating FS hostEntries ..");
509 curr_hostEntry = FSnameList;
510 while (curr_hostEntry) {
511 next_hostEntry = curr_hostEntry->next;
512 if (curr_hostEntry->thresh != NULL)
513 free(curr_hostEntry->thresh);
514 free(curr_hostEntry);
515 curr_hostEntry = next_hostEntry;
518 fprintf(debugFD, "\n");
522 fprintf(debugFD, "Deallocating CM hostEntries ..");
523 curr_hostEntry = CMnameList;
524 while (curr_hostEntry) {
525 next_hostEntry = curr_hostEntry->next;
526 if (curr_hostEntry->thresh != NULL)
527 free(curr_hostEntry->thresh);
528 free(curr_hostEntry);
529 curr_hostEntry = next_hostEntry;
532 fprintf(debugFD, "\n");
535 /* close debug file */
541 if (exec_fsThreshHandler) {
542 code = execvp(fsHandler_argv[0], fsHandler_argv);
544 fprintf(stderr, "execvp() of %s returned %d, errno %d\n",
545 fsHandler_argv[0], code, errno);
553 /*-----------------------------------------------------------------------
557 * Insert a hostname in the file server names list.
562 *----------------------------------------------------------------------*/
565 insert_FS(char *a_hostName) /* name of cache manager to be inserted in list */
567 static struct afsmon_hostEntry *curr_item;
568 static struct afsmon_hostEntry *prev_item;
570 if (*a_hostName == '\0')
572 curr_item = (struct afsmon_hostEntry *)
573 malloc(sizeof(struct afsmon_hostEntry));
574 if (curr_item == (struct afsmon_hostEntry *)0) {
575 fprintf(stderr, "Failed to allocate space for FS nameList\n");
579 strncpy(curr_item->hostName, a_hostName, CFG_STR_LEN);
580 curr_item->next = (struct afsmon_hostEntry *)0;
581 curr_item->numThresh = 0;
582 curr_item->thresh = NULL;
584 if (FSnameList == (struct afsmon_hostEntry *)0)
585 FSnameList = curr_item;
587 prev_item->next = curr_item;
589 prev_item = curr_item;
590 /* record the address of this entry so that its threshold
591 * count can be incremented during the first pass of the config file */
592 last_hostEntry = curr_item;
597 /*-----------------------------------------------------------------------
602 * Prints the file server names linked list.
606 *----------------------------------------------------------------------*/
610 static char rn[] = "print_FS";
611 struct afsmon_hostEntry *tempFS;
612 struct Threshold *threshP;
616 fprintf(debugFD, "[ %s ] Called\n", rn);
622 fprintf(debugFD, "No of File Servers: %d\n", numFS);
625 fprintf(debugFD, "\t %s threshCount = %d\n", tempFS->hostName,
627 threshP = tempFS->thresh;
628 for (i = 0; i < tempFS->numThresh; i++, threshP++)
629 fprintf(debugFD, "\t thresh (%2d) %s %s %s\n",
630 threshP->index, threshP->itemName,
631 threshP->threshVal, threshP->handler);
632 } while ((tempFS = tempFS->next) != (struct afsmon_hostEntry *)0);
634 fprintf(debugFD, "\t\t-----End of List-----\n");
640 /*-----------------------------------------------------------------------
644 * Insert a hostname in the cache manager names list.
649 *----------------------------------------------------------------------*/
652 insert_CM(char *a_hostName) /* name of cache manager to be inserted in list */
654 static struct afsmon_hostEntry *curr_item;
655 static struct afsmon_hostEntry *prev_item;
657 if (*a_hostName == '\0')
659 curr_item = (struct afsmon_hostEntry *)
660 malloc(sizeof(struct afsmon_hostEntry));
661 if (curr_item == (struct afsmon_hostEntry *)0) {
662 fprintf(stderr, "Failed to allocate space for CM nameList\n");
666 strncpy(curr_item->hostName, a_hostName, CFG_STR_LEN);
667 curr_item->next = (struct afsmon_hostEntry *)0;
668 curr_item->numThresh = 0;
669 curr_item->thresh = NULL;
671 if (CMnameList == (struct afsmon_hostEntry *)0)
672 CMnameList = curr_item;
674 prev_item->next = curr_item;
676 prev_item = curr_item;
677 /* side effect. note the address of this entry so that its threshold
678 * count can be incremented during the first pass of the config file */
679 last_hostEntry = curr_item;
685 /*-----------------------------------------------------------------------
690 * Prints the cache manager names linked list.
694 *----------------------------------------------------------------------*/
698 static char rn[] = "print_CM";
699 struct afsmon_hostEntry *tempCM;
700 struct Threshold *threshP;
704 fprintf(debugFD, "[ %s ] Called\n", rn);
710 fprintf(debugFD, "No of Cache Managers: %d\n", numCM);
713 fprintf(debugFD, "\t %s threshCount = %d\n", tempCM->hostName,
715 threshP = tempCM->thresh;
716 for (i = 0; i < tempCM->numThresh; i++, threshP++)
717 fprintf(debugFD, "\t thresh (%2d) %s %s %s\n",
718 threshP->index, threshP->itemName,
719 threshP->threshVal, threshP->handler);
720 } while ((tempCM = tempCM->next) != (struct afsmon_hostEntry *)0);
722 fprintf(debugFD, "\t\t-----End of List-----\n");
729 /*-----------------------------------------------------------------------
733 * Parse the host entry line in the config file. Check the syntax,
734 * and inserts the host name in the FS ot CM linked list. Also
735 * remember if this entry was an fs or cm & the ptr to its hostEntry
736 * structure. The threshold entries in the config file are dependent
737 * on their position relative to the hostname entries. Hence it is
738 * required to remember the names of the last file server and cache
739 * manager entries that were processed.
745 *----------------------------------------------------------------------*/
748 parse_hostEntry(char *a_line)
749 { /* parse_hostEntry */
751 static char rn[] = "parse_hostEntry"; /* routine name */
752 char opcode[CFG_STR_LEN]; /* specifies type of config entry */
753 char arg1[CFG_STR_LEN]; /* hostname or qualifier (fs/cm?) */
754 char arg2[CFG_STR_LEN]; /* threshold variable */
755 char arg3[CFG_STR_LEN]; /* threshold value */
756 char arg4[CFG_STR_LEN]; /* user's handler */
757 struct hostent *he; /* host entry */
760 fprintf(debugFD, "[ %s ] Called, a_line = %s\n", rn, a_line);
770 sscanf(a_line, "%s %s %s %s %s", opcode, arg1, arg2, arg3, arg4);
771 /* syntax is "opcode hostname" */
772 if ((strlen(arg2)) != 0) {
773 fprintf(stderr, "[ %s ] Extraneous characters at end of line\n", rn);
778 he = GetHostByName(arg1);
780 fprintf(stderr, "[ %s ] Unable to resolve hostname %s\n", rn, arg1);
784 if ((strcasecmp(opcode, "fs")) == 0) {
785 /* use the complete host name to insert in the file server names list */
786 insert_FS(he->h_name);
787 /* note that last host entry in the config file was fs */
790 /* threholds are not global anymore */
791 if (global_ThreshFlag)
792 global_ThreshFlag = 0;
793 } else if ((strcasecmp(opcode, "cm")) == 0) {
794 /* use the complete host name to insert in the CM names list */
795 insert_CM(he->h_name);
796 /* last host entry in the config file was cm */
799 /* threholds are not global anymore */
800 if (global_ThreshFlag)
801 global_ThreshFlag = 0;
808 /*-----------------------------------------------------------------------
809 * parse_threshEntry()
812 * Parse the threshold entry line in the config file. This function is
813 * called in the the first pass of the config file. It checks the syntax
814 * of the config lines and verifies their positional validity - eg.,
815 * a cm threshold cannot appear after a fs hostname entry, etc.
816 * It also counts the thresholds applicable to each host.
822 *----------------------------------------------------------------------*/
825 parse_threshEntry(char *a_line)
826 { /* parse_threshEntry */
827 static char rn[] = "parse_threshEntry"; /* routine name */
828 char opcode[CFG_STR_LEN]; /* specifies type of config entry */
829 char arg1[CFG_STR_LEN]; /* hostname or qualifier (fs/cm?) */
830 char arg2[CFG_STR_LEN]; /* threshold variable */
831 char arg3[CFG_STR_LEN]; /* threshold value */
832 char arg4[CFG_STR_LEN]; /* user's handler */
833 char arg5[CFG_STR_LEN]; /* junk characters */
836 fprintf(debugFD, "[ %s ] Called, a_line = %s\n", rn, a_line);
847 sscanf(a_line, "%s %s %s %s %s %s", opcode, arg1, arg2, arg3, arg4, arg5);
849 /* syntax is "thresh fs/cm variable_name threshold_value [handler] " */
850 if (((strlen(arg1)) == 0) || ((strlen(arg2)) == 0)
851 || ((strlen(arg3)) == 0)) {
852 fprintf(stderr, "[ %s ] Incomplete line\n", rn);
855 if (strlen(arg3) > THRESH_VAR_LEN - 2) {
856 fprintf(stderr, "[%s ] threshold value too long\n", rn);
860 if ((strcasecmp(arg1, "fs")) == 0) {
861 switch (lastHostType) {
862 case 0: /* its a global threshold */
863 global_fsThreshCount++;
865 case 1: /* inc thresh count of last file server */
866 last_hostEntry->numThresh++;
870 "[ %s ] A threshold for a File Server cannot be placed after a Cache Manager host entry in the config file \n",
874 fprintf(stderr, "[ %s ] Programming error 1\n", rn);
877 } else if ((strcasecmp(arg1, "cm")) == 0) {
878 switch (lastHostType) {
879 case 0: /* its a global threshold */
880 global_cmThreshCount++;
882 case 2: /* inc thresh count of last cache manager */
883 last_hostEntry->numThresh++;
887 "[ %s ] A threshold for a Cache Manager cannot be placed after a File Server host entry in the config file \n",
891 fprintf(stderr, "[ %s ] Programming error 2\n", rn);
896 "[ %s ] Syntax error. Second argument should be \"fs\" or \"cm\" \n",
902 } /* parse_threshEntry */
905 /*-----------------------------------------------------------------------
909 * The thresholds applicable to each host machine are stored in the
910 * FSnameList and CMnameList. Threshold entries in the config file are
911 * context sensitive. The host to which this threshold is applicable
912 * is pointed to by last_fsHost (for file servers) and last_cmHost
913 * for cache managers. For global thresholds the info is recorded for
914 * all the hosts. This function is called in the second pass of the
915 * config file. In the first pass a count of the number of global
916 * thresholds is determined and this information is used in this
917 * routine. If threshold entries are duplicated the first entry is
919 * Each threshold entry also has an index field. This is a positional
920 * index to the corresponding variable in the prev_[fs/cm]Data arrays.
921 * This makes it easy to check the threshold for overflow.
926 *----------------------------------------------------------------------*/
929 store_threshold(int a_type, /* 1 = fs , 2 = cm */
930 char *a_varName, /* threshold name */
931 char *a_value, /* threshold value */
932 char *a_handler) /* threshold overflow handler */
933 { /* store_thresholds */
935 static char rn[] = "store_thresholds"; /* routine name */
936 struct afsmon_hostEntry *tmp_host; /* tmp ptr to hostEntry */
937 struct afsmon_hostEntry *Header; /* tmp ptr to hostEntry list header */
938 struct Threshold *threshP; /* tmp ptr to threshold list */
940 int index; /* index to fs_varNames or cm_varNames */
943 int srvCount; /* tmp count of host names */
944 int *global_TC; /* ptr to global_xxThreshCount */
949 "[ %s ] Called, a_type= %d, a_varName= %s, a_value= %s, a_handler=%s\n",
950 rn, a_type, a_varName, a_value, a_handler);
954 /* resolve the threshold variable name */
956 if (a_type == 1) { /* fs threshold */
957 for (index = 0; index < NUM_FS_STAT_ENTRIES; index++) {
958 if (strcasecmp(a_varName, fs_varNames[index]) == 0) {
964 fprintf(stderr, "[ %s ] Unknown FS threshold variable name %s\n",
970 hostname = last_fsHost;
971 global_TC = &global_fsThreshCount;
972 } else if (a_type == 2) { /* cm threshold */
973 for (index = 0; index < NUM_CM_STAT_ENTRIES; index++) {
974 if (strcasecmp(a_varName, cm_varNames[index]) == 0) {
980 fprintf(stderr, "[ %s ] Unknown CM threshold variable name %s\n",
986 hostname = last_cmHost;
987 global_TC = &global_cmThreshCount;
993 /* if the global thresh count is not zero, place this threshold on
994 * all the host entries */
998 for (i = 0; i < srvCount; i++) {
999 threshP = tmp_host->thresh;
1001 for (j = 0; j < tmp_host->numThresh; j++) {
1002 if ((threshP->itemName[0] == '\0')
1003 || (strcasecmp(threshP->itemName, a_varName) == 0)) {
1004 strncpy(threshP->itemName, a_varName,
1005 THRESH_VAR_NAME_LEN);
1006 strncpy(threshP->threshVal, a_value, THRESH_VAR_LEN);
1007 strcpy(threshP->handler, a_handler);
1008 threshP->index = index;
1015 fprintf(stderr, "[ %s ] Could not insert threshold entry",
1017 fprintf(stderr, "for %s in thresh list of host %s \n",
1018 a_varName, tmp_host->hostName);
1021 tmp_host = tmp_host->next;
1027 /* it is not a global threshold, insert it in the thresh list of this
1028 * host only. We overwrite the global threshold if it was alread set */
1030 if (*hostname == '\0') {
1031 fprintf(stderr, "[ %s ] Programming error 3\n", rn);
1035 /* get the hostEntry that this threshold belongs to */
1038 for (i = 0; i < srvCount; i++) {
1039 if (strcasecmp(tmp_host->hostName, hostname) == 0) {
1043 tmp_host = tmp_host->next;
1046 fprintf(stderr, "[ %s ] Unable to find host %s in %s hostEntry list",
1047 rn, hostname, (a_type - 1) ? "CM" : "FS");
1051 /* put this entry on the thresh list of this host, overwrite global value
1054 threshP = tmp_host->thresh;
1056 for (i = 0; i < tmp_host->numThresh; i++) {
1057 if ((threshP->itemName[0] == '\0')
1058 || (strcasecmp(threshP->itemName, a_varName) == 0)) {
1059 strncpy(threshP->itemName, a_varName, THRESH_VAR_NAME_LEN);
1060 strncpy(threshP->threshVal, a_value, THRESH_VAR_LEN);
1061 strcpy(threshP->handler, a_handler);
1062 threshP->index = index;
1071 "[ %s ] Unable to insert threshold %s for %s host %s\n", rn,
1072 a_varName, (a_type - 1) ? "CM" : "FS", tmp_host->hostName);
1078 } /* store_thresholds */
1081 /*-----------------------------------------------------------------------
1085 * This function process a "show" entry in the config file. A "show"
1086 * entry specifies what statistics the user wants to see. File
1087 * server and Cache Manager data is divided into sections. Each section
1088 * is made up of one or more groups. If a group name is specified only
1089 * those statistics under that group are shown. If a section name is
1090 * specified all the groups under this section are shown.
1091 * Data as obtained from the xstat probes is considered to be ordered.
1092 * This data is mapped to the screen thru fs_Display_map[] and
1093 * cm_Display_map[]. This routine parses the "show" entry against the
1094 * section/group names in the [fs/cm]_categories[] array. If there is
1095 * no match it tries to match it against a variable name in
1096 * [fs/cm]_varNames[] array. In each case the corresponding indices to
1097 * the data is the [fs/cm]_displayInfo[] is recorded.
1101 * Failure: -1 (invalid entry)
1102 * > -1 (programming error)
1103 *----------------------------------------------------------------------*/
1106 parse_showEntry(char *a_line)
1107 { /* parse_showEntry */
1108 static char rn[] = "parse_showEntry";
1109 char opcode[CFG_STR_LEN]; /* specifies type of config entry */
1110 char arg1[CFG_STR_LEN]; /* show fs or cm entry ? */
1111 char arg2[CFG_STR_LEN]; /* what we gotta show */
1112 char arg3[CFG_STR_LEN]; /* junk */
1113 char catName[CFG_STR_LEN]; /* for category names */
1114 int numGroups; /* number of groups in a section */
1118 int idx = 0; /* index to fs_categories[] */
1124 fprintf(debugFD, "[ %s ] Called, a_line= %s\n", rn, a_line);
1131 sscanf(a_line, "%s %s %s %s", opcode, arg1, arg2, arg3);
1133 if (arg3[0] != '\0') {
1134 fprintf(stderr, "[ %s ] Extraneous characters at end of line\n", rn);
1138 if ((strcasecmp(arg1, "fs") != 0) && (strcasecmp(arg1, "cm") != 0)) {
1140 "[ %s ] Second argument of \"show\" directive should be \"fs\" or \"cm\" \n",
1145 /* Each entry can either be a variable name or a section/group name. Variable
1146 * names are listed in xx_varNames[] and section/group names in xx_categories[].
1147 * The section/group names in xx_categiries[] also give the starting/ending
1148 * indices of the variables belonging to that section/group. These indices
1149 * are stored in order in xx_Display_map[] and displayed to the screen in that
1152 /* To handle duplicate "show" entries we keep track of what what we have
1153 * already marked to show in the xx_showFlags[] */
1155 if (strcasecmp(arg1, "fs") == 0) { /* its a File Server entry */
1157 /* mark that we have to show only what the user wants */
1160 /* if it is a section/group name, find it in the fs_categories[] array */
1163 if (strcasestr(arg2, "_section") != (char *)NULL
1164 || strcasestr(arg2, "_group") != (char *)NULL) {
1166 while (idx < FS_NUM_DATA_CATEGORIES) {
1167 sscanf(fs_categories[idx], "%s %d %d", catName, &fromIdx,
1170 if (strcasecmp(arg2, catName) == 0) {
1176 if (!found) { /* typo in section/group name */
1178 "[ %s ] Could not find section/group name %s\n", rn,
1184 /* if it is a group name, read its start/end indices and fill in the
1185 * fs_Display_map[]. */
1187 if (strcasestr(arg2, "_group") != (char *)NULL) {
1189 if (fromIdx < 0 || toIdx < 0 || fromIdx > NUM_FS_STAT_ENTRIES
1190 || toIdx > NUM_FS_STAT_ENTRIES)
1192 for (j = fromIdx; j <= toIdx; j++) {
1193 if (!fs_showFlags[j]) {
1194 fs_Display_map[fs_DisplayItems_count] = j;
1195 fs_DisplayItems_count++;
1196 fs_showFlags[j] = 1;
1198 if (fs_DisplayItems_count > NUM_FS_STAT_ENTRIES) {
1199 fprintf(stderr, "[ %s ] fs_DisplayItems_count ovf\n", rn);
1204 /* if it is a section name, get the count of number of groups in it and
1205 * for each group fill in the start/end indices in the fs_Display_map[] */
1207 if (strcasestr(arg2, "_section") != (char *)NULL) {
1208 /* fromIdx is actually the number of groups in thi section */
1209 numGroups = fromIdx;
1210 /* for each group in section */
1211 while (idx < FS_NUM_DATA_CATEGORIES && numGroups) {
1212 sscanf(fs_categories[idx], "%s %d %d", catName, &fromIdx,
1215 if (strcasestr(catName, "_group") != NULL) {
1216 if (fromIdx < 0 || toIdx < 0
1217 || fromIdx > NUM_FS_STAT_ENTRIES
1218 || toIdx > NUM_FS_STAT_ENTRIES)
1220 for (j = fromIdx; j <= toIdx; j++) {
1221 if (!fs_showFlags[j]) {
1222 fs_Display_map[fs_DisplayItems_count] = j;
1223 fs_DisplayItems_count++;
1224 fs_showFlags[j] = 1;
1226 if (fs_DisplayItems_count > NUM_FS_STAT_ENTRIES) {
1228 "[ %s ] fs_DisplayItems_count ovf\n", rn);
1233 fprintf(stderr, "[ %s ] Error parsing groups for %s\n",
1239 } /* for each group in section */
1242 } else { /* it is a variable name */
1244 for (i = 0; i < NUM_FS_STAT_ENTRIES; i++) {
1245 if (strcasecmp(arg2, fs_varNames[i]) == 0) {
1246 if (!fs_showFlags[i]) {
1247 fs_Display_map[fs_DisplayItems_count] = i;
1248 fs_DisplayItems_count++;
1249 fs_showFlags[i] = 1;
1251 if (fs_DisplayItems_count >= NUM_FS_STAT_ENTRIES) {
1252 fprintf(stderr, "[ %s ] fs_DisplayItems_count ovf\n",
1259 if (!found) { /* typo in section/group name */
1260 fprintf(stderr, "[ %s ] Could not find variable name %s\n",
1264 } /* its a variable name */
1268 /* it is an fs entry */
1269 if (strcasecmp(arg1, "cm") == 0) { /* its a Cache Manager entry */
1272 /* mark that we have to show only what the user wants */
1275 /* if it is a section/group name, find it in the cm_categories[] array */
1278 if (strcasestr(arg2, "_section") != (char *)NULL
1279 || strcasestr(arg2, "_group") != (char *)NULL) {
1281 while (idx < CM_NUM_DATA_CATEGORIES) {
1282 sscanf(cm_categories[idx], "%s %d %d", catName, &fromIdx,
1285 if (strcasecmp(arg2, catName) == 0) {
1291 if (!found) { /* typo in section/group name */
1293 "[ %s ] Could not find section/group name %s\n", rn,
1299 /* if it is a group name, read its start/end indices and fill in the
1300 * cm_Display_map[]. */
1302 if (strcasestr(arg2, "_group") != (char *)NULL) {
1304 if (fromIdx < 0 || toIdx < 0 || fromIdx > NUM_CM_STAT_ENTRIES
1305 || toIdx > NUM_CM_STAT_ENTRIES)
1307 for (j = fromIdx; j <= toIdx; j++) {
1308 if (!cm_showFlags[j]) {
1309 cm_Display_map[cm_DisplayItems_count] = j;
1310 cm_DisplayItems_count++;
1311 cm_showFlags[j] = 1;
1313 if (cm_DisplayItems_count > NUM_CM_STAT_ENTRIES) {
1314 fprintf(stderr, "[ %s ] cm_DisplayItems_count ovf\n", rn);
1319 /* if it is a section name, get the count of number of groups in it and
1320 * for each group fill in the start/end indices in the cm_Display_map[] */
1322 if (strcasestr(arg2, "_section") != (char *)NULL) {
1323 /* fromIdx is actually the number of groups in thi section */
1324 numGroups = fromIdx;
1325 /* for each group in section */
1326 while (idx < CM_NUM_DATA_CATEGORIES && numGroups) {
1327 sscanf(cm_categories[idx], "%s %d %d", catName, &fromIdx,
1330 if (strcasestr(catName, "_group") != NULL) {
1331 if (fromIdx < 0 || toIdx < 0
1332 || fromIdx > NUM_CM_STAT_ENTRIES
1333 || toIdx > NUM_CM_STAT_ENTRIES)
1335 for (j = fromIdx; j <= toIdx; j++) {
1336 if (!cm_showFlags[j]) {
1337 cm_Display_map[cm_DisplayItems_count] = j;
1338 cm_DisplayItems_count++;
1339 cm_showFlags[j] = 1;
1341 if (cm_DisplayItems_count > NUM_CM_STAT_ENTRIES) {
1343 "[ %s ] cm_DisplayItems_count ovf\n", rn);
1348 fprintf(stderr, "[ %s ] Error parsing groups for %s\n",
1354 } /* for each group in section */
1355 } else { /* it is a variable name */
1357 for (i = 0; i < NUM_CM_STAT_ENTRIES; i++) {
1358 if (strcasecmp(arg2, cm_varNames[i]) == 0) {
1359 if (!cm_showFlags[i]) {
1360 cm_Display_map[cm_DisplayItems_count] = i;
1361 cm_DisplayItems_count++;
1362 cm_showFlags[i] = 1;
1364 if (cm_DisplayItems_count >= NUM_CM_STAT_ENTRIES) {
1365 fprintf(stderr, "[ %s ] cm_DisplayItems_count ovf\n",
1372 if (!found) { /* typo in section/group name */
1373 fprintf(stderr, "[ %s ] Could not find variable name %s\n",
1377 } /* its a variable name */
1380 /* it is an cm entry */
1382 } /* parse_showEntry */
1385 /*-----------------------------------------------------------------------
1386 * process_config_file()
1389 * Parse config file entries in two passes. In the first pass:
1390 * - the syntax of all the entries is checked
1391 * - host names are noted and the FSnamesList and CMnamesList
1393 * - a count of the global thresholds and local thresholds of
1394 * each host are counted.
1395 * - "show" entries are processed.
1396 * In the second pass:
1397 * - thresholds are stored
1401 * Failure: Exits afsmonitor showing error and line.
1402 *----------------------------------------------------------------------*/
1405 process_config_file(char *a_config_filename)
1406 { /* process_config_file() */
1407 static char rn[] = "process_config_file"; /* routine name */
1408 FILE *configFD; /* config file descriptor */
1409 char line[4 * CFG_STR_LEN]; /* a line of config file */
1410 char opcode[CFG_STR_LEN]; /* specifies type of config entry */
1411 char arg1[CFG_STR_LEN]; /* hostname or qualifier (fs/cm?) */
1412 char arg2[CFG_STR_LEN]; /* threshold variable */
1413 char arg3[CFG_STR_LEN]; /* threshold value */
1414 char arg4[CFG_STR_LEN]; /* user's handler */
1415 struct afsmon_hostEntry *curr_host;
1416 struct hostent *he; /* hostentry to resolve host name */
1417 char *handlerPtr; /* ptr to pass theresh handler string */
1418 int code = 0; /* error code */
1419 int linenum = 0; /* config file line number */
1420 int threshCount; /* count of thresholds for each server */
1421 int error_in_config; /* syntax errors in config file ?? */
1426 fprintf(debugFD, "[ %s ] Called, a_config_filename= %s\n", rn,
1431 /* open config file */
1433 configFD = fopen(a_config_filename, "r");
1434 if (configFD == (FILE *) 0) {
1435 fprintf(stderr, "Failed to open config file %s \n",
1438 fprintf(debugFD, "[ %s ] Failed to open config file %s \n", rn,
1445 /* parse config file */
1447 /* We process the config file in two passes. In the first pass we check
1448 * for correct syntax and for valid entries and also keep count of the
1449 * number of servers and thresholds to monitor. This the data strctures
1450 * can be arrays instead of link lists since we would know their sizes. */
1457 error_in_config = 0; /* flag to note if config file has syntax errors */
1459 while ((fgets(line, CFG_STR_LEN, configFD)) != NULL) {
1465 sscanf(line, "%s %s %s %s %s", opcode, arg1, arg2, arg3, arg4);
1467 /* skip blank lines and comment lines */
1468 if ((strlen(opcode) == 0) || line[0] == '#')
1471 if ((strcasecmp(opcode, "fs") == 0)
1472 || (strcasecmp(opcode, "cm")) == 0) {
1473 code = parse_hostEntry(line);
1474 } else if ((strcasecmp(opcode, "thresh")) == 0) {
1475 code = parse_threshEntry(line);
1476 } else if ((strcasecmp(opcode, "show")) == 0) {
1477 code = parse_showEntry(line);
1479 fprintf(stderr, "[ %s ] Unknown opcode %s\n", rn, opcode);
1484 fprintf(stderr, "[ %s ] Error in line:\n %d: %s\n", rn, linenum,
1486 error_in_config = 1;
1490 if (error_in_config)
1494 fprintf(debugFD, "Global FS thresholds count = %d\n",
1495 global_fsThreshCount);
1496 fprintf(debugFD, "Global CM thresholds count = %d\n",
1497 global_cmThreshCount);
1501 /* the threshold count of all hosts in increased by 1 for each global
1502 * threshold. If one of the hosts has a local threshold for the same
1503 * variable it would end up being counted twice. whats a few bytes of memory
1504 * wasted anyway ? */
1506 if (global_fsThreshCount) {
1507 curr_host = FSnameList;
1508 for (i = 0; i < numFS; i++) {
1509 curr_host->numThresh += global_fsThreshCount;
1510 curr_host = curr_host->next;
1513 if (global_cmThreshCount) {
1514 curr_host = CMnameList;
1515 for (i = 0; i < numCM; i++) {
1516 curr_host->numThresh += global_cmThreshCount;
1517 curr_host = curr_host->next;
1522 /* make sure we have something to monitor */
1523 if (numFS == 0 && numCM == 0) {
1525 "\nConfig file must specify atleast one File Server or Cache Manager host to monitor.\n");
1532 fseek(configFD, 0, 0); /* seek to the beginning */
1535 /* allocate memory for threshold lists */
1536 curr_host = FSnameList;
1537 for (i = 0; i < numFS; i++) {
1538 if (curr_host->hostName[0] == '\0') {
1539 fprintf(stderr, "[ %s ] Programming error 4\n", rn);
1542 if (curr_host->numThresh) {
1543 numBytes = curr_host->numThresh * sizeof(struct Threshold);
1544 curr_host->thresh = (struct Threshold *)malloc(numBytes);
1545 if (curr_host->thresh == NULL) {
1546 fprintf(stderr, "[ %s ] Memory Allocation error 1", rn);
1549 memset(curr_host->thresh, 0, numBytes);
1551 curr_host = curr_host->next;;
1554 curr_host = CMnameList;
1555 for (i = 0; i < numCM; i++) {
1556 if (curr_host->hostName[0] == '\0') {
1557 fprintf(stderr, "[ %s ] Programming error 5\n", rn);
1560 if (curr_host->numThresh) {
1561 numBytes = curr_host->numThresh * sizeof(struct Threshold);
1562 curr_host->thresh = (struct Threshold *)malloc(numBytes);
1563 if (curr_host->thresh == NULL) {
1564 fprintf(stderr, "[ %s ] Memory Allocation error 2", rn);
1567 memset(curr_host->thresh, 0, numBytes);
1569 curr_host = curr_host->next;;
1578 last_fsHost[0] = '\0';
1579 last_cmHost[0] = '\0';
1581 while ((fgets(line, CFG_STR_LEN, configFD)) != NULL) {
1587 sscanf(line, "%s %s %s %s %s", opcode, arg1, arg2, arg3, arg4);
1590 /* if we have a host entry, remember the host name */
1591 if (strcasecmp(opcode, "fs") == 0) {
1592 he = GetHostByName(arg1);
1593 strncpy(last_fsHost, he->h_name, HOST_NAME_LEN);
1594 } else if (strcasecmp(opcode, "cm") == 0) {
1595 he = GetHostByName(arg1);
1596 strncpy(last_cmHost, he->h_name, HOST_NAME_LEN);
1597 } else if (strcasecmp(opcode, "thresh") == 0) {
1598 /* if we have a threshold handler it may have arguments
1599 * and the sscanf() above would not get them, so do the
1603 /* now skip over 4 words - this is done by first
1604 * skipping leading blanks then skipping a word */
1605 for (i = 0; i < 4; i++) {
1606 while (isspace(*handlerPtr))
1608 while (!isspace(*handlerPtr))
1611 while (isspace(*handlerPtr))
1613 /* we how have a pointer to the start of the handler
1616 handlerPtr = arg4; /* empty string */
1619 if (strcasecmp(arg1, "fs") == 0)
1620 code = store_threshold(1, /* 1 = fs */
1621 arg2, arg3, handlerPtr);
1623 else if (strcasecmp(arg1, "cm") == 0)
1624 code = store_threshold(2, /* 2 = fs */
1625 arg2, arg3, handlerPtr);
1628 fprintf(stderr, "[ %s ] Programming error 6\n", rn);
1632 fprintf(stderr, "[ %s ] Failed to store threshold\n", rn);
1633 fprintf(stderr, "[ %s ] Error processing line:\n%d: %s", rn,
1645 /*-----------------------------------------------------------------------
1650 * Print the File Server circular buffer.
1654 *----------------------------------------------------------------------*/
1658 { /* Print_FS_CB() */
1660 struct afsmon_fs_Results_list *fslist;
1665 /* print valid info in the fs CB */
1669 "==================== FS Buffer ========================\n");
1670 fprintf(debugFD, "afsmon_fs_curr_CBindex = %d\n",
1671 afsmon_fs_curr_CBindex);
1672 fprintf(debugFD, "afsmon_fs_curr_probeNum = %d\n\n",
1673 afsmon_fs_curr_probeNum);
1675 for (i = 0; i < num_bufSlots; i++) {
1676 fprintf(debugFD, "\t--------- slot %d ----------\n", i);
1677 fslist = afsmon_fs_ResultsCB[i].list;
1680 for (k = 0; k < MAX_NUM_FS_COLLECTIONS; k++) {
1681 if (!(fslist->empty[k])) {
1682 fprintf(debugFD, "\t %d) probeNum = %d host = %s cn = %d",
1684 fslist->fsResults[k]->probeNum,
1685 fslist->fsResults[k]->connP->hostName,
1686 fslist->fsResults[k]->collectionNumber);
1687 if (fslist->fsResults[k]->probeOK)
1688 fprintf(debugFD, " NOTOK\n");
1690 fprintf(debugFD, " OK\n");
1692 fprintf(debugFD, "\t %d) -- empty --\n", j);
1694 fslist = fslist->next;
1697 if (fslist != (struct afsmon_fs_Results_list *)0)
1698 fprintf(debugFD, "dangling last next ptr fs CB\n");
1701 } /* Print_FS_CB() */
1703 /*-----------------------------------------------------------------------
1704 * save_FS_results_inCB()
1707 * Saves the results of the latest FS probe in the fs circular
1708 * buffers. If the current probe cycle is in progress the contents
1709 * of xstat_fs_Results are copied to the end of the list of results
1710 * in the current slot (pointed to by afsmon_fs_curr_CBindex). If
1711 * a new probe cycle has started the next slot in the circular buffer
1712 * is initialized and the results copied. Note that the Rx related
1713 * information available in xstat_fs_Results is not copied.
1717 * Failure: Exits afsmonitor.
1718 *----------------------------------------------------------------------*/
1720 save_FS_results_inCB(int a_newProbeCycle) /* start of a new probe cycle ? */
1721 { /* save_FS_results_inCB() */
1722 static char rn[] = "save_FS_results_inCB"; /* routine name */
1723 struct afsmon_fs_Results_list *tmp_fslist_item; /* temp fs list item */
1724 struct xstat_fs_ProbeResults *tmp_fsPR; /* temp ptr */
1729 fprintf(debugFD, "[ %s ] Called, a_newProbeCycle= %d\n", rn,
1734 switch (xstat_fs_Results.collectionNumber) {
1735 case AFS_XSTATSCOLL_FULL_PERF_INFO:
1738 case AFS_XSTATSCOLL_CBSTATS:
1742 fprintf(stderr, "[ %s ] collection number %d is out of range.\n",
1743 rn, xstat_fs_Results.collectionNumber);
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[index] = 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[index])
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[index]) {
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[index];
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[index] = 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 =
1803 min(xstat_fs_Results.data.AFS_CollData_len,
1804 afsmon_fs_results_length[index]);
1805 memcpy(tmp_fsPR->data.AFS_CollData_val,
1806 xstat_fs_Results.data.AFS_CollData_val,
1807 tmp_fsPR->data.AFS_CollData_len * sizeof(afs_int32));
1810 /* we have a valid results structure so mark the list item used */
1811 tmp_fslist_item->empty[index] = 0;
1813 /* Print the fs circular buffer */
1817 } /* save_FS_results_inCB() */
1820 /*-----------------------------------------------------------------------
1824 * The results of xstat probes are stored in a string format in
1825 * the arrays curr_fsData and prev_fsData. The information stored in
1826 * prev_fsData is copied to the screen.
1827 * This function converts xstat FS results from longs to strings and
1828 * place them in the given buffer (a pointer to an item in curr_fsData).
1829 * When a probe cycle completes, curr_fsData is copied to prev_fsData
1830 * in afsmon_FS_Hnadler().
1834 *----------------------------------------------------------------------*/
1837 fs_Results_ltoa(struct fs_Display_Data *a_fsData, /* target buffer */
1838 struct xstat_fs_ProbeResults *a_fsResults) /* ptr to xstat fs Results */
1839 { /* fs_Results_ltoa */
1841 static char rn[] = "fs_Results_ltoa"; /* routine name */
1844 fprintf(debugFD, "[ %s ] Called, a_fsData= %p, a_fsResults= %p\n", rn,
1845 a_fsData, a_fsResults);
1849 switch (a_fsResults->collectionNumber) {
1850 case AFS_XSTATSCOLL_FULL_PERF_INFO:
1851 fs_FullPerfs_ltoa(a_fsData, a_fsResults);
1853 case AFS_XSTATSCOLL_CBSTATS:
1854 fs_CallBackStats_ltoa(a_fsData, a_fsResults);
1858 fprintf(debugFD, "[ %s ] Unexpected collection id %d\n",
1859 rn, a_fsResults->collectionNumber);
1864 } /* fs_Results_ltoa */
1866 /*-----------------------------------------------------------------------
1867 * fs_FullPerfs_ltoa()
1870 * Convert the full perf xstat collection from int32s to strings.
1874 *----------------------------------------------------------------------*/
1876 fs_FullPerfs_ltoa(struct fs_Display_Data *a_fsData,
1877 struct xstat_fs_ProbeResults *a_fsResults)
1880 struct fs_stats_FullPerfStats *fullPerfP;
1884 afs_int32 numInt32s;
1886 fullPerfP = (struct fs_stats_FullPerfStats *)
1887 (a_fsResults->data.AFS_CollData_val);
1889 /* there are two parts to the xstat FS statistics
1890 * - fullPerfP->overall which give the overall performance statistics, and
1891 * - fullPerfP->det which gives detailed info about file server operation
1892 * execution times */
1895 * Unfortunately, the full perf stats contain timeval structures which
1896 * do not have the same size everywhere. Avoid displaying gargbage,
1897 * but at least try to show the overall stats.
1899 numInt32s = a_fsResults->data.AFS_CollData_len;
1901 (sizeof(struct fs_stats_FullPerfStats) / sizeof(afs_int32))) {
1902 srcbuf = a_fsResults->data.AFS_CollData_val;
1903 for (i = 0; i < NUM_FS_STAT_ENTRIES; i++) {
1904 if (i < numInt32s && i < NUM_XSTAT_FS_AFS_PERFSTATS_LONGS) {
1905 sprintf(a_fsData->data[i], "%d", srcbuf[i]);
1907 sprintf(a_fsData->data[i], "%s", "--");
1913 /* copy overall performance statistics */
1914 srcbuf = (afs_int32 *) & (fullPerfP->overall);
1916 for (i = 0; i < NUM_XSTAT_FS_AFS_PERFSTATS_LONGS; i++) {
1917 sprintf(a_fsData->data[idx], "%d", *srcbuf);
1923 srcbuf = (afs_int32 *) & (fullPerfP->det.epoch);
1924 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* epoch */
1927 /* copy fs operation timing */
1929 srcbuf = (afs_int32 *) (fullPerfP->det.rpcOpTimes);
1931 for (i = 0; i < FS_STATS_NUM_RPC_OPS; i++) {
1932 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* numOps */
1935 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* numSuccesses */
1938 tmpbuf = srcbuf++; /* sum time */
1939 sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1942 tmpbuf = srcbuf++; /* sqr time */
1943 sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1946 tmpbuf = srcbuf++; /* min time */
1947 sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1950 tmpbuf = srcbuf++; /* max time */
1951 sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1956 /* copy fs transfer timings */
1958 srcbuf = (afs_int32 *) (fullPerfP->det.xferOpTimes);
1959 for (i = 0; i < FS_STATS_NUM_XFER_OPS; i++) {
1960 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* numOps */
1963 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* numSuccesses */
1966 tmpbuf = srcbuf++; /* sum time */
1967 sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1970 tmpbuf = srcbuf++; /* sqr time */
1971 sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1974 tmpbuf = srcbuf++; /* min time */
1975 sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1978 tmpbuf = srcbuf++; /* max time */
1979 sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1982 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* sum bytes */
1985 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* min bytes */
1988 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* max bytes */
1991 for (j = 0; j < FS_STATS_NUM_XFER_BUCKETS; j++) {
1992 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* bucket[j] */
2001 /*-----------------------------------------------------------------------
2002 * fs_CallBackStats_ltoa()
2005 * Convert the callback counter xstat collection from
2006 * int32s to strings.
2010 *----------------------------------------------------------------------*/
2013 fs_CallBackStats_ltoa(struct fs_Display_Data *a_fsData,
2014 struct xstat_fs_ProbeResults *a_fsResults)
2018 int len = a_fsResults->data.AFS_CollData_len;
2019 afs_int32 *val = a_fsResults->data.AFS_CollData_val;
2021 /* place callback stats after the full perf stats */
2022 idx = NUM_FS_FULLPERF_ENTRIES;
2023 for (i=0; i < len && i < NUM_FS_CB_ENTRIES; i++) {
2024 sprintf(a_fsData->data[idx++], "%u", val[i]);
2029 /*-----------------------------------------------------------------------
2030 * execute_thresh_handler()
2033 * Execute a threshold handler. An agrv[] array of pointers is
2034 * constructed from the given data. A child process is forked
2035 * which immediately calls afsmon_Exit() with indication that a
2036 * threshold handler is to be exec'ed insted of exiting.
2040 * Failure: Afsmonitor exits if threshold handler has more than 20 args.
2041 *----------------------------------------------------------------------*/
2044 execute_thresh_handler(char *a_handler, /* ptr to handler function + args */
2045 char *a_hostName, /* host name for which threshold crossed */
2046 int a_hostType, /* fs or cm ? */
2047 char *a_threshName, /* threshold variable name */
2048 char *a_threshValue, /* threshold value */
2049 char *a_actValue) /* actual value */
2050 { /* execute_thresh_handler */
2052 static char rn[] = "execute_thresh_handler";
2053 char fileName[256]; /* file name to execute */
2058 int anotherArg; /* boolean used to flag if another arg is available */
2062 "[ %s ] Called, a_handler= %s, a_hostName= %s, a_hostType= %d, a_threshName= %s, a_threshValue= %s, a_actValue= %s\n",
2063 rn, a_handler, a_hostName, a_hostType, a_threshName,
2064 a_threshValue, a_actValue);
2069 /* get the filename to execute - the first argument */
2070 sscanf(a_handler, "%s", fileName);
2072 /* construct the contents of *argv[] */
2074 strncpy(fsHandler_args[0], fileName, 256);
2075 strncpy(fsHandler_args[1], a_hostName, HOST_NAME_LEN);
2076 if (a_hostType == FS)
2077 strcpy(fsHandler_args[2], "fs");
2079 strcpy(fsHandler_args[2], "cm");
2080 strncpy(fsHandler_args[3], a_threshName, THRESH_VAR_NAME_LEN);
2081 strncpy(fsHandler_args[4], a_threshValue, THRESH_VAR_LEN);
2082 strncpy(fsHandler_args[5], a_actValue, THRESH_VAR_LEN);
2089 /* we have already extracted the file name so skip to the 1st arg */
2090 while (isspace(*ch)) /* leading blanks */
2092 while (!isspace(*ch) && *ch != '\0') /* handler filename */
2095 while (*ch != '\0') {
2098 } else if (anotherArg) {
2100 sscanf(ch, "%s", fsHandler_args[argNum]);
2106 "Threshold handlers cannot have more than 20 arguments\n");
2112 fsHandler_argv[argNum] = NULL;
2113 for (i = 0; i < argNum; i++)
2114 fsHandler_argv[i] = fsHandler_args[i];
2117 /* exec the threshold handler */
2120 exec_fsThreshHandler = 1;
2121 code = afsmon_Exit(60);
2125 } /* execute_thresh_handler */
2129 /*-----------------------------------------------------------------------
2130 * check_fs_thresholds()
2133 * Checks the thresholds and sets the overflow flag. Recall that the
2134 * thresholds for each host are stored in the hostEntry lists
2135 * [fs/cm]nameList arrays. The probe results are passed to this
2136 * function in the display-ready format - ie., as strings. Though
2137 * this looks stupid the overhead incurred in converting the strings
2138 * back to floats and comparing them is insignificant and
2139 * programming is easier this way.
2140 * The threshold flags are a part of the display structures
2145 *----------------------------------------------------------------------*/
2148 check_fs_thresholds(struct afsmon_hostEntry *a_hostEntry, /* ptr to hostEntry */
2149 struct fs_Display_Data *a_Data) /* ptr to fs data to be displayed */
2150 { /* check_fs_thresholds */
2152 static char rn[] = "check_fs_thresholds";
2153 struct Threshold *threshP;
2154 double tValue; /* threshold value */
2155 double pValue; /* probe value */
2158 int count; /* number of thresholds exceeded */
2161 fprintf(debugFD, "[ %s ] Called, a_hostEntry= %p, a_Data= %p\n", rn,
2162 a_hostEntry, a_Data);
2166 if (a_hostEntry->numThresh == 0) {
2167 /* store in ovf count ?? */
2172 threshP = a_hostEntry->thresh;
2173 for (i = 0; i < a_hostEntry->numThresh; i++) {
2174 if (threshP->itemName[0] == '\0') {
2178 idx = threshP->index; /* positional index to the data array */
2179 tValue = atof(threshP->threshVal); /* threshold value */
2180 pValue = atof(a_Data->data[idx]); /* probe value */
2181 if (pValue > tValue) {
2185 "[ %s ] fs = %s, thresh ovf for %s, threshold= %s, probevalue= %s\n",
2186 rn, a_hostEntry->hostName, threshP->itemName,
2187 threshP->threshVal, a_Data->data[idx]);
2190 /* if the threshold is crossed, call the handler function
2191 * only if this was a transition -ie, if the threshold was
2192 * crossed in the last probe too just count & keep quite! */
2194 if (!a_Data->threshOvf[idx]) {
2195 a_Data->threshOvf[idx] = 1;
2196 /* call the threshold handler if provided */
2197 if (threshP->handler[0] != '\0') {
2199 fprintf(debugFD, "[ %s ] Calling ovf handler %s\n",
2200 rn, threshP->handler);
2203 execute_thresh_handler(threshP->handler, a_Data->hostName,
2204 FS, threshP->itemName,
2212 /* in case threshold was previously crossed, blank it out */
2213 a_Data->threshOvf[idx] = 0;
2216 /* store the overflow count */
2217 a_Data->ovfCount = count;
2220 } /* check_fs_thresholds */
2223 /*-----------------------------------------------------------------------
2224 * save_FS_data_forDisplay()
2227 * Does the following:
2228 * - if the probe number changed (ie, a cycle completed) curr_fsData
2229 * is copied to prev_fsData, curr_fsData zeroed and refresh the
2230 * overview screen and file server screen with the new data.
2231 * - store the results of the current probe from xstat_fs_Results into
2232 * curr_fsData. ie., convert longs to strings.
2233 * - check the thresholds
2237 * Failure: Exits afsmonitor.
2238 *----------------------------------------------------------------------*/
2241 save_FS_data_forDisplay(struct xstat_fs_ProbeResults *a_fsResults)
2242 { /* save_FS_data_forDisplay */
2244 static char rn[] = "save_FS_data_forDisplay"; /* routine name */
2245 struct fs_Display_Data *curr_fsDataP; /* tmp ptr to curr_fsData */
2246 struct fs_Display_Data *prev_fsDataP; /* tmp ptr to prev_fsData */
2247 struct afsmon_hostEntry *curr_host;
2248 static int results_Received = 0; /* number of probes reveived in
2249 * the current cycle. If this is equal to numFS we got all
2250 * the data we want in this cycle and can now display it */
2259 fprintf(debugFD, "[ %s ] Called, a_fsResults= %p\n", rn, a_fsResults);
2263 /* store results in the display array */
2266 curr_fsDataP = curr_fsData;
2267 for (i = 0; i < numFS; i++) {
2268 if ((strcasecmp(curr_fsDataP->hostName, a_fsResults->connP->hostName))
2278 "[ %s ] Could not insert FS probe results for host %s in fs display array\n",
2279 rn, a_fsResults->connP->hostName);
2283 /* Check the status of the probe. If it succeeded, we store its
2284 * results in the display data structure. If it failed we only mark
2285 * the failed status in the display data structure. */
2287 if (a_fsResults->probeOK) { /* 1 => notOK the xstat results */
2288 curr_fsDataP->probeOK = 0;
2290 /* print the probe status */
2292 fprintf(debugFD, "\n\t\t ----- fs display data ------\n");
2293 fprintf(debugFD, "HostName = %s PROBE FAILED \n",
2294 curr_fsDataP->hostName);
2298 } else { /* probe succeeded, update display data structures */
2299 curr_fsDataP->probeOK = 1;
2301 /* convert longs to strings and place them in curr_fsDataP */
2302 fs_Results_ltoa(curr_fsDataP, a_fsResults);
2304 /* compare with thresholds and set the overflow flags.
2305 * note that the threshold information is in the hostEntry structure and
2306 * each threshold item has a positional index associated with it */
2308 /* locate the hostEntry for this host */
2310 curr_host = FSnameList;
2311 for (i = 0; i < numFS; i++) {
2312 if (strcasecmp(curr_host->hostName, a_fsResults->connP->hostName)
2317 curr_host = curr_host->next;;
2322 code = check_fs_thresholds(curr_host, curr_fsDataP);
2324 fprintf(stderr, "[ %s ] Error in checking thresholds\n", rn);
2328 /* print the info we just saved */
2331 fprintf(debugFD, "\n\t\t ----- fs display data ------\n");
2332 fprintf(debugFD, "HostName = %s\n", curr_fsDataP->hostName);
2333 for (i = 0; i < NUM_FS_STAT_ENTRIES; i++)
2334 fprintf(debugFD, "%20s %30s %s\n", curr_fsDataP->data[i],
2336 curr_fsDataP->threshOvf[i] ? "(ovf)" : "");
2338 fprintf(debugFD, "\t\t--------------------------------\n\n");
2342 } /* the probe succeeded, so we store the data in the display structure */
2345 /* if we have received a reply from all the hosts for this probe cycle,
2346 * it is time to display the data */
2349 if (results_Received == numFS * num_fs_collections) {
2350 results_Received = 0;
2352 if (afsmon_fs_curr_probeNum != afsmon_fs_prev_probeNum + 1) {
2353 sprintf(errMsg, "[ %s ] Probe number %d missed! \n", rn,
2354 afsmon_fs_prev_probeNum + 1);
2357 afsmon_fs_prev_probeNum++;
2359 /* backup the display data of the probe cycle that just completed -
2360 * ie., store curr_fsData in prev_fsData */
2362 memcpy((char *)prev_fsData, (char *)curr_fsData,
2363 (numFS * sizeof(struct fs_Display_Data)));
2366 /* initialize curr_fsData but retain the threshold flag information.
2367 * The previous state of threshold flags is used in check_fs_thresholds() */
2369 numBytes = NUM_FS_STAT_ENTRIES * FS_STAT_STRING_LEN;
2370 curr_fsDataP = curr_fsData;
2371 for (i = 0; i < numFS; i++) {
2372 curr_fsDataP->probeOK = 0;
2373 curr_fsDataP->ovfCount = 0;
2374 memset(curr_fsDataP->data, 0, numBytes);
2379 /* prev_fsData now contains all the information for the probe cycle
2380 * that just completed. Now count the number of threshold overflows for
2381 * use in the overview screen */
2383 prev_fsDataP = prev_fsData;
2385 numHosts_onfs_alerts = 0;
2386 for (i = 0; i < numFS; i++) {
2387 if (!prev_fsDataP->probeOK) { /* if probe failed */
2389 numHosts_onfs_alerts++;
2391 if (prev_fsDataP->ovfCount) { /* overflows ?? */
2392 num_fs_alerts += prev_fsDataP->ovfCount;
2393 numHosts_onfs_alerts++;
2398 fprintf(debugFD, "Number of FS alerts = %d (on %d hosts)\n",
2399 num_fs_alerts, numHosts_onfs_alerts);
2401 /* flag that the data is now ready to be displayed */
2402 fs_Data_Available = 1;
2404 /* call the Overview frame update routine (update only FS info) */
2405 ovw_refresh(ovw_currPage, OVW_UPDATE_FS);
2407 /* call the File Servers frame update routine */
2408 fs_refresh(fs_currPage, fs_curr_LCol);
2413 } /* save_FS_data_forDisplay */
2418 /*-----------------------------------------------------------------------
2419 * afsmon_FS_Handler()
2422 * This is the File Server probe Handler. It updates the afsmonitor
2423 * probe counts, fs circular buffer indices and calls the functions
2424 * to process the results of this probe.
2428 * Failure: Exits afsmonitor.
2429 *----------------------------------------------------------------------*/
2432 afsmon_FS_Handler(void)
2433 { /* afsmon_FS_Handler() */
2434 static char rn[] = "afsmon_FS_Handler"; /* routine name */
2435 int newProbeCycle; /* start of new probe cycle ? */
2436 int code; /* return status */
2441 "[ %s ] Called, hostName= %s, probeNum= %d, status=%s, collection=%d\n", rn,
2442 xstat_fs_Results.connP->hostName, xstat_fs_Results.probeNum,
2443 xstat_fs_Results.probeOK ? "FAILED" : "OK",
2444 xstat_fs_Results.collectionNumber);
2449 /* print the probe results to output file */
2450 if (afsmon_output) {
2451 code = afsmon_fsOutput(output_filename, afsmon_detOutput);
2454 "[ %s ] output to file %s returned error code=%d\n", rn,
2455 output_filename, code);
2459 /* Update current probe number and circular buffer index. if current
2460 * probenum changed make sure it is only by 1 */
2463 if (xstat_fs_Results.probeNum != afsmon_fs_curr_probeNum) {
2464 if (xstat_fs_Results.probeNum == afsmon_fs_curr_probeNum + 1) {
2465 afsmon_fs_curr_probeNum++;
2468 afsmon_fs_curr_CBindex =
2469 (afsmon_fs_curr_probeNum - 1) % num_bufSlots;
2471 fprintf(stderr, "[ %s ] probe number %d-1 missed\n", rn,
2472 xstat_fs_Results.probeNum);
2478 /* store the results of this probe in the FS circular buffer */
2480 save_FS_results_inCB(newProbeCycle);
2483 /* store the results of the current probe in the fs data display structure.
2484 * if the current probe number changed, swap the current and previous display
2485 * structures. note that the display screen is updated from these structures
2486 * and should start showing the data of the just completed probe cycle */
2488 save_FS_data_forDisplay(&xstat_fs_Results);
2495 /*----------------------------------------------------------------------- *
2500 * Prints the Cache Manager circular buffer
2501 *----------------------------------------------------------------------*/
2505 { /* Print_CM_CB() */
2507 struct afsmon_cm_Results_list *cmlist;
2512 /* print valid info in the cm CB */
2516 "==================== CM Buffer ========================\n");
2517 fprintf(debugFD, "afsmon_cm_curr_CBindex = %d\n",
2518 afsmon_cm_curr_CBindex);
2519 fprintf(debugFD, "afsmon_cm_curr_probeNum = %d\n\n",
2520 afsmon_cm_curr_probeNum);
2522 for (i = 0; i < num_bufSlots; i++) {
2523 fprintf(debugFD, "\t--------- slot %d ----------\n", i);
2524 cmlist = afsmon_cm_ResultsCB[i].list;
2527 for (k = 0; k < MAX_NUM_CM_COLLECTIONS; k++) {
2528 if (!cmlist->empty[k]) {
2530 "\t %d) probeNum = %d host = %s cn = %d",
2532 cmlist->cmResults[k]->probeNum,
2533 cmlist->cmResults[k]->connP->hostName,
2534 cmlist->cmResults[k]->collectionNumber);
2535 if (cmlist->cmResults[k]->probeOK)
2536 fprintf(debugFD, " NOTOK\n");
2538 fprintf(debugFD, " OK\n");
2540 fprintf(debugFD, "\t %d) -- empty --\n", j);
2542 cmlist = cmlist->next;
2545 if (cmlist != (struct afsmon_cm_Results_list *)0)
2546 fprintf(debugFD, "dangling last next ptr cm CB\n");
2552 /*-----------------------------------------------------------------------
2553 * save_CM_results_inCB()
2556 * Saves the results of the latest CM probe in the cm circular
2557 * buffers. If the current probe cycle is in progress the contents
2558 * of xstat_cm_Results are copied to the end of the list of results
2559 * in the current slot (pointed to by afsmon_cm_curr_CBindex). If
2560 * a new probe cycle has started the next slot in the circular buffer
2561 * is initialized and the results copied. Note that the Rx related
2562 * information available in xstat_cm_Results is not copied.
2566 * Failure: Exits afsmonitor.
2567 *----------------------------------------------------------------------*/
2570 save_CM_results_inCB(int a_newProbeCycle) /* start of new probe cycle ? */
2571 { /* save_CM_results_inCB() */
2572 static char rn[] = "save_CM_results_inCB"; /* routine name */
2573 struct afsmon_cm_Results_list *tmp_cmlist_item; /* temp cm list item */
2574 struct xstat_cm_ProbeResults *tmp_cmPR; /* temp ptr */
2580 fprintf(debugFD, "[ %s ] Called, a_newProbeCycle= %d\n", rn,
2585 if (xstat_cm_Results.collectionNumber == AFSCB_XSTATSCOLL_FULL_PERF_INFO) {
2588 fprintf(stderr, "[ %s ] collection number %d is out of range.\n",
2589 rn, xstat_cm_Results.collectionNumber);
2593 /* If a new probe cycle started, mark the list in the current buffer
2594 * slot empty for resuse. Note that afsmon_cm_curr_CBindex was appropriately
2595 * incremented in afsmon_CM_Handler() */
2597 if (a_newProbeCycle) {
2598 tmp_cmlist_item = afsmon_cm_ResultsCB[afsmon_cm_curr_CBindex].list;
2599 for (i = 0; i < numCM; i++) {
2600 tmp_cmlist_item->empty[index] = 1;
2601 tmp_cmlist_item = tmp_cmlist_item->next;
2605 /* locate last unused item in list */
2606 tmp_cmlist_item = afsmon_cm_ResultsCB[afsmon_cm_curr_CBindex].list;
2607 for (i = 0; i < numCM; i++) {
2608 if (tmp_cmlist_item->empty[index])
2610 tmp_cmlist_item = tmp_cmlist_item->next;
2613 /* if we could not find one we have an inconsistent list */
2614 if (!tmp_cmlist_item->empty[index]) {
2616 "[ %s ] list inconsistency 1. unable to find an empty slot to store results of probenum %d of %s\n",
2617 rn, xstat_cm_Results.probeNum,
2618 xstat_cm_Results.connP->hostName);
2622 tmp_cmPR = tmp_cmlist_item->cmResults[index];
2624 /* copy hostname and probe number and probe time and probe status.
2625 * if the probe failed return now */
2627 memcpy(tmp_cmPR->connP->hostName, xstat_cm_Results.connP->hostName,
2628 sizeof(xstat_cm_Results.connP->hostName));
2629 tmp_cmPR->probeNum = xstat_cm_Results.probeNum;
2630 tmp_cmPR->probeTime = xstat_cm_Results.probeTime;
2631 tmp_cmPR->probeOK = xstat_cm_Results.probeOK;
2632 if (xstat_cm_Results.probeOK) { /* probeOK = 1 => notOK */
2633 /* we have a nonempty results structure so mark the list item used */
2634 tmp_cmlist_item->empty[index] = 0;
2639 /* copy connection information */
2640 memcpy(&(tmp_cmPR->connP->skt), &(xstat_cm_Results.connP->skt),
2641 sizeof(struct sockaddr_in));
2643 /**** NEED TO COPY rx_connection INFORMATION HERE ******/
2645 memcpy(tmp_cmPR->connP->hostName, xstat_cm_Results.connP->hostName,
2646 sizeof(xstat_cm_Results.connP->hostName));
2647 tmp_cmPR->collectionNumber = xstat_cm_Results.collectionNumber;
2649 /* copy the probe data information */
2650 tmp_cmPR->data.AFSCB_CollData_len =
2651 min(xstat_cm_Results.data.AFSCB_CollData_len,
2652 afsmon_cm_results_length[index]);
2653 memcpy(tmp_cmPR->data.AFSCB_CollData_val,
2654 xstat_cm_Results.data.AFSCB_CollData_val,
2655 tmp_cmPR->data.AFSCB_CollData_len * sizeof(afs_int32));
2658 /* we have a valid results structure so mark the list item used */
2659 tmp_cmlist_item->empty[index] = 0;
2661 /* print the stored info - to make sure we copied it right */
2662 /* Print_cm_FullPerfInfo(tmp_cmPR); */
2663 /* Print the cm circular buffer */
2666 } /* save_CM_results_inCB */
2670 /*-----------------------------------------------------------------------
2674 * The results of xstat probes are stored in a string format in
2675 * the arrays curr_cmData and prev_cmData. The information stored in
2676 * prev_cmData is copied to the screen.
2677 * This function converts xstat FS results from longs to strings and
2678 * places them in the given buffer (a pointer to an item in curr_cmData).
2679 * When a probe cycle completes, curr_cmData is copied to prev_cmData
2680 * in afsmon_CM_Handler().
2684 *----------------------------------------------------------------------*/
2687 cm_Results_ltoa(struct cm_Display_Data *a_cmData, /* target buffer */
2688 struct xstat_cm_ProbeResults *a_cmResults) /* ptr to xstat cm Results */
2689 { /* cm_Results_ltoa */
2691 static char rn[] = "cm_Results_ltoa"; /* routine name */
2692 struct afs_stats_CMFullPerf *fullP; /* ptr to complete CM stats */
2700 fprintf(debugFD, "[ %s ] Called, a_cmData= %p, a_cmResults= %p\n", rn,
2701 a_cmData, a_cmResults);
2706 fullP = (struct afs_stats_CMFullPerf *)
2707 (a_cmResults->data.AFSCB_CollData_val);
2709 /* There are 4 parts to CM statistics
2710 * - Overall performance statistics (including up/down statistics)
2711 * - This CMs FS RPC operations info
2712 * - This CMs FS RPC errors info
2713 * - This CMs FS transfers info
2714 * - Authentication info
2715 * - [Un]Replicated access info
2718 /* copy overall performance statistics */
2719 srcbuf = (afs_int32 *) & (fullP->perf);
2721 /* we skip the 19 entry, ProtServAddr, so the index must account for this */
2722 for (i = 0; i < NUM_AFS_STATS_CMPERF_LONGS + 1; i++) {
2725 continue; /* skip ProtServerAddr */
2727 sprintf(a_cmData->data[idx], "%d", *srcbuf);
2732 /*printf("Ending index value = %d\n",idx-1); */
2734 /* server up/down statistics */
2735 /* copy file server up/down stats */
2736 srcbuf = (afs_int32 *) (fullP->perf.fs_UpDown);
2738 2 * (sizeof(struct afs_stats_SrvUpDownInfo) / sizeof(afs_int32));
2739 for (i = 0; i < numLongs; i++) {
2740 sprintf(a_cmData->data[idx], "%d", *srcbuf);
2745 /*printf("Ending index value = %d\n",idx-1); */
2747 /* copy volume location server up/down stats */
2748 srcbuf = (afs_int32 *) (fullP->perf.vl_UpDown);
2750 2 * (sizeof(struct afs_stats_SrvUpDownInfo) / sizeof(afs_int32));
2751 for (i = 0; i < numLongs; i++) {
2752 sprintf(a_cmData->data[idx], "%d", *srcbuf);
2757 /*printf("Ending index value = %d\n",idx-1); */
2759 /* copy CMs individual FS RPC operations info */
2760 srcbuf = (afs_int32 *) (fullP->rpc.fsRPCTimes);
2761 for (i = 0; i < AFS_STATS_NUM_FS_RPC_OPS; i++) {
2762 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* numOps */
2765 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* numSuccesses */
2768 tmpbuf = srcbuf++; /* sum time */
2769 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2772 tmpbuf = srcbuf++; /* sqr time */
2773 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2776 tmpbuf = srcbuf++; /* min time */
2777 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2780 tmpbuf = srcbuf++; /* max time */
2781 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2786 /*printf("Ending index value = %d\n",idx-1); */
2788 /* copy CMs individual FS RPC errors info */
2790 srcbuf = (afs_int32 *) (fullP->rpc.fsRPCErrors);
2791 for (i = 0; i < AFS_STATS_NUM_FS_RPC_OPS; i++) {
2792 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* server */
2795 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* network */
2798 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* prot */
2801 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* vol */
2804 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* busies */
2807 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* other */
2812 /*printf("Ending index value = %d\n",idx-1); */
2814 /* copy CMs individual RPC transfers info */
2816 srcbuf = (afs_int32 *) (fullP->rpc.fsXferTimes);
2817 for (i = 0; i < AFS_STATS_NUM_FS_XFER_OPS; i++) {
2818 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* numOps */
2821 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* numSuccesses */
2824 tmpbuf = srcbuf++; /* sum time */
2825 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2828 tmpbuf = srcbuf++; /* sqr time */
2829 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2832 tmpbuf = srcbuf++; /* min time */
2833 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2836 tmpbuf = srcbuf++; /* max time */
2837 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2840 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* sum bytes */
2843 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* min bytes */
2846 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* max bytes */
2849 for (j = 0; j < AFS_STATS_NUM_XFER_BUCKETS; j++) {
2850 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* bucket[j] */
2856 /*printf("Ending index value = %d\n",idx-1); */
2858 /* copy CM operations timings */
2860 srcbuf = (afs_int32 *) (fullP->rpc.cmRPCTimes);
2861 for (i = 0; i < AFS_STATS_NUM_CM_RPC_OPS; i++) {
2862 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* numOps */
2865 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* numSuccesses */
2868 tmpbuf = srcbuf++; /* sum time */
2869 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2872 tmpbuf = srcbuf++; /* sqr time */
2873 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2876 tmpbuf = srcbuf++; /* min time */
2877 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2880 tmpbuf = srcbuf++; /* max time */
2881 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2886 /*printf("Ending index value = %d\n",idx-1); */
2888 /* copy authentication info */
2890 srcbuf = (afs_int32 *) & (fullP->authent);
2891 numLongs = sizeof(struct afs_stats_AuthentInfo) / sizeof(afs_int32);
2892 for (i = 0; i < numLongs; i++) {
2893 sprintf(a_cmData->data[idx], "%d", *srcbuf);
2898 /*printf("Ending index value = %d\n",idx-1); */
2900 /* copy CM [un]replicated access info */
2902 srcbuf = (afs_int32 *) & (fullP->accessinf);
2903 numLongs = sizeof(struct afs_stats_AccessInfo) / sizeof(afs_int32);
2904 for (i = 0; i < numLongs; i++) {
2905 sprintf(a_cmData->data[idx], "%d", *srcbuf);
2910 /*printf("Ending index value = %d\n",idx-1); */
2913 } /* cm_Results_ltoa */
2916 /*-----------------------------------------------------------------------
2917 * Function: check_cm_thresholds()
2920 * Checks the thresholds and sets the overflow flag. Recall that the
2921 * thresholds for each host are stored in the hostEntry lists
2922 * [fs/cm]nameList arrays. The probe results are passed to this
2923 * function in the display-ready format - ie., as strings. Though
2924 * this looks stupid the overhead incurred in converting the strings
2925 * back to floats and comparing them is insignificant and
2926 * programming is easier this way.
2927 * The threshold flags are a part of the display structures
2932 *----------------------------------------------------------------------*/
2935 check_cm_thresholds(struct afsmon_hostEntry *a_hostEntry, /* ptr to hostEntry */
2936 struct cm_Display_Data *a_Data) /* ptr to cm data to be displayed */
2937 { /* check_cm_thresholds */
2939 static char rn[] = "check_cm_thresholds";
2940 struct Threshold *threshP;
2941 double tValue; /* threshold value */
2942 double pValue; /* probe value */
2945 int count; /* number of thresholds exceeded */
2948 fprintf(debugFD, "[ %s ] Called, a_hostEntry= %p, a_Data= %p\n", rn,
2949 a_hostEntry, a_Data);
2953 if (a_hostEntry->numThresh == 0) {
2954 /* store in ovf count ?? */
2959 threshP = a_hostEntry->thresh;
2960 for (i = 0; i < a_hostEntry->numThresh; i++) {
2961 if (threshP->itemName[0] == '\0') {
2965 idx = threshP->index; /* positional index to the data array */
2966 tValue = atof(threshP->threshVal); /* threshold value */
2967 pValue = atof(a_Data->data[idx]); /* probe value */
2968 if (pValue > tValue) {
2972 "[ %s ] cm = %s, thresh ovf for %s, threshold= %s, probevalue= %s\n",
2973 rn, a_hostEntry->hostName, threshP->itemName,
2974 threshP->threshVal, a_Data->data[idx]);
2978 /* if the threshold is crossed, call the handler function
2979 * only if this was a transition -ie, if the threshold was
2980 * crossed in the last probe too just count & keep quite! */
2982 if (!a_Data->threshOvf[idx]) {
2983 a_Data->threshOvf[idx] = 1;
2984 /* call the threshold handler if provided */
2985 if (threshP->handler[0] != '\0') {
2987 fprintf(debugFD, "[ %s ] Calling ovf handler %s\n",
2988 rn, threshP->handler);
2991 execute_thresh_handler(threshP->handler, a_Data->hostName,
2992 CM, threshP->itemName,
3000 /* in case threshold was previously crossed, blank it out */
3001 a_Data->threshOvf[idx] = 0;
3004 /* store the overflow count */
3005 a_Data->ovfCount = count;
3008 } /* check_cm_thresholds */
3011 /*-----------------------------------------------------------------------
3012 * save_CM_data_forDisplay()
3015 * Does the following:
3016 * - if the probe number changed (ie, a cycle completed) curr_cmData
3017 * is copied to prev_cmData, curr_cmData zeroed and refresh the
3018 * overview screen and file server screen with the new data.
3019 * - store the results of the current probe from xstat_cm_Results into
3020 * curr_cmData. ie., convert longs to strings.
3021 * - check the thresholds
3025 * Failure: Exits afsmonitor.
3027 *----------------------------------------------------------------------*/
3030 save_CM_data_forDisplay(struct xstat_cm_ProbeResults *a_cmResults)
3031 { /* save_CM_data_forDisplay */
3033 static char rn[] = "save_CM_data_forDisplay"; /* routine name */
3034 struct cm_Display_Data *curr_cmDataP;
3035 struct cm_Display_Data *prev_cmDataP;
3036 struct afsmon_hostEntry *curr_host;
3037 static int results_Received = 0; /* number of probes reveived in
3038 * the current cycle. If this is equal to numFS we got all
3039 * the data we want in this cycle and can now display it */
3047 fprintf(debugFD, "[ %s ] Called, a_cmResults= %p\n", rn, a_cmResults);
3051 /* store results in the display array */
3054 curr_cmDataP = curr_cmData;
3055 for (i = 0; i < numCM; i++) {
3056 if ((strcasecmp(curr_cmDataP->hostName, a_cmResults->connP->hostName))
3066 "[ %s ] Could not insert CM probe results for host %s in cm display array\n",
3067 rn, a_cmResults->connP->hostName);
3071 /* Check the status of the probe. If it succeeded, we store its
3072 * results in the display data structure. If it failed we only mark
3073 * the failed status in the display data structure. */
3076 if (a_cmResults->probeOK) { /* 1 => notOK the xstat results */
3077 curr_cmDataP->probeOK = 0;
3079 /* print the probe status */
3081 fprintf(debugFD, "\n\t\t ----- cm display data ------\n");
3082 fprintf(debugFD, "HostName = %s PROBE FAILED \n",
3083 curr_cmDataP->hostName);
3087 } else { /* probe succeeded, update display data structures */
3088 curr_cmDataP->probeOK = 1;
3091 /* covert longs to strings and place them in curr_cmDataP */
3092 cm_Results_ltoa(curr_cmDataP, a_cmResults);
3094 /* compare with thresholds and set the overflow flags.
3095 * note that the threshold information is in the hostEntry structure and
3096 * each threshold item has a positional index associated with it */
3098 /* locate the hostEntry for this host */
3100 curr_host = CMnameList;
3101 for (i = 0; i < numCM; i++) {
3102 if (strcasecmp(curr_host->hostName, a_cmResults->connP->hostName)
3107 curr_host = curr_host->next;
3112 code = check_cm_thresholds(curr_host, curr_cmDataP);
3114 fprintf(stderr, "[ %s ] Error in checking thresholds\n", rn);
3118 /* print the info we just saved */
3120 fprintf(debugFD, "\n\t\t ----- CM display data ------\n");
3121 fprintf(debugFD, "HostName = %s\n", curr_cmDataP->hostName);
3122 for (i = 0; i < NUM_CM_STAT_ENTRIES; i++) {
3125 fprintf(debugFD, "\t -- Overall Perf Info --\n");
3129 "\t -- File Server up/down stats - same cell --\n");
3133 "\t -- File Server up/down stats - diff cell --\n");
3137 "\t -- VL server up/down stats - same cell --\n");
3141 "\t -- VL server up/down stats - diff cell --\n");
3144 fprintf(debugFD, "\t -- FS Operation Timings --\n");
3147 fprintf(debugFD, "\t -- FS Error Info --\n");
3150 fprintf(debugFD, "\t -- FS Transfer Timings --\n");
3153 fprintf(debugFD, "\t -- CM Operations Timings --\n");
3156 fprintf(debugFD, "\t -- Authentication Info --\n");
3159 fprintf(debugFD, "\t -- Access Info --\n");
3165 fprintf(debugFD, "%20s %30s %s\n", curr_cmDataP->data[i],
3167 curr_cmDataP->threshOvf[i] ? "(ovf)" : "");
3169 fprintf(debugFD, "\t\t--------------------------------\n\n");
3172 } /* if the probe succeeded, update the display data structures */
3174 /* if we have received a reply from all the hosts for this probe cycle,
3175 * it is time to display the data */
3178 if (results_Received == numCM * num_cm_collections) {
3179 results_Received = 0;
3181 if (afsmon_cm_curr_probeNum != afsmon_cm_prev_probeNum + 1) {
3182 sprintf(errMsg, "[ %s ] Probe number %d missed! \n", rn,
3183 afsmon_cm_prev_probeNum + 1);
3186 afsmon_cm_prev_probeNum++;
3189 /* backup the display data of the probe cycle that just completed -
3190 * ie., store curr_cmData in prev_cmData */
3192 memcpy((char *)prev_cmData, (char *)curr_cmData,
3193 (numCM * sizeof(struct cm_Display_Data)));
3196 /* initialize curr_cmData but retain the threshold flag information.
3197 * The previous state of threshold flags is used in check_cm_thresholds() */
3199 curr_cmDataP = curr_cmData;
3200 numBytes = NUM_CM_STAT_ENTRIES * CM_STAT_STRING_LEN;
3201 for (i = 0; i < numCM; i++) {
3202 curr_cmDataP->probeOK = 0;
3203 curr_cmDataP->ovfCount = 0;
3204 memset(curr_cmDataP->data, 0, numBytes);
3208 /* prev_cmData now contains all the information for the probe cycle
3209 * that just completed. Now count the number of threshold overflows for
3210 * use in the overview screen */
3212 prev_cmDataP = prev_cmData;
3214 numHosts_oncm_alerts = 0;
3215 for (i = 0; i < numCM; i++) {
3216 if (!prev_cmDataP->probeOK) { /* if probe failed */
3218 numHosts_oncm_alerts++;
3219 } else if (prev_cmDataP->ovfCount) { /* overflows ?? */
3220 num_cm_alerts += prev_cmDataP->ovfCount;
3221 numHosts_oncm_alerts++;
3226 fprintf(debugFD, "Number of CM alerts = %d (on %d hosts)\n",
3227 num_cm_alerts, numHosts_oncm_alerts);
3230 /* flag that the data is now ready to be displayed */
3231 cm_Data_Available = 1;
3233 /* update the Overview frame (only CM info) */
3234 ovw_refresh(ovw_currPage, OVW_UPDATE_CM);
3236 /* update the Cache Managers frame */
3237 cm_refresh(cm_currPage, cm_curr_LCol);
3243 } /* save_CM_data_forDisplay */
3247 /*-----------------------------------------------------------------------
3248 * afsmon_CM_Handler()
3251 * This is the Cache Manager probe Handler. It updates the afsmonitor
3252 * probe counts, cm circular buffer indices and calls the functions
3253 * to process the results of this probe.
3257 * Failure: Exits afsmonitor.
3258 *----------------------------------------------------------------------*/
3261 afsmon_CM_Handler(void)
3262 { /* afsmon_CM_Handler() */
3263 static char rn[] = "afsmon_CM_Handler"; /* routine name */
3264 int code; /* return status */
3265 int newProbeCycle; /* start of new probe cycle ? */
3269 "[ %s ] Called, hostName= %s, probeNum= %d, status= %s\n", rn,
3270 xstat_cm_Results.connP->hostName, xstat_cm_Results.probeNum,
3271 xstat_cm_Results.probeOK ? "FAILED" : "OK");
3276 /* print the probe results to output file */
3277 if (afsmon_output) {
3278 code = afsmon_cmOutput(output_filename, afsmon_detOutput);
3281 "[ %s ] output to file %s returned error code=%d\n", rn,
3282 output_filename, code);
3286 /* Update current probe number and circular buffer index. if current
3287 * probenum changed make sure it is only by 1 */
3290 if (xstat_cm_Results.probeNum != afsmon_cm_curr_probeNum) {
3291 if (xstat_cm_Results.probeNum == afsmon_cm_curr_probeNum + 1) {
3292 afsmon_cm_curr_probeNum++;
3295 afsmon_cm_curr_CBindex =
3296 (afsmon_cm_curr_probeNum - 1) % num_bufSlots;
3298 fprintf(stderr, "[ %s ] probe number %d-1 missed\n", rn,
3299 xstat_cm_Results.probeNum);
3304 /* save the results of this probe in the CM buffer */
3306 save_CM_results_inCB(newProbeCycle);
3308 /* store the results of the current probe in the cm data display structure.
3309 * if the current probe number changed, swap the current and previous display
3310 * structures. note that the display screen is updated from these structures
3311 * and should start showing the data of the just completed probe cycle */
3313 save_CM_data_forDisplay(&xstat_cm_Results);
3318 /*-----------------------------------------------------------------------
3322 * Allocate and Initialize circular buffers for file servers.
3326 * Failure to allocate memory: exits afsmonitor.
3327 *----------------------------------------------------------------------*/
3330 init_fs_buffers(void)
3331 { /* init_fs_buffers() */
3332 static char rn[] = "init_fs_buffers"; /* routine name */
3333 struct afsmon_fs_Results_list *new_fslist_item; /* ptr for new struct */
3334 struct afsmon_fs_Results_list *tmp_fslist_item; /* temp ptr */
3335 struct xstat_fs_ProbeResults *new_fsPR; /* ptr for new struct */
3342 fprintf(debugFD, "[ %s ] Called\n", rn);
3346 /* allocate memory for the circular buffer of pointers */
3348 afsmon_fs_ResultsCB = (struct afsmon_fs_Results_CBuffer *)
3349 malloc(sizeof(struct afsmon_fs_Results_CBuffer) * num_bufSlots);
3351 /* initialize the fs circular buffer */
3352 for (i = 0; i < num_bufSlots; i++) {
3353 afsmon_fs_ResultsCB[i].list = (struct afsmon_fs_Results_list *)0;
3354 afsmon_fs_ResultsCB[i].probeNum = 0;
3357 /* create a list of numFS items to store fs probe results for
3358 * each slot in CB */
3360 if (numFS) { /* if we have file servers to monitor */
3361 for (bufslot = 0; bufslot < num_bufSlots; bufslot++) {
3362 numfs = numFS; /* get the number of servers */
3365 /* if any of these mallocs fail we only need to free the memory we
3366 * have allocated in this iteration. the rest of it which is in a
3367 * proper linked list will be freed in afsmon_Exit */
3369 /* allocate memory for an fs list item */
3370 new_fslist_item = (struct afsmon_fs_Results_list *)
3371 malloc(sizeof(struct afsmon_fs_Results_list));
3372 if (new_fslist_item == (struct afsmon_fs_Results_list *)0)
3375 for (i = 0; i < MAX_NUM_FS_COLLECTIONS; i++) {
3376 /* allocate memory to store xstat_fs_Results */
3377 new_fsPR = (struct xstat_fs_ProbeResults *)
3378 malloc(sizeof(struct xstat_fs_ProbeResults));
3380 free(new_fslist_item);
3384 new_fsPR->connP = (struct xstat_fs_ConnectionInfo *)
3385 malloc(sizeof(struct xstat_fs_ConnectionInfo));
3386 if (new_fsPR->connP == (struct xstat_fs_ConnectionInfo *)0) {
3387 free(new_fslist_item);
3392 /* >>> need to allocate rx connection info structure here <<< */
3393 new_fsPR->data.AFS_CollData_val = (afs_int32 *)
3394 malloc(afsmon_fs_results_length[i] * sizeof(afs_int32));
3395 if (new_fsPR->data.AFS_CollData_val == NULL) {
3396 free(new_fslist_item);
3397 free(new_fsPR->connP);
3401 new_fslist_item->fsResults[i] = new_fsPR;
3402 new_fslist_item->empty[i] = 1;
3405 /* initialize this list entry */
3406 new_fslist_item->next = (struct afsmon_fs_Results_list *)0;
3408 /* store it at the end of the fs list in the current CB slot */
3409 if (afsmon_fs_ResultsCB[bufslot].list ==
3410 (struct afsmon_fs_Results_list *)0)
3411 afsmon_fs_ResultsCB[bufslot].list = new_fslist_item;
3413 tmp_fslist_item = afsmon_fs_ResultsCB[bufslot].list;
3415 while (tmp_fslist_item !=
3416 (struct afsmon_fs_Results_list *)0) {
3417 if (tmp_fslist_item->next ==
3418 (struct afsmon_fs_Results_list *)0)
3420 tmp_fslist_item = tmp_fslist_item->next;
3422 /* something goofed. exit */
3423 fprintf(stderr, "[ %s ] list creation error\n",
3428 tmp_fslist_item->next = new_fslist_item;
3431 } /* while servers */
3432 } /* for each buffer slot */
3433 } /* if we have file servers to monitor */
3437 /*-----------------------------------------------------------------------
3441 * Allocate and Initialize circular buffers for cache managers.
3445 * Failure to allocate memory: exits afsmonitor.
3446 *----------------------------------------------------------------------*/
3449 init_cm_buffers(void)
3450 { /* init_cm_buffers() */
3451 static char rn[] = "init_cm_buffers"; /* routine name */
3452 struct afsmon_cm_Results_list *new_cmlist_item; /* ptr for new struct */
3453 struct afsmon_cm_Results_list *tmp_cmlist_item; /* temp ptr */
3454 struct xstat_cm_ProbeResults *new_cmPR; /* ptr for new struct */
3460 fprintf(debugFD, "[ %s ] Called\n", rn);
3464 /* allocate memory for the circular buffer of pointers */
3465 afsmon_cm_ResultsCB = (struct afsmon_cm_Results_CBuffer *)
3466 malloc(sizeof(struct afsmon_cm_Results_CBuffer) * num_bufSlots);
3468 /* initialize the fs circular buffer */
3469 for (i = 0; i < num_bufSlots; i++) {
3470 afsmon_cm_ResultsCB[i].list = (struct afsmon_cm_Results_list *)0;
3471 afsmon_cm_ResultsCB[i].probeNum = 0;
3474 /* create a list of numCM items to store fs probe results for
3475 * each slot in CB */
3477 if (numCM) { /* if we have file servers to monitor */
3478 for (bufslot = 0; bufslot < num_bufSlots; bufslot++) {
3479 numcm = numCM; /* get the number of servers */
3482 /* if any of these mallocs fail we only need to free the memory we
3483 * have allocated in this iteration. the rest of it which is in a
3484 * proper linked list will be freed in afsmon_Exit */
3486 /* allocate memory for an fs list item */
3487 new_cmlist_item = (struct afsmon_cm_Results_list *)
3488 malloc(sizeof(struct afsmon_cm_Results_list));
3489 if (new_cmlist_item == (struct afsmon_cm_Results_list *)0)
3492 for (i = 0; i < MAX_NUM_CM_COLLECTIONS; i++) {
3493 /* allocate memory to store xstat_cm_Results */
3494 new_cmPR = (struct xstat_cm_ProbeResults *)
3495 malloc(sizeof(struct xstat_cm_ProbeResults));
3497 free(new_cmlist_item);
3500 new_cmPR->connP = (struct xstat_cm_ConnectionInfo *)
3501 malloc(sizeof(struct xstat_cm_ConnectionInfo));
3502 if (!new_cmPR->connP) {
3503 free(new_cmlist_item);
3508 /* >>> need to allocate rx connection info structure here <<< */
3510 new_cmPR->data.AFSCB_CollData_val =
3511 (afs_int32 *) malloc(XSTAT_CM_FULLPERF_RESULTS_LEN
3512 * sizeof(afs_int32));
3513 if (new_cmPR->data.AFSCB_CollData_val == NULL) {
3514 free(new_cmlist_item);
3515 free(new_cmPR->connP);
3520 new_cmlist_item->cmResults[i] = new_cmPR;
3521 new_cmlist_item->empty[i] = 1;
3524 /* initialize this list entry */
3525 new_cmlist_item->next = (struct afsmon_cm_Results_list *)0;
3527 /* store it at the end of the cm list in the current CB slot */
3528 if (afsmon_cm_ResultsCB[bufslot].list ==
3529 (struct afsmon_cm_Results_list *)0)
3530 afsmon_cm_ResultsCB[bufslot].list = new_cmlist_item;
3532 tmp_cmlist_item = afsmon_cm_ResultsCB[bufslot].list;
3534 while (tmp_cmlist_item !=
3535 (struct afsmon_cm_Results_list *)0) {
3536 if (tmp_cmlist_item->next ==
3537 (struct afsmon_cm_Results_list *)0)
3539 tmp_cmlist_item = tmp_cmlist_item->next;
3541 /* something goofed. exit */
3542 fprintf(stderr, "[ %s ] list creation error\n",
3547 tmp_cmlist_item->next = new_cmlist_item;
3550 } /* while servers */
3551 } /* for each buffer slot */
3553 /* if we have file servers to monitor */
3554 /* print the CB to make sure it is right */
3558 } /* init_cm_buffers() */
3561 /*-------------------------------------------------------------------------
3562 * init_print_buffers()
3565 * Allocate and initialize the buffers used for printing results
3566 * to the display screen. These buffers store the current and
3567 * previous probe results in ascii format.
3572 *------------------------------------------------------------------------*/
3575 init_print_buffers(void)
3576 { /* init_print_buffers */
3578 static char rn[] = "init_print_buffers"; /* routine name */
3579 struct fs_Display_Data *tmp_fsData1; /* temp pointers */
3580 struct fs_Display_Data *tmp_fsData2;
3581 struct cm_Display_Data *tmp_cmData1;
3582 struct cm_Display_Data *tmp_cmData2;
3583 struct afsmon_hostEntry *tmp_fsNames;
3584 struct afsmon_hostEntry *tmp_cmNames;
3589 fprintf(debugFD, "[ %s ] Called\n", rn);
3593 /* allocate numFS blocks of the FS print structure. */
3595 /* we need two instances of this structure - one (curr_fsData) for storing
3596 * the results of the fs probes currently in progress and another (prev_fsData)
3597 * for the last completed probe. The display is updated from the contents of
3598 * prev_fsData. The pointers curr_fsData & prev_fsData are switched whenever
3599 * the probe number changes */
3602 numBytes = numFS * sizeof(struct fs_Display_Data);
3603 curr_fsData = (struct fs_Display_Data *)malloc(numBytes);
3604 if (curr_fsData == (struct fs_Display_Data *)0) {
3605 fprintf(stderr, "[ %s ] Memory allocation failure\n", rn);
3608 memset(curr_fsData, 0, numBytes);
3610 numBytes = numFS * sizeof(struct fs_Display_Data);
3611 prev_fsData = (struct fs_Display_Data *)malloc(numBytes);
3612 if (prev_fsData == (struct fs_Display_Data *)0) {
3613 fprintf(stderr, "[ %s ] Memory allocation failure\n", rn);
3616 memset(prev_fsData, 0, numBytes);
3618 /* fill in the host names */
3619 tmp_fsData1 = curr_fsData;
3620 tmp_fsData2 = curr_fsData;
3621 tmp_fsNames = FSnameList;
3622 for (i = 0; i < numFS; i++) {
3623 strncpy(tmp_fsData1->hostName, tmp_fsNames->hostName,
3625 strncpy(tmp_fsData2->hostName, tmp_fsNames->hostName,
3629 tmp_fsNames = tmp_fsNames->next;;
3634 /* if file servers to monitor */
3635 /* allocate numCM blocks of the CM print structure */
3636 /* we need two instances of this structure for the same reasons as above */
3638 numBytes = numCM * sizeof(struct cm_Display_Data);
3640 curr_cmData = (struct cm_Display_Data *)malloc(numBytes);
3641 if (curr_cmData == (struct cm_Display_Data *)0) {
3642 fprintf(stderr, "[ %s ] Memory allocation failure\n", rn);
3645 memset(curr_cmData, 0, numBytes);
3647 numBytes = numCM * sizeof(struct cm_Display_Data);
3648 prev_cmData = (struct cm_Display_Data *)malloc(numBytes);
3649 if (prev_cmData == (struct cm_Display_Data *)0) {
3650 fprintf(stderr, "[ %s ] Memory allocation failure\n", rn);
3653 memset(prev_cmData, 0, numBytes);
3655 /* fill in the host names */
3656 tmp_cmData1 = curr_cmData;
3657 tmp_cmData2 = curr_cmData;
3658 tmp_cmNames = CMnameList;
3659 for (i = 0; i < numCM; i++) {
3660 strncpy(tmp_cmData1->hostName, tmp_cmNames->hostName,
3662 strncpy(tmp_cmData2->hostName, tmp_cmNames->hostName,
3666 tmp_cmNames = tmp_cmNames->next;;
3670 /* if cache managers to monitor */
3673 } /* init_print_buffers */
3675 /*-----------------------------------------------------------------------
3679 * Trap the interrupt signal. This function is useful only until
3680 * gtx is initialized.
3681 *----------------------------------------------------------------------*/
3684 quit_signal(int sig)
3686 fprintf(stderr, "Received signal %d \n", sig);
3692 /*-----------------------------------------------------------------------
3696 * This is where we start it all. Initialize an array of sockets for
3697 * file servers and cache cache managers and call the xstat_[fs/cm]_Init
3698 * routines. The last step is to call the gtx input server which
3699 * grabs control of the keyboard.
3702 * Does not return. Control is periodically returned to the afsmonitor
3703 * thru afsmon_[FS/CM]_Handler() routines and also through the gtx
3704 * keyboard handler calls.
3706 *----------------------------------------------------------------------*/
3709 afsmon_execute(void)
3710 { /* afsmon_execute() */
3711 static char rn[] = "afsmon_execute"; /* routine name */
3712 static char fullhostname[128]; /* full host name */
3713 struct sockaddr_in *FSSktArray; /* fs socket array */
3714 int FSsktbytes; /* num bytes in above */
3715 struct sockaddr_in *CMSktArray; /* cm socket array */
3716 int CMsktbytes; /* num bytes in above */
3717 struct sockaddr_in *curr_skt; /* ptr to current socket */
3718 struct afsmon_hostEntry *curr_FS; /* ptr to FS name list */
3719 struct afsmon_hostEntry *curr_CM; /* ptr to CM name list */
3720 struct hostent *he; /* host entry */
3721 int FSinitFlags = 0; /* flags for xstat_fs_Init */
3722 int CMinitFlags = 0; /* flags for xstat_cm_Init */
3723 int code; /* function return code */
3724 struct timeval tv; /* time structure */
3729 fprintf(debugFD, "[ %s ] Called\n", rn);
3734 /* process file server entries */
3736 afs_int32 collIDs[MAX_NUM_FS_COLLECTIONS];
3738 /* Allocate an array of sockets for each fileserver we monitor */
3740 FSsktbytes = numFS * sizeof(struct sockaddr_in);
3741 FSSktArray = (struct sockaddr_in *)malloc(FSsktbytes);
3742 if (FSSktArray == (struct sockaddr_in *)0) {
3744 "[ %s ] cannot malloc %d sockaddr_ins for fileservers\n",
3749 memset(FSSktArray, 0, FSsktbytes);
3751 /* Fill in the socket information for each fileserve */
3753 curr_skt = FSSktArray;
3754 curr_FS = FSnameList; /* FS name list header */
3756 strncpy(fullhostname, curr_FS->hostName, sizeof(fullhostname));
3757 he = GetHostByName(fullhostname);
3759 fprintf(stderr, "[ %s ] Cannot get host info for %s\n", rn,
3763 strncpy(curr_FS->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 = AF_INET; /*Internet family */
3766 curr_skt->sin_port = htons(7000); /*FileServer port */
3767 #ifdef STRUCT_SOCKADDR_HAS_SA_LEN
3768 curr_skt->sin_len = sizeof(struct sockaddr_in);
3771 /* get the next dude */
3773 curr_FS = curr_FS->next;
3776 /* Initialize collection IDs, depending on the data requested. */
3777 num_fs_collections = 0;
3778 for (i = 0; i < fs_DisplayItems_count; i++) {
3779 index = fs_Display_map[i];
3780 if (FS_FULLPERF_ENTRY_START <= index && index <= FS_FULLPERF_ENTRY_END) {
3781 collIDs[num_fs_collections++] = AFS_XSTATSCOLL_FULL_PERF_INFO;
3785 for (i = 0; i < fs_DisplayItems_count; i++) {
3786 index = fs_Display_map[i];
3787 if (FS_CB_ENTRY_START <= index && index <= FS_CB_ENTRY_END) {
3788 collIDs[num_fs_collections++] = AFS_XSTATSCOLL_CBSTATS;
3794 if (afsmon_onceOnly) /* option not provided at this time */
3795 FSinitFlags |= XSTAT_FS_INITFLAG_ONE_SHOT;
3798 fprintf(debugFD, "[ %s ] Calling xstat_fs_Init \n", rn);
3802 code = xstat_fs_Init(numFS, /*Num servers */
3803 FSSktArray, /*File Server socket array */
3804 afsmon_probefreq, /*probe frequency */
3805 afsmon_FS_Handler, /*Handler routine */
3806 FSinitFlags, /*Initialization flags */
3807 num_fs_collections, /*Number of collection IDs */
3808 collIDs); /*Ptr to collection ID */
3811 fprintf(stderr, "[ %s ] xstat_fs_init returned error\n", rn);
3818 /* end of process fileserver entries */
3819 /* process cache manager entries */
3821 afs_int32 collIDs[MAX_NUM_CM_COLLECTIONS];
3823 /* Allocate an array of sockets for each cache manager we monitor */
3825 CMsktbytes = numCM * sizeof(struct sockaddr_in);
3826 CMSktArray = (struct sockaddr_in *)malloc(CMsktbytes);
3827 if (CMSktArray == (struct sockaddr_in *)0) {
3829 "[ %s ] cannot malloc %d sockaddr_ins for CM entries\n",
3834 memset(CMSktArray, 0, CMsktbytes);
3836 /* Fill in the socket information for each CM */
3838 curr_skt = CMSktArray;
3839 curr_CM = CMnameList; /* CM name list header */
3841 strncpy(fullhostname, curr_CM->hostName, sizeof(fullhostname));
3842 he = GetHostByName(fullhostname);
3844 fprintf(stderr, "[ %s ] Cannot get host info for %s\n", rn,
3848 strncpy(curr_CM->hostName, he->h_name, HOST_NAME_LEN); /* complete name */
3849 memcpy(&(curr_skt->sin_addr.s_addr), he->h_addr, 4);
3850 curr_skt->sin_family = AF_INET;
3851 curr_skt->sin_port = htons(7001); /* Cache Manager port */
3852 #ifdef STRUCT_SOCKADDR_HAS_SA_LEN
3853 curr_skt->sin_len = sizeof(struct sockaddr_in);
3856 /* get the next dude */
3858 curr_CM = curr_CM->next;
3861 /* initialize collection IDs. We need only one entry since we collect
3862 * all the information from xstat */
3863 num_cm_collections = 0;
3864 collIDs[num_cm_collections++] = AFSCB_XSTATSCOLL_FULL_PERF_INFO;
3867 if (afsmon_onceOnly) /* once only ? */
3868 CMinitFlags |= XSTAT_CM_INITFLAG_ONE_SHOT;
3871 fprintf(debugFD, "[ %s ] Calling xstat_cm_Init \n", rn);
3875 code = xstat_cm_Init(numCM, /*Num servers */
3876 CMSktArray, /*Cache Manager socket array */
3877 afsmon_probefreq, /*probe frequency */
3878 afsmon_CM_Handler, /*Handler routine */
3879 CMinitFlags, /*Initialization flags */
3880 num_cm_collections, /*Number of collection IDs */
3881 collIDs); /*Ptr to collection ID */
3884 fprintf(stderr, "[ %s ] xstat_cm_init returned error\n", rn);
3891 /* end of process cache manager entries */
3892 /* if only one probe was required setup a waiting process for the
3893 * termination signal */
3894 if (afsmon_onceOnly) {
3895 code = LWP_WaitProcess(&terminationEvent);
3898 fprintf(debugFD, "LWP_WaitProcess() returned error %d\n",
3906 /* start the gtx input server */
3907 code = (intptr_t)gtx_InputServer(afsmon_win);
3909 fprintf(stderr, "[ %s ] Failed to start input server \n", rn);
3913 /* This part of the code is reached only if the input server is not started
3914 * for debugging purposes */
3917 tv.tv_sec = 24 * 60;
3919 fprintf(stderr, "[ %s ] going to sleep ...\n", rn);
3921 code = IOMGR_Select(0, /*Num fds */
3922 0, /*Descriptors ready for reading */
3923 0, /*Descriptors ready for writing */
3924 0, /*Descriptors with exceptional conditions */
3925 &tv); /*Timeout structure */
3928 "[ %s ] IOMGR_Select() returned non-zero value %d\n", rn,
3936 /*-----------------------------------------------------------------------
3940 * Afsmonitor initialization routine.
3941 * - processes command line parameters
3942 * - call functions to:
3943 * - process config file
3944 * - initialize circular buffers and display buffers
3946 * - execute afsmonitor
3947 * - initialize the display maps [fs/cm]_Display_map[].
3950 * Success: Does not return from the call to afsmon_execute().
3951 * Failure: Exits afsmonitor.
3952 *----------------------------------------------------------------------*/
3955 afsmonInit(struct cmd_syndesc *as, void *arock)
3956 { /* afsmonInit() */
3958 static char rn[] = "afsmonInit"; /* Routine name */
3959 char *debug_filename; /* pointer to debug filename */
3960 FILE *outputFD; /* output file descriptor */
3961 struct cmd_item *hostPtr; /* ptr to parse command line args */
3962 char buf[256]; /* buffer for processing hostnames */
3967 fprintf(debugFD, "[ %s ] Called, as= %p\n", rn, as);
3971 /* Open the debug file if -debug option is specified */
3972 if (as->parms[P_DEBUG].items != 0) {
3974 debug_filename = as->parms[P_DEBUG].items->data;
3975 debugFD = fopen(debug_filename, "w");
3976 if (debugFD == (FILE *) 0) {
3977 printf("[ %s ] Failed to open debugging file %s for writing\n",
3985 fprintf(debugFD, "[ %s ] Called\n", rn);
3989 /* use curses always until we support other packages */
3991 wpkg_to_use = atoi(as->parms[P_PACKAGE].items->data);
3993 switch (wpkg_to_use) {
3994 case GATOR_WIN_CURSES:
3995 fprintf(stderr, "curses\n");
3997 case GATOR_WIN_DUMB:
3998 fprintf(stderr, "dumb terminal\n");
4001 fprintf(stderr, "X11\n");
4004 fprintf(stderr, "Illegal graphics package: %d\n", wpkg_to_use);
4006 } /*end switch (wpkg_to_use) */
4009 wpkg_to_use = GATOR_WIN_CURSES;
4011 /* get probe frequency . We check for meaningful bounds on the frequency
4012 * and reset to the default value if needed. The upper bound of 24
4013 * hours looks ridiculous though! */
4015 afsmon_probefreq = 0;
4016 if (as->parms[P_FREQUENCY].items != 0)
4017 afsmon_probefreq = atoi(as->parms[P_FREQUENCY].items->data);
4019 afsmon_probefreq = DEFAULT_FREQUENCY;
4021 if (afsmon_probefreq <= 0 || afsmon_probefreq > 24 * 60 * 60) {
4022 afsmon_probefreq = DEFAULT_FREQUENCY;
4025 "[ %s ] Invalid probe frequency %s specified, resetting to default value %d seconds\n",
4026 rn, as->parms[P_FREQUENCY].items->data, afsmon_probefreq);
4030 "Invalid probe frequency %s specified, resetting to default value %d seconds\n",
4031 as->parms[P_FREQUENCY].items->data, afsmon_probefreq);
4036 /* make sure output file is writable, else complain now */
4037 /* we will open and close it as needed after probes */
4039 if (as->parms[P_OUTPUT].items != 0) {
4040 afsmon_output = 1; /* output flag */
4041 strncpy(output_filename, as->parms[P_OUTPUT].items->data, 80);
4042 outputFD = fopen(output_filename, "a");
4043 if (outputFD == (FILE *) 0) {
4044 fprintf(stderr, "Failed to open output file %s \n",
4047 fprintf(debugFD, "[ %s ] Failed to open output file %s \n",
4048 rn, output_filename);
4053 fprintf(debugFD, "[ %s ] output file is %s\n", rn,
4059 /* detailed statistics to storage file */
4060 if (as->parms[P_DETAILED].items != 0) {
4061 if (as->parms[P_OUTPUT].items == 0) {
4063 "-detailed switch can be used only with -output\n");
4066 afsmon_detOutput = 1;
4069 /* Initialize host list headers */
4070 FSnameList = (struct afsmon_hostEntry *)0;
4071 CMnameList = (struct afsmon_hostEntry *)0;
4073 /* The -config option is mutually exclusive with the -fshosts,-cmhosts
4076 if (as->parms[P_CONFIG].items) {
4077 if (as->parms[P_FSHOSTS].items || as->parms[P_CMHOSTS].items) {
4079 "Cannot use -config option with -fshosts or -cmhosts\n");
4083 if (!as->parms[P_FSHOSTS].items && !as->parms[P_CMHOSTS].items) {
4085 "Must specify either -config or (-fshosts and/or -cmhosts) options \n");
4091 /* If a file server host is specified on the command line we reuse
4092 * parse_hostEntry() function . Just the pass the info as if it were
4093 * read off the config file */
4095 if (as->parms[P_FSHOSTS].items) {
4096 hostPtr = as->parms[P_FSHOSTS].items;
4097 while (hostPtr != (struct cmd_item *)0) {
4098 sprintf(buf, "fs %s", hostPtr->data);
4099 code = parse_hostEntry(buf);
4101 fprintf(stderr, "Could not parse %s\n", hostPtr->data);
4105 hostPtr = hostPtr->next;
4109 /* same as above for -cmhosts */
4110 if (as->parms[P_CMHOSTS].items) {
4111 hostPtr = as->parms[P_CMHOSTS].items;
4112 while (hostPtr != (struct cmd_item *)0) {
4113 sprintf(buf, "cm %s", hostPtr->data);
4114 code = parse_hostEntry(buf);
4116 fprintf(stderr, "Could not parse %s\n", hostPtr->data);
4120 hostPtr = hostPtr->next;
4124 /* number of slots in circular buffers */
4125 if (as->parms[P_BUFFERS].items)
4126 num_bufSlots = atoi(as->parms[P_BUFFERS].items->data);
4128 num_bufSlots = DEFAULT_BUFSLOTS;
4130 /* Initialize xx_showFlags[]. This array is used solely for processing the
4131 * "show" directives in the config file in parse_showEntries() */
4132 for (i = 0; i < NUM_FS_STAT_ENTRIES; i++)
4133 fs_showFlags[i] = 0;
4134 for (i = 0; i < NUM_CM_STAT_ENTRIES; i++)
4135 cm_showFlags[i] = 0;
4138 /* Process the configuration file if given. This initializes among other
4139 * things, the list of FS & CM names in FSnameList and CMnameList */
4141 if (as->parms[P_CONFIG].items)
4142 process_config_file(as->parms[P_CONFIG].items->data);
4144 /* print out the FS and CM lists */
4148 /* Initialize the FS results-to-screen map array if there were no "show fs"
4149 * directives in the config file */
4150 if (fs_showDefault) {
4151 for (i = 0; i < NUM_FS_STAT_ENTRIES; i++)
4152 fs_Display_map[i] = i;
4153 fs_DisplayItems_count = NUM_FS_STAT_ENTRIES;
4156 /* Initialize the CM results-to-screen map array if there were no "show cm"
4157 * directives in the config file */
4158 if (cm_showDefault) {
4159 for (i = 0; i < NUM_CM_STAT_ENTRIES; i++)
4160 cm_Display_map[i] = i;
4161 cm_DisplayItems_count = NUM_CM_STAT_ENTRIES;
4166 /* setup an interrupt signal handler; we ain't wanna leak core */
4167 /* this binding is useful only until gtx is initialized after which the
4168 * keyboard input server takes over. */
4169 if ((signal(SIGINT, quit_signal)) == SIG_ERR) {
4170 perror("signal() failed.");
4175 /* init error message buffers. these will be used to print error messages
4176 * once gtx is initialized and there is no access to stderr/stdout */
4182 /* initialize fs and cm circular buffers before initiating probes */
4184 code = init_fs_buffers();
4186 fprintf(stderr, "[ %s ] init_fs_buffers returned %d\n", rn,
4193 code = init_cm_buffers();
4195 fprintf(stderr, "[ %s ] init_cm_buffers returned %d\n", rn,
4202 /* allocate and initialize buffers for holding fs & cm results in ascii
4203 * format suitable for updating the screen */
4204 code = init_print_buffers();
4206 fprintf(stderr, "[ %s ] init_print_buffers returned %d\n", rn, code);
4210 /* perform gtx initializations */
4211 code = gtx_initialize();
4213 fprintf(stderr, "[ %s ] gtx_initialize returned %d\n", rn, code);
4217 /* start xstat probes */
4220 return (0); /* will not return from the call to afsmon_execute() */
4222 } /* afsmonInit() */
4225 /*-----------------------------------------------------------------------
4227 ------------------------------------------------------------------------*/
4229 #include "AFS_component_version_number.c"
4232 main(int argc, char **argv)
4234 afs_int32 code; /*Return code */
4235 struct cmd_syndesc *ts; /*Ptr to cmd line syntax descriptor */
4237 #ifdef AFS_AIX32_ENV
4239 * The following signal action for AIX is necessary so that in case of a
4240 * crash (i.e. core is generated) we can include the user's data section
4241 * in the core dump. Unfortunately, by default, only a partial core is
4242 * generated which, in many cases, isn't too useful.
4244 struct sigaction nsa;
4246 sigemptyset(&nsa.sa_mask);
4247 nsa.sa_handler = SIG_DFL;
4248 nsa.sa_flags = SA_FULLDUMP;
4249 sigaction(SIGSEGV, &nsa, NULL);
4253 * Set up the commands we understand.
4255 ts = cmd_CreateSyntax("initcmd", afsmonInit, NULL, "initialize the program");
4256 cmd_AddParm(ts, "-config", CMD_SINGLE, CMD_OPTIONAL,
4257 "configuration file");
4258 cmd_AddParm(ts, "-frequency", CMD_SINGLE, CMD_OPTIONAL,
4259 "poll frequency, in seconds");
4260 cmd_AddParm(ts, "-output", CMD_SINGLE, CMD_OPTIONAL, "storage file name");
4261 cmd_AddParm(ts, "-detailed", CMD_FLAG, CMD_OPTIONAL,
4262 "output detailed statistics to storage file");
4264 /* we hope to use this .... eventually! */
4265 cmd_AddParm(ts, "-package", CMD_SINGLE, CMD_REQUIRED,
4266 "Graphics Package to use");
4268 cmd_AddParm(ts, "-debug", CMD_SINGLE, CMD_OPTIONAL,
4269 "turn debugging output on to the named file");
4270 cmd_AddParm(ts, "-fshosts", CMD_LIST, CMD_OPTIONAL,
4271 "list of file servers to monitor");
4272 cmd_AddParm(ts, "-cmhosts", CMD_LIST, CMD_OPTIONAL,
4273 "list of cache managers to monitor");
4274 cmd_AddParm(ts, "-buffers", CMD_SINGLE, CMD_OPTIONAL,
4275 "number of buffer slots");
4278 * Parse command-line switches & execute afsmonitor
4281 code = cmd_Dispatch(argc, argv);
4287 exit(0); /* redundant, but gets rid of warning */