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>
28 #include <afs/gtxwindows.h> /*Generic window package */
29 #include <afs/gtxobjects.h> /*Object definitions */
30 #include <afs/gtxlightobj.h> /*Light object interface */
31 #include <afs/gtxcurseswin.h> /*Curses window package */
32 #include <afs/gtxdumbwin.h> /*Dumb terminal window package */
33 #include <afs/gtxX11win.h> /*X11 window package */
34 #include <afs/gtxframe.h> /*Frame package */
35 #include <afs/gtxinput.h>
37 #include <afs/xstat_fs.h>
38 #include <afs/xstat_cm.h>
40 #include "afsmonitor.h"
42 /* command line parameter indices */
48 /* #define P_PACKAGE X */
55 int afsmon_debug = 0; /* debug info to file ? */
56 FILE *debugFD; /* debugging file descriptor */
57 static int afsmon_output = 0; /* output to file ? */
58 static int afsmon_detOutput = 0; /* detailed output ? */
59 static int afsmon_onceOnly = 0; /* probe once only ? (not implemented) */
60 int afsmon_probefreq; /* probe frequency */
61 static int wpkg_to_use; /* graphics package to use */
62 static char output_filename[80]; /* output filename */
63 char errMsg[256]; /* buffers used to print error messages after */
64 char errMsg1[256]; /* gtx is initialized (stderr/stdout gone !) */
65 int num_bufSlots = 0; /* number of slots in fs & cm circular buffers */
67 /* Flags used to process "show" directives in config file */
68 short fs_showFlags[NUM_FS_STAT_ENTRIES];
69 short cm_showFlags[NUM_CM_STAT_ENTRIES];
72 /* afsmonitor misc definitions */
74 #define DEFAULT_FREQUENCY 60 /* default proble frequency in seconds */
75 #define DEFAULT_BUFSLOTS 0 /* default number of buffer slots */
76 #define CFG_STR_LEN 80 /* max length of config file fields */
77 #define FS 1 /* for misc. use */
78 #define CM 2 /* for misc. use */
81 #define NUM_XSTAT_FS_AFS_PERFSTATS_LONGS 70 /* number of fields from struct afs_PerfStats that we display */
82 #define NUM_AFS_STATS_CMPERF_LONGS 40 /* number of longs in struct afs_stats_CMPerf excluding up/down stats and fields we dont display */
85 /* variables used for exec'ing user provided threshold handlers */
86 char *fsHandler_argv[20]; /* *argv[] for the handler */
87 char fsHandler_args[20][256]; /* buffer space for arguments */
88 int exec_fsThreshHandler = 0; /* execute fs threshold handler ? */
91 /* THRESHOLD STRUCTURE DEFINITIONS */
93 /* flag to indicate that threshold entries apply to all hosts. these will
94 be turned off when the first fs or cm host entry is processed */
95 static int global_ThreshFlag = 1;
96 static int global_fsThreshCount = 0; /* number of global fs thresholds */
97 static int global_cmThreshCount = 0; /* number of global cm thresholds */
101 /* Linked lists of file server and cache manager host names are made from
102 the entries in the config file. Head pointers to FS and CM server name lists. */
103 static struct afsmon_hostEntry *FSnameList;
104 static struct afsmon_hostEntry *CMnameList;
106 /* number of fileservers and cache managers to monitor */
110 /* number of xstat collection ids */
111 #define MAX_NUM_FS_COLLECTIONS 2
112 #define MAX_NUM_CM_COLLECTIONS 1
113 int num_fs_collections = 0;
114 int num_cm_collections = 0;
116 /* variables used for processing config file */
117 /* ptr to the hostEntry structure of the last "fs" or "cm" entry processed
118 in the config file */
119 static struct afsmon_hostEntry *last_hostEntry;
120 /* names of the last host processed in the config file */
121 static char last_fsHost[HOST_NAME_LEN];
122 static char last_cmHost[HOST_NAME_LEN];
123 static int lastHostType = 0; /* 0 = no host entries processed
124 * 1 = last host was file server
125 * 2 = last host was cache manager. */
128 /* FILE SERVER CIRCULAR BUFFER VARIABLES */
130 struct afsmon_fs_Results_list {
131 struct xstat_fs_ProbeResults *fsResults[MAX_NUM_FS_COLLECTIONS];
132 int empty[MAX_NUM_FS_COLLECTIONS];
133 struct afsmon_fs_Results_list *next;
136 struct afsmon_fs_Results_CBuffer {
137 int probeNum; /* probe number of entries in this slot */
138 struct afsmon_fs_Results_list *list; /* ptr to list of results */
141 int afsmon_fs_results_length[] =
142 { XSTAT_FS_FULLPERF_RESULTS_LEN, XSTAT_FS_CBSTATS_RESULTS_LEN };
144 /* buffer for FS probe results */
145 struct afsmon_fs_Results_CBuffer *afsmon_fs_ResultsCB;
147 int afsmon_fs_curr_CBindex = 0; /* current fs CB slot */
149 /* Probe number variables. The current probe number is incremented
150 when the first probe from a new probe cycle is received. The prev probe
151 number is incremented when the last probe of the current cycle is
152 received. This difference is because of the purpose for which these
155 int afsmon_fs_curr_probeNum = 1; /* current fs probe number */
156 int afsmon_fs_prev_probeNum = 0; /* previous fs probe number */
159 /* CACHE MANAGER CIRCULAR BUFFER VARIABLES */
161 struct afsmon_cm_Results_list {
162 struct xstat_cm_ProbeResults *cmResults[MAX_NUM_CM_COLLECTIONS];
163 int empty[MAX_NUM_CM_COLLECTIONS];
164 struct afsmon_cm_Results_list *next;
167 struct afsmon_cm_Results_CBuffer {
168 int probeNum; /* probe number of entries in this slot */
169 struct afsmon_cm_Results_list *list; /* ptr to list of results */
172 int afsmon_cm_results_length[] = { XSTAT_CM_FULLPERF_RESULTS_LEN };
174 /* buffer for CM probe results */
175 struct afsmon_cm_Results_CBuffer *afsmon_cm_ResultsCB;
177 int afsmon_cm_curr_CBindex = 0; /* current cm CB slot */
180 /* Probe number variables. The current probe number is incremented
181 when the first probe from a new probe cycle is received. The prev probe
182 number is incremented when the last probe of the current cycle is
183 received. This difference is because of the purpose for which these
186 int afsmon_cm_curr_probeNum = 1; /* current cm probe number */
187 int afsmon_cm_prev_probeNum = 0; /* previous cm probe number */
190 /* Structures to hold FS & CM results in string format(suitable for display ) */
192 /* ptr to array holding the results of FS probes in ascii format */
193 /* for current probe cycle */
194 struct fs_Display_Data *curr_fsData = (struct fs_Display_Data *)0;
195 /* for previous probe cycle */
196 struct fs_Display_Data *prev_fsData = (struct fs_Display_Data *)0;
199 /* ptr to array holding the results of CM probes in ascii format */
200 /* for current probe cycle */
201 struct cm_Display_Data *curr_cmData = (struct cm_Display_Data *)0;
202 /* for previous probe cycle */
203 struct cm_Display_Data *prev_cmData = (struct cm_Display_Data *)0;
205 /* EXTERN DEFINITIONS */
207 /* file server and cache manager variable names (from afsmon_labels.h) */
208 extern char *fs_varNames[];
209 extern char *cm_varNames[];
211 /* GTX & MISC VARIABLES */
213 /* afsmonitor window */
214 extern struct gwin *afsmon_win;
216 /* current page number in the overview frame */
217 extern int ovw_currPage;
219 /* number of FS alerts and number of hosts on FS alerts */
221 int numHosts_onfs_alerts;
223 /* number of CM alerts and number of hosts on FS alerts */
225 int numHosts_oncm_alerts;
227 /* flag to indicate that atleast one probe cycle has completed and
228 data is available for updating the display */
229 extern int fs_Data_Available;
230 extern int cm_Data_Available;
232 extern int gtx_initialized; /* gtx initialized ? */
234 /* This array contains the indices of the file server data items that
235 are to be displayed on the File Servers screen. For example, suppose the
236 user wishes to display only the vcache statistics then the following array
237 will contain indices 2 to 14 corresponding to the position of the
238 vcache data items in the fs_varNames[] array. If the config file contains
239 no "show fs .." directives, it will contain the indices of all the
240 items in the fs_varNames[] array */
242 short fs_Display_map[NUM_FS_STAT_ENTRIES];
243 int fs_DisplayItems_count = 0; /* number of items to display */
244 int fs_showDefault = 1; /* show all of FS data ? */
247 /* same use as above for Cache Managers */
248 short cm_Display_map[NUM_CM_STAT_ENTRIES];
249 int cm_DisplayItems_count = 0; /* number of items to display */
250 int cm_showDefault = 1; /* show all of CM data ? */
252 extern int fs_currPage; /* current page number in the File Servers frame */
253 extern int fs_curr_LCol; /* current leftmost column on display on FS frame */
255 extern int cm_currPage; /* current page number in the Cache Managers frame */
256 extern int cm_curr_LCol; /* current leftmost column on display on CM frame */
258 /* File server and Cache manager data is classified into sections &
259 groups to help the user choose what he wants displayed */
260 extern char *fs_categories[]; /* file server data category names */
261 extern char *cm_categories[]; /* cache manager data category names */
264 static int fs_FullPerfs_ltoa(struct fs_Display_Data *a_fsData,
265 struct xstat_fs_ProbeResults *a_fsResults);
266 static int fs_CallBackStats_ltoa(struct fs_Display_Data *a_fsData,
267 struct xstat_fs_ProbeResults *a_fsResults);
269 #ifdef HAVE_STRCASESTR
270 extern char * strcasestr(const char *, const char *);
273 strcasestr(): Return first occurence of pattern s2 in s1, case
276 This routine is required since I made pattern matching of the
277 config file to be case insensitive.
296 while (len1 >= len2 && len1 > 0) {
297 if ((strncasecmp(ptr, s2, len2)) == 0)
307 GetHostByName(char *name)
314 he = gethostbyname(name);
316 /* On solaris the above does not resolve hostnames to full names */
318 memcpy(ip_addr, he->h_addr, he->h_length);
319 he = gethostbyaddr(ip_addr, he->h_length, he->h_addrtype);
326 /*-----------------------------------------------------------------------
330 * Exit gracefully from the afsmonitor. Frees memory where appropriate,
331 * cleans up after gtx and closes all open file descriptors. If a user
332 * provided threshold handler is to be exec'ed then gtx cleanup is
333 * not performed and an exec() is made instead of an exit().
339 * This function is called to execute a user handler only
340 * by a child process.
342 *----------------------------------------------------------------------*/
345 afsmon_Exit(int a_exitVal) /* exit code */
347 static char rn[] = "afsmon_Exit";
348 struct afsmon_fs_Results_list *tmp_fslist;
349 struct afsmon_fs_Results_list *next_fslist;
350 struct xstat_fs_ProbeResults *tmp_xstat_fsPR;
351 struct afsmon_cm_Results_list *tmp_cmlist;
352 struct afsmon_cm_Results_list *next_cmlist;
353 struct xstat_cm_ProbeResults *tmp_xstat_cmPR;
354 struct afsmon_hostEntry *curr_hostEntry;
355 struct afsmon_hostEntry *next_hostEntry;
362 fprintf(debugFD, "[ %s ] Called with exit code %d\n", rn, a_exitVal);
366 /* get out of curses first, but not if we are here to exec a threshold
367 * handler. If we do, the screen gets messed up */
368 if (gtx_initialized && !exec_fsThreshHandler)
369 gator_cursesgwin_cleanup(afsmon_win);
371 /* print the error message buffer */
372 if (errMsg[0] != '\0')
373 fprintf(stderr, "%s", errMsg);
374 if (errMsg1[0] != '\0')
375 fprintf(stderr, "%s", errMsg1);
377 /* deallocate file server circular buffers */
378 if (numFS && num_bufSlots) {
380 fprintf(debugFD, "freeing FS circular buffers ");
384 for (bufslot = 0; bufslot < num_bufSlots; bufslot++) {
386 fprintf(debugFD, " %d) ", bufslot);
387 if (afsmon_fs_ResultsCB[bufslot].list !=
388 (struct afsmon_fs_Results_list *)0) {
389 tmp_fslist = afsmon_fs_ResultsCB[bufslot].list;
392 /* make sure we do not go astray */
396 "[ %s ] error in deallocating fs CB\n",
400 next_fslist = tmp_fslist->next;
401 for (i = 0; i < MAX_NUM_FS_COLLECTIONS; i++) {
402 tmp_xstat_fsPR = tmp_fslist->fsResults[i];
405 fprintf(debugFD, "%d ", numFS - j);
407 /* free xstat_fs_Results data */
408 free(tmp_xstat_fsPR->data.AFS_CollData_val);
409 free(tmp_xstat_fsPR->connP);
410 free(tmp_xstat_fsPR);
413 /* free the fs list item */
415 tmp_fslist = next_fslist;
417 } /* while fs list items in this slot */
418 } /* if entries in this buffer slot */
419 } /* for each fs buffer slot */
421 fprintf(debugFD, "\n");
426 /* deallocate cache manager curcular buffers */
427 if (numCM && num_bufSlots) {
429 fprintf(debugFD, "freeing CM curcular buffers ");
430 for (bufslot = 0; bufslot < num_bufSlots; bufslot++) {
432 fprintf(debugFD, " %d) ", bufslot);
433 if (afsmon_cm_ResultsCB[bufslot].list !=
434 (struct afsmon_cm_Results_list *)0) {
435 tmp_cmlist = afsmon_cm_ResultsCB[bufslot].list;
438 /* make sure we do not go astray */
442 "[ %s ] error in deallocating cm CB\n",
446 next_cmlist = tmp_cmlist->next;
447 for (i = 0; i < MAX_NUM_CM_COLLECTIONS; i++) {
448 tmp_xstat_cmPR = tmp_cmlist->cmResults[i];
451 fprintf(debugFD, "%d ", numCM - j);
452 /* make sure data is ok */
453 /* Print_cm_FullPerfInfo(tmp_xstat_cmPR); */
455 /* free xstat_cm_Results data */
456 free(tmp_xstat_cmPR->data.AFSCB_CollData_val);
457 free(tmp_xstat_cmPR->connP);
459 free(tmp_cmlist->cmResults);
461 /* free the cm list item */
463 tmp_cmlist = next_cmlist;
465 } /* while cm list items in this slot */
466 } /* if entries in this buffer slot */
467 } /* for each cm buffer slot */
469 fprintf(debugFD, "\n");
473 /* deallocate FS & CM Print buffers */
474 if (curr_fsData != NULL) {
476 fprintf(debugFD, "Deallocating FS Print Buffers .... curr");
479 if (prev_fsData != NULL) {
481 fprintf(debugFD, ", prev \n");
484 if (curr_cmData != NULL) {
486 fprintf(debugFD, "Deallocating CM Print Buffers .... curr");
489 if (prev_cmData != NULL) {
491 fprintf(debugFD, ", prev \n");
495 /* deallocate hostEntry lists */
498 fprintf(debugFD, "Deallocating FS hostEntries ..");
499 curr_hostEntry = FSnameList;
500 while (curr_hostEntry) {
501 next_hostEntry = curr_hostEntry->next;
502 if (curr_hostEntry->thresh != NULL)
503 free(curr_hostEntry->thresh);
504 free(curr_hostEntry);
505 curr_hostEntry = next_hostEntry;
508 fprintf(debugFD, "\n");
512 fprintf(debugFD, "Deallocating CM hostEntries ..");
513 curr_hostEntry = CMnameList;
514 while (curr_hostEntry) {
515 next_hostEntry = curr_hostEntry->next;
516 if (curr_hostEntry->thresh != NULL)
517 free(curr_hostEntry->thresh);
518 free(curr_hostEntry);
519 curr_hostEntry = next_hostEntry;
522 fprintf(debugFD, "\n");
525 /* close debug file */
531 if (exec_fsThreshHandler) {
532 code = execvp(fsHandler_argv[0], fsHandler_argv);
534 fprintf(stderr, "execvp() of %s returned %d, errno %d\n",
535 fsHandler_argv[0], code, errno);
543 /*-----------------------------------------------------------------------
547 * Insert a hostname in the file server names list.
552 *----------------------------------------------------------------------*/
555 insert_FS(char *a_hostName) /* name of cache manager to be inserted in list */
557 static struct afsmon_hostEntry *curr_item;
558 static struct afsmon_hostEntry *prev_item;
560 if (*a_hostName == '\0')
562 curr_item = malloc(sizeof(struct afsmon_hostEntry));
563 if (curr_item == (struct afsmon_hostEntry *)0) {
564 fprintf(stderr, "Failed to allocate space for FS nameList\n");
568 strncpy(curr_item->hostName, a_hostName, CFG_STR_LEN);
569 curr_item->next = (struct afsmon_hostEntry *)0;
570 curr_item->numThresh = 0;
571 curr_item->thresh = NULL;
573 if (FSnameList == (struct afsmon_hostEntry *)0)
574 FSnameList = curr_item;
576 prev_item->next = curr_item;
578 prev_item = curr_item;
579 /* record the address of this entry so that its threshold
580 * count can be incremented during the first pass of the config file */
581 last_hostEntry = curr_item;
586 /*-----------------------------------------------------------------------
591 * Prints the file server names linked list.
595 *----------------------------------------------------------------------*/
599 static char rn[] = "print_FS";
600 struct afsmon_hostEntry *tempFS;
601 struct Threshold *threshP;
605 fprintf(debugFD, "[ %s ] Called\n", rn);
611 fprintf(debugFD, "No of File Servers: %d\n", numFS);
614 fprintf(debugFD, "\t %s threshCount = %d\n", tempFS->hostName,
616 threshP = tempFS->thresh;
617 for (i = 0; i < tempFS->numThresh; i++, threshP++)
618 fprintf(debugFD, "\t thresh (%2d) %s %s %s\n",
619 threshP->index, threshP->itemName,
620 threshP->threshVal, threshP->handler);
621 } while ((tempFS = tempFS->next) != (struct afsmon_hostEntry *)0);
623 fprintf(debugFD, "\t\t-----End of List-----\n");
629 /*-----------------------------------------------------------------------
633 * Insert a hostname in the cache manager names list.
638 *----------------------------------------------------------------------*/
641 insert_CM(char *a_hostName) /* name of cache manager to be inserted in list */
643 static struct afsmon_hostEntry *curr_item;
644 static struct afsmon_hostEntry *prev_item;
646 if (*a_hostName == '\0')
648 curr_item = malloc(sizeof(struct afsmon_hostEntry));
649 if (curr_item == (struct afsmon_hostEntry *)0) {
650 fprintf(stderr, "Failed to allocate space for CM nameList\n");
654 strncpy(curr_item->hostName, a_hostName, CFG_STR_LEN);
655 curr_item->next = (struct afsmon_hostEntry *)0;
656 curr_item->numThresh = 0;
657 curr_item->thresh = NULL;
659 if (CMnameList == (struct afsmon_hostEntry *)0)
660 CMnameList = curr_item;
662 prev_item->next = curr_item;
664 prev_item = curr_item;
665 /* side effect. note the address of this entry so that its threshold
666 * count can be incremented during the first pass of the config file */
667 last_hostEntry = curr_item;
673 /*-----------------------------------------------------------------------
678 * Prints the cache manager names linked list.
682 *----------------------------------------------------------------------*/
686 static char rn[] = "print_CM";
687 struct afsmon_hostEntry *tempCM;
688 struct Threshold *threshP;
692 fprintf(debugFD, "[ %s ] Called\n", rn);
698 fprintf(debugFD, "No of Cache Managers: %d\n", numCM);
701 fprintf(debugFD, "\t %s threshCount = %d\n", tempCM->hostName,
703 threshP = tempCM->thresh;
704 for (i = 0; i < tempCM->numThresh; i++, threshP++)
705 fprintf(debugFD, "\t thresh (%2d) %s %s %s\n",
706 threshP->index, threshP->itemName,
707 threshP->threshVal, threshP->handler);
708 } while ((tempCM = tempCM->next) != (struct afsmon_hostEntry *)0);
710 fprintf(debugFD, "\t\t-----End of List-----\n");
717 /*-----------------------------------------------------------------------
721 * Parse the host entry line in the config file. Check the syntax,
722 * and inserts the host name in the FS ot CM linked list. Also
723 * remember if this entry was an fs or cm & the ptr to its hostEntry
724 * structure. The threshold entries in the config file are dependent
725 * on their position relative to the hostname entries. Hence it is
726 * required to remember the names of the last file server and cache
727 * manager entries that were processed.
733 *----------------------------------------------------------------------*/
736 parse_hostEntry(char *a_line)
737 { /* parse_hostEntry */
739 static char rn[] = "parse_hostEntry"; /* routine name */
740 char opcode[CFG_STR_LEN]; /* specifies type of config entry */
741 char arg1[CFG_STR_LEN]; /* hostname or qualifier (fs/cm?) */
742 char arg2[CFG_STR_LEN]; /* threshold variable */
743 char arg3[CFG_STR_LEN]; /* threshold value */
744 char arg4[CFG_STR_LEN]; /* user's handler */
745 struct hostent *he; /* host entry */
748 fprintf(debugFD, "[ %s ] Called, a_line = %s\n", rn, a_line);
758 sscanf(a_line, "%s %s %s %s %s", opcode, arg1, arg2, arg3, arg4);
759 /* syntax is "opcode hostname" */
760 if ((strlen(arg2)) != 0) {
761 fprintf(stderr, "[ %s ] Extraneous characters at end of line\n", rn);
766 he = GetHostByName(arg1);
768 fprintf(stderr, "[ %s ] Unable to resolve hostname %s\n", rn, arg1);
772 if ((strcasecmp(opcode, "fs")) == 0) {
773 /* use the complete host name to insert in the file server names list */
774 insert_FS(he->h_name);
775 /* note that last host entry in the config file was fs */
778 /* threholds are not global anymore */
779 if (global_ThreshFlag)
780 global_ThreshFlag = 0;
781 } else if ((strcasecmp(opcode, "cm")) == 0) {
782 /* use the complete host name to insert in the CM names list */
783 insert_CM(he->h_name);
784 /* last host entry in the config file was cm */
787 /* threholds are not global anymore */
788 if (global_ThreshFlag)
789 global_ThreshFlag = 0;
796 /*-----------------------------------------------------------------------
797 * parse_threshEntry()
800 * Parse the threshold entry line in the config file. This function is
801 * called in the the first pass of the config file. It checks the syntax
802 * of the config lines and verifies their positional validity - eg.,
803 * a cm threshold cannot appear after a fs hostname entry, etc.
804 * It also counts the thresholds applicable to each host.
810 *----------------------------------------------------------------------*/
813 parse_threshEntry(char *a_line)
814 { /* parse_threshEntry */
815 static char rn[] = "parse_threshEntry"; /* routine name */
816 char opcode[CFG_STR_LEN]; /* specifies type of config entry */
817 char arg1[CFG_STR_LEN]; /* hostname or qualifier (fs/cm?) */
818 char arg2[CFG_STR_LEN]; /* threshold variable */
819 char arg3[CFG_STR_LEN]; /* threshold value */
820 char arg4[CFG_STR_LEN]; /* user's handler */
821 char arg5[CFG_STR_LEN]; /* junk characters */
824 fprintf(debugFD, "[ %s ] Called, a_line = %s\n", rn, a_line);
835 sscanf(a_line, "%s %s %s %s %s %s", opcode, arg1, arg2, arg3, arg4, arg5);
837 /* syntax is "thresh fs/cm variable_name threshold_value [handler] " */
838 if (((strlen(arg1)) == 0) || ((strlen(arg2)) == 0)
839 || ((strlen(arg3)) == 0)) {
840 fprintf(stderr, "[ %s ] Incomplete line\n", rn);
843 if (strlen(arg3) > THRESH_VAR_LEN - 2) {
844 fprintf(stderr, "[%s ] threshold value too long\n", rn);
848 if ((strcasecmp(arg1, "fs")) == 0) {
849 switch (lastHostType) {
850 case 0: /* its a global threshold */
851 global_fsThreshCount++;
853 case 1: /* inc thresh count of last file server */
854 last_hostEntry->numThresh++;
858 "[ %s ] A threshold for a File Server cannot be placed after a Cache Manager host entry in the config file \n",
862 fprintf(stderr, "[ %s ] Programming error 1\n", rn);
865 } else if ((strcasecmp(arg1, "cm")) == 0) {
866 switch (lastHostType) {
867 case 0: /* its a global threshold */
868 global_cmThreshCount++;
870 case 2: /* inc thresh count of last cache manager */
871 last_hostEntry->numThresh++;
875 "[ %s ] A threshold for a Cache Manager cannot be placed after a File Server host entry in the config file \n",
879 fprintf(stderr, "[ %s ] Programming error 2\n", rn);
884 "[ %s ] Syntax error. Second argument should be \"fs\" or \"cm\" \n",
890 } /* parse_threshEntry */
893 /*-----------------------------------------------------------------------
897 * The thresholds applicable to each host machine are stored in the
898 * FSnameList and CMnameList. Threshold entries in the config file are
899 * context sensitive. The host to which this threshold is applicable
900 * is pointed to by last_fsHost (for file servers) and last_cmHost
901 * for cache managers. For global thresholds the info is recorded for
902 * all the hosts. This function is called in the second pass of the
903 * config file. In the first pass a count of the number of global
904 * thresholds is determined and this information is used in this
905 * routine. If threshold entries are duplicated the first entry is
907 * Each threshold entry also has an index field. This is a positional
908 * index to the corresponding variable in the prev_[fs/cm]Data arrays.
909 * This makes it easy to check the threshold for overflow.
914 *----------------------------------------------------------------------*/
917 store_threshold(int a_type, /* 1 = fs , 2 = cm */
918 char *a_varName, /* threshold name */
919 char *a_value, /* threshold value */
920 char *a_handler) /* threshold overflow handler */
921 { /* store_thresholds */
923 static char rn[] = "store_thresholds"; /* routine name */
924 struct afsmon_hostEntry *tmp_host; /* tmp ptr to hostEntry */
925 struct afsmon_hostEntry *Header; /* tmp ptr to hostEntry list header */
926 struct Threshold *threshP; /* tmp ptr to threshold list */
928 int index; /* index to fs_varNames or cm_varNames */
931 int srvCount; /* tmp count of host names */
932 int *global_TC; /* ptr to global_xxThreshCount */
937 "[ %s ] Called, a_type= %d, a_varName= %s, a_value= %s, a_handler=%s\n",
938 rn, a_type, a_varName, a_value, a_handler);
942 /* resolve the threshold variable name */
944 if (a_type == 1) { /* fs threshold */
945 for (index = 0; index < NUM_FS_STAT_ENTRIES; index++) {
946 if (strcasecmp(a_varName, fs_varNames[index]) == 0) {
952 fprintf(stderr, "[ %s ] Unknown FS threshold variable name %s\n",
958 hostname = last_fsHost;
959 global_TC = &global_fsThreshCount;
960 } else if (a_type == 2) { /* cm threshold */
961 for (index = 0; index < NUM_CM_STAT_ENTRIES; index++) {
962 if (strcasecmp(a_varName, cm_varNames[index]) == 0) {
968 fprintf(stderr, "[ %s ] Unknown CM threshold variable name %s\n",
974 hostname = last_cmHost;
975 global_TC = &global_cmThreshCount;
981 /* if the global thresh count is not zero, place this threshold on
982 * all the host entries */
986 for (i = 0; i < srvCount; i++) {
987 threshP = tmp_host->thresh;
989 for (j = 0; j < tmp_host->numThresh; j++) {
990 if ((threshP->itemName[0] == '\0')
991 || (strcasecmp(threshP->itemName, a_varName) == 0)) {
992 strncpy(threshP->itemName, a_varName,
993 THRESH_VAR_NAME_LEN);
994 strncpy(threshP->threshVal, a_value, THRESH_VAR_LEN);
995 strcpy(threshP->handler, a_handler);
996 threshP->index = index;
1003 fprintf(stderr, "[ %s ] Could not insert threshold entry",
1005 fprintf(stderr, "for %s in thresh list of host %s \n",
1006 a_varName, tmp_host->hostName);
1009 tmp_host = tmp_host->next;
1015 /* it is not a global threshold, insert it in the thresh list of this
1016 * host only. We overwrite the global threshold if it was alread set */
1018 if (*hostname == '\0') {
1019 fprintf(stderr, "[ %s ] Programming error 3\n", rn);
1023 /* get the hostEntry that this threshold belongs to */
1026 for (i = 0; i < srvCount; i++) {
1027 if (strcasecmp(tmp_host->hostName, hostname) == 0) {
1031 tmp_host = tmp_host->next;
1034 fprintf(stderr, "[ %s ] Unable to find host %s in %s hostEntry list",
1035 rn, hostname, (a_type - 1) ? "CM" : "FS");
1039 /* put this entry on the thresh list of this host, overwrite global value
1042 threshP = tmp_host->thresh;
1044 for (i = 0; i < tmp_host->numThresh; i++) {
1045 if ((threshP->itemName[0] == '\0')
1046 || (strcasecmp(threshP->itemName, a_varName) == 0)) {
1047 strncpy(threshP->itemName, a_varName, THRESH_VAR_NAME_LEN);
1048 strncpy(threshP->threshVal, a_value, THRESH_VAR_LEN);
1049 strcpy(threshP->handler, a_handler);
1050 threshP->index = index;
1059 "[ %s ] Unable to insert threshold %s for %s host %s\n", rn,
1060 a_varName, (a_type - 1) ? "CM" : "FS", tmp_host->hostName);
1066 } /* store_thresholds */
1069 /*-----------------------------------------------------------------------
1073 * This function process a "show" entry in the config file. A "show"
1074 * entry specifies what statistics the user wants to see. File
1075 * server and Cache Manager data is divided into sections. Each section
1076 * is made up of one or more groups. If a group name is specified only
1077 * those statistics under that group are shown. If a section name is
1078 * specified all the groups under this section are shown.
1079 * Data as obtained from the xstat probes is considered to be ordered.
1080 * This data is mapped to the screen thru fs_Display_map[] and
1081 * cm_Display_map[]. This routine parses the "show" entry against the
1082 * section/group names in the [fs/cm]_categories[] array. If there is
1083 * no match it tries to match it against a variable name in
1084 * [fs/cm]_varNames[] array. In each case the corresponding indices to
1085 * the data is the [fs/cm]_displayInfo[] is recorded.
1089 * Failure: -1 (invalid entry)
1090 * > -1 (programming error)
1091 *----------------------------------------------------------------------*/
1094 parse_showEntry(char *a_line)
1095 { /* parse_showEntry */
1096 static char rn[] = "parse_showEntry";
1097 char opcode[CFG_STR_LEN]; /* specifies type of config entry */
1098 char arg1[CFG_STR_LEN]; /* show fs or cm entry ? */
1099 char arg2[CFG_STR_LEN]; /* what we gotta show */
1100 char arg3[CFG_STR_LEN]; /* junk */
1101 char catName[CFG_STR_LEN]; /* for category names */
1102 int numGroups; /* number of groups in a section */
1106 int idx = 0; /* index to fs_categories[] */
1112 fprintf(debugFD, "[ %s ] Called, a_line= %s\n", rn, a_line);
1119 sscanf(a_line, "%s %s %s %s", opcode, arg1, arg2, arg3);
1121 if (arg3[0] != '\0') {
1122 fprintf(stderr, "[ %s ] Extraneous characters at end of line\n", rn);
1126 if ((strcasecmp(arg1, "fs") != 0) && (strcasecmp(arg1, "cm") != 0)) {
1128 "[ %s ] Second argument of \"show\" directive should be \"fs\" or \"cm\" \n",
1133 /* Each entry can either be a variable name or a section/group name. Variable
1134 * names are listed in xx_varNames[] and section/group names in xx_categories[].
1135 * The section/group names in xx_categiries[] also give the starting/ending
1136 * indices of the variables belonging to that section/group. These indices
1137 * are stored in order in xx_Display_map[] and displayed to the screen in that
1140 /* To handle duplicate "show" entries we keep track of what what we have
1141 * already marked to show in the xx_showFlags[] */
1143 if (strcasecmp(arg1, "fs") == 0) { /* its a File Server entry */
1145 /* mark that we have to show only what the user wants */
1148 /* if it is a section/group name, find it in the fs_categories[] array */
1151 if (strcasestr(arg2, "_section") != NULL
1152 || strcasestr(arg2, "_group") != NULL) {
1154 while (idx < FS_NUM_DATA_CATEGORIES) {
1155 sscanf(fs_categories[idx], "%s %d %d", catName, &fromIdx,
1158 if (strcasecmp(arg2, catName) == 0) {
1164 if (!found) { /* typo in section/group name */
1166 "[ %s ] Could not find section/group name %s\n", rn,
1172 /* if it is a group name, read its start/end indices and fill in the
1173 * fs_Display_map[]. */
1175 if (strcasestr(arg2, "_group") != NULL) {
1177 if (fromIdx < 0 || toIdx < 0 || fromIdx >= NUM_FS_STAT_ENTRIES
1178 || toIdx >= NUM_FS_STAT_ENTRIES)
1180 for (j = fromIdx; j <= toIdx; j++) {
1181 if (!fs_showFlags[j]) {
1182 fs_Display_map[fs_DisplayItems_count] = j;
1183 fs_DisplayItems_count++;
1184 fs_showFlags[j] = 1;
1186 if (fs_DisplayItems_count >= NUM_FS_STAT_ENTRIES) {
1187 fprintf(stderr, "[ %s ] fs_DisplayItems_count ovf\n", rn);
1192 /* if it is a section name, get the count of number of groups in it and
1193 * for each group fill in the start/end indices in the fs_Display_map[] */
1195 if (strcasestr(arg2, "_section") != NULL) {
1196 /* fromIdx is actually the number of groups in thi section */
1197 numGroups = fromIdx;
1198 /* for each group in section */
1199 while (idx < FS_NUM_DATA_CATEGORIES && numGroups) {
1200 sscanf(fs_categories[idx], "%s %d %d", catName, &fromIdx,
1203 if (strcasestr(catName, "_group") != NULL) {
1204 if (fromIdx < 0 || toIdx < 0
1205 || fromIdx >= NUM_FS_STAT_ENTRIES
1206 || toIdx >= NUM_FS_STAT_ENTRIES)
1208 for (j = fromIdx; j <= toIdx; j++) {
1209 if (!fs_showFlags[j]) {
1210 fs_Display_map[fs_DisplayItems_count] = j;
1211 fs_DisplayItems_count++;
1212 fs_showFlags[j] = 1;
1214 if (fs_DisplayItems_count >= NUM_FS_STAT_ENTRIES) {
1216 "[ %s ] fs_DisplayItems_count ovf\n", rn);
1221 fprintf(stderr, "[ %s ] Error parsing groups for %s\n",
1227 } /* for each group in section */
1230 } else { /* it is a variable name */
1232 for (i = 0; i < NUM_FS_STAT_ENTRIES; i++) {
1233 if (strcasecmp(arg2, fs_varNames[i]) == 0) {
1234 if (!fs_showFlags[i]) {
1235 fs_Display_map[fs_DisplayItems_count] = i;
1236 fs_DisplayItems_count++;
1237 fs_showFlags[i] = 1;
1239 if (fs_DisplayItems_count >= NUM_FS_STAT_ENTRIES) {
1240 fprintf(stderr, "[ %s ] fs_DisplayItems_count ovf\n",
1247 if (!found) { /* typo in section/group name */
1248 fprintf(stderr, "[ %s ] Could not find variable name %s\n",
1252 } /* its a variable name */
1256 /* it is an fs entry */
1257 if (strcasecmp(arg1, "cm") == 0) { /* its a Cache Manager entry */
1260 /* mark that we have to show only what the user wants */
1263 /* if it is a section/group name, find it in the cm_categories[] array */
1266 if (strcasestr(arg2, "_section") != NULL
1267 || strcasestr(arg2, "_group") != NULL) {
1269 while (idx < CM_NUM_DATA_CATEGORIES) {
1270 sscanf(cm_categories[idx], "%s %d %d", catName, &fromIdx,
1273 if (strcasecmp(arg2, catName) == 0) {
1279 if (!found) { /* typo in section/group name */
1281 "[ %s ] Could not find section/group name %s\n", rn,
1287 /* if it is a group name, read its start/end indices and fill in the
1288 * cm_Display_map[]. */
1290 if (strcasestr(arg2, "_group") != NULL) {
1292 if (fromIdx < 0 || toIdx < 0 || fromIdx >= NUM_CM_STAT_ENTRIES
1293 || toIdx >= NUM_CM_STAT_ENTRIES)
1295 for (j = fromIdx; j <= toIdx; j++) {
1296 if (!cm_showFlags[j]) {
1297 cm_Display_map[cm_DisplayItems_count] = j;
1298 cm_DisplayItems_count++;
1299 cm_showFlags[j] = 1;
1301 if (cm_DisplayItems_count >= NUM_CM_STAT_ENTRIES) {
1302 fprintf(stderr, "[ %s ] cm_DisplayItems_count ovf\n", rn);
1307 /* if it is a section name, get the count of number of groups in it and
1308 * for each group fill in the start/end indices in the cm_Display_map[] */
1310 if (strcasestr(arg2, "_section") != NULL) {
1311 /* fromIdx is actually the number of groups in thi section */
1312 numGroups = fromIdx;
1313 /* for each group in section */
1314 while (idx < CM_NUM_DATA_CATEGORIES && numGroups) {
1315 sscanf(cm_categories[idx], "%s %d %d", catName, &fromIdx,
1318 if (strcasestr(catName, "_group") != NULL) {
1319 if (fromIdx < 0 || toIdx < 0
1320 || fromIdx >= NUM_CM_STAT_ENTRIES
1321 || toIdx >= NUM_CM_STAT_ENTRIES)
1323 for (j = fromIdx; j <= toIdx; j++) {
1324 if (!cm_showFlags[j]) {
1325 cm_Display_map[cm_DisplayItems_count] = j;
1326 cm_DisplayItems_count++;
1327 cm_showFlags[j] = 1;
1329 if (cm_DisplayItems_count >= NUM_CM_STAT_ENTRIES) {
1331 "[ %s ] cm_DisplayItems_count ovf\n", rn);
1336 fprintf(stderr, "[ %s ] Error parsing groups for %s\n",
1342 } /* for each group in section */
1343 } else { /* it is a variable name */
1345 for (i = 0; i < NUM_CM_STAT_ENTRIES; i++) {
1346 if (strcasecmp(arg2, cm_varNames[i]) == 0) {
1347 if (!cm_showFlags[i]) {
1348 cm_Display_map[cm_DisplayItems_count] = i;
1349 cm_DisplayItems_count++;
1350 cm_showFlags[i] = 1;
1352 if (cm_DisplayItems_count >= NUM_CM_STAT_ENTRIES) {
1353 fprintf(stderr, "[ %s ] cm_DisplayItems_count ovf\n",
1360 if (!found) { /* typo in section/group name */
1361 fprintf(stderr, "[ %s ] Could not find variable name %s\n",
1365 } /* its a variable name */
1368 /* it is an cm entry */
1370 } /* parse_showEntry */
1373 /*-----------------------------------------------------------------------
1374 * process_config_file()
1377 * Parse config file entries in two passes. In the first pass:
1378 * - the syntax of all the entries is checked
1379 * - host names are noted and the FSnamesList and CMnamesList
1381 * - a count of the global thresholds and local thresholds of
1382 * each host are counted.
1383 * - "show" entries are processed.
1384 * In the second pass:
1385 * - thresholds are stored
1389 * Failure: Exits afsmonitor showing error and line.
1390 *----------------------------------------------------------------------*/
1393 process_config_file(char *a_config_filename)
1394 { /* process_config_file() */
1395 static char rn[] = "process_config_file"; /* routine name */
1396 FILE *configFD; /* config file descriptor */
1397 char line[4 * CFG_STR_LEN]; /* a line of config file */
1398 char opcode[CFG_STR_LEN]; /* specifies type of config entry */
1399 char arg1[CFG_STR_LEN]; /* hostname or qualifier (fs/cm?) */
1400 char arg2[CFG_STR_LEN]; /* threshold variable */
1401 char arg3[CFG_STR_LEN]; /* threshold value */
1402 char arg4[CFG_STR_LEN]; /* user's handler */
1403 struct afsmon_hostEntry *curr_host;
1404 struct hostent *he; /* hostentry to resolve host name */
1405 char *handlerPtr; /* ptr to pass theresh handler string */
1406 int code = 0; /* error code */
1407 int linenum = 0; /* config file line number */
1408 int error_in_config; /* syntax errors in config file ?? */
1413 fprintf(debugFD, "[ %s ] Called, a_config_filename= %s\n", rn,
1418 /* open config file */
1420 configFD = fopen(a_config_filename, "r");
1421 if (configFD == (FILE *) 0) {
1422 fprintf(stderr, "Failed to open config file %s \n",
1425 fprintf(debugFD, "[ %s ] Failed to open config file %s \n", rn,
1432 /* parse config file */
1434 /* We process the config file in two passes. In the first pass we check
1435 * for correct syntax and for valid entries and also keep count of the
1436 * number of servers and thresholds to monitor. This the data strctures
1437 * can be arrays instead of link lists since we would know their sizes. */
1443 error_in_config = 0; /* flag to note if config file has syntax errors */
1445 while ((fgets(line, CFG_STR_LEN, configFD)) != NULL) {
1451 sscanf(line, "%s %s %s %s %s", opcode, arg1, arg2, arg3, arg4);
1453 /* skip blank lines and comment lines */
1454 if ((strlen(opcode) == 0) || line[0] == '#')
1457 if ((strcasecmp(opcode, "fs") == 0)
1458 || (strcasecmp(opcode, "cm")) == 0) {
1459 code = parse_hostEntry(line);
1460 } else if ((strcasecmp(opcode, "thresh")) == 0) {
1461 code = parse_threshEntry(line);
1462 } else if ((strcasecmp(opcode, "show")) == 0) {
1463 code = parse_showEntry(line);
1465 fprintf(stderr, "[ %s ] Unknown opcode %s\n", rn, opcode);
1470 fprintf(stderr, "[ %s ] Error in line:\n %d: %s\n", rn, linenum,
1472 error_in_config = 1;
1476 if (error_in_config)
1480 fprintf(debugFD, "Global FS thresholds count = %d\n",
1481 global_fsThreshCount);
1482 fprintf(debugFD, "Global CM thresholds count = %d\n",
1483 global_cmThreshCount);
1487 /* the threshold count of all hosts in increased by 1 for each global
1488 * threshold. If one of the hosts has a local threshold for the same
1489 * variable it would end up being counted twice. whats a few bytes of memory
1490 * wasted anyway ? */
1492 if (global_fsThreshCount) {
1493 curr_host = FSnameList;
1494 for (i = 0; i < numFS; i++) {
1495 curr_host->numThresh += global_fsThreshCount;
1496 curr_host = curr_host->next;
1499 if (global_cmThreshCount) {
1500 curr_host = CMnameList;
1501 for (i = 0; i < numCM; i++) {
1502 curr_host->numThresh += global_cmThreshCount;
1503 curr_host = curr_host->next;
1508 /* make sure we have something to monitor */
1509 if (numFS == 0 && numCM == 0) {
1511 "\nConfig file must specify atleast one File Server or Cache Manager host to monitor.\n");
1518 fseek(configFD, 0, 0); /* seek to the beginning */
1521 /* allocate memory for threshold lists */
1522 curr_host = FSnameList;
1523 for (i = 0; i < numFS; i++) {
1524 if (curr_host->hostName[0] == '\0') {
1525 fprintf(stderr, "[ %s ] Programming error 4\n", rn);
1528 if (curr_host->numThresh) {
1529 numBytes = curr_host->numThresh * sizeof(struct Threshold);
1530 curr_host->thresh = malloc(numBytes);
1531 if (curr_host->thresh == NULL) {
1532 fprintf(stderr, "[ %s ] Memory Allocation error 1", rn);
1535 memset(curr_host->thresh, 0, numBytes);
1537 curr_host = curr_host->next;;
1540 curr_host = CMnameList;
1541 for (i = 0; i < numCM; i++) {
1542 if (curr_host->hostName[0] == '\0') {
1543 fprintf(stderr, "[ %s ] Programming error 5\n", rn);
1546 if (curr_host->numThresh) {
1547 numBytes = curr_host->numThresh * sizeof(struct Threshold);
1548 curr_host->thresh = malloc(numBytes);
1549 if (curr_host->thresh == NULL) {
1550 fprintf(stderr, "[ %s ] Memory Allocation error 2", rn);
1553 memset(curr_host->thresh, 0, numBytes);
1555 curr_host = curr_host->next;;
1564 last_fsHost[0] = '\0';
1565 last_cmHost[0] = '\0';
1567 while ((fgets(line, CFG_STR_LEN, configFD)) != NULL) {
1573 sscanf(line, "%s %s %s %s %s", opcode, arg1, arg2, arg3, arg4);
1576 /* if we have a host entry, remember the host name */
1577 if (strcasecmp(opcode, "fs") == 0) {
1578 he = GetHostByName(arg1);
1579 strncpy(last_fsHost, he->h_name, HOST_NAME_LEN);
1580 } else if (strcasecmp(opcode, "cm") == 0) {
1581 he = GetHostByName(arg1);
1582 strncpy(last_cmHost, he->h_name, HOST_NAME_LEN);
1583 } else if (strcasecmp(opcode, "thresh") == 0) {
1584 /* if we have a threshold handler it may have arguments
1585 * and the sscanf() above would not get them, so do the
1589 /* now skip over 4 words - this is done by first
1590 * skipping leading blanks then skipping a word */
1591 for (i = 0; i < 4; i++) {
1592 while (isspace(*handlerPtr))
1594 while (!isspace(*handlerPtr))
1597 while (isspace(*handlerPtr))
1599 /* we how have a pointer to the start of the handler
1602 handlerPtr = arg4; /* empty string */
1605 if (strcasecmp(arg1, "fs") == 0)
1606 code = store_threshold(1, /* 1 = fs */
1607 arg2, arg3, handlerPtr);
1609 else if (strcasecmp(arg1, "cm") == 0)
1610 code = store_threshold(2, /* 2 = fs */
1611 arg2, arg3, handlerPtr);
1614 fprintf(stderr, "[ %s ] Programming error 6\n", rn);
1618 fprintf(stderr, "[ %s ] Failed to store threshold\n", rn);
1619 fprintf(stderr, "[ %s ] Error processing line:\n%d: %s", rn,
1631 /*-----------------------------------------------------------------------
1636 * Print the File Server circular buffer.
1640 *----------------------------------------------------------------------*/
1644 { /* Print_FS_CB() */
1646 struct afsmon_fs_Results_list *fslist;
1651 /* print valid info in the fs CB */
1655 "==================== FS Buffer ========================\n");
1656 fprintf(debugFD, "afsmon_fs_curr_CBindex = %d\n",
1657 afsmon_fs_curr_CBindex);
1658 fprintf(debugFD, "afsmon_fs_curr_probeNum = %d\n\n",
1659 afsmon_fs_curr_probeNum);
1661 for (i = 0; i < num_bufSlots; i++) {
1662 fprintf(debugFD, "\t--------- slot %d ----------\n", i);
1663 fslist = afsmon_fs_ResultsCB[i].list;
1666 for (k = 0; k < MAX_NUM_FS_COLLECTIONS; k++) {
1667 if (!(fslist->empty[k])) {
1668 fprintf(debugFD, "\t %d) probeNum = %d host = %s cn = %d",
1670 fslist->fsResults[k]->probeNum,
1671 fslist->fsResults[k]->connP->hostName,
1672 fslist->fsResults[k]->collectionNumber);
1673 if (fslist->fsResults[k]->probeOK)
1674 fprintf(debugFD, " NOTOK\n");
1676 fprintf(debugFD, " OK\n");
1678 fprintf(debugFD, "\t %d) -- empty --\n", j);
1680 fslist = fslist->next;
1683 if (fslist != (struct afsmon_fs_Results_list *)0)
1684 fprintf(debugFD, "dangling last next ptr fs CB\n");
1687 } /* Print_FS_CB() */
1689 /*-----------------------------------------------------------------------
1690 * save_FS_results_inCB()
1693 * Saves the results of the latest FS probe in the fs circular
1694 * buffers. If the current probe cycle is in progress the contents
1695 * of xstat_fs_Results are copied to the end of the list of results
1696 * in the current slot (pointed to by afsmon_fs_curr_CBindex). If
1697 * a new probe cycle has started the next slot in the circular buffer
1698 * is initialized and the results copied. Note that the Rx related
1699 * information available in xstat_fs_Results is not copied.
1703 * Failure: Exits afsmonitor.
1704 *----------------------------------------------------------------------*/
1706 save_FS_results_inCB(int a_newProbeCycle) /* start of a new probe cycle ? */
1707 { /* save_FS_results_inCB() */
1708 static char rn[] = "save_FS_results_inCB"; /* routine name */
1709 struct afsmon_fs_Results_list *tmp_fslist_item; /* temp fs list item */
1710 struct xstat_fs_ProbeResults *tmp_fsPR; /* temp ptr */
1715 fprintf(debugFD, "[ %s ] Called, a_newProbeCycle= %d\n", rn,
1720 switch (xstat_fs_Results.collectionNumber) {
1721 case AFS_XSTATSCOLL_FULL_PERF_INFO:
1724 case AFS_XSTATSCOLL_CBSTATS:
1728 fprintf(stderr, "[ %s ] collection number %d is out of range.\n",
1729 rn, xstat_fs_Results.collectionNumber);
1733 /* If a new probe cycle started, mark the list in the current buffer
1734 * slot empty for resuse. Note that afsmon_fs_curr_CBindex was appropriately
1735 * incremented in afsmon_FS_Handler() */
1737 if (a_newProbeCycle) {
1738 tmp_fslist_item = afsmon_fs_ResultsCB[afsmon_fs_curr_CBindex].list;
1739 for (i = 0; i < numFS; i++) {
1740 tmp_fslist_item->empty[index] = 1;
1741 tmp_fslist_item = tmp_fslist_item->next;
1745 /* locate last unused item in list */
1746 tmp_fslist_item = afsmon_fs_ResultsCB[afsmon_fs_curr_CBindex].list;
1747 for (i = 0; i < numFS; i++) {
1748 if (tmp_fslist_item->empty[index])
1750 tmp_fslist_item = tmp_fslist_item->next;
1753 /* if we could not find one we have an inconsistent list */
1754 if (!tmp_fslist_item->empty[index]) {
1756 "[ %s ] list inconsistency 1. unable to find an empty slot to store results of probenum %d of %s\n",
1757 rn, xstat_fs_Results.probeNum,
1758 xstat_fs_Results.connP->hostName);
1762 tmp_fsPR = tmp_fslist_item->fsResults[index];
1764 /* copy hostname and probe number and probe time and probe status.
1765 * if the probe failed return now */
1767 memcpy(tmp_fsPR->connP->hostName, xstat_fs_Results.connP->hostName,
1768 sizeof(xstat_fs_Results.connP->hostName));
1769 tmp_fsPR->probeNum = xstat_fs_Results.probeNum;
1770 tmp_fsPR->probeTime = xstat_fs_Results.probeTime;
1771 tmp_fsPR->probeOK = xstat_fs_Results.probeOK;
1772 if (xstat_fs_Results.probeOK) { /* probeOK = 1 => notOK */
1773 /* we have a nonempty results structure so mark the list item used */
1774 tmp_fslist_item->empty[index] = 0;
1778 /* copy connection information */
1779 memcpy(&(tmp_fsPR->connP->skt), &(xstat_fs_Results.connP->skt),
1780 sizeof(struct sockaddr_in));
1782 memcpy(tmp_fsPR->connP->hostName, xstat_fs_Results.connP->hostName,
1783 sizeof(xstat_fs_Results.connP->hostName));
1784 tmp_fsPR->collectionNumber = xstat_fs_Results.collectionNumber;
1786 /* copy the probe data information */
1787 tmp_fsPR->data.AFS_CollData_len =
1788 min(xstat_fs_Results.data.AFS_CollData_len,
1789 afsmon_fs_results_length[index]);
1790 memcpy(tmp_fsPR->data.AFS_CollData_val,
1791 xstat_fs_Results.data.AFS_CollData_val,
1792 tmp_fsPR->data.AFS_CollData_len * sizeof(afs_int32));
1795 /* we have a valid results structure so mark the list item used */
1796 tmp_fslist_item->empty[index] = 0;
1798 /* Print the fs circular buffer */
1802 } /* save_FS_results_inCB() */
1805 /*-----------------------------------------------------------------------
1809 * The results of xstat probes are stored in a string format in
1810 * the arrays curr_fsData and prev_fsData. The information stored in
1811 * prev_fsData is copied to the screen.
1812 * This function converts xstat FS results from longs to strings and
1813 * place them in the given buffer (a pointer to an item in curr_fsData).
1814 * When a probe cycle completes, curr_fsData is copied to prev_fsData
1815 * in afsmon_FS_Hnadler().
1819 *----------------------------------------------------------------------*/
1822 fs_Results_ltoa(struct fs_Display_Data *a_fsData, /* target buffer */
1823 struct xstat_fs_ProbeResults *a_fsResults) /* ptr to xstat fs Results */
1824 { /* fs_Results_ltoa */
1826 static char rn[] = "fs_Results_ltoa"; /* routine name */
1829 fprintf(debugFD, "[ %s ] Called, a_fsData= %p, a_fsResults= %p\n", rn,
1830 a_fsData, a_fsResults);
1834 switch (a_fsResults->collectionNumber) {
1835 case AFS_XSTATSCOLL_FULL_PERF_INFO:
1836 fs_FullPerfs_ltoa(a_fsData, a_fsResults);
1838 case AFS_XSTATSCOLL_CBSTATS:
1839 fs_CallBackStats_ltoa(a_fsData, a_fsResults);
1843 fprintf(debugFD, "[ %s ] Unexpected collection id %d\n",
1844 rn, a_fsResults->collectionNumber);
1849 } /* fs_Results_ltoa */
1851 /*-----------------------------------------------------------------------
1852 * fs_FullPerfs_ltoa()
1855 * Convert the full perf xstat collection from int32s to strings.
1859 *----------------------------------------------------------------------*/
1861 fs_FullPerfs_ltoa(struct fs_Display_Data *a_fsData,
1862 struct xstat_fs_ProbeResults *a_fsResults)
1865 struct fs_stats_FullPerfStats *fullPerfP;
1866 struct fs_stats_FullPerfStats buffer;
1872 /* there are two parts to the xstat FS statistics
1873 * - fullPerfP->overall which give the overall performance statistics, and
1874 * - fullPerfP->det which gives detailed info about file server operation
1875 * execution times */
1877 code = xstat_fs_DecodeFullPerfStats(&fullPerfP,
1878 a_fsResults->data.AFS_CollData_val,
1879 a_fsResults->data.AFS_CollData_len,
1882 /* Not able to decode the full perf stats. Avoid displaying garbage. */
1883 for (i = 0; i < NUM_FS_STAT_ENTRIES; i++) {
1884 sprintf(a_fsData->data[i], "%s", "--");
1889 /* copy overall performance statistics */
1890 srcbuf = (afs_int32 *) & (fullPerfP->overall);
1892 for (i = 0; i < NUM_XSTAT_FS_AFS_PERFSTATS_LONGS; i++) {
1893 sprintf(a_fsData->data[idx], "%d", *srcbuf);
1899 srcbuf = (afs_int32 *) & (fullPerfP->det.epoch);
1900 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* epoch */
1903 /* copy fs operation timing */
1905 srcbuf = (afs_int32 *) (fullPerfP->det.rpcOpTimes);
1907 for (i = 0; i < FS_STATS_NUM_RPC_OPS; i++) {
1908 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* numOps */
1911 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* numSuccesses */
1914 tmpbuf = srcbuf++; /* sum time */
1915 sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1918 tmpbuf = srcbuf++; /* sqr time */
1919 sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1922 tmpbuf = srcbuf++; /* min time */
1923 sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1926 tmpbuf = srcbuf++; /* max time */
1927 sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1932 /* copy fs transfer timings */
1934 srcbuf = (afs_int32 *) (fullPerfP->det.xferOpTimes);
1935 for (i = 0; i < FS_STATS_NUM_XFER_OPS; i++) {
1936 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* numOps */
1939 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* numSuccesses */
1942 tmpbuf = srcbuf++; /* sum time */
1943 sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1946 tmpbuf = srcbuf++; /* sqr time */
1947 sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1950 tmpbuf = srcbuf++; /* min time */
1951 sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1954 tmpbuf = srcbuf++; /* max time */
1955 sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1958 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* sum bytes */
1961 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* min bytes */
1964 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* max bytes */
1967 for (j = 0; j < FS_STATS_NUM_XFER_BUCKETS; j++) {
1968 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* bucket[j] */
1977 /*-----------------------------------------------------------------------
1978 * fs_CallBackStats_ltoa()
1981 * Convert the callback counter xstat collection from
1982 * int32s to strings.
1986 *----------------------------------------------------------------------*/
1989 fs_CallBackStats_ltoa(struct fs_Display_Data *a_fsData,
1990 struct xstat_fs_ProbeResults *a_fsResults)
1994 int len = a_fsResults->data.AFS_CollData_len;
1995 afs_int32 *val = a_fsResults->data.AFS_CollData_val;
1997 /* place callback stats after the full perf stats */
1998 idx = NUM_FS_FULLPERF_ENTRIES;
1999 for (i=0; i < len && i < NUM_FS_CB_ENTRIES; i++) {
2000 sprintf(a_fsData->data[idx++], "%u", val[i]);
2005 /*-----------------------------------------------------------------------
2006 * execute_thresh_handler()
2009 * Execute a threshold handler. An agrv[] array of pointers is
2010 * constructed from the given data. A child process is forked
2011 * which immediately calls afsmon_Exit() with indication that a
2012 * threshold handler is to be exec'ed insted of exiting.
2016 * Failure: Afsmonitor exits if threshold handler has more than 20 args.
2017 *----------------------------------------------------------------------*/
2020 execute_thresh_handler(char *a_handler, /* ptr to handler function + args */
2021 char *a_hostName, /* host name for which threshold crossed */
2022 int a_hostType, /* fs or cm ? */
2023 char *a_threshName, /* threshold variable name */
2024 char *a_threshValue, /* threshold value */
2025 char *a_actValue) /* actual value */
2026 { /* execute_thresh_handler */
2028 static char rn[] = "execute_thresh_handler";
2029 char fileName[256]; /* file name to execute */
2033 int anotherArg; /* boolean used to flag if another arg is available */
2037 "[ %s ] Called, a_handler= %s, a_hostName= %s, a_hostType= %d, a_threshName= %s, a_threshValue= %s, a_actValue= %s\n",
2038 rn, a_handler, a_hostName, a_hostType, a_threshName,
2039 a_threshValue, a_actValue);
2044 /* get the filename to execute - the first argument */
2045 sscanf(a_handler, "%s", fileName);
2047 /* construct the contents of *argv[] */
2049 strncpy(fsHandler_args[0], fileName, 256);
2050 strncpy(fsHandler_args[1], a_hostName, HOST_NAME_LEN);
2051 if (a_hostType == FS)
2052 strcpy(fsHandler_args[2], "fs");
2054 strcpy(fsHandler_args[2], "cm");
2055 strncpy(fsHandler_args[3], a_threshName, THRESH_VAR_NAME_LEN);
2056 strncpy(fsHandler_args[4], a_threshValue, THRESH_VAR_LEN);
2057 strncpy(fsHandler_args[5], a_actValue, THRESH_VAR_LEN);
2064 /* we have already extracted the file name so skip to the 1st arg */
2065 while (isspace(*ch)) /* leading blanks */
2067 while (!isspace(*ch) && *ch != '\0') /* handler filename */
2070 while (*ch != '\0') {
2073 } else if (anotherArg) {
2075 sscanf(ch, "%s", fsHandler_args[argNum]);
2081 "Threshold handlers cannot have more than 20 arguments\n");
2087 fsHandler_argv[argNum] = NULL;
2088 for (i = 0; i < argNum; i++)
2089 fsHandler_argv[i] = fsHandler_args[i];
2092 /* exec the threshold handler */
2095 exec_fsThreshHandler = 1;
2100 } /* execute_thresh_handler */
2104 /*-----------------------------------------------------------------------
2105 * check_fs_thresholds()
2108 * Checks the thresholds and sets the overflow flag. Recall that the
2109 * thresholds for each host are stored in the hostEntry lists
2110 * [fs/cm]nameList arrays. The probe results are passed to this
2111 * function in the display-ready format - ie., as strings. Though
2112 * this looks stupid the overhead incurred in converting the strings
2113 * back to floats and comparing them is insignificant and
2114 * programming is easier this way.
2115 * The threshold flags are a part of the display structures
2120 *----------------------------------------------------------------------*/
2123 check_fs_thresholds(struct afsmon_hostEntry *a_hostEntry, /* ptr to hostEntry */
2124 struct fs_Display_Data *a_Data) /* ptr to fs data to be displayed */
2125 { /* check_fs_thresholds */
2127 static char rn[] = "check_fs_thresholds";
2128 struct Threshold *threshP;
2129 double tValue; /* threshold value */
2130 double pValue; /* probe value */
2133 int count; /* number of thresholds exceeded */
2136 fprintf(debugFD, "[ %s ] Called, a_hostEntry= %p, a_Data= %p\n", rn,
2137 a_hostEntry, a_Data);
2141 if (a_hostEntry->numThresh == 0) {
2142 /* store in ovf count ?? */
2147 threshP = a_hostEntry->thresh;
2148 for (i = 0; i < a_hostEntry->numThresh; i++) {
2149 if (threshP->itemName[0] == '\0') {
2153 idx = threshP->index; /* positional index to the data array */
2154 tValue = atof(threshP->threshVal); /* threshold value */
2155 pValue = atof(a_Data->data[idx]); /* probe value */
2156 if (pValue > tValue) {
2160 "[ %s ] fs = %s, thresh ovf for %s, threshold= %s, probevalue= %s\n",
2161 rn, a_hostEntry->hostName, threshP->itemName,
2162 threshP->threshVal, a_Data->data[idx]);
2165 /* if the threshold is crossed, call the handler function
2166 * only if this was a transition -ie, if the threshold was
2167 * crossed in the last probe too just count & keep quite! */
2169 if (!a_Data->threshOvf[idx]) {
2170 a_Data->threshOvf[idx] = 1;
2171 /* call the threshold handler if provided */
2172 if (threshP->handler[0] != '\0') {
2174 fprintf(debugFD, "[ %s ] Calling ovf handler %s\n",
2175 rn, threshP->handler);
2178 execute_thresh_handler(threshP->handler, a_Data->hostName,
2179 FS, threshP->itemName,
2187 /* in case threshold was previously crossed, blank it out */
2188 a_Data->threshOvf[idx] = 0;
2191 /* store the overflow count */
2192 a_Data->ovfCount = count;
2195 } /* check_fs_thresholds */
2198 /*-----------------------------------------------------------------------
2199 * save_FS_data_forDisplay()
2202 * Does the following:
2203 * - if the probe number changed (ie, a cycle completed) curr_fsData
2204 * is copied to prev_fsData, curr_fsData zeroed and refresh the
2205 * overview screen and file server screen with the new data.
2206 * - store the results of the current probe from xstat_fs_Results into
2207 * curr_fsData. ie., convert longs to strings.
2208 * - check the thresholds
2212 * Failure: Exits afsmonitor.
2213 *----------------------------------------------------------------------*/
2216 save_FS_data_forDisplay(struct xstat_fs_ProbeResults *a_fsResults)
2217 { /* save_FS_data_forDisplay */
2219 static char rn[] = "save_FS_data_forDisplay"; /* routine name */
2220 struct fs_Display_Data *curr_fsDataP; /* tmp ptr to curr_fsData */
2221 struct fs_Display_Data *prev_fsDataP; /* tmp ptr to prev_fsData */
2222 struct afsmon_hostEntry *curr_host;
2223 static int results_Received = 0; /* number of probes reveived in
2224 * the current cycle. If this is equal to numFS we got all
2225 * the data we want in this cycle and can now display it */
2234 fprintf(debugFD, "[ %s ] Called, a_fsResults= %p\n", rn, a_fsResults);
2238 /* store results in the display array */
2241 curr_fsDataP = curr_fsData;
2242 for (i = 0; i < numFS; i++) {
2243 if ((strcasecmp(curr_fsDataP->hostName, a_fsResults->connP->hostName))
2253 "[ %s ] Could not insert FS probe results for host %s in fs display array\n",
2254 rn, a_fsResults->connP->hostName);
2258 /* Check the status of the probe. If it succeeded, we store its
2259 * results in the display data structure. If it failed we only mark
2260 * the failed status in the display data structure. */
2262 if (a_fsResults->probeOK) { /* 1 => notOK the xstat results */
2263 curr_fsDataP->probeOK = 0;
2265 /* print the probe status */
2267 fprintf(debugFD, "\n\t\t ----- fs display data ------\n");
2268 fprintf(debugFD, "HostName = %s PROBE FAILED \n",
2269 curr_fsDataP->hostName);
2273 } else { /* probe succeeded, update display data structures */
2274 curr_fsDataP->probeOK = 1;
2276 /* convert longs to strings and place them in curr_fsDataP */
2277 fs_Results_ltoa(curr_fsDataP, a_fsResults);
2279 /* compare with thresholds and set the overflow flags.
2280 * note that the threshold information is in the hostEntry structure and
2281 * each threshold item has a positional index associated with it */
2283 /* locate the hostEntry for this host */
2285 curr_host = FSnameList;
2286 for (i = 0; i < numFS; i++) {
2287 if (strcasecmp(curr_host->hostName, a_fsResults->connP->hostName)
2292 curr_host = curr_host->next;;
2297 code = check_fs_thresholds(curr_host, curr_fsDataP);
2299 fprintf(stderr, "[ %s ] Error in checking thresholds\n", rn);
2303 /* print the info we just saved */
2306 fprintf(debugFD, "\n\t\t ----- fs display data ------\n");
2307 fprintf(debugFD, "HostName = %s\n", curr_fsDataP->hostName);
2308 for (i = 0; i < NUM_FS_STAT_ENTRIES; i++)
2309 fprintf(debugFD, "%20s %30s %s\n", curr_fsDataP->data[i],
2311 curr_fsDataP->threshOvf[i] ? "(ovf)" : "");
2313 fprintf(debugFD, "\t\t--------------------------------\n\n");
2317 } /* the probe succeeded, so we store the data in the display structure */
2320 /* if we have received a reply from all the hosts for this probe cycle,
2321 * it is time to display the data */
2324 if (results_Received == numFS * num_fs_collections) {
2325 results_Received = 0;
2327 if (afsmon_fs_curr_probeNum != afsmon_fs_prev_probeNum + 1) {
2328 sprintf(errMsg, "[ %s ] Probe number %d missed! \n", rn,
2329 afsmon_fs_prev_probeNum + 1);
2332 afsmon_fs_prev_probeNum++;
2334 /* backup the display data of the probe cycle that just completed -
2335 * ie., store curr_fsData in prev_fsData */
2337 memcpy((char *)prev_fsData, (char *)curr_fsData,
2338 (numFS * sizeof(struct fs_Display_Data)));
2341 /* initialize curr_fsData but retain the threshold flag information.
2342 * The previous state of threshold flags is used in check_fs_thresholds() */
2344 numBytes = NUM_FS_STAT_ENTRIES * FS_STAT_STRING_LEN;
2345 curr_fsDataP = curr_fsData;
2346 for (i = 0; i < numFS; i++) {
2347 curr_fsDataP->probeOK = 0;
2348 curr_fsDataP->ovfCount = 0;
2349 memset(curr_fsDataP->data, 0, numBytes);
2354 /* prev_fsData now contains all the information for the probe cycle
2355 * that just completed. Now count the number of threshold overflows for
2356 * use in the overview screen */
2358 prev_fsDataP = prev_fsData;
2360 numHosts_onfs_alerts = 0;
2361 for (i = 0; i < numFS; i++) {
2362 if (!prev_fsDataP->probeOK) { /* if probe failed */
2364 numHosts_onfs_alerts++;
2366 if (prev_fsDataP->ovfCount) { /* overflows ?? */
2367 num_fs_alerts += prev_fsDataP->ovfCount;
2368 numHosts_onfs_alerts++;
2373 fprintf(debugFD, "Number of FS alerts = %d (on %d hosts)\n",
2374 num_fs_alerts, numHosts_onfs_alerts);
2376 /* flag that the data is now ready to be displayed */
2377 fs_Data_Available = 1;
2379 /* call the Overview frame update routine (update only FS info) */
2380 ovw_refresh(ovw_currPage, OVW_UPDATE_FS);
2382 /* call the File Servers frame update routine */
2383 fs_refresh(fs_currPage, fs_curr_LCol);
2388 } /* save_FS_data_forDisplay */
2393 /*-----------------------------------------------------------------------
2394 * afsmon_FS_Handler()
2397 * This is the File Server probe Handler. It updates the afsmonitor
2398 * probe counts, fs circular buffer indices and calls the functions
2399 * to process the results of this probe.
2403 * Failure: Exits afsmonitor.
2404 *----------------------------------------------------------------------*/
2407 afsmon_FS_Handler(void)
2408 { /* afsmon_FS_Handler() */
2409 static char rn[] = "afsmon_FS_Handler"; /* routine name */
2410 int newProbeCycle; /* start of new probe cycle ? */
2411 int code; /* return status */
2416 "[ %s ] Called, hostName= %s, probeNum= %d, status=%s, collection=%d\n", rn,
2417 xstat_fs_Results.connP->hostName, xstat_fs_Results.probeNum,
2418 xstat_fs_Results.probeOK ? "FAILED" : "OK",
2419 xstat_fs_Results.collectionNumber);
2424 /* print the probe results to output file */
2425 if (afsmon_output) {
2426 code = afsmon_fsOutput(output_filename, afsmon_detOutput);
2429 "[ %s ] output to file %s returned error code=%d\n", rn,
2430 output_filename, code);
2434 /* Update current probe number and circular buffer index. if current
2435 * probenum changed make sure it is only by 1 */
2438 if (xstat_fs_Results.probeNum != afsmon_fs_curr_probeNum) {
2439 if (xstat_fs_Results.probeNum == afsmon_fs_curr_probeNum + 1) {
2440 afsmon_fs_curr_probeNum++;
2443 afsmon_fs_curr_CBindex =
2444 (afsmon_fs_curr_probeNum - 1) % num_bufSlots;
2446 fprintf(stderr, "[ %s ] probe number %d-1 missed\n", rn,
2447 xstat_fs_Results.probeNum);
2453 /* store the results of this probe in the FS circular buffer */
2455 save_FS_results_inCB(newProbeCycle);
2458 /* store the results of the current probe in the fs data display structure.
2459 * if the current probe number changed, swap the current and previous display
2460 * structures. note that the display screen is updated from these structures
2461 * and should start showing the data of the just completed probe cycle */
2463 save_FS_data_forDisplay(&xstat_fs_Results);
2470 /*----------------------------------------------------------------------- *
2475 * Prints the Cache Manager circular buffer
2476 *----------------------------------------------------------------------*/
2480 { /* Print_CM_CB() */
2482 struct afsmon_cm_Results_list *cmlist;
2487 /* print valid info in the cm CB */
2491 "==================== CM Buffer ========================\n");
2492 fprintf(debugFD, "afsmon_cm_curr_CBindex = %d\n",
2493 afsmon_cm_curr_CBindex);
2494 fprintf(debugFD, "afsmon_cm_curr_probeNum = %d\n\n",
2495 afsmon_cm_curr_probeNum);
2497 for (i = 0; i < num_bufSlots; i++) {
2498 fprintf(debugFD, "\t--------- slot %d ----------\n", i);
2499 cmlist = afsmon_cm_ResultsCB[i].list;
2502 for (k = 0; k < MAX_NUM_CM_COLLECTIONS; k++) {
2503 if (!cmlist->empty[k]) {
2505 "\t %d) probeNum = %d host = %s cn = %d",
2507 cmlist->cmResults[k]->probeNum,
2508 cmlist->cmResults[k]->connP->hostName,
2509 cmlist->cmResults[k]->collectionNumber);
2510 if (cmlist->cmResults[k]->probeOK)
2511 fprintf(debugFD, " NOTOK\n");
2513 fprintf(debugFD, " OK\n");
2515 fprintf(debugFD, "\t %d) -- empty --\n", j);
2517 cmlist = cmlist->next;
2520 if (cmlist != (struct afsmon_cm_Results_list *)0)
2521 fprintf(debugFD, "dangling last next ptr cm CB\n");
2527 /*-----------------------------------------------------------------------
2528 * save_CM_results_inCB()
2531 * Saves the results of the latest CM probe in the cm circular
2532 * buffers. If the current probe cycle is in progress the contents
2533 * of xstat_cm_Results are copied to the end of the list of results
2534 * in the current slot (pointed to by afsmon_cm_curr_CBindex). If
2535 * a new probe cycle has started the next slot in the circular buffer
2536 * is initialized and the results copied. Note that the Rx related
2537 * information available in xstat_cm_Results is not copied.
2541 * Failure: Exits afsmonitor.
2542 *----------------------------------------------------------------------*/
2545 save_CM_results_inCB(int a_newProbeCycle) /* start of new probe cycle ? */
2546 { /* save_CM_results_inCB() */
2547 static char rn[] = "save_CM_results_inCB"; /* routine name */
2548 struct afsmon_cm_Results_list *tmp_cmlist_item; /* temp cm list item */
2549 struct xstat_cm_ProbeResults *tmp_cmPR; /* temp ptr */
2555 fprintf(debugFD, "[ %s ] Called, a_newProbeCycle= %d\n", rn,
2560 if (xstat_cm_Results.collectionNumber == AFSCB_XSTATSCOLL_FULL_PERF_INFO) {
2563 fprintf(stderr, "[ %s ] collection number %d is out of range.\n",
2564 rn, xstat_cm_Results.collectionNumber);
2568 /* If a new probe cycle started, mark the list in the current buffer
2569 * slot empty for resuse. Note that afsmon_cm_curr_CBindex was appropriately
2570 * incremented in afsmon_CM_Handler() */
2572 if (a_newProbeCycle) {
2573 tmp_cmlist_item = afsmon_cm_ResultsCB[afsmon_cm_curr_CBindex].list;
2574 for (i = 0; i < numCM; i++) {
2575 tmp_cmlist_item->empty[index] = 1;
2576 tmp_cmlist_item = tmp_cmlist_item->next;
2580 /* locate last unused item in list */
2581 tmp_cmlist_item = afsmon_cm_ResultsCB[afsmon_cm_curr_CBindex].list;
2582 for (i = 0; i < numCM; i++) {
2583 if (tmp_cmlist_item->empty[index])
2585 tmp_cmlist_item = tmp_cmlist_item->next;
2588 /* if we could not find one we have an inconsistent list */
2589 if (!tmp_cmlist_item->empty[index]) {
2591 "[ %s ] list inconsistency 1. unable to find an empty slot to store results of probenum %d of %s\n",
2592 rn, xstat_cm_Results.probeNum,
2593 xstat_cm_Results.connP->hostName);
2597 tmp_cmPR = tmp_cmlist_item->cmResults[index];
2599 /* copy hostname and probe number and probe time and probe status.
2600 * if the probe failed return now */
2602 memcpy(tmp_cmPR->connP->hostName, xstat_cm_Results.connP->hostName,
2603 sizeof(xstat_cm_Results.connP->hostName));
2604 tmp_cmPR->probeNum = xstat_cm_Results.probeNum;
2605 tmp_cmPR->probeTime = xstat_cm_Results.probeTime;
2606 tmp_cmPR->probeOK = xstat_cm_Results.probeOK;
2607 if (xstat_cm_Results.probeOK) { /* probeOK = 1 => notOK */
2608 /* we have a nonempty results structure so mark the list item used */
2609 tmp_cmlist_item->empty[index] = 0;
2614 /* copy connection information */
2615 memcpy(&(tmp_cmPR->connP->skt), &(xstat_cm_Results.connP->skt),
2616 sizeof(struct sockaddr_in));
2618 /**** NEED TO COPY rx_connection INFORMATION HERE ******/
2620 memcpy(tmp_cmPR->connP->hostName, xstat_cm_Results.connP->hostName,
2621 sizeof(xstat_cm_Results.connP->hostName));
2622 tmp_cmPR->collectionNumber = xstat_cm_Results.collectionNumber;
2624 /* copy the probe data information */
2625 tmp_cmPR->data.AFSCB_CollData_len =
2626 min(xstat_cm_Results.data.AFSCB_CollData_len,
2627 afsmon_cm_results_length[index]);
2628 memcpy(tmp_cmPR->data.AFSCB_CollData_val,
2629 xstat_cm_Results.data.AFSCB_CollData_val,
2630 tmp_cmPR->data.AFSCB_CollData_len * sizeof(afs_int32));
2633 /* we have a valid results structure so mark the list item used */
2634 tmp_cmlist_item->empty[index] = 0;
2636 /* print the stored info - to make sure we copied it right */
2637 /* Print_cm_FullPerfInfo(tmp_cmPR); */
2638 /* Print the cm circular buffer */
2641 } /* save_CM_results_inCB */
2645 /*-----------------------------------------------------------------------
2649 * The results of xstat probes are stored in a string format in
2650 * the arrays curr_cmData and prev_cmData. The information stored in
2651 * prev_cmData is copied to the screen.
2652 * This function converts xstat FS results from longs to strings and
2653 * places them in the given buffer (a pointer to an item in curr_cmData).
2654 * When a probe cycle completes, curr_cmData is copied to prev_cmData
2655 * in afsmon_CM_Handler().
2659 *----------------------------------------------------------------------*/
2662 cm_Results_ltoa(struct cm_Display_Data *a_cmData, /* target buffer */
2663 struct xstat_cm_ProbeResults *a_cmResults) /* ptr to xstat cm Results */
2664 { /* cm_Results_ltoa */
2666 static char rn[] = "cm_Results_ltoa"; /* routine name */
2667 struct afs_stats_CMFullPerf *fullP; /* ptr to complete CM stats */
2675 fprintf(debugFD, "[ %s ] Called, a_cmData= %p, a_cmResults= %p\n", rn,
2676 a_cmData, a_cmResults);
2681 fullP = (struct afs_stats_CMFullPerf *)
2682 (a_cmResults->data.AFSCB_CollData_val);
2684 /* There are 4 parts to CM statistics
2685 * - Overall performance statistics (including up/down statistics)
2686 * - This CMs FS RPC operations info
2687 * - This CMs FS RPC errors info
2688 * - This CMs FS transfers info
2689 * - Authentication info
2690 * - [Un]Replicated access info
2693 /* copy overall performance statistics */
2694 srcbuf = (afs_int32 *) & (fullP->perf);
2696 /* we skip the 19 entry, ProtServAddr, so the index must account for this */
2697 for (i = 0; i < NUM_AFS_STATS_CMPERF_LONGS + 1; i++) {
2700 continue; /* skip ProtServerAddr */
2702 sprintf(a_cmData->data[idx], "%d", *srcbuf);
2707 /*printf("Ending index value = %d\n",idx-1); */
2709 /* server up/down statistics */
2710 /* copy file server up/down stats */
2711 srcbuf = (afs_int32 *) (fullP->perf.fs_UpDown);
2713 2 * (sizeof(struct afs_stats_SrvUpDownInfo) / sizeof(afs_int32));
2714 for (i = 0; i < numLongs; i++) {
2715 sprintf(a_cmData->data[idx], "%d", *srcbuf);
2720 /*printf("Ending index value = %d\n",idx-1); */
2722 /* copy volume location server up/down stats */
2723 srcbuf = (afs_int32 *) (fullP->perf.vl_UpDown);
2725 2 * (sizeof(struct afs_stats_SrvUpDownInfo) / sizeof(afs_int32));
2726 for (i = 0; i < numLongs; i++) {
2727 sprintf(a_cmData->data[idx], "%d", *srcbuf);
2732 /*printf("Ending index value = %d\n",idx-1); */
2734 /* copy CMs individual FS RPC operations info */
2735 srcbuf = (afs_int32 *) (fullP->rpc.fsRPCTimes);
2736 for (i = 0; i < AFS_STATS_NUM_FS_RPC_OPS; i++) {
2737 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* numOps */
2740 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* numSuccesses */
2743 tmpbuf = srcbuf++; /* sum time */
2744 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2747 tmpbuf = srcbuf++; /* sqr time */
2748 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2751 tmpbuf = srcbuf++; /* min time */
2752 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2755 tmpbuf = srcbuf++; /* max time */
2756 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2761 /*printf("Ending index value = %d\n",idx-1); */
2763 /* copy CMs individual FS RPC errors info */
2765 srcbuf = (afs_int32 *) (fullP->rpc.fsRPCErrors);
2766 for (i = 0; i < AFS_STATS_NUM_FS_RPC_OPS; i++) {
2767 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* server */
2770 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* network */
2773 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* prot */
2776 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* vol */
2779 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* busies */
2782 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* other */
2787 /*printf("Ending index value = %d\n",idx-1); */
2789 /* copy CMs individual RPC transfers info */
2791 srcbuf = (afs_int32 *) (fullP->rpc.fsXferTimes);
2792 for (i = 0; i < AFS_STATS_NUM_FS_XFER_OPS; i++) {
2793 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* numOps */
2796 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* numSuccesses */
2799 tmpbuf = srcbuf++; /* sum time */
2800 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2803 tmpbuf = srcbuf++; /* sqr time */
2804 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2807 tmpbuf = srcbuf++; /* min time */
2808 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2811 tmpbuf = srcbuf++; /* max time */
2812 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2815 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* sum bytes */
2818 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* min bytes */
2821 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* max bytes */
2824 for (j = 0; j < AFS_STATS_NUM_XFER_BUCKETS; j++) {
2825 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* bucket[j] */
2831 /*printf("Ending index value = %d\n",idx-1); */
2833 /* copy CM operations timings */
2835 srcbuf = (afs_int32 *) (fullP->rpc.cmRPCTimes);
2836 for (i = 0; i < AFS_STATS_NUM_CM_RPC_OPS; i++) {
2837 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* numOps */
2840 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* numSuccesses */
2843 tmpbuf = srcbuf++; /* sum time */
2844 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2847 tmpbuf = srcbuf++; /* sqr time */
2848 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2851 tmpbuf = srcbuf++; /* min time */
2852 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2855 tmpbuf = srcbuf++; /* max time */
2856 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2861 /*printf("Ending index value = %d\n",idx-1); */
2863 /* copy authentication info */
2865 srcbuf = (afs_int32 *) & (fullP->authent);
2866 numLongs = sizeof(struct afs_stats_AuthentInfo) / sizeof(afs_int32);
2867 for (i = 0; i < numLongs; i++) {
2868 sprintf(a_cmData->data[idx], "%d", *srcbuf);
2873 /*printf("Ending index value = %d\n",idx-1); */
2875 /* copy CM [un]replicated access info */
2877 srcbuf = (afs_int32 *) & (fullP->accessinf);
2878 numLongs = sizeof(struct afs_stats_AccessInfo) / sizeof(afs_int32);
2879 for (i = 0; i < numLongs; i++) {
2880 sprintf(a_cmData->data[idx], "%d", *srcbuf);
2885 /*printf("Ending index value = %d\n",idx-1); */
2888 } /* cm_Results_ltoa */
2891 /*-----------------------------------------------------------------------
2892 * Function: check_cm_thresholds()
2895 * Checks the thresholds and sets the overflow flag. Recall that the
2896 * thresholds for each host are stored in the hostEntry lists
2897 * [fs/cm]nameList arrays. The probe results are passed to this
2898 * function in the display-ready format - ie., as strings. Though
2899 * this looks stupid the overhead incurred in converting the strings
2900 * back to floats and comparing them is insignificant and
2901 * programming is easier this way.
2902 * The threshold flags are a part of the display structures
2907 *----------------------------------------------------------------------*/
2910 check_cm_thresholds(struct afsmon_hostEntry *a_hostEntry, /* ptr to hostEntry */
2911 struct cm_Display_Data *a_Data) /* ptr to cm data to be displayed */
2912 { /* check_cm_thresholds */
2914 static char rn[] = "check_cm_thresholds";
2915 struct Threshold *threshP;
2916 double tValue; /* threshold value */
2917 double pValue; /* probe value */
2920 int count; /* number of thresholds exceeded */
2923 fprintf(debugFD, "[ %s ] Called, a_hostEntry= %p, a_Data= %p\n", rn,
2924 a_hostEntry, a_Data);
2928 if (a_hostEntry->numThresh == 0) {
2929 /* store in ovf count ?? */
2934 threshP = a_hostEntry->thresh;
2935 for (i = 0; i < a_hostEntry->numThresh; i++) {
2936 if (threshP->itemName[0] == '\0') {
2940 idx = threshP->index; /* positional index to the data array */
2941 tValue = atof(threshP->threshVal); /* threshold value */
2942 pValue = atof(a_Data->data[idx]); /* probe value */
2943 if (pValue > tValue) {
2947 "[ %s ] cm = %s, thresh ovf for %s, threshold= %s, probevalue= %s\n",
2948 rn, a_hostEntry->hostName, threshP->itemName,
2949 threshP->threshVal, a_Data->data[idx]);
2953 /* if the threshold is crossed, call the handler function
2954 * only if this was a transition -ie, if the threshold was
2955 * crossed in the last probe too just count & keep quite! */
2957 if (!a_Data->threshOvf[idx]) {
2958 a_Data->threshOvf[idx] = 1;
2959 /* call the threshold handler if provided */
2960 if (threshP->handler[0] != '\0') {
2962 fprintf(debugFD, "[ %s ] Calling ovf handler %s\n",
2963 rn, threshP->handler);
2966 execute_thresh_handler(threshP->handler, a_Data->hostName,
2967 CM, threshP->itemName,
2975 /* in case threshold was previously crossed, blank it out */
2976 a_Data->threshOvf[idx] = 0;
2979 /* store the overflow count */
2980 a_Data->ovfCount = count;
2983 } /* check_cm_thresholds */
2986 /*-----------------------------------------------------------------------
2987 * save_CM_data_forDisplay()
2990 * Does the following:
2991 * - if the probe number changed (ie, a cycle completed) curr_cmData
2992 * is copied to prev_cmData, curr_cmData zeroed and refresh the
2993 * overview screen and file server screen with the new data.
2994 * - store the results of the current probe from xstat_cm_Results into
2995 * curr_cmData. ie., convert longs to strings.
2996 * - check the thresholds
3000 * Failure: Exits afsmonitor.
3002 *----------------------------------------------------------------------*/
3005 save_CM_data_forDisplay(struct xstat_cm_ProbeResults *a_cmResults)
3006 { /* save_CM_data_forDisplay */
3008 static char rn[] = "save_CM_data_forDisplay"; /* routine name */
3009 struct cm_Display_Data *curr_cmDataP;
3010 struct cm_Display_Data *prev_cmDataP;
3011 struct afsmon_hostEntry *curr_host;
3012 static int results_Received = 0; /* number of probes reveived in
3013 * the current cycle. If this is equal to numFS we got all
3014 * the data we want in this cycle and can now display it */
3022 fprintf(debugFD, "[ %s ] Called, a_cmResults= %p\n", rn, a_cmResults);
3026 /* store results in the display array */
3029 curr_cmDataP = curr_cmData;
3030 for (i = 0; i < numCM; i++) {
3031 if ((strcasecmp(curr_cmDataP->hostName, a_cmResults->connP->hostName))
3041 "[ %s ] Could not insert CM probe results for host %s in cm display array\n",
3042 rn, a_cmResults->connP->hostName);
3046 /* Check the status of the probe. If it succeeded, we store its
3047 * results in the display data structure. If it failed we only mark
3048 * the failed status in the display data structure. */
3051 if (a_cmResults->probeOK) { /* 1 => notOK the xstat results */
3052 curr_cmDataP->probeOK = 0;
3054 /* print the probe status */
3056 fprintf(debugFD, "\n\t\t ----- cm display data ------\n");
3057 fprintf(debugFD, "HostName = %s PROBE FAILED \n",
3058 curr_cmDataP->hostName);
3062 } else { /* probe succeeded, update display data structures */
3063 curr_cmDataP->probeOK = 1;
3066 /* covert longs to strings and place them in curr_cmDataP */
3067 cm_Results_ltoa(curr_cmDataP, a_cmResults);
3069 /* compare with thresholds and set the overflow flags.
3070 * note that the threshold information is in the hostEntry structure and
3071 * each threshold item has a positional index associated with it */
3073 /* locate the hostEntry for this host */
3075 curr_host = CMnameList;
3076 for (i = 0; i < numCM; i++) {
3077 if (strcasecmp(curr_host->hostName, a_cmResults->connP->hostName)
3082 curr_host = curr_host->next;
3087 code = check_cm_thresholds(curr_host, curr_cmDataP);
3089 fprintf(stderr, "[ %s ] Error in checking thresholds\n", rn);
3093 /* print the info we just saved */
3095 fprintf(debugFD, "\n\t\t ----- CM display data ------\n");
3096 fprintf(debugFD, "HostName = %s\n", curr_cmDataP->hostName);
3097 for (i = 0; i < NUM_CM_STAT_ENTRIES; i++) {
3100 fprintf(debugFD, "\t -- Overall Perf Info --\n");
3104 "\t -- File Server up/down stats - same cell --\n");
3108 "\t -- File Server up/down stats - diff cell --\n");
3112 "\t -- VL server up/down stats - same cell --\n");
3116 "\t -- VL server up/down stats - diff cell --\n");
3119 fprintf(debugFD, "\t -- FS Operation Timings --\n");
3122 fprintf(debugFD, "\t -- FS Error Info --\n");
3125 fprintf(debugFD, "\t -- FS Transfer Timings --\n");
3128 fprintf(debugFD, "\t -- CM Operations Timings --\n");
3131 fprintf(debugFD, "\t -- Authentication Info --\n");
3134 fprintf(debugFD, "\t -- Access Info --\n");
3140 fprintf(debugFD, "%20s %30s %s\n", curr_cmDataP->data[i],
3142 curr_cmDataP->threshOvf[i] ? "(ovf)" : "");
3144 fprintf(debugFD, "\t\t--------------------------------\n\n");
3147 } /* if the probe succeeded, update the display data structures */
3149 /* if we have received a reply from all the hosts for this probe cycle,
3150 * it is time to display the data */
3153 if (results_Received == numCM * num_cm_collections) {
3154 results_Received = 0;
3156 if (afsmon_cm_curr_probeNum != afsmon_cm_prev_probeNum + 1) {
3157 sprintf(errMsg, "[ %s ] Probe number %d missed! \n", rn,
3158 afsmon_cm_prev_probeNum + 1);
3161 afsmon_cm_prev_probeNum++;
3164 /* backup the display data of the probe cycle that just completed -
3165 * ie., store curr_cmData in prev_cmData */
3167 memcpy((char *)prev_cmData, (char *)curr_cmData,
3168 (numCM * sizeof(struct cm_Display_Data)));
3171 /* initialize curr_cmData but retain the threshold flag information.
3172 * The previous state of threshold flags is used in check_cm_thresholds() */
3174 curr_cmDataP = curr_cmData;
3175 numBytes = NUM_CM_STAT_ENTRIES * CM_STAT_STRING_LEN;
3176 for (i = 0; i < numCM; i++) {
3177 curr_cmDataP->probeOK = 0;
3178 curr_cmDataP->ovfCount = 0;
3179 memset(curr_cmDataP->data, 0, numBytes);
3183 /* prev_cmData now contains all the information for the probe cycle
3184 * that just completed. Now count the number of threshold overflows for
3185 * use in the overview screen */
3187 prev_cmDataP = prev_cmData;
3189 numHosts_oncm_alerts = 0;
3190 for (i = 0; i < numCM; i++) {
3191 if (!prev_cmDataP->probeOK) { /* if probe failed */
3193 numHosts_oncm_alerts++;
3194 } else if (prev_cmDataP->ovfCount) { /* overflows ?? */
3195 num_cm_alerts += prev_cmDataP->ovfCount;
3196 numHosts_oncm_alerts++;
3201 fprintf(debugFD, "Number of CM alerts = %d (on %d hosts)\n",
3202 num_cm_alerts, numHosts_oncm_alerts);
3205 /* flag that the data is now ready to be displayed */
3206 cm_Data_Available = 1;
3208 /* update the Overview frame (only CM info) */
3209 ovw_refresh(ovw_currPage, OVW_UPDATE_CM);
3211 /* update the Cache Managers frame */
3212 cm_refresh(cm_currPage, cm_curr_LCol);
3218 } /* save_CM_data_forDisplay */
3222 /*-----------------------------------------------------------------------
3223 * afsmon_CM_Handler()
3226 * This is the Cache Manager probe Handler. It updates the afsmonitor
3227 * probe counts, cm circular buffer indices and calls the functions
3228 * to process the results of this probe.
3232 * Failure: Exits afsmonitor.
3233 *----------------------------------------------------------------------*/
3236 afsmon_CM_Handler(void)
3237 { /* afsmon_CM_Handler() */
3238 static char rn[] = "afsmon_CM_Handler"; /* routine name */
3239 int code; /* return status */
3240 int newProbeCycle; /* start of new probe cycle ? */
3244 "[ %s ] Called, hostName= %s, probeNum= %d, status= %s\n", rn,
3245 xstat_cm_Results.connP->hostName, xstat_cm_Results.probeNum,
3246 xstat_cm_Results.probeOK ? "FAILED" : "OK");
3251 /* print the probe results to output file */
3252 if (afsmon_output) {
3253 code = afsmon_cmOutput(output_filename, afsmon_detOutput);
3256 "[ %s ] output to file %s returned error code=%d\n", rn,
3257 output_filename, code);
3261 /* Update current probe number and circular buffer index. if current
3262 * probenum changed make sure it is only by 1 */
3265 if (xstat_cm_Results.probeNum != afsmon_cm_curr_probeNum) {
3266 if (xstat_cm_Results.probeNum == afsmon_cm_curr_probeNum + 1) {
3267 afsmon_cm_curr_probeNum++;
3270 afsmon_cm_curr_CBindex =
3271 (afsmon_cm_curr_probeNum - 1) % num_bufSlots;
3273 fprintf(stderr, "[ %s ] probe number %d-1 missed\n", rn,
3274 xstat_cm_Results.probeNum);
3279 /* save the results of this probe in the CM buffer */
3281 save_CM_results_inCB(newProbeCycle);
3283 /* store the results of the current probe in the cm data display structure.
3284 * if the current probe number changed, swap the current and previous display
3285 * structures. note that the display screen is updated from these structures
3286 * and should start showing the data of the just completed probe cycle */
3288 save_CM_data_forDisplay(&xstat_cm_Results);
3293 /*-----------------------------------------------------------------------
3297 * Allocate and Initialize circular buffers for file servers.
3301 * Failure to allocate memory: exits afsmonitor.
3302 *----------------------------------------------------------------------*/
3305 init_fs_buffers(void)
3306 { /* init_fs_buffers() */
3307 static char rn[] = "init_fs_buffers"; /* routine name */
3308 struct afsmon_fs_Results_list *new_fslist_item; /* ptr for new struct */
3309 struct afsmon_fs_Results_list *tmp_fslist_item; /* temp ptr */
3310 struct xstat_fs_ProbeResults *new_fsPR; /* ptr for new struct */
3317 fprintf(debugFD, "[ %s ] Called\n", rn);
3321 /* allocate memory for the circular buffer of pointers */
3323 afsmon_fs_ResultsCB = (struct afsmon_fs_Results_CBuffer *)
3324 malloc(sizeof(struct afsmon_fs_Results_CBuffer) * num_bufSlots);
3326 /* initialize the fs circular buffer */
3327 for (i = 0; i < num_bufSlots; i++) {
3328 afsmon_fs_ResultsCB[i].list = (struct afsmon_fs_Results_list *)0;
3329 afsmon_fs_ResultsCB[i].probeNum = 0;
3332 /* create a list of numFS items to store fs probe results for
3333 * each slot in CB */
3335 if (numFS) { /* if we have file servers to monitor */
3336 for (bufslot = 0; bufslot < num_bufSlots; bufslot++) {
3337 numfs = numFS; /* get the number of servers */
3340 /* if any of these mallocs fail we only need to free the memory we
3341 * have allocated in this iteration. the rest of it which is in a
3342 * proper linked list will be freed in afsmon_Exit */
3344 /* allocate memory for an fs list item */
3345 new_fslist_item = (struct afsmon_fs_Results_list *)
3346 malloc(sizeof(struct afsmon_fs_Results_list));
3347 if (new_fslist_item == (struct afsmon_fs_Results_list *)0)
3350 for (i = 0; i < MAX_NUM_FS_COLLECTIONS; i++) {
3351 /* allocate memory to store xstat_fs_Results */
3352 new_fsPR = (struct xstat_fs_ProbeResults *)
3353 malloc(sizeof(struct xstat_fs_ProbeResults));
3355 free(new_fslist_item);
3359 new_fsPR->connP = (struct xstat_fs_ConnectionInfo *)
3360 malloc(sizeof(struct xstat_fs_ConnectionInfo));
3361 if (new_fsPR->connP == (struct xstat_fs_ConnectionInfo *)0) {
3362 free(new_fslist_item);
3367 /* >>> need to allocate rx connection info structure here <<< */
3368 new_fsPR->data.AFS_CollData_val = (afs_int32 *)
3369 malloc(afsmon_fs_results_length[i] * sizeof(afs_int32));
3370 if (new_fsPR->data.AFS_CollData_val == NULL) {
3371 free(new_fslist_item);
3372 free(new_fsPR->connP);
3376 new_fslist_item->fsResults[i] = new_fsPR;
3377 new_fslist_item->empty[i] = 1;
3380 /* initialize this list entry */
3381 new_fslist_item->next = (struct afsmon_fs_Results_list *)0;
3383 /* store it at the end of the fs list in the current CB slot */
3384 if (afsmon_fs_ResultsCB[bufslot].list ==
3385 (struct afsmon_fs_Results_list *)0)
3386 afsmon_fs_ResultsCB[bufslot].list = new_fslist_item;
3388 tmp_fslist_item = afsmon_fs_ResultsCB[bufslot].list;
3390 while (tmp_fslist_item !=
3391 (struct afsmon_fs_Results_list *)0) {
3392 if (tmp_fslist_item->next ==
3393 (struct afsmon_fs_Results_list *)0)
3395 tmp_fslist_item = tmp_fslist_item->next;
3397 /* something goofed. exit */
3398 fprintf(stderr, "[ %s ] list creation error\n",
3403 tmp_fslist_item->next = new_fslist_item;
3406 } /* while servers */
3407 } /* for each buffer slot */
3408 } /* if we have file servers to monitor */
3412 /*-----------------------------------------------------------------------
3416 * Allocate and Initialize circular buffers for cache managers.
3420 * Failure to allocate memory: exits afsmonitor.
3421 *----------------------------------------------------------------------*/
3424 init_cm_buffers(void)
3425 { /* init_cm_buffers() */
3426 static char rn[] = "init_cm_buffers"; /* routine name */
3427 struct afsmon_cm_Results_list *new_cmlist_item; /* ptr for new struct */
3428 struct afsmon_cm_Results_list *tmp_cmlist_item; /* temp ptr */
3429 struct xstat_cm_ProbeResults *new_cmPR; /* ptr for new struct */
3435 fprintf(debugFD, "[ %s ] Called\n", rn);
3439 /* allocate memory for the circular buffer of pointers */
3440 afsmon_cm_ResultsCB = (struct afsmon_cm_Results_CBuffer *)
3441 malloc(sizeof(struct afsmon_cm_Results_CBuffer) * num_bufSlots);
3443 /* initialize the fs circular buffer */
3444 for (i = 0; i < num_bufSlots; i++) {
3445 afsmon_cm_ResultsCB[i].list = (struct afsmon_cm_Results_list *)0;
3446 afsmon_cm_ResultsCB[i].probeNum = 0;
3449 /* create a list of numCM items to store fs probe results for
3450 * each slot in CB */
3452 if (numCM) { /* if we have file servers to monitor */
3453 for (bufslot = 0; bufslot < num_bufSlots; bufslot++) {
3454 numcm = numCM; /* get the number of servers */
3457 /* if any of these mallocs fail we only need to free the memory we
3458 * have allocated in this iteration. the rest of it which is in a
3459 * proper linked list will be freed in afsmon_Exit */
3461 /* allocate memory for an fs list item */
3462 new_cmlist_item = (struct afsmon_cm_Results_list *)
3463 malloc(sizeof(struct afsmon_cm_Results_list));
3464 if (new_cmlist_item == (struct afsmon_cm_Results_list *)0)
3467 for (i = 0; i < MAX_NUM_CM_COLLECTIONS; i++) {
3468 /* allocate memory to store xstat_cm_Results */
3469 new_cmPR = (struct xstat_cm_ProbeResults *)
3470 malloc(sizeof(struct xstat_cm_ProbeResults));
3472 free(new_cmlist_item);
3475 new_cmPR->connP = (struct xstat_cm_ConnectionInfo *)
3476 malloc(sizeof(struct xstat_cm_ConnectionInfo));
3477 if (!new_cmPR->connP) {
3478 free(new_cmlist_item);
3483 /* >>> need to allocate rx connection info structure here <<< */
3485 new_cmPR->data.AFSCB_CollData_val =
3486 malloc(XSTAT_CM_FULLPERF_RESULTS_LEN
3487 *sizeof(afs_int32));
3488 if (new_cmPR->data.AFSCB_CollData_val == NULL) {
3489 free(new_cmlist_item);
3490 free(new_cmPR->connP);
3495 new_cmlist_item->cmResults[i] = new_cmPR;
3496 new_cmlist_item->empty[i] = 1;
3499 /* initialize this list entry */
3500 new_cmlist_item->next = (struct afsmon_cm_Results_list *)0;
3502 /* store it at the end of the cm list in the current CB slot */
3503 if (afsmon_cm_ResultsCB[bufslot].list ==
3504 (struct afsmon_cm_Results_list *)0)
3505 afsmon_cm_ResultsCB[bufslot].list = new_cmlist_item;
3507 tmp_cmlist_item = afsmon_cm_ResultsCB[bufslot].list;
3509 while (tmp_cmlist_item !=
3510 (struct afsmon_cm_Results_list *)0) {
3511 if (tmp_cmlist_item->next ==
3512 (struct afsmon_cm_Results_list *)0)
3514 tmp_cmlist_item = tmp_cmlist_item->next;
3516 /* something goofed. exit */
3517 fprintf(stderr, "[ %s ] list creation error\n",
3522 tmp_cmlist_item->next = new_cmlist_item;
3525 } /* while servers */
3526 } /* for each buffer slot */
3528 /* if we have file servers to monitor */
3529 /* print the CB to make sure it is right */
3533 } /* init_cm_buffers() */
3536 /*-------------------------------------------------------------------------
3537 * init_print_buffers()
3540 * Allocate and initialize the buffers used for printing results
3541 * to the display screen. These buffers store the current and
3542 * previous probe results in ascii format.
3547 *------------------------------------------------------------------------*/
3550 init_print_buffers(void)
3551 { /* init_print_buffers */
3553 static char rn[] = "init_print_buffers"; /* routine name */
3554 struct fs_Display_Data *tmp_fsData1; /* temp pointers */
3555 struct fs_Display_Data *tmp_fsData2;
3556 struct cm_Display_Data *tmp_cmData1;
3557 struct cm_Display_Data *tmp_cmData2;
3558 struct afsmon_hostEntry *tmp_fsNames;
3559 struct afsmon_hostEntry *tmp_cmNames;
3564 fprintf(debugFD, "[ %s ] Called\n", rn);
3568 /* allocate numFS blocks of the FS print structure. */
3570 /* we need two instances of this structure - one (curr_fsData) for storing
3571 * the results of the fs probes currently in progress and another (prev_fsData)
3572 * for the last completed probe. The display is updated from the contents of
3573 * prev_fsData. The pointers curr_fsData & prev_fsData are switched whenever
3574 * the probe number changes */
3577 numBytes = numFS * sizeof(struct fs_Display_Data);
3578 curr_fsData = malloc(numBytes);
3579 if (curr_fsData == (struct fs_Display_Data *)0) {
3580 fprintf(stderr, "[ %s ] Memory allocation failure\n", rn);
3583 memset(curr_fsData, 0, numBytes);
3585 numBytes = numFS * sizeof(struct fs_Display_Data);
3586 prev_fsData = malloc(numBytes);
3587 if (prev_fsData == (struct fs_Display_Data *)0) {
3588 fprintf(stderr, "[ %s ] Memory allocation failure\n", rn);
3591 memset(prev_fsData, 0, numBytes);
3593 /* fill in the host names */
3594 tmp_fsData1 = curr_fsData;
3595 tmp_fsData2 = curr_fsData;
3596 tmp_fsNames = FSnameList;
3597 for (i = 0; i < numFS; i++) {
3598 strncpy(tmp_fsData1->hostName, tmp_fsNames->hostName,
3600 strncpy(tmp_fsData2->hostName, tmp_fsNames->hostName,
3604 tmp_fsNames = tmp_fsNames->next;;
3609 /* if file servers to monitor */
3610 /* allocate numCM blocks of the CM print structure */
3611 /* we need two instances of this structure for the same reasons as above */
3613 numBytes = numCM * sizeof(struct cm_Display_Data);
3615 curr_cmData = malloc(numBytes);
3616 if (curr_cmData == (struct cm_Display_Data *)0) {
3617 fprintf(stderr, "[ %s ] Memory allocation failure\n", rn);
3620 memset(curr_cmData, 0, numBytes);
3622 numBytes = numCM * sizeof(struct cm_Display_Data);
3623 prev_cmData = malloc(numBytes);
3624 if (prev_cmData == (struct cm_Display_Data *)0) {
3625 fprintf(stderr, "[ %s ] Memory allocation failure\n", rn);
3628 memset(prev_cmData, 0, numBytes);
3630 /* fill in the host names */
3631 tmp_cmData1 = curr_cmData;
3632 tmp_cmData2 = curr_cmData;
3633 tmp_cmNames = CMnameList;
3634 for (i = 0; i < numCM; i++) {
3635 strncpy(tmp_cmData1->hostName, tmp_cmNames->hostName,
3637 strncpy(tmp_cmData2->hostName, tmp_cmNames->hostName,
3641 tmp_cmNames = tmp_cmNames->next;;
3645 /* if cache managers to monitor */
3648 } /* init_print_buffers */
3650 /*-----------------------------------------------------------------------
3654 * Trap the interrupt signal. This function is useful only until
3655 * gtx is initialized.
3656 *----------------------------------------------------------------------*/
3659 quit_signal(int sig)
3661 fprintf(stderr, "Received signal %d \n", sig);
3667 /*-----------------------------------------------------------------------
3671 * This is where we start it all. Initialize an array of sockets for
3672 * file servers and cache cache managers and call the xstat_[fs/cm]_Init
3673 * routines. The last step is to call the gtx input server which
3674 * grabs control of the keyboard.
3677 * Does not return. Control is periodically returned to the afsmonitor
3678 * thru afsmon_[FS/CM]_Handler() routines and also through the gtx
3679 * keyboard handler calls.
3681 *----------------------------------------------------------------------*/
3684 afsmon_execute(void)
3685 { /* afsmon_execute() */
3686 static char rn[] = "afsmon_execute"; /* routine name */
3687 static char fullhostname[128]; /* full host name */
3688 struct sockaddr_in *FSSktArray; /* fs socket array */
3689 int FSsktbytes; /* num bytes in above */
3690 struct sockaddr_in *CMSktArray; /* cm socket array */
3691 int CMsktbytes; /* num bytes in above */
3692 struct sockaddr_in *curr_skt; /* ptr to current socket */
3693 struct afsmon_hostEntry *curr_FS; /* ptr to FS name list */
3694 struct afsmon_hostEntry *curr_CM; /* ptr to CM name list */
3695 struct hostent *he; /* host entry */
3696 int FSinitFlags = 0; /* flags for xstat_fs_Init */
3697 int CMinitFlags = 0; /* flags for xstat_cm_Init */
3698 int code; /* function return code */
3699 struct timeval tv; /* time structure */
3704 fprintf(debugFD, "[ %s ] Called\n", rn);
3709 /* process file server entries */
3711 afs_int32 collIDs[MAX_NUM_FS_COLLECTIONS];
3713 /* Allocate an array of sockets for each fileserver we monitor */
3715 FSsktbytes = numFS * sizeof(struct sockaddr_in);
3716 FSSktArray = malloc(FSsktbytes);
3717 if (FSSktArray == (struct sockaddr_in *)0) {
3719 "[ %s ] cannot malloc %d sockaddr_ins for fileservers\n",
3724 memset(FSSktArray, 0, FSsktbytes);
3726 /* Fill in the socket information for each fileserve */
3728 curr_skt = FSSktArray;
3729 curr_FS = FSnameList; /* FS name list header */
3731 strncpy(fullhostname, curr_FS->hostName, sizeof(fullhostname));
3732 he = GetHostByName(fullhostname);
3734 fprintf(stderr, "[ %s ] Cannot get host info for %s\n", rn,
3738 strncpy(curr_FS->hostName, he->h_name, HOST_NAME_LEN); /* complete name */
3739 memcpy(&(curr_skt->sin_addr.s_addr), he->h_addr, 4);
3740 curr_skt->sin_family = AF_INET; /*Internet family */
3741 curr_skt->sin_port = htons(7000); /*FileServer port */
3742 #ifdef STRUCT_SOCKADDR_HAS_SA_LEN
3743 curr_skt->sin_len = sizeof(struct sockaddr_in);
3746 /* get the next dude */
3748 curr_FS = curr_FS->next;
3751 /* Initialize collection IDs, depending on the data requested. */
3752 num_fs_collections = 0;
3753 for (i = 0; i < fs_DisplayItems_count; i++) {
3754 index = fs_Display_map[i];
3755 if (FS_FULLPERF_ENTRY_START <= index && index <= FS_FULLPERF_ENTRY_END) {
3756 collIDs[num_fs_collections++] = AFS_XSTATSCOLL_FULL_PERF_INFO;
3760 for (i = 0; i < fs_DisplayItems_count; i++) {
3761 index = fs_Display_map[i];
3762 if (FS_CB_ENTRY_START <= index && index <= FS_CB_ENTRY_END) {
3763 collIDs[num_fs_collections++] = AFS_XSTATSCOLL_CBSTATS;
3769 if (afsmon_onceOnly) /* option not provided at this time */
3770 FSinitFlags |= XSTAT_FS_INITFLAG_ONE_SHOT;
3773 fprintf(debugFD, "[ %s ] Calling xstat_fs_Init \n", rn);
3777 code = xstat_fs_Init(numFS, /*Num servers */
3778 FSSktArray, /*File Server socket array */
3779 afsmon_probefreq, /*probe frequency */
3780 afsmon_FS_Handler, /*Handler routine */
3781 FSinitFlags, /*Initialization flags */
3782 num_fs_collections, /*Number of collection IDs */
3783 collIDs); /*Ptr to collection ID */
3786 fprintf(stderr, "[ %s ] xstat_fs_init returned error\n", rn);
3793 /* end of process fileserver entries */
3794 /* process cache manager entries */
3796 afs_int32 collIDs[MAX_NUM_CM_COLLECTIONS];
3798 /* Allocate an array of sockets for each cache manager we monitor */
3800 CMsktbytes = numCM * sizeof(struct sockaddr_in);
3801 CMSktArray = malloc(CMsktbytes);
3802 if (CMSktArray == (struct sockaddr_in *)0) {
3804 "[ %s ] cannot malloc %d sockaddr_ins for CM entries\n",
3809 memset(CMSktArray, 0, CMsktbytes);
3811 /* Fill in the socket information for each CM */
3813 curr_skt = CMSktArray;
3814 curr_CM = CMnameList; /* CM name list header */
3816 strncpy(fullhostname, curr_CM->hostName, sizeof(fullhostname));
3817 he = GetHostByName(fullhostname);
3819 fprintf(stderr, "[ %s ] Cannot get host info for %s\n", rn,
3823 strncpy(curr_CM->hostName, he->h_name, HOST_NAME_LEN); /* complete name */
3824 memcpy(&(curr_skt->sin_addr.s_addr), he->h_addr, 4);
3825 curr_skt->sin_family = AF_INET;
3826 curr_skt->sin_port = htons(7001); /* Cache Manager port */
3827 #ifdef STRUCT_SOCKADDR_HAS_SA_LEN
3828 curr_skt->sin_len = sizeof(struct sockaddr_in);
3831 /* get the next dude */
3833 curr_CM = curr_CM->next;
3836 /* initialize collection IDs. We need only one entry since we collect
3837 * all the information from xstat */
3838 num_cm_collections = 0;
3839 collIDs[num_cm_collections++] = AFSCB_XSTATSCOLL_FULL_PERF_INFO;
3842 if (afsmon_onceOnly) /* once only ? */
3843 CMinitFlags |= XSTAT_CM_INITFLAG_ONE_SHOT;
3846 fprintf(debugFD, "[ %s ] Calling xstat_cm_Init \n", rn);
3850 code = xstat_cm_Init(numCM, /*Num servers */
3851 CMSktArray, /*Cache Manager socket array */
3852 afsmon_probefreq, /*probe frequency */
3853 afsmon_CM_Handler, /*Handler routine */
3854 CMinitFlags, /*Initialization flags */
3855 num_cm_collections, /*Number of collection IDs */
3856 collIDs); /*Ptr to collection ID */
3859 fprintf(stderr, "[ %s ] xstat_cm_init returned error\n", rn);
3866 /* end of process cache manager entries */
3867 /* if only one probe was required setup a waiting process for the
3868 * termination signal */
3869 if (afsmon_onceOnly) {
3870 code = LWP_WaitProcess(&terminationEvent);
3873 fprintf(debugFD, "LWP_WaitProcess() returned error %d\n",
3881 /* start the gtx input server */
3882 code = (intptr_t)gtx_InputServer(afsmon_win);
3884 fprintf(stderr, "[ %s ] Failed to start input server \n", rn);
3888 /* This part of the code is reached only if the input server is not started
3889 * for debugging purposes */
3892 tv.tv_sec = 24 * 60;
3894 fprintf(stderr, "[ %s ] going to sleep ...\n", rn);
3896 code = IOMGR_Select(0, /*Num fds */
3897 0, /*Descriptors ready for reading */
3898 0, /*Descriptors ready for writing */
3899 0, /*Descriptors with exceptional conditions */
3900 &tv); /*Timeout structure */
3903 "[ %s ] IOMGR_Select() returned non-zero value %d\n", rn,
3911 /*-----------------------------------------------------------------------
3915 * Afsmonitor initialization routine.
3916 * - processes command line parameters
3917 * - call functions to:
3918 * - process config file
3919 * - initialize circular buffers and display buffers
3921 * - execute afsmonitor
3922 * - initialize the display maps [fs/cm]_Display_map[].
3925 * Success: Does not return from the call to afsmon_execute().
3926 * Failure: Exits afsmonitor.
3927 *----------------------------------------------------------------------*/
3930 afsmonInit(struct cmd_syndesc *as, void *arock)
3931 { /* afsmonInit() */
3933 static char rn[] = "afsmonInit"; /* Routine name */
3934 char *debug_filename; /* pointer to debug filename */
3935 FILE *outputFD; /* output file descriptor */
3936 struct cmd_item *hostPtr; /* ptr to parse command line args */
3937 char buf[256]; /* buffer for processing hostnames */
3942 fprintf(debugFD, "[ %s ] Called, as= %p\n", rn, as);
3946 /* Open the debug file if -debug option is specified */
3947 if (as->parms[P_DEBUG].items != 0) {
3949 debug_filename = as->parms[P_DEBUG].items->data;
3950 debugFD = fopen(debug_filename, "w");
3951 if (debugFD == (FILE *) 0) {
3952 printf("[ %s ] Failed to open debugging file %s for writing\n",
3960 fprintf(debugFD, "[ %s ] Called\n", rn);
3964 /* use curses always until we support other packages */
3966 wpkg_to_use = atoi(as->parms[P_PACKAGE].items->data);
3968 switch (wpkg_to_use) {
3969 case GATOR_WIN_CURSES:
3970 fprintf(stderr, "curses\n");
3972 case GATOR_WIN_DUMB:
3973 fprintf(stderr, "dumb terminal\n");
3976 fprintf(stderr, "X11\n");
3979 fprintf(stderr, "Illegal graphics package: %d\n", wpkg_to_use);
3981 } /*end switch (wpkg_to_use) */
3984 wpkg_to_use = GATOR_WIN_CURSES;
3986 /* get probe frequency . We check for meaningful bounds on the frequency
3987 * and reset to the default value if needed. The upper bound of 24
3988 * hours looks ridiculous though! */
3990 afsmon_probefreq = 0;
3991 if (as->parms[P_FREQUENCY].items != 0)
3992 afsmon_probefreq = atoi(as->parms[P_FREQUENCY].items->data);
3994 afsmon_probefreq = DEFAULT_FREQUENCY;
3996 if (afsmon_probefreq <= 0 || afsmon_probefreq > 24 * 60 * 60) {
3997 afsmon_probefreq = DEFAULT_FREQUENCY;
4000 "[ %s ] Invalid probe frequency %s specified, resetting to default value %d seconds\n",
4001 rn, as->parms[P_FREQUENCY].items->data, afsmon_probefreq);
4005 "Invalid probe frequency %s specified, resetting to default value %d seconds\n",
4006 as->parms[P_FREQUENCY].items->data, afsmon_probefreq);
4011 /* make sure output file is writable, else complain now */
4012 /* we will open and close it as needed after probes */
4014 if (as->parms[P_OUTPUT].items != 0) {
4015 afsmon_output = 1; /* output flag */
4016 strncpy(output_filename, as->parms[P_OUTPUT].items->data, 80);
4017 outputFD = fopen(output_filename, "a");
4018 if (outputFD == (FILE *) 0) {
4019 fprintf(stderr, "Failed to open output file %s \n",
4022 fprintf(debugFD, "[ %s ] Failed to open output file %s \n",
4023 rn, output_filename);
4028 fprintf(debugFD, "[ %s ] output file is %s\n", rn,
4034 /* detailed statistics to storage file */
4035 if (as->parms[P_DETAILED].items != 0) {
4036 if (as->parms[P_OUTPUT].items == 0) {
4038 "-detailed switch can be used only with -output\n");
4041 afsmon_detOutput = 1;
4044 /* Initialize host list headers */
4045 FSnameList = (struct afsmon_hostEntry *)0;
4046 CMnameList = (struct afsmon_hostEntry *)0;
4048 /* The -config option is mutually exclusive with the -fshosts,-cmhosts
4051 if (as->parms[P_CONFIG].items) {
4052 if (as->parms[P_FSHOSTS].items || as->parms[P_CMHOSTS].items) {
4054 "Cannot use -config option with -fshosts or -cmhosts\n");
4058 if (!as->parms[P_FSHOSTS].items && !as->parms[P_CMHOSTS].items) {
4060 "Must specify either -config or (-fshosts and/or -cmhosts) options \n");
4066 /* If a file server host is specified on the command line we reuse
4067 * parse_hostEntry() function . Just the pass the info as if it were
4068 * read off the config file */
4070 if (as->parms[P_FSHOSTS].items) {
4071 hostPtr = as->parms[P_FSHOSTS].items;
4072 while (hostPtr != (struct cmd_item *)0) {
4073 sprintf(buf, "fs %s", hostPtr->data);
4074 code = parse_hostEntry(buf);
4076 fprintf(stderr, "Could not parse %s\n", hostPtr->data);
4080 hostPtr = hostPtr->next;
4084 /* same as above for -cmhosts */
4085 if (as->parms[P_CMHOSTS].items) {
4086 hostPtr = as->parms[P_CMHOSTS].items;
4087 while (hostPtr != (struct cmd_item *)0) {
4088 sprintf(buf, "cm %s", hostPtr->data);
4089 code = parse_hostEntry(buf);
4091 fprintf(stderr, "Could not parse %s\n", hostPtr->data);
4095 hostPtr = hostPtr->next;
4099 /* number of slots in circular buffers */
4100 if (as->parms[P_BUFFERS].items)
4101 num_bufSlots = atoi(as->parms[P_BUFFERS].items->data);
4103 num_bufSlots = DEFAULT_BUFSLOTS;
4105 /* Initialize xx_showFlags[]. This array is used solely for processing the
4106 * "show" directives in the config file in parse_showEntries() */
4107 for (i = 0; i < NUM_FS_STAT_ENTRIES; i++)
4108 fs_showFlags[i] = 0;
4109 for (i = 0; i < NUM_CM_STAT_ENTRIES; i++)
4110 cm_showFlags[i] = 0;
4113 /* Process the configuration file if given. This initializes among other
4114 * things, the list of FS & CM names in FSnameList and CMnameList */
4116 if (as->parms[P_CONFIG].items)
4117 process_config_file(as->parms[P_CONFIG].items->data);
4119 /* print out the FS and CM lists */
4123 /* Initialize the FS results-to-screen map array if there were no "show fs"
4124 * directives in the config file */
4125 if (fs_showDefault) {
4126 for (i = 0; i < NUM_FS_STAT_ENTRIES; i++)
4127 fs_Display_map[i] = i;
4128 fs_DisplayItems_count = NUM_FS_STAT_ENTRIES;
4131 /* Initialize the CM results-to-screen map array if there were no "show cm"
4132 * directives in the config file */
4133 if (cm_showDefault) {
4134 for (i = 0; i < NUM_CM_STAT_ENTRIES; i++)
4135 cm_Display_map[i] = i;
4136 cm_DisplayItems_count = NUM_CM_STAT_ENTRIES;
4141 /* setup an interrupt signal handler; we ain't wanna leak core */
4142 /* this binding is useful only until gtx is initialized after which the
4143 * keyboard input server takes over. */
4144 if ((signal(SIGINT, quit_signal)) == SIG_ERR) {
4145 perror("signal() failed.");
4150 /* init error message buffers. these will be used to print error messages
4151 * once gtx is initialized and there is no access to stderr/stdout */
4157 /* initialize fs and cm circular buffers before initiating probes */
4159 code = init_fs_buffers();
4161 fprintf(stderr, "[ %s ] init_fs_buffers returned %d\n", rn,
4168 code = init_cm_buffers();
4170 fprintf(stderr, "[ %s ] init_cm_buffers returned %d\n", rn,
4177 /* allocate and initialize buffers for holding fs & cm results in ascii
4178 * format suitable for updating the screen */
4179 code = init_print_buffers();
4181 fprintf(stderr, "[ %s ] init_print_buffers returned %d\n", rn, code);
4185 /* perform gtx initializations */
4186 code = gtx_initialize();
4188 fprintf(stderr, "[ %s ] gtx_initialize returned %d\n", rn, code);
4192 /* start xstat probes */
4195 return (0); /* will not return from the call to afsmon_execute() */
4197 } /* afsmonInit() */
4200 /*-----------------------------------------------------------------------
4202 ------------------------------------------------------------------------*/
4204 #include "AFS_component_version_number.c"
4207 main(int argc, char **argv)
4209 afs_int32 code; /*Return code */
4210 struct cmd_syndesc *ts; /*Ptr to cmd line syntax descriptor */
4212 #ifdef AFS_AIX32_ENV
4214 * The following signal action for AIX is necessary so that in case of a
4215 * crash (i.e. core is generated) we can include the user's data section
4216 * in the core dump. Unfortunately, by default, only a partial core is
4217 * generated which, in many cases, isn't too useful.
4219 struct sigaction nsa;
4221 sigemptyset(&nsa.sa_mask);
4222 nsa.sa_handler = SIG_DFL;
4223 nsa.sa_flags = SA_FULLDUMP;
4224 sigaction(SIGSEGV, &nsa, NULL);
4228 * Set up the commands we understand.
4230 ts = cmd_CreateSyntax("initcmd", afsmonInit, NULL, "initialize the program");
4231 cmd_AddParm(ts, "-config", CMD_SINGLE, CMD_OPTIONAL,
4232 "configuration file");
4233 cmd_AddParm(ts, "-frequency", CMD_SINGLE, CMD_OPTIONAL,
4234 "poll frequency, in seconds");
4235 cmd_AddParm(ts, "-output", CMD_SINGLE, CMD_OPTIONAL, "storage file name");
4236 cmd_AddParm(ts, "-detailed", CMD_FLAG, CMD_OPTIONAL,
4237 "output detailed statistics to storage file");
4239 /* we hope to use this .... eventually! */
4240 cmd_AddParm(ts, "-package", CMD_SINGLE, CMD_REQUIRED,
4241 "Graphics Package to use");
4243 cmd_AddParm(ts, "-debug", CMD_SINGLE, CMD_OPTIONAL,
4244 "turn debugging output on to the named file");
4245 cmd_AddParm(ts, "-fshosts", CMD_LIST, CMD_OPTIONAL,
4246 "list of file servers to monitor");
4247 cmd_AddParm(ts, "-cmhosts", CMD_LIST, CMD_OPTIONAL,
4248 "list of cache managers to monitor");
4249 cmd_AddParm(ts, "-buffers", CMD_SINGLE, CMD_OPTIONAL,
4250 "number of buffer slots");
4253 * Parse command-line switches & execute afsmonitor
4256 code = cmd_Dispatch(argc, argv);
4262 exit(0); /* redundant, but gets rid of warning */