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 *prev_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 for (i = 0; i < numFS; i++) {
511 prev_hostEntry = curr_hostEntry;
512 if (curr_hostEntry->thresh != NULL)
513 free(curr_hostEntry->thresh);
514 free(curr_hostEntry);
516 fprintf(debugFD, " %d", i);
517 curr_hostEntry = prev_hostEntry->next;
520 fprintf(debugFD, "\n");
524 fprintf(debugFD, "Deallocating CM hostEntries ..");
525 curr_hostEntry = CMnameList;
526 for (i = 0; i < numCM; i++) {
527 prev_hostEntry = curr_hostEntry;
528 if (curr_hostEntry->thresh != NULL)
529 free(curr_hostEntry->thresh);
530 free(curr_hostEntry);
532 fprintf(debugFD, " %d", i);
533 curr_hostEntry = prev_hostEntry->next;
536 fprintf(debugFD, "\n");
539 /* close debug file */
545 if (exec_fsThreshHandler) {
546 code = execvp(fsHandler_argv[0], fsHandler_argv);
548 fprintf(stderr, "execvp() of %s returned %d, errno %d\n",
549 fsHandler_argv[0], code, errno);
557 /*-----------------------------------------------------------------------
561 * Insert a hostname in the file server names list.
566 *----------------------------------------------------------------------*/
569 insert_FS(char *a_hostName) /* name of cache manager to be inserted in list */
571 static struct afsmon_hostEntry *curr_item;
572 static struct afsmon_hostEntry *prev_item;
574 if (*a_hostName == '\0')
576 curr_item = (struct afsmon_hostEntry *)
577 malloc(sizeof(struct afsmon_hostEntry));
578 if (curr_item == (struct afsmon_hostEntry *)0) {
579 fprintf(stderr, "Failed to allocate space for FS nameList\n");
583 strncpy(curr_item->hostName, a_hostName, CFG_STR_LEN);
584 curr_item->next = (struct afsmon_hostEntry *)0;
585 curr_item->numThresh = 0;
586 curr_item->thresh = NULL;
588 if (FSnameList == (struct afsmon_hostEntry *)0)
589 FSnameList = curr_item;
591 prev_item->next = curr_item;
593 prev_item = curr_item;
594 /* record the address of this entry so that its threshold
595 * count can be incremented during the first pass of the config file */
596 last_hostEntry = curr_item;
601 /*-----------------------------------------------------------------------
606 * Prints the file server names linked list.
610 *----------------------------------------------------------------------*/
614 static char rn[] = "print_FS";
615 struct afsmon_hostEntry *tempFS;
616 struct Threshold *threshP;
620 fprintf(debugFD, "[ %s ] Called\n", rn);
626 fprintf(debugFD, "No of File Servers: %d\n", numFS);
629 fprintf(debugFD, "\t %s threshCount = %d\n", tempFS->hostName,
631 threshP = tempFS->thresh;
632 for (i = 0; i < tempFS->numThresh; i++, threshP++)
633 fprintf(debugFD, "\t thresh (%2d) %s %s %s\n",
634 threshP->index, threshP->itemName,
635 threshP->threshVal, threshP->handler);
636 } while ((tempFS = tempFS->next) != (struct afsmon_hostEntry *)0);
638 fprintf(debugFD, "\t\t-----End of List-----\n");
644 /*-----------------------------------------------------------------------
648 * Insert a hostname in the cache manager names list.
653 *----------------------------------------------------------------------*/
656 insert_CM(char *a_hostName) /* name of cache manager to be inserted in list */
658 static struct afsmon_hostEntry *curr_item;
659 static struct afsmon_hostEntry *prev_item;
661 if (*a_hostName == '\0')
663 curr_item = (struct afsmon_hostEntry *)
664 malloc(sizeof(struct afsmon_hostEntry));
665 if (curr_item == (struct afsmon_hostEntry *)0) {
666 fprintf(stderr, "Failed to allocate space for CM nameList\n");
670 strncpy(curr_item->hostName, a_hostName, CFG_STR_LEN);
671 curr_item->next = (struct afsmon_hostEntry *)0;
672 curr_item->numThresh = 0;
673 curr_item->thresh = NULL;
675 if (CMnameList == (struct afsmon_hostEntry *)0)
676 CMnameList = curr_item;
678 prev_item->next = curr_item;
680 prev_item = curr_item;
681 /* side effect. note the address of this entry so that its threshold
682 * count can be incremented during the first pass of the config file */
683 last_hostEntry = curr_item;
689 /*-----------------------------------------------------------------------
694 * Prints the cache manager names linked list.
698 *----------------------------------------------------------------------*/
702 static char rn[] = "print_CM";
703 struct afsmon_hostEntry *tempCM;
704 struct Threshold *threshP;
708 fprintf(debugFD, "[ %s ] Called\n", rn);
714 fprintf(debugFD, "No of Cache Managers: %d\n", numCM);
717 fprintf(debugFD, "\t %s threshCount = %d\n", tempCM->hostName,
719 threshP = tempCM->thresh;
720 for (i = 0; i < tempCM->numThresh; i++, threshP++)
721 fprintf(debugFD, "\t thresh (%2d) %s %s %s\n",
722 threshP->index, threshP->itemName,
723 threshP->threshVal, threshP->handler);
724 } while ((tempCM = tempCM->next) != (struct afsmon_hostEntry *)0);
726 fprintf(debugFD, "\t\t-----End of List-----\n");
733 /*-----------------------------------------------------------------------
737 * Parse the host entry line in the config file. Check the syntax,
738 * and inserts the host name in the FS ot CM linked list. Also
739 * remember if this entry was an fs or cm & the ptr to its hostEntry
740 * structure. The threshold entries in the config file are dependent
741 * on their position relative to the hostname entries. Hence it is
742 * required to remember the names of the last file server and cache
743 * manager entries that were processed.
749 *----------------------------------------------------------------------*/
752 parse_hostEntry(char *a_line)
753 { /* parse_hostEntry */
755 static char rn[] = "parse_hostEntry"; /* routine name */
756 char opcode[CFG_STR_LEN]; /* specifies type of config entry */
757 char arg1[CFG_STR_LEN]; /* hostname or qualifier (fs/cm?) */
758 char arg2[CFG_STR_LEN]; /* threshold variable */
759 char arg3[CFG_STR_LEN]; /* threshold value */
760 char arg4[CFG_STR_LEN]; /* user's handler */
761 struct hostent *he; /* host entry */
764 fprintf(debugFD, "[ %s ] Called, a_line = %s\n", rn, a_line);
774 sscanf(a_line, "%s %s %s %s %s", opcode, arg1, arg2, arg3, arg4);
775 /* syntax is "opcode hostname" */
776 if ((strlen(arg2)) != 0) {
777 fprintf(stderr, "[ %s ] Extraneous characters at end of line\n", rn);
782 he = GetHostByName(arg1);
784 fprintf(stderr, "[ %s ] Unable to resolve hostname %s\n", rn, arg1);
788 if ((strcasecmp(opcode, "fs")) == 0) {
789 /* use the complete host name to insert in the file server names list */
790 insert_FS(he->h_name);
791 /* note that last host entry in the config file was fs */
794 /* threholds are not global anymore */
795 if (global_ThreshFlag)
796 global_ThreshFlag = 0;
797 } else if ((strcasecmp(opcode, "cm")) == 0) {
798 /* use the complete host name to insert in the CM names list */
799 insert_CM(he->h_name);
800 /* last host entry in the config file was cm */
803 /* threholds are not global anymore */
804 if (global_ThreshFlag)
805 global_ThreshFlag = 0;
812 /*-----------------------------------------------------------------------
813 * parse_threshEntry()
816 * Parse the threshold entry line in the config file. This function is
817 * called in the the first pass of the config file. It checks the syntax
818 * of the config lines and verifies their positional validity - eg.,
819 * a cm threshold cannot appear after a fs hostname entry, etc.
820 * It also counts the thresholds applicable to each host.
826 *----------------------------------------------------------------------*/
829 parse_threshEntry(char *a_line)
830 { /* parse_threshEntry */
831 static char rn[] = "parse_threshEntry"; /* routine name */
832 char opcode[CFG_STR_LEN]; /* specifies type of config entry */
833 char arg1[CFG_STR_LEN]; /* hostname or qualifier (fs/cm?) */
834 char arg2[CFG_STR_LEN]; /* threshold variable */
835 char arg3[CFG_STR_LEN]; /* threshold value */
836 char arg4[CFG_STR_LEN]; /* user's handler */
837 char arg5[CFG_STR_LEN]; /* junk characters */
840 fprintf(debugFD, "[ %s ] Called, a_line = %s\n", rn, a_line);
851 sscanf(a_line, "%s %s %s %s %s %s", opcode, arg1, arg2, arg3, arg4, arg5);
853 /* syntax is "thresh fs/cm variable_name threshold_value [handler] " */
854 if (((strlen(arg1)) == 0) || ((strlen(arg2)) == 0)
855 || ((strlen(arg3)) == 0)) {
856 fprintf(stderr, "[ %s ] Incomplete line\n", rn);
859 if (strlen(arg3) > THRESH_VAR_LEN - 2) {
860 fprintf(stderr, "[%s ] threshold value too long\n", rn);
864 if ((strcasecmp(arg1, "fs")) == 0) {
865 switch (lastHostType) {
866 case 0: /* its a global threshold */
867 global_fsThreshCount++;
869 case 1: /* inc thresh count of last file server */
870 last_hostEntry->numThresh++;
874 "[ %s ] A threshold for a File Server cannot be placed after a Cache Manager host entry in the config file \n",
878 fprintf(stderr, "[ %s ] Programming error 1\n", rn);
881 } else if ((strcasecmp(arg1, "cm")) == 0) {
882 switch (lastHostType) {
883 case 0: /* its a global threshold */
884 global_cmThreshCount++;
886 case 2: /* inc thresh count of last cache manager */
887 last_hostEntry->numThresh++;
891 "[ %s ] A threshold for a Cache Manager cannot be placed after a File Server host entry in the config file \n",
895 fprintf(stderr, "[ %s ] Programming error 2\n", rn);
900 "[ %s ] Syntax error. Second argument should be \"fs\" or \"cm\" \n",
906 } /* parse_threshEntry */
909 /*-----------------------------------------------------------------------
913 * The thresholds applicable to each host machine are stored in the
914 * FSnameList and CMnameList. Threshold entries in the config file are
915 * context sensitive. The host to which this threshold is applicable
916 * is pointed to by last_fsHost (for file servers) and last_cmHost
917 * for cache managers. For global thresholds the info is recorded for
918 * all the hosts. This function is called in the second pass of the
919 * config file. In the first pass a count of the number of global
920 * thresholds is determined and this information is used in this
921 * routine. If threshold entries are duplicated the first entry is
923 * Each threshold entry also has an index field. This is a positional
924 * index to the corresponding variable in the prev_[fs/cm]Data arrays.
925 * This makes it easy to check the threshold for overflow.
930 *----------------------------------------------------------------------*/
933 store_threshold(int a_type, /* 1 = fs , 2 = cm */
934 char *a_varName, /* threshold name */
935 char *a_value, /* threshold value */
936 char *a_handler) /* threshold overflow handler */
937 { /* store_thresholds */
939 static char rn[] = "store_thresholds"; /* routine name */
940 struct afsmon_hostEntry *tmp_host; /* tmp ptr to hostEntry */
941 struct afsmon_hostEntry *Header; /* tmp ptr to hostEntry list header */
942 struct Threshold *threshP; /* tmp ptr to threshold list */
944 int index; /* index to fs_varNames or cm_varNames */
947 int srvCount; /* tmp count of host names */
948 int *global_TC; /* ptr to global_xxThreshCount */
953 "[ %s ] Called, a_type= %d, a_varName= %s, a_value= %s, a_handler=%s\n",
954 rn, a_type, a_varName, a_value, a_handler);
958 /* resolve the threshold variable name */
960 if (a_type == 1) { /* fs threshold */
961 for (index = 0; index < NUM_FS_STAT_ENTRIES; index++) {
962 if (strcasecmp(a_varName, fs_varNames[index]) == 0) {
968 fprintf(stderr, "[ %s ] Unknown FS threshold variable name %s\n",
974 hostname = last_fsHost;
975 global_TC = &global_fsThreshCount;
976 } else if (a_type == 2) { /* cm threshold */
977 for (index = 0; index < NUM_CM_STAT_ENTRIES; index++) {
978 if (strcasecmp(a_varName, cm_varNames[index]) == 0) {
984 fprintf(stderr, "[ %s ] Unknown CM threshold variable name %s\n",
990 hostname = last_cmHost;
991 global_TC = &global_cmThreshCount;
997 /* if the global thresh count is not zero, place this threshold on
998 * all the host entries */
1002 for (i = 0; i < srvCount; i++) {
1003 threshP = tmp_host->thresh;
1005 for (j = 0; j < tmp_host->numThresh; j++) {
1006 if ((threshP->itemName[0] == '\0')
1007 || (strcasecmp(threshP->itemName, a_varName) == 0)) {
1008 strncpy(threshP->itemName, a_varName,
1009 THRESH_VAR_NAME_LEN);
1010 strncpy(threshP->threshVal, a_value, THRESH_VAR_LEN);
1011 strcpy(threshP->handler, a_handler);
1012 threshP->index = index;
1019 fprintf(stderr, "[ %s ] Could not insert threshold entry",
1021 fprintf(stderr, "for %s in thresh list of host %s \n",
1022 a_varName, tmp_host->hostName);
1025 tmp_host = tmp_host->next;
1031 /* it is not a global threshold, insert it in the thresh list of this
1032 * host only. We overwrite the global threshold if it was alread set */
1034 if (*hostname == '\0') {
1035 fprintf(stderr, "[ %s ] Programming error 3\n", rn);
1039 /* get the hostEntry that this threshold belongs to */
1042 for (i = 0; i < srvCount; i++) {
1043 if (strcasecmp(tmp_host->hostName, hostname) == 0) {
1047 tmp_host = tmp_host->next;
1050 fprintf(stderr, "[ %s ] Unable to find host %s in %s hostEntry list",
1051 rn, hostname, (a_type - 1) ? "CM" : "FS");
1055 /* put this entry on the thresh list of this host, overwrite global value
1058 threshP = tmp_host->thresh;
1060 for (i = 0; i < tmp_host->numThresh; i++) {
1061 if ((threshP->itemName[0] == '\0')
1062 || (strcasecmp(threshP->itemName, a_varName) == 0)) {
1063 strncpy(threshP->itemName, a_varName, THRESH_VAR_NAME_LEN);
1064 strncpy(threshP->threshVal, a_value, THRESH_VAR_LEN);
1065 strcpy(threshP->handler, a_handler);
1066 threshP->index = index;
1075 "[ %s ] Unable to insert threshold %s for %s host %s\n", rn,
1076 a_varName, (a_type - 1) ? "CM" : "FS", tmp_host->hostName);
1082 } /* store_thresholds */
1085 /*-----------------------------------------------------------------------
1089 * This function process a "show" entry in the config file. A "show"
1090 * entry specifies what statistics the user wants to see. File
1091 * server and Cache Manager data is divided into sections. Each section
1092 * is made up of one or more groups. If a group name is specified only
1093 * those statistics under that group are shown. If a section name is
1094 * specified all the groups under this section are shown.
1095 * Data as obtained from the xstat probes is considered to be ordered.
1096 * This data is mapped to the screen thru fs_Display_map[] and
1097 * cm_Display_map[]. This routine parses the "show" entry against the
1098 * section/group names in the [fs/cm]_categories[] array. If there is
1099 * no match it tries to match it against a variable name in
1100 * [fs/cm]_varNames[] array. In each case the corresponding indices to
1101 * the data is the [fs/cm]_displayInfo[] is recorded.
1105 * Failure: -1 (invalid entry)
1106 * > -1 (programming error)
1107 *----------------------------------------------------------------------*/
1110 parse_showEntry(char *a_line)
1111 { /* parse_showEntry */
1112 static char rn[] = "parse_showEntry";
1113 char opcode[CFG_STR_LEN]; /* specifies type of config entry */
1114 char arg1[CFG_STR_LEN]; /* show fs or cm entry ? */
1115 char arg2[CFG_STR_LEN]; /* what we gotta show */
1116 char arg3[CFG_STR_LEN]; /* junk */
1117 char catName[CFG_STR_LEN]; /* for category names */
1118 int numGroups; /* number of groups in a section */
1122 int idx = 0; /* index to fs_categories[] */
1128 fprintf(debugFD, "[ %s ] Called, a_line= %s\n", rn, a_line);
1135 sscanf(a_line, "%s %s %s %s", opcode, arg1, arg2, arg3);
1137 if (arg3[0] != '\0') {
1138 fprintf(stderr, "[ %s ] Extraneous characters at end of line\n", rn);
1142 if ((strcasecmp(arg1, "fs") != 0) && (strcasecmp(arg1, "cm") != 0)) {
1144 "[ %s ] Second argument of \"show\" directive should be \"fs\" or \"cm\" \n",
1149 /* Each entry can either be a variable name or a section/group name. Variable
1150 * names are listed in xx_varNames[] and section/group names in xx_categories[].
1151 * The section/group names in xx_categiries[] also give the starting/ending
1152 * indices of the variables belonging to that section/group. These indices
1153 * are stored in order in xx_Display_map[] and displayed to the screen in that
1156 /* To handle duplicate "show" entries we keep track of what what we have
1157 * already marked to show in the xx_showFlags[] */
1159 if (strcasecmp(arg1, "fs") == 0) { /* its a File Server entry */
1161 /* mark that we have to show only what the user wants */
1164 /* if it is a section/group name, find it in the fs_categories[] array */
1167 if (strcasestr(arg2, "_section") != (char *)NULL
1168 || strcasestr(arg2, "_group") != (char *)NULL) {
1170 while (idx < FS_NUM_DATA_CATEGORIES) {
1171 sscanf(fs_categories[idx], "%s %d %d", catName, &fromIdx,
1174 if (strcasecmp(arg2, catName) == 0) {
1180 if (!found) { /* typo in section/group name */
1182 "[ %s ] Could not find section/group name %s\n", rn,
1188 /* if it is a group name, read its start/end indices and fill in the
1189 * fs_Display_map[]. */
1191 if (strcasestr(arg2, "_group") != (char *)NULL) {
1193 if (fromIdx < 0 || toIdx < 0 || fromIdx > NUM_FS_STAT_ENTRIES
1194 || toIdx > NUM_FS_STAT_ENTRIES)
1196 for (j = fromIdx; j <= toIdx; j++) {
1197 if (!fs_showFlags[j]) {
1198 fs_Display_map[fs_DisplayItems_count] = j;
1199 fs_DisplayItems_count++;
1200 fs_showFlags[j] = 1;
1202 if (fs_DisplayItems_count > NUM_FS_STAT_ENTRIES) {
1203 fprintf(stderr, "[ %s ] fs_DisplayItems_count ovf\n", rn);
1208 /* if it is a section name, get the count of number of groups in it and
1209 * for each group fill in the start/end indices in the fs_Display_map[] */
1211 if (strcasestr(arg2, "_section") != (char *)NULL) {
1212 /* fromIdx is actually the number of groups in thi section */
1213 numGroups = fromIdx;
1214 /* for each group in section */
1215 while (idx < FS_NUM_DATA_CATEGORIES && numGroups) {
1216 sscanf(fs_categories[idx], "%s %d %d", catName, &fromIdx,
1219 if (strcasestr(catName, "_group") != NULL) {
1220 if (fromIdx < 0 || toIdx < 0
1221 || fromIdx > NUM_FS_STAT_ENTRIES
1222 || toIdx > NUM_FS_STAT_ENTRIES)
1224 for (j = fromIdx; j <= toIdx; j++) {
1225 if (!fs_showFlags[j]) {
1226 fs_Display_map[fs_DisplayItems_count] = j;
1227 fs_DisplayItems_count++;
1228 fs_showFlags[j] = 1;
1230 if (fs_DisplayItems_count > NUM_FS_STAT_ENTRIES) {
1232 "[ %s ] fs_DisplayItems_count ovf\n", rn);
1237 fprintf(stderr, "[ %s ] Error parsing groups for %s\n",
1243 } /* for each group in section */
1246 } else { /* it is a variable name */
1248 for (i = 0; i < NUM_FS_STAT_ENTRIES; i++) {
1249 if (strcasecmp(arg2, fs_varNames[i]) == 0) {
1250 if (!fs_showFlags[i]) {
1251 fs_Display_map[fs_DisplayItems_count] = i;
1252 fs_DisplayItems_count++;
1253 fs_showFlags[i] = 1;
1255 if (fs_DisplayItems_count >= NUM_FS_STAT_ENTRIES) {
1256 fprintf(stderr, "[ %s ] fs_DisplayItems_count ovf\n",
1263 if (!found) { /* typo in section/group name */
1264 fprintf(stderr, "[ %s ] Could not find variable name %s\n",
1268 } /* its a variable name */
1272 /* it is an fs entry */
1273 if (strcasecmp(arg1, "cm") == 0) { /* its a Cache Manager entry */
1276 /* mark that we have to show only what the user wants */
1279 /* if it is a section/group name, find it in the cm_categories[] array */
1282 if (strcasestr(arg2, "_section") != (char *)NULL
1283 || strcasestr(arg2, "_group") != (char *)NULL) {
1285 while (idx < CM_NUM_DATA_CATEGORIES) {
1286 sscanf(cm_categories[idx], "%s %d %d", catName, &fromIdx,
1289 if (strcasecmp(arg2, catName) == 0) {
1295 if (!found) { /* typo in section/group name */
1297 "[ %s ] Could not find section/group name %s\n", rn,
1303 /* if it is a group name, read its start/end indices and fill in the
1304 * cm_Display_map[]. */
1306 if (strcasestr(arg2, "_group") != (char *)NULL) {
1308 if (fromIdx < 0 || toIdx < 0 || fromIdx > NUM_CM_STAT_ENTRIES
1309 || toIdx > NUM_CM_STAT_ENTRIES)
1311 for (j = fromIdx; j <= toIdx; j++) {
1312 if (!cm_showFlags[j]) {
1313 cm_Display_map[cm_DisplayItems_count] = j;
1314 cm_DisplayItems_count++;
1315 cm_showFlags[j] = 1;
1317 if (cm_DisplayItems_count > NUM_CM_STAT_ENTRIES) {
1318 fprintf(stderr, "[ %s ] cm_DisplayItems_count ovf\n", rn);
1323 /* if it is a section name, get the count of number of groups in it and
1324 * for each group fill in the start/end indices in the cm_Display_map[] */
1326 if (strcasestr(arg2, "_section") != (char *)NULL) {
1327 /* fromIdx is actually the number of groups in thi section */
1328 numGroups = fromIdx;
1329 /* for each group in section */
1330 while (idx < CM_NUM_DATA_CATEGORIES && numGroups) {
1331 sscanf(cm_categories[idx], "%s %d %d", catName, &fromIdx,
1334 if (strcasestr(catName, "_group") != NULL) {
1335 if (fromIdx < 0 || toIdx < 0
1336 || fromIdx > NUM_CM_STAT_ENTRIES
1337 || toIdx > NUM_CM_STAT_ENTRIES)
1339 for (j = fromIdx; j <= toIdx; j++) {
1340 if (!cm_showFlags[j]) {
1341 cm_Display_map[cm_DisplayItems_count] = j;
1342 cm_DisplayItems_count++;
1343 cm_showFlags[j] = 1;
1345 if (cm_DisplayItems_count > NUM_CM_STAT_ENTRIES) {
1347 "[ %s ] cm_DisplayItems_count ovf\n", rn);
1352 fprintf(stderr, "[ %s ] Error parsing groups for %s\n",
1358 } /* for each group in section */
1359 } else { /* it is a variable name */
1361 for (i = 0; i < NUM_CM_STAT_ENTRIES; i++) {
1362 if (strcasecmp(arg2, cm_varNames[i]) == 0) {
1363 if (!cm_showFlags[i]) {
1364 cm_Display_map[cm_DisplayItems_count] = i;
1365 cm_DisplayItems_count++;
1366 cm_showFlags[i] = 1;
1368 if (cm_DisplayItems_count >= NUM_CM_STAT_ENTRIES) {
1369 fprintf(stderr, "[ %s ] cm_DisplayItems_count ovf\n",
1376 if (!found) { /* typo in section/group name */
1377 fprintf(stderr, "[ %s ] Could not find variable name %s\n",
1381 } /* its a variable name */
1384 /* it is an cm entry */
1386 } /* parse_showEntry */
1389 /*-----------------------------------------------------------------------
1390 * process_config_file()
1393 * Parse config file entries in two passes. In the first pass:
1394 * - the syntax of all the entries is checked
1395 * - host names are noted and the FSnamesList and CMnamesList
1397 * - a count of the global thresholds and local thresholds of
1398 * each host are counted.
1399 * - "show" entries are processed.
1400 * In the second pass:
1401 * - thresholds are stored
1405 * Failure: Exits afsmonitor showing error and line.
1406 *----------------------------------------------------------------------*/
1409 process_config_file(char *a_config_filename)
1410 { /* process_config_file() */
1411 static char rn[] = "process_config_file"; /* routine name */
1412 FILE *configFD; /* config file descriptor */
1413 char line[4 * CFG_STR_LEN]; /* a line of config file */
1414 char opcode[CFG_STR_LEN]; /* specifies type of config entry */
1415 char arg1[CFG_STR_LEN]; /* hostname or qualifier (fs/cm?) */
1416 char arg2[CFG_STR_LEN]; /* threshold variable */
1417 char arg3[CFG_STR_LEN]; /* threshold value */
1418 char arg4[CFG_STR_LEN]; /* user's handler */
1419 struct afsmon_hostEntry *curr_host;
1420 struct hostent *he; /* hostentry to resolve host name */
1421 char *handlerPtr; /* ptr to pass theresh handler string */
1422 int code = 0; /* error code */
1423 int linenum = 0; /* config file line number */
1424 int threshCount; /* count of thresholds for each server */
1425 int error_in_config; /* syntax errors in config file ?? */
1430 fprintf(debugFD, "[ %s ] Called, a_config_filename= %s\n", rn,
1435 /* open config file */
1437 configFD = fopen(a_config_filename, "r");
1438 if (configFD == (FILE *) 0) {
1439 fprintf(stderr, "Failed to open config file %s \n",
1442 fprintf(debugFD, "[ %s ] Failed to open config file %s \n", rn,
1449 /* parse config file */
1451 /* We process the config file in two passes. In the first pass we check
1452 * for correct syntax and for valid entries and also keep count of the
1453 * number of servers and thresholds to monitor. This the data strctures
1454 * can be arrays instead of link lists since we would know their sizes. */
1461 error_in_config = 0; /* flag to note if config file has syntax errors */
1463 while ((fgets(line, CFG_STR_LEN, configFD)) != NULL) {
1469 sscanf(line, "%s %s %s %s %s", opcode, arg1, arg2, arg3, arg4);
1471 /* skip blank lines and comment lines */
1472 if ((strlen(opcode) == 0) || line[0] == '#')
1475 if ((strcasecmp(opcode, "fs") == 0)
1476 || (strcasecmp(opcode, "cm")) == 0) {
1477 code = parse_hostEntry(line);
1478 } else if ((strcasecmp(opcode, "thresh")) == 0) {
1479 code = parse_threshEntry(line);
1480 } else if ((strcasecmp(opcode, "show")) == 0) {
1481 code = parse_showEntry(line);
1483 fprintf(stderr, "[ %s ] Unknown opcode %s\n", rn, opcode);
1488 fprintf(stderr, "[ %s ] Error in line:\n %d: %s\n", rn, linenum,
1490 error_in_config = 1;
1494 if (error_in_config)
1498 fprintf(debugFD, "Global FS thresholds count = %d\n",
1499 global_fsThreshCount);
1500 fprintf(debugFD, "Global CM thresholds count = %d\n",
1501 global_cmThreshCount);
1505 /* the threshold count of all hosts in increased by 1 for each global
1506 * threshold. If one of the hosts has a local threshold for the same
1507 * variable it would end up being counted twice. whats a few bytes of memory
1508 * wasted anyway ? */
1510 if (global_fsThreshCount) {
1511 curr_host = FSnameList;
1512 for (i = 0; i < numFS; i++) {
1513 curr_host->numThresh += global_fsThreshCount;
1514 curr_host = curr_host->next;
1517 if (global_cmThreshCount) {
1518 curr_host = CMnameList;
1519 for (i = 0; i < numCM; i++) {
1520 curr_host->numThresh += global_cmThreshCount;
1521 curr_host = curr_host->next;
1526 /* make sure we have something to monitor */
1527 if (numFS == 0 && numCM == 0) {
1529 "\nConfig file must specify atleast one File Server or Cache Manager host to monitor.\n");
1536 fseek(configFD, 0, 0); /* seek to the beginning */
1539 /* allocate memory for threshold lists */
1540 curr_host = FSnameList;
1541 for (i = 0; i < numFS; i++) {
1542 if (curr_host->hostName[0] == '\0') {
1543 fprintf(stderr, "[ %s ] Programming error 4\n", rn);
1546 if (curr_host->numThresh) {
1547 numBytes = curr_host->numThresh * sizeof(struct Threshold);
1548 curr_host->thresh = (struct Threshold *)malloc(numBytes);
1549 if (curr_host->thresh == NULL) {
1550 fprintf(stderr, "[ %s ] Memory Allocation error 1", rn);
1553 memset(curr_host->thresh, 0, numBytes);
1555 curr_host = curr_host->next;;
1558 curr_host = CMnameList;
1559 for (i = 0; i < numCM; i++) {
1560 if (curr_host->hostName[0] == '\0') {
1561 fprintf(stderr, "[ %s ] Programming error 5\n", rn);
1564 if (curr_host->numThresh) {
1565 numBytes = curr_host->numThresh * sizeof(struct Threshold);
1566 curr_host->thresh = (struct Threshold *)malloc(numBytes);
1567 if (curr_host->thresh == NULL) {
1568 fprintf(stderr, "[ %s ] Memory Allocation error 2", rn);
1571 memset(curr_host->thresh, 0, numBytes);
1573 curr_host = curr_host->next;;
1582 last_fsHost[0] = '\0';
1583 last_cmHost[0] = '\0';
1585 while ((fgets(line, CFG_STR_LEN, configFD)) != NULL) {
1591 sscanf(line, "%s %s %s %s %s", opcode, arg1, arg2, arg3, arg4);
1594 /* if we have a host entry, remember the host name */
1595 if (strcasecmp(opcode, "fs") == 0) {
1596 he = GetHostByName(arg1);
1597 strncpy(last_fsHost, he->h_name, HOST_NAME_LEN);
1598 } else if (strcasecmp(opcode, "cm") == 0) {
1599 he = GetHostByName(arg1);
1600 strncpy(last_cmHost, he->h_name, HOST_NAME_LEN);
1601 } else if (strcasecmp(opcode, "thresh") == 0) {
1602 /* if we have a threshold handler it may have arguments
1603 * and the sscanf() above would not get them, so do the
1607 /* now skip over 4 words - this is done by first
1608 * skipping leading blanks then skipping a word */
1609 for (i = 0; i < 4; i++) {
1610 while (isspace(*handlerPtr))
1612 while (!isspace(*handlerPtr))
1615 while (isspace(*handlerPtr))
1617 /* we how have a pointer to the start of the handler
1620 handlerPtr = arg4; /* empty string */
1623 if (strcasecmp(arg1, "fs") == 0)
1624 code = store_threshold(1, /* 1 = fs */
1625 arg2, arg3, handlerPtr);
1627 else if (strcasecmp(arg1, "cm") == 0)
1628 code = store_threshold(2, /* 2 = fs */
1629 arg2, arg3, handlerPtr);
1632 fprintf(stderr, "[ %s ] Programming error 6\n", rn);
1636 fprintf(stderr, "[ %s ] Failed to store threshold\n", rn);
1637 fprintf(stderr, "[ %s ] Error processing line:\n%d: %s", rn,
1649 /*-----------------------------------------------------------------------
1654 * Print the File Server circular buffer.
1658 *----------------------------------------------------------------------*/
1662 { /* Print_FS_CB() */
1664 struct afsmon_fs_Results_list *fslist;
1669 /* print valid info in the fs CB */
1673 "==================== FS Buffer ========================\n");
1674 fprintf(debugFD, "afsmon_fs_curr_CBindex = %d\n",
1675 afsmon_fs_curr_CBindex);
1676 fprintf(debugFD, "afsmon_fs_curr_probeNum = %d\n\n",
1677 afsmon_fs_curr_probeNum);
1679 for (i = 0; i < num_bufSlots; i++) {
1680 fprintf(debugFD, "\t--------- slot %d ----------\n", i);
1681 fslist = afsmon_fs_ResultsCB[i].list;
1684 for (k = 0; k < MAX_NUM_FS_COLLECTIONS; k++) {
1685 if (!(fslist->empty[k])) {
1686 fprintf(debugFD, "\t %d) probeNum = %d host = %s cn = %d",
1688 fslist->fsResults[k]->probeNum,
1689 fslist->fsResults[k]->connP->hostName,
1690 fslist->fsResults[k]->collectionNumber);
1691 if (fslist->fsResults[k]->probeOK)
1692 fprintf(debugFD, " NOTOK\n");
1694 fprintf(debugFD, " OK\n");
1696 fprintf(debugFD, "\t %d) -- empty --\n", j);
1698 fslist = fslist->next;
1701 if (fslist != (struct afsmon_fs_Results_list *)0)
1702 fprintf(debugFD, "dangling last next ptr fs CB\n");
1705 } /* Print_FS_CB() */
1707 /*-----------------------------------------------------------------------
1708 * save_FS_results_inCB()
1711 * Saves the results of the latest FS probe in the fs circular
1712 * buffers. If the current probe cycle is in progress the contents
1713 * of xstat_fs_Results are copied to the end of the list of results
1714 * in the current slot (pointed to by afsmon_fs_curr_CBindex). If
1715 * a new probe cycle has started the next slot in the circular buffer
1716 * is initialized and the results copied. Note that the Rx related
1717 * information available in xstat_fs_Results is not copied.
1721 * Failure: Exits afsmonitor.
1722 *----------------------------------------------------------------------*/
1724 save_FS_results_inCB(int a_newProbeCycle) /* start of a new probe cycle ? */
1725 { /* save_FS_results_inCB() */
1726 static char rn[] = "save_FS_results_inCB"; /* routine name */
1727 struct afsmon_fs_Results_list *tmp_fslist_item; /* temp fs list item */
1728 struct xstat_fs_ProbeResults *tmp_fsPR; /* temp ptr */
1733 fprintf(debugFD, "[ %s ] Called, a_newProbeCycle= %d\n", rn,
1738 switch (xstat_fs_Results.collectionNumber) {
1739 case AFS_XSTATSCOLL_FULL_PERF_INFO:
1742 case AFS_XSTATSCOLL_CBSTATS:
1746 fprintf(stderr, "[ %s ] collection number %d is out of range.\n",
1747 rn, xstat_fs_Results.collectionNumber);
1752 /* If a new probe cycle started, mark the list in the current buffer
1753 * slot empty for resuse. Note that afsmon_fs_curr_CBindex was appropriately
1754 * incremented in afsmon_FS_Handler() */
1756 if (a_newProbeCycle) {
1757 tmp_fslist_item = afsmon_fs_ResultsCB[afsmon_fs_curr_CBindex].list;
1758 for (i = 0; i < numFS; i++) {
1759 tmp_fslist_item->empty[index] = 1;
1760 tmp_fslist_item = tmp_fslist_item->next;
1764 /* locate last unused item in list */
1765 tmp_fslist_item = afsmon_fs_ResultsCB[afsmon_fs_curr_CBindex].list;
1766 for (i = 0; i < numFS; i++) {
1767 if (tmp_fslist_item->empty[index])
1769 tmp_fslist_item = tmp_fslist_item->next;
1772 /* if we could not find one we have an inconsistent list */
1773 if (!tmp_fslist_item->empty[index]) {
1775 "[ %s ] list inconsistency 1. unable to find an empty slot to store results of probenum %d of %s\n",
1776 rn, xstat_fs_Results.probeNum,
1777 xstat_fs_Results.connP->hostName);
1781 tmp_fsPR = tmp_fslist_item->fsResults[index];
1783 /* copy hostname and probe number and probe time and probe status.
1784 * if the probe failed return now */
1786 memcpy(tmp_fsPR->connP->hostName, xstat_fs_Results.connP->hostName,
1787 sizeof(xstat_fs_Results.connP->hostName));
1788 tmp_fsPR->probeNum = xstat_fs_Results.probeNum;
1789 tmp_fsPR->probeTime = xstat_fs_Results.probeTime;
1790 tmp_fsPR->probeOK = xstat_fs_Results.probeOK;
1791 if (xstat_fs_Results.probeOK) { /* probeOK = 1 => notOK */
1792 /* we have a nonempty results structure so mark the list item used */
1793 tmp_fslist_item->empty[index] = 0;
1797 /* copy connection information */
1798 memcpy(&(tmp_fsPR->connP->skt), &(xstat_fs_Results.connP->skt),
1799 sizeof(struct sockaddr_in));
1801 memcpy(tmp_fsPR->connP->hostName, xstat_fs_Results.connP->hostName,
1802 sizeof(xstat_fs_Results.connP->hostName));
1803 tmp_fsPR->collectionNumber = xstat_fs_Results.collectionNumber;
1805 /* copy the probe data information */
1806 tmp_fsPR->data.AFS_CollData_len =
1807 min(xstat_fs_Results.data.AFS_CollData_len,
1808 afsmon_fs_results_length[index]);
1809 memcpy(tmp_fsPR->data.AFS_CollData_val,
1810 xstat_fs_Results.data.AFS_CollData_val,
1811 tmp_fsPR->data.AFS_CollData_len * sizeof(afs_int32));
1814 /* we have a valid results structure so mark the list item used */
1815 tmp_fslist_item->empty[index] = 0;
1817 /* Print the fs circular buffer */
1821 } /* save_FS_results_inCB() */
1824 /*-----------------------------------------------------------------------
1828 * The results of xstat probes are stored in a string format in
1829 * the arrays curr_fsData and prev_fsData. The information stored in
1830 * prev_fsData is copied to the screen.
1831 * This function converts xstat FS results from longs to strings and
1832 * place them in the given buffer (a pointer to an item in curr_fsData).
1833 * When a probe cycle completes, curr_fsData is copied to prev_fsData
1834 * in afsmon_FS_Hnadler().
1838 *----------------------------------------------------------------------*/
1841 fs_Results_ltoa(struct fs_Display_Data *a_fsData, /* target buffer */
1842 struct xstat_fs_ProbeResults *a_fsResults) /* ptr to xstat fs Results */
1843 { /* fs_Results_ltoa */
1845 static char rn[] = "fs_Results_ltoa"; /* routine name */
1848 fprintf(debugFD, "[ %s ] Called, a_fsData= %p, a_fsResults= %p\n", rn,
1849 a_fsData, a_fsResults);
1853 switch (a_fsResults->collectionNumber) {
1854 case AFS_XSTATSCOLL_FULL_PERF_INFO:
1855 fs_FullPerfs_ltoa(a_fsData, a_fsResults);
1857 case AFS_XSTATSCOLL_CBSTATS:
1858 fs_CallBackStats_ltoa(a_fsData, a_fsResults);
1862 fprintf(debugFD, "[ %s ] Unexpected collection id %d\n",
1863 rn, a_fsResults->collectionNumber);
1868 } /* fs_Results_ltoa */
1870 /*-----------------------------------------------------------------------
1871 * fs_FullPerfs_ltoa()
1874 * Convert the full perf xstat collection from int32s to strings.
1878 *----------------------------------------------------------------------*/
1880 fs_FullPerfs_ltoa(struct fs_Display_Data *a_fsData,
1881 struct xstat_fs_ProbeResults *a_fsResults)
1884 struct fs_stats_FullPerfStats *fullPerfP;
1888 afs_int32 numInt32s;
1890 fullPerfP = (struct fs_stats_FullPerfStats *)
1891 (a_fsResults->data.AFS_CollData_val);
1893 /* there are two parts to the xstat FS statistics
1894 * - fullPerfP->overall which give the overall performance statistics, and
1895 * - fullPerfP->det which gives detailed info about file server operation
1896 * execution times */
1899 * Unfortunately, the full perf stats contain timeval structures which
1900 * do not have the same size everywhere. Avoid displaying gargbage,
1901 * but at least try to show the overall stats.
1903 numInt32s = a_fsResults->data.AFS_CollData_len;
1905 (sizeof(struct fs_stats_FullPerfStats) / sizeof(afs_int32))) {
1906 srcbuf = a_fsResults->data.AFS_CollData_val;
1907 for (i = 0; i < NUM_FS_STAT_ENTRIES; i++) {
1908 if (i < numInt32s && i < NUM_XSTAT_FS_AFS_PERFSTATS_LONGS) {
1909 sprintf(a_fsData->data[i], "%d", srcbuf[i]);
1911 sprintf(a_fsData->data[i], "%s", "--");
1917 /* copy overall performance statistics */
1918 srcbuf = (afs_int32 *) & (fullPerfP->overall);
1920 for (i = 0; i < NUM_XSTAT_FS_AFS_PERFSTATS_LONGS; i++) {
1921 sprintf(a_fsData->data[idx], "%d", *srcbuf);
1927 srcbuf = (afs_int32 *) & (fullPerfP->det.epoch);
1928 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* epoch */
1931 /* copy fs operation timing */
1933 srcbuf = (afs_int32 *) (fullPerfP->det.rpcOpTimes);
1935 for (i = 0; i < FS_STATS_NUM_RPC_OPS; i++) {
1936 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* numOps */
1939 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* numSuccesses */
1942 tmpbuf = srcbuf++; /* sum time */
1943 sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1946 tmpbuf = srcbuf++; /* sqr time */
1947 sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1950 tmpbuf = srcbuf++; /* min time */
1951 sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1954 tmpbuf = srcbuf++; /* max time */
1955 sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1960 /* copy fs transfer timings */
1962 srcbuf = (afs_int32 *) (fullPerfP->det.xferOpTimes);
1963 for (i = 0; i < FS_STATS_NUM_XFER_OPS; i++) {
1964 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* numOps */
1967 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* numSuccesses */
1970 tmpbuf = srcbuf++; /* sum time */
1971 sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1974 tmpbuf = srcbuf++; /* sqr time */
1975 sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1978 tmpbuf = srcbuf++; /* min time */
1979 sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1982 tmpbuf = srcbuf++; /* max time */
1983 sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1986 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* sum bytes */
1989 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* min bytes */
1992 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* max bytes */
1995 for (j = 0; j < FS_STATS_NUM_XFER_BUCKETS; j++) {
1996 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* bucket[j] */
2005 /*-----------------------------------------------------------------------
2006 * fs_CallBackStats_ltoa()
2009 * Convert the callback counter xstat collection from
2010 * int32s to strings.
2014 *----------------------------------------------------------------------*/
2017 fs_CallBackStats_ltoa(struct fs_Display_Data *a_fsData,
2018 struct xstat_fs_ProbeResults *a_fsResults)
2022 int len = a_fsResults->data.AFS_CollData_len;
2023 afs_int32 *val = a_fsResults->data.AFS_CollData_val;
2025 /* place callback stats after the full perf stats */
2026 idx = NUM_FS_FULLPERF_ENTRIES;
2027 for (i=0; i < len && i < NUM_FS_CB_ENTRIES; i++) {
2028 sprintf(a_fsData->data[idx++], "%u", val[i]);
2033 /*-----------------------------------------------------------------------
2034 * execute_thresh_handler()
2037 * Execute a threshold handler. An agrv[] array of pointers is
2038 * constructed from the given data. A child process is forked
2039 * which immediately calls afsmon_Exit() with indication that a
2040 * threshold handler is to be exec'ed insted of exiting.
2044 * Failure: Afsmonitor exits if threshold handler has more than 20 args.
2045 *----------------------------------------------------------------------*/
2048 execute_thresh_handler(char *a_handler, /* ptr to handler function + args */
2049 char *a_hostName, /* host name for which threshold crossed */
2050 int a_hostType, /* fs or cm ? */
2051 char *a_threshName, /* threshold variable name */
2052 char *a_threshValue, /* threshold value */
2053 char *a_actValue) /* actual value */
2054 { /* execute_thresh_handler */
2056 static char rn[] = "execute_thresh_handler";
2057 char fileName[256]; /* file name to execute */
2062 int anotherArg; /* boolean used to flag if another arg is available */
2066 "[ %s ] Called, a_handler= %s, a_hostName= %s, a_hostType= %d, a_threshName= %s, a_threshValue= %s, a_actValue= %s\n",
2067 rn, a_handler, a_hostName, a_hostType, a_threshName,
2068 a_threshValue, a_actValue);
2073 /* get the filename to execute - the first argument */
2074 sscanf(a_handler, "%s", fileName);
2076 /* construct the contents of *argv[] */
2078 strncpy(fsHandler_args[0], fileName, 256);
2079 strncpy(fsHandler_args[1], a_hostName, HOST_NAME_LEN);
2080 if (a_hostType == FS)
2081 strcpy(fsHandler_args[2], "fs");
2083 strcpy(fsHandler_args[2], "cm");
2084 strncpy(fsHandler_args[3], a_threshName, THRESH_VAR_NAME_LEN);
2085 strncpy(fsHandler_args[4], a_threshValue, THRESH_VAR_LEN);
2086 strncpy(fsHandler_args[5], a_actValue, THRESH_VAR_LEN);
2093 /* we have already extracted the file name so skip to the 1st arg */
2094 while (isspace(*ch)) /* leading blanks */
2096 while (!isspace(*ch) && *ch != '\0') /* handler filename */
2099 while (*ch != '\0') {
2102 } else if (anotherArg) {
2104 sscanf(ch, "%s", fsHandler_args[argNum]);
2110 "Threshold handlers cannot have more than 20 arguments\n");
2116 fsHandler_argv[argNum] = NULL;
2117 for (i = 0; i < argNum; i++)
2118 fsHandler_argv[i] = fsHandler_args[i];
2121 /* exec the threshold handler */
2124 exec_fsThreshHandler = 1;
2125 code = afsmon_Exit(60);
2129 } /* execute_thresh_handler */
2133 /*-----------------------------------------------------------------------
2134 * check_fs_thresholds()
2137 * Checks the thresholds and sets the overflow flag. Recall that the
2138 * thresholds for each host are stored in the hostEntry lists
2139 * [fs/cm]nameList arrays. The probe results are passed to this
2140 * function in the display-ready format - ie., as strings. Though
2141 * this looks stupid the overhead incurred in converting the strings
2142 * back to floats and comparing them is insignificant and
2143 * programming is easier this way.
2144 * The threshold flags are a part of the display structures
2149 *----------------------------------------------------------------------*/
2152 check_fs_thresholds(struct afsmon_hostEntry *a_hostEntry, /* ptr to hostEntry */
2153 struct fs_Display_Data *a_Data) /* ptr to fs data to be displayed */
2154 { /* check_fs_thresholds */
2156 static char rn[] = "check_fs_thresholds";
2157 struct Threshold *threshP;
2158 double tValue; /* threshold value */
2159 double pValue; /* probe value */
2162 int count; /* number of thresholds exceeded */
2165 fprintf(debugFD, "[ %s ] Called, a_hostEntry= %p, a_Data= %p\n", rn,
2166 a_hostEntry, a_Data);
2170 if (a_hostEntry->numThresh == 0) {
2171 /* store in ovf count ?? */
2176 threshP = a_hostEntry->thresh;
2177 for (i = 0; i < a_hostEntry->numThresh; i++) {
2178 if (threshP->itemName[0] == '\0') {
2182 idx = threshP->index; /* positional index to the data array */
2183 tValue = atof(threshP->threshVal); /* threshold value */
2184 pValue = atof(a_Data->data[idx]); /* probe value */
2185 if (pValue > tValue) {
2189 "[ %s ] fs = %s, thresh ovf for %s, threshold= %s, probevalue= %s\n",
2190 rn, a_hostEntry->hostName, threshP->itemName,
2191 threshP->threshVal, a_Data->data[idx]);
2194 /* if the threshold is crossed, call the handler function
2195 * only if this was a transition -ie, if the threshold was
2196 * crossed in the last probe too just count & keep quite! */
2198 if (!a_Data->threshOvf[idx]) {
2199 a_Data->threshOvf[idx] = 1;
2200 /* call the threshold handler if provided */
2201 if (threshP->handler[0] != '\0') {
2203 fprintf(debugFD, "[ %s ] Calling ovf handler %s\n",
2204 rn, threshP->handler);
2207 execute_thresh_handler(threshP->handler, a_Data->hostName,
2208 FS, threshP->itemName,
2216 /* in case threshold was previously crossed, blank it out */
2217 a_Data->threshOvf[idx] = 0;
2220 /* store the overflow count */
2221 a_Data->ovfCount = count;
2224 } /* check_fs_thresholds */
2227 /*-----------------------------------------------------------------------
2228 * save_FS_data_forDisplay()
2231 * Does the following:
2232 * - if the probe number changed (ie, a cycle completed) curr_fsData
2233 * is copied to prev_fsData, curr_fsData zeroed and refresh the
2234 * overview screen and file server screen with the new data.
2235 * - store the results of the current probe from xstat_fs_Results into
2236 * curr_fsData. ie., convert longs to strings.
2237 * - check the thresholds
2241 * Failure: Exits afsmonitor.
2242 *----------------------------------------------------------------------*/
2245 save_FS_data_forDisplay(struct xstat_fs_ProbeResults *a_fsResults)
2246 { /* save_FS_data_forDisplay */
2248 static char rn[] = "save_FS_data_forDisplay"; /* routine name */
2249 struct fs_Display_Data *curr_fsDataP; /* tmp ptr to curr_fsData */
2250 struct fs_Display_Data *prev_fsDataP; /* tmp ptr to prev_fsData */
2251 struct afsmon_hostEntry *curr_host;
2252 static int results_Received = 0; /* number of probes reveived in
2253 * the current cycle. If this is equal to numFS we got all
2254 * the data we want in this cycle and can now display it */
2263 fprintf(debugFD, "[ %s ] Called, a_fsResults= %p\n", rn, a_fsResults);
2267 /* store results in the display array */
2270 curr_fsDataP = curr_fsData;
2271 for (i = 0; i < numFS; i++) {
2272 if ((strcasecmp(curr_fsDataP->hostName, a_fsResults->connP->hostName))
2282 "[ %s ] Could not insert FS probe results for host %s in fs display array\n",
2283 rn, a_fsResults->connP->hostName);
2287 /* Check the status of the probe. If it succeeded, we store its
2288 * results in the display data structure. If it failed we only mark
2289 * the failed status in the display data structure. */
2291 if (a_fsResults->probeOK) { /* 1 => notOK the xstat results */
2292 curr_fsDataP->probeOK = 0;
2294 /* print the probe status */
2296 fprintf(debugFD, "\n\t\t ----- fs display data ------\n");
2297 fprintf(debugFD, "HostName = %s PROBE FAILED \n",
2298 curr_fsDataP->hostName);
2302 } else { /* probe succeeded, update display data structures */
2303 curr_fsDataP->probeOK = 1;
2305 /* convert longs to strings and place them in curr_fsDataP */
2306 fs_Results_ltoa(curr_fsDataP, a_fsResults);
2308 /* compare with thresholds and set the overflow flags.
2309 * note that the threshold information is in the hostEntry structure and
2310 * each threshold item has a positional index associated with it */
2312 /* locate the hostEntry for this host */
2314 curr_host = FSnameList;
2315 for (i = 0; i < numFS; i++) {
2316 if (strcasecmp(curr_host->hostName, a_fsResults->connP->hostName)
2321 curr_host = curr_host->next;;
2326 code = check_fs_thresholds(curr_host, curr_fsDataP);
2328 fprintf(stderr, "[ %s ] Error in checking thresholds\n", rn);
2332 /* print the info we just saved */
2335 fprintf(debugFD, "\n\t\t ----- fs display data ------\n");
2336 fprintf(debugFD, "HostName = %s\n", curr_fsDataP->hostName);
2337 for (i = 0; i < NUM_FS_STAT_ENTRIES; i++)
2338 fprintf(debugFD, "%20s %30s %s\n", curr_fsDataP->data[i],
2340 curr_fsDataP->threshOvf[i] ? "(ovf)" : "");
2342 fprintf(debugFD, "\t\t--------------------------------\n\n");
2346 } /* the probe succeeded, so we store the data in the display structure */
2349 /* if we have received a reply from all the hosts for this probe cycle,
2350 * it is time to display the data */
2353 if (results_Received == numFS * num_fs_collections) {
2354 results_Received = 0;
2356 if (afsmon_fs_curr_probeNum != afsmon_fs_prev_probeNum + 1) {
2357 sprintf(errMsg, "[ %s ] Probe number %d missed! \n", rn,
2358 afsmon_fs_prev_probeNum + 1);
2361 afsmon_fs_prev_probeNum++;
2363 /* backup the display data of the probe cycle that just completed -
2364 * ie., store curr_fsData in prev_fsData */
2366 memcpy((char *)prev_fsData, (char *)curr_fsData,
2367 (numFS * sizeof(struct fs_Display_Data)));
2370 /* initialize curr_fsData but retain the threshold flag information.
2371 * The previous state of threshold flags is used in check_fs_thresholds() */
2373 numBytes = NUM_FS_STAT_ENTRIES * FS_STAT_STRING_LEN;
2374 curr_fsDataP = curr_fsData;
2375 for (i = 0; i < numFS; i++) {
2376 curr_fsDataP->probeOK = 0;
2377 curr_fsDataP->ovfCount = 0;
2378 memset(curr_fsDataP->data, 0, numBytes);
2383 /* prev_fsData now contains all the information for the probe cycle
2384 * that just completed. Now count the number of threshold overflows for
2385 * use in the overview screen */
2387 prev_fsDataP = prev_fsData;
2389 numHosts_onfs_alerts = 0;
2390 for (i = 0; i < numFS; i++) {
2391 if (!prev_fsDataP->probeOK) { /* if probe failed */
2393 numHosts_onfs_alerts++;
2395 if (prev_fsDataP->ovfCount) { /* overflows ?? */
2396 num_fs_alerts += prev_fsDataP->ovfCount;
2397 numHosts_onfs_alerts++;
2402 fprintf(debugFD, "Number of FS alerts = %d (on %d hosts)\n",
2403 num_fs_alerts, numHosts_onfs_alerts);
2405 /* flag that the data is now ready to be displayed */
2406 fs_Data_Available = 1;
2408 /* call the Overview frame update routine (update only FS info) */
2409 ovw_refresh(ovw_currPage, OVW_UPDATE_FS);
2411 /* call the File Servers frame update routine */
2412 fs_refresh(fs_currPage, fs_curr_LCol);
2417 } /* save_FS_data_forDisplay */
2422 /*-----------------------------------------------------------------------
2423 * afsmon_FS_Handler()
2426 * This is the File Server probe Handler. It updates the afsmonitor
2427 * probe counts, fs circular buffer indices and calls the functions
2428 * to process the results of this probe.
2432 * Failure: Exits afsmonitor.
2433 *----------------------------------------------------------------------*/
2436 afsmon_FS_Handler(void)
2437 { /* afsmon_FS_Handler() */
2438 static char rn[] = "afsmon_FS_Handler"; /* routine name */
2439 int newProbeCycle; /* start of new probe cycle ? */
2440 int code; /* return status */
2445 "[ %s ] Called, hostName= %s, probeNum= %d, status=%s, collection=%d\n", rn,
2446 xstat_fs_Results.connP->hostName, xstat_fs_Results.probeNum,
2447 xstat_fs_Results.probeOK ? "FAILED" : "OK",
2448 xstat_fs_Results.collectionNumber);
2453 /* print the probe results to output file */
2454 if (afsmon_output) {
2455 code = afsmon_fsOutput(output_filename, afsmon_detOutput);
2458 "[ %s ] output to file %s returned error code=%d\n", rn,
2459 output_filename, code);
2463 /* Update current probe number and circular buffer index. if current
2464 * probenum changed make sure it is only by 1 */
2467 if (xstat_fs_Results.probeNum != afsmon_fs_curr_probeNum) {
2468 if (xstat_fs_Results.probeNum == afsmon_fs_curr_probeNum + 1) {
2469 afsmon_fs_curr_probeNum++;
2472 afsmon_fs_curr_CBindex =
2473 (afsmon_fs_curr_probeNum - 1) % num_bufSlots;
2475 fprintf(stderr, "[ %s ] probe number %d-1 missed\n", rn,
2476 xstat_fs_Results.probeNum);
2482 /* store the results of this probe in the FS circular buffer */
2484 save_FS_results_inCB(newProbeCycle);
2487 /* store the results of the current probe in the fs data display structure.
2488 * if the current probe number changed, swap the current and previous display
2489 * structures. note that the display screen is updated from these structures
2490 * and should start showing the data of the just completed probe cycle */
2492 save_FS_data_forDisplay(&xstat_fs_Results);
2499 /*----------------------------------------------------------------------- *
2504 * Prints the Cache Manager circular buffer
2505 *----------------------------------------------------------------------*/
2509 { /* Print_CM_CB() */
2511 struct afsmon_cm_Results_list *cmlist;
2516 /* print valid info in the cm CB */
2520 "==================== CM Buffer ========================\n");
2521 fprintf(debugFD, "afsmon_cm_curr_CBindex = %d\n",
2522 afsmon_cm_curr_CBindex);
2523 fprintf(debugFD, "afsmon_cm_curr_probeNum = %d\n\n",
2524 afsmon_cm_curr_probeNum);
2526 for (i = 0; i < num_bufSlots; i++) {
2527 fprintf(debugFD, "\t--------- slot %d ----------\n", i);
2528 cmlist = afsmon_cm_ResultsCB[i].list;
2531 for (k = 0; k < MAX_NUM_CM_COLLECTIONS; k++) {
2532 if (!cmlist->empty[k]) {
2534 "\t %d) probeNum = %d host = %s cn = %d",
2536 cmlist->cmResults[k]->probeNum,
2537 cmlist->cmResults[k]->connP->hostName,
2538 cmlist->cmResults[k]->collectionNumber);
2539 if (cmlist->cmResults[k]->probeOK)
2540 fprintf(debugFD, " NOTOK\n");
2542 fprintf(debugFD, " OK\n");
2544 fprintf(debugFD, "\t %d) -- empty --\n", j);
2546 cmlist = cmlist->next;
2549 if (cmlist != (struct afsmon_cm_Results_list *)0)
2550 fprintf(debugFD, "dangling last next ptr cm CB\n");
2556 /*-----------------------------------------------------------------------
2557 * save_CM_results_inCB()
2560 * Saves the results of the latest CM probe in the cm circular
2561 * buffers. If the current probe cycle is in progress the contents
2562 * of xstat_cm_Results are copied to the end of the list of results
2563 * in the current slot (pointed to by afsmon_cm_curr_CBindex). If
2564 * a new probe cycle has started the next slot in the circular buffer
2565 * is initialized and the results copied. Note that the Rx related
2566 * information available in xstat_cm_Results is not copied.
2570 * Failure: Exits afsmonitor.
2571 *----------------------------------------------------------------------*/
2574 save_CM_results_inCB(int a_newProbeCycle) /* start of new probe cycle ? */
2575 { /* save_CM_results_inCB() */
2576 static char rn[] = "save_CM_results_inCB"; /* routine name */
2577 struct afsmon_cm_Results_list *tmp_cmlist_item; /* temp cm list item */
2578 struct xstat_cm_ProbeResults *tmp_cmPR; /* temp ptr */
2584 fprintf(debugFD, "[ %s ] Called, a_newProbeCycle= %d\n", rn,
2589 if (xstat_cm_Results.collectionNumber == AFSCB_XSTATSCOLL_FULL_PERF_INFO) {
2592 fprintf(stderr, "[ %s ] collection number %d is out of range.\n",
2593 rn, xstat_cm_Results.collectionNumber);
2597 /* If a new probe cycle started, mark the list in the current buffer
2598 * slot empty for resuse. Note that afsmon_cm_curr_CBindex was appropriately
2599 * incremented in afsmon_CM_Handler() */
2601 if (a_newProbeCycle) {
2602 tmp_cmlist_item = afsmon_cm_ResultsCB[afsmon_cm_curr_CBindex].list;
2603 for (i = 0; i < numCM; i++) {
2604 tmp_cmlist_item->empty[index] = 1;
2605 tmp_cmlist_item = tmp_cmlist_item->next;
2609 /* locate last unused item in list */
2610 tmp_cmlist_item = afsmon_cm_ResultsCB[afsmon_cm_curr_CBindex].list;
2611 for (i = 0; i < numCM; i++) {
2612 if (tmp_cmlist_item->empty[index])
2614 tmp_cmlist_item = tmp_cmlist_item->next;
2617 /* if we could not find one we have an inconsistent list */
2618 if (!tmp_cmlist_item->empty[index]) {
2620 "[ %s ] list inconsistency 1. unable to find an empty slot to store results of probenum %d of %s\n",
2621 rn, xstat_cm_Results.probeNum,
2622 xstat_cm_Results.connP->hostName);
2626 tmp_cmPR = tmp_cmlist_item->cmResults[index];
2628 /* copy hostname and probe number and probe time and probe status.
2629 * if the probe failed return now */
2631 memcpy(tmp_cmPR->connP->hostName, xstat_cm_Results.connP->hostName,
2632 sizeof(xstat_cm_Results.connP->hostName));
2633 tmp_cmPR->probeNum = xstat_cm_Results.probeNum;
2634 tmp_cmPR->probeTime = xstat_cm_Results.probeTime;
2635 tmp_cmPR->probeOK = xstat_cm_Results.probeOK;
2636 if (xstat_cm_Results.probeOK) { /* probeOK = 1 => notOK */
2637 /* we have a nonempty results structure so mark the list item used */
2638 tmp_cmlist_item->empty[index] = 0;
2643 /* copy connection information */
2644 memcpy(&(tmp_cmPR->connP->skt), &(xstat_cm_Results.connP->skt),
2645 sizeof(struct sockaddr_in));
2647 /**** NEED TO COPY rx_connection INFORMATION HERE ******/
2649 memcpy(tmp_cmPR->connP->hostName, xstat_cm_Results.connP->hostName,
2650 sizeof(xstat_cm_Results.connP->hostName));
2651 tmp_cmPR->collectionNumber = xstat_cm_Results.collectionNumber;
2653 /* copy the probe data information */
2654 tmp_cmPR->data.AFSCB_CollData_len =
2655 min(xstat_cm_Results.data.AFSCB_CollData_len,
2656 afsmon_cm_results_length[index]);
2657 memcpy(tmp_cmPR->data.AFSCB_CollData_val,
2658 xstat_cm_Results.data.AFSCB_CollData_val,
2659 tmp_cmPR->data.AFSCB_CollData_len * sizeof(afs_int32));
2662 /* we have a valid results structure so mark the list item used */
2663 tmp_cmlist_item->empty[index] = 0;
2665 /* print the stored info - to make sure we copied it right */
2666 /* Print_cm_FullPerfInfo(tmp_cmPR); */
2667 /* Print the cm circular buffer */
2670 } /* save_CM_results_inCB */
2674 /*-----------------------------------------------------------------------
2678 * The results of xstat probes are stored in a string format in
2679 * the arrays curr_cmData and prev_cmData. The information stored in
2680 * prev_cmData is copied to the screen.
2681 * This function converts xstat FS results from longs to strings and
2682 * places them in the given buffer (a pointer to an item in curr_cmData).
2683 * When a probe cycle completes, curr_cmData is copied to prev_cmData
2684 * in afsmon_CM_Handler().
2688 *----------------------------------------------------------------------*/
2691 cm_Results_ltoa(struct cm_Display_Data *a_cmData, /* target buffer */
2692 struct xstat_cm_ProbeResults *a_cmResults) /* ptr to xstat cm Results */
2693 { /* cm_Results_ltoa */
2695 static char rn[] = "cm_Results_ltoa"; /* routine name */
2696 struct afs_stats_CMFullPerf *fullP; /* ptr to complete CM stats */
2704 fprintf(debugFD, "[ %s ] Called, a_cmData= %p, a_cmResults= %p\n", rn,
2705 a_cmData, a_cmResults);
2710 fullP = (struct afs_stats_CMFullPerf *)
2711 (a_cmResults->data.AFSCB_CollData_val);
2713 /* There are 4 parts to CM statistics
2714 * - Overall performance statistics (including up/down statistics)
2715 * - This CMs FS RPC operations info
2716 * - This CMs FS RPC errors info
2717 * - This CMs FS transfers info
2718 * - Authentication info
2719 * - [Un]Replicated access info
2722 /* copy overall performance statistics */
2723 srcbuf = (afs_int32 *) & (fullP->perf);
2725 /* we skip the 19 entry, ProtServAddr, so the index must account for this */
2726 for (i = 0; i < NUM_AFS_STATS_CMPERF_LONGS + 1; i++) {
2729 continue; /* skip ProtServerAddr */
2731 sprintf(a_cmData->data[idx], "%d", *srcbuf);
2736 /*printf("Ending index value = %d\n",idx-1); */
2738 /* server up/down statistics */
2739 /* copy file server up/down stats */
2740 srcbuf = (afs_int32 *) (fullP->perf.fs_UpDown);
2742 2 * (sizeof(struct afs_stats_SrvUpDownInfo) / sizeof(afs_int32));
2743 for (i = 0; i < numLongs; i++) {
2744 sprintf(a_cmData->data[idx], "%d", *srcbuf);
2749 /*printf("Ending index value = %d\n",idx-1); */
2751 /* copy volume location server up/down stats */
2752 srcbuf = (afs_int32 *) (fullP->perf.vl_UpDown);
2754 2 * (sizeof(struct afs_stats_SrvUpDownInfo) / sizeof(afs_int32));
2755 for (i = 0; i < numLongs; i++) {
2756 sprintf(a_cmData->data[idx], "%d", *srcbuf);
2761 /*printf("Ending index value = %d\n",idx-1); */
2763 /* copy CMs individual FS RPC operations info */
2764 srcbuf = (afs_int32 *) (fullP->rpc.fsRPCTimes);
2765 for (i = 0; i < AFS_STATS_NUM_FS_RPC_OPS; i++) {
2766 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* numOps */
2769 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* numSuccesses */
2772 tmpbuf = srcbuf++; /* sum time */
2773 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2776 tmpbuf = srcbuf++; /* sqr time */
2777 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2780 tmpbuf = srcbuf++; /* min time */
2781 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2784 tmpbuf = srcbuf++; /* max time */
2785 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2790 /*printf("Ending index value = %d\n",idx-1); */
2792 /* copy CMs individual FS RPC errors info */
2794 srcbuf = (afs_int32 *) (fullP->rpc.fsRPCErrors);
2795 for (i = 0; i < AFS_STATS_NUM_FS_RPC_OPS; i++) {
2796 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* server */
2799 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* network */
2802 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* prot */
2805 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* vol */
2808 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* busies */
2811 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* other */
2816 /*printf("Ending index value = %d\n",idx-1); */
2818 /* copy CMs individual RPC transfers info */
2820 srcbuf = (afs_int32 *) (fullP->rpc.fsXferTimes);
2821 for (i = 0; i < AFS_STATS_NUM_FS_XFER_OPS; i++) {
2822 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* numOps */
2825 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* numSuccesses */
2828 tmpbuf = srcbuf++; /* sum time */
2829 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2832 tmpbuf = srcbuf++; /* sqr time */
2833 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2836 tmpbuf = srcbuf++; /* min time */
2837 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2840 tmpbuf = srcbuf++; /* max time */
2841 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2844 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* sum bytes */
2847 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* min bytes */
2850 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* max bytes */
2853 for (j = 0; j < AFS_STATS_NUM_XFER_BUCKETS; j++) {
2854 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* bucket[j] */
2860 /*printf("Ending index value = %d\n",idx-1); */
2862 /* copy CM operations timings */
2864 srcbuf = (afs_int32 *) (fullP->rpc.cmRPCTimes);
2865 for (i = 0; i < AFS_STATS_NUM_CM_RPC_OPS; i++) {
2866 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* numOps */
2869 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* numSuccesses */
2872 tmpbuf = srcbuf++; /* sum time */
2873 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2876 tmpbuf = srcbuf++; /* sqr time */
2877 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2880 tmpbuf = srcbuf++; /* min time */
2881 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2884 tmpbuf = srcbuf++; /* max time */
2885 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2890 /*printf("Ending index value = %d\n",idx-1); */
2892 /* copy authentication info */
2894 srcbuf = (afs_int32 *) & (fullP->authent);
2895 numLongs = sizeof(struct afs_stats_AuthentInfo) / sizeof(afs_int32);
2896 for (i = 0; i < numLongs; i++) {
2897 sprintf(a_cmData->data[idx], "%d", *srcbuf);
2902 /*printf("Ending index value = %d\n",idx-1); */
2904 /* copy CM [un]replicated access info */
2906 srcbuf = (afs_int32 *) & (fullP->accessinf);
2907 numLongs = sizeof(struct afs_stats_AccessInfo) / sizeof(afs_int32);
2908 for (i = 0; i < numLongs; i++) {
2909 sprintf(a_cmData->data[idx], "%d", *srcbuf);
2914 /*printf("Ending index value = %d\n",idx-1); */
2917 } /* cm_Results_ltoa */
2920 /*-----------------------------------------------------------------------
2921 * Function: check_cm_thresholds()
2924 * Checks the thresholds and sets the overflow flag. Recall that the
2925 * thresholds for each host are stored in the hostEntry lists
2926 * [fs/cm]nameList arrays. The probe results are passed to this
2927 * function in the display-ready format - ie., as strings. Though
2928 * this looks stupid the overhead incurred in converting the strings
2929 * back to floats and comparing them is insignificant and
2930 * programming is easier this way.
2931 * The threshold flags are a part of the display structures
2936 *----------------------------------------------------------------------*/
2939 check_cm_thresholds(struct afsmon_hostEntry *a_hostEntry, /* ptr to hostEntry */
2940 struct cm_Display_Data *a_Data) /* ptr to cm data to be displayed */
2941 { /* check_cm_thresholds */
2943 static char rn[] = "check_cm_thresholds";
2944 struct Threshold *threshP;
2945 double tValue; /* threshold value */
2946 double pValue; /* probe value */
2949 int count; /* number of thresholds exceeded */
2952 fprintf(debugFD, "[ %s ] Called, a_hostEntry= %p, a_Data= %p\n", rn,
2953 a_hostEntry, a_Data);
2957 if (a_hostEntry->numThresh == 0) {
2958 /* store in ovf count ?? */
2963 threshP = a_hostEntry->thresh;
2964 for (i = 0; i < a_hostEntry->numThresh; i++) {
2965 if (threshP->itemName[0] == '\0') {
2969 idx = threshP->index; /* positional index to the data array */
2970 tValue = atof(threshP->threshVal); /* threshold value */
2971 pValue = atof(a_Data->data[idx]); /* probe value */
2972 if (pValue > tValue) {
2976 "[ %s ] cm = %s, thresh ovf for %s, threshold= %s, probevalue= %s\n",
2977 rn, a_hostEntry->hostName, threshP->itemName,
2978 threshP->threshVal, a_Data->data[idx]);
2982 /* if the threshold is crossed, call the handler function
2983 * only if this was a transition -ie, if the threshold was
2984 * crossed in the last probe too just count & keep quite! */
2986 if (!a_Data->threshOvf[idx]) {
2987 a_Data->threshOvf[idx] = 1;
2988 /* call the threshold handler if provided */
2989 if (threshP->handler[0] != '\0') {
2991 fprintf(debugFD, "[ %s ] Calling ovf handler %s\n",
2992 rn, threshP->handler);
2995 execute_thresh_handler(threshP->handler, a_Data->hostName,
2996 CM, threshP->itemName,
3004 /* in case threshold was previously crossed, blank it out */
3005 a_Data->threshOvf[idx] = 0;
3008 /* store the overflow count */
3009 a_Data->ovfCount = count;
3012 } /* check_cm_thresholds */
3015 /*-----------------------------------------------------------------------
3016 * save_CM_data_forDisplay()
3019 * Does the following:
3020 * - if the probe number changed (ie, a cycle completed) curr_cmData
3021 * is copied to prev_cmData, curr_cmData zeroed and refresh the
3022 * overview screen and file server screen with the new data.
3023 * - store the results of the current probe from xstat_cm_Results into
3024 * curr_cmData. ie., convert longs to strings.
3025 * - check the thresholds
3029 * Failure: Exits afsmonitor.
3031 *----------------------------------------------------------------------*/
3034 save_CM_data_forDisplay(struct xstat_cm_ProbeResults *a_cmResults)
3035 { /* save_CM_data_forDisplay */
3037 static char rn[] = "save_CM_data_forDisplay"; /* routine name */
3038 struct cm_Display_Data *curr_cmDataP;
3039 struct cm_Display_Data *prev_cmDataP;
3040 struct afsmon_hostEntry *curr_host;
3041 static int results_Received = 0; /* number of probes reveived in
3042 * the current cycle. If this is equal to numFS we got all
3043 * the data we want in this cycle and can now display it */
3051 fprintf(debugFD, "[ %s ] Called, a_cmResults= %p\n", rn, a_cmResults);
3055 /* store results in the display array */
3058 curr_cmDataP = curr_cmData;
3059 for (i = 0; i < numCM; i++) {
3060 if ((strcasecmp(curr_cmDataP->hostName, a_cmResults->connP->hostName))
3070 "[ %s ] Could not insert CM probe results for host %s in cm display array\n",
3071 rn, a_cmResults->connP->hostName);
3075 /* Check the status of the probe. If it succeeded, we store its
3076 * results in the display data structure. If it failed we only mark
3077 * the failed status in the display data structure. */
3080 if (a_cmResults->probeOK) { /* 1 => notOK the xstat results */
3081 curr_cmDataP->probeOK = 0;
3083 /* print the probe status */
3085 fprintf(debugFD, "\n\t\t ----- cm display data ------\n");
3086 fprintf(debugFD, "HostName = %s PROBE FAILED \n",
3087 curr_cmDataP->hostName);
3091 } else { /* probe succeeded, update display data structures */
3092 curr_cmDataP->probeOK = 1;
3095 /* covert longs to strings and place them in curr_cmDataP */
3096 cm_Results_ltoa(curr_cmDataP, a_cmResults);
3098 /* compare with thresholds and set the overflow flags.
3099 * note that the threshold information is in the hostEntry structure and
3100 * each threshold item has a positional index associated with it */
3102 /* locate the hostEntry for this host */
3104 curr_host = CMnameList;
3105 for (i = 0; i < numCM; i++) {
3106 if (strcasecmp(curr_host->hostName, a_cmResults->connP->hostName)
3111 curr_host = curr_host->next;
3116 code = check_cm_thresholds(curr_host, curr_cmDataP);
3118 fprintf(stderr, "[ %s ] Error in checking thresholds\n", rn);
3122 /* print the info we just saved */
3124 fprintf(debugFD, "\n\t\t ----- CM display data ------\n");
3125 fprintf(debugFD, "HostName = %s\n", curr_cmDataP->hostName);
3126 for (i = 0; i < NUM_CM_STAT_ENTRIES; i++) {
3129 fprintf(debugFD, "\t -- Overall Perf Info --\n");
3133 "\t -- File Server up/down stats - same cell --\n");
3137 "\t -- File Server up/down stats - diff cell --\n");
3141 "\t -- VL server up/down stats - same cell --\n");
3145 "\t -- VL server up/down stats - diff cell --\n");
3148 fprintf(debugFD, "\t -- FS Operation Timings --\n");
3151 fprintf(debugFD, "\t -- FS Error Info --\n");
3154 fprintf(debugFD, "\t -- FS Transfer Timings --\n");
3157 fprintf(debugFD, "\t -- CM Operations Timings --\n");
3160 fprintf(debugFD, "\t -- Authentication Info --\n");
3163 fprintf(debugFD, "\t -- Access Info --\n");
3169 fprintf(debugFD, "%20s %30s %s\n", curr_cmDataP->data[i],
3171 curr_cmDataP->threshOvf[i] ? "(ovf)" : "");
3173 fprintf(debugFD, "\t\t--------------------------------\n\n");
3176 } /* if the probe succeeded, update the display data structures */
3178 /* if we have received a reply from all the hosts for this probe cycle,
3179 * it is time to display the data */
3182 if (results_Received == numCM * num_cm_collections) {
3183 results_Received = 0;
3185 if (afsmon_cm_curr_probeNum != afsmon_cm_prev_probeNum + 1) {
3186 sprintf(errMsg, "[ %s ] Probe number %d missed! \n", rn,
3187 afsmon_cm_prev_probeNum + 1);
3190 afsmon_cm_prev_probeNum++;
3193 /* backup the display data of the probe cycle that just completed -
3194 * ie., store curr_cmData in prev_cmData */
3196 memcpy((char *)prev_cmData, (char *)curr_cmData,
3197 (numCM * sizeof(struct cm_Display_Data)));
3200 /* initialize curr_cmData but retain the threshold flag information.
3201 * The previous state of threshold flags is used in check_cm_thresholds() */
3203 curr_cmDataP = curr_cmData;
3204 numBytes = NUM_CM_STAT_ENTRIES * CM_STAT_STRING_LEN;
3205 for (i = 0; i < numCM; i++) {
3206 curr_cmDataP->probeOK = 0;
3207 curr_cmDataP->ovfCount = 0;
3208 memset(curr_cmDataP->data, 0, numBytes);
3212 /* prev_cmData now contains all the information for the probe cycle
3213 * that just completed. Now count the number of threshold overflows for
3214 * use in the overview screen */
3216 prev_cmDataP = prev_cmData;
3218 numHosts_oncm_alerts = 0;
3219 for (i = 0; i < numCM; i++) {
3220 if (!prev_cmDataP->probeOK) { /* if probe failed */
3222 numHosts_oncm_alerts++;
3223 } else if (prev_cmDataP->ovfCount) { /* overflows ?? */
3224 num_cm_alerts += prev_cmDataP->ovfCount;
3225 numHosts_oncm_alerts++;
3230 fprintf(debugFD, "Number of CM alerts = %d (on %d hosts)\n",
3231 num_cm_alerts, numHosts_oncm_alerts);
3234 /* flag that the data is now ready to be displayed */
3235 cm_Data_Available = 1;
3237 /* update the Overview frame (only CM info) */
3238 ovw_refresh(ovw_currPage, OVW_UPDATE_CM);
3240 /* update the Cache Managers frame */
3241 cm_refresh(cm_currPage, cm_curr_LCol);
3247 } /* save_CM_data_forDisplay */
3251 /*-----------------------------------------------------------------------
3252 * afsmon_CM_Handler()
3255 * This is the Cache Manager probe Handler. It updates the afsmonitor
3256 * probe counts, cm circular buffer indices and calls the functions
3257 * to process the results of this probe.
3261 * Failure: Exits afsmonitor.
3262 *----------------------------------------------------------------------*/
3265 afsmon_CM_Handler(void)
3266 { /* afsmon_CM_Handler() */
3267 static char rn[] = "afsmon_CM_Handler"; /* routine name */
3268 int code; /* return status */
3269 int newProbeCycle; /* start of new probe cycle ? */
3273 "[ %s ] Called, hostName= %s, probeNum= %d, status= %s\n", rn,
3274 xstat_cm_Results.connP->hostName, xstat_cm_Results.probeNum,
3275 xstat_cm_Results.probeOK ? "FAILED" : "OK");
3280 /* print the probe results to output file */
3281 if (afsmon_output) {
3282 code = afsmon_cmOutput(output_filename, afsmon_detOutput);
3285 "[ %s ] output to file %s returned error code=%d\n", rn,
3286 output_filename, code);
3290 /* Update current probe number and circular buffer index. if current
3291 * probenum changed make sure it is only by 1 */
3294 if (xstat_cm_Results.probeNum != afsmon_cm_curr_probeNum) {
3295 if (xstat_cm_Results.probeNum == afsmon_cm_curr_probeNum + 1) {
3296 afsmon_cm_curr_probeNum++;
3299 afsmon_cm_curr_CBindex =
3300 (afsmon_cm_curr_probeNum - 1) % num_bufSlots;
3302 fprintf(stderr, "[ %s ] probe number %d-1 missed\n", rn,
3303 xstat_cm_Results.probeNum);
3308 /* save the results of this probe in the CM buffer */
3310 save_CM_results_inCB(newProbeCycle);
3312 /* store the results of the current probe in the cm data display structure.
3313 * if the current probe number changed, swap the current and previous display
3314 * structures. note that the display screen is updated from these structures
3315 * and should start showing the data of the just completed probe cycle */
3317 save_CM_data_forDisplay(&xstat_cm_Results);
3322 /*-----------------------------------------------------------------------
3326 * Allocate and Initialize circular buffers for file servers.
3330 * Failure to allocate memory: exits afsmonitor.
3331 *----------------------------------------------------------------------*/
3334 init_fs_buffers(void)
3335 { /* init_fs_buffers() */
3336 static char rn[] = "init_fs_buffers"; /* routine name */
3337 struct afsmon_fs_Results_list *new_fslist_item; /* ptr for new struct */
3338 struct afsmon_fs_Results_list *tmp_fslist_item; /* temp ptr */
3339 struct xstat_fs_ProbeResults *new_fsPR; /* ptr for new struct */
3346 fprintf(debugFD, "[ %s ] Called\n", rn);
3350 /* allocate memory for the circular buffer of pointers */
3352 afsmon_fs_ResultsCB = (struct afsmon_fs_Results_CBuffer *)
3353 malloc(sizeof(struct afsmon_fs_Results_CBuffer) * num_bufSlots);
3355 /* initialize the fs circular buffer */
3356 for (i = 0; i < num_bufSlots; i++) {
3357 afsmon_fs_ResultsCB[i].list = (struct afsmon_fs_Results_list *)0;
3358 afsmon_fs_ResultsCB[i].probeNum = 0;
3361 /* create a list of numFS items to store fs probe results for
3362 * each slot in CB */
3364 if (numFS) { /* if we have file servers to monitor */
3365 for (bufslot = 0; bufslot < num_bufSlots; bufslot++) {
3366 numfs = numFS; /* get the number of servers */
3369 /* if any of these mallocs fail we only need to free the memory we
3370 * have allocated in this iteration. the rest of it which is in a
3371 * proper linked list will be freed in afsmon_Exit */
3373 /* allocate memory for an fs list item */
3374 new_fslist_item = (struct afsmon_fs_Results_list *)
3375 malloc(sizeof(struct afsmon_fs_Results_list));
3376 if (new_fslist_item == (struct afsmon_fs_Results_list *)0)
3379 for (i = 0; i < MAX_NUM_FS_COLLECTIONS; i++) {
3380 /* allocate memory to store xstat_fs_Results */
3381 new_fsPR = (struct xstat_fs_ProbeResults *)
3382 malloc(sizeof(struct xstat_fs_ProbeResults));
3384 free(new_fslist_item);
3388 new_fsPR->connP = (struct xstat_fs_ConnectionInfo *)
3389 malloc(sizeof(struct xstat_fs_ConnectionInfo));
3390 if (new_fsPR->connP == (struct xstat_fs_ConnectionInfo *)0) {
3391 free(new_fslist_item);
3396 /* >>> need to allocate rx connection info structure here <<< */
3397 new_fsPR->data.AFS_CollData_val = (afs_int32 *)
3398 malloc(afsmon_fs_results_length[i] * sizeof(afs_int32));
3399 if (new_fsPR->data.AFS_CollData_val == NULL) {
3400 free(new_fslist_item);
3401 free(new_fsPR->connP);
3405 new_fslist_item->fsResults[i] = new_fsPR;
3406 new_fslist_item->empty[i] = 1;
3409 /* initialize this list entry */
3410 new_fslist_item->next = (struct afsmon_fs_Results_list *)0;
3412 /* store it at the end of the fs list in the current CB slot */
3413 if (afsmon_fs_ResultsCB[bufslot].list ==
3414 (struct afsmon_fs_Results_list *)0)
3415 afsmon_fs_ResultsCB[bufslot].list = new_fslist_item;
3417 tmp_fslist_item = afsmon_fs_ResultsCB[bufslot].list;
3419 while (tmp_fslist_item !=
3420 (struct afsmon_fs_Results_list *)0) {
3421 if (tmp_fslist_item->next ==
3422 (struct afsmon_fs_Results_list *)0)
3424 tmp_fslist_item = tmp_fslist_item->next;
3426 /* something goofed. exit */
3427 fprintf(stderr, "[ %s ] list creation error\n",
3432 tmp_fslist_item->next = new_fslist_item;
3435 } /* while servers */
3436 } /* for each buffer slot */
3437 } /* if we have file servers to monitor */
3441 /*-----------------------------------------------------------------------
3445 * Allocate and Initialize circular buffers for cache managers.
3449 * Failure to allocate memory: exits afsmonitor.
3450 *----------------------------------------------------------------------*/
3453 init_cm_buffers(void)
3454 { /* init_cm_buffers() */
3455 static char rn[] = "init_cm_buffers"; /* routine name */
3456 struct afsmon_cm_Results_list *new_cmlist_item; /* ptr for new struct */
3457 struct afsmon_cm_Results_list *tmp_cmlist_item; /* temp ptr */
3458 struct xstat_cm_ProbeResults *new_cmPR; /* ptr for new struct */
3464 fprintf(debugFD, "[ %s ] Called\n", rn);
3468 /* allocate memory for the circular buffer of pointers */
3469 afsmon_cm_ResultsCB = (struct afsmon_cm_Results_CBuffer *)
3470 malloc(sizeof(struct afsmon_cm_Results_CBuffer) * num_bufSlots);
3472 /* initialize the fs circular buffer */
3473 for (i = 0; i < num_bufSlots; i++) {
3474 afsmon_cm_ResultsCB[i].list = (struct afsmon_cm_Results_list *)0;
3475 afsmon_cm_ResultsCB[i].probeNum = 0;
3478 /* create a list of numCM items to store fs probe results for
3479 * each slot in CB */
3481 if (numCM) { /* if we have file servers to monitor */
3482 for (bufslot = 0; bufslot < num_bufSlots; bufslot++) {
3483 numcm = numCM; /* get the number of servers */
3486 /* if any of these mallocs fail we only need to free the memory we
3487 * have allocated in this iteration. the rest of it which is in a
3488 * proper linked list will be freed in afsmon_Exit */
3490 /* allocate memory for an fs list item */
3491 new_cmlist_item = (struct afsmon_cm_Results_list *)
3492 malloc(sizeof(struct afsmon_cm_Results_list));
3493 if (new_cmlist_item == (struct afsmon_cm_Results_list *)0)
3496 for (i = 0; i < MAX_NUM_CM_COLLECTIONS; i++) {
3497 /* allocate memory to store xstat_cm_Results */
3498 new_cmPR = (struct xstat_cm_ProbeResults *)
3499 malloc(sizeof(struct xstat_cm_ProbeResults));
3501 free(new_cmlist_item);
3504 new_cmPR->connP = (struct xstat_cm_ConnectionInfo *)
3505 malloc(sizeof(struct xstat_cm_ConnectionInfo));
3506 if (!new_cmPR->connP) {
3507 free(new_cmlist_item);
3512 /* >>> need to allocate rx connection info structure here <<< */
3514 new_cmPR->data.AFSCB_CollData_val =
3515 (afs_int32 *) malloc(XSTAT_CM_FULLPERF_RESULTS_LEN
3516 * sizeof(afs_int32));
3517 if (new_cmPR->data.AFSCB_CollData_val == NULL) {
3518 free(new_cmlist_item);
3519 free(new_cmPR->connP);
3524 new_cmlist_item->cmResults[i] = new_cmPR;
3525 new_cmlist_item->empty[i] = 1;
3528 /* initialize this list entry */
3529 new_cmlist_item->next = (struct afsmon_cm_Results_list *)0;
3531 /* store it at the end of the cm list in the current CB slot */
3532 if (afsmon_cm_ResultsCB[bufslot].list ==
3533 (struct afsmon_cm_Results_list *)0)
3534 afsmon_cm_ResultsCB[bufslot].list = new_cmlist_item;
3536 tmp_cmlist_item = afsmon_cm_ResultsCB[bufslot].list;
3538 while (tmp_cmlist_item !=
3539 (struct afsmon_cm_Results_list *)0) {
3540 if (tmp_cmlist_item->next ==
3541 (struct afsmon_cm_Results_list *)0)
3543 tmp_cmlist_item = tmp_cmlist_item->next;
3545 /* something goofed. exit */
3546 fprintf(stderr, "[ %s ] list creation error\n",
3551 tmp_cmlist_item->next = new_cmlist_item;
3554 } /* while servers */
3555 } /* for each buffer slot */
3557 /* if we have file servers to monitor */
3558 /* print the CB to make sure it is right */
3562 } /* init_cm_buffers() */
3565 /*-------------------------------------------------------------------------
3566 * init_print_buffers()
3569 * Allocate and initialize the buffers used for printing results
3570 * to the display screen. These buffers store the current and
3571 * previous probe results in ascii format.
3576 *------------------------------------------------------------------------*/
3579 init_print_buffers(void)
3580 { /* init_print_buffers */
3582 static char rn[] = "init_print_buffers"; /* routine name */
3583 struct fs_Display_Data *tmp_fsData1; /* temp pointers */
3584 struct fs_Display_Data *tmp_fsData2;
3585 struct cm_Display_Data *tmp_cmData1;
3586 struct cm_Display_Data *tmp_cmData2;
3587 struct afsmon_hostEntry *tmp_fsNames;
3588 struct afsmon_hostEntry *tmp_cmNames;
3593 fprintf(debugFD, "[ %s ] Called\n", rn);
3597 /* allocate numFS blocks of the FS print structure. */
3599 /* we need two instances of this structure - one (curr_fsData) for storing
3600 * the results of the fs probes currently in progress and another (prev_fsData)
3601 * for the last completed probe. The display is updated from the contents of
3602 * prev_fsData. The pointers curr_fsData & prev_fsData are switched whenever
3603 * the probe number changes */
3606 numBytes = numFS * sizeof(struct fs_Display_Data);
3607 curr_fsData = (struct fs_Display_Data *)malloc(numBytes);
3608 if (curr_fsData == (struct fs_Display_Data *)0) {
3609 fprintf(stderr, "[ %s ] Memory allocation failure\n", rn);
3612 memset(curr_fsData, 0, numBytes);
3614 numBytes = numFS * sizeof(struct fs_Display_Data);
3615 prev_fsData = (struct fs_Display_Data *)malloc(numBytes);
3616 if (prev_fsData == (struct fs_Display_Data *)0) {
3617 fprintf(stderr, "[ %s ] Memory allocation failure\n", rn);
3620 memset(prev_fsData, 0, numBytes);
3622 /* fill in the host names */
3623 tmp_fsData1 = curr_fsData;
3624 tmp_fsData2 = curr_fsData;
3625 tmp_fsNames = FSnameList;
3626 for (i = 0; i < numFS; i++) {
3627 strncpy(tmp_fsData1->hostName, tmp_fsNames->hostName,
3629 strncpy(tmp_fsData2->hostName, tmp_fsNames->hostName,
3633 tmp_fsNames = tmp_fsNames->next;;
3638 /* if file servers to monitor */
3639 /* allocate numCM blocks of the CM print structure */
3640 /* we need two instances of this structure for the same reasons as above */
3642 numBytes = numCM * sizeof(struct cm_Display_Data);
3644 curr_cmData = (struct cm_Display_Data *)malloc(numBytes);
3645 if (curr_cmData == (struct cm_Display_Data *)0) {
3646 fprintf(stderr, "[ %s ] Memory allocation failure\n", rn);
3649 memset(curr_cmData, 0, numBytes);
3651 numBytes = numCM * sizeof(struct cm_Display_Data);
3652 prev_cmData = (struct cm_Display_Data *)malloc(numBytes);
3653 if (prev_cmData == (struct cm_Display_Data *)0) {
3654 fprintf(stderr, "[ %s ] Memory allocation failure\n", rn);
3657 memset(prev_cmData, 0, numBytes);
3659 /* fill in the host names */
3660 tmp_cmData1 = curr_cmData;
3661 tmp_cmData2 = curr_cmData;
3662 tmp_cmNames = CMnameList;
3663 for (i = 0; i < numCM; i++) {
3664 strncpy(tmp_cmData1->hostName, tmp_cmNames->hostName,
3666 strncpy(tmp_cmData2->hostName, tmp_cmNames->hostName,
3670 tmp_cmNames = tmp_cmNames->next;;
3674 /* if cache managers to monitor */
3677 } /* init_print_buffers */
3679 /*-----------------------------------------------------------------------
3683 * Trap the interrupt signal. This function is useful only until
3684 * gtx is initialized.
3685 *----------------------------------------------------------------------*/
3688 quit_signal(int sig)
3690 fprintf(stderr, "Received signal %d \n", sig);
3696 /*-----------------------------------------------------------------------
3700 * This is where we start it all. Initialize an array of sockets for
3701 * file servers and cache cache managers and call the xstat_[fs/cm]_Init
3702 * routines. The last step is to call the gtx input server which
3703 * grabs control of the keyboard.
3706 * Does not return. Control is periodically returned to the afsmonitor
3707 * thru afsmon_[FS/CM]_Handler() routines and also through the gtx
3708 * keyboard handler calls.
3710 *----------------------------------------------------------------------*/
3713 afsmon_execute(void)
3714 { /* afsmon_execute() */
3715 static char rn[] = "afsmon_execute"; /* routine name */
3716 static char fullhostname[128]; /* full host name */
3717 struct sockaddr_in *FSSktArray; /* fs socket array */
3718 int FSsktbytes; /* num bytes in above */
3719 struct sockaddr_in *CMSktArray; /* cm socket array */
3720 int CMsktbytes; /* num bytes in above */
3721 struct sockaddr_in *curr_skt; /* ptr to current socket */
3722 struct afsmon_hostEntry *curr_FS; /* ptr to FS name list */
3723 struct afsmon_hostEntry *curr_CM; /* ptr to CM name list */
3724 struct hostent *he; /* host entry */
3725 int FSinitFlags = 0; /* flags for xstat_fs_Init */
3726 int CMinitFlags = 0; /* flags for xstat_cm_Init */
3727 int code; /* function return code */
3728 struct timeval tv; /* time structure */
3733 fprintf(debugFD, "[ %s ] Called\n", rn);
3738 /* process file server entries */
3740 afs_int32 collIDs[MAX_NUM_FS_COLLECTIONS];
3742 /* Allocate an array of sockets for each fileserver we monitor */
3744 FSsktbytes = numFS * sizeof(struct sockaddr_in);
3745 FSSktArray = (struct sockaddr_in *)malloc(FSsktbytes);
3746 if (FSSktArray == (struct sockaddr_in *)0) {
3748 "[ %s ] cannot malloc %d sockaddr_ins for fileservers\n",
3753 memset(FSSktArray, 0, FSsktbytes);
3755 /* Fill in the socket information for each fileserve */
3757 curr_skt = FSSktArray;
3758 curr_FS = FSnameList; /* FS name list header */
3760 strncpy(fullhostname, curr_FS->hostName, sizeof(fullhostname));
3761 he = GetHostByName(fullhostname);
3763 fprintf(stderr, "[ %s ] Cannot get host info for %s\n", rn,
3767 strncpy(curr_FS->hostName, he->h_name, HOST_NAME_LEN); /* complete name */
3768 memcpy(&(curr_skt->sin_addr.s_addr), he->h_addr, 4);
3769 curr_skt->sin_family = AF_INET; /*Internet family */
3770 curr_skt->sin_port = htons(7000); /*FileServer port */
3771 #ifdef STRUCT_SOCKADDR_HAS_SA_LEN
3772 curr_skt->sin_len = sizeof(struct sockaddr_in);
3775 /* get the next dude */
3777 curr_FS = curr_FS->next;
3780 /* Initialize collection IDs, depending on the data requested. */
3781 num_fs_collections = 0;
3782 for (i = 0; i < fs_DisplayItems_count; i++) {
3783 index = fs_Display_map[i];
3784 if (FS_FULLPERF_ENTRY_START <= index && index <= FS_FULLPERF_ENTRY_END) {
3785 collIDs[num_fs_collections++] = AFS_XSTATSCOLL_FULL_PERF_INFO;
3789 for (i = 0; i < fs_DisplayItems_count; i++) {
3790 index = fs_Display_map[i];
3791 if (FS_CB_ENTRY_START <= index && index <= FS_CB_ENTRY_END) {
3792 collIDs[num_fs_collections++] = AFS_XSTATSCOLL_CBSTATS;
3798 if (afsmon_onceOnly) /* option not provided at this time */
3799 FSinitFlags |= XSTAT_FS_INITFLAG_ONE_SHOT;
3802 fprintf(debugFD, "[ %s ] Calling xstat_fs_Init \n", rn);
3806 code = xstat_fs_Init(numFS, /*Num servers */
3807 FSSktArray, /*File Server socket array */
3808 afsmon_probefreq, /*probe frequency */
3809 afsmon_FS_Handler, /*Handler routine */
3810 FSinitFlags, /*Initialization flags */
3811 num_fs_collections, /*Number of collection IDs */
3812 collIDs); /*Ptr to collection ID */
3815 fprintf(stderr, "[ %s ] xstat_fs_init returned error\n", rn);
3822 /* end of process fileserver entries */
3823 /* process cache manager entries */
3825 afs_int32 collIDs[MAX_NUM_CM_COLLECTIONS];
3827 /* Allocate an array of sockets for each cache manager we monitor */
3829 CMsktbytes = numCM * sizeof(struct sockaddr_in);
3830 CMSktArray = (struct sockaddr_in *)malloc(CMsktbytes);
3831 if (CMSktArray == (struct sockaddr_in *)0) {
3833 "[ %s ] cannot malloc %d sockaddr_ins for CM entries\n",
3838 memset(CMSktArray, 0, CMsktbytes);
3840 /* Fill in the socket information for each CM */
3842 curr_skt = CMSktArray;
3843 curr_CM = CMnameList; /* CM name list header */
3845 strncpy(fullhostname, curr_CM->hostName, sizeof(fullhostname));
3846 he = GetHostByName(fullhostname);
3848 fprintf(stderr, "[ %s ] Cannot get host info for %s\n", rn,
3852 strncpy(curr_CM->hostName, he->h_name, HOST_NAME_LEN); /* complete name */
3853 memcpy(&(curr_skt->sin_addr.s_addr), he->h_addr, 4);
3854 #if defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
3855 curr_skt->sin_family = AF_INET; /*Internet family */
3857 curr_skt->sin_family = htons(AF_INET); /*Internet family */
3859 curr_skt->sin_port = htons(7001); /*Cache Manager port */
3860 #ifdef STRUCT_SOCKADDR_HAS_SA_LEN
3861 curr_skt->sin_len = sizeof(struct sockaddr_in);
3864 /* get the next dude */
3866 curr_CM = curr_CM->next;
3869 /* initialize collection IDs. We need only one entry since we collect
3870 * all the information from xstat */
3871 num_cm_collections = 0;
3872 collIDs[num_cm_collections++] = AFSCB_XSTATSCOLL_FULL_PERF_INFO;
3875 if (afsmon_onceOnly) /* once only ? */
3876 CMinitFlags |= XSTAT_CM_INITFLAG_ONE_SHOT;
3879 fprintf(debugFD, "[ %s ] Calling xstat_cm_Init \n", rn);
3883 code = xstat_cm_Init(numCM, /*Num servers */
3884 CMSktArray, /*Cache Manager socket array */
3885 afsmon_probefreq, /*probe frequency */
3886 afsmon_CM_Handler, /*Handler routine */
3887 CMinitFlags, /*Initialization flags */
3888 num_cm_collections, /*Number of collection IDs */
3889 collIDs); /*Ptr to collection ID */
3892 fprintf(stderr, "[ %s ] xstat_cm_init returned error\n", rn);
3899 /* end of process cache manager entries */
3900 /* if only one probe was required setup a waiting process for the
3901 * termination signal */
3902 if (afsmon_onceOnly) {
3903 code = LWP_WaitProcess(&terminationEvent);
3906 fprintf(debugFD, "LWP_WaitProcess() returned error %d\n",
3914 /* start the gtx input server */
3915 code = (intptr_t)gtx_InputServer(afsmon_win);
3917 fprintf(stderr, "[ %s ] Failed to start input server \n", rn);
3921 /* This part of the code is reached only if the input server is not started
3922 * for debugging purposes */
3925 tv.tv_sec = 24 * 60;
3927 fprintf(stderr, "[ %s ] going to sleep ...\n", rn);
3929 code = IOMGR_Select(0, /*Num fds */
3930 0, /*Descriptors ready for reading */
3931 0, /*Descriptors ready for writing */
3932 0, /*Descriptors with exceptional conditions */
3933 &tv); /*Timeout structure */
3936 "[ %s ] IOMGR_Select() returned non-zero value %d\n", rn,
3944 /*-----------------------------------------------------------------------
3948 * Afsmonitor initialization routine.
3949 * - processes command line parameters
3950 * - call functions to:
3951 * - process config file
3952 * - initialize circular buffers and display buffers
3954 * - execute afsmonitor
3955 * - initialize the display maps [fs/cm]_Display_map[].
3958 * Success: Does not return from the call to afsmon_execute().
3959 * Failure: Exits afsmonitor.
3960 *----------------------------------------------------------------------*/
3963 afsmonInit(struct cmd_syndesc *as, void *arock)
3964 { /* afsmonInit() */
3966 static char rn[] = "afsmonInit"; /* Routine name */
3967 char *debug_filename; /* pointer to debug filename */
3968 FILE *outputFD; /* output file descriptor */
3969 struct cmd_item *hostPtr; /* ptr to parse command line args */
3970 char buf[256]; /* buffer for processing hostnames */
3975 fprintf(debugFD, "[ %s ] Called, as= %p\n", rn, as);
3979 /* Open the debug file if -debug option is specified */
3980 if (as->parms[P_DEBUG].items != 0) {
3982 debug_filename = as->parms[P_DEBUG].items->data;
3983 debugFD = fopen(debug_filename, "w");
3984 if (debugFD == (FILE *) 0) {
3985 printf("[ %s ] Failed to open debugging file %s for writing\n",
3993 fprintf(debugFD, "[ %s ] Called\n", rn);
3997 /* use curses always until we support other packages */
3999 wpkg_to_use = atoi(as->parms[P_PACKAGE].items->data);
4001 switch (wpkg_to_use) {
4002 case GATOR_WIN_CURSES:
4003 fprintf(stderr, "curses\n");
4005 case GATOR_WIN_DUMB:
4006 fprintf(stderr, "dumb terminal\n");
4009 fprintf(stderr, "X11\n");
4012 fprintf(stderr, "Illegal graphics package: %d\n", wpkg_to_use);
4014 } /*end switch (wpkg_to_use) */
4017 wpkg_to_use = GATOR_WIN_CURSES;
4019 /* get probe frequency . We check for meaningful bounds on the frequency
4020 * and reset to the default value if needed. The upper bound of 24
4021 * hours looks ridiculous though! */
4023 afsmon_probefreq = 0;
4024 if (as->parms[P_FREQUENCY].items != 0)
4025 afsmon_probefreq = atoi(as->parms[P_FREQUENCY].items->data);
4027 afsmon_probefreq = DEFAULT_FREQUENCY;
4029 if (afsmon_probefreq <= 0 || afsmon_probefreq > 24 * 60 * 60) {
4030 afsmon_probefreq = DEFAULT_FREQUENCY;
4033 "[ %s ] Invalid probe frequency %s specified, resetting to default value %d seconds\n",
4034 rn, as->parms[P_FREQUENCY].items->data, afsmon_probefreq);
4038 "Invalid probe frequency %s specified, resetting to default value %d seconds\n",
4039 as->parms[P_FREQUENCY].items->data, afsmon_probefreq);
4044 /* make sure output file is writable, else complain now */
4045 /* we will open and close it as needed after probes */
4047 if (as->parms[P_OUTPUT].items != 0) {
4048 afsmon_output = 1; /* output flag */
4049 strncpy(output_filename, as->parms[P_OUTPUT].items->data, 80);
4050 outputFD = fopen(output_filename, "a");
4051 if (outputFD == (FILE *) 0) {
4052 fprintf(stderr, "Failed to open output file %s \n",
4055 fprintf(debugFD, "[ %s ] Failed to open output file %s \n",
4056 rn, output_filename);
4061 fprintf(debugFD, "[ %s ] output file is %s\n", rn,
4067 /* detailed statistics to storage file */
4068 if (as->parms[P_DETAILED].items != 0) {
4069 if (as->parms[P_OUTPUT].items == 0) {
4071 "-detailed switch can be used only with -output\n");
4074 afsmon_detOutput = 1;
4077 /* Initialize host list headers */
4078 FSnameList = (struct afsmon_hostEntry *)0;
4079 CMnameList = (struct afsmon_hostEntry *)0;
4081 /* The -config option is mutually exclusive with the -fshosts,-cmhosts
4084 if (as->parms[P_CONFIG].items) {
4085 if (as->parms[P_FSHOSTS].items || as->parms[P_CMHOSTS].items) {
4087 "Cannot use -config option with -fshosts or -cmhosts\n");
4091 if (!as->parms[P_FSHOSTS].items && !as->parms[P_CMHOSTS].items) {
4093 "Must specify either -config or (-fshosts and/or -cmhosts) options \n");
4099 /* If a file server host is specified on the command line we reuse
4100 * parse_hostEntry() function . Just the pass the info as if it were
4101 * read off the config file */
4103 if (as->parms[P_FSHOSTS].items) {
4104 hostPtr = as->parms[P_FSHOSTS].items;
4105 while (hostPtr != (struct cmd_item *)0) {
4106 sprintf(buf, "fs %s", hostPtr->data);
4107 code = parse_hostEntry(buf);
4109 fprintf(stderr, "Could not parse %s\n", hostPtr->data);
4113 hostPtr = hostPtr->next;
4117 /* same as above for -cmhosts */
4118 if (as->parms[P_CMHOSTS].items) {
4119 hostPtr = as->parms[P_CMHOSTS].items;
4120 while (hostPtr != (struct cmd_item *)0) {
4121 sprintf(buf, "cm %s", hostPtr->data);
4122 code = parse_hostEntry(buf);
4124 fprintf(stderr, "Could not parse %s\n", hostPtr->data);
4128 hostPtr = hostPtr->next;
4132 /* number of slots in circular buffers */
4133 if (as->parms[P_BUFFERS].items)
4134 num_bufSlots = atoi(as->parms[P_BUFFERS].items->data);
4136 num_bufSlots = DEFAULT_BUFSLOTS;
4138 /* Initialize xx_showFlags[]. This array is used solely for processing the
4139 * "show" directives in the config file in parse_showEntries() */
4140 for (i = 0; i < NUM_FS_STAT_ENTRIES; i++)
4141 fs_showFlags[i] = 0;
4142 for (i = 0; i < NUM_CM_STAT_ENTRIES; i++)
4143 cm_showFlags[i] = 0;
4146 /* Process the configuration file if given. This initializes among other
4147 * things, the list of FS & CM names in FSnameList and CMnameList */
4149 if (as->parms[P_CONFIG].items)
4150 process_config_file(as->parms[P_CONFIG].items->data);
4152 /* print out the FS and CM lists */
4156 /* Initialize the FS results-to-screen map array if there were no "show fs"
4157 * directives in the config file */
4158 if (fs_showDefault) {
4159 for (i = 0; i < NUM_FS_STAT_ENTRIES; i++)
4160 fs_Display_map[i] = i;
4161 fs_DisplayItems_count = NUM_FS_STAT_ENTRIES;
4164 /* Initialize the CM results-to-screen map array if there were no "show cm"
4165 * directives in the config file */
4166 if (cm_showDefault) {
4167 for (i = 0; i < NUM_CM_STAT_ENTRIES; i++)
4168 cm_Display_map[i] = i;
4169 cm_DisplayItems_count = NUM_CM_STAT_ENTRIES;
4174 /* setup an interrupt signal handler; we ain't wanna leak core */
4175 /* this binding is useful only until gtx is initialized after which the
4176 * keyboard input server takes over. */
4177 if ((signal(SIGINT, quit_signal)) == SIG_ERR) {
4178 perror("signal() failed.");
4183 /* init error message buffers. these will be used to print error messages
4184 * once gtx is initialized and there is no access to stderr/stdout */
4190 /* initialize fs and cm circular buffers before initiating probes */
4192 code = init_fs_buffers();
4194 fprintf(stderr, "[ %s ] init_fs_buffers returned %d\n", rn,
4201 code = init_cm_buffers();
4203 fprintf(stderr, "[ %s ] init_cm_buffers returned %d\n", rn,
4210 /* allocate and initialize buffers for holding fs & cm results in ascii
4211 * format suitable for updating the screen */
4212 code = init_print_buffers();
4214 fprintf(stderr, "[ %s ] init_print_buffers returned %d\n", rn, code);
4218 /* perform gtx initializations */
4219 code = gtx_initialize();
4221 fprintf(stderr, "[ %s ] gtx_initialize returned %d\n", rn, code);
4225 /* start xstat probes */
4228 return (0); /* will not return from the call to afsmon_execute() */
4230 } /* afsmonInit() */
4233 /*-----------------------------------------------------------------------
4235 ------------------------------------------------------------------------*/
4237 #include "AFS_component_version_number.c"
4240 main(int argc, char **argv)
4242 afs_int32 code; /*Return code */
4243 struct cmd_syndesc *ts; /*Ptr to cmd line syntax descriptor */
4245 #ifdef AFS_AIX32_ENV
4247 * The following signal action for AIX is necessary so that in case of a
4248 * crash (i.e. core is generated) we can include the user's data section
4249 * in the core dump. Unfortunately, by default, only a partial core is
4250 * generated which, in many cases, isn't too useful.
4252 struct sigaction nsa;
4254 sigemptyset(&nsa.sa_mask);
4255 nsa.sa_handler = SIG_DFL;
4256 nsa.sa_flags = SA_FULLDUMP;
4257 sigaction(SIGSEGV, &nsa, NULL);
4261 * Set up the commands we understand.
4263 ts = cmd_CreateSyntax("initcmd", afsmonInit, NULL, "initialize the program");
4264 cmd_AddParm(ts, "-config", CMD_SINGLE, CMD_OPTIONAL,
4265 "configuration file");
4266 cmd_AddParm(ts, "-frequency", CMD_SINGLE, CMD_OPTIONAL,
4267 "poll frequency, in seconds");
4268 cmd_AddParm(ts, "-output", CMD_SINGLE, CMD_OPTIONAL, "storage file name");
4269 cmd_AddParm(ts, "-detailed", CMD_FLAG, CMD_OPTIONAL,
4270 "output detailed statistics to storage file");
4272 /* we hope to use this .... eventually! */
4273 cmd_AddParm(ts, "-package", CMD_SINGLE, CMD_REQUIRED,
4274 "Graphics Package to use");
4276 cmd_AddParm(ts, "-debug", CMD_SINGLE, CMD_OPTIONAL,
4277 "turn debugging output on to the named file");
4278 cmd_AddParm(ts, "-fshosts", CMD_LIST, CMD_OPTIONAL,
4279 "list of file servers to monitor");
4280 cmd_AddParm(ts, "-cmhosts", CMD_LIST, CMD_OPTIONAL,
4281 "list of cache managers to monitor");
4282 cmd_AddParm(ts, "-buffers", CMD_SINGLE, CMD_OPTIONAL,
4283 "number of buffer slots");
4286 * Parse command-line switches & execute afsmonitor
4289 code = cmd_Dispatch(argc, argv);
4295 exit(0); /* redundant, but gets rid of warning */