2 * Copyright 2000, International Business Machines Corporation and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
9 * Portions Copyright (c) 2003 Apple Computer, Inc.
13 * Afsmonitor: An AFS Performance Monitoring Tool
15 *-------------------------------------------------------------------------*/
18 #include <afsconfig.h>
19 #include <afs/param.h>
29 #include <sys/types.h>
30 #include <netinet/in.h>
31 #include <sys/socket.h>
38 #include <afs/gtxwindows.h> /*Generic window package */
39 #include <afs/gtxobjects.h> /*Object definitions */
40 #include <afs/gtxlightobj.h> /*Light object interface */
41 #include <afs/gtxcurseswin.h> /*Curses window package */
42 #include <afs/gtxdumbwin.h> /*Dumb terminal window package */
43 #include <afs/gtxX11win.h> /*X11 window package */
44 #include <afs/gtxframe.h> /*Frame package */
45 #include <afs/gtxinput.h>
47 #include <afs/xstat_fs.h>
48 #include <afs/xstat_cm.h>
50 #include "afsmonitor.h"
52 /* command line parameter indices */
58 /* #define P_PACKAGE X */
65 int afsmon_debug = 0; /* debug info to file ? */
66 FILE *debugFD; /* debugging file descriptor */
67 static int afsmon_output = 0; /* output to file ? */
68 static int afsmon_detOutput = 0; /* detailed output ? */
69 static int afsmon_onceOnly = 0; /* probe once only ? (not implemented) */
70 int afsmon_probefreq; /* probe frequency */
71 static int wpkg_to_use; /* graphics package to use */
72 static char output_filename[80]; /* output filename */
73 char errMsg[256]; /* buffers used to print error messages after */
74 char errMsg1[256]; /* gtx is initialized (stderr/stdout gone !) */
75 int num_bufSlots = 0; /* number of slots in fs & cm circular buffers */
77 /* Flags used to process "show" directives in config file */
78 short fs_showFlags[NUM_FS_STAT_ENTRIES];
79 short cm_showFlags[NUM_CM_STAT_ENTRIES];
82 /* afsmonitor misc definitions */
84 #define DEFAULT_FREQUENCY 60 /* default proble frequency in seconds */
85 #define DEFAULT_BUFSLOTS 0 /* default number of buffer slots */
86 #define CFG_STR_LEN 80 /* max length of config file fields */
87 #define FS 1 /* for misc. use */
88 #define CM 2 /* for misc. use */
91 #define NUM_XSTAT_FS_AFS_PERFSTATS_LONGS 70 /* number of fields from struct afs_PerfStats that we display */
92 #define NUM_AFS_STATS_CMPERF_LONGS 40 /* number of longs in struct afs_stats_CMPerf excluding up/down stats and fields we dont display */
95 /* variables used for exec'ing user provided threshold handlers */
96 char *fsHandler_argv[20]; /* *argv[] for the handler */
97 char fsHandler_args[20][256]; /* buffer space for arguments */
98 int exec_fsThreshHandler = 0; /* execute fs threshold handler ? */
101 /* THRESHOLD STRUCTURE DEFINITIONS */
103 /* flag to indicate that threshold entries apply to all hosts. these will
104 be turned off when the first fs or cm host entry is processed */
105 static int global_ThreshFlag = 1;
106 static int global_fsThreshCount = 0; /* number of global fs thresholds */
107 static int global_cmThreshCount = 0; /* number of global cm thresholds */
111 /* Linked lists of file server and cache manager host names are made from
112 the entries in the config file. Head pointers to FS and CM server name lists. */
113 static struct afsmon_hostEntry *FSnameList;
114 static struct afsmon_hostEntry *CMnameList;
116 /* number of fileservers and cache managers to monitor */
120 /* number of xstat collection ids */
121 #define MAX_NUM_FS_COLLECTIONS 2
122 #define MAX_NUM_CM_COLLECTIONS 1
123 int num_fs_collections = 0;
124 int num_cm_collections = 0;
126 /* variables used for processing config file */
127 /* ptr to the hostEntry structure of the last "fs" or "cm" entry processed
128 in the config file */
129 static struct afsmon_hostEntry *last_hostEntry;
130 /* names of the last host processed in the config file */
131 static char last_fsHost[HOST_NAME_LEN];
132 static char last_cmHost[HOST_NAME_LEN];
133 static int lastHostType = 0; /* 0 = no host entries processed
134 * 1 = last host was file server
135 * 2 = last host was cache manager. */
138 /* FILE SERVER CIRCULAR BUFFER VARIABLES */
140 struct afsmon_fs_Results_list {
141 struct xstat_fs_ProbeResults *fsResults[MAX_NUM_FS_COLLECTIONS];
142 int empty[MAX_NUM_FS_COLLECTIONS];
143 struct afsmon_fs_Results_list *next;
146 struct afsmon_fs_Results_CBuffer {
147 int probeNum; /* probe number of entries in this slot */
148 struct afsmon_fs_Results_list *list; /* ptr to list of results */
151 int afsmon_fs_results_length[] =
152 { XSTAT_FS_FULLPERF_RESULTS_LEN, XSTAT_FS_CBSTATS_RESULTS_LEN };
154 /* buffer for FS probe results */
155 struct afsmon_fs_Results_CBuffer *afsmon_fs_ResultsCB;
157 int afsmon_fs_curr_CBindex = 0; /* current fs CB slot */
159 /* Probe number variables. The current probe number is incremented
160 when the first probe from a new probe cycle is received. The prev probe
161 number is incremented when the last probe of the current cycle is
162 received. This difference is because of the purpose for which these
165 int afsmon_fs_curr_probeNum = 1; /* current fs probe number */
166 int afsmon_fs_prev_probeNum = 0; /* previous fs probe number */
169 /* CACHE MANAGER CIRCULAR BUFFER VARIABLES */
171 struct afsmon_cm_Results_list {
172 struct xstat_cm_ProbeResults *cmResults[MAX_NUM_CM_COLLECTIONS];
173 int empty[MAX_NUM_CM_COLLECTIONS];
174 struct afsmon_cm_Results_list *next;
177 struct afsmon_cm_Results_CBuffer {
178 int probeNum; /* probe number of entries in this slot */
179 struct afsmon_cm_Results_list *list; /* ptr to list of results */
182 int afsmon_cm_results_length[] = { XSTAT_CM_FULLPERF_RESULTS_LEN };
184 /* buffer for CM probe results */
185 struct afsmon_cm_Results_CBuffer *afsmon_cm_ResultsCB;
187 int afsmon_cm_curr_CBindex = 0; /* current cm CB slot */
190 /* Probe number variables. The current probe number is incremented
191 when the first probe from a new probe cycle is received. The prev probe
192 number is incremented when the last probe of the current cycle is
193 received. This difference is because of the purpose for which these
196 int afsmon_cm_curr_probeNum = 1; /* current cm probe number */
197 int afsmon_cm_prev_probeNum = 0; /* previous cm probe number */
200 /* Structures to hold FS & CM results in string format(suitable for display ) */
202 /* ptr to array holding the results of FS probes in ascii format */
203 /* for current probe cycle */
204 struct fs_Display_Data *curr_fsData = (struct fs_Display_Data *)0;
205 /* for previous probe cycle */
206 struct fs_Display_Data *prev_fsData = (struct fs_Display_Data *)0;
209 /* ptr to array holding the results of CM probes in ascii format */
210 /* for current probe cycle */
211 struct cm_Display_Data *curr_cmData = (struct cm_Display_Data *)0;
212 /* for previous probe cycle */
213 struct cm_Display_Data *prev_cmData = (struct cm_Display_Data *)0;
215 /* EXTERN DEFINITIONS */
217 /* file server and cache manager variable names (from afsmon_labels.h) */
218 extern char *fs_varNames[];
219 extern char *cm_varNames[];
221 /* GTX & MISC VARIABLES */
223 /* afsmonitor window */
224 extern struct gwin *afsmon_win;
226 /* current page number in the overview frame */
227 extern int ovw_currPage;
229 /* number of FS alerts and number of hosts on FS alerts */
231 int numHosts_onfs_alerts;
233 /* number of CM alerts and number of hosts on FS alerts */
235 int numHosts_oncm_alerts;
237 /* flag to indicate that atleast one probe cycle has completed and
238 data is available for updating the display */
239 extern int fs_Data_Available;
240 extern int cm_Data_Available;
242 extern int gtx_initialized; /* gtx initialized ? */
244 /* This array contains the indices of the file server data items that
245 are to be displayed on the File Servers screen. For example, suppose the
246 user wishes to display only the vcache statistics then the following array
247 will contain indices 2 to 14 corresponding to the position of the
248 vcache data items in the fs_varNames[] array. If the config file contains
249 no "show fs .." directives, it will contain the indices of all the
250 items in the fs_varNames[] array */
252 short fs_Display_map[NUM_FS_STAT_ENTRIES];
253 int fs_DisplayItems_count = 0; /* number of items to display */
254 int fs_showDefault = 1; /* show all of FS data ? */
257 /* same use as above for Cache Managers */
258 short cm_Display_map[NUM_CM_STAT_ENTRIES];
259 int cm_DisplayItems_count = 0; /* number of items to display */
260 int cm_showDefault = 1; /* show all of CM data ? */
262 extern int fs_currPage; /* current page number in the File Servers frame */
263 extern int fs_curr_LCol; /* current leftmost column on display on FS frame */
265 extern int cm_currPage; /* current page number in the Cache Managers frame */
266 extern int cm_curr_LCol; /* current leftmost column on display on CM frame */
268 /* File server and Cache manager data is classified into sections &
269 groups to help the user choose what he wants displayed */
270 extern char *fs_categories[]; /* file server data category names */
271 extern char *cm_categories[]; /* cache manager data category names */
274 static int fs_FullPerfs_ltoa(struct fs_Display_Data *a_fsData,
275 struct xstat_fs_ProbeResults *a_fsResults);
276 static int fs_CallBackStats_ltoa(struct fs_Display_Data *a_fsData,
277 struct xstat_fs_ProbeResults *a_fsResults);
279 #ifdef HAVE_STRCASESTR
280 extern char * strcasestr(const char *, const char *);
283 strcasestr(): Return first occurence of pattern s2 in s1, case
286 This routine is required since I made pattern matching of the
287 config file to be case insensitive.
302 return ((char *)NULL);
306 while (len1 >= len2 && len1 > 0) {
307 if ((strncasecmp(ptr, s2, len2)) == 0)
312 return ((char *)NULL);
317 GetHostByName(char *name)
324 he = gethostbyname(name);
326 /* On solaris the above does not resolve hostnames to full names */
328 memcpy(ip_addr, he->h_addr, he->h_length);
329 he = gethostbyaddr(ip_addr, he->h_length, he->h_addrtype);
336 /*-----------------------------------------------------------------------
340 * Exit gracefully from the afsmonitor. Frees memory where appropriate,
341 * cleans up after gtx and closes all open file descriptors. If a user
342 * provided threshold handler is to be exec'ed then gtx cleanup is
343 * not performed and an exec() is made instead of an exit().
349 * This function is called to execute a user handler only
350 * by a child process.
352 *----------------------------------------------------------------------*/
355 afsmon_Exit(int a_exitVal) /* exit code */
357 static char rn[] = "afsmon_Exit";
358 struct afsmon_fs_Results_list *tmp_fslist;
359 struct afsmon_fs_Results_list *next_fslist;
360 struct xstat_fs_ProbeResults *tmp_xstat_fsPR;
361 struct afsmon_cm_Results_list *tmp_cmlist;
362 struct afsmon_cm_Results_list *next_cmlist;
363 struct xstat_cm_ProbeResults *tmp_xstat_cmPR;
364 struct afsmon_hostEntry *curr_hostEntry;
365 struct afsmon_hostEntry *next_hostEntry;
372 fprintf(debugFD, "[ %s ] Called with exit code %d\n", rn, a_exitVal);
376 /* get out of curses first, but not if we are here to exec a threshold
377 * handler. If we do, the screen gets messed up */
378 if (gtx_initialized && !exec_fsThreshHandler)
379 gator_cursesgwin_cleanup(afsmon_win);
381 /* print the error message buffer */
382 if (errMsg[0] != '\0')
383 fprintf(stderr, "%s", errMsg);
384 if (errMsg1[0] != '\0')
385 fprintf(stderr, "%s", errMsg1);
387 /* deallocate file server circular buffers */
388 if (numFS && num_bufSlots) {
390 fprintf(debugFD, "freeing FS circular buffers ");
394 for (bufslot = 0; bufslot < num_bufSlots; bufslot++) {
396 fprintf(debugFD, " %d) ", bufslot);
397 if (afsmon_fs_ResultsCB[bufslot].list !=
398 (struct afsmon_fs_Results_list *)0) {
399 tmp_fslist = afsmon_fs_ResultsCB[bufslot].list;
402 /* make sure we do not go astray */
406 "[ %s ] error in deallocating fs CB\n",
410 next_fslist = tmp_fslist->next;
411 for (i = 0; i < MAX_NUM_FS_COLLECTIONS; i++) {
412 tmp_xstat_fsPR = tmp_fslist->fsResults[i];
415 fprintf(debugFD, "%d ", numFS - j);
417 /* free xstat_fs_Results data */
418 free(tmp_xstat_fsPR->data.AFS_CollData_val);
419 free(tmp_xstat_fsPR->connP);
420 free(tmp_xstat_fsPR);
423 /* free the fs list item */
425 tmp_fslist = next_fslist;
427 } /* while fs list items in this slot */
428 } /* if entries in this buffer slot */
429 } /* for each fs buffer slot */
431 fprintf(debugFD, "\n");
436 /* deallocate cache manager curcular buffers */
437 if (numCM && num_bufSlots) {
439 fprintf(debugFD, "freeing CM curcular buffers ");
440 for (bufslot = 0; bufslot < num_bufSlots; bufslot++) {
442 fprintf(debugFD, " %d) ", bufslot);
443 if (afsmon_cm_ResultsCB[bufslot].list !=
444 (struct afsmon_cm_Results_list *)0) {
445 tmp_cmlist = afsmon_cm_ResultsCB[bufslot].list;
448 /* make sure we do not go astray */
452 "[ %s ] error in deallocating cm CB\n",
456 next_cmlist = tmp_cmlist->next;
457 for (i = 0; i < MAX_NUM_CM_COLLECTIONS; i++) {
458 tmp_xstat_cmPR = tmp_cmlist->cmResults[i];
461 fprintf(debugFD, "%d ", numCM - j);
462 /* make sure data is ok */
463 /* Print_cm_FullPerfInfo(tmp_xstat_cmPR); */
465 /* free xstat_cm_Results data */
466 free(tmp_xstat_cmPR->data.AFSCB_CollData_val);
467 free(tmp_xstat_cmPR->connP);
469 free(tmp_cmlist->cmResults);
471 /* free the cm list item */
473 tmp_cmlist = next_cmlist;
475 } /* while cm list items in this slot */
476 } /* if entries in this buffer slot */
477 } /* for each cm buffer slot */
479 fprintf(debugFD, "\n");
483 /* deallocate FS & CM Print buffers */
484 if (curr_fsData != (struct fs_Display_Data *)0) {
486 fprintf(debugFD, "Deallocating FS Print Buffers .... curr");
489 if (prev_fsData != (struct fs_Display_Data *)0) {
491 fprintf(debugFD, ", prev \n");
494 if (prev_cmData != (struct cm_Display_Data *)0) {
496 fprintf(debugFD, "Deallocating CM Print Buffers .... curr");
499 if (prev_cmData != (struct cm_Display_Data *)0) {
501 fprintf(debugFD, ", prev \n");
505 /* deallocate hostEntry lists */
508 fprintf(debugFD, "Deallocating FS hostEntries ..");
509 curr_hostEntry = FSnameList;
510 while (curr_hostEntry) {
511 next_hostEntry = curr_hostEntry->next;
512 if (curr_hostEntry->thresh != NULL)
513 free(curr_hostEntry->thresh);
514 free(curr_hostEntry);
515 curr_hostEntry = next_hostEntry;
518 fprintf(debugFD, "\n");
522 fprintf(debugFD, "Deallocating CM hostEntries ..");
523 curr_hostEntry = CMnameList;
524 while (curr_hostEntry) {
525 next_hostEntry = curr_hostEntry->next;
526 if (curr_hostEntry->thresh != NULL)
527 free(curr_hostEntry->thresh);
528 free(curr_hostEntry);
529 curr_hostEntry = next_hostEntry;
532 fprintf(debugFD, "\n");
535 /* close debug file */
541 if (exec_fsThreshHandler) {
542 code = execvp(fsHandler_argv[0], fsHandler_argv);
544 fprintf(stderr, "execvp() of %s returned %d, errno %d\n",
545 fsHandler_argv[0], code, errno);
553 /*-----------------------------------------------------------------------
557 * Insert a hostname in the file server names list.
562 *----------------------------------------------------------------------*/
565 insert_FS(char *a_hostName) /* name of cache manager to be inserted in list */
567 static struct afsmon_hostEntry *curr_item;
568 static struct afsmon_hostEntry *prev_item;
570 if (*a_hostName == '\0')
572 curr_item = malloc(sizeof(struct afsmon_hostEntry));
573 if (curr_item == (struct afsmon_hostEntry *)0) {
574 fprintf(stderr, "Failed to allocate space for FS nameList\n");
578 strncpy(curr_item->hostName, a_hostName, CFG_STR_LEN);
579 curr_item->next = (struct afsmon_hostEntry *)0;
580 curr_item->numThresh = 0;
581 curr_item->thresh = NULL;
583 if (FSnameList == (struct afsmon_hostEntry *)0)
584 FSnameList = curr_item;
586 prev_item->next = curr_item;
588 prev_item = curr_item;
589 /* record the address of this entry so that its threshold
590 * count can be incremented during the first pass of the config file */
591 last_hostEntry = curr_item;
596 /*-----------------------------------------------------------------------
601 * Prints the file server names linked list.
605 *----------------------------------------------------------------------*/
609 static char rn[] = "print_FS";
610 struct afsmon_hostEntry *tempFS;
611 struct Threshold *threshP;
615 fprintf(debugFD, "[ %s ] Called\n", rn);
621 fprintf(debugFD, "No of File Servers: %d\n", numFS);
624 fprintf(debugFD, "\t %s threshCount = %d\n", tempFS->hostName,
626 threshP = tempFS->thresh;
627 for (i = 0; i < tempFS->numThresh; i++, threshP++)
628 fprintf(debugFD, "\t thresh (%2d) %s %s %s\n",
629 threshP->index, threshP->itemName,
630 threshP->threshVal, threshP->handler);
631 } while ((tempFS = tempFS->next) != (struct afsmon_hostEntry *)0);
633 fprintf(debugFD, "\t\t-----End of List-----\n");
639 /*-----------------------------------------------------------------------
643 * Insert a hostname in the cache manager names list.
648 *----------------------------------------------------------------------*/
651 insert_CM(char *a_hostName) /* name of cache manager to be inserted in list */
653 static struct afsmon_hostEntry *curr_item;
654 static struct afsmon_hostEntry *prev_item;
656 if (*a_hostName == '\0')
658 curr_item = malloc(sizeof(struct afsmon_hostEntry));
659 if (curr_item == (struct afsmon_hostEntry *)0) {
660 fprintf(stderr, "Failed to allocate space for CM nameList\n");
664 strncpy(curr_item->hostName, a_hostName, CFG_STR_LEN);
665 curr_item->next = (struct afsmon_hostEntry *)0;
666 curr_item->numThresh = 0;
667 curr_item->thresh = NULL;
669 if (CMnameList == (struct afsmon_hostEntry *)0)
670 CMnameList = curr_item;
672 prev_item->next = curr_item;
674 prev_item = curr_item;
675 /* side effect. note the address of this entry so that its threshold
676 * count can be incremented during the first pass of the config file */
677 last_hostEntry = curr_item;
683 /*-----------------------------------------------------------------------
688 * Prints the cache manager names linked list.
692 *----------------------------------------------------------------------*/
696 static char rn[] = "print_CM";
697 struct afsmon_hostEntry *tempCM;
698 struct Threshold *threshP;
702 fprintf(debugFD, "[ %s ] Called\n", rn);
708 fprintf(debugFD, "No of Cache Managers: %d\n", numCM);
711 fprintf(debugFD, "\t %s threshCount = %d\n", tempCM->hostName,
713 threshP = tempCM->thresh;
714 for (i = 0; i < tempCM->numThresh; i++, threshP++)
715 fprintf(debugFD, "\t thresh (%2d) %s %s %s\n",
716 threshP->index, threshP->itemName,
717 threshP->threshVal, threshP->handler);
718 } while ((tempCM = tempCM->next) != (struct afsmon_hostEntry *)0);
720 fprintf(debugFD, "\t\t-----End of List-----\n");
727 /*-----------------------------------------------------------------------
731 * Parse the host entry line in the config file. Check the syntax,
732 * and inserts the host name in the FS ot CM linked list. Also
733 * remember if this entry was an fs or cm & the ptr to its hostEntry
734 * structure. The threshold entries in the config file are dependent
735 * on their position relative to the hostname entries. Hence it is
736 * required to remember the names of the last file server and cache
737 * manager entries that were processed.
743 *----------------------------------------------------------------------*/
746 parse_hostEntry(char *a_line)
747 { /* parse_hostEntry */
749 static char rn[] = "parse_hostEntry"; /* routine name */
750 char opcode[CFG_STR_LEN]; /* specifies type of config entry */
751 char arg1[CFG_STR_LEN]; /* hostname or qualifier (fs/cm?) */
752 char arg2[CFG_STR_LEN]; /* threshold variable */
753 char arg3[CFG_STR_LEN]; /* threshold value */
754 char arg4[CFG_STR_LEN]; /* user's handler */
755 struct hostent *he; /* host entry */
758 fprintf(debugFD, "[ %s ] Called, a_line = %s\n", rn, a_line);
768 sscanf(a_line, "%s %s %s %s %s", opcode, arg1, arg2, arg3, arg4);
769 /* syntax is "opcode hostname" */
770 if ((strlen(arg2)) != 0) {
771 fprintf(stderr, "[ %s ] Extraneous characters at end of line\n", rn);
776 he = GetHostByName(arg1);
778 fprintf(stderr, "[ %s ] Unable to resolve hostname %s\n", rn, arg1);
782 if ((strcasecmp(opcode, "fs")) == 0) {
783 /* use the complete host name to insert in the file server names list */
784 insert_FS(he->h_name);
785 /* note that last host entry in the config file was fs */
788 /* threholds are not global anymore */
789 if (global_ThreshFlag)
790 global_ThreshFlag = 0;
791 } else if ((strcasecmp(opcode, "cm")) == 0) {
792 /* use the complete host name to insert in the CM names list */
793 insert_CM(he->h_name);
794 /* last host entry in the config file was cm */
797 /* threholds are not global anymore */
798 if (global_ThreshFlag)
799 global_ThreshFlag = 0;
806 /*-----------------------------------------------------------------------
807 * parse_threshEntry()
810 * Parse the threshold entry line in the config file. This function is
811 * called in the the first pass of the config file. It checks the syntax
812 * of the config lines and verifies their positional validity - eg.,
813 * a cm threshold cannot appear after a fs hostname entry, etc.
814 * It also counts the thresholds applicable to each host.
820 *----------------------------------------------------------------------*/
823 parse_threshEntry(char *a_line)
824 { /* parse_threshEntry */
825 static char rn[] = "parse_threshEntry"; /* routine name */
826 char opcode[CFG_STR_LEN]; /* specifies type of config entry */
827 char arg1[CFG_STR_LEN]; /* hostname or qualifier (fs/cm?) */
828 char arg2[CFG_STR_LEN]; /* threshold variable */
829 char arg3[CFG_STR_LEN]; /* threshold value */
830 char arg4[CFG_STR_LEN]; /* user's handler */
831 char arg5[CFG_STR_LEN]; /* junk characters */
834 fprintf(debugFD, "[ %s ] Called, a_line = %s\n", rn, a_line);
845 sscanf(a_line, "%s %s %s %s %s %s", opcode, arg1, arg2, arg3, arg4, arg5);
847 /* syntax is "thresh fs/cm variable_name threshold_value [handler] " */
848 if (((strlen(arg1)) == 0) || ((strlen(arg2)) == 0)
849 || ((strlen(arg3)) == 0)) {
850 fprintf(stderr, "[ %s ] Incomplete line\n", rn);
853 if (strlen(arg3) > THRESH_VAR_LEN - 2) {
854 fprintf(stderr, "[%s ] threshold value too long\n", rn);
858 if ((strcasecmp(arg1, "fs")) == 0) {
859 switch (lastHostType) {
860 case 0: /* its a global threshold */
861 global_fsThreshCount++;
863 case 1: /* inc thresh count of last file server */
864 last_hostEntry->numThresh++;
868 "[ %s ] A threshold for a File Server cannot be placed after a Cache Manager host entry in the config file \n",
872 fprintf(stderr, "[ %s ] Programming error 1\n", rn);
875 } else if ((strcasecmp(arg1, "cm")) == 0) {
876 switch (lastHostType) {
877 case 0: /* its a global threshold */
878 global_cmThreshCount++;
880 case 2: /* inc thresh count of last cache manager */
881 last_hostEntry->numThresh++;
885 "[ %s ] A threshold for a Cache Manager cannot be placed after a File Server host entry in the config file \n",
889 fprintf(stderr, "[ %s ] Programming error 2\n", rn);
894 "[ %s ] Syntax error. Second argument should be \"fs\" or \"cm\" \n",
900 } /* parse_threshEntry */
903 /*-----------------------------------------------------------------------
907 * The thresholds applicable to each host machine are stored in the
908 * FSnameList and CMnameList. Threshold entries in the config file are
909 * context sensitive. The host to which this threshold is applicable
910 * is pointed to by last_fsHost (for file servers) and last_cmHost
911 * for cache managers. For global thresholds the info is recorded for
912 * all the hosts. This function is called in the second pass of the
913 * config file. In the first pass a count of the number of global
914 * thresholds is determined and this information is used in this
915 * routine. If threshold entries are duplicated the first entry is
917 * Each threshold entry also has an index field. This is a positional
918 * index to the corresponding variable in the prev_[fs/cm]Data arrays.
919 * This makes it easy to check the threshold for overflow.
924 *----------------------------------------------------------------------*/
927 store_threshold(int a_type, /* 1 = fs , 2 = cm */
928 char *a_varName, /* threshold name */
929 char *a_value, /* threshold value */
930 char *a_handler) /* threshold overflow handler */
931 { /* store_thresholds */
933 static char rn[] = "store_thresholds"; /* routine name */
934 struct afsmon_hostEntry *tmp_host; /* tmp ptr to hostEntry */
935 struct afsmon_hostEntry *Header; /* tmp ptr to hostEntry list header */
936 struct Threshold *threshP; /* tmp ptr to threshold list */
938 int index; /* index to fs_varNames or cm_varNames */
941 int srvCount; /* tmp count of host names */
942 int *global_TC; /* ptr to global_xxThreshCount */
947 "[ %s ] Called, a_type= %d, a_varName= %s, a_value= %s, a_handler=%s\n",
948 rn, a_type, a_varName, a_value, a_handler);
952 /* resolve the threshold variable name */
954 if (a_type == 1) { /* fs threshold */
955 for (index = 0; index < NUM_FS_STAT_ENTRIES; index++) {
956 if (strcasecmp(a_varName, fs_varNames[index]) == 0) {
962 fprintf(stderr, "[ %s ] Unknown FS threshold variable name %s\n",
968 hostname = last_fsHost;
969 global_TC = &global_fsThreshCount;
970 } else if (a_type == 2) { /* cm threshold */
971 for (index = 0; index < NUM_CM_STAT_ENTRIES; index++) {
972 if (strcasecmp(a_varName, cm_varNames[index]) == 0) {
978 fprintf(stderr, "[ %s ] Unknown CM threshold variable name %s\n",
984 hostname = last_cmHost;
985 global_TC = &global_cmThreshCount;
991 /* if the global thresh count is not zero, place this threshold on
992 * all the host entries */
996 for (i = 0; i < srvCount; i++) {
997 threshP = tmp_host->thresh;
999 for (j = 0; j < tmp_host->numThresh; j++) {
1000 if ((threshP->itemName[0] == '\0')
1001 || (strcasecmp(threshP->itemName, a_varName) == 0)) {
1002 strncpy(threshP->itemName, a_varName,
1003 THRESH_VAR_NAME_LEN);
1004 strncpy(threshP->threshVal, a_value, THRESH_VAR_LEN);
1005 strcpy(threshP->handler, a_handler);
1006 threshP->index = index;
1013 fprintf(stderr, "[ %s ] Could not insert threshold entry",
1015 fprintf(stderr, "for %s in thresh list of host %s \n",
1016 a_varName, tmp_host->hostName);
1019 tmp_host = tmp_host->next;
1025 /* it is not a global threshold, insert it in the thresh list of this
1026 * host only. We overwrite the global threshold if it was alread set */
1028 if (*hostname == '\0') {
1029 fprintf(stderr, "[ %s ] Programming error 3\n", rn);
1033 /* get the hostEntry that this threshold belongs to */
1036 for (i = 0; i < srvCount; i++) {
1037 if (strcasecmp(tmp_host->hostName, hostname) == 0) {
1041 tmp_host = tmp_host->next;
1044 fprintf(stderr, "[ %s ] Unable to find host %s in %s hostEntry list",
1045 rn, hostname, (a_type - 1) ? "CM" : "FS");
1049 /* put this entry on the thresh list of this host, overwrite global value
1052 threshP = tmp_host->thresh;
1054 for (i = 0; i < tmp_host->numThresh; i++) {
1055 if ((threshP->itemName[0] == '\0')
1056 || (strcasecmp(threshP->itemName, a_varName) == 0)) {
1057 strncpy(threshP->itemName, a_varName, THRESH_VAR_NAME_LEN);
1058 strncpy(threshP->threshVal, a_value, THRESH_VAR_LEN);
1059 strcpy(threshP->handler, a_handler);
1060 threshP->index = index;
1069 "[ %s ] Unable to insert threshold %s for %s host %s\n", rn,
1070 a_varName, (a_type - 1) ? "CM" : "FS", tmp_host->hostName);
1076 } /* store_thresholds */
1079 /*-----------------------------------------------------------------------
1083 * This function process a "show" entry in the config file. A "show"
1084 * entry specifies what statistics the user wants to see. File
1085 * server and Cache Manager data is divided into sections. Each section
1086 * is made up of one or more groups. If a group name is specified only
1087 * those statistics under that group are shown. If a section name is
1088 * specified all the groups under this section are shown.
1089 * Data as obtained from the xstat probes is considered to be ordered.
1090 * This data is mapped to the screen thru fs_Display_map[] and
1091 * cm_Display_map[]. This routine parses the "show" entry against the
1092 * section/group names in the [fs/cm]_categories[] array. If there is
1093 * no match it tries to match it against a variable name in
1094 * [fs/cm]_varNames[] array. In each case the corresponding indices to
1095 * the data is the [fs/cm]_displayInfo[] is recorded.
1099 * Failure: -1 (invalid entry)
1100 * > -1 (programming error)
1101 *----------------------------------------------------------------------*/
1104 parse_showEntry(char *a_line)
1105 { /* parse_showEntry */
1106 static char rn[] = "parse_showEntry";
1107 char opcode[CFG_STR_LEN]; /* specifies type of config entry */
1108 char arg1[CFG_STR_LEN]; /* show fs or cm entry ? */
1109 char arg2[CFG_STR_LEN]; /* what we gotta show */
1110 char arg3[CFG_STR_LEN]; /* junk */
1111 char catName[CFG_STR_LEN]; /* for category names */
1112 int numGroups; /* number of groups in a section */
1116 int idx = 0; /* index to fs_categories[] */
1122 fprintf(debugFD, "[ %s ] Called, a_line= %s\n", rn, a_line);
1129 sscanf(a_line, "%s %s %s %s", opcode, arg1, arg2, arg3);
1131 if (arg3[0] != '\0') {
1132 fprintf(stderr, "[ %s ] Extraneous characters at end of line\n", rn);
1136 if ((strcasecmp(arg1, "fs") != 0) && (strcasecmp(arg1, "cm") != 0)) {
1138 "[ %s ] Second argument of \"show\" directive should be \"fs\" or \"cm\" \n",
1143 /* Each entry can either be a variable name or a section/group name. Variable
1144 * names are listed in xx_varNames[] and section/group names in xx_categories[].
1145 * The section/group names in xx_categiries[] also give the starting/ending
1146 * indices of the variables belonging to that section/group. These indices
1147 * are stored in order in xx_Display_map[] and displayed to the screen in that
1150 /* To handle duplicate "show" entries we keep track of what what we have
1151 * already marked to show in the xx_showFlags[] */
1153 if (strcasecmp(arg1, "fs") == 0) { /* its a File Server entry */
1155 /* mark that we have to show only what the user wants */
1158 /* if it is a section/group name, find it in the fs_categories[] array */
1161 if (strcasestr(arg2, "_section") != (char *)NULL
1162 || strcasestr(arg2, "_group") != (char *)NULL) {
1164 while (idx < FS_NUM_DATA_CATEGORIES) {
1165 sscanf(fs_categories[idx], "%s %d %d", catName, &fromIdx,
1168 if (strcasecmp(arg2, catName) == 0) {
1174 if (!found) { /* typo in section/group name */
1176 "[ %s ] Could not find section/group name %s\n", rn,
1182 /* if it is a group name, read its start/end indices and fill in the
1183 * fs_Display_map[]. */
1185 if (strcasestr(arg2, "_group") != (char *)NULL) {
1187 if (fromIdx < 0 || toIdx < 0 || fromIdx > NUM_FS_STAT_ENTRIES
1188 || toIdx > NUM_FS_STAT_ENTRIES)
1190 for (j = fromIdx; j <= toIdx; j++) {
1191 if (!fs_showFlags[j]) {
1192 fs_Display_map[fs_DisplayItems_count] = j;
1193 fs_DisplayItems_count++;
1194 fs_showFlags[j] = 1;
1196 if (fs_DisplayItems_count > NUM_FS_STAT_ENTRIES) {
1197 fprintf(stderr, "[ %s ] fs_DisplayItems_count ovf\n", rn);
1202 /* if it is a section name, get the count of number of groups in it and
1203 * for each group fill in the start/end indices in the fs_Display_map[] */
1205 if (strcasestr(arg2, "_section") != (char *)NULL) {
1206 /* fromIdx is actually the number of groups in thi section */
1207 numGroups = fromIdx;
1208 /* for each group in section */
1209 while (idx < FS_NUM_DATA_CATEGORIES && numGroups) {
1210 sscanf(fs_categories[idx], "%s %d %d", catName, &fromIdx,
1213 if (strcasestr(catName, "_group") != NULL) {
1214 if (fromIdx < 0 || toIdx < 0
1215 || fromIdx > NUM_FS_STAT_ENTRIES
1216 || toIdx > NUM_FS_STAT_ENTRIES)
1218 for (j = fromIdx; j <= toIdx; j++) {
1219 if (!fs_showFlags[j]) {
1220 fs_Display_map[fs_DisplayItems_count] = j;
1221 fs_DisplayItems_count++;
1222 fs_showFlags[j] = 1;
1224 if (fs_DisplayItems_count > NUM_FS_STAT_ENTRIES) {
1226 "[ %s ] fs_DisplayItems_count ovf\n", rn);
1231 fprintf(stderr, "[ %s ] Error parsing groups for %s\n",
1237 } /* for each group in section */
1240 } else { /* it is a variable name */
1242 for (i = 0; i < NUM_FS_STAT_ENTRIES; i++) {
1243 if (strcasecmp(arg2, fs_varNames[i]) == 0) {
1244 if (!fs_showFlags[i]) {
1245 fs_Display_map[fs_DisplayItems_count] = i;
1246 fs_DisplayItems_count++;
1247 fs_showFlags[i] = 1;
1249 if (fs_DisplayItems_count >= NUM_FS_STAT_ENTRIES) {
1250 fprintf(stderr, "[ %s ] fs_DisplayItems_count ovf\n",
1257 if (!found) { /* typo in section/group name */
1258 fprintf(stderr, "[ %s ] Could not find variable name %s\n",
1262 } /* its a variable name */
1266 /* it is an fs entry */
1267 if (strcasecmp(arg1, "cm") == 0) { /* its a Cache Manager entry */
1270 /* mark that we have to show only what the user wants */
1273 /* if it is a section/group name, find it in the cm_categories[] array */
1276 if (strcasestr(arg2, "_section") != (char *)NULL
1277 || strcasestr(arg2, "_group") != (char *)NULL) {
1279 while (idx < CM_NUM_DATA_CATEGORIES) {
1280 sscanf(cm_categories[idx], "%s %d %d", catName, &fromIdx,
1283 if (strcasecmp(arg2, catName) == 0) {
1289 if (!found) { /* typo in section/group name */
1291 "[ %s ] Could not find section/group name %s\n", rn,
1297 /* if it is a group name, read its start/end indices and fill in the
1298 * cm_Display_map[]. */
1300 if (strcasestr(arg2, "_group") != (char *)NULL) {
1302 if (fromIdx < 0 || toIdx < 0 || fromIdx > NUM_CM_STAT_ENTRIES
1303 || toIdx > NUM_CM_STAT_ENTRIES)
1305 for (j = fromIdx; j <= toIdx; j++) {
1306 if (!cm_showFlags[j]) {
1307 cm_Display_map[cm_DisplayItems_count] = j;
1308 cm_DisplayItems_count++;
1309 cm_showFlags[j] = 1;
1311 if (cm_DisplayItems_count > NUM_CM_STAT_ENTRIES) {
1312 fprintf(stderr, "[ %s ] cm_DisplayItems_count ovf\n", rn);
1317 /* if it is a section name, get the count of number of groups in it and
1318 * for each group fill in the start/end indices in the cm_Display_map[] */
1320 if (strcasestr(arg2, "_section") != (char *)NULL) {
1321 /* fromIdx is actually the number of groups in thi section */
1322 numGroups = fromIdx;
1323 /* for each group in section */
1324 while (idx < CM_NUM_DATA_CATEGORIES && numGroups) {
1325 sscanf(cm_categories[idx], "%s %d %d", catName, &fromIdx,
1328 if (strcasestr(catName, "_group") != NULL) {
1329 if (fromIdx < 0 || toIdx < 0
1330 || fromIdx > NUM_CM_STAT_ENTRIES
1331 || toIdx > NUM_CM_STAT_ENTRIES)
1333 for (j = fromIdx; j <= toIdx; j++) {
1334 if (!cm_showFlags[j]) {
1335 cm_Display_map[cm_DisplayItems_count] = j;
1336 cm_DisplayItems_count++;
1337 cm_showFlags[j] = 1;
1339 if (cm_DisplayItems_count > NUM_CM_STAT_ENTRIES) {
1341 "[ %s ] cm_DisplayItems_count ovf\n", rn);
1346 fprintf(stderr, "[ %s ] Error parsing groups for %s\n",
1352 } /* for each group in section */
1353 } else { /* it is a variable name */
1355 for (i = 0; i < NUM_CM_STAT_ENTRIES; i++) {
1356 if (strcasecmp(arg2, cm_varNames[i]) == 0) {
1357 if (!cm_showFlags[i]) {
1358 cm_Display_map[cm_DisplayItems_count] = i;
1359 cm_DisplayItems_count++;
1360 cm_showFlags[i] = 1;
1362 if (cm_DisplayItems_count >= NUM_CM_STAT_ENTRIES) {
1363 fprintf(stderr, "[ %s ] cm_DisplayItems_count ovf\n",
1370 if (!found) { /* typo in section/group name */
1371 fprintf(stderr, "[ %s ] Could not find variable name %s\n",
1375 } /* its a variable name */
1378 /* it is an cm entry */
1380 } /* parse_showEntry */
1383 /*-----------------------------------------------------------------------
1384 * process_config_file()
1387 * Parse config file entries in two passes. In the first pass:
1388 * - the syntax of all the entries is checked
1389 * - host names are noted and the FSnamesList and CMnamesList
1391 * - a count of the global thresholds and local thresholds of
1392 * each host are counted.
1393 * - "show" entries are processed.
1394 * In the second pass:
1395 * - thresholds are stored
1399 * Failure: Exits afsmonitor showing error and line.
1400 *----------------------------------------------------------------------*/
1403 process_config_file(char *a_config_filename)
1404 { /* process_config_file() */
1405 static char rn[] = "process_config_file"; /* routine name */
1406 FILE *configFD; /* config file descriptor */
1407 char line[4 * CFG_STR_LEN]; /* a line of config file */
1408 char opcode[CFG_STR_LEN]; /* specifies type of config entry */
1409 char arg1[CFG_STR_LEN]; /* hostname or qualifier (fs/cm?) */
1410 char arg2[CFG_STR_LEN]; /* threshold variable */
1411 char arg3[CFG_STR_LEN]; /* threshold value */
1412 char arg4[CFG_STR_LEN]; /* user's handler */
1413 struct afsmon_hostEntry *curr_host;
1414 struct hostent *he; /* hostentry to resolve host name */
1415 char *handlerPtr; /* ptr to pass theresh handler string */
1416 int code = 0; /* error code */
1417 int linenum = 0; /* config file line number */
1418 int error_in_config; /* syntax errors in config file ?? */
1423 fprintf(debugFD, "[ %s ] Called, a_config_filename= %s\n", rn,
1428 /* open config file */
1430 configFD = fopen(a_config_filename, "r");
1431 if (configFD == (FILE *) 0) {
1432 fprintf(stderr, "Failed to open config file %s \n",
1435 fprintf(debugFD, "[ %s ] Failed to open config file %s \n", rn,
1442 /* parse config file */
1444 /* We process the config file in two passes. In the first pass we check
1445 * for correct syntax and for valid entries and also keep count of the
1446 * number of servers and thresholds to monitor. This the data strctures
1447 * can be arrays instead of link lists since we would know their sizes. */
1453 error_in_config = 0; /* flag to note if config file has syntax errors */
1455 while ((fgets(line, CFG_STR_LEN, configFD)) != NULL) {
1461 sscanf(line, "%s %s %s %s %s", opcode, arg1, arg2, arg3, arg4);
1463 /* skip blank lines and comment lines */
1464 if ((strlen(opcode) == 0) || line[0] == '#')
1467 if ((strcasecmp(opcode, "fs") == 0)
1468 || (strcasecmp(opcode, "cm")) == 0) {
1469 code = parse_hostEntry(line);
1470 } else if ((strcasecmp(opcode, "thresh")) == 0) {
1471 code = parse_threshEntry(line);
1472 } else if ((strcasecmp(opcode, "show")) == 0) {
1473 code = parse_showEntry(line);
1475 fprintf(stderr, "[ %s ] Unknown opcode %s\n", rn, opcode);
1480 fprintf(stderr, "[ %s ] Error in line:\n %d: %s\n", rn, linenum,
1482 error_in_config = 1;
1486 if (error_in_config)
1490 fprintf(debugFD, "Global FS thresholds count = %d\n",
1491 global_fsThreshCount);
1492 fprintf(debugFD, "Global CM thresholds count = %d\n",
1493 global_cmThreshCount);
1497 /* the threshold count of all hosts in increased by 1 for each global
1498 * threshold. If one of the hosts has a local threshold for the same
1499 * variable it would end up being counted twice. whats a few bytes of memory
1500 * wasted anyway ? */
1502 if (global_fsThreshCount) {
1503 curr_host = FSnameList;
1504 for (i = 0; i < numFS; i++) {
1505 curr_host->numThresh += global_fsThreshCount;
1506 curr_host = curr_host->next;
1509 if (global_cmThreshCount) {
1510 curr_host = CMnameList;
1511 for (i = 0; i < numCM; i++) {
1512 curr_host->numThresh += global_cmThreshCount;
1513 curr_host = curr_host->next;
1518 /* make sure we have something to monitor */
1519 if (numFS == 0 && numCM == 0) {
1521 "\nConfig file must specify atleast one File Server or Cache Manager host to monitor.\n");
1528 fseek(configFD, 0, 0); /* seek to the beginning */
1531 /* allocate memory for threshold lists */
1532 curr_host = FSnameList;
1533 for (i = 0; i < numFS; i++) {
1534 if (curr_host->hostName[0] == '\0') {
1535 fprintf(stderr, "[ %s ] Programming error 4\n", rn);
1538 if (curr_host->numThresh) {
1539 numBytes = curr_host->numThresh * sizeof(struct Threshold);
1540 curr_host->thresh = malloc(numBytes);
1541 if (curr_host->thresh == NULL) {
1542 fprintf(stderr, "[ %s ] Memory Allocation error 1", rn);
1545 memset(curr_host->thresh, 0, numBytes);
1547 curr_host = curr_host->next;;
1550 curr_host = CMnameList;
1551 for (i = 0; i < numCM; i++) {
1552 if (curr_host->hostName[0] == '\0') {
1553 fprintf(stderr, "[ %s ] Programming error 5\n", rn);
1556 if (curr_host->numThresh) {
1557 numBytes = curr_host->numThresh * sizeof(struct Threshold);
1558 curr_host->thresh = malloc(numBytes);
1559 if (curr_host->thresh == NULL) {
1560 fprintf(stderr, "[ %s ] Memory Allocation error 2", rn);
1563 memset(curr_host->thresh, 0, numBytes);
1565 curr_host = curr_host->next;;
1574 last_fsHost[0] = '\0';
1575 last_cmHost[0] = '\0';
1577 while ((fgets(line, CFG_STR_LEN, configFD)) != NULL) {
1583 sscanf(line, "%s %s %s %s %s", opcode, arg1, arg2, arg3, arg4);
1586 /* if we have a host entry, remember the host name */
1587 if (strcasecmp(opcode, "fs") == 0) {
1588 he = GetHostByName(arg1);
1589 strncpy(last_fsHost, he->h_name, HOST_NAME_LEN);
1590 } else if (strcasecmp(opcode, "cm") == 0) {
1591 he = GetHostByName(arg1);
1592 strncpy(last_cmHost, he->h_name, HOST_NAME_LEN);
1593 } else if (strcasecmp(opcode, "thresh") == 0) {
1594 /* if we have a threshold handler it may have arguments
1595 * and the sscanf() above would not get them, so do the
1599 /* now skip over 4 words - this is done by first
1600 * skipping leading blanks then skipping a word */
1601 for (i = 0; i < 4; i++) {
1602 while (isspace(*handlerPtr))
1604 while (!isspace(*handlerPtr))
1607 while (isspace(*handlerPtr))
1609 /* we how have a pointer to the start of the handler
1612 handlerPtr = arg4; /* empty string */
1615 if (strcasecmp(arg1, "fs") == 0)
1616 code = store_threshold(1, /* 1 = fs */
1617 arg2, arg3, handlerPtr);
1619 else if (strcasecmp(arg1, "cm") == 0)
1620 code = store_threshold(2, /* 2 = fs */
1621 arg2, arg3, handlerPtr);
1624 fprintf(stderr, "[ %s ] Programming error 6\n", rn);
1628 fprintf(stderr, "[ %s ] Failed to store threshold\n", rn);
1629 fprintf(stderr, "[ %s ] Error processing line:\n%d: %s", rn,
1641 /*-----------------------------------------------------------------------
1646 * Print the File Server circular buffer.
1650 *----------------------------------------------------------------------*/
1654 { /* Print_FS_CB() */
1656 struct afsmon_fs_Results_list *fslist;
1661 /* print valid info in the fs CB */
1665 "==================== FS Buffer ========================\n");
1666 fprintf(debugFD, "afsmon_fs_curr_CBindex = %d\n",
1667 afsmon_fs_curr_CBindex);
1668 fprintf(debugFD, "afsmon_fs_curr_probeNum = %d\n\n",
1669 afsmon_fs_curr_probeNum);
1671 for (i = 0; i < num_bufSlots; i++) {
1672 fprintf(debugFD, "\t--------- slot %d ----------\n", i);
1673 fslist = afsmon_fs_ResultsCB[i].list;
1676 for (k = 0; k < MAX_NUM_FS_COLLECTIONS; k++) {
1677 if (!(fslist->empty[k])) {
1678 fprintf(debugFD, "\t %d) probeNum = %d host = %s cn = %d",
1680 fslist->fsResults[k]->probeNum,
1681 fslist->fsResults[k]->connP->hostName,
1682 fslist->fsResults[k]->collectionNumber);
1683 if (fslist->fsResults[k]->probeOK)
1684 fprintf(debugFD, " NOTOK\n");
1686 fprintf(debugFD, " OK\n");
1688 fprintf(debugFD, "\t %d) -- empty --\n", j);
1690 fslist = fslist->next;
1693 if (fslist != (struct afsmon_fs_Results_list *)0)
1694 fprintf(debugFD, "dangling last next ptr fs CB\n");
1697 } /* Print_FS_CB() */
1699 /*-----------------------------------------------------------------------
1700 * save_FS_results_inCB()
1703 * Saves the results of the latest FS probe in the fs circular
1704 * buffers. If the current probe cycle is in progress the contents
1705 * of xstat_fs_Results are copied to the end of the list of results
1706 * in the current slot (pointed to by afsmon_fs_curr_CBindex). If
1707 * a new probe cycle has started the next slot in the circular buffer
1708 * is initialized and the results copied. Note that the Rx related
1709 * information available in xstat_fs_Results is not copied.
1713 * Failure: Exits afsmonitor.
1714 *----------------------------------------------------------------------*/
1716 save_FS_results_inCB(int a_newProbeCycle) /* start of a new probe cycle ? */
1717 { /* save_FS_results_inCB() */
1718 static char rn[] = "save_FS_results_inCB"; /* routine name */
1719 struct afsmon_fs_Results_list *tmp_fslist_item; /* temp fs list item */
1720 struct xstat_fs_ProbeResults *tmp_fsPR; /* temp ptr */
1725 fprintf(debugFD, "[ %s ] Called, a_newProbeCycle= %d\n", rn,
1730 switch (xstat_fs_Results.collectionNumber) {
1731 case AFS_XSTATSCOLL_FULL_PERF_INFO:
1734 case AFS_XSTATSCOLL_CBSTATS:
1738 fprintf(stderr, "[ %s ] collection number %d is out of range.\n",
1739 rn, xstat_fs_Results.collectionNumber);
1744 /* If a new probe cycle started, mark the list in the current buffer
1745 * slot empty for resuse. Note that afsmon_fs_curr_CBindex was appropriately
1746 * incremented in afsmon_FS_Handler() */
1748 if (a_newProbeCycle) {
1749 tmp_fslist_item = afsmon_fs_ResultsCB[afsmon_fs_curr_CBindex].list;
1750 for (i = 0; i < numFS; i++) {
1751 tmp_fslist_item->empty[index] = 1;
1752 tmp_fslist_item = tmp_fslist_item->next;
1756 /* locate last unused item in list */
1757 tmp_fslist_item = afsmon_fs_ResultsCB[afsmon_fs_curr_CBindex].list;
1758 for (i = 0; i < numFS; i++) {
1759 if (tmp_fslist_item->empty[index])
1761 tmp_fslist_item = tmp_fslist_item->next;
1764 /* if we could not find one we have an inconsistent list */
1765 if (!tmp_fslist_item->empty[index]) {
1767 "[ %s ] list inconsistency 1. unable to find an empty slot to store results of probenum %d of %s\n",
1768 rn, xstat_fs_Results.probeNum,
1769 xstat_fs_Results.connP->hostName);
1773 tmp_fsPR = tmp_fslist_item->fsResults[index];
1775 /* copy hostname and probe number and probe time and probe status.
1776 * if the probe failed return now */
1778 memcpy(tmp_fsPR->connP->hostName, xstat_fs_Results.connP->hostName,
1779 sizeof(xstat_fs_Results.connP->hostName));
1780 tmp_fsPR->probeNum = xstat_fs_Results.probeNum;
1781 tmp_fsPR->probeTime = xstat_fs_Results.probeTime;
1782 tmp_fsPR->probeOK = xstat_fs_Results.probeOK;
1783 if (xstat_fs_Results.probeOK) { /* probeOK = 1 => notOK */
1784 /* we have a nonempty results structure so mark the list item used */
1785 tmp_fslist_item->empty[index] = 0;
1789 /* copy connection information */
1790 memcpy(&(tmp_fsPR->connP->skt), &(xstat_fs_Results.connP->skt),
1791 sizeof(struct sockaddr_in));
1793 memcpy(tmp_fsPR->connP->hostName, xstat_fs_Results.connP->hostName,
1794 sizeof(xstat_fs_Results.connP->hostName));
1795 tmp_fsPR->collectionNumber = xstat_fs_Results.collectionNumber;
1797 /* copy the probe data information */
1798 tmp_fsPR->data.AFS_CollData_len =
1799 min(xstat_fs_Results.data.AFS_CollData_len,
1800 afsmon_fs_results_length[index]);
1801 memcpy(tmp_fsPR->data.AFS_CollData_val,
1802 xstat_fs_Results.data.AFS_CollData_val,
1803 tmp_fsPR->data.AFS_CollData_len * sizeof(afs_int32));
1806 /* we have a valid results structure so mark the list item used */
1807 tmp_fslist_item->empty[index] = 0;
1809 /* Print the fs circular buffer */
1813 } /* save_FS_results_inCB() */
1816 /*-----------------------------------------------------------------------
1820 * The results of xstat probes are stored in a string format in
1821 * the arrays curr_fsData and prev_fsData. The information stored in
1822 * prev_fsData is copied to the screen.
1823 * This function converts xstat FS results from longs to strings and
1824 * place them in the given buffer (a pointer to an item in curr_fsData).
1825 * When a probe cycle completes, curr_fsData is copied to prev_fsData
1826 * in afsmon_FS_Hnadler().
1830 *----------------------------------------------------------------------*/
1833 fs_Results_ltoa(struct fs_Display_Data *a_fsData, /* target buffer */
1834 struct xstat_fs_ProbeResults *a_fsResults) /* ptr to xstat fs Results */
1835 { /* fs_Results_ltoa */
1837 static char rn[] = "fs_Results_ltoa"; /* routine name */
1840 fprintf(debugFD, "[ %s ] Called, a_fsData= %p, a_fsResults= %p\n", rn,
1841 a_fsData, a_fsResults);
1845 switch (a_fsResults->collectionNumber) {
1846 case AFS_XSTATSCOLL_FULL_PERF_INFO:
1847 fs_FullPerfs_ltoa(a_fsData, a_fsResults);
1849 case AFS_XSTATSCOLL_CBSTATS:
1850 fs_CallBackStats_ltoa(a_fsData, a_fsResults);
1854 fprintf(debugFD, "[ %s ] Unexpected collection id %d\n",
1855 rn, a_fsResults->collectionNumber);
1860 } /* fs_Results_ltoa */
1862 /*-----------------------------------------------------------------------
1863 * fs_FullPerfs_ltoa()
1866 * Convert the full perf xstat collection from int32s to strings.
1870 *----------------------------------------------------------------------*/
1872 fs_FullPerfs_ltoa(struct fs_Display_Data *a_fsData,
1873 struct xstat_fs_ProbeResults *a_fsResults)
1876 struct fs_stats_FullPerfStats *fullPerfP;
1877 struct fs_stats_FullPerfStats buffer;
1883 /* there are two parts to the xstat FS statistics
1884 * - fullPerfP->overall which give the overall performance statistics, and
1885 * - fullPerfP->det which gives detailed info about file server operation
1886 * execution times */
1888 code = xstat_fs_DecodeFullPerfStats(&fullPerfP,
1889 a_fsResults->data.AFS_CollData_val,
1890 a_fsResults->data.AFS_CollData_len,
1893 /* Not able to decode the full perf stats. Avoid displaying garbage. */
1894 for (i = 0; i < NUM_FS_STAT_ENTRIES; i++) {
1895 sprintf(a_fsData->data[i], "%s", "--");
1900 /* copy overall performance statistics */
1901 srcbuf = (afs_int32 *) & (fullPerfP->overall);
1903 for (i = 0; i < NUM_XSTAT_FS_AFS_PERFSTATS_LONGS; i++) {
1904 sprintf(a_fsData->data[idx], "%d", *srcbuf);
1910 srcbuf = (afs_int32 *) & (fullPerfP->det.epoch);
1911 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* epoch */
1914 /* copy fs operation timing */
1916 srcbuf = (afs_int32 *) (fullPerfP->det.rpcOpTimes);
1918 for (i = 0; i < FS_STATS_NUM_RPC_OPS; i++) {
1919 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* numOps */
1922 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* numSuccesses */
1925 tmpbuf = srcbuf++; /* sum time */
1926 sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1929 tmpbuf = srcbuf++; /* sqr time */
1930 sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1933 tmpbuf = srcbuf++; /* min time */
1934 sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1937 tmpbuf = srcbuf++; /* max time */
1938 sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1943 /* copy fs transfer timings */
1945 srcbuf = (afs_int32 *) (fullPerfP->det.xferOpTimes);
1946 for (i = 0; i < FS_STATS_NUM_XFER_OPS; i++) {
1947 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* numOps */
1950 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* numSuccesses */
1953 tmpbuf = srcbuf++; /* sum time */
1954 sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1957 tmpbuf = srcbuf++; /* sqr time */
1958 sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1961 tmpbuf = srcbuf++; /* min time */
1962 sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1965 tmpbuf = srcbuf++; /* max time */
1966 sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1969 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* sum bytes */
1972 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* min bytes */
1975 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* max bytes */
1978 for (j = 0; j < FS_STATS_NUM_XFER_BUCKETS; j++) {
1979 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* bucket[j] */
1988 /*-----------------------------------------------------------------------
1989 * fs_CallBackStats_ltoa()
1992 * Convert the callback counter xstat collection from
1993 * int32s to strings.
1997 *----------------------------------------------------------------------*/
2000 fs_CallBackStats_ltoa(struct fs_Display_Data *a_fsData,
2001 struct xstat_fs_ProbeResults *a_fsResults)
2005 int len = a_fsResults->data.AFS_CollData_len;
2006 afs_int32 *val = a_fsResults->data.AFS_CollData_val;
2008 /* place callback stats after the full perf stats */
2009 idx = NUM_FS_FULLPERF_ENTRIES;
2010 for (i=0; i < len && i < NUM_FS_CB_ENTRIES; i++) {
2011 sprintf(a_fsData->data[idx++], "%u", val[i]);
2016 /*-----------------------------------------------------------------------
2017 * execute_thresh_handler()
2020 * Execute a threshold handler. An agrv[] array of pointers is
2021 * constructed from the given data. A child process is forked
2022 * which immediately calls afsmon_Exit() with indication that a
2023 * threshold handler is to be exec'ed insted of exiting.
2027 * Failure: Afsmonitor exits if threshold handler has more than 20 args.
2028 *----------------------------------------------------------------------*/
2031 execute_thresh_handler(char *a_handler, /* ptr to handler function + args */
2032 char *a_hostName, /* host name for which threshold crossed */
2033 int a_hostType, /* fs or cm ? */
2034 char *a_threshName, /* threshold variable name */
2035 char *a_threshValue, /* threshold value */
2036 char *a_actValue) /* actual value */
2037 { /* execute_thresh_handler */
2039 static char rn[] = "execute_thresh_handler";
2040 char fileName[256]; /* file name to execute */
2044 int anotherArg; /* boolean used to flag if another arg is available */
2048 "[ %s ] Called, a_handler= %s, a_hostName= %s, a_hostType= %d, a_threshName= %s, a_threshValue= %s, a_actValue= %s\n",
2049 rn, a_handler, a_hostName, a_hostType, a_threshName,
2050 a_threshValue, a_actValue);
2055 /* get the filename to execute - the first argument */
2056 sscanf(a_handler, "%s", fileName);
2058 /* construct the contents of *argv[] */
2060 strncpy(fsHandler_args[0], fileName, 256);
2061 strncpy(fsHandler_args[1], a_hostName, HOST_NAME_LEN);
2062 if (a_hostType == FS)
2063 strcpy(fsHandler_args[2], "fs");
2065 strcpy(fsHandler_args[2], "cm");
2066 strncpy(fsHandler_args[3], a_threshName, THRESH_VAR_NAME_LEN);
2067 strncpy(fsHandler_args[4], a_threshValue, THRESH_VAR_LEN);
2068 strncpy(fsHandler_args[5], a_actValue, THRESH_VAR_LEN);
2075 /* we have already extracted the file name so skip to the 1st arg */
2076 while (isspace(*ch)) /* leading blanks */
2078 while (!isspace(*ch) && *ch != '\0') /* handler filename */
2081 while (*ch != '\0') {
2084 } else if (anotherArg) {
2086 sscanf(ch, "%s", fsHandler_args[argNum]);
2092 "Threshold handlers cannot have more than 20 arguments\n");
2098 fsHandler_argv[argNum] = NULL;
2099 for (i = 0; i < argNum; i++)
2100 fsHandler_argv[i] = fsHandler_args[i];
2103 /* exec the threshold handler */
2106 exec_fsThreshHandler = 1;
2111 } /* execute_thresh_handler */
2115 /*-----------------------------------------------------------------------
2116 * check_fs_thresholds()
2119 * Checks the thresholds and sets the overflow flag. Recall that the
2120 * thresholds for each host are stored in the hostEntry lists
2121 * [fs/cm]nameList arrays. The probe results are passed to this
2122 * function in the display-ready format - ie., as strings. Though
2123 * this looks stupid the overhead incurred in converting the strings
2124 * back to floats and comparing them is insignificant and
2125 * programming is easier this way.
2126 * The threshold flags are a part of the display structures
2131 *----------------------------------------------------------------------*/
2134 check_fs_thresholds(struct afsmon_hostEntry *a_hostEntry, /* ptr to hostEntry */
2135 struct fs_Display_Data *a_Data) /* ptr to fs data to be displayed */
2136 { /* check_fs_thresholds */
2138 static char rn[] = "check_fs_thresholds";
2139 struct Threshold *threshP;
2140 double tValue; /* threshold value */
2141 double pValue; /* probe value */
2144 int count; /* number of thresholds exceeded */
2147 fprintf(debugFD, "[ %s ] Called, a_hostEntry= %p, a_Data= %p\n", rn,
2148 a_hostEntry, a_Data);
2152 if (a_hostEntry->numThresh == 0) {
2153 /* store in ovf count ?? */
2158 threshP = a_hostEntry->thresh;
2159 for (i = 0; i < a_hostEntry->numThresh; i++) {
2160 if (threshP->itemName[0] == '\0') {
2164 idx = threshP->index; /* positional index to the data array */
2165 tValue = atof(threshP->threshVal); /* threshold value */
2166 pValue = atof(a_Data->data[idx]); /* probe value */
2167 if (pValue > tValue) {
2171 "[ %s ] fs = %s, thresh ovf for %s, threshold= %s, probevalue= %s\n",
2172 rn, a_hostEntry->hostName, threshP->itemName,
2173 threshP->threshVal, a_Data->data[idx]);
2176 /* if the threshold is crossed, call the handler function
2177 * only if this was a transition -ie, if the threshold was
2178 * crossed in the last probe too just count & keep quite! */
2180 if (!a_Data->threshOvf[idx]) {
2181 a_Data->threshOvf[idx] = 1;
2182 /* call the threshold handler if provided */
2183 if (threshP->handler[0] != '\0') {
2185 fprintf(debugFD, "[ %s ] Calling ovf handler %s\n",
2186 rn, threshP->handler);
2189 execute_thresh_handler(threshP->handler, a_Data->hostName,
2190 FS, threshP->itemName,
2198 /* in case threshold was previously crossed, blank it out */
2199 a_Data->threshOvf[idx] = 0;
2202 /* store the overflow count */
2203 a_Data->ovfCount = count;
2206 } /* check_fs_thresholds */
2209 /*-----------------------------------------------------------------------
2210 * save_FS_data_forDisplay()
2213 * Does the following:
2214 * - if the probe number changed (ie, a cycle completed) curr_fsData
2215 * is copied to prev_fsData, curr_fsData zeroed and refresh the
2216 * overview screen and file server screen with the new data.
2217 * - store the results of the current probe from xstat_fs_Results into
2218 * curr_fsData. ie., convert longs to strings.
2219 * - check the thresholds
2223 * Failure: Exits afsmonitor.
2224 *----------------------------------------------------------------------*/
2227 save_FS_data_forDisplay(struct xstat_fs_ProbeResults *a_fsResults)
2228 { /* save_FS_data_forDisplay */
2230 static char rn[] = "save_FS_data_forDisplay"; /* routine name */
2231 struct fs_Display_Data *curr_fsDataP; /* tmp ptr to curr_fsData */
2232 struct fs_Display_Data *prev_fsDataP; /* tmp ptr to prev_fsData */
2233 struct afsmon_hostEntry *curr_host;
2234 static int results_Received = 0; /* number of probes reveived in
2235 * the current cycle. If this is equal to numFS we got all
2236 * the data we want in this cycle and can now display it */
2245 fprintf(debugFD, "[ %s ] Called, a_fsResults= %p\n", rn, a_fsResults);
2249 /* store results in the display array */
2252 curr_fsDataP = curr_fsData;
2253 for (i = 0; i < numFS; i++) {
2254 if ((strcasecmp(curr_fsDataP->hostName, a_fsResults->connP->hostName))
2264 "[ %s ] Could not insert FS probe results for host %s in fs display array\n",
2265 rn, a_fsResults->connP->hostName);
2269 /* Check the status of the probe. If it succeeded, we store its
2270 * results in the display data structure. If it failed we only mark
2271 * the failed status in the display data structure. */
2273 if (a_fsResults->probeOK) { /* 1 => notOK the xstat results */
2274 curr_fsDataP->probeOK = 0;
2276 /* print the probe status */
2278 fprintf(debugFD, "\n\t\t ----- fs display data ------\n");
2279 fprintf(debugFD, "HostName = %s PROBE FAILED \n",
2280 curr_fsDataP->hostName);
2284 } else { /* probe succeeded, update display data structures */
2285 curr_fsDataP->probeOK = 1;
2287 /* convert longs to strings and place them in curr_fsDataP */
2288 fs_Results_ltoa(curr_fsDataP, a_fsResults);
2290 /* compare with thresholds and set the overflow flags.
2291 * note that the threshold information is in the hostEntry structure and
2292 * each threshold item has a positional index associated with it */
2294 /* locate the hostEntry for this host */
2296 curr_host = FSnameList;
2297 for (i = 0; i < numFS; i++) {
2298 if (strcasecmp(curr_host->hostName, a_fsResults->connP->hostName)
2303 curr_host = curr_host->next;;
2308 code = check_fs_thresholds(curr_host, curr_fsDataP);
2310 fprintf(stderr, "[ %s ] Error in checking thresholds\n", rn);
2314 /* print the info we just saved */
2317 fprintf(debugFD, "\n\t\t ----- fs display data ------\n");
2318 fprintf(debugFD, "HostName = %s\n", curr_fsDataP->hostName);
2319 for (i = 0; i < NUM_FS_STAT_ENTRIES; i++)
2320 fprintf(debugFD, "%20s %30s %s\n", curr_fsDataP->data[i],
2322 curr_fsDataP->threshOvf[i] ? "(ovf)" : "");
2324 fprintf(debugFD, "\t\t--------------------------------\n\n");
2328 } /* the probe succeeded, so we store the data in the display structure */
2331 /* if we have received a reply from all the hosts for this probe cycle,
2332 * it is time to display the data */
2335 if (results_Received == numFS * num_fs_collections) {
2336 results_Received = 0;
2338 if (afsmon_fs_curr_probeNum != afsmon_fs_prev_probeNum + 1) {
2339 sprintf(errMsg, "[ %s ] Probe number %d missed! \n", rn,
2340 afsmon_fs_prev_probeNum + 1);
2343 afsmon_fs_prev_probeNum++;
2345 /* backup the display data of the probe cycle that just completed -
2346 * ie., store curr_fsData in prev_fsData */
2348 memcpy((char *)prev_fsData, (char *)curr_fsData,
2349 (numFS * sizeof(struct fs_Display_Data)));
2352 /* initialize curr_fsData but retain the threshold flag information.
2353 * The previous state of threshold flags is used in check_fs_thresholds() */
2355 numBytes = NUM_FS_STAT_ENTRIES * FS_STAT_STRING_LEN;
2356 curr_fsDataP = curr_fsData;
2357 for (i = 0; i < numFS; i++) {
2358 curr_fsDataP->probeOK = 0;
2359 curr_fsDataP->ovfCount = 0;
2360 memset(curr_fsDataP->data, 0, numBytes);
2365 /* prev_fsData now contains all the information for the probe cycle
2366 * that just completed. Now count the number of threshold overflows for
2367 * use in the overview screen */
2369 prev_fsDataP = prev_fsData;
2371 numHosts_onfs_alerts = 0;
2372 for (i = 0; i < numFS; i++) {
2373 if (!prev_fsDataP->probeOK) { /* if probe failed */
2375 numHosts_onfs_alerts++;
2377 if (prev_fsDataP->ovfCount) { /* overflows ?? */
2378 num_fs_alerts += prev_fsDataP->ovfCount;
2379 numHosts_onfs_alerts++;
2384 fprintf(debugFD, "Number of FS alerts = %d (on %d hosts)\n",
2385 num_fs_alerts, numHosts_onfs_alerts);
2387 /* flag that the data is now ready to be displayed */
2388 fs_Data_Available = 1;
2390 /* call the Overview frame update routine (update only FS info) */
2391 ovw_refresh(ovw_currPage, OVW_UPDATE_FS);
2393 /* call the File Servers frame update routine */
2394 fs_refresh(fs_currPage, fs_curr_LCol);
2399 } /* save_FS_data_forDisplay */
2404 /*-----------------------------------------------------------------------
2405 * afsmon_FS_Handler()
2408 * This is the File Server probe Handler. It updates the afsmonitor
2409 * probe counts, fs circular buffer indices and calls the functions
2410 * to process the results of this probe.
2414 * Failure: Exits afsmonitor.
2415 *----------------------------------------------------------------------*/
2418 afsmon_FS_Handler(void)
2419 { /* afsmon_FS_Handler() */
2420 static char rn[] = "afsmon_FS_Handler"; /* routine name */
2421 int newProbeCycle; /* start of new probe cycle ? */
2422 int code; /* return status */
2427 "[ %s ] Called, hostName= %s, probeNum= %d, status=%s, collection=%d\n", rn,
2428 xstat_fs_Results.connP->hostName, xstat_fs_Results.probeNum,
2429 xstat_fs_Results.probeOK ? "FAILED" : "OK",
2430 xstat_fs_Results.collectionNumber);
2435 /* print the probe results to output file */
2436 if (afsmon_output) {
2437 code = afsmon_fsOutput(output_filename, afsmon_detOutput);
2440 "[ %s ] output to file %s returned error code=%d\n", rn,
2441 output_filename, code);
2445 /* Update current probe number and circular buffer index. if current
2446 * probenum changed make sure it is only by 1 */
2449 if (xstat_fs_Results.probeNum != afsmon_fs_curr_probeNum) {
2450 if (xstat_fs_Results.probeNum == afsmon_fs_curr_probeNum + 1) {
2451 afsmon_fs_curr_probeNum++;
2454 afsmon_fs_curr_CBindex =
2455 (afsmon_fs_curr_probeNum - 1) % num_bufSlots;
2457 fprintf(stderr, "[ %s ] probe number %d-1 missed\n", rn,
2458 xstat_fs_Results.probeNum);
2464 /* store the results of this probe in the FS circular buffer */
2466 save_FS_results_inCB(newProbeCycle);
2469 /* store the results of the current probe in the fs data display structure.
2470 * if the current probe number changed, swap the current and previous display
2471 * structures. note that the display screen is updated from these structures
2472 * and should start showing the data of the just completed probe cycle */
2474 save_FS_data_forDisplay(&xstat_fs_Results);
2481 /*----------------------------------------------------------------------- *
2486 * Prints the Cache Manager circular buffer
2487 *----------------------------------------------------------------------*/
2491 { /* Print_CM_CB() */
2493 struct afsmon_cm_Results_list *cmlist;
2498 /* print valid info in the cm CB */
2502 "==================== CM Buffer ========================\n");
2503 fprintf(debugFD, "afsmon_cm_curr_CBindex = %d\n",
2504 afsmon_cm_curr_CBindex);
2505 fprintf(debugFD, "afsmon_cm_curr_probeNum = %d\n\n",
2506 afsmon_cm_curr_probeNum);
2508 for (i = 0; i < num_bufSlots; i++) {
2509 fprintf(debugFD, "\t--------- slot %d ----------\n", i);
2510 cmlist = afsmon_cm_ResultsCB[i].list;
2513 for (k = 0; k < MAX_NUM_CM_COLLECTIONS; k++) {
2514 if (!cmlist->empty[k]) {
2516 "\t %d) probeNum = %d host = %s cn = %d",
2518 cmlist->cmResults[k]->probeNum,
2519 cmlist->cmResults[k]->connP->hostName,
2520 cmlist->cmResults[k]->collectionNumber);
2521 if (cmlist->cmResults[k]->probeOK)
2522 fprintf(debugFD, " NOTOK\n");
2524 fprintf(debugFD, " OK\n");
2526 fprintf(debugFD, "\t %d) -- empty --\n", j);
2528 cmlist = cmlist->next;
2531 if (cmlist != (struct afsmon_cm_Results_list *)0)
2532 fprintf(debugFD, "dangling last next ptr cm CB\n");
2538 /*-----------------------------------------------------------------------
2539 * save_CM_results_inCB()
2542 * Saves the results of the latest CM probe in the cm circular
2543 * buffers. If the current probe cycle is in progress the contents
2544 * of xstat_cm_Results are copied to the end of the list of results
2545 * in the current slot (pointed to by afsmon_cm_curr_CBindex). If
2546 * a new probe cycle has started the next slot in the circular buffer
2547 * is initialized and the results copied. Note that the Rx related
2548 * information available in xstat_cm_Results is not copied.
2552 * Failure: Exits afsmonitor.
2553 *----------------------------------------------------------------------*/
2556 save_CM_results_inCB(int a_newProbeCycle) /* start of new probe cycle ? */
2557 { /* save_CM_results_inCB() */
2558 static char rn[] = "save_CM_results_inCB"; /* routine name */
2559 struct afsmon_cm_Results_list *tmp_cmlist_item; /* temp cm list item */
2560 struct xstat_cm_ProbeResults *tmp_cmPR; /* temp ptr */
2566 fprintf(debugFD, "[ %s ] Called, a_newProbeCycle= %d\n", rn,
2571 if (xstat_cm_Results.collectionNumber == AFSCB_XSTATSCOLL_FULL_PERF_INFO) {
2574 fprintf(stderr, "[ %s ] collection number %d is out of range.\n",
2575 rn, xstat_cm_Results.collectionNumber);
2579 /* If a new probe cycle started, mark the list in the current buffer
2580 * slot empty for resuse. Note that afsmon_cm_curr_CBindex was appropriately
2581 * incremented in afsmon_CM_Handler() */
2583 if (a_newProbeCycle) {
2584 tmp_cmlist_item = afsmon_cm_ResultsCB[afsmon_cm_curr_CBindex].list;
2585 for (i = 0; i < numCM; i++) {
2586 tmp_cmlist_item->empty[index] = 1;
2587 tmp_cmlist_item = tmp_cmlist_item->next;
2591 /* locate last unused item in list */
2592 tmp_cmlist_item = afsmon_cm_ResultsCB[afsmon_cm_curr_CBindex].list;
2593 for (i = 0; i < numCM; i++) {
2594 if (tmp_cmlist_item->empty[index])
2596 tmp_cmlist_item = tmp_cmlist_item->next;
2599 /* if we could not find one we have an inconsistent list */
2600 if (!tmp_cmlist_item->empty[index]) {
2602 "[ %s ] list inconsistency 1. unable to find an empty slot to store results of probenum %d of %s\n",
2603 rn, xstat_cm_Results.probeNum,
2604 xstat_cm_Results.connP->hostName);
2608 tmp_cmPR = tmp_cmlist_item->cmResults[index];
2610 /* copy hostname and probe number and probe time and probe status.
2611 * if the probe failed return now */
2613 memcpy(tmp_cmPR->connP->hostName, xstat_cm_Results.connP->hostName,
2614 sizeof(xstat_cm_Results.connP->hostName));
2615 tmp_cmPR->probeNum = xstat_cm_Results.probeNum;
2616 tmp_cmPR->probeTime = xstat_cm_Results.probeTime;
2617 tmp_cmPR->probeOK = xstat_cm_Results.probeOK;
2618 if (xstat_cm_Results.probeOK) { /* probeOK = 1 => notOK */
2619 /* we have a nonempty results structure so mark the list item used */
2620 tmp_cmlist_item->empty[index] = 0;
2625 /* copy connection information */
2626 memcpy(&(tmp_cmPR->connP->skt), &(xstat_cm_Results.connP->skt),
2627 sizeof(struct sockaddr_in));
2629 /**** NEED TO COPY rx_connection INFORMATION HERE ******/
2631 memcpy(tmp_cmPR->connP->hostName, xstat_cm_Results.connP->hostName,
2632 sizeof(xstat_cm_Results.connP->hostName));
2633 tmp_cmPR->collectionNumber = xstat_cm_Results.collectionNumber;
2635 /* copy the probe data information */
2636 tmp_cmPR->data.AFSCB_CollData_len =
2637 min(xstat_cm_Results.data.AFSCB_CollData_len,
2638 afsmon_cm_results_length[index]);
2639 memcpy(tmp_cmPR->data.AFSCB_CollData_val,
2640 xstat_cm_Results.data.AFSCB_CollData_val,
2641 tmp_cmPR->data.AFSCB_CollData_len * sizeof(afs_int32));
2644 /* we have a valid results structure so mark the list item used */
2645 tmp_cmlist_item->empty[index] = 0;
2647 /* print the stored info - to make sure we copied it right */
2648 /* Print_cm_FullPerfInfo(tmp_cmPR); */
2649 /* Print the cm circular buffer */
2652 } /* save_CM_results_inCB */
2656 /*-----------------------------------------------------------------------
2660 * The results of xstat probes are stored in a string format in
2661 * the arrays curr_cmData and prev_cmData. The information stored in
2662 * prev_cmData is copied to the screen.
2663 * This function converts xstat FS results from longs to strings and
2664 * places them in the given buffer (a pointer to an item in curr_cmData).
2665 * When a probe cycle completes, curr_cmData is copied to prev_cmData
2666 * in afsmon_CM_Handler().
2670 *----------------------------------------------------------------------*/
2673 cm_Results_ltoa(struct cm_Display_Data *a_cmData, /* target buffer */
2674 struct xstat_cm_ProbeResults *a_cmResults) /* ptr to xstat cm Results */
2675 { /* cm_Results_ltoa */
2677 static char rn[] = "cm_Results_ltoa"; /* routine name */
2678 struct afs_stats_CMFullPerf *fullP; /* ptr to complete CM stats */
2686 fprintf(debugFD, "[ %s ] Called, a_cmData= %p, a_cmResults= %p\n", rn,
2687 a_cmData, a_cmResults);
2692 fullP = (struct afs_stats_CMFullPerf *)
2693 (a_cmResults->data.AFSCB_CollData_val);
2695 /* There are 4 parts to CM statistics
2696 * - Overall performance statistics (including up/down statistics)
2697 * - This CMs FS RPC operations info
2698 * - This CMs FS RPC errors info
2699 * - This CMs FS transfers info
2700 * - Authentication info
2701 * - [Un]Replicated access info
2704 /* copy overall performance statistics */
2705 srcbuf = (afs_int32 *) & (fullP->perf);
2707 /* we skip the 19 entry, ProtServAddr, so the index must account for this */
2708 for (i = 0; i < NUM_AFS_STATS_CMPERF_LONGS + 1; i++) {
2711 continue; /* skip ProtServerAddr */
2713 sprintf(a_cmData->data[idx], "%d", *srcbuf);
2718 /*printf("Ending index value = %d\n",idx-1); */
2720 /* server up/down statistics */
2721 /* copy file server up/down stats */
2722 srcbuf = (afs_int32 *) (fullP->perf.fs_UpDown);
2724 2 * (sizeof(struct afs_stats_SrvUpDownInfo) / sizeof(afs_int32));
2725 for (i = 0; i < numLongs; i++) {
2726 sprintf(a_cmData->data[idx], "%d", *srcbuf);
2731 /*printf("Ending index value = %d\n",idx-1); */
2733 /* copy volume location server up/down stats */
2734 srcbuf = (afs_int32 *) (fullP->perf.vl_UpDown);
2736 2 * (sizeof(struct afs_stats_SrvUpDownInfo) / sizeof(afs_int32));
2737 for (i = 0; i < numLongs; i++) {
2738 sprintf(a_cmData->data[idx], "%d", *srcbuf);
2743 /*printf("Ending index value = %d\n",idx-1); */
2745 /* copy CMs individual FS RPC operations info */
2746 srcbuf = (afs_int32 *) (fullP->rpc.fsRPCTimes);
2747 for (i = 0; i < AFS_STATS_NUM_FS_RPC_OPS; i++) {
2748 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* numOps */
2751 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* numSuccesses */
2754 tmpbuf = srcbuf++; /* sum time */
2755 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2758 tmpbuf = srcbuf++; /* sqr time */
2759 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2762 tmpbuf = srcbuf++; /* min time */
2763 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2766 tmpbuf = srcbuf++; /* max time */
2767 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2772 /*printf("Ending index value = %d\n",idx-1); */
2774 /* copy CMs individual FS RPC errors info */
2776 srcbuf = (afs_int32 *) (fullP->rpc.fsRPCErrors);
2777 for (i = 0; i < AFS_STATS_NUM_FS_RPC_OPS; i++) {
2778 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* server */
2781 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* network */
2784 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* prot */
2787 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* vol */
2790 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* busies */
2793 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* other */
2798 /*printf("Ending index value = %d\n",idx-1); */
2800 /* copy CMs individual RPC transfers info */
2802 srcbuf = (afs_int32 *) (fullP->rpc.fsXferTimes);
2803 for (i = 0; i < AFS_STATS_NUM_FS_XFER_OPS; i++) {
2804 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* numOps */
2807 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* numSuccesses */
2810 tmpbuf = srcbuf++; /* sum time */
2811 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2814 tmpbuf = srcbuf++; /* sqr time */
2815 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2818 tmpbuf = srcbuf++; /* min time */
2819 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2822 tmpbuf = srcbuf++; /* max time */
2823 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2826 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* sum bytes */
2829 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* min bytes */
2832 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* max bytes */
2835 for (j = 0; j < AFS_STATS_NUM_XFER_BUCKETS; j++) {
2836 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* bucket[j] */
2842 /*printf("Ending index value = %d\n",idx-1); */
2844 /* copy CM operations timings */
2846 srcbuf = (afs_int32 *) (fullP->rpc.cmRPCTimes);
2847 for (i = 0; i < AFS_STATS_NUM_CM_RPC_OPS; i++) {
2848 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* numOps */
2851 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* numSuccesses */
2854 tmpbuf = srcbuf++; /* sum time */
2855 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2858 tmpbuf = srcbuf++; /* sqr time */
2859 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2862 tmpbuf = srcbuf++; /* min time */
2863 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2866 tmpbuf = srcbuf++; /* max time */
2867 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2872 /*printf("Ending index value = %d\n",idx-1); */
2874 /* copy authentication info */
2876 srcbuf = (afs_int32 *) & (fullP->authent);
2877 numLongs = sizeof(struct afs_stats_AuthentInfo) / sizeof(afs_int32);
2878 for (i = 0; i < numLongs; i++) {
2879 sprintf(a_cmData->data[idx], "%d", *srcbuf);
2884 /*printf("Ending index value = %d\n",idx-1); */
2886 /* copy CM [un]replicated access info */
2888 srcbuf = (afs_int32 *) & (fullP->accessinf);
2889 numLongs = sizeof(struct afs_stats_AccessInfo) / sizeof(afs_int32);
2890 for (i = 0; i < numLongs; i++) {
2891 sprintf(a_cmData->data[idx], "%d", *srcbuf);
2896 /*printf("Ending index value = %d\n",idx-1); */
2899 } /* cm_Results_ltoa */
2902 /*-----------------------------------------------------------------------
2903 * Function: check_cm_thresholds()
2906 * Checks the thresholds and sets the overflow flag. Recall that the
2907 * thresholds for each host are stored in the hostEntry lists
2908 * [fs/cm]nameList arrays. The probe results are passed to this
2909 * function in the display-ready format - ie., as strings. Though
2910 * this looks stupid the overhead incurred in converting the strings
2911 * back to floats and comparing them is insignificant and
2912 * programming is easier this way.
2913 * The threshold flags are a part of the display structures
2918 *----------------------------------------------------------------------*/
2921 check_cm_thresholds(struct afsmon_hostEntry *a_hostEntry, /* ptr to hostEntry */
2922 struct cm_Display_Data *a_Data) /* ptr to cm data to be displayed */
2923 { /* check_cm_thresholds */
2925 static char rn[] = "check_cm_thresholds";
2926 struct Threshold *threshP;
2927 double tValue; /* threshold value */
2928 double pValue; /* probe value */
2931 int count; /* number of thresholds exceeded */
2934 fprintf(debugFD, "[ %s ] Called, a_hostEntry= %p, a_Data= %p\n", rn,
2935 a_hostEntry, a_Data);
2939 if (a_hostEntry->numThresh == 0) {
2940 /* store in ovf count ?? */
2945 threshP = a_hostEntry->thresh;
2946 for (i = 0; i < a_hostEntry->numThresh; i++) {
2947 if (threshP->itemName[0] == '\0') {
2951 idx = threshP->index; /* positional index to the data array */
2952 tValue = atof(threshP->threshVal); /* threshold value */
2953 pValue = atof(a_Data->data[idx]); /* probe value */
2954 if (pValue > tValue) {
2958 "[ %s ] cm = %s, thresh ovf for %s, threshold= %s, probevalue= %s\n",
2959 rn, a_hostEntry->hostName, threshP->itemName,
2960 threshP->threshVal, a_Data->data[idx]);
2964 /* if the threshold is crossed, call the handler function
2965 * only if this was a transition -ie, if the threshold was
2966 * crossed in the last probe too just count & keep quite! */
2968 if (!a_Data->threshOvf[idx]) {
2969 a_Data->threshOvf[idx] = 1;
2970 /* call the threshold handler if provided */
2971 if (threshP->handler[0] != '\0') {
2973 fprintf(debugFD, "[ %s ] Calling ovf handler %s\n",
2974 rn, threshP->handler);
2977 execute_thresh_handler(threshP->handler, a_Data->hostName,
2978 CM, threshP->itemName,
2986 /* in case threshold was previously crossed, blank it out */
2987 a_Data->threshOvf[idx] = 0;
2990 /* store the overflow count */
2991 a_Data->ovfCount = count;
2994 } /* check_cm_thresholds */
2997 /*-----------------------------------------------------------------------
2998 * save_CM_data_forDisplay()
3001 * Does the following:
3002 * - if the probe number changed (ie, a cycle completed) curr_cmData
3003 * is copied to prev_cmData, curr_cmData zeroed and refresh the
3004 * overview screen and file server screen with the new data.
3005 * - store the results of the current probe from xstat_cm_Results into
3006 * curr_cmData. ie., convert longs to strings.
3007 * - check the thresholds
3011 * Failure: Exits afsmonitor.
3013 *----------------------------------------------------------------------*/
3016 save_CM_data_forDisplay(struct xstat_cm_ProbeResults *a_cmResults)
3017 { /* save_CM_data_forDisplay */
3019 static char rn[] = "save_CM_data_forDisplay"; /* routine name */
3020 struct cm_Display_Data *curr_cmDataP;
3021 struct cm_Display_Data *prev_cmDataP;
3022 struct afsmon_hostEntry *curr_host;
3023 static int results_Received = 0; /* number of probes reveived in
3024 * the current cycle. If this is equal to numFS we got all
3025 * the data we want in this cycle and can now display it */
3033 fprintf(debugFD, "[ %s ] Called, a_cmResults= %p\n", rn, a_cmResults);
3037 /* store results in the display array */
3040 curr_cmDataP = curr_cmData;
3041 for (i = 0; i < numCM; i++) {
3042 if ((strcasecmp(curr_cmDataP->hostName, a_cmResults->connP->hostName))
3052 "[ %s ] Could not insert CM probe results for host %s in cm display array\n",
3053 rn, a_cmResults->connP->hostName);
3057 /* Check the status of the probe. If it succeeded, we store its
3058 * results in the display data structure. If it failed we only mark
3059 * the failed status in the display data structure. */
3062 if (a_cmResults->probeOK) { /* 1 => notOK the xstat results */
3063 curr_cmDataP->probeOK = 0;
3065 /* print the probe status */
3067 fprintf(debugFD, "\n\t\t ----- cm display data ------\n");
3068 fprintf(debugFD, "HostName = %s PROBE FAILED \n",
3069 curr_cmDataP->hostName);
3073 } else { /* probe succeeded, update display data structures */
3074 curr_cmDataP->probeOK = 1;
3077 /* covert longs to strings and place them in curr_cmDataP */
3078 cm_Results_ltoa(curr_cmDataP, a_cmResults);
3080 /* compare with thresholds and set the overflow flags.
3081 * note that the threshold information is in the hostEntry structure and
3082 * each threshold item has a positional index associated with it */
3084 /* locate the hostEntry for this host */
3086 curr_host = CMnameList;
3087 for (i = 0; i < numCM; i++) {
3088 if (strcasecmp(curr_host->hostName, a_cmResults->connP->hostName)
3093 curr_host = curr_host->next;
3098 code = check_cm_thresholds(curr_host, curr_cmDataP);
3100 fprintf(stderr, "[ %s ] Error in checking thresholds\n", rn);
3104 /* print the info we just saved */
3106 fprintf(debugFD, "\n\t\t ----- CM display data ------\n");
3107 fprintf(debugFD, "HostName = %s\n", curr_cmDataP->hostName);
3108 for (i = 0; i < NUM_CM_STAT_ENTRIES; i++) {
3111 fprintf(debugFD, "\t -- Overall Perf Info --\n");
3115 "\t -- File Server up/down stats - same cell --\n");
3119 "\t -- File Server up/down stats - diff cell --\n");
3123 "\t -- VL server up/down stats - same cell --\n");
3127 "\t -- VL server up/down stats - diff cell --\n");
3130 fprintf(debugFD, "\t -- FS Operation Timings --\n");
3133 fprintf(debugFD, "\t -- FS Error Info --\n");
3136 fprintf(debugFD, "\t -- FS Transfer Timings --\n");
3139 fprintf(debugFD, "\t -- CM Operations Timings --\n");
3142 fprintf(debugFD, "\t -- Authentication Info --\n");
3145 fprintf(debugFD, "\t -- Access Info --\n");
3151 fprintf(debugFD, "%20s %30s %s\n", curr_cmDataP->data[i],
3153 curr_cmDataP->threshOvf[i] ? "(ovf)" : "");
3155 fprintf(debugFD, "\t\t--------------------------------\n\n");
3158 } /* if the probe succeeded, update the display data structures */
3160 /* if we have received a reply from all the hosts for this probe cycle,
3161 * it is time to display the data */
3164 if (results_Received == numCM * num_cm_collections) {
3165 results_Received = 0;
3167 if (afsmon_cm_curr_probeNum != afsmon_cm_prev_probeNum + 1) {
3168 sprintf(errMsg, "[ %s ] Probe number %d missed! \n", rn,
3169 afsmon_cm_prev_probeNum + 1);
3172 afsmon_cm_prev_probeNum++;
3175 /* backup the display data of the probe cycle that just completed -
3176 * ie., store curr_cmData in prev_cmData */
3178 memcpy((char *)prev_cmData, (char *)curr_cmData,
3179 (numCM * sizeof(struct cm_Display_Data)));
3182 /* initialize curr_cmData but retain the threshold flag information.
3183 * The previous state of threshold flags is used in check_cm_thresholds() */
3185 curr_cmDataP = curr_cmData;
3186 numBytes = NUM_CM_STAT_ENTRIES * CM_STAT_STRING_LEN;
3187 for (i = 0; i < numCM; i++) {
3188 curr_cmDataP->probeOK = 0;
3189 curr_cmDataP->ovfCount = 0;
3190 memset(curr_cmDataP->data, 0, numBytes);
3194 /* prev_cmData now contains all the information for the probe cycle
3195 * that just completed. Now count the number of threshold overflows for
3196 * use in the overview screen */
3198 prev_cmDataP = prev_cmData;
3200 numHosts_oncm_alerts = 0;
3201 for (i = 0; i < numCM; i++) {
3202 if (!prev_cmDataP->probeOK) { /* if probe failed */
3204 numHosts_oncm_alerts++;
3205 } else if (prev_cmDataP->ovfCount) { /* overflows ?? */
3206 num_cm_alerts += prev_cmDataP->ovfCount;
3207 numHosts_oncm_alerts++;
3212 fprintf(debugFD, "Number of CM alerts = %d (on %d hosts)\n",
3213 num_cm_alerts, numHosts_oncm_alerts);
3216 /* flag that the data is now ready to be displayed */
3217 cm_Data_Available = 1;
3219 /* update the Overview frame (only CM info) */
3220 ovw_refresh(ovw_currPage, OVW_UPDATE_CM);
3222 /* update the Cache Managers frame */
3223 cm_refresh(cm_currPage, cm_curr_LCol);
3229 } /* save_CM_data_forDisplay */
3233 /*-----------------------------------------------------------------------
3234 * afsmon_CM_Handler()
3237 * This is the Cache Manager probe Handler. It updates the afsmonitor
3238 * probe counts, cm circular buffer indices and calls the functions
3239 * to process the results of this probe.
3243 * Failure: Exits afsmonitor.
3244 *----------------------------------------------------------------------*/
3247 afsmon_CM_Handler(void)
3248 { /* afsmon_CM_Handler() */
3249 static char rn[] = "afsmon_CM_Handler"; /* routine name */
3250 int code; /* return status */
3251 int newProbeCycle; /* start of new probe cycle ? */
3255 "[ %s ] Called, hostName= %s, probeNum= %d, status= %s\n", rn,
3256 xstat_cm_Results.connP->hostName, xstat_cm_Results.probeNum,
3257 xstat_cm_Results.probeOK ? "FAILED" : "OK");
3262 /* print the probe results to output file */
3263 if (afsmon_output) {
3264 code = afsmon_cmOutput(output_filename, afsmon_detOutput);
3267 "[ %s ] output to file %s returned error code=%d\n", rn,
3268 output_filename, code);
3272 /* Update current probe number and circular buffer index. if current
3273 * probenum changed make sure it is only by 1 */
3276 if (xstat_cm_Results.probeNum != afsmon_cm_curr_probeNum) {
3277 if (xstat_cm_Results.probeNum == afsmon_cm_curr_probeNum + 1) {
3278 afsmon_cm_curr_probeNum++;
3281 afsmon_cm_curr_CBindex =
3282 (afsmon_cm_curr_probeNum - 1) % num_bufSlots;
3284 fprintf(stderr, "[ %s ] probe number %d-1 missed\n", rn,
3285 xstat_cm_Results.probeNum);
3290 /* save the results of this probe in the CM buffer */
3292 save_CM_results_inCB(newProbeCycle);
3294 /* store the results of the current probe in the cm data display structure.
3295 * if the current probe number changed, swap the current and previous display
3296 * structures. note that the display screen is updated from these structures
3297 * and should start showing the data of the just completed probe cycle */
3299 save_CM_data_forDisplay(&xstat_cm_Results);
3304 /*-----------------------------------------------------------------------
3308 * Allocate and Initialize circular buffers for file servers.
3312 * Failure to allocate memory: exits afsmonitor.
3313 *----------------------------------------------------------------------*/
3316 init_fs_buffers(void)
3317 { /* init_fs_buffers() */
3318 static char rn[] = "init_fs_buffers"; /* routine name */
3319 struct afsmon_fs_Results_list *new_fslist_item; /* ptr for new struct */
3320 struct afsmon_fs_Results_list *tmp_fslist_item; /* temp ptr */
3321 struct xstat_fs_ProbeResults *new_fsPR; /* ptr for new struct */
3328 fprintf(debugFD, "[ %s ] Called\n", rn);
3332 /* allocate memory for the circular buffer of pointers */
3334 afsmon_fs_ResultsCB = (struct afsmon_fs_Results_CBuffer *)
3335 malloc(sizeof(struct afsmon_fs_Results_CBuffer) * num_bufSlots);
3337 /* initialize the fs circular buffer */
3338 for (i = 0; i < num_bufSlots; i++) {
3339 afsmon_fs_ResultsCB[i].list = (struct afsmon_fs_Results_list *)0;
3340 afsmon_fs_ResultsCB[i].probeNum = 0;
3343 /* create a list of numFS items to store fs probe results for
3344 * each slot in CB */
3346 if (numFS) { /* if we have file servers to monitor */
3347 for (bufslot = 0; bufslot < num_bufSlots; bufslot++) {
3348 numfs = numFS; /* get the number of servers */
3351 /* if any of these mallocs fail we only need to free the memory we
3352 * have allocated in this iteration. the rest of it which is in a
3353 * proper linked list will be freed in afsmon_Exit */
3355 /* allocate memory for an fs list item */
3356 new_fslist_item = (struct afsmon_fs_Results_list *)
3357 malloc(sizeof(struct afsmon_fs_Results_list));
3358 if (new_fslist_item == (struct afsmon_fs_Results_list *)0)
3361 for (i = 0; i < MAX_NUM_FS_COLLECTIONS; i++) {
3362 /* allocate memory to store xstat_fs_Results */
3363 new_fsPR = (struct xstat_fs_ProbeResults *)
3364 malloc(sizeof(struct xstat_fs_ProbeResults));
3366 free(new_fslist_item);
3370 new_fsPR->connP = (struct xstat_fs_ConnectionInfo *)
3371 malloc(sizeof(struct xstat_fs_ConnectionInfo));
3372 if (new_fsPR->connP == (struct xstat_fs_ConnectionInfo *)0) {
3373 free(new_fslist_item);
3378 /* >>> need to allocate rx connection info structure here <<< */
3379 new_fsPR->data.AFS_CollData_val = (afs_int32 *)
3380 malloc(afsmon_fs_results_length[i] * sizeof(afs_int32));
3381 if (new_fsPR->data.AFS_CollData_val == NULL) {
3382 free(new_fslist_item);
3383 free(new_fsPR->connP);
3387 new_fslist_item->fsResults[i] = new_fsPR;
3388 new_fslist_item->empty[i] = 1;
3391 /* initialize this list entry */
3392 new_fslist_item->next = (struct afsmon_fs_Results_list *)0;
3394 /* store it at the end of the fs list in the current CB slot */
3395 if (afsmon_fs_ResultsCB[bufslot].list ==
3396 (struct afsmon_fs_Results_list *)0)
3397 afsmon_fs_ResultsCB[bufslot].list = new_fslist_item;
3399 tmp_fslist_item = afsmon_fs_ResultsCB[bufslot].list;
3401 while (tmp_fslist_item !=
3402 (struct afsmon_fs_Results_list *)0) {
3403 if (tmp_fslist_item->next ==
3404 (struct afsmon_fs_Results_list *)0)
3406 tmp_fslist_item = tmp_fslist_item->next;
3408 /* something goofed. exit */
3409 fprintf(stderr, "[ %s ] list creation error\n",
3414 tmp_fslist_item->next = new_fslist_item;
3417 } /* while servers */
3418 } /* for each buffer slot */
3419 } /* if we have file servers to monitor */
3423 /*-----------------------------------------------------------------------
3427 * Allocate and Initialize circular buffers for cache managers.
3431 * Failure to allocate memory: exits afsmonitor.
3432 *----------------------------------------------------------------------*/
3435 init_cm_buffers(void)
3436 { /* init_cm_buffers() */
3437 static char rn[] = "init_cm_buffers"; /* routine name */
3438 struct afsmon_cm_Results_list *new_cmlist_item; /* ptr for new struct */
3439 struct afsmon_cm_Results_list *tmp_cmlist_item; /* temp ptr */
3440 struct xstat_cm_ProbeResults *new_cmPR; /* ptr for new struct */
3446 fprintf(debugFD, "[ %s ] Called\n", rn);
3450 /* allocate memory for the circular buffer of pointers */
3451 afsmon_cm_ResultsCB = (struct afsmon_cm_Results_CBuffer *)
3452 malloc(sizeof(struct afsmon_cm_Results_CBuffer) * num_bufSlots);
3454 /* initialize the fs circular buffer */
3455 for (i = 0; i < num_bufSlots; i++) {
3456 afsmon_cm_ResultsCB[i].list = (struct afsmon_cm_Results_list *)0;
3457 afsmon_cm_ResultsCB[i].probeNum = 0;
3460 /* create a list of numCM items to store fs probe results for
3461 * each slot in CB */
3463 if (numCM) { /* if we have file servers to monitor */
3464 for (bufslot = 0; bufslot < num_bufSlots; bufslot++) {
3465 numcm = numCM; /* get the number of servers */
3468 /* if any of these mallocs fail we only need to free the memory we
3469 * have allocated in this iteration. the rest of it which is in a
3470 * proper linked list will be freed in afsmon_Exit */
3472 /* allocate memory for an fs list item */
3473 new_cmlist_item = (struct afsmon_cm_Results_list *)
3474 malloc(sizeof(struct afsmon_cm_Results_list));
3475 if (new_cmlist_item == (struct afsmon_cm_Results_list *)0)
3478 for (i = 0; i < MAX_NUM_CM_COLLECTIONS; i++) {
3479 /* allocate memory to store xstat_cm_Results */
3480 new_cmPR = (struct xstat_cm_ProbeResults *)
3481 malloc(sizeof(struct xstat_cm_ProbeResults));
3483 free(new_cmlist_item);
3486 new_cmPR->connP = (struct xstat_cm_ConnectionInfo *)
3487 malloc(sizeof(struct xstat_cm_ConnectionInfo));
3488 if (!new_cmPR->connP) {
3489 free(new_cmlist_item);
3494 /* >>> need to allocate rx connection info structure here <<< */
3496 new_cmPR->data.AFSCB_CollData_val =
3497 malloc(XSTAT_CM_FULLPERF_RESULTS_LEN
3498 *sizeof(afs_int32));
3499 if (new_cmPR->data.AFSCB_CollData_val == NULL) {
3500 free(new_cmlist_item);
3501 free(new_cmPR->connP);
3506 new_cmlist_item->cmResults[i] = new_cmPR;
3507 new_cmlist_item->empty[i] = 1;
3510 /* initialize this list entry */
3511 new_cmlist_item->next = (struct afsmon_cm_Results_list *)0;
3513 /* store it at the end of the cm list in the current CB slot */
3514 if (afsmon_cm_ResultsCB[bufslot].list ==
3515 (struct afsmon_cm_Results_list *)0)
3516 afsmon_cm_ResultsCB[bufslot].list = new_cmlist_item;
3518 tmp_cmlist_item = afsmon_cm_ResultsCB[bufslot].list;
3520 while (tmp_cmlist_item !=
3521 (struct afsmon_cm_Results_list *)0) {
3522 if (tmp_cmlist_item->next ==
3523 (struct afsmon_cm_Results_list *)0)
3525 tmp_cmlist_item = tmp_cmlist_item->next;
3527 /* something goofed. exit */
3528 fprintf(stderr, "[ %s ] list creation error\n",
3533 tmp_cmlist_item->next = new_cmlist_item;
3536 } /* while servers */
3537 } /* for each buffer slot */
3539 /* if we have file servers to monitor */
3540 /* print the CB to make sure it is right */
3544 } /* init_cm_buffers() */
3547 /*-------------------------------------------------------------------------
3548 * init_print_buffers()
3551 * Allocate and initialize the buffers used for printing results
3552 * to the display screen. These buffers store the current and
3553 * previous probe results in ascii format.
3558 *------------------------------------------------------------------------*/
3561 init_print_buffers(void)
3562 { /* init_print_buffers */
3564 static char rn[] = "init_print_buffers"; /* routine name */
3565 struct fs_Display_Data *tmp_fsData1; /* temp pointers */
3566 struct fs_Display_Data *tmp_fsData2;
3567 struct cm_Display_Data *tmp_cmData1;
3568 struct cm_Display_Data *tmp_cmData2;
3569 struct afsmon_hostEntry *tmp_fsNames;
3570 struct afsmon_hostEntry *tmp_cmNames;
3575 fprintf(debugFD, "[ %s ] Called\n", rn);
3579 /* allocate numFS blocks of the FS print structure. */
3581 /* we need two instances of this structure - one (curr_fsData) for storing
3582 * the results of the fs probes currently in progress and another (prev_fsData)
3583 * for the last completed probe. The display is updated from the contents of
3584 * prev_fsData. The pointers curr_fsData & prev_fsData are switched whenever
3585 * the probe number changes */
3588 numBytes = numFS * sizeof(struct fs_Display_Data);
3589 curr_fsData = malloc(numBytes);
3590 if (curr_fsData == (struct fs_Display_Data *)0) {
3591 fprintf(stderr, "[ %s ] Memory allocation failure\n", rn);
3594 memset(curr_fsData, 0, numBytes);
3596 numBytes = numFS * sizeof(struct fs_Display_Data);
3597 prev_fsData = malloc(numBytes);
3598 if (prev_fsData == (struct fs_Display_Data *)0) {
3599 fprintf(stderr, "[ %s ] Memory allocation failure\n", rn);
3602 memset(prev_fsData, 0, numBytes);
3604 /* fill in the host names */
3605 tmp_fsData1 = curr_fsData;
3606 tmp_fsData2 = curr_fsData;
3607 tmp_fsNames = FSnameList;
3608 for (i = 0; i < numFS; i++) {
3609 strncpy(tmp_fsData1->hostName, tmp_fsNames->hostName,
3611 strncpy(tmp_fsData2->hostName, tmp_fsNames->hostName,
3615 tmp_fsNames = tmp_fsNames->next;;
3620 /* if file servers to monitor */
3621 /* allocate numCM blocks of the CM print structure */
3622 /* we need two instances of this structure for the same reasons as above */
3624 numBytes = numCM * sizeof(struct cm_Display_Data);
3626 curr_cmData = malloc(numBytes);
3627 if (curr_cmData == (struct cm_Display_Data *)0) {
3628 fprintf(stderr, "[ %s ] Memory allocation failure\n", rn);
3631 memset(curr_cmData, 0, numBytes);
3633 numBytes = numCM * sizeof(struct cm_Display_Data);
3634 prev_cmData = malloc(numBytes);
3635 if (prev_cmData == (struct cm_Display_Data *)0) {
3636 fprintf(stderr, "[ %s ] Memory allocation failure\n", rn);
3639 memset(prev_cmData, 0, numBytes);
3641 /* fill in the host names */
3642 tmp_cmData1 = curr_cmData;
3643 tmp_cmData2 = curr_cmData;
3644 tmp_cmNames = CMnameList;
3645 for (i = 0; i < numCM; i++) {
3646 strncpy(tmp_cmData1->hostName, tmp_cmNames->hostName,
3648 strncpy(tmp_cmData2->hostName, tmp_cmNames->hostName,
3652 tmp_cmNames = tmp_cmNames->next;;
3656 /* if cache managers to monitor */
3659 } /* init_print_buffers */
3661 /*-----------------------------------------------------------------------
3665 * Trap the interrupt signal. This function is useful only until
3666 * gtx is initialized.
3667 *----------------------------------------------------------------------*/
3670 quit_signal(int sig)
3672 fprintf(stderr, "Received signal %d \n", sig);
3678 /*-----------------------------------------------------------------------
3682 * This is where we start it all. Initialize an array of sockets for
3683 * file servers and cache cache managers and call the xstat_[fs/cm]_Init
3684 * routines. The last step is to call the gtx input server which
3685 * grabs control of the keyboard.
3688 * Does not return. Control is periodically returned to the afsmonitor
3689 * thru afsmon_[FS/CM]_Handler() routines and also through the gtx
3690 * keyboard handler calls.
3692 *----------------------------------------------------------------------*/
3695 afsmon_execute(void)
3696 { /* afsmon_execute() */
3697 static char rn[] = "afsmon_execute"; /* routine name */
3698 static char fullhostname[128]; /* full host name */
3699 struct sockaddr_in *FSSktArray; /* fs socket array */
3700 int FSsktbytes; /* num bytes in above */
3701 struct sockaddr_in *CMSktArray; /* cm socket array */
3702 int CMsktbytes; /* num bytes in above */
3703 struct sockaddr_in *curr_skt; /* ptr to current socket */
3704 struct afsmon_hostEntry *curr_FS; /* ptr to FS name list */
3705 struct afsmon_hostEntry *curr_CM; /* ptr to CM name list */
3706 struct hostent *he; /* host entry */
3707 int FSinitFlags = 0; /* flags for xstat_fs_Init */
3708 int CMinitFlags = 0; /* flags for xstat_cm_Init */
3709 int code; /* function return code */
3710 struct timeval tv; /* time structure */
3715 fprintf(debugFD, "[ %s ] Called\n", rn);
3720 /* process file server entries */
3722 afs_int32 collIDs[MAX_NUM_FS_COLLECTIONS];
3724 /* Allocate an array of sockets for each fileserver we monitor */
3726 FSsktbytes = numFS * sizeof(struct sockaddr_in);
3727 FSSktArray = malloc(FSsktbytes);
3728 if (FSSktArray == (struct sockaddr_in *)0) {
3730 "[ %s ] cannot malloc %d sockaddr_ins for fileservers\n",
3735 memset(FSSktArray, 0, FSsktbytes);
3737 /* Fill in the socket information for each fileserve */
3739 curr_skt = FSSktArray;
3740 curr_FS = FSnameList; /* FS name list header */
3742 strncpy(fullhostname, curr_FS->hostName, sizeof(fullhostname));
3743 he = GetHostByName(fullhostname);
3745 fprintf(stderr, "[ %s ] Cannot get host info for %s\n", rn,
3749 strncpy(curr_FS->hostName, he->h_name, HOST_NAME_LEN); /* complete name */
3750 memcpy(&(curr_skt->sin_addr.s_addr), he->h_addr, 4);
3751 curr_skt->sin_family = AF_INET; /*Internet family */
3752 curr_skt->sin_port = htons(7000); /*FileServer port */
3753 #ifdef STRUCT_SOCKADDR_HAS_SA_LEN
3754 curr_skt->sin_len = sizeof(struct sockaddr_in);
3757 /* get the next dude */
3759 curr_FS = curr_FS->next;
3762 /* Initialize collection IDs, depending on the data requested. */
3763 num_fs_collections = 0;
3764 for (i = 0; i < fs_DisplayItems_count; i++) {
3765 index = fs_Display_map[i];
3766 if (FS_FULLPERF_ENTRY_START <= index && index <= FS_FULLPERF_ENTRY_END) {
3767 collIDs[num_fs_collections++] = AFS_XSTATSCOLL_FULL_PERF_INFO;
3771 for (i = 0; i < fs_DisplayItems_count; i++) {
3772 index = fs_Display_map[i];
3773 if (FS_CB_ENTRY_START <= index && index <= FS_CB_ENTRY_END) {
3774 collIDs[num_fs_collections++] = AFS_XSTATSCOLL_CBSTATS;
3780 if (afsmon_onceOnly) /* option not provided at this time */
3781 FSinitFlags |= XSTAT_FS_INITFLAG_ONE_SHOT;
3784 fprintf(debugFD, "[ %s ] Calling xstat_fs_Init \n", rn);
3788 code = xstat_fs_Init(numFS, /*Num servers */
3789 FSSktArray, /*File Server socket array */
3790 afsmon_probefreq, /*probe frequency */
3791 afsmon_FS_Handler, /*Handler routine */
3792 FSinitFlags, /*Initialization flags */
3793 num_fs_collections, /*Number of collection IDs */
3794 collIDs); /*Ptr to collection ID */
3797 fprintf(stderr, "[ %s ] xstat_fs_init returned error\n", rn);
3804 /* end of process fileserver entries */
3805 /* process cache manager entries */
3807 afs_int32 collIDs[MAX_NUM_CM_COLLECTIONS];
3809 /* Allocate an array of sockets for each cache manager we monitor */
3811 CMsktbytes = numCM * sizeof(struct sockaddr_in);
3812 CMSktArray = malloc(CMsktbytes);
3813 if (CMSktArray == (struct sockaddr_in *)0) {
3815 "[ %s ] cannot malloc %d sockaddr_ins for CM entries\n",
3820 memset(CMSktArray, 0, CMsktbytes);
3822 /* Fill in the socket information for each CM */
3824 curr_skt = CMSktArray;
3825 curr_CM = CMnameList; /* CM name list header */
3827 strncpy(fullhostname, curr_CM->hostName, sizeof(fullhostname));
3828 he = GetHostByName(fullhostname);
3830 fprintf(stderr, "[ %s ] Cannot get host info for %s\n", rn,
3834 strncpy(curr_CM->hostName, he->h_name, HOST_NAME_LEN); /* complete name */
3835 memcpy(&(curr_skt->sin_addr.s_addr), he->h_addr, 4);
3836 curr_skt->sin_family = AF_INET;
3837 curr_skt->sin_port = htons(7001); /* Cache Manager port */
3838 #ifdef STRUCT_SOCKADDR_HAS_SA_LEN
3839 curr_skt->sin_len = sizeof(struct sockaddr_in);
3842 /* get the next dude */
3844 curr_CM = curr_CM->next;
3847 /* initialize collection IDs. We need only one entry since we collect
3848 * all the information from xstat */
3849 num_cm_collections = 0;
3850 collIDs[num_cm_collections++] = AFSCB_XSTATSCOLL_FULL_PERF_INFO;
3853 if (afsmon_onceOnly) /* once only ? */
3854 CMinitFlags |= XSTAT_CM_INITFLAG_ONE_SHOT;
3857 fprintf(debugFD, "[ %s ] Calling xstat_cm_Init \n", rn);
3861 code = xstat_cm_Init(numCM, /*Num servers */
3862 CMSktArray, /*Cache Manager socket array */
3863 afsmon_probefreq, /*probe frequency */
3864 afsmon_CM_Handler, /*Handler routine */
3865 CMinitFlags, /*Initialization flags */
3866 num_cm_collections, /*Number of collection IDs */
3867 collIDs); /*Ptr to collection ID */
3870 fprintf(stderr, "[ %s ] xstat_cm_init returned error\n", rn);
3877 /* end of process cache manager entries */
3878 /* if only one probe was required setup a waiting process for the
3879 * termination signal */
3880 if (afsmon_onceOnly) {
3881 code = LWP_WaitProcess(&terminationEvent);
3884 fprintf(debugFD, "LWP_WaitProcess() returned error %d\n",
3892 /* start the gtx input server */
3893 code = (intptr_t)gtx_InputServer(afsmon_win);
3895 fprintf(stderr, "[ %s ] Failed to start input server \n", rn);
3899 /* This part of the code is reached only if the input server is not started
3900 * for debugging purposes */
3903 tv.tv_sec = 24 * 60;
3905 fprintf(stderr, "[ %s ] going to sleep ...\n", rn);
3907 code = IOMGR_Select(0, /*Num fds */
3908 0, /*Descriptors ready for reading */
3909 0, /*Descriptors ready for writing */
3910 0, /*Descriptors with exceptional conditions */
3911 &tv); /*Timeout structure */
3914 "[ %s ] IOMGR_Select() returned non-zero value %d\n", rn,
3922 /*-----------------------------------------------------------------------
3926 * Afsmonitor initialization routine.
3927 * - processes command line parameters
3928 * - call functions to:
3929 * - process config file
3930 * - initialize circular buffers and display buffers
3932 * - execute afsmonitor
3933 * - initialize the display maps [fs/cm]_Display_map[].
3936 * Success: Does not return from the call to afsmon_execute().
3937 * Failure: Exits afsmonitor.
3938 *----------------------------------------------------------------------*/
3941 afsmonInit(struct cmd_syndesc *as, void *arock)
3942 { /* afsmonInit() */
3944 static char rn[] = "afsmonInit"; /* Routine name */
3945 char *debug_filename; /* pointer to debug filename */
3946 FILE *outputFD; /* output file descriptor */
3947 struct cmd_item *hostPtr; /* ptr to parse command line args */
3948 char buf[256]; /* buffer for processing hostnames */
3953 fprintf(debugFD, "[ %s ] Called, as= %p\n", rn, as);
3957 /* Open the debug file if -debug option is specified */
3958 if (as->parms[P_DEBUG].items != 0) {
3960 debug_filename = as->parms[P_DEBUG].items->data;
3961 debugFD = fopen(debug_filename, "w");
3962 if (debugFD == (FILE *) 0) {
3963 printf("[ %s ] Failed to open debugging file %s for writing\n",
3971 fprintf(debugFD, "[ %s ] Called\n", rn);
3975 /* use curses always until we support other packages */
3977 wpkg_to_use = atoi(as->parms[P_PACKAGE].items->data);
3979 switch (wpkg_to_use) {
3980 case GATOR_WIN_CURSES:
3981 fprintf(stderr, "curses\n");
3983 case GATOR_WIN_DUMB:
3984 fprintf(stderr, "dumb terminal\n");
3987 fprintf(stderr, "X11\n");
3990 fprintf(stderr, "Illegal graphics package: %d\n", wpkg_to_use);
3992 } /*end switch (wpkg_to_use) */
3995 wpkg_to_use = GATOR_WIN_CURSES;
3997 /* get probe frequency . We check for meaningful bounds on the frequency
3998 * and reset to the default value if needed. The upper bound of 24
3999 * hours looks ridiculous though! */
4001 afsmon_probefreq = 0;
4002 if (as->parms[P_FREQUENCY].items != 0)
4003 afsmon_probefreq = atoi(as->parms[P_FREQUENCY].items->data);
4005 afsmon_probefreq = DEFAULT_FREQUENCY;
4007 if (afsmon_probefreq <= 0 || afsmon_probefreq > 24 * 60 * 60) {
4008 afsmon_probefreq = DEFAULT_FREQUENCY;
4011 "[ %s ] Invalid probe frequency %s specified, resetting to default value %d seconds\n",
4012 rn, as->parms[P_FREQUENCY].items->data, afsmon_probefreq);
4016 "Invalid probe frequency %s specified, resetting to default value %d seconds\n",
4017 as->parms[P_FREQUENCY].items->data, afsmon_probefreq);
4022 /* make sure output file is writable, else complain now */
4023 /* we will open and close it as needed after probes */
4025 if (as->parms[P_OUTPUT].items != 0) {
4026 afsmon_output = 1; /* output flag */
4027 strncpy(output_filename, as->parms[P_OUTPUT].items->data, 80);
4028 outputFD = fopen(output_filename, "a");
4029 if (outputFD == (FILE *) 0) {
4030 fprintf(stderr, "Failed to open output file %s \n",
4033 fprintf(debugFD, "[ %s ] Failed to open output file %s \n",
4034 rn, output_filename);
4039 fprintf(debugFD, "[ %s ] output file is %s\n", rn,
4045 /* detailed statistics to storage file */
4046 if (as->parms[P_DETAILED].items != 0) {
4047 if (as->parms[P_OUTPUT].items == 0) {
4049 "-detailed switch can be used only with -output\n");
4052 afsmon_detOutput = 1;
4055 /* Initialize host list headers */
4056 FSnameList = (struct afsmon_hostEntry *)0;
4057 CMnameList = (struct afsmon_hostEntry *)0;
4059 /* The -config option is mutually exclusive with the -fshosts,-cmhosts
4062 if (as->parms[P_CONFIG].items) {
4063 if (as->parms[P_FSHOSTS].items || as->parms[P_CMHOSTS].items) {
4065 "Cannot use -config option with -fshosts or -cmhosts\n");
4069 if (!as->parms[P_FSHOSTS].items && !as->parms[P_CMHOSTS].items) {
4071 "Must specify either -config or (-fshosts and/or -cmhosts) options \n");
4077 /* If a file server host is specified on the command line we reuse
4078 * parse_hostEntry() function . Just the pass the info as if it were
4079 * read off the config file */
4081 if (as->parms[P_FSHOSTS].items) {
4082 hostPtr = as->parms[P_FSHOSTS].items;
4083 while (hostPtr != (struct cmd_item *)0) {
4084 sprintf(buf, "fs %s", hostPtr->data);
4085 code = parse_hostEntry(buf);
4087 fprintf(stderr, "Could not parse %s\n", hostPtr->data);
4091 hostPtr = hostPtr->next;
4095 /* same as above for -cmhosts */
4096 if (as->parms[P_CMHOSTS].items) {
4097 hostPtr = as->parms[P_CMHOSTS].items;
4098 while (hostPtr != (struct cmd_item *)0) {
4099 sprintf(buf, "cm %s", hostPtr->data);
4100 code = parse_hostEntry(buf);
4102 fprintf(stderr, "Could not parse %s\n", hostPtr->data);
4106 hostPtr = hostPtr->next;
4110 /* number of slots in circular buffers */
4111 if (as->parms[P_BUFFERS].items)
4112 num_bufSlots = atoi(as->parms[P_BUFFERS].items->data);
4114 num_bufSlots = DEFAULT_BUFSLOTS;
4116 /* Initialize xx_showFlags[]. This array is used solely for processing the
4117 * "show" directives in the config file in parse_showEntries() */
4118 for (i = 0; i < NUM_FS_STAT_ENTRIES; i++)
4119 fs_showFlags[i] = 0;
4120 for (i = 0; i < NUM_CM_STAT_ENTRIES; i++)
4121 cm_showFlags[i] = 0;
4124 /* Process the configuration file if given. This initializes among other
4125 * things, the list of FS & CM names in FSnameList and CMnameList */
4127 if (as->parms[P_CONFIG].items)
4128 process_config_file(as->parms[P_CONFIG].items->data);
4130 /* print out the FS and CM lists */
4134 /* Initialize the FS results-to-screen map array if there were no "show fs"
4135 * directives in the config file */
4136 if (fs_showDefault) {
4137 for (i = 0; i < NUM_FS_STAT_ENTRIES; i++)
4138 fs_Display_map[i] = i;
4139 fs_DisplayItems_count = NUM_FS_STAT_ENTRIES;
4142 /* Initialize the CM results-to-screen map array if there were no "show cm"
4143 * directives in the config file */
4144 if (cm_showDefault) {
4145 for (i = 0; i < NUM_CM_STAT_ENTRIES; i++)
4146 cm_Display_map[i] = i;
4147 cm_DisplayItems_count = NUM_CM_STAT_ENTRIES;
4152 /* setup an interrupt signal handler; we ain't wanna leak core */
4153 /* this binding is useful only until gtx is initialized after which the
4154 * keyboard input server takes over. */
4155 if ((signal(SIGINT, quit_signal)) == SIG_ERR) {
4156 perror("signal() failed.");
4161 /* init error message buffers. these will be used to print error messages
4162 * once gtx is initialized and there is no access to stderr/stdout */
4168 /* initialize fs and cm circular buffers before initiating probes */
4170 code = init_fs_buffers();
4172 fprintf(stderr, "[ %s ] init_fs_buffers returned %d\n", rn,
4179 code = init_cm_buffers();
4181 fprintf(stderr, "[ %s ] init_cm_buffers returned %d\n", rn,
4188 /* allocate and initialize buffers for holding fs & cm results in ascii
4189 * format suitable for updating the screen */
4190 code = init_print_buffers();
4192 fprintf(stderr, "[ %s ] init_print_buffers returned %d\n", rn, code);
4196 /* perform gtx initializations */
4197 code = gtx_initialize();
4199 fprintf(stderr, "[ %s ] gtx_initialize returned %d\n", rn, code);
4203 /* start xstat probes */
4206 return (0); /* will not return from the call to afsmon_execute() */
4208 } /* afsmonInit() */
4211 /*-----------------------------------------------------------------------
4213 ------------------------------------------------------------------------*/
4215 #include "AFS_component_version_number.c"
4218 main(int argc, char **argv)
4220 afs_int32 code; /*Return code */
4221 struct cmd_syndesc *ts; /*Ptr to cmd line syntax descriptor */
4223 #ifdef AFS_AIX32_ENV
4225 * The following signal action for AIX is necessary so that in case of a
4226 * crash (i.e. core is generated) we can include the user's data section
4227 * in the core dump. Unfortunately, by default, only a partial core is
4228 * generated which, in many cases, isn't too useful.
4230 struct sigaction nsa;
4232 sigemptyset(&nsa.sa_mask);
4233 nsa.sa_handler = SIG_DFL;
4234 nsa.sa_flags = SA_FULLDUMP;
4235 sigaction(SIGSEGV, &nsa, NULL);
4239 * Set up the commands we understand.
4241 ts = cmd_CreateSyntax("initcmd", afsmonInit, NULL, "initialize the program");
4242 cmd_AddParm(ts, "-config", CMD_SINGLE, CMD_OPTIONAL,
4243 "configuration file");
4244 cmd_AddParm(ts, "-frequency", CMD_SINGLE, CMD_OPTIONAL,
4245 "poll frequency, in seconds");
4246 cmd_AddParm(ts, "-output", CMD_SINGLE, CMD_OPTIONAL, "storage file name");
4247 cmd_AddParm(ts, "-detailed", CMD_FLAG, CMD_OPTIONAL,
4248 "output detailed statistics to storage file");
4250 /* we hope to use this .... eventually! */
4251 cmd_AddParm(ts, "-package", CMD_SINGLE, CMD_REQUIRED,
4252 "Graphics Package to use");
4254 cmd_AddParm(ts, "-debug", CMD_SINGLE, CMD_OPTIONAL,
4255 "turn debugging output on to the named file");
4256 cmd_AddParm(ts, "-fshosts", CMD_LIST, CMD_OPTIONAL,
4257 "list of file servers to monitor");
4258 cmd_AddParm(ts, "-cmhosts", CMD_LIST, CMD_OPTIONAL,
4259 "list of cache managers to monitor");
4260 cmd_AddParm(ts, "-buffers", CMD_SINGLE, CMD_OPTIONAL,
4261 "number of buffer slots");
4264 * Parse command-line switches & execute afsmonitor
4267 code = cmd_Dispatch(argc, argv);
4273 exit(0); /* redundant, but gets rid of warning */