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 strlcpy(threshP->itemName, a_varName,
993 sizeof(threshP->itemName));
994 strlcpy(threshP->threshVal, a_value,
995 sizeof(threshP->threshVal));
996 strlcpy(threshP->handler, a_handler,
997 sizeof(threshP->handler));
998 threshP->index = index;
1005 fprintf(stderr, "[ %s ] Could not insert threshold entry",
1007 fprintf(stderr, "for %s in thresh list of host %s \n",
1008 a_varName, tmp_host->hostName);
1011 tmp_host = tmp_host->next;
1017 /* it is not a global threshold, insert it in the thresh list of this
1018 * host only. We overwrite the global threshold if it was alread set */
1020 if (*hostname == '\0') {
1021 fprintf(stderr, "[ %s ] Programming error 3\n", rn);
1025 /* get the hostEntry that this threshold belongs to */
1028 for (i = 0; i < srvCount; i++) {
1029 if (strcasecmp(tmp_host->hostName, hostname) == 0) {
1033 tmp_host = tmp_host->next;
1036 fprintf(stderr, "[ %s ] Unable to find host %s in %s hostEntry list",
1037 rn, hostname, (a_type - 1) ? "CM" : "FS");
1041 /* put this entry on the thresh list of this host, overwrite global value
1044 threshP = tmp_host->thresh;
1046 for (i = 0; i < tmp_host->numThresh; i++) {
1047 if ((threshP->itemName[0] == '\0')
1048 || (strcasecmp(threshP->itemName, a_varName) == 0)) {
1049 strlcpy(threshP->itemName, a_varName, sizeof(threshP->itemName));
1050 strlcpy(threshP->threshVal, a_value, sizeof(threshP->threshVal));
1051 strlcpy(threshP->handler, a_handler, sizeof(threshP->handler));
1052 threshP->index = index;
1061 "[ %s ] Unable to insert threshold %s for %s host %s\n", rn,
1062 a_varName, (a_type - 1) ? "CM" : "FS", tmp_host->hostName);
1068 } /* store_thresholds */
1071 /*-----------------------------------------------------------------------
1075 * This function process a "show" entry in the config file. A "show"
1076 * entry specifies what statistics the user wants to see. File
1077 * server and Cache Manager data is divided into sections. Each section
1078 * is made up of one or more groups. If a group name is specified only
1079 * those statistics under that group are shown. If a section name is
1080 * specified all the groups under this section are shown.
1081 * Data as obtained from the xstat probes is considered to be ordered.
1082 * This data is mapped to the screen thru fs_Display_map[] and
1083 * cm_Display_map[]. This routine parses the "show" entry against the
1084 * section/group names in the [fs/cm]_categories[] array. If there is
1085 * no match it tries to match it against a variable name in
1086 * [fs/cm]_varNames[] array. In each case the corresponding indices to
1087 * the data is the [fs/cm]_displayInfo[] is recorded.
1091 * Failure: -1 (invalid entry)
1092 * > -1 (programming error)
1093 *----------------------------------------------------------------------*/
1096 parse_showEntry(char *a_line)
1097 { /* parse_showEntry */
1098 static char rn[] = "parse_showEntry";
1099 char opcode[CFG_STR_LEN]; /* specifies type of config entry */
1100 char arg1[CFG_STR_LEN]; /* show fs or cm entry ? */
1101 char arg2[CFG_STR_LEN]; /* what we gotta show */
1102 char arg3[CFG_STR_LEN]; /* junk */
1103 char catName[CFG_STR_LEN]; /* for category names */
1104 int numGroups; /* number of groups in a section */
1108 int idx = 0; /* index to fs_categories[] */
1114 fprintf(debugFD, "[ %s ] Called, a_line= %s\n", rn, a_line);
1121 sscanf(a_line, "%s %s %s %s", opcode, arg1, arg2, arg3);
1123 if (arg3[0] != '\0') {
1124 fprintf(stderr, "[ %s ] Extraneous characters at end of line\n", rn);
1128 if ((strcasecmp(arg1, "fs") != 0) && (strcasecmp(arg1, "cm") != 0)) {
1130 "[ %s ] Second argument of \"show\" directive should be \"fs\" or \"cm\" \n",
1135 /* Each entry can either be a variable name or a section/group name. Variable
1136 * names are listed in xx_varNames[] and section/group names in xx_categories[].
1137 * The section/group names in xx_categiries[] also give the starting/ending
1138 * indices of the variables belonging to that section/group. These indices
1139 * are stored in order in xx_Display_map[] and displayed to the screen in that
1142 /* To handle duplicate "show" entries we keep track of what what we have
1143 * already marked to show in the xx_showFlags[] */
1145 if (strcasecmp(arg1, "fs") == 0) { /* its a File Server entry */
1147 /* mark that we have to show only what the user wants */
1150 /* if it is a section/group name, find it in the fs_categories[] array */
1153 if (strcasestr(arg2, "_section") != NULL
1154 || strcasestr(arg2, "_group") != NULL) {
1156 while (idx < FS_NUM_DATA_CATEGORIES) {
1157 sscanf(fs_categories[idx], "%s %d %d", catName, &fromIdx,
1160 if (strcasecmp(arg2, catName) == 0) {
1166 if (!found) { /* typo in section/group name */
1168 "[ %s ] Could not find section/group name %s\n", rn,
1174 /* if it is a group name, read its start/end indices and fill in the
1175 * fs_Display_map[]. */
1177 if (strcasestr(arg2, "_group") != NULL) {
1179 if (fromIdx < 0 || toIdx < 0 || fromIdx >= NUM_FS_STAT_ENTRIES
1180 || toIdx >= NUM_FS_STAT_ENTRIES)
1182 for (j = fromIdx; j <= toIdx; j++) {
1183 if (!fs_showFlags[j]) {
1184 fs_Display_map[fs_DisplayItems_count] = j;
1185 fs_DisplayItems_count++;
1186 fs_showFlags[j] = 1;
1188 if (fs_DisplayItems_count >= NUM_FS_STAT_ENTRIES) {
1189 fprintf(stderr, "[ %s ] fs_DisplayItems_count ovf\n", rn);
1194 /* if it is a section name, get the count of number of groups in it and
1195 * for each group fill in the start/end indices in the fs_Display_map[] */
1197 if (strcasestr(arg2, "_section") != NULL) {
1198 /* fromIdx is actually the number of groups in thi section */
1199 numGroups = fromIdx;
1200 /* for each group in section */
1201 while (idx < FS_NUM_DATA_CATEGORIES && numGroups) {
1202 sscanf(fs_categories[idx], "%s %d %d", catName, &fromIdx,
1205 if (strcasestr(catName, "_group") != NULL) {
1206 if (fromIdx < 0 || toIdx < 0
1207 || fromIdx >= NUM_FS_STAT_ENTRIES
1208 || toIdx >= NUM_FS_STAT_ENTRIES)
1210 for (j = fromIdx; j <= toIdx; j++) {
1211 if (!fs_showFlags[j]) {
1212 fs_Display_map[fs_DisplayItems_count] = j;
1213 fs_DisplayItems_count++;
1214 fs_showFlags[j] = 1;
1216 if (fs_DisplayItems_count >= NUM_FS_STAT_ENTRIES) {
1218 "[ %s ] fs_DisplayItems_count ovf\n", rn);
1223 fprintf(stderr, "[ %s ] Error parsing groups for %s\n",
1229 } /* for each group in section */
1232 } else { /* it is a variable name */
1234 for (i = 0; i < NUM_FS_STAT_ENTRIES; i++) {
1235 if (strcasecmp(arg2, fs_varNames[i]) == 0) {
1236 if (!fs_showFlags[i]) {
1237 fs_Display_map[fs_DisplayItems_count] = i;
1238 fs_DisplayItems_count++;
1239 fs_showFlags[i] = 1;
1241 if (fs_DisplayItems_count >= NUM_FS_STAT_ENTRIES) {
1242 fprintf(stderr, "[ %s ] fs_DisplayItems_count ovf\n",
1249 if (!found) { /* typo in section/group name */
1250 fprintf(stderr, "[ %s ] Could not find variable name %s\n",
1254 } /* its a variable name */
1258 /* it is an fs entry */
1259 if (strcasecmp(arg1, "cm") == 0) { /* its a Cache Manager entry */
1262 /* mark that we have to show only what the user wants */
1265 /* if it is a section/group name, find it in the cm_categories[] array */
1268 if (strcasestr(arg2, "_section") != NULL
1269 || strcasestr(arg2, "_group") != NULL) {
1271 while (idx < CM_NUM_DATA_CATEGORIES) {
1272 sscanf(cm_categories[idx], "%s %d %d", catName, &fromIdx,
1275 if (strcasecmp(arg2, catName) == 0) {
1281 if (!found) { /* typo in section/group name */
1283 "[ %s ] Could not find section/group name %s\n", rn,
1289 /* if it is a group name, read its start/end indices and fill in the
1290 * cm_Display_map[]. */
1292 if (strcasestr(arg2, "_group") != NULL) {
1294 if (fromIdx < 0 || toIdx < 0 || fromIdx >= NUM_CM_STAT_ENTRIES
1295 || toIdx >= NUM_CM_STAT_ENTRIES)
1297 for (j = fromIdx; j <= toIdx; j++) {
1298 if (!cm_showFlags[j]) {
1299 cm_Display_map[cm_DisplayItems_count] = j;
1300 cm_DisplayItems_count++;
1301 cm_showFlags[j] = 1;
1303 if (cm_DisplayItems_count >= NUM_CM_STAT_ENTRIES) {
1304 fprintf(stderr, "[ %s ] cm_DisplayItems_count ovf\n", rn);
1309 /* if it is a section name, get the count of number of groups in it and
1310 * for each group fill in the start/end indices in the cm_Display_map[] */
1312 if (strcasestr(arg2, "_section") != NULL) {
1313 /* fromIdx is actually the number of groups in thi section */
1314 numGroups = fromIdx;
1315 /* for each group in section */
1316 while (idx < CM_NUM_DATA_CATEGORIES && numGroups) {
1317 sscanf(cm_categories[idx], "%s %d %d", catName, &fromIdx,
1320 if (strcasestr(catName, "_group") != NULL) {
1321 if (fromIdx < 0 || toIdx < 0
1322 || fromIdx >= NUM_CM_STAT_ENTRIES
1323 || toIdx >= NUM_CM_STAT_ENTRIES)
1325 for (j = fromIdx; j <= toIdx; j++) {
1326 if (!cm_showFlags[j]) {
1327 cm_Display_map[cm_DisplayItems_count] = j;
1328 cm_DisplayItems_count++;
1329 cm_showFlags[j] = 1;
1331 if (cm_DisplayItems_count >= NUM_CM_STAT_ENTRIES) {
1333 "[ %s ] cm_DisplayItems_count ovf\n", rn);
1338 fprintf(stderr, "[ %s ] Error parsing groups for %s\n",
1344 } /* for each group in section */
1345 } else { /* it is a variable name */
1347 for (i = 0; i < NUM_CM_STAT_ENTRIES; i++) {
1348 if (strcasecmp(arg2, cm_varNames[i]) == 0) {
1349 if (!cm_showFlags[i]) {
1350 cm_Display_map[cm_DisplayItems_count] = i;
1351 cm_DisplayItems_count++;
1352 cm_showFlags[i] = 1;
1354 if (cm_DisplayItems_count >= NUM_CM_STAT_ENTRIES) {
1355 fprintf(stderr, "[ %s ] cm_DisplayItems_count ovf\n",
1362 if (!found) { /* typo in section/group name */
1363 fprintf(stderr, "[ %s ] Could not find variable name %s\n",
1367 } /* its a variable name */
1370 /* it is an cm entry */
1372 } /* parse_showEntry */
1375 /*-----------------------------------------------------------------------
1376 * process_config_file()
1379 * Parse config file entries in two passes. In the first pass:
1380 * - the syntax of all the entries is checked
1381 * - host names are noted and the FSnamesList and CMnamesList
1383 * - a count of the global thresholds and local thresholds of
1384 * each host are counted.
1385 * - "show" entries are processed.
1386 * In the second pass:
1387 * - thresholds are stored
1391 * Failure: Exits afsmonitor showing error and line.
1392 *----------------------------------------------------------------------*/
1395 process_config_file(char *a_config_filename)
1396 { /* process_config_file() */
1397 static char rn[] = "process_config_file"; /* routine name */
1398 FILE *configFD; /* config file descriptor */
1399 char line[4 * CFG_STR_LEN]; /* a line of config file */
1400 char opcode[CFG_STR_LEN]; /* specifies type of config entry */
1401 char arg1[CFG_STR_LEN]; /* hostname or qualifier (fs/cm?) */
1402 char arg2[CFG_STR_LEN]; /* threshold variable */
1403 char arg3[CFG_STR_LEN]; /* threshold value */
1404 char arg4[CFG_STR_LEN]; /* user's handler */
1405 struct afsmon_hostEntry *curr_host;
1406 struct hostent *he; /* hostentry to resolve host name */
1407 char *handlerPtr; /* ptr to pass theresh handler string */
1408 int code = 0; /* error code */
1409 int linenum = 0; /* config file line number */
1410 int error_in_config; /* syntax errors in config file ?? */
1415 fprintf(debugFD, "[ %s ] Called, a_config_filename= %s\n", rn,
1420 /* open config file */
1422 configFD = fopen(a_config_filename, "r");
1423 if (configFD == (FILE *) 0) {
1424 fprintf(stderr, "Failed to open config file %s \n",
1427 fprintf(debugFD, "[ %s ] Failed to open config file %s \n", rn,
1434 /* parse config file */
1436 /* We process the config file in two passes. In the first pass we check
1437 * for correct syntax and for valid entries and also keep count of the
1438 * number of servers and thresholds to monitor. This the data strctures
1439 * can be arrays instead of link lists since we would know their sizes. */
1445 error_in_config = 0; /* flag to note if config file has syntax errors */
1447 while ((fgets(line, CFG_STR_LEN, configFD)) != NULL) {
1453 sscanf(line, "%s %s %s %s %s", opcode, arg1, arg2, arg3, arg4);
1455 /* skip blank lines and comment lines */
1456 if ((strlen(opcode) == 0) || line[0] == '#')
1459 if ((strcasecmp(opcode, "fs") == 0)
1460 || (strcasecmp(opcode, "cm")) == 0) {
1461 code = parse_hostEntry(line);
1462 } else if ((strcasecmp(opcode, "thresh")) == 0) {
1463 code = parse_threshEntry(line);
1464 } else if ((strcasecmp(opcode, "show")) == 0) {
1465 code = parse_showEntry(line);
1467 fprintf(stderr, "[ %s ] Unknown opcode %s\n", rn, opcode);
1472 fprintf(stderr, "[ %s ] Error in line:\n %d: %s\n", rn, linenum,
1474 error_in_config = 1;
1478 if (error_in_config)
1482 fprintf(debugFD, "Global FS thresholds count = %d\n",
1483 global_fsThreshCount);
1484 fprintf(debugFD, "Global CM thresholds count = %d\n",
1485 global_cmThreshCount);
1489 /* the threshold count of all hosts in increased by 1 for each global
1490 * threshold. If one of the hosts has a local threshold for the same
1491 * variable it would end up being counted twice. whats a few bytes of memory
1492 * wasted anyway ? */
1494 if (global_fsThreshCount) {
1495 curr_host = FSnameList;
1496 for (i = 0; i < numFS; i++) {
1497 curr_host->numThresh += global_fsThreshCount;
1498 curr_host = curr_host->next;
1501 if (global_cmThreshCount) {
1502 curr_host = CMnameList;
1503 for (i = 0; i < numCM; i++) {
1504 curr_host->numThresh += global_cmThreshCount;
1505 curr_host = curr_host->next;
1510 /* make sure we have something to monitor */
1511 if (numFS == 0 && numCM == 0) {
1513 "\nConfig file must specify atleast one File Server or Cache Manager host to monitor.\n");
1520 fseek(configFD, 0, 0); /* seek to the beginning */
1523 /* allocate memory for threshold lists */
1524 curr_host = FSnameList;
1525 for (i = 0; i < numFS; i++) {
1526 if (curr_host->hostName[0] == '\0') {
1527 fprintf(stderr, "[ %s ] Programming error 4\n", rn);
1530 if (curr_host->numThresh) {
1531 numBytes = curr_host->numThresh * sizeof(struct Threshold);
1532 curr_host->thresh = malloc(numBytes);
1533 if (curr_host->thresh == NULL) {
1534 fprintf(stderr, "[ %s ] Memory Allocation error 1", rn);
1537 memset(curr_host->thresh, 0, numBytes);
1539 curr_host = curr_host->next;;
1542 curr_host = CMnameList;
1543 for (i = 0; i < numCM; i++) {
1544 if (curr_host->hostName[0] == '\0') {
1545 fprintf(stderr, "[ %s ] Programming error 5\n", rn);
1548 if (curr_host->numThresh) {
1549 numBytes = curr_host->numThresh * sizeof(struct Threshold);
1550 curr_host->thresh = malloc(numBytes);
1551 if (curr_host->thresh == NULL) {
1552 fprintf(stderr, "[ %s ] Memory Allocation error 2", rn);
1555 memset(curr_host->thresh, 0, numBytes);
1557 curr_host = curr_host->next;;
1566 last_fsHost[0] = '\0';
1567 last_cmHost[0] = '\0';
1569 while ((fgets(line, CFG_STR_LEN, configFD)) != NULL) {
1575 sscanf(line, "%s %s %s %s %s", opcode, arg1, arg2, arg3, arg4);
1578 /* if we have a host entry, remember the host name */
1579 if (strcasecmp(opcode, "fs") == 0) {
1580 he = GetHostByName(arg1);
1581 strncpy(last_fsHost, he->h_name, HOST_NAME_LEN);
1582 } else if (strcasecmp(opcode, "cm") == 0) {
1583 he = GetHostByName(arg1);
1584 strncpy(last_cmHost, he->h_name, HOST_NAME_LEN);
1585 } else if (strcasecmp(opcode, "thresh") == 0) {
1586 /* if we have a threshold handler it may have arguments
1587 * and the sscanf() above would not get them, so do the
1591 /* now skip over 4 words - this is done by first
1592 * skipping leading blanks then skipping a word */
1593 for (i = 0; i < 4; i++) {
1594 while (isspace(*handlerPtr))
1596 while (!isspace(*handlerPtr))
1599 while (isspace(*handlerPtr))
1601 /* we how have a pointer to the start of the handler
1604 handlerPtr = arg4; /* empty string */
1607 if (strcasecmp(arg1, "fs") == 0)
1608 code = store_threshold(1, /* 1 = fs */
1609 arg2, arg3, handlerPtr);
1611 else if (strcasecmp(arg1, "cm") == 0)
1612 code = store_threshold(2, /* 2 = fs */
1613 arg2, arg3, handlerPtr);
1616 fprintf(stderr, "[ %s ] Programming error 6\n", rn);
1620 fprintf(stderr, "[ %s ] Failed to store threshold\n", rn);
1621 fprintf(stderr, "[ %s ] Error processing line:\n%d: %s", rn,
1633 /*-----------------------------------------------------------------------
1638 * Print the File Server circular buffer.
1642 *----------------------------------------------------------------------*/
1646 { /* Print_FS_CB() */
1648 struct afsmon_fs_Results_list *fslist;
1653 /* print valid info in the fs CB */
1657 "==================== FS Buffer ========================\n");
1658 fprintf(debugFD, "afsmon_fs_curr_CBindex = %d\n",
1659 afsmon_fs_curr_CBindex);
1660 fprintf(debugFD, "afsmon_fs_curr_probeNum = %d\n\n",
1661 afsmon_fs_curr_probeNum);
1663 for (i = 0; i < num_bufSlots; i++) {
1664 fprintf(debugFD, "\t--------- slot %d ----------\n", i);
1665 fslist = afsmon_fs_ResultsCB[i].list;
1668 for (k = 0; k < MAX_NUM_FS_COLLECTIONS; k++) {
1669 if (!(fslist->empty[k])) {
1670 fprintf(debugFD, "\t %d) probeNum = %d host = %s cn = %d",
1672 fslist->fsResults[k]->probeNum,
1673 fslist->fsResults[k]->connP->hostName,
1674 fslist->fsResults[k]->collectionNumber);
1675 if (fslist->fsResults[k]->probeOK)
1676 fprintf(debugFD, " NOTOK\n");
1678 fprintf(debugFD, " OK\n");
1680 fprintf(debugFD, "\t %d) -- empty --\n", j);
1682 fslist = fslist->next;
1685 if (fslist != (struct afsmon_fs_Results_list *)0)
1686 fprintf(debugFD, "dangling last next ptr fs CB\n");
1689 } /* Print_FS_CB() */
1691 /*-----------------------------------------------------------------------
1692 * save_FS_results_inCB()
1695 * Saves the results of the latest FS probe in the fs circular
1696 * buffers. If the current probe cycle is in progress the contents
1697 * of xstat_fs_Results are copied to the end of the list of results
1698 * in the current slot (pointed to by afsmon_fs_curr_CBindex). If
1699 * a new probe cycle has started the next slot in the circular buffer
1700 * is initialized and the results copied. Note that the Rx related
1701 * information available in xstat_fs_Results is not copied.
1705 * Failure: Exits afsmonitor.
1706 *----------------------------------------------------------------------*/
1708 save_FS_results_inCB(int a_newProbeCycle) /* start of a new probe cycle ? */
1709 { /* save_FS_results_inCB() */
1710 static char rn[] = "save_FS_results_inCB"; /* routine name */
1711 struct afsmon_fs_Results_list *tmp_fslist_item; /* temp fs list item */
1712 struct xstat_fs_ProbeResults *tmp_fsPR; /* temp ptr */
1717 fprintf(debugFD, "[ %s ] Called, a_newProbeCycle= %d\n", rn,
1722 switch (xstat_fs_Results.collectionNumber) {
1723 case AFS_XSTATSCOLL_FULL_PERF_INFO:
1726 case AFS_XSTATSCOLL_CBSTATS:
1730 fprintf(stderr, "[ %s ] collection number %d is out of range.\n",
1731 rn, xstat_fs_Results.collectionNumber);
1735 /* If a new probe cycle started, mark the list in the current buffer
1736 * slot empty for resuse. Note that afsmon_fs_curr_CBindex was appropriately
1737 * incremented in afsmon_FS_Handler() */
1739 if (a_newProbeCycle) {
1740 tmp_fslist_item = afsmon_fs_ResultsCB[afsmon_fs_curr_CBindex].list;
1741 for (i = 0; i < numFS; i++) {
1742 tmp_fslist_item->empty[index] = 1;
1743 tmp_fslist_item = tmp_fslist_item->next;
1747 /* locate last unused item in list */
1748 tmp_fslist_item = afsmon_fs_ResultsCB[afsmon_fs_curr_CBindex].list;
1749 for (i = 0; i < numFS; i++) {
1750 if (tmp_fslist_item->empty[index])
1752 tmp_fslist_item = tmp_fslist_item->next;
1755 /* if we could not find one we have an inconsistent list */
1756 if (!tmp_fslist_item->empty[index]) {
1758 "[ %s ] list inconsistency 1. unable to find an empty slot to store results of probenum %d of %s\n",
1759 rn, xstat_fs_Results.probeNum,
1760 xstat_fs_Results.connP->hostName);
1764 tmp_fsPR = tmp_fslist_item->fsResults[index];
1766 /* copy hostname and probe number and probe time and probe status.
1767 * if the probe failed return now */
1769 memcpy(tmp_fsPR->connP->hostName, xstat_fs_Results.connP->hostName,
1770 sizeof(xstat_fs_Results.connP->hostName));
1771 tmp_fsPR->probeNum = xstat_fs_Results.probeNum;
1772 tmp_fsPR->probeTime = xstat_fs_Results.probeTime;
1773 tmp_fsPR->probeOK = xstat_fs_Results.probeOK;
1774 if (xstat_fs_Results.probeOK) { /* probeOK = 1 => notOK */
1775 /* we have a nonempty results structure so mark the list item used */
1776 tmp_fslist_item->empty[index] = 0;
1780 /* copy connection information */
1781 memcpy(&(tmp_fsPR->connP->skt), &(xstat_fs_Results.connP->skt),
1782 sizeof(struct sockaddr_in));
1784 memcpy(tmp_fsPR->connP->hostName, xstat_fs_Results.connP->hostName,
1785 sizeof(xstat_fs_Results.connP->hostName));
1786 tmp_fsPR->collectionNumber = xstat_fs_Results.collectionNumber;
1788 /* copy the probe data information */
1789 tmp_fsPR->data.AFS_CollData_len =
1790 min(xstat_fs_Results.data.AFS_CollData_len,
1791 afsmon_fs_results_length[index]);
1792 memcpy(tmp_fsPR->data.AFS_CollData_val,
1793 xstat_fs_Results.data.AFS_CollData_val,
1794 tmp_fsPR->data.AFS_CollData_len * sizeof(afs_int32));
1797 /* we have a valid results structure so mark the list item used */
1798 tmp_fslist_item->empty[index] = 0;
1800 /* Print the fs circular buffer */
1804 } /* save_FS_results_inCB() */
1807 /*-----------------------------------------------------------------------
1811 * The results of xstat probes are stored in a string format in
1812 * the arrays curr_fsData and prev_fsData. The information stored in
1813 * prev_fsData is copied to the screen.
1814 * This function converts xstat FS results from longs to strings and
1815 * place them in the given buffer (a pointer to an item in curr_fsData).
1816 * When a probe cycle completes, curr_fsData is copied to prev_fsData
1817 * in afsmon_FS_Hnadler().
1821 *----------------------------------------------------------------------*/
1824 fs_Results_ltoa(struct fs_Display_Data *a_fsData, /* target buffer */
1825 struct xstat_fs_ProbeResults *a_fsResults) /* ptr to xstat fs Results */
1826 { /* fs_Results_ltoa */
1828 static char rn[] = "fs_Results_ltoa"; /* routine name */
1831 fprintf(debugFD, "[ %s ] Called, a_fsData= %p, a_fsResults= %p\n", rn,
1832 a_fsData, a_fsResults);
1836 switch (a_fsResults->collectionNumber) {
1837 case AFS_XSTATSCOLL_FULL_PERF_INFO:
1838 fs_FullPerfs_ltoa(a_fsData, a_fsResults);
1840 case AFS_XSTATSCOLL_CBSTATS:
1841 fs_CallBackStats_ltoa(a_fsData, a_fsResults);
1845 fprintf(debugFD, "[ %s ] Unexpected collection id %d\n",
1846 rn, a_fsResults->collectionNumber);
1851 } /* fs_Results_ltoa */
1853 /*-----------------------------------------------------------------------
1854 * fs_FullPerfs_ltoa()
1857 * Convert the full perf xstat collection from int32s to strings.
1861 *----------------------------------------------------------------------*/
1863 fs_FullPerfs_ltoa(struct fs_Display_Data *a_fsData,
1864 struct xstat_fs_ProbeResults *a_fsResults)
1867 struct fs_stats_FullPerfStats *fullPerfP;
1868 struct fs_stats_FullPerfStats buffer;
1874 /* there are two parts to the xstat FS statistics
1875 * - fullPerfP->overall which give the overall performance statistics, and
1876 * - fullPerfP->det which gives detailed info about file server operation
1877 * execution times */
1879 code = xstat_fs_DecodeFullPerfStats(&fullPerfP,
1880 a_fsResults->data.AFS_CollData_val,
1881 a_fsResults->data.AFS_CollData_len,
1884 /* Not able to decode the full perf stats. Avoid displaying garbage. */
1885 for (i = 0; i < NUM_FS_STAT_ENTRIES; i++) {
1886 sprintf(a_fsData->data[i], "%s", "--");
1891 /* copy overall performance statistics */
1892 srcbuf = (afs_int32 *) & (fullPerfP->overall);
1894 for (i = 0; i < NUM_XSTAT_FS_AFS_PERFSTATS_LONGS; i++) {
1895 sprintf(a_fsData->data[idx], "%d", *srcbuf);
1901 srcbuf = (afs_int32 *) & (fullPerfP->det.epoch);
1902 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* epoch */
1905 /* copy fs operation timing */
1907 srcbuf = (afs_int32 *) (fullPerfP->det.rpcOpTimes);
1909 for (i = 0; i < FS_STATS_NUM_RPC_OPS; i++) {
1910 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* numOps */
1913 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* numSuccesses */
1916 tmpbuf = srcbuf++; /* sum time */
1917 sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1920 tmpbuf = srcbuf++; /* sqr time */
1921 sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1924 tmpbuf = srcbuf++; /* min time */
1925 sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1928 tmpbuf = srcbuf++; /* max time */
1929 sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1934 /* copy fs transfer timings */
1936 srcbuf = (afs_int32 *) (fullPerfP->det.xferOpTimes);
1937 for (i = 0; i < FS_STATS_NUM_XFER_OPS; i++) {
1938 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* numOps */
1941 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* numSuccesses */
1944 tmpbuf = srcbuf++; /* sum time */
1945 sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1948 tmpbuf = srcbuf++; /* sqr time */
1949 sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1952 tmpbuf = srcbuf++; /* min time */
1953 sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1956 tmpbuf = srcbuf++; /* max time */
1957 sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1960 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* sum bytes */
1963 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* min bytes */
1966 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* max bytes */
1969 for (j = 0; j < FS_STATS_NUM_XFER_BUCKETS; j++) {
1970 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* bucket[j] */
1979 /*-----------------------------------------------------------------------
1980 * fs_CallBackStats_ltoa()
1983 * Convert the callback counter xstat collection from
1984 * int32s to strings.
1988 *----------------------------------------------------------------------*/
1991 fs_CallBackStats_ltoa(struct fs_Display_Data *a_fsData,
1992 struct xstat_fs_ProbeResults *a_fsResults)
1996 int len = a_fsResults->data.AFS_CollData_len;
1997 afs_int32 *val = a_fsResults->data.AFS_CollData_val;
1999 /* place callback stats after the full perf stats */
2000 idx = NUM_FS_FULLPERF_ENTRIES;
2001 for (i=0; i < len && i < NUM_FS_CB_ENTRIES; i++) {
2002 sprintf(a_fsData->data[idx++], "%u", val[i]);
2007 /*-----------------------------------------------------------------------
2008 * execute_thresh_handler()
2011 * Execute a threshold handler. An agrv[] array of pointers is
2012 * constructed from the given data. A child process is forked
2013 * which immediately calls afsmon_Exit() with indication that a
2014 * threshold handler is to be exec'ed insted of exiting.
2018 * Failure: Afsmonitor exits if threshold handler has more than 20 args.
2019 *----------------------------------------------------------------------*/
2022 execute_thresh_handler(char *a_handler, /* ptr to handler function + args */
2023 char *a_hostName, /* host name for which threshold crossed */
2024 int a_hostType, /* fs or cm ? */
2025 char *a_threshName, /* threshold variable name */
2026 char *a_threshValue, /* threshold value */
2027 char *a_actValue) /* actual value */
2028 { /* execute_thresh_handler */
2030 static char rn[] = "execute_thresh_handler";
2031 char fileName[256]; /* file name to execute */
2035 int anotherArg; /* boolean used to flag if another arg is available */
2039 "[ %s ] Called, a_handler= %s, a_hostName= %s, a_hostType= %d, a_threshName= %s, a_threshValue= %s, a_actValue= %s\n",
2040 rn, a_handler, a_hostName, a_hostType, a_threshName,
2041 a_threshValue, a_actValue);
2046 /* get the filename to execute - the first argument */
2047 sscanf(a_handler, "%s", fileName);
2049 /* construct the contents of *argv[] */
2051 strncpy(fsHandler_args[0], fileName, 256);
2052 strncpy(fsHandler_args[1], a_hostName, HOST_NAME_LEN);
2053 if (a_hostType == FS)
2054 strcpy(fsHandler_args[2], "fs");
2056 strcpy(fsHandler_args[2], "cm");
2057 strncpy(fsHandler_args[3], a_threshName, THRESH_VAR_NAME_LEN);
2058 strncpy(fsHandler_args[4], a_threshValue, THRESH_VAR_LEN);
2059 strncpy(fsHandler_args[5], a_actValue, THRESH_VAR_LEN);
2066 /* we have already extracted the file name so skip to the 1st arg */
2067 while (isspace(*ch)) /* leading blanks */
2069 while (!isspace(*ch) && *ch != '\0') /* handler filename */
2072 while (*ch != '\0') {
2075 } else if (anotherArg) {
2077 sscanf(ch, "%s", fsHandler_args[argNum]);
2083 "Threshold handlers cannot have more than 20 arguments\n");
2089 fsHandler_argv[argNum] = NULL;
2090 for (i = 0; i < argNum; i++)
2091 fsHandler_argv[i] = fsHandler_args[i];
2094 /* exec the threshold handler */
2097 exec_fsThreshHandler = 1;
2102 } /* execute_thresh_handler */
2106 /*-----------------------------------------------------------------------
2107 * check_fs_thresholds()
2110 * Checks the thresholds and sets the overflow flag. Recall that the
2111 * thresholds for each host are stored in the hostEntry lists
2112 * [fs/cm]nameList arrays. The probe results are passed to this
2113 * function in the display-ready format - ie., as strings. Though
2114 * this looks stupid the overhead incurred in converting the strings
2115 * back to floats and comparing them is insignificant and
2116 * programming is easier this way.
2117 * The threshold flags are a part of the display structures
2122 *----------------------------------------------------------------------*/
2125 check_fs_thresholds(struct afsmon_hostEntry *a_hostEntry, /* ptr to hostEntry */
2126 struct fs_Display_Data *a_Data) /* ptr to fs data to be displayed */
2127 { /* check_fs_thresholds */
2129 static char rn[] = "check_fs_thresholds";
2130 struct Threshold *threshP;
2131 double tValue; /* threshold value */
2132 double pValue; /* probe value */
2135 int count; /* number of thresholds exceeded */
2138 fprintf(debugFD, "[ %s ] Called, a_hostEntry= %p, a_Data= %p\n", rn,
2139 a_hostEntry, a_Data);
2143 if (a_hostEntry->numThresh == 0) {
2144 /* store in ovf count ?? */
2149 threshP = a_hostEntry->thresh;
2150 for (i = 0; i < a_hostEntry->numThresh; i++) {
2151 if (threshP->itemName[0] == '\0') {
2155 idx = threshP->index; /* positional index to the data array */
2156 tValue = atof(threshP->threshVal); /* threshold value */
2157 pValue = atof(a_Data->data[idx]); /* probe value */
2158 if (pValue > tValue) {
2162 "[ %s ] fs = %s, thresh ovf for %s, threshold= %s, probevalue= %s\n",
2163 rn, a_hostEntry->hostName, threshP->itemName,
2164 threshP->threshVal, a_Data->data[idx]);
2167 /* if the threshold is crossed, call the handler function
2168 * only if this was a transition -ie, if the threshold was
2169 * crossed in the last probe too just count & keep quite! */
2171 if (!a_Data->threshOvf[idx]) {
2172 a_Data->threshOvf[idx] = 1;
2173 /* call the threshold handler if provided */
2174 if (threshP->handler[0] != '\0') {
2176 fprintf(debugFD, "[ %s ] Calling ovf handler %s\n",
2177 rn, threshP->handler);
2180 execute_thresh_handler(threshP->handler, a_Data->hostName,
2181 FS, threshP->itemName,
2189 /* in case threshold was previously crossed, blank it out */
2190 a_Data->threshOvf[idx] = 0;
2193 /* store the overflow count */
2194 a_Data->ovfCount = count;
2197 } /* check_fs_thresholds */
2200 /*-----------------------------------------------------------------------
2201 * save_FS_data_forDisplay()
2204 * Does the following:
2205 * - if the probe number changed (ie, a cycle completed) curr_fsData
2206 * is copied to prev_fsData, curr_fsData zeroed and refresh the
2207 * overview screen and file server screen with the new data.
2208 * - store the results of the current probe from xstat_fs_Results into
2209 * curr_fsData. ie., convert longs to strings.
2210 * - check the thresholds
2214 * Failure: Exits afsmonitor.
2215 *----------------------------------------------------------------------*/
2218 save_FS_data_forDisplay(struct xstat_fs_ProbeResults *a_fsResults)
2219 { /* save_FS_data_forDisplay */
2221 static char rn[] = "save_FS_data_forDisplay"; /* routine name */
2222 struct fs_Display_Data *curr_fsDataP; /* tmp ptr to curr_fsData */
2223 struct fs_Display_Data *prev_fsDataP; /* tmp ptr to prev_fsData */
2224 struct afsmon_hostEntry *curr_host;
2225 static int results_Received = 0; /* number of probes reveived in
2226 * the current cycle. If this is equal to numFS we got all
2227 * the data we want in this cycle and can now display it */
2236 fprintf(debugFD, "[ %s ] Called, a_fsResults= %p\n", rn, a_fsResults);
2240 /* store results in the display array */
2243 curr_fsDataP = curr_fsData;
2244 for (i = 0; i < numFS; i++) {
2245 if ((strcasecmp(curr_fsDataP->hostName, a_fsResults->connP->hostName))
2255 "[ %s ] Could not insert FS probe results for host %s in fs display array\n",
2256 rn, a_fsResults->connP->hostName);
2260 /* Check the status of the probe. If it succeeded, we store its
2261 * results in the display data structure. If it failed we only mark
2262 * the failed status in the display data structure. */
2264 if (a_fsResults->probeOK) { /* 1 => notOK the xstat results */
2265 curr_fsDataP->probeOK = 0;
2267 /* print the probe status */
2269 fprintf(debugFD, "\n\t\t ----- fs display data ------\n");
2270 fprintf(debugFD, "HostName = %s PROBE FAILED \n",
2271 curr_fsDataP->hostName);
2275 } else { /* probe succeeded, update display data structures */
2276 curr_fsDataP->probeOK = 1;
2278 /* convert longs to strings and place them in curr_fsDataP */
2279 fs_Results_ltoa(curr_fsDataP, a_fsResults);
2281 /* compare with thresholds and set the overflow flags.
2282 * note that the threshold information is in the hostEntry structure and
2283 * each threshold item has a positional index associated with it */
2285 /* locate the hostEntry for this host */
2287 curr_host = FSnameList;
2288 for (i = 0; i < numFS; i++) {
2289 if (strcasecmp(curr_host->hostName, a_fsResults->connP->hostName)
2294 curr_host = curr_host->next;;
2299 code = check_fs_thresholds(curr_host, curr_fsDataP);
2301 fprintf(stderr, "[ %s ] Error in checking thresholds\n", rn);
2305 /* print the info we just saved */
2308 fprintf(debugFD, "\n\t\t ----- fs display data ------\n");
2309 fprintf(debugFD, "HostName = %s\n", curr_fsDataP->hostName);
2310 for (i = 0; i < NUM_FS_STAT_ENTRIES; i++)
2311 fprintf(debugFD, "%20s %30s %s\n", curr_fsDataP->data[i],
2313 curr_fsDataP->threshOvf[i] ? "(ovf)" : "");
2315 fprintf(debugFD, "\t\t--------------------------------\n\n");
2319 } /* the probe succeeded, so we store the data in the display structure */
2322 /* if we have received a reply from all the hosts for this probe cycle,
2323 * it is time to display the data */
2326 if (results_Received == numFS * num_fs_collections) {
2327 results_Received = 0;
2329 if (afsmon_fs_curr_probeNum != afsmon_fs_prev_probeNum + 1) {
2330 sprintf(errMsg, "[ %s ] Probe number %d missed! \n", rn,
2331 afsmon_fs_prev_probeNum + 1);
2334 afsmon_fs_prev_probeNum++;
2336 /* backup the display data of the probe cycle that just completed -
2337 * ie., store curr_fsData in prev_fsData */
2339 memcpy((char *)prev_fsData, (char *)curr_fsData,
2340 (numFS * sizeof(struct fs_Display_Data)));
2343 /* initialize curr_fsData but retain the threshold flag information.
2344 * The previous state of threshold flags is used in check_fs_thresholds() */
2346 numBytes = NUM_FS_STAT_ENTRIES * FS_STAT_STRING_LEN;
2347 curr_fsDataP = curr_fsData;
2348 for (i = 0; i < numFS; i++) {
2349 curr_fsDataP->probeOK = 0;
2350 curr_fsDataP->ovfCount = 0;
2351 memset(curr_fsDataP->data, 0, numBytes);
2356 /* prev_fsData now contains all the information for the probe cycle
2357 * that just completed. Now count the number of threshold overflows for
2358 * use in the overview screen */
2360 prev_fsDataP = prev_fsData;
2362 numHosts_onfs_alerts = 0;
2363 for (i = 0; i < numFS; i++) {
2364 if (!prev_fsDataP->probeOK) { /* if probe failed */
2366 numHosts_onfs_alerts++;
2368 if (prev_fsDataP->ovfCount) { /* overflows ?? */
2369 num_fs_alerts += prev_fsDataP->ovfCount;
2370 numHosts_onfs_alerts++;
2375 fprintf(debugFD, "Number of FS alerts = %d (on %d hosts)\n",
2376 num_fs_alerts, numHosts_onfs_alerts);
2378 /* flag that the data is now ready to be displayed */
2379 fs_Data_Available = 1;
2381 /* call the Overview frame update routine (update only FS info) */
2382 ovw_refresh(ovw_currPage, OVW_UPDATE_FS);
2384 /* call the File Servers frame update routine */
2385 fs_refresh(fs_currPage, fs_curr_LCol);
2390 } /* save_FS_data_forDisplay */
2395 /*-----------------------------------------------------------------------
2396 * afsmon_FS_Handler()
2399 * This is the File Server probe Handler. It updates the afsmonitor
2400 * probe counts, fs circular buffer indices and calls the functions
2401 * to process the results of this probe.
2405 * Failure: Exits afsmonitor.
2406 *----------------------------------------------------------------------*/
2409 afsmon_FS_Handler(void)
2410 { /* afsmon_FS_Handler() */
2411 static char rn[] = "afsmon_FS_Handler"; /* routine name */
2412 int newProbeCycle; /* start of new probe cycle ? */
2413 int code; /* return status */
2418 "[ %s ] Called, hostName= %s, probeNum= %d, status=%s, collection=%d\n", rn,
2419 xstat_fs_Results.connP->hostName, xstat_fs_Results.probeNum,
2420 xstat_fs_Results.probeOK ? "FAILED" : "OK",
2421 xstat_fs_Results.collectionNumber);
2426 /* print the probe results to output file */
2427 if (afsmon_output) {
2428 code = afsmon_fsOutput(output_filename, afsmon_detOutput);
2431 "[ %s ] output to file %s returned error code=%d\n", rn,
2432 output_filename, code);
2436 /* Update current probe number and circular buffer index. if current
2437 * probenum changed make sure it is only by 1 */
2440 if (xstat_fs_Results.probeNum != afsmon_fs_curr_probeNum) {
2441 if (xstat_fs_Results.probeNum == afsmon_fs_curr_probeNum + 1) {
2442 afsmon_fs_curr_probeNum++;
2445 afsmon_fs_curr_CBindex =
2446 (afsmon_fs_curr_probeNum - 1) % num_bufSlots;
2448 fprintf(stderr, "[ %s ] probe number %d-1 missed\n", rn,
2449 xstat_fs_Results.probeNum);
2455 /* store the results of this probe in the FS circular buffer */
2457 save_FS_results_inCB(newProbeCycle);
2460 /* store the results of the current probe in the fs data display structure.
2461 * if the current probe number changed, swap the current and previous display
2462 * structures. note that the display screen is updated from these structures
2463 * and should start showing the data of the just completed probe cycle */
2465 save_FS_data_forDisplay(&xstat_fs_Results);
2472 /*----------------------------------------------------------------------- *
2477 * Prints the Cache Manager circular buffer
2478 *----------------------------------------------------------------------*/
2482 { /* Print_CM_CB() */
2484 struct afsmon_cm_Results_list *cmlist;
2489 /* print valid info in the cm CB */
2493 "==================== CM Buffer ========================\n");
2494 fprintf(debugFD, "afsmon_cm_curr_CBindex = %d\n",
2495 afsmon_cm_curr_CBindex);
2496 fprintf(debugFD, "afsmon_cm_curr_probeNum = %d\n\n",
2497 afsmon_cm_curr_probeNum);
2499 for (i = 0; i < num_bufSlots; i++) {
2500 fprintf(debugFD, "\t--------- slot %d ----------\n", i);
2501 cmlist = afsmon_cm_ResultsCB[i].list;
2504 for (k = 0; k < MAX_NUM_CM_COLLECTIONS; k++) {
2505 if (!cmlist->empty[k]) {
2507 "\t %d) probeNum = %d host = %s cn = %d",
2509 cmlist->cmResults[k]->probeNum,
2510 cmlist->cmResults[k]->connP->hostName,
2511 cmlist->cmResults[k]->collectionNumber);
2512 if (cmlist->cmResults[k]->probeOK)
2513 fprintf(debugFD, " NOTOK\n");
2515 fprintf(debugFD, " OK\n");
2517 fprintf(debugFD, "\t %d) -- empty --\n", j);
2519 cmlist = cmlist->next;
2522 if (cmlist != (struct afsmon_cm_Results_list *)0)
2523 fprintf(debugFD, "dangling last next ptr cm CB\n");
2529 /*-----------------------------------------------------------------------
2530 * save_CM_results_inCB()
2533 * Saves the results of the latest CM probe in the cm circular
2534 * buffers. If the current probe cycle is in progress the contents
2535 * of xstat_cm_Results are copied to the end of the list of results
2536 * in the current slot (pointed to by afsmon_cm_curr_CBindex). If
2537 * a new probe cycle has started the next slot in the circular buffer
2538 * is initialized and the results copied. Note that the Rx related
2539 * information available in xstat_cm_Results is not copied.
2543 * Failure: Exits afsmonitor.
2544 *----------------------------------------------------------------------*/
2547 save_CM_results_inCB(int a_newProbeCycle) /* start of new probe cycle ? */
2548 { /* save_CM_results_inCB() */
2549 static char rn[] = "save_CM_results_inCB"; /* routine name */
2550 struct afsmon_cm_Results_list *tmp_cmlist_item; /* temp cm list item */
2551 struct xstat_cm_ProbeResults *tmp_cmPR; /* temp ptr */
2557 fprintf(debugFD, "[ %s ] Called, a_newProbeCycle= %d\n", rn,
2562 if (xstat_cm_Results.collectionNumber == AFSCB_XSTATSCOLL_FULL_PERF_INFO) {
2565 fprintf(stderr, "[ %s ] collection number %d is out of range.\n",
2566 rn, xstat_cm_Results.collectionNumber);
2570 /* If a new probe cycle started, mark the list in the current buffer
2571 * slot empty for resuse. Note that afsmon_cm_curr_CBindex was appropriately
2572 * incremented in afsmon_CM_Handler() */
2574 if (a_newProbeCycle) {
2575 tmp_cmlist_item = afsmon_cm_ResultsCB[afsmon_cm_curr_CBindex].list;
2576 for (i = 0; i < numCM; i++) {
2577 tmp_cmlist_item->empty[index] = 1;
2578 tmp_cmlist_item = tmp_cmlist_item->next;
2582 /* locate last unused item in list */
2583 tmp_cmlist_item = afsmon_cm_ResultsCB[afsmon_cm_curr_CBindex].list;
2584 for (i = 0; i < numCM; i++) {
2585 if (tmp_cmlist_item->empty[index])
2587 tmp_cmlist_item = tmp_cmlist_item->next;
2590 /* if we could not find one we have an inconsistent list */
2591 if (!tmp_cmlist_item->empty[index]) {
2593 "[ %s ] list inconsistency 1. unable to find an empty slot to store results of probenum %d of %s\n",
2594 rn, xstat_cm_Results.probeNum,
2595 xstat_cm_Results.connP->hostName);
2599 tmp_cmPR = tmp_cmlist_item->cmResults[index];
2601 /* copy hostname and probe number and probe time and probe status.
2602 * if the probe failed return now */
2604 memcpy(tmp_cmPR->connP->hostName, xstat_cm_Results.connP->hostName,
2605 sizeof(xstat_cm_Results.connP->hostName));
2606 tmp_cmPR->probeNum = xstat_cm_Results.probeNum;
2607 tmp_cmPR->probeTime = xstat_cm_Results.probeTime;
2608 tmp_cmPR->probeOK = xstat_cm_Results.probeOK;
2609 if (xstat_cm_Results.probeOK) { /* probeOK = 1 => notOK */
2610 /* we have a nonempty results structure so mark the list item used */
2611 tmp_cmlist_item->empty[index] = 0;
2616 /* copy connection information */
2617 memcpy(&(tmp_cmPR->connP->skt), &(xstat_cm_Results.connP->skt),
2618 sizeof(struct sockaddr_in));
2620 /**** NEED TO COPY rx_connection INFORMATION HERE ******/
2622 memcpy(tmp_cmPR->connP->hostName, xstat_cm_Results.connP->hostName,
2623 sizeof(xstat_cm_Results.connP->hostName));
2624 tmp_cmPR->collectionNumber = xstat_cm_Results.collectionNumber;
2626 /* copy the probe data information */
2627 tmp_cmPR->data.AFSCB_CollData_len =
2628 min(xstat_cm_Results.data.AFSCB_CollData_len,
2629 afsmon_cm_results_length[index]);
2630 memcpy(tmp_cmPR->data.AFSCB_CollData_val,
2631 xstat_cm_Results.data.AFSCB_CollData_val,
2632 tmp_cmPR->data.AFSCB_CollData_len * sizeof(afs_int32));
2635 /* we have a valid results structure so mark the list item used */
2636 tmp_cmlist_item->empty[index] = 0;
2638 /* print the stored info - to make sure we copied it right */
2639 /* Print_cm_FullPerfInfo(tmp_cmPR); */
2640 /* Print the cm circular buffer */
2643 } /* save_CM_results_inCB */
2647 /*-----------------------------------------------------------------------
2651 * The results of xstat probes are stored in a string format in
2652 * the arrays curr_cmData and prev_cmData. The information stored in
2653 * prev_cmData is copied to the screen.
2654 * This function converts xstat FS results from longs to strings and
2655 * places them in the given buffer (a pointer to an item in curr_cmData).
2656 * When a probe cycle completes, curr_cmData is copied to prev_cmData
2657 * in afsmon_CM_Handler().
2661 *----------------------------------------------------------------------*/
2664 cm_Results_ltoa(struct cm_Display_Data *a_cmData, /* target buffer */
2665 struct xstat_cm_ProbeResults *a_cmResults) /* ptr to xstat cm Results */
2666 { /* cm_Results_ltoa */
2668 static char rn[] = "cm_Results_ltoa"; /* routine name */
2669 struct afs_stats_CMFullPerf *fullP; /* ptr to complete CM stats */
2677 fprintf(debugFD, "[ %s ] Called, a_cmData= %p, a_cmResults= %p\n", rn,
2678 a_cmData, a_cmResults);
2683 fullP = (struct afs_stats_CMFullPerf *)
2684 (a_cmResults->data.AFSCB_CollData_val);
2686 /* There are 4 parts to CM statistics
2687 * - Overall performance statistics (including up/down statistics)
2688 * - This CMs FS RPC operations info
2689 * - This CMs FS RPC errors info
2690 * - This CMs FS transfers info
2691 * - Authentication info
2692 * - [Un]Replicated access info
2695 /* copy overall performance statistics */
2696 srcbuf = (afs_int32 *) & (fullP->perf);
2698 /* we skip the 19 entry, ProtServAddr, so the index must account for this */
2699 for (i = 0; i < NUM_AFS_STATS_CMPERF_LONGS + 1; i++) {
2702 continue; /* skip ProtServerAddr */
2704 sprintf(a_cmData->data[idx], "%d", *srcbuf);
2709 /*printf("Ending index value = %d\n",idx-1); */
2711 /* server up/down statistics */
2712 /* copy file server up/down stats */
2713 srcbuf = (afs_int32 *) (fullP->perf.fs_UpDown);
2715 2 * (sizeof(struct afs_stats_SrvUpDownInfo) / sizeof(afs_int32));
2716 for (i = 0; i < numLongs; i++) {
2717 sprintf(a_cmData->data[idx], "%d", *srcbuf);
2722 /*printf("Ending index value = %d\n",idx-1); */
2724 /* copy volume location server up/down stats */
2725 srcbuf = (afs_int32 *) (fullP->perf.vl_UpDown);
2727 2 * (sizeof(struct afs_stats_SrvUpDownInfo) / sizeof(afs_int32));
2728 for (i = 0; i < numLongs; i++) {
2729 sprintf(a_cmData->data[idx], "%d", *srcbuf);
2734 /*printf("Ending index value = %d\n",idx-1); */
2736 /* copy CMs individual FS RPC operations info */
2737 srcbuf = (afs_int32 *) (fullP->rpc.fsRPCTimes);
2738 for (i = 0; i < AFS_STATS_NUM_FS_RPC_OPS; i++) {
2739 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* numOps */
2742 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* numSuccesses */
2745 tmpbuf = srcbuf++; /* sum time */
2746 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2749 tmpbuf = srcbuf++; /* sqr time */
2750 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2753 tmpbuf = srcbuf++; /* min time */
2754 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2757 tmpbuf = srcbuf++; /* max time */
2758 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2763 /*printf("Ending index value = %d\n",idx-1); */
2765 /* copy CMs individual FS RPC errors info */
2767 srcbuf = (afs_int32 *) (fullP->rpc.fsRPCErrors);
2768 for (i = 0; i < AFS_STATS_NUM_FS_RPC_OPS; i++) {
2769 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* server */
2772 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* network */
2775 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* prot */
2778 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* vol */
2781 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* busies */
2784 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* other */
2789 /*printf("Ending index value = %d\n",idx-1); */
2791 /* copy CMs individual RPC transfers info */
2793 srcbuf = (afs_int32 *) (fullP->rpc.fsXferTimes);
2794 for (i = 0; i < AFS_STATS_NUM_FS_XFER_OPS; i++) {
2795 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* numOps */
2798 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* numSuccesses */
2801 tmpbuf = srcbuf++; /* sum time */
2802 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2805 tmpbuf = srcbuf++; /* sqr time */
2806 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2809 tmpbuf = srcbuf++; /* min time */
2810 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2813 tmpbuf = srcbuf++; /* max time */
2814 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2817 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* sum bytes */
2820 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* min bytes */
2823 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* max bytes */
2826 for (j = 0; j < AFS_STATS_NUM_XFER_BUCKETS; j++) {
2827 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* bucket[j] */
2833 /*printf("Ending index value = %d\n",idx-1); */
2835 /* copy CM operations timings */
2837 srcbuf = (afs_int32 *) (fullP->rpc.cmRPCTimes);
2838 for (i = 0; i < AFS_STATS_NUM_CM_RPC_OPS; i++) {
2839 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* numOps */
2842 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* numSuccesses */
2845 tmpbuf = srcbuf++; /* sum time */
2846 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2849 tmpbuf = srcbuf++; /* sqr time */
2850 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2853 tmpbuf = srcbuf++; /* min time */
2854 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2857 tmpbuf = srcbuf++; /* max time */
2858 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2863 /*printf("Ending index value = %d\n",idx-1); */
2865 /* copy authentication info */
2867 srcbuf = (afs_int32 *) & (fullP->authent);
2868 numLongs = sizeof(struct afs_stats_AuthentInfo) / sizeof(afs_int32);
2869 for (i = 0; i < numLongs; i++) {
2870 sprintf(a_cmData->data[idx], "%d", *srcbuf);
2875 /*printf("Ending index value = %d\n",idx-1); */
2877 /* copy CM [un]replicated access info */
2879 srcbuf = (afs_int32 *) & (fullP->accessinf);
2880 numLongs = sizeof(struct afs_stats_AccessInfo) / sizeof(afs_int32);
2881 for (i = 0; i < numLongs; i++) {
2882 sprintf(a_cmData->data[idx], "%d", *srcbuf);
2887 /*printf("Ending index value = %d\n",idx-1); */
2890 } /* cm_Results_ltoa */
2893 /*-----------------------------------------------------------------------
2894 * Function: check_cm_thresholds()
2897 * Checks the thresholds and sets the overflow flag. Recall that the
2898 * thresholds for each host are stored in the hostEntry lists
2899 * [fs/cm]nameList arrays. The probe results are passed to this
2900 * function in the display-ready format - ie., as strings. Though
2901 * this looks stupid the overhead incurred in converting the strings
2902 * back to floats and comparing them is insignificant and
2903 * programming is easier this way.
2904 * The threshold flags are a part of the display structures
2909 *----------------------------------------------------------------------*/
2912 check_cm_thresholds(struct afsmon_hostEntry *a_hostEntry, /* ptr to hostEntry */
2913 struct cm_Display_Data *a_Data) /* ptr to cm data to be displayed */
2914 { /* check_cm_thresholds */
2916 static char rn[] = "check_cm_thresholds";
2917 struct Threshold *threshP;
2918 double tValue; /* threshold value */
2919 double pValue; /* probe value */
2922 int count; /* number of thresholds exceeded */
2925 fprintf(debugFD, "[ %s ] Called, a_hostEntry= %p, a_Data= %p\n", rn,
2926 a_hostEntry, a_Data);
2930 if (a_hostEntry->numThresh == 0) {
2931 /* store in ovf count ?? */
2936 threshP = a_hostEntry->thresh;
2937 for (i = 0; i < a_hostEntry->numThresh; i++) {
2938 if (threshP->itemName[0] == '\0') {
2942 idx = threshP->index; /* positional index to the data array */
2943 tValue = atof(threshP->threshVal); /* threshold value */
2944 pValue = atof(a_Data->data[idx]); /* probe value */
2945 if (pValue > tValue) {
2949 "[ %s ] cm = %s, thresh ovf for %s, threshold= %s, probevalue= %s\n",
2950 rn, a_hostEntry->hostName, threshP->itemName,
2951 threshP->threshVal, a_Data->data[idx]);
2955 /* if the threshold is crossed, call the handler function
2956 * only if this was a transition -ie, if the threshold was
2957 * crossed in the last probe too just count & keep quite! */
2959 if (!a_Data->threshOvf[idx]) {
2960 a_Data->threshOvf[idx] = 1;
2961 /* call the threshold handler if provided */
2962 if (threshP->handler[0] != '\0') {
2964 fprintf(debugFD, "[ %s ] Calling ovf handler %s\n",
2965 rn, threshP->handler);
2968 execute_thresh_handler(threshP->handler, a_Data->hostName,
2969 CM, threshP->itemName,
2977 /* in case threshold was previously crossed, blank it out */
2978 a_Data->threshOvf[idx] = 0;
2981 /* store the overflow count */
2982 a_Data->ovfCount = count;
2985 } /* check_cm_thresholds */
2988 /*-----------------------------------------------------------------------
2989 * save_CM_data_forDisplay()
2992 * Does the following:
2993 * - if the probe number changed (ie, a cycle completed) curr_cmData
2994 * is copied to prev_cmData, curr_cmData zeroed and refresh the
2995 * overview screen and file server screen with the new data.
2996 * - store the results of the current probe from xstat_cm_Results into
2997 * curr_cmData. ie., convert longs to strings.
2998 * - check the thresholds
3002 * Failure: Exits afsmonitor.
3004 *----------------------------------------------------------------------*/
3007 save_CM_data_forDisplay(struct xstat_cm_ProbeResults *a_cmResults)
3008 { /* save_CM_data_forDisplay */
3010 static char rn[] = "save_CM_data_forDisplay"; /* routine name */
3011 struct cm_Display_Data *curr_cmDataP;
3012 struct cm_Display_Data *prev_cmDataP;
3013 struct afsmon_hostEntry *curr_host;
3014 static int results_Received = 0; /* number of probes reveived in
3015 * the current cycle. If this is equal to numFS we got all
3016 * the data we want in this cycle and can now display it */
3024 fprintf(debugFD, "[ %s ] Called, a_cmResults= %p\n", rn, a_cmResults);
3028 /* store results in the display array */
3031 curr_cmDataP = curr_cmData;
3032 for (i = 0; i < numCM; i++) {
3033 if ((strcasecmp(curr_cmDataP->hostName, a_cmResults->connP->hostName))
3043 "[ %s ] Could not insert CM probe results for host %s in cm display array\n",
3044 rn, a_cmResults->connP->hostName);
3048 /* Check the status of the probe. If it succeeded, we store its
3049 * results in the display data structure. If it failed we only mark
3050 * the failed status in the display data structure. */
3053 if (a_cmResults->probeOK) { /* 1 => notOK the xstat results */
3054 curr_cmDataP->probeOK = 0;
3056 /* print the probe status */
3058 fprintf(debugFD, "\n\t\t ----- cm display data ------\n");
3059 fprintf(debugFD, "HostName = %s PROBE FAILED \n",
3060 curr_cmDataP->hostName);
3064 } else { /* probe succeeded, update display data structures */
3065 curr_cmDataP->probeOK = 1;
3068 /* covert longs to strings and place them in curr_cmDataP */
3069 cm_Results_ltoa(curr_cmDataP, a_cmResults);
3071 /* compare with thresholds and set the overflow flags.
3072 * note that the threshold information is in the hostEntry structure and
3073 * each threshold item has a positional index associated with it */
3075 /* locate the hostEntry for this host */
3077 curr_host = CMnameList;
3078 for (i = 0; i < numCM; i++) {
3079 if (strcasecmp(curr_host->hostName, a_cmResults->connP->hostName)
3084 curr_host = curr_host->next;
3089 code = check_cm_thresholds(curr_host, curr_cmDataP);
3091 fprintf(stderr, "[ %s ] Error in checking thresholds\n", rn);
3095 /* print the info we just saved */
3097 fprintf(debugFD, "\n\t\t ----- CM display data ------\n");
3098 fprintf(debugFD, "HostName = %s\n", curr_cmDataP->hostName);
3099 for (i = 0; i < NUM_CM_STAT_ENTRIES; i++) {
3102 fprintf(debugFD, "\t -- Overall Perf Info --\n");
3106 "\t -- File Server up/down stats - same cell --\n");
3110 "\t -- File Server up/down stats - diff cell --\n");
3114 "\t -- VL server up/down stats - same cell --\n");
3118 "\t -- VL server up/down stats - diff cell --\n");
3121 fprintf(debugFD, "\t -- FS Operation Timings --\n");
3124 fprintf(debugFD, "\t -- FS Error Info --\n");
3127 fprintf(debugFD, "\t -- FS Transfer Timings --\n");
3130 fprintf(debugFD, "\t -- CM Operations Timings --\n");
3133 fprintf(debugFD, "\t -- Authentication Info --\n");
3136 fprintf(debugFD, "\t -- Access Info --\n");
3142 fprintf(debugFD, "%20s %30s %s\n", curr_cmDataP->data[i],
3144 curr_cmDataP->threshOvf[i] ? "(ovf)" : "");
3146 fprintf(debugFD, "\t\t--------------------------------\n\n");
3149 } /* if the probe succeeded, update the display data structures */
3151 /* if we have received a reply from all the hosts for this probe cycle,
3152 * it is time to display the data */
3155 if (results_Received == numCM * num_cm_collections) {
3156 results_Received = 0;
3158 if (afsmon_cm_curr_probeNum != afsmon_cm_prev_probeNum + 1) {
3159 sprintf(errMsg, "[ %s ] Probe number %d missed! \n", rn,
3160 afsmon_cm_prev_probeNum + 1);
3163 afsmon_cm_prev_probeNum++;
3166 /* backup the display data of the probe cycle that just completed -
3167 * ie., store curr_cmData in prev_cmData */
3169 memcpy((char *)prev_cmData, (char *)curr_cmData,
3170 (numCM * sizeof(struct cm_Display_Data)));
3173 /* initialize curr_cmData but retain the threshold flag information.
3174 * The previous state of threshold flags is used in check_cm_thresholds() */
3176 curr_cmDataP = curr_cmData;
3177 numBytes = NUM_CM_STAT_ENTRIES * CM_STAT_STRING_LEN;
3178 for (i = 0; i < numCM; i++) {
3179 curr_cmDataP->probeOK = 0;
3180 curr_cmDataP->ovfCount = 0;
3181 memset(curr_cmDataP->data, 0, numBytes);
3185 /* prev_cmData now contains all the information for the probe cycle
3186 * that just completed. Now count the number of threshold overflows for
3187 * use in the overview screen */
3189 prev_cmDataP = prev_cmData;
3191 numHosts_oncm_alerts = 0;
3192 for (i = 0; i < numCM; i++) {
3193 if (!prev_cmDataP->probeOK) { /* if probe failed */
3195 numHosts_oncm_alerts++;
3196 } else if (prev_cmDataP->ovfCount) { /* overflows ?? */
3197 num_cm_alerts += prev_cmDataP->ovfCount;
3198 numHosts_oncm_alerts++;
3203 fprintf(debugFD, "Number of CM alerts = %d (on %d hosts)\n",
3204 num_cm_alerts, numHosts_oncm_alerts);
3207 /* flag that the data is now ready to be displayed */
3208 cm_Data_Available = 1;
3210 /* update the Overview frame (only CM info) */
3211 ovw_refresh(ovw_currPage, OVW_UPDATE_CM);
3213 /* update the Cache Managers frame */
3214 cm_refresh(cm_currPage, cm_curr_LCol);
3220 } /* save_CM_data_forDisplay */
3224 /*-----------------------------------------------------------------------
3225 * afsmon_CM_Handler()
3228 * This is the Cache Manager probe Handler. It updates the afsmonitor
3229 * probe counts, cm circular buffer indices and calls the functions
3230 * to process the results of this probe.
3234 * Failure: Exits afsmonitor.
3235 *----------------------------------------------------------------------*/
3238 afsmon_CM_Handler(void)
3239 { /* afsmon_CM_Handler() */
3240 static char rn[] = "afsmon_CM_Handler"; /* routine name */
3241 int code; /* return status */
3242 int newProbeCycle; /* start of new probe cycle ? */
3246 "[ %s ] Called, hostName= %s, probeNum= %d, status= %s\n", rn,
3247 xstat_cm_Results.connP->hostName, xstat_cm_Results.probeNum,
3248 xstat_cm_Results.probeOK ? "FAILED" : "OK");
3253 /* print the probe results to output file */
3254 if (afsmon_output) {
3255 code = afsmon_cmOutput(output_filename, afsmon_detOutput);
3258 "[ %s ] output to file %s returned error code=%d\n", rn,
3259 output_filename, code);
3263 /* Update current probe number and circular buffer index. if current
3264 * probenum changed make sure it is only by 1 */
3267 if (xstat_cm_Results.probeNum != afsmon_cm_curr_probeNum) {
3268 if (xstat_cm_Results.probeNum == afsmon_cm_curr_probeNum + 1) {
3269 afsmon_cm_curr_probeNum++;
3272 afsmon_cm_curr_CBindex =
3273 (afsmon_cm_curr_probeNum - 1) % num_bufSlots;
3275 fprintf(stderr, "[ %s ] probe number %d-1 missed\n", rn,
3276 xstat_cm_Results.probeNum);
3281 /* save the results of this probe in the CM buffer */
3283 save_CM_results_inCB(newProbeCycle);
3285 /* store the results of the current probe in the cm data display structure.
3286 * if the current probe number changed, swap the current and previous display
3287 * structures. note that the display screen is updated from these structures
3288 * and should start showing the data of the just completed probe cycle */
3290 save_CM_data_forDisplay(&xstat_cm_Results);
3295 /*-----------------------------------------------------------------------
3299 * Allocate and Initialize circular buffers for file servers.
3303 * Failure to allocate memory: exits afsmonitor.
3304 *----------------------------------------------------------------------*/
3307 init_fs_buffers(void)
3308 { /* init_fs_buffers() */
3309 static char rn[] = "init_fs_buffers"; /* routine name */
3310 struct afsmon_fs_Results_list *new_fslist_item; /* ptr for new struct */
3311 struct afsmon_fs_Results_list *tmp_fslist_item; /* temp ptr */
3312 struct xstat_fs_ProbeResults *new_fsPR; /* ptr for new struct */
3319 fprintf(debugFD, "[ %s ] Called\n", rn);
3323 /* allocate memory for the circular buffer of pointers */
3325 afsmon_fs_ResultsCB = (struct afsmon_fs_Results_CBuffer *)
3326 malloc(sizeof(struct afsmon_fs_Results_CBuffer) * num_bufSlots);
3328 /* initialize the fs circular buffer */
3329 for (i = 0; i < num_bufSlots; i++) {
3330 afsmon_fs_ResultsCB[i].list = (struct afsmon_fs_Results_list *)0;
3331 afsmon_fs_ResultsCB[i].probeNum = 0;
3334 /* create a list of numFS items to store fs probe results for
3335 * each slot in CB */
3337 if (numFS) { /* if we have file servers to monitor */
3338 for (bufslot = 0; bufslot < num_bufSlots; bufslot++) {
3339 numfs = numFS; /* get the number of servers */
3342 /* if any of these mallocs fail we only need to free the memory we
3343 * have allocated in this iteration. the rest of it which is in a
3344 * proper linked list will be freed in afsmon_Exit */
3346 /* allocate memory for an fs list item */
3347 new_fslist_item = (struct afsmon_fs_Results_list *)
3348 malloc(sizeof(struct afsmon_fs_Results_list));
3349 if (new_fslist_item == (struct afsmon_fs_Results_list *)0)
3352 for (i = 0; i < MAX_NUM_FS_COLLECTIONS; i++) {
3353 /* allocate memory to store xstat_fs_Results */
3354 new_fsPR = (struct xstat_fs_ProbeResults *)
3355 malloc(sizeof(struct xstat_fs_ProbeResults));
3357 free(new_fslist_item);
3361 new_fsPR->connP = (struct xstat_fs_ConnectionInfo *)
3362 malloc(sizeof(struct xstat_fs_ConnectionInfo));
3363 if (new_fsPR->connP == (struct xstat_fs_ConnectionInfo *)0) {
3364 free(new_fslist_item);
3369 /* >>> need to allocate rx connection info structure here <<< */
3370 new_fsPR->data.AFS_CollData_val = (afs_int32 *)
3371 malloc(afsmon_fs_results_length[i] * sizeof(afs_int32));
3372 if (new_fsPR->data.AFS_CollData_val == NULL) {
3373 free(new_fslist_item);
3374 free(new_fsPR->connP);
3378 new_fslist_item->fsResults[i] = new_fsPR;
3379 new_fslist_item->empty[i] = 1;
3382 /* initialize this list entry */
3383 new_fslist_item->next = (struct afsmon_fs_Results_list *)0;
3385 /* store it at the end of the fs list in the current CB slot */
3386 if (afsmon_fs_ResultsCB[bufslot].list ==
3387 (struct afsmon_fs_Results_list *)0)
3388 afsmon_fs_ResultsCB[bufslot].list = new_fslist_item;
3390 tmp_fslist_item = afsmon_fs_ResultsCB[bufslot].list;
3392 while (tmp_fslist_item !=
3393 (struct afsmon_fs_Results_list *)0) {
3394 if (tmp_fslist_item->next ==
3395 (struct afsmon_fs_Results_list *)0)
3397 tmp_fslist_item = tmp_fslist_item->next;
3399 /* something goofed. exit */
3400 fprintf(stderr, "[ %s ] list creation error\n",
3405 tmp_fslist_item->next = new_fslist_item;
3408 } /* while servers */
3409 } /* for each buffer slot */
3410 } /* if we have file servers to monitor */
3414 /*-----------------------------------------------------------------------
3418 * Allocate and Initialize circular buffers for cache managers.
3422 * Failure to allocate memory: exits afsmonitor.
3423 *----------------------------------------------------------------------*/
3426 init_cm_buffers(void)
3427 { /* init_cm_buffers() */
3428 static char rn[] = "init_cm_buffers"; /* routine name */
3429 struct afsmon_cm_Results_list *new_cmlist_item; /* ptr for new struct */
3430 struct afsmon_cm_Results_list *tmp_cmlist_item; /* temp ptr */
3431 struct xstat_cm_ProbeResults *new_cmPR; /* ptr for new struct */
3437 fprintf(debugFD, "[ %s ] Called\n", rn);
3441 /* allocate memory for the circular buffer of pointers */
3442 afsmon_cm_ResultsCB = (struct afsmon_cm_Results_CBuffer *)
3443 malloc(sizeof(struct afsmon_cm_Results_CBuffer) * num_bufSlots);
3445 /* initialize the fs circular buffer */
3446 for (i = 0; i < num_bufSlots; i++) {
3447 afsmon_cm_ResultsCB[i].list = (struct afsmon_cm_Results_list *)0;
3448 afsmon_cm_ResultsCB[i].probeNum = 0;
3451 /* create a list of numCM items to store fs probe results for
3452 * each slot in CB */
3454 if (numCM) { /* if we have file servers to monitor */
3455 for (bufslot = 0; bufslot < num_bufSlots; bufslot++) {
3456 numcm = numCM; /* get the number of servers */
3459 /* if any of these mallocs fail we only need to free the memory we
3460 * have allocated in this iteration. the rest of it which is in a
3461 * proper linked list will be freed in afsmon_Exit */
3463 /* allocate memory for an fs list item */
3464 new_cmlist_item = (struct afsmon_cm_Results_list *)
3465 malloc(sizeof(struct afsmon_cm_Results_list));
3466 if (new_cmlist_item == (struct afsmon_cm_Results_list *)0)
3469 for (i = 0; i < MAX_NUM_CM_COLLECTIONS; i++) {
3470 /* allocate memory to store xstat_cm_Results */
3471 new_cmPR = (struct xstat_cm_ProbeResults *)
3472 malloc(sizeof(struct xstat_cm_ProbeResults));
3474 free(new_cmlist_item);
3477 new_cmPR->connP = (struct xstat_cm_ConnectionInfo *)
3478 malloc(sizeof(struct xstat_cm_ConnectionInfo));
3479 if (!new_cmPR->connP) {
3480 free(new_cmlist_item);
3485 /* >>> need to allocate rx connection info structure here <<< */
3487 new_cmPR->data.AFSCB_CollData_val =
3488 malloc(XSTAT_CM_FULLPERF_RESULTS_LEN
3489 *sizeof(afs_int32));
3490 if (new_cmPR->data.AFSCB_CollData_val == NULL) {
3491 free(new_cmlist_item);
3492 free(new_cmPR->connP);
3497 new_cmlist_item->cmResults[i] = new_cmPR;
3498 new_cmlist_item->empty[i] = 1;
3501 /* initialize this list entry */
3502 new_cmlist_item->next = (struct afsmon_cm_Results_list *)0;
3504 /* store it at the end of the cm list in the current CB slot */
3505 if (afsmon_cm_ResultsCB[bufslot].list ==
3506 (struct afsmon_cm_Results_list *)0)
3507 afsmon_cm_ResultsCB[bufslot].list = new_cmlist_item;
3509 tmp_cmlist_item = afsmon_cm_ResultsCB[bufslot].list;
3511 while (tmp_cmlist_item !=
3512 (struct afsmon_cm_Results_list *)0) {
3513 if (tmp_cmlist_item->next ==
3514 (struct afsmon_cm_Results_list *)0)
3516 tmp_cmlist_item = tmp_cmlist_item->next;
3518 /* something goofed. exit */
3519 fprintf(stderr, "[ %s ] list creation error\n",
3524 tmp_cmlist_item->next = new_cmlist_item;
3527 } /* while servers */
3528 } /* for each buffer slot */
3530 /* if we have file servers to monitor */
3531 /* print the CB to make sure it is right */
3535 } /* init_cm_buffers() */
3538 /*-------------------------------------------------------------------------
3539 * init_print_buffers()
3542 * Allocate and initialize the buffers used for printing results
3543 * to the display screen. These buffers store the current and
3544 * previous probe results in ascii format.
3549 *------------------------------------------------------------------------*/
3552 init_print_buffers(void)
3553 { /* init_print_buffers */
3555 static char rn[] = "init_print_buffers"; /* routine name */
3556 struct fs_Display_Data *tmp_fsData1; /* temp pointers */
3557 struct fs_Display_Data *tmp_fsData2;
3558 struct cm_Display_Data *tmp_cmData1;
3559 struct cm_Display_Data *tmp_cmData2;
3560 struct afsmon_hostEntry *tmp_fsNames;
3561 struct afsmon_hostEntry *tmp_cmNames;
3566 fprintf(debugFD, "[ %s ] Called\n", rn);
3570 /* allocate numFS blocks of the FS print structure. */
3572 /* we need two instances of this structure - one (curr_fsData) for storing
3573 * the results of the fs probes currently in progress and another (prev_fsData)
3574 * for the last completed probe. The display is updated from the contents of
3575 * prev_fsData. The pointers curr_fsData & prev_fsData are switched whenever
3576 * the probe number changes */
3579 numBytes = numFS * sizeof(struct fs_Display_Data);
3580 curr_fsData = malloc(numBytes);
3581 if (curr_fsData == (struct fs_Display_Data *)0) {
3582 fprintf(stderr, "[ %s ] Memory allocation failure\n", rn);
3585 memset(curr_fsData, 0, numBytes);
3587 numBytes = numFS * sizeof(struct fs_Display_Data);
3588 prev_fsData = malloc(numBytes);
3589 if (prev_fsData == (struct fs_Display_Data *)0) {
3590 fprintf(stderr, "[ %s ] Memory allocation failure\n", rn);
3593 memset(prev_fsData, 0, numBytes);
3595 /* fill in the host names */
3596 tmp_fsData1 = curr_fsData;
3597 tmp_fsData2 = curr_fsData;
3598 tmp_fsNames = FSnameList;
3599 for (i = 0; i < numFS; i++) {
3600 strncpy(tmp_fsData1->hostName, tmp_fsNames->hostName,
3602 strncpy(tmp_fsData2->hostName, tmp_fsNames->hostName,
3606 tmp_fsNames = tmp_fsNames->next;;
3611 /* if file servers to monitor */
3612 /* allocate numCM blocks of the CM print structure */
3613 /* we need two instances of this structure for the same reasons as above */
3615 numBytes = numCM * sizeof(struct cm_Display_Data);
3617 curr_cmData = malloc(numBytes);
3618 if (curr_cmData == (struct cm_Display_Data *)0) {
3619 fprintf(stderr, "[ %s ] Memory allocation failure\n", rn);
3622 memset(curr_cmData, 0, numBytes);
3624 numBytes = numCM * sizeof(struct cm_Display_Data);
3625 prev_cmData = malloc(numBytes);
3626 if (prev_cmData == (struct cm_Display_Data *)0) {
3627 fprintf(stderr, "[ %s ] Memory allocation failure\n", rn);
3630 memset(prev_cmData, 0, numBytes);
3632 /* fill in the host names */
3633 tmp_cmData1 = curr_cmData;
3634 tmp_cmData2 = curr_cmData;
3635 tmp_cmNames = CMnameList;
3636 for (i = 0; i < numCM; i++) {
3637 strncpy(tmp_cmData1->hostName, tmp_cmNames->hostName,
3639 strncpy(tmp_cmData2->hostName, tmp_cmNames->hostName,
3643 tmp_cmNames = tmp_cmNames->next;;
3647 /* if cache managers to monitor */
3650 } /* init_print_buffers */
3652 /*-----------------------------------------------------------------------
3656 * Trap the interrupt signal. This function is useful only until
3657 * gtx is initialized.
3658 *----------------------------------------------------------------------*/
3661 quit_signal(int sig)
3663 fprintf(stderr, "Received signal %d \n", sig);
3669 /*-----------------------------------------------------------------------
3673 * This is where we start it all. Initialize an array of sockets for
3674 * file servers and cache cache managers and call the xstat_[fs/cm]_Init
3675 * routines. The last step is to call the gtx input server which
3676 * grabs control of the keyboard.
3679 * Does not return. Control is periodically returned to the afsmonitor
3680 * thru afsmon_[FS/CM]_Handler() routines and also through the gtx
3681 * keyboard handler calls.
3683 *----------------------------------------------------------------------*/
3686 afsmon_execute(void)
3687 { /* afsmon_execute() */
3688 static char rn[] = "afsmon_execute"; /* routine name */
3689 static char fullhostname[128]; /* full host name */
3690 struct sockaddr_in *FSSktArray; /* fs socket array */
3691 int FSsktbytes; /* num bytes in above */
3692 struct sockaddr_in *CMSktArray; /* cm socket array */
3693 int CMsktbytes; /* num bytes in above */
3694 struct sockaddr_in *curr_skt; /* ptr to current socket */
3695 struct afsmon_hostEntry *curr_FS; /* ptr to FS name list */
3696 struct afsmon_hostEntry *curr_CM; /* ptr to CM name list */
3697 struct hostent *he; /* host entry */
3698 int FSinitFlags = 0; /* flags for xstat_fs_Init */
3699 int CMinitFlags = 0; /* flags for xstat_cm_Init */
3700 int code; /* function return code */
3701 struct timeval tv; /* time structure */
3706 fprintf(debugFD, "[ %s ] Called\n", rn);
3711 /* process file server entries */
3713 afs_int32 collIDs[MAX_NUM_FS_COLLECTIONS];
3715 /* Allocate an array of sockets for each fileserver we monitor */
3717 FSsktbytes = numFS * sizeof(struct sockaddr_in);
3718 FSSktArray = malloc(FSsktbytes);
3719 if (FSSktArray == (struct sockaddr_in *)0) {
3721 "[ %s ] cannot malloc %d sockaddr_ins for fileservers\n",
3726 memset(FSSktArray, 0, FSsktbytes);
3728 /* Fill in the socket information for each fileserve */
3730 curr_skt = FSSktArray;
3731 curr_FS = FSnameList; /* FS name list header */
3733 strncpy(fullhostname, curr_FS->hostName, sizeof(fullhostname));
3734 he = GetHostByName(fullhostname);
3736 fprintf(stderr, "[ %s ] Cannot get host info for %s\n", rn,
3740 strncpy(curr_FS->hostName, he->h_name, HOST_NAME_LEN); /* complete name */
3741 memcpy(&(curr_skt->sin_addr.s_addr), he->h_addr, 4);
3742 curr_skt->sin_family = AF_INET; /*Internet family */
3743 curr_skt->sin_port = htons(7000); /*FileServer port */
3744 #ifdef STRUCT_SOCKADDR_HAS_SA_LEN
3745 curr_skt->sin_len = sizeof(struct sockaddr_in);
3748 /* get the next dude */
3750 curr_FS = curr_FS->next;
3753 /* Initialize collection IDs, depending on the data requested. */
3754 num_fs_collections = 0;
3755 for (i = 0; i < fs_DisplayItems_count; i++) {
3756 index = fs_Display_map[i];
3757 if (FS_FULLPERF_ENTRY_START <= index && index <= FS_FULLPERF_ENTRY_END) {
3758 collIDs[num_fs_collections++] = AFS_XSTATSCOLL_FULL_PERF_INFO;
3762 for (i = 0; i < fs_DisplayItems_count; i++) {
3763 index = fs_Display_map[i];
3764 if (FS_CB_ENTRY_START <= index && index <= FS_CB_ENTRY_END) {
3765 collIDs[num_fs_collections++] = AFS_XSTATSCOLL_CBSTATS;
3771 if (afsmon_onceOnly) /* option not provided at this time */
3772 FSinitFlags |= XSTAT_FS_INITFLAG_ONE_SHOT;
3775 fprintf(debugFD, "[ %s ] Calling xstat_fs_Init \n", rn);
3779 code = xstat_fs_Init(numFS, /*Num servers */
3780 FSSktArray, /*File Server socket array */
3781 afsmon_probefreq, /*probe frequency */
3782 afsmon_FS_Handler, /*Handler routine */
3783 FSinitFlags, /*Initialization flags */
3784 num_fs_collections, /*Number of collection IDs */
3785 collIDs); /*Ptr to collection ID */
3788 fprintf(stderr, "[ %s ] xstat_fs_init returned error\n", rn);
3795 /* end of process fileserver entries */
3796 /* process cache manager entries */
3798 afs_int32 collIDs[MAX_NUM_CM_COLLECTIONS];
3800 /* Allocate an array of sockets for each cache manager we monitor */
3802 CMsktbytes = numCM * sizeof(struct sockaddr_in);
3803 CMSktArray = malloc(CMsktbytes);
3804 if (CMSktArray == (struct sockaddr_in *)0) {
3806 "[ %s ] cannot malloc %d sockaddr_ins for CM entries\n",
3811 memset(CMSktArray, 0, CMsktbytes);
3813 /* Fill in the socket information for each CM */
3815 curr_skt = CMSktArray;
3816 curr_CM = CMnameList; /* CM name list header */
3818 strncpy(fullhostname, curr_CM->hostName, sizeof(fullhostname));
3819 he = GetHostByName(fullhostname);
3821 fprintf(stderr, "[ %s ] Cannot get host info for %s\n", rn,
3825 strncpy(curr_CM->hostName, he->h_name, HOST_NAME_LEN); /* complete name */
3826 memcpy(&(curr_skt->sin_addr.s_addr), he->h_addr, 4);
3827 curr_skt->sin_family = AF_INET;
3828 curr_skt->sin_port = htons(7001); /* Cache Manager port */
3829 #ifdef STRUCT_SOCKADDR_HAS_SA_LEN
3830 curr_skt->sin_len = sizeof(struct sockaddr_in);
3833 /* get the next dude */
3835 curr_CM = curr_CM->next;
3838 /* initialize collection IDs. We need only one entry since we collect
3839 * all the information from xstat */
3840 num_cm_collections = 0;
3841 collIDs[num_cm_collections++] = AFSCB_XSTATSCOLL_FULL_PERF_INFO;
3844 if (afsmon_onceOnly) /* once only ? */
3845 CMinitFlags |= XSTAT_CM_INITFLAG_ONE_SHOT;
3848 fprintf(debugFD, "[ %s ] Calling xstat_cm_Init \n", rn);
3852 code = xstat_cm_Init(numCM, /*Num servers */
3853 CMSktArray, /*Cache Manager socket array */
3854 afsmon_probefreq, /*probe frequency */
3855 afsmon_CM_Handler, /*Handler routine */
3856 CMinitFlags, /*Initialization flags */
3857 num_cm_collections, /*Number of collection IDs */
3858 collIDs); /*Ptr to collection ID */
3861 fprintf(stderr, "[ %s ] xstat_cm_init returned error\n", rn);
3868 /* end of process cache manager entries */
3869 /* if only one probe was required setup a waiting process for the
3870 * termination signal */
3871 if (afsmon_onceOnly) {
3872 code = LWP_WaitProcess(&terminationEvent);
3875 fprintf(debugFD, "LWP_WaitProcess() returned error %d\n",
3883 /* start the gtx input server */
3884 code = (intptr_t)gtx_InputServer(afsmon_win);
3886 fprintf(stderr, "[ %s ] Failed to start input server \n", rn);
3890 /* This part of the code is reached only if the input server is not started
3891 * for debugging purposes */
3894 tv.tv_sec = 24 * 60;
3896 fprintf(stderr, "[ %s ] going to sleep ...\n", rn);
3898 code = IOMGR_Select(0, /*Num fds */
3899 0, /*Descriptors ready for reading */
3900 0, /*Descriptors ready for writing */
3901 0, /*Descriptors with exceptional conditions */
3902 &tv); /*Timeout structure */
3905 "[ %s ] IOMGR_Select() returned non-zero value %d\n", rn,
3913 /*-----------------------------------------------------------------------
3917 * Afsmonitor initialization routine.
3918 * - processes command line parameters
3919 * - call functions to:
3920 * - process config file
3921 * - initialize circular buffers and display buffers
3923 * - execute afsmonitor
3924 * - initialize the display maps [fs/cm]_Display_map[].
3927 * Success: Does not return from the call to afsmon_execute().
3928 * Failure: Exits afsmonitor.
3929 *----------------------------------------------------------------------*/
3932 afsmonInit(struct cmd_syndesc *as, void *arock)
3933 { /* afsmonInit() */
3935 static char rn[] = "afsmonInit"; /* Routine name */
3936 char *debug_filename; /* pointer to debug filename */
3937 FILE *outputFD; /* output file descriptor */
3938 struct cmd_item *hostPtr; /* ptr to parse command line args */
3939 char buf[256]; /* buffer for processing hostnames */
3944 fprintf(debugFD, "[ %s ] Called, as= %p\n", rn, as);
3948 /* Open the debug file if -debug option is specified */
3949 if (as->parms[P_DEBUG].items != 0) {
3951 debug_filename = as->parms[P_DEBUG].items->data;
3952 debugFD = fopen(debug_filename, "w");
3953 if (debugFD == (FILE *) 0) {
3954 printf("[ %s ] Failed to open debugging file %s for writing\n",
3962 fprintf(debugFD, "[ %s ] Called\n", rn);
3966 /* use curses always until we support other packages */
3968 wpkg_to_use = atoi(as->parms[P_PACKAGE].items->data);
3970 switch (wpkg_to_use) {
3971 case GATOR_WIN_CURSES:
3972 fprintf(stderr, "curses\n");
3974 case GATOR_WIN_DUMB:
3975 fprintf(stderr, "dumb terminal\n");
3978 fprintf(stderr, "X11\n");
3981 fprintf(stderr, "Illegal graphics package: %d\n", wpkg_to_use);
3983 } /*end switch (wpkg_to_use) */
3986 wpkg_to_use = GATOR_WIN_CURSES;
3988 /* get probe frequency . We check for meaningful bounds on the frequency
3989 * and reset to the default value if needed. The upper bound of 24
3990 * hours looks ridiculous though! */
3992 afsmon_probefreq = 0;
3993 if (as->parms[P_FREQUENCY].items != 0)
3994 afsmon_probefreq = atoi(as->parms[P_FREQUENCY].items->data);
3996 afsmon_probefreq = DEFAULT_FREQUENCY;
3998 if (afsmon_probefreq <= 0 || afsmon_probefreq > 24 * 60 * 60) {
3999 afsmon_probefreq = DEFAULT_FREQUENCY;
4002 "[ %s ] Invalid probe frequency %s specified, resetting to default value %d seconds\n",
4003 rn, as->parms[P_FREQUENCY].items->data, afsmon_probefreq);
4007 "Invalid probe frequency %s specified, resetting to default value %d seconds\n",
4008 as->parms[P_FREQUENCY].items->data, afsmon_probefreq);
4013 /* make sure output file is writable, else complain now */
4014 /* we will open and close it as needed after probes */
4016 if (as->parms[P_OUTPUT].items != 0) {
4017 afsmon_output = 1; /* output flag */
4018 strncpy(output_filename, as->parms[P_OUTPUT].items->data, 80);
4019 outputFD = fopen(output_filename, "a");
4020 if (outputFD == (FILE *) 0) {
4021 fprintf(stderr, "Failed to open output file %s \n",
4024 fprintf(debugFD, "[ %s ] Failed to open output file %s \n",
4025 rn, output_filename);
4030 fprintf(debugFD, "[ %s ] output file is %s\n", rn,
4036 /* detailed statistics to storage file */
4037 if (as->parms[P_DETAILED].items != 0) {
4038 if (as->parms[P_OUTPUT].items == 0) {
4040 "-detailed switch can be used only with -output\n");
4043 afsmon_detOutput = 1;
4046 /* Initialize host list headers */
4047 FSnameList = (struct afsmon_hostEntry *)0;
4048 CMnameList = (struct afsmon_hostEntry *)0;
4050 /* The -config option is mutually exclusive with the -fshosts,-cmhosts
4053 if (as->parms[P_CONFIG].items) {
4054 if (as->parms[P_FSHOSTS].items || as->parms[P_CMHOSTS].items) {
4056 "Cannot use -config option with -fshosts or -cmhosts\n");
4060 if (!as->parms[P_FSHOSTS].items && !as->parms[P_CMHOSTS].items) {
4062 "Must specify either -config or (-fshosts and/or -cmhosts) options \n");
4068 /* If a file server host is specified on the command line we reuse
4069 * parse_hostEntry() function . Just the pass the info as if it were
4070 * read off the config file */
4072 if (as->parms[P_FSHOSTS].items) {
4073 hostPtr = as->parms[P_FSHOSTS].items;
4074 while (hostPtr != (struct cmd_item *)0) {
4075 sprintf(buf, "fs %s", hostPtr->data);
4076 code = parse_hostEntry(buf);
4078 fprintf(stderr, "Could not parse %s\n", hostPtr->data);
4082 hostPtr = hostPtr->next;
4086 /* same as above for -cmhosts */
4087 if (as->parms[P_CMHOSTS].items) {
4088 hostPtr = as->parms[P_CMHOSTS].items;
4089 while (hostPtr != (struct cmd_item *)0) {
4090 sprintf(buf, "cm %s", hostPtr->data);
4091 code = parse_hostEntry(buf);
4093 fprintf(stderr, "Could not parse %s\n", hostPtr->data);
4097 hostPtr = hostPtr->next;
4101 /* number of slots in circular buffers */
4102 if (as->parms[P_BUFFERS].items)
4103 num_bufSlots = atoi(as->parms[P_BUFFERS].items->data);
4105 num_bufSlots = DEFAULT_BUFSLOTS;
4107 /* Initialize xx_showFlags[]. This array is used solely for processing the
4108 * "show" directives in the config file in parse_showEntries() */
4109 for (i = 0; i < NUM_FS_STAT_ENTRIES; i++)
4110 fs_showFlags[i] = 0;
4111 for (i = 0; i < NUM_CM_STAT_ENTRIES; i++)
4112 cm_showFlags[i] = 0;
4115 /* Process the configuration file if given. This initializes among other
4116 * things, the list of FS & CM names in FSnameList and CMnameList */
4118 if (as->parms[P_CONFIG].items)
4119 process_config_file(as->parms[P_CONFIG].items->data);
4121 /* print out the FS and CM lists */
4125 /* Initialize the FS results-to-screen map array if there were no "show fs"
4126 * directives in the config file */
4127 if (fs_showDefault) {
4128 for (i = 0; i < NUM_FS_STAT_ENTRIES; i++)
4129 fs_Display_map[i] = i;
4130 fs_DisplayItems_count = NUM_FS_STAT_ENTRIES;
4133 /* Initialize the CM results-to-screen map array if there were no "show cm"
4134 * directives in the config file */
4135 if (cm_showDefault) {
4136 for (i = 0; i < NUM_CM_STAT_ENTRIES; i++)
4137 cm_Display_map[i] = i;
4138 cm_DisplayItems_count = NUM_CM_STAT_ENTRIES;
4143 /* setup an interrupt signal handler; we ain't wanna leak core */
4144 /* this binding is useful only until gtx is initialized after which the
4145 * keyboard input server takes over. */
4146 if ((signal(SIGINT, quit_signal)) == SIG_ERR) {
4147 perror("signal() failed.");
4152 /* init error message buffers. these will be used to print error messages
4153 * once gtx is initialized and there is no access to stderr/stdout */
4159 /* initialize fs and cm circular buffers before initiating probes */
4161 code = init_fs_buffers();
4163 fprintf(stderr, "[ %s ] init_fs_buffers returned %d\n", rn,
4170 code = init_cm_buffers();
4172 fprintf(stderr, "[ %s ] init_cm_buffers returned %d\n", rn,
4179 /* allocate and initialize buffers for holding fs & cm results in ascii
4180 * format suitable for updating the screen */
4181 code = init_print_buffers();
4183 fprintf(stderr, "[ %s ] init_print_buffers returned %d\n", rn, code);
4187 /* perform gtx initializations */
4188 code = gtx_initialize();
4190 fprintf(stderr, "[ %s ] gtx_initialize returned %d\n", rn, code);
4194 /* start xstat probes */
4197 return (0); /* will not return from the call to afsmon_execute() */
4199 } /* afsmonInit() */
4202 /*-----------------------------------------------------------------------
4204 ------------------------------------------------------------------------*/
4206 #include "AFS_component_version_number.c"
4209 main(int argc, char **argv)
4211 afs_int32 code; /*Return code */
4212 struct cmd_syndesc *ts; /*Ptr to cmd line syntax descriptor */
4214 #ifdef AFS_AIX32_ENV
4216 * The following signal action for AIX is necessary so that in case of a
4217 * crash (i.e. core is generated) we can include the user's data section
4218 * in the core dump. Unfortunately, by default, only a partial core is
4219 * generated which, in many cases, isn't too useful.
4221 struct sigaction nsa;
4223 sigemptyset(&nsa.sa_mask);
4224 nsa.sa_handler = SIG_DFL;
4225 nsa.sa_flags = SA_FULLDUMP;
4226 sigaction(SIGSEGV, &nsa, NULL);
4230 * Set up the commands we understand.
4232 ts = cmd_CreateSyntax("initcmd", afsmonInit, NULL, "initialize the program");
4233 cmd_AddParm(ts, "-config", CMD_SINGLE, CMD_OPTIONAL,
4234 "configuration file");
4235 cmd_AddParm(ts, "-frequency", CMD_SINGLE, CMD_OPTIONAL,
4236 "poll frequency, in seconds");
4237 cmd_AddParm(ts, "-output", CMD_SINGLE, CMD_OPTIONAL, "storage file name");
4238 cmd_AddParm(ts, "-detailed", CMD_FLAG, CMD_OPTIONAL,
4239 "output detailed statistics to storage file");
4241 /* we hope to use this .... eventually! */
4242 cmd_AddParm(ts, "-package", CMD_SINGLE, CMD_REQUIRED,
4243 "Graphics Package to use");
4245 cmd_AddParm(ts, "-debug", CMD_SINGLE, CMD_OPTIONAL,
4246 "turn debugging output on to the named file");
4247 cmd_AddParm(ts, "-fshosts", CMD_LIST, CMD_OPTIONAL,
4248 "list of file servers to monitor");
4249 cmd_AddParm(ts, "-cmhosts", CMD_LIST, CMD_OPTIONAL,
4250 "list of cache managers to monitor");
4251 cmd_AddParm(ts, "-buffers", CMD_SINGLE, CMD_OPTIONAL,
4252 "number of buffer slots");
4255 * Parse command-line switches & execute afsmonitor
4258 code = cmd_Dispatch(argc, argv);
4264 exit(0); /* redundant, but gets rid of warning */