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.
306 while (len1 >= len2 && len1 > 0) {
307 if ((strncasecmp(ptr, s2, len2)) == 0)
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 != NULL) {
486 fprintf(debugFD, "Deallocating FS Print Buffers .... curr");
489 if (prev_fsData != NULL) {
491 fprintf(debugFD, ", prev \n");
494 if (curr_cmData != NULL) {
496 fprintf(debugFD, "Deallocating CM Print Buffers .... curr");
499 if (prev_cmData != NULL) {
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") != NULL
1162 || strcasestr(arg2, "_group") != 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") != 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") != 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") != NULL
1277 || strcasestr(arg2, "_group") != 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") != 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") != 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);
1743 /* If a new probe cycle started, mark the list in the current buffer
1744 * slot empty for resuse. Note that afsmon_fs_curr_CBindex was appropriately
1745 * incremented in afsmon_FS_Handler() */
1747 if (a_newProbeCycle) {
1748 tmp_fslist_item = afsmon_fs_ResultsCB[afsmon_fs_curr_CBindex].list;
1749 for (i = 0; i < numFS; i++) {
1750 tmp_fslist_item->empty[index] = 1;
1751 tmp_fslist_item = tmp_fslist_item->next;
1755 /* locate last unused item in list */
1756 tmp_fslist_item = afsmon_fs_ResultsCB[afsmon_fs_curr_CBindex].list;
1757 for (i = 0; i < numFS; i++) {
1758 if (tmp_fslist_item->empty[index])
1760 tmp_fslist_item = tmp_fslist_item->next;
1763 /* if we could not find one we have an inconsistent list */
1764 if (!tmp_fslist_item->empty[index]) {
1766 "[ %s ] list inconsistency 1. unable to find an empty slot to store results of probenum %d of %s\n",
1767 rn, xstat_fs_Results.probeNum,
1768 xstat_fs_Results.connP->hostName);
1772 tmp_fsPR = tmp_fslist_item->fsResults[index];
1774 /* copy hostname and probe number and probe time and probe status.
1775 * if the probe failed return now */
1777 memcpy(tmp_fsPR->connP->hostName, xstat_fs_Results.connP->hostName,
1778 sizeof(xstat_fs_Results.connP->hostName));
1779 tmp_fsPR->probeNum = xstat_fs_Results.probeNum;
1780 tmp_fsPR->probeTime = xstat_fs_Results.probeTime;
1781 tmp_fsPR->probeOK = xstat_fs_Results.probeOK;
1782 if (xstat_fs_Results.probeOK) { /* probeOK = 1 => notOK */
1783 /* we have a nonempty results structure so mark the list item used */
1784 tmp_fslist_item->empty[index] = 0;
1788 /* copy connection information */
1789 memcpy(&(tmp_fsPR->connP->skt), &(xstat_fs_Results.connP->skt),
1790 sizeof(struct sockaddr_in));
1792 memcpy(tmp_fsPR->connP->hostName, xstat_fs_Results.connP->hostName,
1793 sizeof(xstat_fs_Results.connP->hostName));
1794 tmp_fsPR->collectionNumber = xstat_fs_Results.collectionNumber;
1796 /* copy the probe data information */
1797 tmp_fsPR->data.AFS_CollData_len =
1798 min(xstat_fs_Results.data.AFS_CollData_len,
1799 afsmon_fs_results_length[index]);
1800 memcpy(tmp_fsPR->data.AFS_CollData_val,
1801 xstat_fs_Results.data.AFS_CollData_val,
1802 tmp_fsPR->data.AFS_CollData_len * sizeof(afs_int32));
1805 /* we have a valid results structure so mark the list item used */
1806 tmp_fslist_item->empty[index] = 0;
1808 /* Print the fs circular buffer */
1812 } /* save_FS_results_inCB() */
1815 /*-----------------------------------------------------------------------
1819 * The results of xstat probes are stored in a string format in
1820 * the arrays curr_fsData and prev_fsData. The information stored in
1821 * prev_fsData is copied to the screen.
1822 * This function converts xstat FS results from longs to strings and
1823 * place them in the given buffer (a pointer to an item in curr_fsData).
1824 * When a probe cycle completes, curr_fsData is copied to prev_fsData
1825 * in afsmon_FS_Hnadler().
1829 *----------------------------------------------------------------------*/
1832 fs_Results_ltoa(struct fs_Display_Data *a_fsData, /* target buffer */
1833 struct xstat_fs_ProbeResults *a_fsResults) /* ptr to xstat fs Results */
1834 { /* fs_Results_ltoa */
1836 static char rn[] = "fs_Results_ltoa"; /* routine name */
1839 fprintf(debugFD, "[ %s ] Called, a_fsData= %p, a_fsResults= %p\n", rn,
1840 a_fsData, a_fsResults);
1844 switch (a_fsResults->collectionNumber) {
1845 case AFS_XSTATSCOLL_FULL_PERF_INFO:
1846 fs_FullPerfs_ltoa(a_fsData, a_fsResults);
1848 case AFS_XSTATSCOLL_CBSTATS:
1849 fs_CallBackStats_ltoa(a_fsData, a_fsResults);
1853 fprintf(debugFD, "[ %s ] Unexpected collection id %d\n",
1854 rn, a_fsResults->collectionNumber);
1859 } /* fs_Results_ltoa */
1861 /*-----------------------------------------------------------------------
1862 * fs_FullPerfs_ltoa()
1865 * Convert the full perf xstat collection from int32s to strings.
1869 *----------------------------------------------------------------------*/
1871 fs_FullPerfs_ltoa(struct fs_Display_Data *a_fsData,
1872 struct xstat_fs_ProbeResults *a_fsResults)
1875 struct fs_stats_FullPerfStats *fullPerfP;
1876 struct fs_stats_FullPerfStats buffer;
1882 /* there are two parts to the xstat FS statistics
1883 * - fullPerfP->overall which give the overall performance statistics, and
1884 * - fullPerfP->det which gives detailed info about file server operation
1885 * execution times */
1887 code = xstat_fs_DecodeFullPerfStats(&fullPerfP,
1888 a_fsResults->data.AFS_CollData_val,
1889 a_fsResults->data.AFS_CollData_len,
1892 /* Not able to decode the full perf stats. Avoid displaying garbage. */
1893 for (i = 0; i < NUM_FS_STAT_ENTRIES; i++) {
1894 sprintf(a_fsData->data[i], "%s", "--");
1899 /* copy overall performance statistics */
1900 srcbuf = (afs_int32 *) & (fullPerfP->overall);
1902 for (i = 0; i < NUM_XSTAT_FS_AFS_PERFSTATS_LONGS; i++) {
1903 sprintf(a_fsData->data[idx], "%d", *srcbuf);
1909 srcbuf = (afs_int32 *) & (fullPerfP->det.epoch);
1910 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* epoch */
1913 /* copy fs operation timing */
1915 srcbuf = (afs_int32 *) (fullPerfP->det.rpcOpTimes);
1917 for (i = 0; i < FS_STATS_NUM_RPC_OPS; i++) {
1918 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* numOps */
1921 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* numSuccesses */
1924 tmpbuf = srcbuf++; /* sum time */
1925 sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1928 tmpbuf = srcbuf++; /* sqr time */
1929 sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1932 tmpbuf = srcbuf++; /* min time */
1933 sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1936 tmpbuf = srcbuf++; /* max time */
1937 sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1942 /* copy fs transfer timings */
1944 srcbuf = (afs_int32 *) (fullPerfP->det.xferOpTimes);
1945 for (i = 0; i < FS_STATS_NUM_XFER_OPS; i++) {
1946 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* numOps */
1949 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* numSuccesses */
1952 tmpbuf = srcbuf++; /* sum time */
1953 sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1956 tmpbuf = srcbuf++; /* sqr time */
1957 sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1960 tmpbuf = srcbuf++; /* min time */
1961 sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1964 tmpbuf = srcbuf++; /* max time */
1965 sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1968 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* sum bytes */
1971 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* min bytes */
1974 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* max bytes */
1977 for (j = 0; j < FS_STATS_NUM_XFER_BUCKETS; j++) {
1978 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* bucket[j] */
1987 /*-----------------------------------------------------------------------
1988 * fs_CallBackStats_ltoa()
1991 * Convert the callback counter xstat collection from
1992 * int32s to strings.
1996 *----------------------------------------------------------------------*/
1999 fs_CallBackStats_ltoa(struct fs_Display_Data *a_fsData,
2000 struct xstat_fs_ProbeResults *a_fsResults)
2004 int len = a_fsResults->data.AFS_CollData_len;
2005 afs_int32 *val = a_fsResults->data.AFS_CollData_val;
2007 /* place callback stats after the full perf stats */
2008 idx = NUM_FS_FULLPERF_ENTRIES;
2009 for (i=0; i < len && i < NUM_FS_CB_ENTRIES; i++) {
2010 sprintf(a_fsData->data[idx++], "%u", val[i]);
2015 /*-----------------------------------------------------------------------
2016 * execute_thresh_handler()
2019 * Execute a threshold handler. An agrv[] array of pointers is
2020 * constructed from the given data. A child process is forked
2021 * which immediately calls afsmon_Exit() with indication that a
2022 * threshold handler is to be exec'ed insted of exiting.
2026 * Failure: Afsmonitor exits if threshold handler has more than 20 args.
2027 *----------------------------------------------------------------------*/
2030 execute_thresh_handler(char *a_handler, /* ptr to handler function + args */
2031 char *a_hostName, /* host name for which threshold crossed */
2032 int a_hostType, /* fs or cm ? */
2033 char *a_threshName, /* threshold variable name */
2034 char *a_threshValue, /* threshold value */
2035 char *a_actValue) /* actual value */
2036 { /* execute_thresh_handler */
2038 static char rn[] = "execute_thresh_handler";
2039 char fileName[256]; /* file name to execute */
2043 int anotherArg; /* boolean used to flag if another arg is available */
2047 "[ %s ] Called, a_handler= %s, a_hostName= %s, a_hostType= %d, a_threshName= %s, a_threshValue= %s, a_actValue= %s\n",
2048 rn, a_handler, a_hostName, a_hostType, a_threshName,
2049 a_threshValue, a_actValue);
2054 /* get the filename to execute - the first argument */
2055 sscanf(a_handler, "%s", fileName);
2057 /* construct the contents of *argv[] */
2059 strncpy(fsHandler_args[0], fileName, 256);
2060 strncpy(fsHandler_args[1], a_hostName, HOST_NAME_LEN);
2061 if (a_hostType == FS)
2062 strcpy(fsHandler_args[2], "fs");
2064 strcpy(fsHandler_args[2], "cm");
2065 strncpy(fsHandler_args[3], a_threshName, THRESH_VAR_NAME_LEN);
2066 strncpy(fsHandler_args[4], a_threshValue, THRESH_VAR_LEN);
2067 strncpy(fsHandler_args[5], a_actValue, THRESH_VAR_LEN);
2074 /* we have already extracted the file name so skip to the 1st arg */
2075 while (isspace(*ch)) /* leading blanks */
2077 while (!isspace(*ch) && *ch != '\0') /* handler filename */
2080 while (*ch != '\0') {
2083 } else if (anotherArg) {
2085 sscanf(ch, "%s", fsHandler_args[argNum]);
2091 "Threshold handlers cannot have more than 20 arguments\n");
2097 fsHandler_argv[argNum] = NULL;
2098 for (i = 0; i < argNum; i++)
2099 fsHandler_argv[i] = fsHandler_args[i];
2102 /* exec the threshold handler */
2105 exec_fsThreshHandler = 1;
2110 } /* execute_thresh_handler */
2114 /*-----------------------------------------------------------------------
2115 * check_fs_thresholds()
2118 * Checks the thresholds and sets the overflow flag. Recall that the
2119 * thresholds for each host are stored in the hostEntry lists
2120 * [fs/cm]nameList arrays. The probe results are passed to this
2121 * function in the display-ready format - ie., as strings. Though
2122 * this looks stupid the overhead incurred in converting the strings
2123 * back to floats and comparing them is insignificant and
2124 * programming is easier this way.
2125 * The threshold flags are a part of the display structures
2130 *----------------------------------------------------------------------*/
2133 check_fs_thresholds(struct afsmon_hostEntry *a_hostEntry, /* ptr to hostEntry */
2134 struct fs_Display_Data *a_Data) /* ptr to fs data to be displayed */
2135 { /* check_fs_thresholds */
2137 static char rn[] = "check_fs_thresholds";
2138 struct Threshold *threshP;
2139 double tValue; /* threshold value */
2140 double pValue; /* probe value */
2143 int count; /* number of thresholds exceeded */
2146 fprintf(debugFD, "[ %s ] Called, a_hostEntry= %p, a_Data= %p\n", rn,
2147 a_hostEntry, a_Data);
2151 if (a_hostEntry->numThresh == 0) {
2152 /* store in ovf count ?? */
2157 threshP = a_hostEntry->thresh;
2158 for (i = 0; i < a_hostEntry->numThresh; i++) {
2159 if (threshP->itemName[0] == '\0') {
2163 idx = threshP->index; /* positional index to the data array */
2164 tValue = atof(threshP->threshVal); /* threshold value */
2165 pValue = atof(a_Data->data[idx]); /* probe value */
2166 if (pValue > tValue) {
2170 "[ %s ] fs = %s, thresh ovf for %s, threshold= %s, probevalue= %s\n",
2171 rn, a_hostEntry->hostName, threshP->itemName,
2172 threshP->threshVal, a_Data->data[idx]);
2175 /* if the threshold is crossed, call the handler function
2176 * only if this was a transition -ie, if the threshold was
2177 * crossed in the last probe too just count & keep quite! */
2179 if (!a_Data->threshOvf[idx]) {
2180 a_Data->threshOvf[idx] = 1;
2181 /* call the threshold handler if provided */
2182 if (threshP->handler[0] != '\0') {
2184 fprintf(debugFD, "[ %s ] Calling ovf handler %s\n",
2185 rn, threshP->handler);
2188 execute_thresh_handler(threshP->handler, a_Data->hostName,
2189 FS, threshP->itemName,
2197 /* in case threshold was previously crossed, blank it out */
2198 a_Data->threshOvf[idx] = 0;
2201 /* store the overflow count */
2202 a_Data->ovfCount = count;
2205 } /* check_fs_thresholds */
2208 /*-----------------------------------------------------------------------
2209 * save_FS_data_forDisplay()
2212 * Does the following:
2213 * - if the probe number changed (ie, a cycle completed) curr_fsData
2214 * is copied to prev_fsData, curr_fsData zeroed and refresh the
2215 * overview screen and file server screen with the new data.
2216 * - store the results of the current probe from xstat_fs_Results into
2217 * curr_fsData. ie., convert longs to strings.
2218 * - check the thresholds
2222 * Failure: Exits afsmonitor.
2223 *----------------------------------------------------------------------*/
2226 save_FS_data_forDisplay(struct xstat_fs_ProbeResults *a_fsResults)
2227 { /* save_FS_data_forDisplay */
2229 static char rn[] = "save_FS_data_forDisplay"; /* routine name */
2230 struct fs_Display_Data *curr_fsDataP; /* tmp ptr to curr_fsData */
2231 struct fs_Display_Data *prev_fsDataP; /* tmp ptr to prev_fsData */
2232 struct afsmon_hostEntry *curr_host;
2233 static int results_Received = 0; /* number of probes reveived in
2234 * the current cycle. If this is equal to numFS we got all
2235 * the data we want in this cycle and can now display it */
2244 fprintf(debugFD, "[ %s ] Called, a_fsResults= %p\n", rn, a_fsResults);
2248 /* store results in the display array */
2251 curr_fsDataP = curr_fsData;
2252 for (i = 0; i < numFS; i++) {
2253 if ((strcasecmp(curr_fsDataP->hostName, a_fsResults->connP->hostName))
2263 "[ %s ] Could not insert FS probe results for host %s in fs display array\n",
2264 rn, a_fsResults->connP->hostName);
2268 /* Check the status of the probe. If it succeeded, we store its
2269 * results in the display data structure. If it failed we only mark
2270 * the failed status in the display data structure. */
2272 if (a_fsResults->probeOK) { /* 1 => notOK the xstat results */
2273 curr_fsDataP->probeOK = 0;
2275 /* print the probe status */
2277 fprintf(debugFD, "\n\t\t ----- fs display data ------\n");
2278 fprintf(debugFD, "HostName = %s PROBE FAILED \n",
2279 curr_fsDataP->hostName);
2283 } else { /* probe succeeded, update display data structures */
2284 curr_fsDataP->probeOK = 1;
2286 /* convert longs to strings and place them in curr_fsDataP */
2287 fs_Results_ltoa(curr_fsDataP, a_fsResults);
2289 /* compare with thresholds and set the overflow flags.
2290 * note that the threshold information is in the hostEntry structure and
2291 * each threshold item has a positional index associated with it */
2293 /* locate the hostEntry for this host */
2295 curr_host = FSnameList;
2296 for (i = 0; i < numFS; i++) {
2297 if (strcasecmp(curr_host->hostName, a_fsResults->connP->hostName)
2302 curr_host = curr_host->next;;
2307 code = check_fs_thresholds(curr_host, curr_fsDataP);
2309 fprintf(stderr, "[ %s ] Error in checking thresholds\n", rn);
2313 /* print the info we just saved */
2316 fprintf(debugFD, "\n\t\t ----- fs display data ------\n");
2317 fprintf(debugFD, "HostName = %s\n", curr_fsDataP->hostName);
2318 for (i = 0; i < NUM_FS_STAT_ENTRIES; i++)
2319 fprintf(debugFD, "%20s %30s %s\n", curr_fsDataP->data[i],
2321 curr_fsDataP->threshOvf[i] ? "(ovf)" : "");
2323 fprintf(debugFD, "\t\t--------------------------------\n\n");
2327 } /* the probe succeeded, so we store the data in the display structure */
2330 /* if we have received a reply from all the hosts for this probe cycle,
2331 * it is time to display the data */
2334 if (results_Received == numFS * num_fs_collections) {
2335 results_Received = 0;
2337 if (afsmon_fs_curr_probeNum != afsmon_fs_prev_probeNum + 1) {
2338 sprintf(errMsg, "[ %s ] Probe number %d missed! \n", rn,
2339 afsmon_fs_prev_probeNum + 1);
2342 afsmon_fs_prev_probeNum++;
2344 /* backup the display data of the probe cycle that just completed -
2345 * ie., store curr_fsData in prev_fsData */
2347 memcpy((char *)prev_fsData, (char *)curr_fsData,
2348 (numFS * sizeof(struct fs_Display_Data)));
2351 /* initialize curr_fsData but retain the threshold flag information.
2352 * The previous state of threshold flags is used in check_fs_thresholds() */
2354 numBytes = NUM_FS_STAT_ENTRIES * FS_STAT_STRING_LEN;
2355 curr_fsDataP = curr_fsData;
2356 for (i = 0; i < numFS; i++) {
2357 curr_fsDataP->probeOK = 0;
2358 curr_fsDataP->ovfCount = 0;
2359 memset(curr_fsDataP->data, 0, numBytes);
2364 /* prev_fsData now contains all the information for the probe cycle
2365 * that just completed. Now count the number of threshold overflows for
2366 * use in the overview screen */
2368 prev_fsDataP = prev_fsData;
2370 numHosts_onfs_alerts = 0;
2371 for (i = 0; i < numFS; i++) {
2372 if (!prev_fsDataP->probeOK) { /* if probe failed */
2374 numHosts_onfs_alerts++;
2376 if (prev_fsDataP->ovfCount) { /* overflows ?? */
2377 num_fs_alerts += prev_fsDataP->ovfCount;
2378 numHosts_onfs_alerts++;
2383 fprintf(debugFD, "Number of FS alerts = %d (on %d hosts)\n",
2384 num_fs_alerts, numHosts_onfs_alerts);
2386 /* flag that the data is now ready to be displayed */
2387 fs_Data_Available = 1;
2389 /* call the Overview frame update routine (update only FS info) */
2390 ovw_refresh(ovw_currPage, OVW_UPDATE_FS);
2392 /* call the File Servers frame update routine */
2393 fs_refresh(fs_currPage, fs_curr_LCol);
2398 } /* save_FS_data_forDisplay */
2403 /*-----------------------------------------------------------------------
2404 * afsmon_FS_Handler()
2407 * This is the File Server probe Handler. It updates the afsmonitor
2408 * probe counts, fs circular buffer indices and calls the functions
2409 * to process the results of this probe.
2413 * Failure: Exits afsmonitor.
2414 *----------------------------------------------------------------------*/
2417 afsmon_FS_Handler(void)
2418 { /* afsmon_FS_Handler() */
2419 static char rn[] = "afsmon_FS_Handler"; /* routine name */
2420 int newProbeCycle; /* start of new probe cycle ? */
2421 int code; /* return status */
2426 "[ %s ] Called, hostName= %s, probeNum= %d, status=%s, collection=%d\n", rn,
2427 xstat_fs_Results.connP->hostName, xstat_fs_Results.probeNum,
2428 xstat_fs_Results.probeOK ? "FAILED" : "OK",
2429 xstat_fs_Results.collectionNumber);
2434 /* print the probe results to output file */
2435 if (afsmon_output) {
2436 code = afsmon_fsOutput(output_filename, afsmon_detOutput);
2439 "[ %s ] output to file %s returned error code=%d\n", rn,
2440 output_filename, code);
2444 /* Update current probe number and circular buffer index. if current
2445 * probenum changed make sure it is only by 1 */
2448 if (xstat_fs_Results.probeNum != afsmon_fs_curr_probeNum) {
2449 if (xstat_fs_Results.probeNum == afsmon_fs_curr_probeNum + 1) {
2450 afsmon_fs_curr_probeNum++;
2453 afsmon_fs_curr_CBindex =
2454 (afsmon_fs_curr_probeNum - 1) % num_bufSlots;
2456 fprintf(stderr, "[ %s ] probe number %d-1 missed\n", rn,
2457 xstat_fs_Results.probeNum);
2463 /* store the results of this probe in the FS circular buffer */
2465 save_FS_results_inCB(newProbeCycle);
2468 /* store the results of the current probe in the fs data display structure.
2469 * if the current probe number changed, swap the current and previous display
2470 * structures. note that the display screen is updated from these structures
2471 * and should start showing the data of the just completed probe cycle */
2473 save_FS_data_forDisplay(&xstat_fs_Results);
2480 /*----------------------------------------------------------------------- *
2485 * Prints the Cache Manager circular buffer
2486 *----------------------------------------------------------------------*/
2490 { /* Print_CM_CB() */
2492 struct afsmon_cm_Results_list *cmlist;
2497 /* print valid info in the cm CB */
2501 "==================== CM Buffer ========================\n");
2502 fprintf(debugFD, "afsmon_cm_curr_CBindex = %d\n",
2503 afsmon_cm_curr_CBindex);
2504 fprintf(debugFD, "afsmon_cm_curr_probeNum = %d\n\n",
2505 afsmon_cm_curr_probeNum);
2507 for (i = 0; i < num_bufSlots; i++) {
2508 fprintf(debugFD, "\t--------- slot %d ----------\n", i);
2509 cmlist = afsmon_cm_ResultsCB[i].list;
2512 for (k = 0; k < MAX_NUM_CM_COLLECTIONS; k++) {
2513 if (!cmlist->empty[k]) {
2515 "\t %d) probeNum = %d host = %s cn = %d",
2517 cmlist->cmResults[k]->probeNum,
2518 cmlist->cmResults[k]->connP->hostName,
2519 cmlist->cmResults[k]->collectionNumber);
2520 if (cmlist->cmResults[k]->probeOK)
2521 fprintf(debugFD, " NOTOK\n");
2523 fprintf(debugFD, " OK\n");
2525 fprintf(debugFD, "\t %d) -- empty --\n", j);
2527 cmlist = cmlist->next;
2530 if (cmlist != (struct afsmon_cm_Results_list *)0)
2531 fprintf(debugFD, "dangling last next ptr cm CB\n");
2537 /*-----------------------------------------------------------------------
2538 * save_CM_results_inCB()
2541 * Saves the results of the latest CM probe in the cm circular
2542 * buffers. If the current probe cycle is in progress the contents
2543 * of xstat_cm_Results are copied to the end of the list of results
2544 * in the current slot (pointed to by afsmon_cm_curr_CBindex). If
2545 * a new probe cycle has started the next slot in the circular buffer
2546 * is initialized and the results copied. Note that the Rx related
2547 * information available in xstat_cm_Results is not copied.
2551 * Failure: Exits afsmonitor.
2552 *----------------------------------------------------------------------*/
2555 save_CM_results_inCB(int a_newProbeCycle) /* start of new probe cycle ? */
2556 { /* save_CM_results_inCB() */
2557 static char rn[] = "save_CM_results_inCB"; /* routine name */
2558 struct afsmon_cm_Results_list *tmp_cmlist_item; /* temp cm list item */
2559 struct xstat_cm_ProbeResults *tmp_cmPR; /* temp ptr */
2565 fprintf(debugFD, "[ %s ] Called, a_newProbeCycle= %d\n", rn,
2570 if (xstat_cm_Results.collectionNumber == AFSCB_XSTATSCOLL_FULL_PERF_INFO) {
2573 fprintf(stderr, "[ %s ] collection number %d is out of range.\n",
2574 rn, xstat_cm_Results.collectionNumber);
2578 /* If a new probe cycle started, mark the list in the current buffer
2579 * slot empty for resuse. Note that afsmon_cm_curr_CBindex was appropriately
2580 * incremented in afsmon_CM_Handler() */
2582 if (a_newProbeCycle) {
2583 tmp_cmlist_item = afsmon_cm_ResultsCB[afsmon_cm_curr_CBindex].list;
2584 for (i = 0; i < numCM; i++) {
2585 tmp_cmlist_item->empty[index] = 1;
2586 tmp_cmlist_item = tmp_cmlist_item->next;
2590 /* locate last unused item in list */
2591 tmp_cmlist_item = afsmon_cm_ResultsCB[afsmon_cm_curr_CBindex].list;
2592 for (i = 0; i < numCM; i++) {
2593 if (tmp_cmlist_item->empty[index])
2595 tmp_cmlist_item = tmp_cmlist_item->next;
2598 /* if we could not find one we have an inconsistent list */
2599 if (!tmp_cmlist_item->empty[index]) {
2601 "[ %s ] list inconsistency 1. unable to find an empty slot to store results of probenum %d of %s\n",
2602 rn, xstat_cm_Results.probeNum,
2603 xstat_cm_Results.connP->hostName);
2607 tmp_cmPR = tmp_cmlist_item->cmResults[index];
2609 /* copy hostname and probe number and probe time and probe status.
2610 * if the probe failed return now */
2612 memcpy(tmp_cmPR->connP->hostName, xstat_cm_Results.connP->hostName,
2613 sizeof(xstat_cm_Results.connP->hostName));
2614 tmp_cmPR->probeNum = xstat_cm_Results.probeNum;
2615 tmp_cmPR->probeTime = xstat_cm_Results.probeTime;
2616 tmp_cmPR->probeOK = xstat_cm_Results.probeOK;
2617 if (xstat_cm_Results.probeOK) { /* probeOK = 1 => notOK */
2618 /* we have a nonempty results structure so mark the list item used */
2619 tmp_cmlist_item->empty[index] = 0;
2624 /* copy connection information */
2625 memcpy(&(tmp_cmPR->connP->skt), &(xstat_cm_Results.connP->skt),
2626 sizeof(struct sockaddr_in));
2628 /**** NEED TO COPY rx_connection INFORMATION HERE ******/
2630 memcpy(tmp_cmPR->connP->hostName, xstat_cm_Results.connP->hostName,
2631 sizeof(xstat_cm_Results.connP->hostName));
2632 tmp_cmPR->collectionNumber = xstat_cm_Results.collectionNumber;
2634 /* copy the probe data information */
2635 tmp_cmPR->data.AFSCB_CollData_len =
2636 min(xstat_cm_Results.data.AFSCB_CollData_len,
2637 afsmon_cm_results_length[index]);
2638 memcpy(tmp_cmPR->data.AFSCB_CollData_val,
2639 xstat_cm_Results.data.AFSCB_CollData_val,
2640 tmp_cmPR->data.AFSCB_CollData_len * sizeof(afs_int32));
2643 /* we have a valid results structure so mark the list item used */
2644 tmp_cmlist_item->empty[index] = 0;
2646 /* print the stored info - to make sure we copied it right */
2647 /* Print_cm_FullPerfInfo(tmp_cmPR); */
2648 /* Print the cm circular buffer */
2651 } /* save_CM_results_inCB */
2655 /*-----------------------------------------------------------------------
2659 * The results of xstat probes are stored in a string format in
2660 * the arrays curr_cmData and prev_cmData. The information stored in
2661 * prev_cmData is copied to the screen.
2662 * This function converts xstat FS results from longs to strings and
2663 * places them in the given buffer (a pointer to an item in curr_cmData).
2664 * When a probe cycle completes, curr_cmData is copied to prev_cmData
2665 * in afsmon_CM_Handler().
2669 *----------------------------------------------------------------------*/
2672 cm_Results_ltoa(struct cm_Display_Data *a_cmData, /* target buffer */
2673 struct xstat_cm_ProbeResults *a_cmResults) /* ptr to xstat cm Results */
2674 { /* cm_Results_ltoa */
2676 static char rn[] = "cm_Results_ltoa"; /* routine name */
2677 struct afs_stats_CMFullPerf *fullP; /* ptr to complete CM stats */
2685 fprintf(debugFD, "[ %s ] Called, a_cmData= %p, a_cmResults= %p\n", rn,
2686 a_cmData, a_cmResults);
2691 fullP = (struct afs_stats_CMFullPerf *)
2692 (a_cmResults->data.AFSCB_CollData_val);
2694 /* There are 4 parts to CM statistics
2695 * - Overall performance statistics (including up/down statistics)
2696 * - This CMs FS RPC operations info
2697 * - This CMs FS RPC errors info
2698 * - This CMs FS transfers info
2699 * - Authentication info
2700 * - [Un]Replicated access info
2703 /* copy overall performance statistics */
2704 srcbuf = (afs_int32 *) & (fullP->perf);
2706 /* we skip the 19 entry, ProtServAddr, so the index must account for this */
2707 for (i = 0; i < NUM_AFS_STATS_CMPERF_LONGS + 1; i++) {
2710 continue; /* skip ProtServerAddr */
2712 sprintf(a_cmData->data[idx], "%d", *srcbuf);
2717 /*printf("Ending index value = %d\n",idx-1); */
2719 /* server up/down statistics */
2720 /* copy file server up/down stats */
2721 srcbuf = (afs_int32 *) (fullP->perf.fs_UpDown);
2723 2 * (sizeof(struct afs_stats_SrvUpDownInfo) / sizeof(afs_int32));
2724 for (i = 0; i < numLongs; i++) {
2725 sprintf(a_cmData->data[idx], "%d", *srcbuf);
2730 /*printf("Ending index value = %d\n",idx-1); */
2732 /* copy volume location server up/down stats */
2733 srcbuf = (afs_int32 *) (fullP->perf.vl_UpDown);
2735 2 * (sizeof(struct afs_stats_SrvUpDownInfo) / sizeof(afs_int32));
2736 for (i = 0; i < numLongs; i++) {
2737 sprintf(a_cmData->data[idx], "%d", *srcbuf);
2742 /*printf("Ending index value = %d\n",idx-1); */
2744 /* copy CMs individual FS RPC operations info */
2745 srcbuf = (afs_int32 *) (fullP->rpc.fsRPCTimes);
2746 for (i = 0; i < AFS_STATS_NUM_FS_RPC_OPS; i++) {
2747 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* numOps */
2750 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* numSuccesses */
2753 tmpbuf = srcbuf++; /* sum time */
2754 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2757 tmpbuf = srcbuf++; /* sqr time */
2758 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2761 tmpbuf = srcbuf++; /* min time */
2762 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2765 tmpbuf = srcbuf++; /* max time */
2766 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2771 /*printf("Ending index value = %d\n",idx-1); */
2773 /* copy CMs individual FS RPC errors info */
2775 srcbuf = (afs_int32 *) (fullP->rpc.fsRPCErrors);
2776 for (i = 0; i < AFS_STATS_NUM_FS_RPC_OPS; i++) {
2777 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* server */
2780 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* network */
2783 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* prot */
2786 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* vol */
2789 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* busies */
2792 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* other */
2797 /*printf("Ending index value = %d\n",idx-1); */
2799 /* copy CMs individual RPC transfers info */
2801 srcbuf = (afs_int32 *) (fullP->rpc.fsXferTimes);
2802 for (i = 0; i < AFS_STATS_NUM_FS_XFER_OPS; i++) {
2803 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* numOps */
2806 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* numSuccesses */
2809 tmpbuf = srcbuf++; /* sum time */
2810 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2813 tmpbuf = srcbuf++; /* sqr time */
2814 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2817 tmpbuf = srcbuf++; /* min time */
2818 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2821 tmpbuf = srcbuf++; /* max time */
2822 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2825 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* sum bytes */
2828 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* min bytes */
2831 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* max bytes */
2834 for (j = 0; j < AFS_STATS_NUM_XFER_BUCKETS; j++) {
2835 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* bucket[j] */
2841 /*printf("Ending index value = %d\n",idx-1); */
2843 /* copy CM operations timings */
2845 srcbuf = (afs_int32 *) (fullP->rpc.cmRPCTimes);
2846 for (i = 0; i < AFS_STATS_NUM_CM_RPC_OPS; i++) {
2847 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* numOps */
2850 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* numSuccesses */
2853 tmpbuf = srcbuf++; /* sum time */
2854 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2857 tmpbuf = srcbuf++; /* sqr time */
2858 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2861 tmpbuf = srcbuf++; /* min time */
2862 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2865 tmpbuf = srcbuf++; /* max time */
2866 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2871 /*printf("Ending index value = %d\n",idx-1); */
2873 /* copy authentication info */
2875 srcbuf = (afs_int32 *) & (fullP->authent);
2876 numLongs = sizeof(struct afs_stats_AuthentInfo) / sizeof(afs_int32);
2877 for (i = 0; i < numLongs; i++) {
2878 sprintf(a_cmData->data[idx], "%d", *srcbuf);
2883 /*printf("Ending index value = %d\n",idx-1); */
2885 /* copy CM [un]replicated access info */
2887 srcbuf = (afs_int32 *) & (fullP->accessinf);
2888 numLongs = sizeof(struct afs_stats_AccessInfo) / sizeof(afs_int32);
2889 for (i = 0; i < numLongs; i++) {
2890 sprintf(a_cmData->data[idx], "%d", *srcbuf);
2895 /*printf("Ending index value = %d\n",idx-1); */
2898 } /* cm_Results_ltoa */
2901 /*-----------------------------------------------------------------------
2902 * Function: check_cm_thresholds()
2905 * Checks the thresholds and sets the overflow flag. Recall that the
2906 * thresholds for each host are stored in the hostEntry lists
2907 * [fs/cm]nameList arrays. The probe results are passed to this
2908 * function in the display-ready format - ie., as strings. Though
2909 * this looks stupid the overhead incurred in converting the strings
2910 * back to floats and comparing them is insignificant and
2911 * programming is easier this way.
2912 * The threshold flags are a part of the display structures
2917 *----------------------------------------------------------------------*/
2920 check_cm_thresholds(struct afsmon_hostEntry *a_hostEntry, /* ptr to hostEntry */
2921 struct cm_Display_Data *a_Data) /* ptr to cm data to be displayed */
2922 { /* check_cm_thresholds */
2924 static char rn[] = "check_cm_thresholds";
2925 struct Threshold *threshP;
2926 double tValue; /* threshold value */
2927 double pValue; /* probe value */
2930 int count; /* number of thresholds exceeded */
2933 fprintf(debugFD, "[ %s ] Called, a_hostEntry= %p, a_Data= %p\n", rn,
2934 a_hostEntry, a_Data);
2938 if (a_hostEntry->numThresh == 0) {
2939 /* store in ovf count ?? */
2944 threshP = a_hostEntry->thresh;
2945 for (i = 0; i < a_hostEntry->numThresh; i++) {
2946 if (threshP->itemName[0] == '\0') {
2950 idx = threshP->index; /* positional index to the data array */
2951 tValue = atof(threshP->threshVal); /* threshold value */
2952 pValue = atof(a_Data->data[idx]); /* probe value */
2953 if (pValue > tValue) {
2957 "[ %s ] cm = %s, thresh ovf for %s, threshold= %s, probevalue= %s\n",
2958 rn, a_hostEntry->hostName, threshP->itemName,
2959 threshP->threshVal, a_Data->data[idx]);
2963 /* if the threshold is crossed, call the handler function
2964 * only if this was a transition -ie, if the threshold was
2965 * crossed in the last probe too just count & keep quite! */
2967 if (!a_Data->threshOvf[idx]) {
2968 a_Data->threshOvf[idx] = 1;
2969 /* call the threshold handler if provided */
2970 if (threshP->handler[0] != '\0') {
2972 fprintf(debugFD, "[ %s ] Calling ovf handler %s\n",
2973 rn, threshP->handler);
2976 execute_thresh_handler(threshP->handler, a_Data->hostName,
2977 CM, threshP->itemName,
2985 /* in case threshold was previously crossed, blank it out */
2986 a_Data->threshOvf[idx] = 0;
2989 /* store the overflow count */
2990 a_Data->ovfCount = count;
2993 } /* check_cm_thresholds */
2996 /*-----------------------------------------------------------------------
2997 * save_CM_data_forDisplay()
3000 * Does the following:
3001 * - if the probe number changed (ie, a cycle completed) curr_cmData
3002 * is copied to prev_cmData, curr_cmData zeroed and refresh the
3003 * overview screen and file server screen with the new data.
3004 * - store the results of the current probe from xstat_cm_Results into
3005 * curr_cmData. ie., convert longs to strings.
3006 * - check the thresholds
3010 * Failure: Exits afsmonitor.
3012 *----------------------------------------------------------------------*/
3015 save_CM_data_forDisplay(struct xstat_cm_ProbeResults *a_cmResults)
3016 { /* save_CM_data_forDisplay */
3018 static char rn[] = "save_CM_data_forDisplay"; /* routine name */
3019 struct cm_Display_Data *curr_cmDataP;
3020 struct cm_Display_Data *prev_cmDataP;
3021 struct afsmon_hostEntry *curr_host;
3022 static int results_Received = 0; /* number of probes reveived in
3023 * the current cycle. If this is equal to numFS we got all
3024 * the data we want in this cycle and can now display it */
3032 fprintf(debugFD, "[ %s ] Called, a_cmResults= %p\n", rn, a_cmResults);
3036 /* store results in the display array */
3039 curr_cmDataP = curr_cmData;
3040 for (i = 0; i < numCM; i++) {
3041 if ((strcasecmp(curr_cmDataP->hostName, a_cmResults->connP->hostName))
3051 "[ %s ] Could not insert CM probe results for host %s in cm display array\n",
3052 rn, a_cmResults->connP->hostName);
3056 /* Check the status of the probe. If it succeeded, we store its
3057 * results in the display data structure. If it failed we only mark
3058 * the failed status in the display data structure. */
3061 if (a_cmResults->probeOK) { /* 1 => notOK the xstat results */
3062 curr_cmDataP->probeOK = 0;
3064 /* print the probe status */
3066 fprintf(debugFD, "\n\t\t ----- cm display data ------\n");
3067 fprintf(debugFD, "HostName = %s PROBE FAILED \n",
3068 curr_cmDataP->hostName);
3072 } else { /* probe succeeded, update display data structures */
3073 curr_cmDataP->probeOK = 1;
3076 /* covert longs to strings and place them in curr_cmDataP */
3077 cm_Results_ltoa(curr_cmDataP, a_cmResults);
3079 /* compare with thresholds and set the overflow flags.
3080 * note that the threshold information is in the hostEntry structure and
3081 * each threshold item has a positional index associated with it */
3083 /* locate the hostEntry for this host */
3085 curr_host = CMnameList;
3086 for (i = 0; i < numCM; i++) {
3087 if (strcasecmp(curr_host->hostName, a_cmResults->connP->hostName)
3092 curr_host = curr_host->next;
3097 code = check_cm_thresholds(curr_host, curr_cmDataP);
3099 fprintf(stderr, "[ %s ] Error in checking thresholds\n", rn);
3103 /* print the info we just saved */
3105 fprintf(debugFD, "\n\t\t ----- CM display data ------\n");
3106 fprintf(debugFD, "HostName = %s\n", curr_cmDataP->hostName);
3107 for (i = 0; i < NUM_CM_STAT_ENTRIES; i++) {
3110 fprintf(debugFD, "\t -- Overall Perf Info --\n");
3114 "\t -- File Server up/down stats - same cell --\n");
3118 "\t -- File Server up/down stats - diff cell --\n");
3122 "\t -- VL server up/down stats - same cell --\n");
3126 "\t -- VL server up/down stats - diff cell --\n");
3129 fprintf(debugFD, "\t -- FS Operation Timings --\n");
3132 fprintf(debugFD, "\t -- FS Error Info --\n");
3135 fprintf(debugFD, "\t -- FS Transfer Timings --\n");
3138 fprintf(debugFD, "\t -- CM Operations Timings --\n");
3141 fprintf(debugFD, "\t -- Authentication Info --\n");
3144 fprintf(debugFD, "\t -- Access Info --\n");
3150 fprintf(debugFD, "%20s %30s %s\n", curr_cmDataP->data[i],
3152 curr_cmDataP->threshOvf[i] ? "(ovf)" : "");
3154 fprintf(debugFD, "\t\t--------------------------------\n\n");
3157 } /* if the probe succeeded, update the display data structures */
3159 /* if we have received a reply from all the hosts for this probe cycle,
3160 * it is time to display the data */
3163 if (results_Received == numCM * num_cm_collections) {
3164 results_Received = 0;
3166 if (afsmon_cm_curr_probeNum != afsmon_cm_prev_probeNum + 1) {
3167 sprintf(errMsg, "[ %s ] Probe number %d missed! \n", rn,
3168 afsmon_cm_prev_probeNum + 1);
3171 afsmon_cm_prev_probeNum++;
3174 /* backup the display data of the probe cycle that just completed -
3175 * ie., store curr_cmData in prev_cmData */
3177 memcpy((char *)prev_cmData, (char *)curr_cmData,
3178 (numCM * sizeof(struct cm_Display_Data)));
3181 /* initialize curr_cmData but retain the threshold flag information.
3182 * The previous state of threshold flags is used in check_cm_thresholds() */
3184 curr_cmDataP = curr_cmData;
3185 numBytes = NUM_CM_STAT_ENTRIES * CM_STAT_STRING_LEN;
3186 for (i = 0; i < numCM; i++) {
3187 curr_cmDataP->probeOK = 0;
3188 curr_cmDataP->ovfCount = 0;
3189 memset(curr_cmDataP->data, 0, numBytes);
3193 /* prev_cmData now contains all the information for the probe cycle
3194 * that just completed. Now count the number of threshold overflows for
3195 * use in the overview screen */
3197 prev_cmDataP = prev_cmData;
3199 numHosts_oncm_alerts = 0;
3200 for (i = 0; i < numCM; i++) {
3201 if (!prev_cmDataP->probeOK) { /* if probe failed */
3203 numHosts_oncm_alerts++;
3204 } else if (prev_cmDataP->ovfCount) { /* overflows ?? */
3205 num_cm_alerts += prev_cmDataP->ovfCount;
3206 numHosts_oncm_alerts++;
3211 fprintf(debugFD, "Number of CM alerts = %d (on %d hosts)\n",
3212 num_cm_alerts, numHosts_oncm_alerts);
3215 /* flag that the data is now ready to be displayed */
3216 cm_Data_Available = 1;
3218 /* update the Overview frame (only CM info) */
3219 ovw_refresh(ovw_currPage, OVW_UPDATE_CM);
3221 /* update the Cache Managers frame */
3222 cm_refresh(cm_currPage, cm_curr_LCol);
3228 } /* save_CM_data_forDisplay */
3232 /*-----------------------------------------------------------------------
3233 * afsmon_CM_Handler()
3236 * This is the Cache Manager probe Handler. It updates the afsmonitor
3237 * probe counts, cm circular buffer indices and calls the functions
3238 * to process the results of this probe.
3242 * Failure: Exits afsmonitor.
3243 *----------------------------------------------------------------------*/
3246 afsmon_CM_Handler(void)
3247 { /* afsmon_CM_Handler() */
3248 static char rn[] = "afsmon_CM_Handler"; /* routine name */
3249 int code; /* return status */
3250 int newProbeCycle; /* start of new probe cycle ? */
3254 "[ %s ] Called, hostName= %s, probeNum= %d, status= %s\n", rn,
3255 xstat_cm_Results.connP->hostName, xstat_cm_Results.probeNum,
3256 xstat_cm_Results.probeOK ? "FAILED" : "OK");
3261 /* print the probe results to output file */
3262 if (afsmon_output) {
3263 code = afsmon_cmOutput(output_filename, afsmon_detOutput);
3266 "[ %s ] output to file %s returned error code=%d\n", rn,
3267 output_filename, code);
3271 /* Update current probe number and circular buffer index. if current
3272 * probenum changed make sure it is only by 1 */
3275 if (xstat_cm_Results.probeNum != afsmon_cm_curr_probeNum) {
3276 if (xstat_cm_Results.probeNum == afsmon_cm_curr_probeNum + 1) {
3277 afsmon_cm_curr_probeNum++;
3280 afsmon_cm_curr_CBindex =
3281 (afsmon_cm_curr_probeNum - 1) % num_bufSlots;
3283 fprintf(stderr, "[ %s ] probe number %d-1 missed\n", rn,
3284 xstat_cm_Results.probeNum);
3289 /* save the results of this probe in the CM buffer */
3291 save_CM_results_inCB(newProbeCycle);
3293 /* store the results of the current probe in the cm data display structure.
3294 * if the current probe number changed, swap the current and previous display
3295 * structures. note that the display screen is updated from these structures
3296 * and should start showing the data of the just completed probe cycle */
3298 save_CM_data_forDisplay(&xstat_cm_Results);
3303 /*-----------------------------------------------------------------------
3307 * Allocate and Initialize circular buffers for file servers.
3311 * Failure to allocate memory: exits afsmonitor.
3312 *----------------------------------------------------------------------*/
3315 init_fs_buffers(void)
3316 { /* init_fs_buffers() */
3317 static char rn[] = "init_fs_buffers"; /* routine name */
3318 struct afsmon_fs_Results_list *new_fslist_item; /* ptr for new struct */
3319 struct afsmon_fs_Results_list *tmp_fslist_item; /* temp ptr */
3320 struct xstat_fs_ProbeResults *new_fsPR; /* ptr for new struct */
3327 fprintf(debugFD, "[ %s ] Called\n", rn);
3331 /* allocate memory for the circular buffer of pointers */
3333 afsmon_fs_ResultsCB = (struct afsmon_fs_Results_CBuffer *)
3334 malloc(sizeof(struct afsmon_fs_Results_CBuffer) * num_bufSlots);
3336 /* initialize the fs circular buffer */
3337 for (i = 0; i < num_bufSlots; i++) {
3338 afsmon_fs_ResultsCB[i].list = (struct afsmon_fs_Results_list *)0;
3339 afsmon_fs_ResultsCB[i].probeNum = 0;
3342 /* create a list of numFS items to store fs probe results for
3343 * each slot in CB */
3345 if (numFS) { /* if we have file servers to monitor */
3346 for (bufslot = 0; bufslot < num_bufSlots; bufslot++) {
3347 numfs = numFS; /* get the number of servers */
3350 /* if any of these mallocs fail we only need to free the memory we
3351 * have allocated in this iteration. the rest of it which is in a
3352 * proper linked list will be freed in afsmon_Exit */
3354 /* allocate memory for an fs list item */
3355 new_fslist_item = (struct afsmon_fs_Results_list *)
3356 malloc(sizeof(struct afsmon_fs_Results_list));
3357 if (new_fslist_item == (struct afsmon_fs_Results_list *)0)
3360 for (i = 0; i < MAX_NUM_FS_COLLECTIONS; i++) {
3361 /* allocate memory to store xstat_fs_Results */
3362 new_fsPR = (struct xstat_fs_ProbeResults *)
3363 malloc(sizeof(struct xstat_fs_ProbeResults));
3365 free(new_fslist_item);
3369 new_fsPR->connP = (struct xstat_fs_ConnectionInfo *)
3370 malloc(sizeof(struct xstat_fs_ConnectionInfo));
3371 if (new_fsPR->connP == (struct xstat_fs_ConnectionInfo *)0) {
3372 free(new_fslist_item);
3377 /* >>> need to allocate rx connection info structure here <<< */
3378 new_fsPR->data.AFS_CollData_val = (afs_int32 *)
3379 malloc(afsmon_fs_results_length[i] * sizeof(afs_int32));
3380 if (new_fsPR->data.AFS_CollData_val == NULL) {
3381 free(new_fslist_item);
3382 free(new_fsPR->connP);
3386 new_fslist_item->fsResults[i] = new_fsPR;
3387 new_fslist_item->empty[i] = 1;
3390 /* initialize this list entry */
3391 new_fslist_item->next = (struct afsmon_fs_Results_list *)0;
3393 /* store it at the end of the fs list in the current CB slot */
3394 if (afsmon_fs_ResultsCB[bufslot].list ==
3395 (struct afsmon_fs_Results_list *)0)
3396 afsmon_fs_ResultsCB[bufslot].list = new_fslist_item;
3398 tmp_fslist_item = afsmon_fs_ResultsCB[bufslot].list;
3400 while (tmp_fslist_item !=
3401 (struct afsmon_fs_Results_list *)0) {
3402 if (tmp_fslist_item->next ==
3403 (struct afsmon_fs_Results_list *)0)
3405 tmp_fslist_item = tmp_fslist_item->next;
3407 /* something goofed. exit */
3408 fprintf(stderr, "[ %s ] list creation error\n",
3413 tmp_fslist_item->next = new_fslist_item;
3416 } /* while servers */
3417 } /* for each buffer slot */
3418 } /* if we have file servers to monitor */
3422 /*-----------------------------------------------------------------------
3426 * Allocate and Initialize circular buffers for cache managers.
3430 * Failure to allocate memory: exits afsmonitor.
3431 *----------------------------------------------------------------------*/
3434 init_cm_buffers(void)
3435 { /* init_cm_buffers() */
3436 static char rn[] = "init_cm_buffers"; /* routine name */
3437 struct afsmon_cm_Results_list *new_cmlist_item; /* ptr for new struct */
3438 struct afsmon_cm_Results_list *tmp_cmlist_item; /* temp ptr */
3439 struct xstat_cm_ProbeResults *new_cmPR; /* ptr for new struct */
3445 fprintf(debugFD, "[ %s ] Called\n", rn);
3449 /* allocate memory for the circular buffer of pointers */
3450 afsmon_cm_ResultsCB = (struct afsmon_cm_Results_CBuffer *)
3451 malloc(sizeof(struct afsmon_cm_Results_CBuffer) * num_bufSlots);
3453 /* initialize the fs circular buffer */
3454 for (i = 0; i < num_bufSlots; i++) {
3455 afsmon_cm_ResultsCB[i].list = (struct afsmon_cm_Results_list *)0;
3456 afsmon_cm_ResultsCB[i].probeNum = 0;
3459 /* create a list of numCM items to store fs probe results for
3460 * each slot in CB */
3462 if (numCM) { /* if we have file servers to monitor */
3463 for (bufslot = 0; bufslot < num_bufSlots; bufslot++) {
3464 numcm = numCM; /* get the number of servers */
3467 /* if any of these mallocs fail we only need to free the memory we
3468 * have allocated in this iteration. the rest of it which is in a
3469 * proper linked list will be freed in afsmon_Exit */
3471 /* allocate memory for an fs list item */
3472 new_cmlist_item = (struct afsmon_cm_Results_list *)
3473 malloc(sizeof(struct afsmon_cm_Results_list));
3474 if (new_cmlist_item == (struct afsmon_cm_Results_list *)0)
3477 for (i = 0; i < MAX_NUM_CM_COLLECTIONS; i++) {
3478 /* allocate memory to store xstat_cm_Results */
3479 new_cmPR = (struct xstat_cm_ProbeResults *)
3480 malloc(sizeof(struct xstat_cm_ProbeResults));
3482 free(new_cmlist_item);
3485 new_cmPR->connP = (struct xstat_cm_ConnectionInfo *)
3486 malloc(sizeof(struct xstat_cm_ConnectionInfo));
3487 if (!new_cmPR->connP) {
3488 free(new_cmlist_item);
3493 /* >>> need to allocate rx connection info structure here <<< */
3495 new_cmPR->data.AFSCB_CollData_val =
3496 malloc(XSTAT_CM_FULLPERF_RESULTS_LEN
3497 *sizeof(afs_int32));
3498 if (new_cmPR->data.AFSCB_CollData_val == NULL) {
3499 free(new_cmlist_item);
3500 free(new_cmPR->connP);
3505 new_cmlist_item->cmResults[i] = new_cmPR;
3506 new_cmlist_item->empty[i] = 1;
3509 /* initialize this list entry */
3510 new_cmlist_item->next = (struct afsmon_cm_Results_list *)0;
3512 /* store it at the end of the cm list in the current CB slot */
3513 if (afsmon_cm_ResultsCB[bufslot].list ==
3514 (struct afsmon_cm_Results_list *)0)
3515 afsmon_cm_ResultsCB[bufslot].list = new_cmlist_item;
3517 tmp_cmlist_item = afsmon_cm_ResultsCB[bufslot].list;
3519 while (tmp_cmlist_item !=
3520 (struct afsmon_cm_Results_list *)0) {
3521 if (tmp_cmlist_item->next ==
3522 (struct afsmon_cm_Results_list *)0)
3524 tmp_cmlist_item = tmp_cmlist_item->next;
3526 /* something goofed. exit */
3527 fprintf(stderr, "[ %s ] list creation error\n",
3532 tmp_cmlist_item->next = new_cmlist_item;
3535 } /* while servers */
3536 } /* for each buffer slot */
3538 /* if we have file servers to monitor */
3539 /* print the CB to make sure it is right */
3543 } /* init_cm_buffers() */
3546 /*-------------------------------------------------------------------------
3547 * init_print_buffers()
3550 * Allocate and initialize the buffers used for printing results
3551 * to the display screen. These buffers store the current and
3552 * previous probe results in ascii format.
3557 *------------------------------------------------------------------------*/
3560 init_print_buffers(void)
3561 { /* init_print_buffers */
3563 static char rn[] = "init_print_buffers"; /* routine name */
3564 struct fs_Display_Data *tmp_fsData1; /* temp pointers */
3565 struct fs_Display_Data *tmp_fsData2;
3566 struct cm_Display_Data *tmp_cmData1;
3567 struct cm_Display_Data *tmp_cmData2;
3568 struct afsmon_hostEntry *tmp_fsNames;
3569 struct afsmon_hostEntry *tmp_cmNames;
3574 fprintf(debugFD, "[ %s ] Called\n", rn);
3578 /* allocate numFS blocks of the FS print structure. */
3580 /* we need two instances of this structure - one (curr_fsData) for storing
3581 * the results of the fs probes currently in progress and another (prev_fsData)
3582 * for the last completed probe. The display is updated from the contents of
3583 * prev_fsData. The pointers curr_fsData & prev_fsData are switched whenever
3584 * the probe number changes */
3587 numBytes = numFS * sizeof(struct fs_Display_Data);
3588 curr_fsData = malloc(numBytes);
3589 if (curr_fsData == (struct fs_Display_Data *)0) {
3590 fprintf(stderr, "[ %s ] Memory allocation failure\n", rn);
3593 memset(curr_fsData, 0, numBytes);
3595 numBytes = numFS * sizeof(struct fs_Display_Data);
3596 prev_fsData = malloc(numBytes);
3597 if (prev_fsData == (struct fs_Display_Data *)0) {
3598 fprintf(stderr, "[ %s ] Memory allocation failure\n", rn);
3601 memset(prev_fsData, 0, numBytes);
3603 /* fill in the host names */
3604 tmp_fsData1 = curr_fsData;
3605 tmp_fsData2 = curr_fsData;
3606 tmp_fsNames = FSnameList;
3607 for (i = 0; i < numFS; i++) {
3608 strncpy(tmp_fsData1->hostName, tmp_fsNames->hostName,
3610 strncpy(tmp_fsData2->hostName, tmp_fsNames->hostName,
3614 tmp_fsNames = tmp_fsNames->next;;
3619 /* if file servers to monitor */
3620 /* allocate numCM blocks of the CM print structure */
3621 /* we need two instances of this structure for the same reasons as above */
3623 numBytes = numCM * sizeof(struct cm_Display_Data);
3625 curr_cmData = malloc(numBytes);
3626 if (curr_cmData == (struct cm_Display_Data *)0) {
3627 fprintf(stderr, "[ %s ] Memory allocation failure\n", rn);
3630 memset(curr_cmData, 0, numBytes);
3632 numBytes = numCM * sizeof(struct cm_Display_Data);
3633 prev_cmData = malloc(numBytes);
3634 if (prev_cmData == (struct cm_Display_Data *)0) {
3635 fprintf(stderr, "[ %s ] Memory allocation failure\n", rn);
3638 memset(prev_cmData, 0, numBytes);
3640 /* fill in the host names */
3641 tmp_cmData1 = curr_cmData;
3642 tmp_cmData2 = curr_cmData;
3643 tmp_cmNames = CMnameList;
3644 for (i = 0; i < numCM; i++) {
3645 strncpy(tmp_cmData1->hostName, tmp_cmNames->hostName,
3647 strncpy(tmp_cmData2->hostName, tmp_cmNames->hostName,
3651 tmp_cmNames = tmp_cmNames->next;;
3655 /* if cache managers to monitor */
3658 } /* init_print_buffers */
3660 /*-----------------------------------------------------------------------
3664 * Trap the interrupt signal. This function is useful only until
3665 * gtx is initialized.
3666 *----------------------------------------------------------------------*/
3669 quit_signal(int sig)
3671 fprintf(stderr, "Received signal %d \n", sig);
3677 /*-----------------------------------------------------------------------
3681 * This is where we start it all. Initialize an array of sockets for
3682 * file servers and cache cache managers and call the xstat_[fs/cm]_Init
3683 * routines. The last step is to call the gtx input server which
3684 * grabs control of the keyboard.
3687 * Does not return. Control is periodically returned to the afsmonitor
3688 * thru afsmon_[FS/CM]_Handler() routines and also through the gtx
3689 * keyboard handler calls.
3691 *----------------------------------------------------------------------*/
3694 afsmon_execute(void)
3695 { /* afsmon_execute() */
3696 static char rn[] = "afsmon_execute"; /* routine name */
3697 static char fullhostname[128]; /* full host name */
3698 struct sockaddr_in *FSSktArray; /* fs socket array */
3699 int FSsktbytes; /* num bytes in above */
3700 struct sockaddr_in *CMSktArray; /* cm socket array */
3701 int CMsktbytes; /* num bytes in above */
3702 struct sockaddr_in *curr_skt; /* ptr to current socket */
3703 struct afsmon_hostEntry *curr_FS; /* ptr to FS name list */
3704 struct afsmon_hostEntry *curr_CM; /* ptr to CM name list */
3705 struct hostent *he; /* host entry */
3706 int FSinitFlags = 0; /* flags for xstat_fs_Init */
3707 int CMinitFlags = 0; /* flags for xstat_cm_Init */
3708 int code; /* function return code */
3709 struct timeval tv; /* time structure */
3714 fprintf(debugFD, "[ %s ] Called\n", rn);
3719 /* process file server entries */
3721 afs_int32 collIDs[MAX_NUM_FS_COLLECTIONS];
3723 /* Allocate an array of sockets for each fileserver we monitor */
3725 FSsktbytes = numFS * sizeof(struct sockaddr_in);
3726 FSSktArray = malloc(FSsktbytes);
3727 if (FSSktArray == (struct sockaddr_in *)0) {
3729 "[ %s ] cannot malloc %d sockaddr_ins for fileservers\n",
3734 memset(FSSktArray, 0, FSsktbytes);
3736 /* Fill in the socket information for each fileserve */
3738 curr_skt = FSSktArray;
3739 curr_FS = FSnameList; /* FS name list header */
3741 strncpy(fullhostname, curr_FS->hostName, sizeof(fullhostname));
3742 he = GetHostByName(fullhostname);
3744 fprintf(stderr, "[ %s ] Cannot get host info for %s\n", rn,
3748 strncpy(curr_FS->hostName, he->h_name, HOST_NAME_LEN); /* complete name */
3749 memcpy(&(curr_skt->sin_addr.s_addr), he->h_addr, 4);
3750 curr_skt->sin_family = AF_INET; /*Internet family */
3751 curr_skt->sin_port = htons(7000); /*FileServer port */
3752 #ifdef STRUCT_SOCKADDR_HAS_SA_LEN
3753 curr_skt->sin_len = sizeof(struct sockaddr_in);
3756 /* get the next dude */
3758 curr_FS = curr_FS->next;
3761 /* Initialize collection IDs, depending on the data requested. */
3762 num_fs_collections = 0;
3763 for (i = 0; i < fs_DisplayItems_count; i++) {
3764 index = fs_Display_map[i];
3765 if (FS_FULLPERF_ENTRY_START <= index && index <= FS_FULLPERF_ENTRY_END) {
3766 collIDs[num_fs_collections++] = AFS_XSTATSCOLL_FULL_PERF_INFO;
3770 for (i = 0; i < fs_DisplayItems_count; i++) {
3771 index = fs_Display_map[i];
3772 if (FS_CB_ENTRY_START <= index && index <= FS_CB_ENTRY_END) {
3773 collIDs[num_fs_collections++] = AFS_XSTATSCOLL_CBSTATS;
3779 if (afsmon_onceOnly) /* option not provided at this time */
3780 FSinitFlags |= XSTAT_FS_INITFLAG_ONE_SHOT;
3783 fprintf(debugFD, "[ %s ] Calling xstat_fs_Init \n", rn);
3787 code = xstat_fs_Init(numFS, /*Num servers */
3788 FSSktArray, /*File Server socket array */
3789 afsmon_probefreq, /*probe frequency */
3790 afsmon_FS_Handler, /*Handler routine */
3791 FSinitFlags, /*Initialization flags */
3792 num_fs_collections, /*Number of collection IDs */
3793 collIDs); /*Ptr to collection ID */
3796 fprintf(stderr, "[ %s ] xstat_fs_init returned error\n", rn);
3803 /* end of process fileserver entries */
3804 /* process cache manager entries */
3806 afs_int32 collIDs[MAX_NUM_CM_COLLECTIONS];
3808 /* Allocate an array of sockets for each cache manager we monitor */
3810 CMsktbytes = numCM * sizeof(struct sockaddr_in);
3811 CMSktArray = malloc(CMsktbytes);
3812 if (CMSktArray == (struct sockaddr_in *)0) {
3814 "[ %s ] cannot malloc %d sockaddr_ins for CM entries\n",
3819 memset(CMSktArray, 0, CMsktbytes);
3821 /* Fill in the socket information for each CM */
3823 curr_skt = CMSktArray;
3824 curr_CM = CMnameList; /* CM name list header */
3826 strncpy(fullhostname, curr_CM->hostName, sizeof(fullhostname));
3827 he = GetHostByName(fullhostname);
3829 fprintf(stderr, "[ %s ] Cannot get host info for %s\n", rn,
3833 strncpy(curr_CM->hostName, he->h_name, HOST_NAME_LEN); /* complete name */
3834 memcpy(&(curr_skt->sin_addr.s_addr), he->h_addr, 4);
3835 curr_skt->sin_family = AF_INET;
3836 curr_skt->sin_port = htons(7001); /* Cache Manager port */
3837 #ifdef STRUCT_SOCKADDR_HAS_SA_LEN
3838 curr_skt->sin_len = sizeof(struct sockaddr_in);
3841 /* get the next dude */
3843 curr_CM = curr_CM->next;
3846 /* initialize collection IDs. We need only one entry since we collect
3847 * all the information from xstat */
3848 num_cm_collections = 0;
3849 collIDs[num_cm_collections++] = AFSCB_XSTATSCOLL_FULL_PERF_INFO;
3852 if (afsmon_onceOnly) /* once only ? */
3853 CMinitFlags |= XSTAT_CM_INITFLAG_ONE_SHOT;
3856 fprintf(debugFD, "[ %s ] Calling xstat_cm_Init \n", rn);
3860 code = xstat_cm_Init(numCM, /*Num servers */
3861 CMSktArray, /*Cache Manager socket array */
3862 afsmon_probefreq, /*probe frequency */
3863 afsmon_CM_Handler, /*Handler routine */
3864 CMinitFlags, /*Initialization flags */
3865 num_cm_collections, /*Number of collection IDs */
3866 collIDs); /*Ptr to collection ID */
3869 fprintf(stderr, "[ %s ] xstat_cm_init returned error\n", rn);
3876 /* end of process cache manager entries */
3877 /* if only one probe was required setup a waiting process for the
3878 * termination signal */
3879 if (afsmon_onceOnly) {
3880 code = LWP_WaitProcess(&terminationEvent);
3883 fprintf(debugFD, "LWP_WaitProcess() returned error %d\n",
3891 /* start the gtx input server */
3892 code = (intptr_t)gtx_InputServer(afsmon_win);
3894 fprintf(stderr, "[ %s ] Failed to start input server \n", rn);
3898 /* This part of the code is reached only if the input server is not started
3899 * for debugging purposes */
3902 tv.tv_sec = 24 * 60;
3904 fprintf(stderr, "[ %s ] going to sleep ...\n", rn);
3906 code = IOMGR_Select(0, /*Num fds */
3907 0, /*Descriptors ready for reading */
3908 0, /*Descriptors ready for writing */
3909 0, /*Descriptors with exceptional conditions */
3910 &tv); /*Timeout structure */
3913 "[ %s ] IOMGR_Select() returned non-zero value %d\n", rn,
3921 /*-----------------------------------------------------------------------
3925 * Afsmonitor initialization routine.
3926 * - processes command line parameters
3927 * - call functions to:
3928 * - process config file
3929 * - initialize circular buffers and display buffers
3931 * - execute afsmonitor
3932 * - initialize the display maps [fs/cm]_Display_map[].
3935 * Success: Does not return from the call to afsmon_execute().
3936 * Failure: Exits afsmonitor.
3937 *----------------------------------------------------------------------*/
3940 afsmonInit(struct cmd_syndesc *as, void *arock)
3941 { /* afsmonInit() */
3943 static char rn[] = "afsmonInit"; /* Routine name */
3944 char *debug_filename; /* pointer to debug filename */
3945 FILE *outputFD; /* output file descriptor */
3946 struct cmd_item *hostPtr; /* ptr to parse command line args */
3947 char buf[256]; /* buffer for processing hostnames */
3952 fprintf(debugFD, "[ %s ] Called, as= %p\n", rn, as);
3956 /* Open the debug file if -debug option is specified */
3957 if (as->parms[P_DEBUG].items != 0) {
3959 debug_filename = as->parms[P_DEBUG].items->data;
3960 debugFD = fopen(debug_filename, "w");
3961 if (debugFD == (FILE *) 0) {
3962 printf("[ %s ] Failed to open debugging file %s for writing\n",
3970 fprintf(debugFD, "[ %s ] Called\n", rn);
3974 /* use curses always until we support other packages */
3976 wpkg_to_use = atoi(as->parms[P_PACKAGE].items->data);
3978 switch (wpkg_to_use) {
3979 case GATOR_WIN_CURSES:
3980 fprintf(stderr, "curses\n");
3982 case GATOR_WIN_DUMB:
3983 fprintf(stderr, "dumb terminal\n");
3986 fprintf(stderr, "X11\n");
3989 fprintf(stderr, "Illegal graphics package: %d\n", wpkg_to_use);
3991 } /*end switch (wpkg_to_use) */
3994 wpkg_to_use = GATOR_WIN_CURSES;
3996 /* get probe frequency . We check for meaningful bounds on the frequency
3997 * and reset to the default value if needed. The upper bound of 24
3998 * hours looks ridiculous though! */
4000 afsmon_probefreq = 0;
4001 if (as->parms[P_FREQUENCY].items != 0)
4002 afsmon_probefreq = atoi(as->parms[P_FREQUENCY].items->data);
4004 afsmon_probefreq = DEFAULT_FREQUENCY;
4006 if (afsmon_probefreq <= 0 || afsmon_probefreq > 24 * 60 * 60) {
4007 afsmon_probefreq = DEFAULT_FREQUENCY;
4010 "[ %s ] Invalid probe frequency %s specified, resetting to default value %d seconds\n",
4011 rn, as->parms[P_FREQUENCY].items->data, afsmon_probefreq);
4015 "Invalid probe frequency %s specified, resetting to default value %d seconds\n",
4016 as->parms[P_FREQUENCY].items->data, afsmon_probefreq);
4021 /* make sure output file is writable, else complain now */
4022 /* we will open and close it as needed after probes */
4024 if (as->parms[P_OUTPUT].items != 0) {
4025 afsmon_output = 1; /* output flag */
4026 strncpy(output_filename, as->parms[P_OUTPUT].items->data, 80);
4027 outputFD = fopen(output_filename, "a");
4028 if (outputFD == (FILE *) 0) {
4029 fprintf(stderr, "Failed to open output file %s \n",
4032 fprintf(debugFD, "[ %s ] Failed to open output file %s \n",
4033 rn, output_filename);
4038 fprintf(debugFD, "[ %s ] output file is %s\n", rn,
4044 /* detailed statistics to storage file */
4045 if (as->parms[P_DETAILED].items != 0) {
4046 if (as->parms[P_OUTPUT].items == 0) {
4048 "-detailed switch can be used only with -output\n");
4051 afsmon_detOutput = 1;
4054 /* Initialize host list headers */
4055 FSnameList = (struct afsmon_hostEntry *)0;
4056 CMnameList = (struct afsmon_hostEntry *)0;
4058 /* The -config option is mutually exclusive with the -fshosts,-cmhosts
4061 if (as->parms[P_CONFIG].items) {
4062 if (as->parms[P_FSHOSTS].items || as->parms[P_CMHOSTS].items) {
4064 "Cannot use -config option with -fshosts or -cmhosts\n");
4068 if (!as->parms[P_FSHOSTS].items && !as->parms[P_CMHOSTS].items) {
4070 "Must specify either -config or (-fshosts and/or -cmhosts) options \n");
4076 /* If a file server host is specified on the command line we reuse
4077 * parse_hostEntry() function . Just the pass the info as if it were
4078 * read off the config file */
4080 if (as->parms[P_FSHOSTS].items) {
4081 hostPtr = as->parms[P_FSHOSTS].items;
4082 while (hostPtr != (struct cmd_item *)0) {
4083 sprintf(buf, "fs %s", hostPtr->data);
4084 code = parse_hostEntry(buf);
4086 fprintf(stderr, "Could not parse %s\n", hostPtr->data);
4090 hostPtr = hostPtr->next;
4094 /* same as above for -cmhosts */
4095 if (as->parms[P_CMHOSTS].items) {
4096 hostPtr = as->parms[P_CMHOSTS].items;
4097 while (hostPtr != (struct cmd_item *)0) {
4098 sprintf(buf, "cm %s", hostPtr->data);
4099 code = parse_hostEntry(buf);
4101 fprintf(stderr, "Could not parse %s\n", hostPtr->data);
4105 hostPtr = hostPtr->next;
4109 /* number of slots in circular buffers */
4110 if (as->parms[P_BUFFERS].items)
4111 num_bufSlots = atoi(as->parms[P_BUFFERS].items->data);
4113 num_bufSlots = DEFAULT_BUFSLOTS;
4115 /* Initialize xx_showFlags[]. This array is used solely for processing the
4116 * "show" directives in the config file in parse_showEntries() */
4117 for (i = 0; i < NUM_FS_STAT_ENTRIES; i++)
4118 fs_showFlags[i] = 0;
4119 for (i = 0; i < NUM_CM_STAT_ENTRIES; i++)
4120 cm_showFlags[i] = 0;
4123 /* Process the configuration file if given. This initializes among other
4124 * things, the list of FS & CM names in FSnameList and CMnameList */
4126 if (as->parms[P_CONFIG].items)
4127 process_config_file(as->parms[P_CONFIG].items->data);
4129 /* print out the FS and CM lists */
4133 /* Initialize the FS results-to-screen map array if there were no "show fs"
4134 * directives in the config file */
4135 if (fs_showDefault) {
4136 for (i = 0; i < NUM_FS_STAT_ENTRIES; i++)
4137 fs_Display_map[i] = i;
4138 fs_DisplayItems_count = NUM_FS_STAT_ENTRIES;
4141 /* Initialize the CM results-to-screen map array if there were no "show cm"
4142 * directives in the config file */
4143 if (cm_showDefault) {
4144 for (i = 0; i < NUM_CM_STAT_ENTRIES; i++)
4145 cm_Display_map[i] = i;
4146 cm_DisplayItems_count = NUM_CM_STAT_ENTRIES;
4151 /* setup an interrupt signal handler; we ain't wanna leak core */
4152 /* this binding is useful only until gtx is initialized after which the
4153 * keyboard input server takes over. */
4154 if ((signal(SIGINT, quit_signal)) == SIG_ERR) {
4155 perror("signal() failed.");
4160 /* init error message buffers. these will be used to print error messages
4161 * once gtx is initialized and there is no access to stderr/stdout */
4167 /* initialize fs and cm circular buffers before initiating probes */
4169 code = init_fs_buffers();
4171 fprintf(stderr, "[ %s ] init_fs_buffers returned %d\n", rn,
4178 code = init_cm_buffers();
4180 fprintf(stderr, "[ %s ] init_cm_buffers returned %d\n", rn,
4187 /* allocate and initialize buffers for holding fs & cm results in ascii
4188 * format suitable for updating the screen */
4189 code = init_print_buffers();
4191 fprintf(stderr, "[ %s ] init_print_buffers returned %d\n", rn, code);
4195 /* perform gtx initializations */
4196 code = gtx_initialize();
4198 fprintf(stderr, "[ %s ] gtx_initialize returned %d\n", rn, code);
4202 /* start xstat probes */
4205 return (0); /* will not return from the call to afsmon_execute() */
4207 } /* afsmonInit() */
4210 /*-----------------------------------------------------------------------
4212 ------------------------------------------------------------------------*/
4214 #include "AFS_component_version_number.c"
4217 main(int argc, char **argv)
4219 afs_int32 code; /*Return code */
4220 struct cmd_syndesc *ts; /*Ptr to cmd line syntax descriptor */
4222 #ifdef AFS_AIX32_ENV
4224 * The following signal action for AIX is necessary so that in case of a
4225 * crash (i.e. core is generated) we can include the user's data section
4226 * in the core dump. Unfortunately, by default, only a partial core is
4227 * generated which, in many cases, isn't too useful.
4229 struct sigaction nsa;
4231 sigemptyset(&nsa.sa_mask);
4232 nsa.sa_handler = SIG_DFL;
4233 nsa.sa_flags = SA_FULLDUMP;
4234 sigaction(SIGSEGV, &nsa, NULL);
4238 * Set up the commands we understand.
4240 ts = cmd_CreateSyntax("initcmd", afsmonInit, NULL, "initialize the program");
4241 cmd_AddParm(ts, "-config", CMD_SINGLE, CMD_OPTIONAL,
4242 "configuration file");
4243 cmd_AddParm(ts, "-frequency", CMD_SINGLE, CMD_OPTIONAL,
4244 "poll frequency, in seconds");
4245 cmd_AddParm(ts, "-output", CMD_SINGLE, CMD_OPTIONAL, "storage file name");
4246 cmd_AddParm(ts, "-detailed", CMD_FLAG, CMD_OPTIONAL,
4247 "output detailed statistics to storage file");
4249 /* we hope to use this .... eventually! */
4250 cmd_AddParm(ts, "-package", CMD_SINGLE, CMD_REQUIRED,
4251 "Graphics Package to use");
4253 cmd_AddParm(ts, "-debug", CMD_SINGLE, CMD_OPTIONAL,
4254 "turn debugging output on to the named file");
4255 cmd_AddParm(ts, "-fshosts", CMD_LIST, CMD_OPTIONAL,
4256 "list of file servers to monitor");
4257 cmd_AddParm(ts, "-cmhosts", CMD_LIST, CMD_OPTIONAL,
4258 "list of cache managers to monitor");
4259 cmd_AddParm(ts, "-buffers", CMD_SINGLE, CMD_OPTIONAL,
4260 "number of buffer slots");
4263 * Parse command-line switches & execute afsmonitor
4266 code = cmd_Dispatch(argc, argv);
4272 exit(0); /* redundant, but gets rid of warning */