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 int afsmon_probefreq; /* probe frequency */
60 static int wpkg_to_use; /* graphics package to use */
61 static char output_filename[80]; /* output filename */
62 char errMsg[256]; /* buffers used to print error messages after */
63 char errMsg1[256]; /* gtx is initialized (stderr/stdout gone !) */
64 int num_bufSlots = 0; /* number of slots in fs & cm circular buffers */
66 /* Flags used to process "show" directives in config file */
67 short fs_showFlags[NUM_FS_STAT_ENTRIES];
68 short cm_showFlags[NUM_CM_STAT_ENTRIES];
71 /* afsmonitor misc definitions */
73 #define DEFAULT_FREQUENCY 60 /* default proble frequency in seconds */
74 #define DEFAULT_BUFSLOTS 0 /* default number of buffer slots */
75 #define CFG_STR_LEN 80 /* max length of config file fields */
76 #define FS 1 /* for misc. use */
77 #define CM 2 /* for misc. use */
80 #define NUM_XSTAT_FS_AFS_PERFSTATS_LONGS 70 /* number of fields from struct afs_PerfStats that we display */
81 #define NUM_AFS_STATS_CMPERF_LONGS 40 /* number of longs in struct afs_stats_CMPerf excluding up/down stats and fields we dont display */
84 /* variables used for exec'ing user provided threshold handlers */
85 char *fsHandler_argv[20]; /* *argv[] for the handler */
86 char fsHandler_args[20][256]; /* buffer space for arguments */
87 int exec_fsThreshHandler = 0; /* execute fs threshold handler ? */
90 /* THRESHOLD STRUCTURE DEFINITIONS */
92 /* flag to indicate that threshold entries apply to all hosts. these will
93 be turned off when the first fs or cm host entry is processed */
94 static int global_ThreshFlag = 1;
95 static int global_fsThreshCount = 0; /* number of global fs thresholds */
96 static int global_cmThreshCount = 0; /* number of global cm thresholds */
100 /* Linked lists of file server and cache manager host names are made from
101 the entries in the config file. Head pointers to FS and CM server name lists. */
102 static struct afsmon_hostEntry *FSnameList;
103 static struct afsmon_hostEntry *CMnameList;
105 /* number of fileservers and cache managers to monitor */
109 /* number of xstat collection ids */
110 #define MAX_NUM_FS_COLLECTIONS 2
111 #define MAX_NUM_CM_COLLECTIONS 1
112 int num_fs_collections = 0;
113 int num_cm_collections = 0;
115 /* variables used for processing config file */
116 /* ptr to the hostEntry structure of the last "fs" or "cm" entry processed
117 in the config file */
118 static struct afsmon_hostEntry *last_hostEntry;
119 /* names of the last host processed in the config file */
120 static char last_fsHost[HOST_NAME_LEN];
121 static char last_cmHost[HOST_NAME_LEN];
122 static int lastHostType = 0; /* 0 = no host entries processed
123 * 1 = last host was file server
124 * 2 = last host was cache manager. */
127 /* FILE SERVER CIRCULAR BUFFER VARIABLES */
129 struct afsmon_fs_Results_list {
130 struct xstat_fs_ProbeResults *fsResults[MAX_NUM_FS_COLLECTIONS];
131 int empty[MAX_NUM_FS_COLLECTIONS];
132 struct afsmon_fs_Results_list *next;
135 struct afsmon_fs_Results_CBuffer {
136 int probeNum; /* probe number of entries in this slot */
137 struct afsmon_fs_Results_list *list; /* ptr to list of results */
140 int afsmon_fs_results_length[] =
141 { XSTAT_FS_FULLPERF_RESULTS_LEN, XSTAT_FS_CBSTATS_RESULTS_LEN };
143 /* buffer for FS probe results */
144 struct afsmon_fs_Results_CBuffer *afsmon_fs_ResultsCB;
146 int afsmon_fs_curr_CBindex = 0; /* current fs CB slot */
148 /* Probe number variables. The current probe number is incremented
149 when the first probe from a new probe cycle is received. The prev probe
150 number is incremented when the last probe of the current cycle is
151 received. This difference is because of the purpose for which these
154 int afsmon_fs_curr_probeNum = 1; /* current fs probe number */
155 int afsmon_fs_prev_probeNum = 0; /* previous fs probe number */
158 /* CACHE MANAGER CIRCULAR BUFFER VARIABLES */
160 struct afsmon_cm_Results_list {
161 struct xstat_cm_ProbeResults *cmResults[MAX_NUM_CM_COLLECTIONS];
162 int empty[MAX_NUM_CM_COLLECTIONS];
163 struct afsmon_cm_Results_list *next;
166 struct afsmon_cm_Results_CBuffer {
167 int probeNum; /* probe number of entries in this slot */
168 struct afsmon_cm_Results_list *list; /* ptr to list of results */
171 int afsmon_cm_results_length[] = { XSTAT_CM_FULLPERF_RESULTS_LEN };
173 /* buffer for CM probe results */
174 struct afsmon_cm_Results_CBuffer *afsmon_cm_ResultsCB;
176 int afsmon_cm_curr_CBindex = 0; /* current cm CB slot */
179 /* Probe number variables. The current probe number is incremented
180 when the first probe from a new probe cycle is received. The prev probe
181 number is incremented when the last probe of the current cycle is
182 received. This difference is because of the purpose for which these
185 int afsmon_cm_curr_probeNum = 1; /* current cm probe number */
186 int afsmon_cm_prev_probeNum = 0; /* previous cm probe number */
189 /* Structures to hold FS & CM results in string format(suitable for display ) */
191 /* ptr to array holding the results of FS probes in ascii format */
192 /* for current probe cycle */
193 struct fs_Display_Data *curr_fsData = (struct fs_Display_Data *)0;
194 /* for previous probe cycle */
195 struct fs_Display_Data *prev_fsData = (struct fs_Display_Data *)0;
198 /* ptr to array holding the results of CM probes in ascii format */
199 /* for current probe cycle */
200 struct cm_Display_Data *curr_cmData = (struct cm_Display_Data *)0;
201 /* for previous probe cycle */
202 struct cm_Display_Data *prev_cmData = (struct cm_Display_Data *)0;
204 /* EXTERN DEFINITIONS */
206 /* file server and cache manager variable names (from afsmon_labels.h) */
207 extern char *fs_varNames[];
208 extern char *cm_varNames[];
210 /* GTX & MISC VARIABLES */
212 /* afsmonitor window */
213 extern struct gwin *afsmon_win;
215 /* current page number in the overview frame */
216 extern int ovw_currPage;
218 /* number of FS alerts and number of hosts on FS alerts */
220 int numHosts_onfs_alerts;
222 /* number of CM alerts and number of hosts on FS alerts */
224 int numHosts_oncm_alerts;
226 /* flag to indicate that atleast one probe cycle has completed and
227 data is available for updating the display */
228 extern int fs_Data_Available;
229 extern int cm_Data_Available;
231 extern int gtx_initialized; /* gtx initialized ? */
233 /* This array contains the indices of the file server data items that
234 are to be displayed on the File Servers screen. For example, suppose the
235 user wishes to display only the vcache statistics then the following array
236 will contain indices 2 to 14 corresponding to the position of the
237 vcache data items in the fs_varNames[] array. If the config file contains
238 no "show fs .." directives, it will contain the indices of all the
239 items in the fs_varNames[] array */
241 short fs_Display_map[NUM_FS_STAT_ENTRIES];
242 int fs_DisplayItems_count = 0; /* number of items to display */
243 int fs_showDefault = 1; /* show all of FS data ? */
246 /* same use as above for Cache Managers */
247 short cm_Display_map[NUM_CM_STAT_ENTRIES];
248 int cm_DisplayItems_count = 0; /* number of items to display */
249 int cm_showDefault = 1; /* show all of CM data ? */
251 extern int fs_currPage; /* current page number in the File Servers frame */
252 extern int fs_curr_LCol; /* current leftmost column on display on FS frame */
254 extern int cm_currPage; /* current page number in the Cache Managers frame */
255 extern int cm_curr_LCol; /* current leftmost column on display on CM frame */
257 /* File server and Cache manager data is classified into sections &
258 groups to help the user choose what he wants displayed */
259 extern char *fs_categories[]; /* file server data category names */
260 extern char *cm_categories[]; /* cache manager data category names */
263 static int fs_FullPerfs_ltoa(struct fs_Display_Data *a_fsData,
264 struct xstat_fs_ProbeResults *a_fsResults);
265 static int fs_CallBackStats_ltoa(struct fs_Display_Data *a_fsData,
266 struct xstat_fs_ProbeResults *a_fsResults);
268 #ifdef HAVE_STRCASESTR
269 extern char * strcasestr(const char *, const char *);
272 strcasestr(): Return first occurence of pattern s2 in s1, case
275 This routine is required since I made pattern matching of the
276 config file to be case insensitive.
295 while (len1 >= len2 && len1 > 0) {
296 if ((strncasecmp(ptr, s2, len2)) == 0)
306 GetHostByName(char *name)
313 he = gethostbyname(name);
315 /* On solaris the above does not resolve hostnames to full names */
317 memcpy(ip_addr, he->h_addr, he->h_length);
318 he = gethostbyaddr(ip_addr, he->h_length, he->h_addrtype);
325 /*-----------------------------------------------------------------------
329 * Exit gracefully from the afsmonitor. Frees memory where appropriate,
330 * cleans up after gtx and closes all open file descriptors. If a user
331 * provided threshold handler is to be exec'ed then gtx cleanup is
332 * not performed and an exec() is made instead of an exit().
338 * This function is called to execute a user handler only
339 * by a child process.
341 *----------------------------------------------------------------------*/
344 afsmon_Exit(int a_exitVal) /* exit code */
346 static char rn[] = "afsmon_Exit";
347 struct afsmon_fs_Results_list *tmp_fslist;
348 struct afsmon_fs_Results_list *next_fslist;
349 struct xstat_fs_ProbeResults *tmp_xstat_fsPR;
350 struct afsmon_cm_Results_list *tmp_cmlist;
351 struct afsmon_cm_Results_list *next_cmlist;
352 struct xstat_cm_ProbeResults *tmp_xstat_cmPR;
353 struct afsmon_hostEntry *curr_hostEntry;
354 struct afsmon_hostEntry *next_hostEntry;
361 fprintf(debugFD, "[ %s ] Called with exit code %d\n", rn, a_exitVal);
365 /* get out of curses first, but not if we are here to exec a threshold
366 * handler. If we do, the screen gets messed up */
367 if (gtx_initialized && !exec_fsThreshHandler)
368 gator_cursesgwin_cleanup(afsmon_win);
370 /* print the error message buffer */
371 if (errMsg[0] != '\0')
372 fprintf(stderr, "%s", errMsg);
373 if (errMsg1[0] != '\0')
374 fprintf(stderr, "%s", errMsg1);
376 /* deallocate file server circular buffers */
377 if (numFS && num_bufSlots) {
379 fprintf(debugFD, "freeing FS circular buffers ");
383 for (bufslot = 0; bufslot < num_bufSlots; bufslot++) {
385 fprintf(debugFD, " %d) ", bufslot);
386 if (afsmon_fs_ResultsCB[bufslot].list !=
387 (struct afsmon_fs_Results_list *)0) {
388 tmp_fslist = afsmon_fs_ResultsCB[bufslot].list;
391 /* make sure we do not go astray */
395 "[ %s ] error in deallocating fs CB\n",
399 next_fslist = tmp_fslist->next;
400 for (i = 0; i < MAX_NUM_FS_COLLECTIONS; i++) {
401 tmp_xstat_fsPR = tmp_fslist->fsResults[i];
404 fprintf(debugFD, "%d ", numFS - j);
406 /* free xstat_fs_Results data */
407 free(tmp_xstat_fsPR->data.AFS_CollData_val);
408 free(tmp_xstat_fsPR->connP);
409 free(tmp_xstat_fsPR);
412 /* free the fs list item */
414 tmp_fslist = next_fslist;
416 } /* while fs list items in this slot */
417 } /* if entries in this buffer slot */
418 } /* for each fs buffer slot */
420 fprintf(debugFD, "\n");
425 /* deallocate cache manager curcular buffers */
426 if (numCM && num_bufSlots) {
428 fprintf(debugFD, "freeing CM curcular buffers ");
429 for (bufslot = 0; bufslot < num_bufSlots; bufslot++) {
431 fprintf(debugFD, " %d) ", bufslot);
432 if (afsmon_cm_ResultsCB[bufslot].list !=
433 (struct afsmon_cm_Results_list *)0) {
434 tmp_cmlist = afsmon_cm_ResultsCB[bufslot].list;
437 /* make sure we do not go astray */
441 "[ %s ] error in deallocating cm CB\n",
445 next_cmlist = tmp_cmlist->next;
446 for (i = 0; i < MAX_NUM_CM_COLLECTIONS; i++) {
447 tmp_xstat_cmPR = tmp_cmlist->cmResults[i];
450 fprintf(debugFD, "%d ", numCM - j);
451 /* make sure data is ok */
452 /* Print_cm_FullPerfInfo(tmp_xstat_cmPR); */
454 /* free xstat_cm_Results data */
455 free(tmp_xstat_cmPR->data.AFSCB_CollData_val);
456 free(tmp_xstat_cmPR->connP);
457 free(tmp_xstat_cmPR);
460 /* free the cm list item */
462 tmp_cmlist = next_cmlist;
464 } /* while cm list items in this slot */
465 } /* if entries in this buffer slot */
466 } /* for each cm buffer slot */
468 fprintf(debugFD, "\n");
472 /* deallocate FS & CM Print buffers */
473 if (curr_fsData != NULL) {
475 fprintf(debugFD, "Deallocating FS Print Buffers .... curr");
478 if (prev_fsData != NULL) {
480 fprintf(debugFD, ", prev \n");
483 if (curr_cmData != NULL) {
485 fprintf(debugFD, "Deallocating CM Print Buffers .... curr");
488 if (prev_cmData != NULL) {
490 fprintf(debugFD, ", prev \n");
494 /* deallocate hostEntry lists */
497 fprintf(debugFD, "Deallocating FS hostEntries ..");
498 curr_hostEntry = FSnameList;
499 while (curr_hostEntry) {
500 next_hostEntry = curr_hostEntry->next;
501 if (curr_hostEntry->thresh != NULL)
502 free(curr_hostEntry->thresh);
503 free(curr_hostEntry);
504 curr_hostEntry = next_hostEntry;
507 fprintf(debugFD, "\n");
511 fprintf(debugFD, "Deallocating CM hostEntries ..");
512 curr_hostEntry = CMnameList;
513 while (curr_hostEntry) {
514 next_hostEntry = curr_hostEntry->next;
515 if (curr_hostEntry->thresh != NULL)
516 free(curr_hostEntry->thresh);
517 free(curr_hostEntry);
518 curr_hostEntry = next_hostEntry;
521 fprintf(debugFD, "\n");
524 /* close debug file */
530 if (exec_fsThreshHandler) {
531 code = execvp(fsHandler_argv[0], fsHandler_argv);
533 fprintf(stderr, "execvp() of %s returned %d, errno %d\n",
534 fsHandler_argv[0], code, errno);
542 /*-----------------------------------------------------------------------
546 * Insert a hostname in the file server names list.
551 *----------------------------------------------------------------------*/
554 insert_FS(char *a_hostName) /* name of cache manager to be inserted in list */
556 static struct afsmon_hostEntry *curr_item;
557 static struct afsmon_hostEntry *prev_item;
559 if (*a_hostName == '\0')
561 curr_item = malloc(sizeof(struct afsmon_hostEntry));
562 if (curr_item == (struct afsmon_hostEntry *)0) {
563 fprintf(stderr, "Failed to allocate space for FS nameList\n");
567 strncpy(curr_item->hostName, a_hostName, CFG_STR_LEN);
568 curr_item->next = (struct afsmon_hostEntry *)0;
569 curr_item->numThresh = 0;
570 curr_item->thresh = NULL;
572 if (FSnameList == (struct afsmon_hostEntry *)0)
573 FSnameList = curr_item;
575 prev_item->next = curr_item;
577 prev_item = curr_item;
578 /* record the address of this entry so that its threshold
579 * count can be incremented during the first pass of the config file */
580 last_hostEntry = curr_item;
585 /*-----------------------------------------------------------------------
590 * Prints the file server names linked list.
594 *----------------------------------------------------------------------*/
598 static char rn[] = "print_FS";
599 struct afsmon_hostEntry *tempFS;
600 struct Threshold *threshP;
604 fprintf(debugFD, "[ %s ] Called\n", rn);
610 fprintf(debugFD, "No of File Servers: %d\n", numFS);
613 fprintf(debugFD, "\t %s threshCount = %d\n", tempFS->hostName,
615 threshP = tempFS->thresh;
616 for (i = 0; i < tempFS->numThresh; i++, threshP++)
617 fprintf(debugFD, "\t thresh (%2d) %s %s %s\n",
618 threshP->index, threshP->itemName,
619 threshP->threshVal, threshP->handler);
620 } while ((tempFS = tempFS->next) != (struct afsmon_hostEntry *)0);
622 fprintf(debugFD, "\t\t-----End of List-----\n");
628 /*-----------------------------------------------------------------------
632 * Insert a hostname in the cache manager names list.
637 *----------------------------------------------------------------------*/
640 insert_CM(char *a_hostName) /* name of cache manager to be inserted in list */
642 static struct afsmon_hostEntry *curr_item;
643 static struct afsmon_hostEntry *prev_item;
645 if (*a_hostName == '\0')
647 curr_item = malloc(sizeof(struct afsmon_hostEntry));
648 if (curr_item == (struct afsmon_hostEntry *)0) {
649 fprintf(stderr, "Failed to allocate space for CM nameList\n");
653 strncpy(curr_item->hostName, a_hostName, CFG_STR_LEN);
654 curr_item->next = (struct afsmon_hostEntry *)0;
655 curr_item->numThresh = 0;
656 curr_item->thresh = NULL;
658 if (CMnameList == (struct afsmon_hostEntry *)0)
659 CMnameList = curr_item;
661 prev_item->next = curr_item;
663 prev_item = curr_item;
664 /* side effect. note the address of this entry so that its threshold
665 * count can be incremented during the first pass of the config file */
666 last_hostEntry = curr_item;
672 /*-----------------------------------------------------------------------
677 * Prints the cache manager names linked list.
681 *----------------------------------------------------------------------*/
685 static char rn[] = "print_CM";
686 struct afsmon_hostEntry *tempCM;
687 struct Threshold *threshP;
691 fprintf(debugFD, "[ %s ] Called\n", rn);
697 fprintf(debugFD, "No of Cache Managers: %d\n", numCM);
700 fprintf(debugFD, "\t %s threshCount = %d\n", tempCM->hostName,
702 threshP = tempCM->thresh;
703 for (i = 0; i < tempCM->numThresh; i++, threshP++)
704 fprintf(debugFD, "\t thresh (%2d) %s %s %s\n",
705 threshP->index, threshP->itemName,
706 threshP->threshVal, threshP->handler);
707 } while ((tempCM = tempCM->next) != (struct afsmon_hostEntry *)0);
709 fprintf(debugFD, "\t\t-----End of List-----\n");
716 /*-----------------------------------------------------------------------
720 * Parse the host entry line in the config file. Check the syntax,
721 * and inserts the host name in the FS ot CM linked list. Also
722 * remember if this entry was an fs or cm & the ptr to its hostEntry
723 * structure. The threshold entries in the config file are dependent
724 * on their position relative to the hostname entries. Hence it is
725 * required to remember the names of the last file server and cache
726 * manager entries that were processed.
732 *----------------------------------------------------------------------*/
735 parse_hostEntry(char *a_line)
736 { /* parse_hostEntry */
738 static char rn[] = "parse_hostEntry"; /* routine name */
739 char opcode[CFG_STR_LEN]; /* specifies type of config entry */
740 char arg1[CFG_STR_LEN]; /* hostname or qualifier (fs/cm?) */
741 char arg2[CFG_STR_LEN]; /* threshold variable */
742 char arg3[CFG_STR_LEN]; /* threshold value */
743 char arg4[CFG_STR_LEN]; /* user's handler */
744 struct hostent *he; /* host entry */
747 fprintf(debugFD, "[ %s ] Called, a_line = %s\n", rn, a_line);
757 sscanf(a_line, "%s %s %s %s %s", opcode, arg1, arg2, arg3, arg4);
758 /* syntax is "opcode hostname" */
759 if ((strlen(arg2)) != 0) {
760 fprintf(stderr, "[ %s ] Extraneous characters at end of line\n", rn);
765 he = GetHostByName(arg1);
767 fprintf(stderr, "[ %s ] Unable to resolve hostname %s\n", rn, arg1);
771 if ((strcasecmp(opcode, "fs")) == 0) {
772 /* use the complete host name to insert in the file server names list */
773 insert_FS(he->h_name);
774 /* note that last host entry in the config file was fs */
777 /* threholds are not global anymore */
778 if (global_ThreshFlag)
779 global_ThreshFlag = 0;
780 } else if ((strcasecmp(opcode, "cm")) == 0) {
781 /* use the complete host name to insert in the CM names list */
782 insert_CM(he->h_name);
783 /* last host entry in the config file was cm */
786 /* threholds are not global anymore */
787 if (global_ThreshFlag)
788 global_ThreshFlag = 0;
795 /*-----------------------------------------------------------------------
796 * parse_threshEntry()
799 * Parse the threshold entry line in the config file. This function is
800 * called in the the first pass of the config file. It checks the syntax
801 * of the config lines and verifies their positional validity - eg.,
802 * a cm threshold cannot appear after a fs hostname entry, etc.
803 * It also counts the thresholds applicable to each host.
809 *----------------------------------------------------------------------*/
812 parse_threshEntry(char *a_line)
813 { /* parse_threshEntry */
814 static char rn[] = "parse_threshEntry"; /* routine name */
815 char opcode[CFG_STR_LEN]; /* specifies type of config entry */
816 char arg1[CFG_STR_LEN]; /* hostname or qualifier (fs/cm?) */
817 char arg2[CFG_STR_LEN]; /* threshold variable */
818 char arg3[CFG_STR_LEN]; /* threshold value */
819 char arg4[CFG_STR_LEN]; /* user's handler */
820 char arg5[CFG_STR_LEN]; /* junk characters */
823 fprintf(debugFD, "[ %s ] Called, a_line = %s\n", rn, a_line);
834 sscanf(a_line, "%s %s %s %s %s %s", opcode, arg1, arg2, arg3, arg4, arg5);
836 /* syntax is "thresh fs/cm variable_name threshold_value [handler] " */
837 if (((strlen(arg1)) == 0) || ((strlen(arg2)) == 0)
838 || ((strlen(arg3)) == 0)) {
839 fprintf(stderr, "[ %s ] Incomplete line\n", rn);
842 if (strlen(arg3) > THRESH_VAR_LEN - 2) {
843 fprintf(stderr, "[%s ] threshold value too long\n", rn);
847 if ((strcasecmp(arg1, "fs")) == 0) {
848 switch (lastHostType) {
849 case 0: /* its a global threshold */
850 global_fsThreshCount++;
852 case 1: /* inc thresh count of last file server */
853 last_hostEntry->numThresh++;
857 "[ %s ] A threshold for a File Server cannot be placed after a Cache Manager host entry in the config file \n",
861 fprintf(stderr, "[ %s ] Programming error 1\n", rn);
864 } else if ((strcasecmp(arg1, "cm")) == 0) {
865 switch (lastHostType) {
866 case 0: /* its a global threshold */
867 global_cmThreshCount++;
869 case 2: /* inc thresh count of last cache manager */
870 last_hostEntry->numThresh++;
874 "[ %s ] A threshold for a Cache Manager cannot be placed after a File Server host entry in the config file \n",
878 fprintf(stderr, "[ %s ] Programming error 2\n", rn);
883 "[ %s ] Syntax error. Second argument should be \"fs\" or \"cm\" \n",
889 } /* parse_threshEntry */
892 /*-----------------------------------------------------------------------
896 * The thresholds applicable to each host machine are stored in the
897 * FSnameList and CMnameList. Threshold entries in the config file are
898 * context sensitive. The host to which this threshold is applicable
899 * is pointed to by last_fsHost (for file servers) and last_cmHost
900 * for cache managers. For global thresholds the info is recorded for
901 * all the hosts. This function is called in the second pass of the
902 * config file. In the first pass a count of the number of global
903 * thresholds is determined and this information is used in this
904 * routine. If threshold entries are duplicated the first entry is
906 * Each threshold entry also has an index field. This is a positional
907 * index to the corresponding variable in the prev_[fs/cm]Data arrays.
908 * This makes it easy to check the threshold for overflow.
913 *----------------------------------------------------------------------*/
916 store_threshold(int a_type, /* 1 = fs , 2 = cm */
917 char *a_varName, /* threshold name */
918 char *a_value, /* threshold value */
919 char *a_handler) /* threshold overflow handler */
920 { /* store_thresholds */
922 static char rn[] = "store_thresholds"; /* routine name */
923 struct afsmon_hostEntry *tmp_host; /* tmp ptr to hostEntry */
924 struct afsmon_hostEntry *Header; /* tmp ptr to hostEntry list header */
925 struct Threshold *threshP; /* tmp ptr to threshold list */
927 int index; /* index to fs_varNames or cm_varNames */
930 int srvCount; /* tmp count of host names */
931 int *global_TC; /* ptr to global_xxThreshCount */
936 "[ %s ] Called, a_type= %d, a_varName= %s, a_value= %s, a_handler=%s\n",
937 rn, a_type, a_varName, a_value, a_handler);
941 /* resolve the threshold variable name */
943 if (a_type == 1) { /* fs threshold */
944 for (index = 0; index < NUM_FS_STAT_ENTRIES; index++) {
945 if (strcasecmp(a_varName, fs_varNames[index]) == 0) {
951 fprintf(stderr, "[ %s ] Unknown FS threshold variable name %s\n",
957 hostname = last_fsHost;
958 global_TC = &global_fsThreshCount;
959 } else if (a_type == 2) { /* cm threshold */
960 for (index = 0; index < NUM_CM_STAT_ENTRIES; index++) {
961 if (strcasecmp(a_varName, cm_varNames[index]) == 0) {
967 fprintf(stderr, "[ %s ] Unknown CM threshold variable name %s\n",
973 hostname = last_cmHost;
974 global_TC = &global_cmThreshCount;
980 /* if the global thresh count is not zero, place this threshold on
981 * all the host entries */
985 for (i = 0; i < srvCount; i++) {
986 threshP = tmp_host->thresh;
988 for (j = 0; j < tmp_host->numThresh; j++) {
989 if ((threshP->itemName[0] == '\0')
990 || (strcasecmp(threshP->itemName, a_varName) == 0)) {
991 strlcpy(threshP->itemName, a_varName,
992 sizeof(threshP->itemName));
993 strlcpy(threshP->threshVal, a_value,
994 sizeof(threshP->threshVal));
995 strlcpy(threshP->handler, a_handler,
996 sizeof(threshP->handler));
997 threshP->index = index;
1004 fprintf(stderr, "[ %s ] Could not insert threshold entry",
1006 fprintf(stderr, "for %s in thresh list of host %s \n",
1007 a_varName, tmp_host->hostName);
1010 tmp_host = tmp_host->next;
1016 /* it is not a global threshold, insert it in the thresh list of this
1017 * host only. We overwrite the global threshold if it was alread set */
1019 if (*hostname == '\0') {
1020 fprintf(stderr, "[ %s ] Programming error 3\n", rn);
1024 /* get the hostEntry that this threshold belongs to */
1027 for (i = 0; i < srvCount; i++) {
1028 if (strcasecmp(tmp_host->hostName, hostname) == 0) {
1032 tmp_host = tmp_host->next;
1035 fprintf(stderr, "[ %s ] Unable to find host %s in %s hostEntry list",
1036 rn, hostname, (a_type - 1) ? "CM" : "FS");
1040 /* put this entry on the thresh list of this host, overwrite global value
1043 threshP = tmp_host->thresh;
1045 for (i = 0; i < tmp_host->numThresh; i++) {
1046 if ((threshP->itemName[0] == '\0')
1047 || (strcasecmp(threshP->itemName, a_varName) == 0)) {
1048 strlcpy(threshP->itemName, a_varName, sizeof(threshP->itemName));
1049 strlcpy(threshP->threshVal, a_value, sizeof(threshP->threshVal));
1050 strlcpy(threshP->handler, a_handler, sizeof(threshP->handler));
1051 threshP->index = index;
1060 "[ %s ] Unable to insert threshold %s for %s host %s\n", rn,
1061 a_varName, (a_type - 1) ? "CM" : "FS", tmp_host->hostName);
1067 } /* store_thresholds */
1070 /*-----------------------------------------------------------------------
1074 * This function process a "show" entry in the config file. A "show"
1075 * entry specifies what statistics the user wants to see. File
1076 * server and Cache Manager data is divided into sections. Each section
1077 * is made up of one or more groups. If a group name is specified only
1078 * those statistics under that group are shown. If a section name is
1079 * specified all the groups under this section are shown.
1080 * Data as obtained from the xstat probes is considered to be ordered.
1081 * This data is mapped to the screen thru fs_Display_map[] and
1082 * cm_Display_map[]. This routine parses the "show" entry against the
1083 * section/group names in the [fs/cm]_categories[] array. If there is
1084 * no match it tries to match it against a variable name in
1085 * [fs/cm]_varNames[] array. In each case the corresponding indices to
1086 * the data is the [fs/cm]_displayInfo[] is recorded.
1090 * Failure: -1 (invalid entry)
1091 * > -1 (programming error)
1092 *----------------------------------------------------------------------*/
1095 parse_showEntry(char *a_line)
1096 { /* parse_showEntry */
1097 static char rn[] = "parse_showEntry";
1098 char opcode[CFG_STR_LEN]; /* specifies type of config entry */
1099 char arg1[CFG_STR_LEN]; /* show fs or cm entry ? */
1100 char arg2[CFG_STR_LEN]; /* what we gotta show */
1101 char arg3[CFG_STR_LEN]; /* junk */
1102 char catName[CFG_STR_LEN]; /* for category names */
1103 int numGroups; /* number of groups in a section */
1107 int idx = 0; /* index to fs_categories[] */
1113 fprintf(debugFD, "[ %s ] Called, a_line= %s\n", rn, a_line);
1120 sscanf(a_line, "%s %s %s %s", opcode, arg1, arg2, arg3);
1122 if (arg3[0] != '\0') {
1123 fprintf(stderr, "[ %s ] Extraneous characters at end of line\n", rn);
1127 if ((strcasecmp(arg1, "fs") != 0) && (strcasecmp(arg1, "cm") != 0)) {
1129 "[ %s ] Second argument of \"show\" directive should be \"fs\" or \"cm\" \n",
1134 /* Each entry can either be a variable name or a section/group name. Variable
1135 * names are listed in xx_varNames[] and section/group names in xx_categories[].
1136 * The section/group names in xx_categiries[] also give the starting/ending
1137 * indices of the variables belonging to that section/group. These indices
1138 * are stored in order in xx_Display_map[] and displayed to the screen in that
1141 /* To handle duplicate "show" entries we keep track of what what we have
1142 * already marked to show in the xx_showFlags[] */
1144 if (strcasecmp(arg1, "fs") == 0) { /* its a File Server entry */
1146 /* mark that we have to show only what the user wants */
1149 /* if it is a section/group name, find it in the fs_categories[] array */
1152 if (strcasestr(arg2, "_section") != NULL
1153 || strcasestr(arg2, "_group") != NULL) {
1155 while (idx < FS_NUM_DATA_CATEGORIES) {
1156 sscanf(fs_categories[idx], "%s %d %d", catName, &fromIdx,
1159 if (strcasecmp(arg2, catName) == 0) {
1165 if (!found) { /* typo in section/group name */
1167 "[ %s ] Could not find section/group name %s\n", rn,
1173 /* if it is a group name, read its start/end indices and fill in the
1174 * fs_Display_map[]. */
1176 if (strcasestr(arg2, "_group") != NULL) {
1178 if (fromIdx < 0 || toIdx < 0 || fromIdx >= NUM_FS_STAT_ENTRIES
1179 || toIdx >= NUM_FS_STAT_ENTRIES)
1181 for (j = fromIdx; j <= toIdx; j++) {
1182 if (!fs_showFlags[j]) {
1183 fs_Display_map[fs_DisplayItems_count] = j;
1184 fs_DisplayItems_count++;
1185 fs_showFlags[j] = 1;
1187 if (fs_DisplayItems_count >= NUM_FS_STAT_ENTRIES) {
1188 fprintf(stderr, "[ %s ] fs_DisplayItems_count ovf\n", rn);
1193 /* if it is a section name, get the count of number of groups in it and
1194 * for each group fill in the start/end indices in the fs_Display_map[] */
1196 if (strcasestr(arg2, "_section") != NULL) {
1197 /* fromIdx is actually the number of groups in thi section */
1198 numGroups = fromIdx;
1199 /* for each group in section */
1200 while (idx < FS_NUM_DATA_CATEGORIES && numGroups) {
1201 sscanf(fs_categories[idx], "%s %d %d", catName, &fromIdx,
1204 if (strcasestr(catName, "_group") != NULL) {
1205 if (fromIdx < 0 || toIdx < 0
1206 || fromIdx >= NUM_FS_STAT_ENTRIES
1207 || toIdx >= NUM_FS_STAT_ENTRIES)
1209 for (j = fromIdx; j <= toIdx; j++) {
1210 if (!fs_showFlags[j]) {
1211 fs_Display_map[fs_DisplayItems_count] = j;
1212 fs_DisplayItems_count++;
1213 fs_showFlags[j] = 1;
1215 if (fs_DisplayItems_count >= NUM_FS_STAT_ENTRIES) {
1217 "[ %s ] fs_DisplayItems_count ovf\n", rn);
1222 fprintf(stderr, "[ %s ] Error parsing groups for %s\n",
1228 } /* for each group in section */
1231 } else { /* it is a variable name */
1233 for (i = 0; i < NUM_FS_STAT_ENTRIES; i++) {
1234 if (strcasecmp(arg2, fs_varNames[i]) == 0) {
1235 if (!fs_showFlags[i]) {
1236 fs_Display_map[fs_DisplayItems_count] = i;
1237 fs_DisplayItems_count++;
1238 fs_showFlags[i] = 1;
1240 if (fs_DisplayItems_count >= NUM_FS_STAT_ENTRIES) {
1241 fprintf(stderr, "[ %s ] fs_DisplayItems_count ovf\n",
1248 if (!found) { /* typo in section/group name */
1249 fprintf(stderr, "[ %s ] Could not find variable name %s\n",
1253 } /* its a variable name */
1257 /* it is an fs entry */
1258 if (strcasecmp(arg1, "cm") == 0) { /* its a Cache Manager entry */
1261 /* mark that we have to show only what the user wants */
1264 /* if it is a section/group name, find it in the cm_categories[] array */
1267 if (strcasestr(arg2, "_section") != NULL
1268 || strcasestr(arg2, "_group") != NULL) {
1270 while (idx < CM_NUM_DATA_CATEGORIES) {
1271 sscanf(cm_categories[idx], "%s %d %d", catName, &fromIdx,
1274 if (strcasecmp(arg2, catName) == 0) {
1280 if (!found) { /* typo in section/group name */
1282 "[ %s ] Could not find section/group name %s\n", rn,
1288 /* if it is a group name, read its start/end indices and fill in the
1289 * cm_Display_map[]. */
1291 if (strcasestr(arg2, "_group") != NULL) {
1293 if (fromIdx < 0 || toIdx < 0 || fromIdx >= NUM_CM_STAT_ENTRIES
1294 || toIdx >= NUM_CM_STAT_ENTRIES)
1296 for (j = fromIdx; j <= toIdx; j++) {
1297 if (!cm_showFlags[j]) {
1298 cm_Display_map[cm_DisplayItems_count] = j;
1299 cm_DisplayItems_count++;
1300 cm_showFlags[j] = 1;
1302 if (cm_DisplayItems_count >= NUM_CM_STAT_ENTRIES) {
1303 fprintf(stderr, "[ %s ] cm_DisplayItems_count ovf\n", rn);
1308 /* if it is a section name, get the count of number of groups in it and
1309 * for each group fill in the start/end indices in the cm_Display_map[] */
1311 if (strcasestr(arg2, "_section") != NULL) {
1312 /* fromIdx is actually the number of groups in thi section */
1313 numGroups = fromIdx;
1314 /* for each group in section */
1315 while (idx < CM_NUM_DATA_CATEGORIES && numGroups) {
1316 sscanf(cm_categories[idx], "%s %d %d", catName, &fromIdx,
1319 if (strcasestr(catName, "_group") != NULL) {
1320 if (fromIdx < 0 || toIdx < 0
1321 || fromIdx >= NUM_CM_STAT_ENTRIES
1322 || toIdx >= NUM_CM_STAT_ENTRIES)
1324 for (j = fromIdx; j <= toIdx; j++) {
1325 if (!cm_showFlags[j]) {
1326 cm_Display_map[cm_DisplayItems_count] = j;
1327 cm_DisplayItems_count++;
1328 cm_showFlags[j] = 1;
1330 if (cm_DisplayItems_count >= NUM_CM_STAT_ENTRIES) {
1332 "[ %s ] cm_DisplayItems_count ovf\n", rn);
1337 fprintf(stderr, "[ %s ] Error parsing groups for %s\n",
1343 } /* for each group in section */
1344 } else { /* it is a variable name */
1346 for (i = 0; i < NUM_CM_STAT_ENTRIES; i++) {
1347 if (strcasecmp(arg2, cm_varNames[i]) == 0) {
1348 if (!cm_showFlags[i]) {
1349 cm_Display_map[cm_DisplayItems_count] = i;
1350 cm_DisplayItems_count++;
1351 cm_showFlags[i] = 1;
1353 if (cm_DisplayItems_count >= NUM_CM_STAT_ENTRIES) {
1354 fprintf(stderr, "[ %s ] cm_DisplayItems_count ovf\n",
1361 if (!found) { /* typo in section/group name */
1362 fprintf(stderr, "[ %s ] Could not find variable name %s\n",
1366 } /* its a variable name */
1369 /* it is an cm entry */
1371 } /* parse_showEntry */
1374 /*-----------------------------------------------------------------------
1375 * process_config_file()
1378 * Parse config file entries in two passes. In the first pass:
1379 * - the syntax of all the entries is checked
1380 * - host names are noted and the FSnamesList and CMnamesList
1382 * - a count of the global thresholds and local thresholds of
1383 * each host are counted.
1384 * - "show" entries are processed.
1385 * In the second pass:
1386 * - thresholds are stored
1390 * Failure: Exits afsmonitor showing error and line.
1391 *----------------------------------------------------------------------*/
1394 process_config_file(char *a_config_filename)
1395 { /* process_config_file() */
1396 static char rn[] = "process_config_file"; /* routine name */
1397 FILE *configFD; /* config file descriptor */
1398 char line[4 * CFG_STR_LEN]; /* a line of config file */
1399 char opcode[CFG_STR_LEN]; /* specifies type of config entry */
1400 char arg1[CFG_STR_LEN]; /* hostname or qualifier (fs/cm?) */
1401 char arg2[CFG_STR_LEN]; /* threshold variable */
1402 char arg3[CFG_STR_LEN]; /* threshold value */
1403 char arg4[CFG_STR_LEN]; /* user's handler */
1404 struct afsmon_hostEntry *curr_host;
1405 struct hostent *he; /* hostentry to resolve host name */
1406 char *handlerPtr; /* ptr to pass theresh handler string */
1407 int code = 0; /* error code */
1408 int linenum = 0; /* config file line number */
1409 int error_in_config; /* syntax errors in config file ?? */
1414 fprintf(debugFD, "[ %s ] Called, a_config_filename= %s\n", rn,
1419 /* open config file */
1421 configFD = fopen(a_config_filename, "r");
1422 if (configFD == (FILE *) 0) {
1423 fprintf(stderr, "Failed to open config file %s \n",
1426 fprintf(debugFD, "[ %s ] Failed to open config file %s \n", rn,
1433 /* parse config file */
1435 /* We process the config file in two passes. In the first pass we check
1436 * for correct syntax and for valid entries and also keep count of the
1437 * number of servers and thresholds to monitor. This the data strctures
1438 * can be arrays instead of link lists since we would know their sizes. */
1444 error_in_config = 0; /* flag to note if config file has syntax errors */
1446 while ((fgets(line, CFG_STR_LEN, configFD)) != NULL) {
1452 sscanf(line, "%s %s %s %s %s", opcode, arg1, arg2, arg3, arg4);
1454 /* skip blank lines and comment lines */
1455 if ((strlen(opcode) == 0) || line[0] == '#')
1458 if ((strcasecmp(opcode, "fs") == 0)
1459 || (strcasecmp(opcode, "cm")) == 0) {
1460 code = parse_hostEntry(line);
1461 } else if ((strcasecmp(opcode, "thresh")) == 0) {
1462 code = parse_threshEntry(line);
1463 } else if ((strcasecmp(opcode, "show")) == 0) {
1464 code = parse_showEntry(line);
1466 fprintf(stderr, "[ %s ] Unknown opcode %s\n", rn, opcode);
1471 fprintf(stderr, "[ %s ] Error in line:\n %d: %s\n", rn, linenum,
1473 error_in_config = 1;
1477 if (error_in_config)
1481 fprintf(debugFD, "Global FS thresholds count = %d\n",
1482 global_fsThreshCount);
1483 fprintf(debugFD, "Global CM thresholds count = %d\n",
1484 global_cmThreshCount);
1488 /* the threshold count of all hosts in increased by 1 for each global
1489 * threshold. If one of the hosts has a local threshold for the same
1490 * variable it would end up being counted twice. whats a few bytes of memory
1491 * wasted anyway ? */
1493 if (global_fsThreshCount) {
1494 curr_host = FSnameList;
1495 for (i = 0; i < numFS; i++) {
1496 curr_host->numThresh += global_fsThreshCount;
1497 curr_host = curr_host->next;
1500 if (global_cmThreshCount) {
1501 curr_host = CMnameList;
1502 for (i = 0; i < numCM; i++) {
1503 curr_host->numThresh += global_cmThreshCount;
1504 curr_host = curr_host->next;
1509 /* make sure we have something to monitor */
1510 if (numFS == 0 && numCM == 0) {
1512 "\nConfig file must specify atleast one File Server or Cache Manager host to monitor.\n");
1519 fseek(configFD, 0, 0); /* seek to the beginning */
1522 /* allocate memory for threshold lists */
1523 curr_host = FSnameList;
1524 for (i = 0; i < numFS; i++) {
1525 if (curr_host->hostName[0] == '\0') {
1526 fprintf(stderr, "[ %s ] Programming error 4\n", rn);
1529 if (curr_host->numThresh) {
1530 numBytes = curr_host->numThresh * sizeof(struct Threshold);
1531 curr_host->thresh = malloc(numBytes);
1532 if (curr_host->thresh == NULL) {
1533 fprintf(stderr, "[ %s ] Memory Allocation error 1", rn);
1536 memset(curr_host->thresh, 0, numBytes);
1538 curr_host = curr_host->next;;
1541 curr_host = CMnameList;
1542 for (i = 0; i < numCM; i++) {
1543 if (curr_host->hostName[0] == '\0') {
1544 fprintf(stderr, "[ %s ] Programming error 5\n", rn);
1547 if (curr_host->numThresh) {
1548 numBytes = curr_host->numThresh * sizeof(struct Threshold);
1549 curr_host->thresh = malloc(numBytes);
1550 if (curr_host->thresh == NULL) {
1551 fprintf(stderr, "[ %s ] Memory Allocation error 2", rn);
1554 memset(curr_host->thresh, 0, numBytes);
1556 curr_host = curr_host->next;;
1565 last_fsHost[0] = '\0';
1566 last_cmHost[0] = '\0';
1568 while ((fgets(line, CFG_STR_LEN, configFD)) != NULL) {
1574 sscanf(line, "%s %s %s %s %s", opcode, arg1, arg2, arg3, arg4);
1577 /* if we have a host entry, remember the host name */
1578 if (strcasecmp(opcode, "fs") == 0) {
1579 he = GetHostByName(arg1);
1580 strncpy(last_fsHost, he->h_name, HOST_NAME_LEN);
1581 } else if (strcasecmp(opcode, "cm") == 0) {
1582 he = GetHostByName(arg1);
1583 strncpy(last_cmHost, he->h_name, HOST_NAME_LEN);
1584 } else if (strcasecmp(opcode, "thresh") == 0) {
1585 /* if we have a threshold handler it may have arguments
1586 * and the sscanf() above would not get them, so do the
1590 /* now skip over 4 words - this is done by first
1591 * skipping leading blanks then skipping a word */
1592 for (i = 0; i < 4; i++) {
1593 while (isspace(*handlerPtr))
1595 while (!isspace(*handlerPtr))
1598 while (isspace(*handlerPtr))
1600 /* we how have a pointer to the start of the handler
1603 handlerPtr = arg4; /* empty string */
1606 if (strcasecmp(arg1, "fs") == 0)
1607 code = store_threshold(1, /* 1 = fs */
1608 arg2, arg3, handlerPtr);
1610 else if (strcasecmp(arg1, "cm") == 0)
1611 code = store_threshold(2, /* 2 = fs */
1612 arg2, arg3, handlerPtr);
1615 fprintf(stderr, "[ %s ] Programming error 6\n", rn);
1619 fprintf(stderr, "[ %s ] Failed to store threshold\n", rn);
1620 fprintf(stderr, "[ %s ] Error processing line:\n%d: %s", rn,
1632 /*-----------------------------------------------------------------------
1637 * Print the File Server circular buffer.
1641 *----------------------------------------------------------------------*/
1645 { /* Print_FS_CB() */
1647 struct afsmon_fs_Results_list *fslist;
1652 /* print valid info in the fs CB */
1656 "==================== FS Buffer ========================\n");
1657 fprintf(debugFD, "afsmon_fs_curr_CBindex = %d\n",
1658 afsmon_fs_curr_CBindex);
1659 fprintf(debugFD, "afsmon_fs_curr_probeNum = %d\n\n",
1660 afsmon_fs_curr_probeNum);
1662 for (i = 0; i < num_bufSlots; i++) {
1663 fprintf(debugFD, "\t--------- slot %d ----------\n", i);
1664 fslist = afsmon_fs_ResultsCB[i].list;
1667 for (k = 0; k < MAX_NUM_FS_COLLECTIONS; k++) {
1668 if (!(fslist->empty[k])) {
1669 fprintf(debugFD, "\t %d) probeNum = %d host = %s cn = %d",
1671 fslist->fsResults[k]->probeNum,
1672 fslist->fsResults[k]->connP->hostName,
1673 fslist->fsResults[k]->collectionNumber);
1674 if (fslist->fsResults[k]->probeOK)
1675 fprintf(debugFD, " NOTOK\n");
1677 fprintf(debugFD, " OK\n");
1679 fprintf(debugFD, "\t %d) -- empty --\n", j);
1681 fslist = fslist->next;
1684 if (fslist != (struct afsmon_fs_Results_list *)0)
1685 fprintf(debugFD, "dangling last next ptr fs CB\n");
1688 } /* Print_FS_CB() */
1690 /*-----------------------------------------------------------------------
1691 * save_FS_results_inCB()
1694 * Saves the results of the latest FS probe in the fs circular
1695 * buffers. If the current probe cycle is in progress the contents
1696 * of xstat_fs_Results are copied to the end of the list of results
1697 * in the current slot (pointed to by afsmon_fs_curr_CBindex). If
1698 * a new probe cycle has started the next slot in the circular buffer
1699 * is initialized and the results copied. Note that the Rx related
1700 * information available in xstat_fs_Results is not copied.
1704 * Failure: Exits afsmonitor.
1705 *----------------------------------------------------------------------*/
1707 save_FS_results_inCB(int a_newProbeCycle) /* start of a new probe cycle ? */
1708 { /* save_FS_results_inCB() */
1709 static char rn[] = "save_FS_results_inCB"; /* routine name */
1710 struct afsmon_fs_Results_list *tmp_fslist_item; /* temp fs list item */
1711 struct xstat_fs_ProbeResults *tmp_fsPR; /* temp ptr */
1716 fprintf(debugFD, "[ %s ] Called, a_newProbeCycle= %d\n", rn,
1721 switch (xstat_fs_Results.collectionNumber) {
1722 case AFS_XSTATSCOLL_FULL_PERF_INFO:
1725 case AFS_XSTATSCOLL_CBSTATS:
1729 fprintf(stderr, "[ %s ] collection number %d is out of range.\n",
1730 rn, xstat_fs_Results.collectionNumber);
1734 /* If a new probe cycle started, mark the list in the current buffer
1735 * slot empty for resuse. Note that afsmon_fs_curr_CBindex was appropriately
1736 * incremented in afsmon_FS_Handler() */
1738 if (a_newProbeCycle) {
1739 tmp_fslist_item = afsmon_fs_ResultsCB[afsmon_fs_curr_CBindex].list;
1740 for (i = 0; i < numFS; i++) {
1741 tmp_fslist_item->empty[index] = 1;
1742 tmp_fslist_item = tmp_fslist_item->next;
1746 /* locate last unused item in list */
1747 tmp_fslist_item = afsmon_fs_ResultsCB[afsmon_fs_curr_CBindex].list;
1748 for (i = 0; i < numFS; i++) {
1749 if (tmp_fslist_item->empty[index])
1751 tmp_fslist_item = tmp_fslist_item->next;
1754 /* if we could not find one we have an inconsistent list */
1755 if (!tmp_fslist_item->empty[index]) {
1757 "[ %s ] list inconsistency 1. unable to find an empty slot to store results of probenum %d of %s\n",
1758 rn, xstat_fs_Results.probeNum,
1759 xstat_fs_Results.connP->hostName);
1763 tmp_fsPR = tmp_fslist_item->fsResults[index];
1765 /* copy hostname and probe number and probe time and probe status.
1766 * if the probe failed return now */
1768 memcpy(tmp_fsPR->connP->hostName, xstat_fs_Results.connP->hostName,
1769 sizeof(xstat_fs_Results.connP->hostName));
1770 tmp_fsPR->probeNum = xstat_fs_Results.probeNum;
1771 tmp_fsPR->probeTime = xstat_fs_Results.probeTime;
1772 tmp_fsPR->probeOK = xstat_fs_Results.probeOK;
1773 if (xstat_fs_Results.probeOK) { /* probeOK = 1 => notOK */
1774 /* we have a nonempty results structure so mark the list item used */
1775 tmp_fslist_item->empty[index] = 0;
1779 /* copy connection information */
1780 memcpy(&(tmp_fsPR->connP->skt), &(xstat_fs_Results.connP->skt),
1781 sizeof(struct sockaddr_in));
1783 memcpy(tmp_fsPR->connP->hostName, xstat_fs_Results.connP->hostName,
1784 sizeof(xstat_fs_Results.connP->hostName));
1785 tmp_fsPR->collectionNumber = xstat_fs_Results.collectionNumber;
1787 /* copy the probe data information */
1788 tmp_fsPR->data.AFS_CollData_len =
1789 min(xstat_fs_Results.data.AFS_CollData_len,
1790 afsmon_fs_results_length[index]);
1791 memcpy(tmp_fsPR->data.AFS_CollData_val,
1792 xstat_fs_Results.data.AFS_CollData_val,
1793 tmp_fsPR->data.AFS_CollData_len * sizeof(afs_int32));
1796 /* we have a valid results structure so mark the list item used */
1797 tmp_fslist_item->empty[index] = 0;
1799 /* Print the fs circular buffer */
1803 } /* save_FS_results_inCB() */
1806 /*-----------------------------------------------------------------------
1810 * The results of xstat probes are stored in a string format in
1811 * the arrays curr_fsData and prev_fsData. The information stored in
1812 * prev_fsData is copied to the screen.
1813 * This function converts xstat FS results from longs to strings and
1814 * place them in the given buffer (a pointer to an item in curr_fsData).
1815 * When a probe cycle completes, curr_fsData is copied to prev_fsData
1816 * in afsmon_FS_Hnadler().
1820 *----------------------------------------------------------------------*/
1823 fs_Results_ltoa(struct fs_Display_Data *a_fsData, /* target buffer */
1824 struct xstat_fs_ProbeResults *a_fsResults) /* ptr to xstat fs Results */
1825 { /* fs_Results_ltoa */
1827 static char rn[] = "fs_Results_ltoa"; /* routine name */
1830 fprintf(debugFD, "[ %s ] Called, a_fsData= %p, a_fsResults= %p\n", rn,
1831 a_fsData, a_fsResults);
1835 switch (a_fsResults->collectionNumber) {
1836 case AFS_XSTATSCOLL_FULL_PERF_INFO:
1837 fs_FullPerfs_ltoa(a_fsData, a_fsResults);
1839 case AFS_XSTATSCOLL_CBSTATS:
1840 fs_CallBackStats_ltoa(a_fsData, a_fsResults);
1844 fprintf(debugFD, "[ %s ] Unexpected collection id %d\n",
1845 rn, a_fsResults->collectionNumber);
1850 } /* fs_Results_ltoa */
1852 /*-----------------------------------------------------------------------
1853 * fs_FullPerfs_ltoa()
1856 * Convert the full perf xstat collection from int32s to strings.
1860 *----------------------------------------------------------------------*/
1862 fs_FullPerfs_ltoa(struct fs_Display_Data *a_fsData,
1863 struct xstat_fs_ProbeResults *a_fsResults)
1866 struct fs_stats_FullPerfStats *fullPerfP;
1867 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);
1910 * For every time value below, we'll have to skip an additional
1911 * 64 bits of input if struct timeval uses 64-bit values
1913 if (sizeof(struct timeval) == 16)
1918 for (i = 0; i < FS_STATS_NUM_RPC_OPS; i++) {
1919 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* numOps */
1922 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* numSuccesses */
1925 tmpbuf = srcbuf++; /* sum time */
1926 sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1931 tmpbuf = srcbuf++; /* sqr time */
1932 sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1937 tmpbuf = srcbuf++; /* min time */
1938 sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1943 tmpbuf = srcbuf++; /* max time */
1944 sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1951 /* copy fs transfer timings */
1953 srcbuf = (afs_int32 *) (fullPerfP->det.xferOpTimes);
1954 for (i = 0; i < FS_STATS_NUM_XFER_OPS; i++) {
1955 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* numOps */
1958 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* numSuccesses */
1961 tmpbuf = srcbuf++; /* sum time */
1962 sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1967 tmpbuf = srcbuf++; /* sqr time */
1968 sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1973 tmpbuf = srcbuf++; /* min time */
1974 sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1979 tmpbuf = srcbuf++; /* max time */
1980 sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1985 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* sum bytes */
1988 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* min bytes */
1991 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* max bytes */
1994 for (j = 0; j < FS_STATS_NUM_XFER_BUCKETS; j++) {
1995 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* bucket[j] */
2004 /*-----------------------------------------------------------------------
2005 * fs_CallBackStats_ltoa()
2008 * Convert the callback counter xstat collection from
2009 * int32s to strings.
2013 *----------------------------------------------------------------------*/
2016 fs_CallBackStats_ltoa(struct fs_Display_Data *a_fsData,
2017 struct xstat_fs_ProbeResults *a_fsResults)
2021 int len = a_fsResults->data.AFS_CollData_len;
2022 afs_int32 *val = a_fsResults->data.AFS_CollData_val;
2024 /* place callback stats after the full perf stats */
2025 idx = NUM_FS_FULLPERF_ENTRIES;
2026 for (i=0; i < len && i < NUM_FS_CB_ENTRIES; i++) {
2027 sprintf(a_fsData->data[idx++], "%u", val[i]);
2032 /*-----------------------------------------------------------------------
2033 * execute_thresh_handler()
2036 * Execute a threshold handler. An agrv[] array of pointers is
2037 * constructed from the given data. A child process is forked
2038 * which immediately calls afsmon_Exit() with indication that a
2039 * threshold handler is to be exec'ed insted of exiting.
2043 * Failure: Afsmonitor exits if threshold handler has more than 20 args.
2044 *----------------------------------------------------------------------*/
2047 execute_thresh_handler(char *a_handler, /* ptr to handler function + args */
2048 char *a_hostName, /* host name for which threshold crossed */
2049 int a_hostType, /* fs or cm ? */
2050 char *a_threshName, /* threshold variable name */
2051 char *a_threshValue, /* threshold value */
2052 char *a_actValue) /* actual value */
2053 { /* execute_thresh_handler */
2055 static char rn[] = "execute_thresh_handler";
2056 char fileName[256]; /* file name to execute */
2060 int anotherArg; /* boolean used to flag if another arg is available */
2064 "[ %s ] Called, a_handler= %s, a_hostName= %s, a_hostType= %d, a_threshName= %s, a_threshValue= %s, a_actValue= %s\n",
2065 rn, a_handler, a_hostName, a_hostType, a_threshName,
2066 a_threshValue, a_actValue);
2071 /* get the filename to execute - the first argument */
2072 sscanf(a_handler, "%s", fileName);
2074 /* construct the contents of *argv[] */
2076 strncpy(fsHandler_args[0], fileName, 256);
2077 strncpy(fsHandler_args[1], a_hostName, HOST_NAME_LEN);
2078 if (a_hostType == FS)
2079 strcpy(fsHandler_args[2], "fs");
2081 strcpy(fsHandler_args[2], "cm");
2082 strncpy(fsHandler_args[3], a_threshName, THRESH_VAR_NAME_LEN);
2083 strncpy(fsHandler_args[4], a_threshValue, THRESH_VAR_LEN);
2084 strncpy(fsHandler_args[5], a_actValue, THRESH_VAR_LEN);
2091 /* we have already extracted the file name so skip to the 1st arg */
2092 while (isspace(*ch)) /* leading blanks */
2094 while (!isspace(*ch) && *ch != '\0') /* handler filename */
2097 while (*ch != '\0') {
2100 } else if (anotherArg) {
2102 sscanf(ch, "%s", fsHandler_args[argNum]);
2108 "Threshold handlers cannot have more than 20 arguments\n");
2114 fsHandler_argv[argNum] = NULL;
2115 for (i = 0; i < argNum; i++)
2116 fsHandler_argv[i] = fsHandler_args[i];
2119 /* exec the threshold handler */
2122 exec_fsThreshHandler = 1;
2127 } /* execute_thresh_handler */
2131 /*-----------------------------------------------------------------------
2132 * check_fs_thresholds()
2135 * Checks the thresholds and sets the overflow flag. Recall that the
2136 * thresholds for each host are stored in the hostEntry lists
2137 * [fs/cm]nameList arrays. The probe results are passed to this
2138 * function in the display-ready format - ie., as strings. Though
2139 * this looks stupid the overhead incurred in converting the strings
2140 * back to floats and comparing them is insignificant and
2141 * programming is easier this way.
2142 * The threshold flags are a part of the display structures
2147 *----------------------------------------------------------------------*/
2150 check_fs_thresholds(struct afsmon_hostEntry *a_hostEntry, /* ptr to hostEntry */
2151 struct fs_Display_Data *a_Data) /* ptr to fs data to be displayed */
2152 { /* check_fs_thresholds */
2154 static char rn[] = "check_fs_thresholds";
2155 struct Threshold *threshP;
2156 double tValue; /* threshold value */
2157 double pValue; /* probe value */
2160 int count; /* number of thresholds exceeded */
2163 fprintf(debugFD, "[ %s ] Called, a_hostEntry= %p, a_Data= %p\n", rn,
2164 a_hostEntry, a_Data);
2168 if (a_hostEntry->numThresh == 0) {
2169 /* store in ovf count ?? */
2174 threshP = a_hostEntry->thresh;
2175 for (i = 0; i < a_hostEntry->numThresh; i++) {
2176 if (threshP->itemName[0] == '\0') {
2180 idx = threshP->index; /* positional index to the data array */
2181 tValue = atof(threshP->threshVal); /* threshold value */
2182 pValue = atof(a_Data->data[idx]); /* probe value */
2183 if (pValue > tValue) {
2187 "[ %s ] fs = %s, thresh ovf for %s, threshold= %s, probevalue= %s\n",
2188 rn, a_hostEntry->hostName, threshP->itemName,
2189 threshP->threshVal, a_Data->data[idx]);
2192 /* if the threshold is crossed, call the handler function
2193 * only if this was a transition -ie, if the threshold was
2194 * crossed in the last probe too just count & keep quite! */
2196 if (!a_Data->threshOvf[idx]) {
2197 a_Data->threshOvf[idx] = 1;
2198 /* call the threshold handler if provided */
2199 if (threshP->handler[0] != '\0') {
2201 fprintf(debugFD, "[ %s ] Calling ovf handler %s\n",
2202 rn, threshP->handler);
2205 execute_thresh_handler(threshP->handler, a_Data->hostName,
2206 FS, threshP->itemName,
2214 /* in case threshold was previously crossed, blank it out */
2215 a_Data->threshOvf[idx] = 0;
2218 /* store the overflow count */
2219 a_Data->ovfCount = count;
2222 } /* check_fs_thresholds */
2225 /*-----------------------------------------------------------------------
2226 * save_FS_data_forDisplay()
2229 * Does the following:
2230 * - if the probe number changed (ie, a cycle completed) curr_fsData
2231 * is copied to prev_fsData, curr_fsData zeroed and refresh the
2232 * overview screen and file server screen with the new data.
2233 * - store the results of the current probe from xstat_fs_Results into
2234 * curr_fsData. ie., convert longs to strings.
2235 * - check the thresholds
2239 * Failure: Exits afsmonitor.
2240 *----------------------------------------------------------------------*/
2243 save_FS_data_forDisplay(struct xstat_fs_ProbeResults *a_fsResults)
2244 { /* save_FS_data_forDisplay */
2246 static char rn[] = "save_FS_data_forDisplay"; /* routine name */
2247 struct fs_Display_Data *curr_fsDataP; /* tmp ptr to curr_fsData */
2248 struct fs_Display_Data *prev_fsDataP; /* tmp ptr to prev_fsData */
2249 struct afsmon_hostEntry *curr_host;
2250 static int results_Received = 0; /* number of probes reveived in
2251 * the current cycle. If this is equal to numFS we got all
2252 * the data we want in this cycle and can now display it */
2261 fprintf(debugFD, "[ %s ] Called, a_fsResults= %p\n", rn, a_fsResults);
2265 /* store results in the display array */
2268 curr_fsDataP = curr_fsData;
2269 for (i = 0; i < numFS; i++) {
2270 if ((strcasecmp(curr_fsDataP->hostName, a_fsResults->connP->hostName))
2280 "[ %s ] Could not insert FS probe results for host %s in fs display array\n",
2281 rn, a_fsResults->connP->hostName);
2285 /* Check the status of the probe. If it succeeded, we store its
2286 * results in the display data structure. If it failed we only mark
2287 * the failed status in the display data structure. */
2289 if (a_fsResults->probeOK) { /* 1 => notOK the xstat results */
2290 curr_fsDataP->probeOK = 0;
2292 /* print the probe status */
2294 fprintf(debugFD, "\n\t\t ----- fs display data ------\n");
2295 fprintf(debugFD, "HostName = %s PROBE FAILED \n",
2296 curr_fsDataP->hostName);
2300 } else { /* probe succeeded, update display data structures */
2301 curr_fsDataP->probeOK = 1;
2303 /* convert longs to strings and place them in curr_fsDataP */
2304 fs_Results_ltoa(curr_fsDataP, a_fsResults);
2306 /* compare with thresholds and set the overflow flags.
2307 * note that the threshold information is in the hostEntry structure and
2308 * each threshold item has a positional index associated with it */
2310 /* locate the hostEntry for this host */
2312 curr_host = FSnameList;
2313 for (i = 0; i < numFS; i++) {
2314 if (strcasecmp(curr_host->hostName, a_fsResults->connP->hostName)
2319 curr_host = curr_host->next;;
2324 code = check_fs_thresholds(curr_host, curr_fsDataP);
2326 fprintf(stderr, "[ %s ] Error in checking thresholds\n", rn);
2330 /* print the info we just saved */
2333 fprintf(debugFD, "\n\t\t ----- fs display data ------\n");
2334 fprintf(debugFD, "HostName = %s\n", curr_fsDataP->hostName);
2335 for (i = 0; i < NUM_FS_STAT_ENTRIES; i++)
2336 fprintf(debugFD, "%20s %30s %s\n", curr_fsDataP->data[i],
2338 curr_fsDataP->threshOvf[i] ? "(ovf)" : "");
2340 fprintf(debugFD, "\t\t--------------------------------\n\n");
2344 } /* the probe succeeded, so we store the data in the display structure */
2347 /* if we have received a reply from all the hosts for this probe cycle,
2348 * it is time to display the data */
2351 if (results_Received == numFS * num_fs_collections) {
2352 results_Received = 0;
2354 if (afsmon_fs_curr_probeNum != afsmon_fs_prev_probeNum + 1) {
2355 sprintf(errMsg, "[ %s ] Probe number %d missed! \n", rn,
2356 afsmon_fs_prev_probeNum + 1);
2359 afsmon_fs_prev_probeNum++;
2361 /* backup the display data of the probe cycle that just completed -
2362 * ie., store curr_fsData in prev_fsData */
2364 memcpy((char *)prev_fsData, (char *)curr_fsData,
2365 (numFS * sizeof(struct fs_Display_Data)));
2368 /* initialize curr_fsData but retain the threshold flag information.
2369 * The previous state of threshold flags is used in check_fs_thresholds() */
2371 numBytes = NUM_FS_STAT_ENTRIES * FS_STAT_STRING_LEN;
2372 curr_fsDataP = curr_fsData;
2373 for (i = 0; i < numFS; i++) {
2374 curr_fsDataP->probeOK = 0;
2375 curr_fsDataP->ovfCount = 0;
2376 memset(curr_fsDataP->data, 0, numBytes);
2381 /* prev_fsData now contains all the information for the probe cycle
2382 * that just completed. Now count the number of threshold overflows for
2383 * use in the overview screen */
2385 prev_fsDataP = prev_fsData;
2387 numHosts_onfs_alerts = 0;
2388 for (i = 0; i < numFS; i++) {
2389 if (!prev_fsDataP->probeOK) { /* if probe failed */
2391 numHosts_onfs_alerts++;
2393 if (prev_fsDataP->ovfCount) { /* overflows ?? */
2394 num_fs_alerts += prev_fsDataP->ovfCount;
2395 numHosts_onfs_alerts++;
2400 fprintf(debugFD, "Number of FS alerts = %d (on %d hosts)\n",
2401 num_fs_alerts, numHosts_onfs_alerts);
2403 /* flag that the data is now ready to be displayed */
2404 fs_Data_Available = 1;
2406 /* call the Overview frame update routine (update only FS info) */
2407 ovw_refresh(ovw_currPage, OVW_UPDATE_FS);
2409 /* call the File Servers frame update routine */
2410 fs_refresh(fs_currPage, fs_curr_LCol);
2415 } /* save_FS_data_forDisplay */
2420 /*-----------------------------------------------------------------------
2421 * afsmon_FS_Handler()
2424 * This is the File Server probe Handler. It updates the afsmonitor
2425 * probe counts, fs circular buffer indices and calls the functions
2426 * to process the results of this probe.
2430 * Failure: Exits afsmonitor.
2431 *----------------------------------------------------------------------*/
2434 afsmon_FS_Handler(void)
2435 { /* afsmon_FS_Handler() */
2436 static char rn[] = "afsmon_FS_Handler"; /* routine name */
2437 int newProbeCycle; /* start of new probe cycle ? */
2438 int code; /* return status */
2443 "[ %s ] Called, hostName= %s, probeNum= %d, status=%s, collection=%d\n", rn,
2444 xstat_fs_Results.connP->hostName, xstat_fs_Results.probeNum,
2445 xstat_fs_Results.probeOK ? "FAILED" : "OK",
2446 xstat_fs_Results.collectionNumber);
2451 /* print the probe results to output file */
2452 if (afsmon_output) {
2453 code = afsmon_fsOutput(output_filename, afsmon_detOutput);
2456 "[ %s ] output to file %s returned error code=%d\n", rn,
2457 output_filename, code);
2461 /* Update current probe number and circular buffer index. if current
2462 * probenum changed make sure it is only by 1 */
2465 if (xstat_fs_Results.probeNum != afsmon_fs_curr_probeNum) {
2466 if (xstat_fs_Results.probeNum == afsmon_fs_curr_probeNum + 1) {
2467 afsmon_fs_curr_probeNum++;
2470 afsmon_fs_curr_CBindex =
2471 (afsmon_fs_curr_probeNum - 1) % num_bufSlots;
2473 fprintf(stderr, "[ %s ] probe number %d-1 missed\n", rn,
2474 xstat_fs_Results.probeNum);
2480 /* store the results of this probe in the FS circular buffer */
2482 save_FS_results_inCB(newProbeCycle);
2485 /* store the results of the current probe in the fs data display structure.
2486 * if the current probe number changed, swap the current and previous display
2487 * structures. note that the display screen is updated from these structures
2488 * and should start showing the data of the just completed probe cycle */
2490 save_FS_data_forDisplay(&xstat_fs_Results);
2497 /*----------------------------------------------------------------------- *
2502 * Prints the Cache Manager circular buffer
2503 *----------------------------------------------------------------------*/
2507 { /* Print_CM_CB() */
2509 struct afsmon_cm_Results_list *cmlist;
2514 /* print valid info in the cm CB */
2518 "==================== CM Buffer ========================\n");
2519 fprintf(debugFD, "afsmon_cm_curr_CBindex = %d\n",
2520 afsmon_cm_curr_CBindex);
2521 fprintf(debugFD, "afsmon_cm_curr_probeNum = %d\n\n",
2522 afsmon_cm_curr_probeNum);
2524 for (i = 0; i < num_bufSlots; i++) {
2525 fprintf(debugFD, "\t--------- slot %d ----------\n", i);
2526 cmlist = afsmon_cm_ResultsCB[i].list;
2529 for (k = 0; k < MAX_NUM_CM_COLLECTIONS; k++) {
2530 if (!cmlist->empty[k]) {
2532 "\t %d) probeNum = %d host = %s cn = %d",
2534 cmlist->cmResults[k]->probeNum,
2535 cmlist->cmResults[k]->connP->hostName,
2536 cmlist->cmResults[k]->collectionNumber);
2537 if (cmlist->cmResults[k]->probeOK)
2538 fprintf(debugFD, " NOTOK\n");
2540 fprintf(debugFD, " OK\n");
2542 fprintf(debugFD, "\t %d) -- empty --\n", j);
2544 cmlist = cmlist->next;
2547 if (cmlist != (struct afsmon_cm_Results_list *)0)
2548 fprintf(debugFD, "dangling last next ptr cm CB\n");
2554 /*-----------------------------------------------------------------------
2555 * save_CM_results_inCB()
2558 * Saves the results of the latest CM probe in the cm circular
2559 * buffers. If the current probe cycle is in progress the contents
2560 * of xstat_cm_Results are copied to the end of the list of results
2561 * in the current slot (pointed to by afsmon_cm_curr_CBindex). If
2562 * a new probe cycle has started the next slot in the circular buffer
2563 * is initialized and the results copied. Note that the Rx related
2564 * information available in xstat_cm_Results is not copied.
2568 * Failure: Exits afsmonitor.
2569 *----------------------------------------------------------------------*/
2572 save_CM_results_inCB(int a_newProbeCycle) /* start of new probe cycle ? */
2573 { /* save_CM_results_inCB() */
2574 static char rn[] = "save_CM_results_inCB"; /* routine name */
2575 struct afsmon_cm_Results_list *tmp_cmlist_item; /* temp cm list item */
2576 struct xstat_cm_ProbeResults *tmp_cmPR; /* temp ptr */
2582 fprintf(debugFD, "[ %s ] Called, a_newProbeCycle= %d\n", rn,
2587 if (xstat_cm_Results.collectionNumber == AFSCB_XSTATSCOLL_FULL_PERF_INFO) {
2590 fprintf(stderr, "[ %s ] collection number %d is out of range.\n",
2591 rn, xstat_cm_Results.collectionNumber);
2595 /* If a new probe cycle started, mark the list in the current buffer
2596 * slot empty for resuse. Note that afsmon_cm_curr_CBindex was appropriately
2597 * incremented in afsmon_CM_Handler() */
2599 if (a_newProbeCycle) {
2600 tmp_cmlist_item = afsmon_cm_ResultsCB[afsmon_cm_curr_CBindex].list;
2601 for (i = 0; i < numCM; i++) {
2602 tmp_cmlist_item->empty[index] = 1;
2603 tmp_cmlist_item = tmp_cmlist_item->next;
2607 /* locate last unused item in list */
2608 tmp_cmlist_item = afsmon_cm_ResultsCB[afsmon_cm_curr_CBindex].list;
2609 for (i = 0; i < numCM; i++) {
2610 if (tmp_cmlist_item->empty[index])
2612 tmp_cmlist_item = tmp_cmlist_item->next;
2615 /* if we could not find one we have an inconsistent list */
2616 if (!tmp_cmlist_item->empty[index]) {
2618 "[ %s ] list inconsistency 1. unable to find an empty slot to store results of probenum %d of %s\n",
2619 rn, xstat_cm_Results.probeNum,
2620 xstat_cm_Results.connP->hostName);
2624 tmp_cmPR = tmp_cmlist_item->cmResults[index];
2626 /* copy hostname and probe number and probe time and probe status.
2627 * if the probe failed return now */
2629 memcpy(tmp_cmPR->connP->hostName, xstat_cm_Results.connP->hostName,
2630 sizeof(xstat_cm_Results.connP->hostName));
2631 tmp_cmPR->probeNum = xstat_cm_Results.probeNum;
2632 tmp_cmPR->probeTime = xstat_cm_Results.probeTime;
2633 tmp_cmPR->probeOK = xstat_cm_Results.probeOK;
2634 if (xstat_cm_Results.probeOK) { /* probeOK = 1 => notOK */
2635 /* we have a nonempty results structure so mark the list item used */
2636 tmp_cmlist_item->empty[index] = 0;
2641 /* copy connection information */
2642 memcpy(&(tmp_cmPR->connP->skt), &(xstat_cm_Results.connP->skt),
2643 sizeof(struct sockaddr_in));
2645 /**** NEED TO COPY rx_connection INFORMATION HERE ******/
2647 memcpy(tmp_cmPR->connP->hostName, xstat_cm_Results.connP->hostName,
2648 sizeof(xstat_cm_Results.connP->hostName));
2649 tmp_cmPR->collectionNumber = xstat_cm_Results.collectionNumber;
2651 /* copy the probe data information */
2652 tmp_cmPR->data.AFSCB_CollData_len =
2653 min(xstat_cm_Results.data.AFSCB_CollData_len,
2654 afsmon_cm_results_length[index]);
2655 memcpy(tmp_cmPR->data.AFSCB_CollData_val,
2656 xstat_cm_Results.data.AFSCB_CollData_val,
2657 tmp_cmPR->data.AFSCB_CollData_len * sizeof(afs_int32));
2660 /* we have a valid results structure so mark the list item used */
2661 tmp_cmlist_item->empty[index] = 0;
2663 /* print the stored info - to make sure we copied it right */
2664 /* Print_cm_FullPerfInfo(tmp_cmPR); */
2665 /* Print the cm circular buffer */
2668 } /* save_CM_results_inCB */
2672 /*-----------------------------------------------------------------------
2676 * The results of xstat probes are stored in a string format in
2677 * the arrays curr_cmData and prev_cmData. The information stored in
2678 * prev_cmData is copied to the screen.
2679 * This function converts xstat FS results from longs to strings and
2680 * places them in the given buffer (a pointer to an item in curr_cmData).
2681 * When a probe cycle completes, curr_cmData is copied to prev_cmData
2682 * in afsmon_CM_Handler().
2686 *----------------------------------------------------------------------*/
2689 cm_Results_ltoa(struct cm_Display_Data *a_cmData, /* target buffer */
2690 struct xstat_cm_ProbeResults *a_cmResults) /* ptr to xstat cm Results */
2691 { /* cm_Results_ltoa */
2693 static char rn[] = "cm_Results_ltoa"; /* routine name */
2694 struct afs_stats_CMFullPerf *fullP; /* ptr to complete CM stats */
2702 fprintf(debugFD, "[ %s ] Called, a_cmData= %p, a_cmResults= %p\n", rn,
2703 a_cmData, a_cmResults);
2708 fullP = (struct afs_stats_CMFullPerf *)
2709 (a_cmResults->data.AFSCB_CollData_val);
2711 /* There are 4 parts to CM statistics
2712 * - Overall performance statistics (including up/down statistics)
2713 * - This CMs FS RPC operations info
2714 * - This CMs FS RPC errors info
2715 * - This CMs FS transfers info
2716 * - Authentication info
2717 * - [Un]Replicated access info
2720 /* copy overall performance statistics */
2721 srcbuf = (afs_int32 *) & (fullP->perf);
2723 /* we skip the 19 entry, ProtServAddr, so the index must account for this */
2724 for (i = 0; i < NUM_AFS_STATS_CMPERF_LONGS + 1; i++) {
2727 continue; /* skip ProtServerAddr */
2729 sprintf(a_cmData->data[idx], "%d", *srcbuf);
2734 /*printf("Ending index value = %d\n",idx-1); */
2736 /* server up/down statistics */
2737 /* copy file server up/down stats */
2738 srcbuf = (afs_int32 *) (fullP->perf.fs_UpDown);
2740 2 * (sizeof(struct afs_stats_SrvUpDownInfo) / sizeof(afs_int32));
2741 for (i = 0; i < numLongs; i++) {
2742 sprintf(a_cmData->data[idx], "%d", *srcbuf);
2747 /*printf("Ending index value = %d\n",idx-1); */
2749 /* copy volume location server up/down stats */
2750 srcbuf = (afs_int32 *) (fullP->perf.vl_UpDown);
2752 2 * (sizeof(struct afs_stats_SrvUpDownInfo) / sizeof(afs_int32));
2753 for (i = 0; i < numLongs; i++) {
2754 sprintf(a_cmData->data[idx], "%d", *srcbuf);
2759 /*printf("Ending index value = %d\n",idx-1); */
2761 /* copy CMs individual FS RPC operations info */
2762 srcbuf = (afs_int32 *) (fullP->rpc.fsRPCTimes);
2763 for (i = 0; i < AFS_STATS_NUM_FS_RPC_OPS; i++) {
2764 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* numOps */
2767 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* numSuccesses */
2770 tmpbuf = srcbuf++; /* sum time */
2771 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2774 tmpbuf = srcbuf++; /* sqr time */
2775 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2778 tmpbuf = srcbuf++; /* min time */
2779 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2782 tmpbuf = srcbuf++; /* max time */
2783 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2788 /*printf("Ending index value = %d\n",idx-1); */
2790 /* copy CMs individual FS RPC errors info */
2792 srcbuf = (afs_int32 *) (fullP->rpc.fsRPCErrors);
2793 for (i = 0; i < AFS_STATS_NUM_FS_RPC_OPS; i++) {
2794 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* server */
2797 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* network */
2800 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* prot */
2803 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* vol */
2806 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* busies */
2809 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* other */
2814 /*printf("Ending index value = %d\n",idx-1); */
2816 /* copy CMs individual RPC transfers info */
2818 srcbuf = (afs_int32 *) (fullP->rpc.fsXferTimes);
2819 for (i = 0; i < AFS_STATS_NUM_FS_XFER_OPS; i++) {
2820 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* numOps */
2823 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* numSuccesses */
2826 tmpbuf = srcbuf++; /* sum time */
2827 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2830 tmpbuf = srcbuf++; /* sqr time */
2831 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2834 tmpbuf = srcbuf++; /* min time */
2835 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2838 tmpbuf = srcbuf++; /* max time */
2839 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2842 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* sum bytes */
2845 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* min bytes */
2848 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* max bytes */
2851 for (j = 0; j < AFS_STATS_NUM_XFER_BUCKETS; j++) {
2852 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* bucket[j] */
2858 /*printf("Ending index value = %d\n",idx-1); */
2860 /* copy CM operations timings */
2862 srcbuf = (afs_int32 *) (fullP->rpc.cmRPCTimes);
2863 for (i = 0; i < AFS_STATS_NUM_CM_RPC_OPS; i++) {
2864 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* numOps */
2867 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* numSuccesses */
2870 tmpbuf = srcbuf++; /* sum time */
2871 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2874 tmpbuf = srcbuf++; /* sqr time */
2875 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2878 tmpbuf = srcbuf++; /* min time */
2879 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2882 tmpbuf = srcbuf++; /* max time */
2883 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2888 /*printf("Ending index value = %d\n",idx-1); */
2890 /* copy authentication info */
2892 srcbuf = (afs_int32 *) & (fullP->authent);
2893 numLongs = sizeof(struct afs_stats_AuthentInfo) / sizeof(afs_int32);
2894 for (i = 0; i < numLongs; i++) {
2895 sprintf(a_cmData->data[idx], "%d", *srcbuf);
2900 /*printf("Ending index value = %d\n",idx-1); */
2902 /* copy CM [un]replicated access info */
2904 srcbuf = (afs_int32 *) & (fullP->accessinf);
2905 numLongs = sizeof(struct afs_stats_AccessInfo) / sizeof(afs_int32);
2906 for (i = 0; i < numLongs; i++) {
2907 sprintf(a_cmData->data[idx], "%d", *srcbuf);
2912 /*printf("Ending index value = %d\n",idx-1); */
2915 } /* cm_Results_ltoa */
2918 /*-----------------------------------------------------------------------
2919 * Function: check_cm_thresholds()
2922 * Checks the thresholds and sets the overflow flag. Recall that the
2923 * thresholds for each host are stored in the hostEntry lists
2924 * [fs/cm]nameList arrays. The probe results are passed to this
2925 * function in the display-ready format - ie., as strings. Though
2926 * this looks stupid the overhead incurred in converting the strings
2927 * back to floats and comparing them is insignificant and
2928 * programming is easier this way.
2929 * The threshold flags are a part of the display structures
2934 *----------------------------------------------------------------------*/
2937 check_cm_thresholds(struct afsmon_hostEntry *a_hostEntry, /* ptr to hostEntry */
2938 struct cm_Display_Data *a_Data) /* ptr to cm data to be displayed */
2939 { /* check_cm_thresholds */
2941 static char rn[] = "check_cm_thresholds";
2942 struct Threshold *threshP;
2943 double tValue; /* threshold value */
2944 double pValue; /* probe value */
2947 int count; /* number of thresholds exceeded */
2950 fprintf(debugFD, "[ %s ] Called, a_hostEntry= %p, a_Data= %p\n", rn,
2951 a_hostEntry, a_Data);
2955 if (a_hostEntry->numThresh == 0) {
2956 /* store in ovf count ?? */
2961 threshP = a_hostEntry->thresh;
2962 for (i = 0; i < a_hostEntry->numThresh; i++) {
2963 if (threshP->itemName[0] == '\0') {
2967 idx = threshP->index; /* positional index to the data array */
2968 tValue = atof(threshP->threshVal); /* threshold value */
2969 pValue = atof(a_Data->data[idx]); /* probe value */
2970 if (pValue > tValue) {
2974 "[ %s ] cm = %s, thresh ovf for %s, threshold= %s, probevalue= %s\n",
2975 rn, a_hostEntry->hostName, threshP->itemName,
2976 threshP->threshVal, a_Data->data[idx]);
2980 /* if the threshold is crossed, call the handler function
2981 * only if this was a transition -ie, if the threshold was
2982 * crossed in the last probe too just count & keep quite! */
2984 if (!a_Data->threshOvf[idx]) {
2985 a_Data->threshOvf[idx] = 1;
2986 /* call the threshold handler if provided */
2987 if (threshP->handler[0] != '\0') {
2989 fprintf(debugFD, "[ %s ] Calling ovf handler %s\n",
2990 rn, threshP->handler);
2993 execute_thresh_handler(threshP->handler, a_Data->hostName,
2994 CM, threshP->itemName,
3002 /* in case threshold was previously crossed, blank it out */
3003 a_Data->threshOvf[idx] = 0;
3006 /* store the overflow count */
3007 a_Data->ovfCount = count;
3010 } /* check_cm_thresholds */
3013 /*-----------------------------------------------------------------------
3014 * save_CM_data_forDisplay()
3017 * Does the following:
3018 * - if the probe number changed (ie, a cycle completed) curr_cmData
3019 * is copied to prev_cmData, curr_cmData zeroed and refresh the
3020 * overview screen and file server screen with the new data.
3021 * - store the results of the current probe from xstat_cm_Results into
3022 * curr_cmData. ie., convert longs to strings.
3023 * - check the thresholds
3027 * Failure: Exits afsmonitor.
3029 *----------------------------------------------------------------------*/
3032 save_CM_data_forDisplay(struct xstat_cm_ProbeResults *a_cmResults)
3033 { /* save_CM_data_forDisplay */
3035 static char rn[] = "save_CM_data_forDisplay"; /* routine name */
3036 struct cm_Display_Data *curr_cmDataP;
3037 struct cm_Display_Data *prev_cmDataP;
3038 struct afsmon_hostEntry *curr_host;
3039 static int results_Received = 0; /* number of probes reveived in
3040 * the current cycle. If this is equal to numFS we got all
3041 * the data we want in this cycle and can now display it */
3049 fprintf(debugFD, "[ %s ] Called, a_cmResults= %p\n", rn, a_cmResults);
3053 /* store results in the display array */
3056 curr_cmDataP = curr_cmData;
3057 for (i = 0; i < numCM; i++) {
3058 if ((strcasecmp(curr_cmDataP->hostName, a_cmResults->connP->hostName))
3068 "[ %s ] Could not insert CM probe results for host %s in cm display array\n",
3069 rn, a_cmResults->connP->hostName);
3073 /* Check the status of the probe. If it succeeded, we store its
3074 * results in the display data structure. If it failed we only mark
3075 * the failed status in the display data structure. */
3078 if (a_cmResults->probeOK) { /* 1 => notOK the xstat results */
3079 curr_cmDataP->probeOK = 0;
3081 /* print the probe status */
3083 fprintf(debugFD, "\n\t\t ----- cm display data ------\n");
3084 fprintf(debugFD, "HostName = %s PROBE FAILED \n",
3085 curr_cmDataP->hostName);
3089 } else { /* probe succeeded, update display data structures */
3090 curr_cmDataP->probeOK = 1;
3093 /* covert longs to strings and place them in curr_cmDataP */
3094 cm_Results_ltoa(curr_cmDataP, a_cmResults);
3096 /* compare with thresholds and set the overflow flags.
3097 * note that the threshold information is in the hostEntry structure and
3098 * each threshold item has a positional index associated with it */
3100 /* locate the hostEntry for this host */
3102 curr_host = CMnameList;
3103 for (i = 0; i < numCM; i++) {
3104 if (strcasecmp(curr_host->hostName, a_cmResults->connP->hostName)
3109 curr_host = curr_host->next;
3114 code = check_cm_thresholds(curr_host, curr_cmDataP);
3116 fprintf(stderr, "[ %s ] Error in checking thresholds\n", rn);
3120 /* print the info we just saved */
3122 fprintf(debugFD, "\n\t\t ----- CM display data ------\n");
3123 fprintf(debugFD, "HostName = %s\n", curr_cmDataP->hostName);
3124 for (i = 0; i < NUM_CM_STAT_ENTRIES; i++) {
3127 fprintf(debugFD, "\t -- Overall Perf Info --\n");
3131 "\t -- File Server up/down stats - same cell --\n");
3135 "\t -- File Server up/down stats - diff cell --\n");
3139 "\t -- VL server up/down stats - same cell --\n");
3143 "\t -- VL server up/down stats - diff cell --\n");
3146 fprintf(debugFD, "\t -- FS Operation Timings --\n");
3149 fprintf(debugFD, "\t -- FS Error Info --\n");
3152 fprintf(debugFD, "\t -- FS Transfer Timings --\n");
3155 fprintf(debugFD, "\t -- CM Operations Timings --\n");
3158 fprintf(debugFD, "\t -- Authentication Info --\n");
3161 fprintf(debugFD, "\t -- Access Info --\n");
3167 fprintf(debugFD, "%20s %30s %s\n", curr_cmDataP->data[i],
3169 curr_cmDataP->threshOvf[i] ? "(ovf)" : "");
3171 fprintf(debugFD, "\t\t--------------------------------\n\n");
3174 } /* if the probe succeeded, update the display data structures */
3176 /* if we have received a reply from all the hosts for this probe cycle,
3177 * it is time to display the data */
3180 if (results_Received == numCM * num_cm_collections) {
3181 results_Received = 0;
3183 if (afsmon_cm_curr_probeNum != afsmon_cm_prev_probeNum + 1) {
3184 sprintf(errMsg, "[ %s ] Probe number %d missed! \n", rn,
3185 afsmon_cm_prev_probeNum + 1);
3188 afsmon_cm_prev_probeNum++;
3191 /* backup the display data of the probe cycle that just completed -
3192 * ie., store curr_cmData in prev_cmData */
3194 memcpy((char *)prev_cmData, (char *)curr_cmData,
3195 (numCM * sizeof(struct cm_Display_Data)));
3198 /* initialize curr_cmData but retain the threshold flag information.
3199 * The previous state of threshold flags is used in check_cm_thresholds() */
3201 curr_cmDataP = curr_cmData;
3202 numBytes = NUM_CM_STAT_ENTRIES * CM_STAT_STRING_LEN;
3203 for (i = 0; i < numCM; i++) {
3204 curr_cmDataP->probeOK = 0;
3205 curr_cmDataP->ovfCount = 0;
3206 memset(curr_cmDataP->data, 0, numBytes);
3210 /* prev_cmData now contains all the information for the probe cycle
3211 * that just completed. Now count the number of threshold overflows for
3212 * use in the overview screen */
3214 prev_cmDataP = prev_cmData;
3216 numHosts_oncm_alerts = 0;
3217 for (i = 0; i < numCM; i++) {
3218 if (!prev_cmDataP->probeOK) { /* if probe failed */
3220 numHosts_oncm_alerts++;
3221 } else if (prev_cmDataP->ovfCount) { /* overflows ?? */
3222 num_cm_alerts += prev_cmDataP->ovfCount;
3223 numHosts_oncm_alerts++;
3228 fprintf(debugFD, "Number of CM alerts = %d (on %d hosts)\n",
3229 num_cm_alerts, numHosts_oncm_alerts);
3232 /* flag that the data is now ready to be displayed */
3233 cm_Data_Available = 1;
3235 /* update the Overview frame (only CM info) */
3236 ovw_refresh(ovw_currPage, OVW_UPDATE_CM);
3238 /* update the Cache Managers frame */
3239 cm_refresh(cm_currPage, cm_curr_LCol);
3245 } /* save_CM_data_forDisplay */
3249 /*-----------------------------------------------------------------------
3250 * afsmon_CM_Handler()
3253 * This is the Cache Manager probe Handler. It updates the afsmonitor
3254 * probe counts, cm circular buffer indices and calls the functions
3255 * to process the results of this probe.
3259 * Failure: Exits afsmonitor.
3260 *----------------------------------------------------------------------*/
3263 afsmon_CM_Handler(void)
3264 { /* afsmon_CM_Handler() */
3265 static char rn[] = "afsmon_CM_Handler"; /* routine name */
3266 int code; /* return status */
3267 int newProbeCycle; /* start of new probe cycle ? */
3271 "[ %s ] Called, hostName= %s, probeNum= %d, status= %s\n", rn,
3272 xstat_cm_Results.connP->hostName, xstat_cm_Results.probeNum,
3273 xstat_cm_Results.probeOK ? "FAILED" : "OK");
3278 /* print the probe results to output file */
3279 if (afsmon_output) {
3280 code = afsmon_cmOutput(output_filename, afsmon_detOutput);
3283 "[ %s ] output to file %s returned error code=%d\n", rn,
3284 output_filename, code);
3288 /* Update current probe number and circular buffer index. if current
3289 * probenum changed make sure it is only by 1 */
3292 if (xstat_cm_Results.probeNum != afsmon_cm_curr_probeNum) {
3293 if (xstat_cm_Results.probeNum == afsmon_cm_curr_probeNum + 1) {
3294 afsmon_cm_curr_probeNum++;
3297 afsmon_cm_curr_CBindex =
3298 (afsmon_cm_curr_probeNum - 1) % num_bufSlots;
3300 fprintf(stderr, "[ %s ] probe number %d-1 missed\n", rn,
3301 xstat_cm_Results.probeNum);
3306 /* save the results of this probe in the CM buffer */
3308 save_CM_results_inCB(newProbeCycle);
3310 /* store the results of the current probe in the cm data display structure.
3311 * if the current probe number changed, swap the current and previous display
3312 * structures. note that the display screen is updated from these structures
3313 * and should start showing the data of the just completed probe cycle */
3315 save_CM_data_forDisplay(&xstat_cm_Results);
3320 /*-----------------------------------------------------------------------
3324 * Allocate and Initialize circular buffers for file servers.
3328 * Failure to allocate memory: exits afsmonitor.
3329 *----------------------------------------------------------------------*/
3332 init_fs_buffers(void)
3333 { /* init_fs_buffers() */
3334 static char rn[] = "init_fs_buffers"; /* routine name */
3335 struct afsmon_fs_Results_list *new_fslist_item; /* ptr for new struct */
3336 struct afsmon_fs_Results_list *tmp_fslist_item; /* temp ptr */
3337 struct xstat_fs_ProbeResults *new_fsPR; /* ptr for new struct */
3344 fprintf(debugFD, "[ %s ] Called\n", rn);
3348 /* allocate memory for the circular buffer of pointers */
3350 afsmon_fs_ResultsCB = (struct afsmon_fs_Results_CBuffer *)
3351 malloc(sizeof(struct afsmon_fs_Results_CBuffer) * num_bufSlots);
3353 /* initialize the fs circular buffer */
3354 for (i = 0; i < num_bufSlots; i++) {
3355 afsmon_fs_ResultsCB[i].list = (struct afsmon_fs_Results_list *)0;
3356 afsmon_fs_ResultsCB[i].probeNum = 0;
3359 /* create a list of numFS items to store fs probe results for
3360 * each slot in CB */
3362 if (numFS) { /* if we have file servers to monitor */
3363 for (bufslot = 0; bufslot < num_bufSlots; bufslot++) {
3364 numfs = numFS; /* get the number of servers */
3367 /* if any of these mallocs fail we only need to free the memory we
3368 * have allocated in this iteration. the rest of it which is in a
3369 * proper linked list will be freed in afsmon_Exit */
3371 /* allocate memory for an fs list item */
3372 new_fslist_item = (struct afsmon_fs_Results_list *)
3373 malloc(sizeof(struct afsmon_fs_Results_list));
3374 if (new_fslist_item == (struct afsmon_fs_Results_list *)0)
3377 for (i = 0; i < MAX_NUM_FS_COLLECTIONS; i++) {
3378 /* allocate memory to store xstat_fs_Results */
3379 new_fsPR = (struct xstat_fs_ProbeResults *)
3380 malloc(sizeof(struct xstat_fs_ProbeResults));
3382 free(new_fslist_item);
3386 new_fsPR->connP = (struct xstat_fs_ConnectionInfo *)
3387 malloc(sizeof(struct xstat_fs_ConnectionInfo));
3388 if (new_fsPR->connP == (struct xstat_fs_ConnectionInfo *)0) {
3389 free(new_fslist_item);
3394 /* >>> need to allocate rx connection info structure here <<< */
3395 new_fsPR->data.AFS_CollData_val = (afs_int32 *)
3396 malloc(afsmon_fs_results_length[i] * sizeof(afs_int32));
3397 if (new_fsPR->data.AFS_CollData_val == NULL) {
3398 free(new_fslist_item);
3399 free(new_fsPR->connP);
3403 new_fslist_item->fsResults[i] = new_fsPR;
3404 new_fslist_item->empty[i] = 1;
3407 /* initialize this list entry */
3408 new_fslist_item->next = (struct afsmon_fs_Results_list *)0;
3410 /* store it at the end of the fs list in the current CB slot */
3411 if (afsmon_fs_ResultsCB[bufslot].list ==
3412 (struct afsmon_fs_Results_list *)0)
3413 afsmon_fs_ResultsCB[bufslot].list = new_fslist_item;
3415 tmp_fslist_item = afsmon_fs_ResultsCB[bufslot].list;
3417 while (tmp_fslist_item !=
3418 (struct afsmon_fs_Results_list *)0) {
3419 if (tmp_fslist_item->next ==
3420 (struct afsmon_fs_Results_list *)0)
3422 tmp_fslist_item = tmp_fslist_item->next;
3424 /* something goofed. exit */
3425 fprintf(stderr, "[ %s ] list creation error\n",
3430 tmp_fslist_item->next = new_fslist_item;
3433 } /* while servers */
3434 } /* for each buffer slot */
3435 } /* if we have file servers to monitor */
3439 /*-----------------------------------------------------------------------
3443 * Allocate and Initialize circular buffers for cache managers.
3447 * Failure to allocate memory: exits afsmonitor.
3448 *----------------------------------------------------------------------*/
3451 init_cm_buffers(void)
3452 { /* init_cm_buffers() */
3453 static char rn[] = "init_cm_buffers"; /* routine name */
3454 struct afsmon_cm_Results_list *new_cmlist_item; /* ptr for new struct */
3455 struct afsmon_cm_Results_list *tmp_cmlist_item; /* temp ptr */
3456 struct xstat_cm_ProbeResults *new_cmPR; /* ptr for new struct */
3462 fprintf(debugFD, "[ %s ] Called\n", rn);
3466 /* allocate memory for the circular buffer of pointers */
3467 afsmon_cm_ResultsCB = (struct afsmon_cm_Results_CBuffer *)
3468 malloc(sizeof(struct afsmon_cm_Results_CBuffer) * num_bufSlots);
3470 /* initialize the fs circular buffer */
3471 for (i = 0; i < num_bufSlots; i++) {
3472 afsmon_cm_ResultsCB[i].list = (struct afsmon_cm_Results_list *)0;
3473 afsmon_cm_ResultsCB[i].probeNum = 0;
3476 /* create a list of numCM items to store fs probe results for
3477 * each slot in CB */
3479 if (numCM) { /* if we have file servers to monitor */
3480 for (bufslot = 0; bufslot < num_bufSlots; bufslot++) {
3481 numcm = numCM; /* get the number of servers */
3484 /* if any of these mallocs fail we only need to free the memory we
3485 * have allocated in this iteration. the rest of it which is in a
3486 * proper linked list will be freed in afsmon_Exit */
3488 /* allocate memory for an fs list item */
3489 new_cmlist_item = (struct afsmon_cm_Results_list *)
3490 malloc(sizeof(struct afsmon_cm_Results_list));
3491 if (new_cmlist_item == (struct afsmon_cm_Results_list *)0)
3494 for (i = 0; i < MAX_NUM_CM_COLLECTIONS; i++) {
3495 /* allocate memory to store xstat_cm_Results */
3496 new_cmPR = (struct xstat_cm_ProbeResults *)
3497 malloc(sizeof(struct xstat_cm_ProbeResults));
3499 free(new_cmlist_item);
3502 new_cmPR->connP = (struct xstat_cm_ConnectionInfo *)
3503 malloc(sizeof(struct xstat_cm_ConnectionInfo));
3504 if (!new_cmPR->connP) {
3505 free(new_cmlist_item);
3510 /* >>> need to allocate rx connection info structure here <<< */
3512 new_cmPR->data.AFSCB_CollData_val =
3513 malloc(XSTAT_CM_FULLPERF_RESULTS_LEN
3514 *sizeof(afs_int32));
3515 if (new_cmPR->data.AFSCB_CollData_val == NULL) {
3516 free(new_cmlist_item);
3517 free(new_cmPR->connP);
3522 new_cmlist_item->cmResults[i] = new_cmPR;
3523 new_cmlist_item->empty[i] = 1;
3526 /* initialize this list entry */
3527 new_cmlist_item->next = (struct afsmon_cm_Results_list *)0;
3529 /* store it at the end of the cm list in the current CB slot */
3530 if (afsmon_cm_ResultsCB[bufslot].list ==
3531 (struct afsmon_cm_Results_list *)0)
3532 afsmon_cm_ResultsCB[bufslot].list = new_cmlist_item;
3534 tmp_cmlist_item = afsmon_cm_ResultsCB[bufslot].list;
3536 while (tmp_cmlist_item !=
3537 (struct afsmon_cm_Results_list *)0) {
3538 if (tmp_cmlist_item->next ==
3539 (struct afsmon_cm_Results_list *)0)
3541 tmp_cmlist_item = tmp_cmlist_item->next;
3543 /* something goofed. exit */
3544 fprintf(stderr, "[ %s ] list creation error\n",
3549 tmp_cmlist_item->next = new_cmlist_item;
3552 } /* while servers */
3553 } /* for each buffer slot */
3555 /* if we have file servers to monitor */
3556 /* print the CB to make sure it is right */
3560 } /* init_cm_buffers() */
3563 /*-------------------------------------------------------------------------
3564 * init_print_buffers()
3567 * Allocate and initialize the buffers used for printing results
3568 * to the display screen. These buffers store the current and
3569 * previous probe results in ascii format.
3574 *------------------------------------------------------------------------*/
3577 init_print_buffers(void)
3578 { /* init_print_buffers */
3580 static char rn[] = "init_print_buffers"; /* routine name */
3581 struct fs_Display_Data *tmp_fsData1; /* temp pointers */
3582 struct fs_Display_Data *tmp_fsData2;
3583 struct cm_Display_Data *tmp_cmData1;
3584 struct cm_Display_Data *tmp_cmData2;
3585 struct afsmon_hostEntry *tmp_fsNames;
3586 struct afsmon_hostEntry *tmp_cmNames;
3591 fprintf(debugFD, "[ %s ] Called\n", rn);
3595 /* allocate numFS blocks of the FS print structure. */
3597 /* we need two instances of this structure - one (curr_fsData) for storing
3598 * the results of the fs probes currently in progress and another (prev_fsData)
3599 * for the last completed probe. The display is updated from the contents of
3600 * prev_fsData. The pointers curr_fsData & prev_fsData are switched whenever
3601 * the probe number changes */
3604 numBytes = numFS * sizeof(struct fs_Display_Data);
3605 curr_fsData = malloc(numBytes);
3606 if (curr_fsData == (struct fs_Display_Data *)0) {
3607 fprintf(stderr, "[ %s ] Memory allocation failure\n", rn);
3610 memset(curr_fsData, 0, numBytes);
3612 numBytes = numFS * sizeof(struct fs_Display_Data);
3613 prev_fsData = malloc(numBytes);
3614 if (prev_fsData == (struct fs_Display_Data *)0) {
3615 fprintf(stderr, "[ %s ] Memory allocation failure\n", rn);
3618 memset(prev_fsData, 0, numBytes);
3620 /* fill in the host names */
3621 tmp_fsData1 = curr_fsData;
3622 tmp_fsData2 = curr_fsData;
3623 tmp_fsNames = FSnameList;
3624 for (i = 0; i < numFS; i++) {
3625 strncpy(tmp_fsData1->hostName, tmp_fsNames->hostName,
3627 strncpy(tmp_fsData2->hostName, tmp_fsNames->hostName,
3631 tmp_fsNames = tmp_fsNames->next;;
3636 /* if file servers to monitor */
3637 /* allocate numCM blocks of the CM print structure */
3638 /* we need two instances of this structure for the same reasons as above */
3640 numBytes = numCM * sizeof(struct cm_Display_Data);
3642 curr_cmData = malloc(numBytes);
3643 if (curr_cmData == (struct cm_Display_Data *)0) {
3644 fprintf(stderr, "[ %s ] Memory allocation failure\n", rn);
3647 memset(curr_cmData, 0, numBytes);
3649 numBytes = numCM * sizeof(struct cm_Display_Data);
3650 prev_cmData = malloc(numBytes);
3651 if (prev_cmData == (struct cm_Display_Data *)0) {
3652 fprintf(stderr, "[ %s ] Memory allocation failure\n", rn);
3655 memset(prev_cmData, 0, numBytes);
3657 /* fill in the host names */
3658 tmp_cmData1 = curr_cmData;
3659 tmp_cmData2 = curr_cmData;
3660 tmp_cmNames = CMnameList;
3661 for (i = 0; i < numCM; i++) {
3662 strncpy(tmp_cmData1->hostName, tmp_cmNames->hostName,
3664 strncpy(tmp_cmData2->hostName, tmp_cmNames->hostName,
3668 tmp_cmNames = tmp_cmNames->next;;
3672 /* if cache managers to monitor */
3675 } /* init_print_buffers */
3677 /*-----------------------------------------------------------------------
3681 * Trap the interrupt signal. This function is useful only until
3682 * gtx is initialized.
3683 *----------------------------------------------------------------------*/
3686 quit_signal(int sig)
3688 fprintf(stderr, "Received signal %d \n", sig);
3694 /*-----------------------------------------------------------------------
3698 * This is where we start it all. Initialize an array of sockets for
3699 * file servers and cache cache managers and call the xstat_[fs/cm]_Init
3700 * routines. The last step is to call the gtx input server which
3701 * grabs control of the keyboard.
3704 * Does not return. Control is periodically returned to the afsmonitor
3705 * thru afsmon_[FS/CM]_Handler() routines and also through the gtx
3706 * keyboard handler calls.
3708 *----------------------------------------------------------------------*/
3711 afsmon_execute(void)
3712 { /* afsmon_execute() */
3713 static char rn[] = "afsmon_execute"; /* routine name */
3714 static char fullhostname[128]; /* full host name */
3715 struct sockaddr_in *FSSktArray; /* fs socket array */
3716 int FSsktbytes; /* num bytes in above */
3717 struct sockaddr_in *CMSktArray; /* cm socket array */
3718 int CMsktbytes; /* num bytes in above */
3719 struct sockaddr_in *curr_skt; /* ptr to current socket */
3720 struct afsmon_hostEntry *curr_FS; /* ptr to FS name list */
3721 struct afsmon_hostEntry *curr_CM; /* ptr to CM name list */
3722 struct hostent *he; /* host entry */
3723 int FSinitFlags = 0; /* flags for xstat_fs_Init */
3724 int CMinitFlags = 0; /* flags for xstat_cm_Init */
3725 int code; /* function return code */
3730 fprintf(debugFD, "[ %s ] Called\n", rn);
3735 /* process file server entries */
3737 afs_int32 collIDs[MAX_NUM_FS_COLLECTIONS];
3739 /* Allocate an array of sockets for each fileserver we monitor */
3741 FSsktbytes = numFS * sizeof(struct sockaddr_in);
3742 FSSktArray = malloc(FSsktbytes);
3743 if (FSSktArray == (struct sockaddr_in *)0) {
3745 "[ %s ] cannot malloc %d sockaddr_ins for fileservers\n",
3750 memset(FSSktArray, 0, FSsktbytes);
3752 /* Fill in the socket information for each fileserve */
3754 curr_skt = FSSktArray;
3755 curr_FS = FSnameList; /* FS name list header */
3757 strncpy(fullhostname, curr_FS->hostName, sizeof(fullhostname));
3758 he = GetHostByName(fullhostname);
3760 fprintf(stderr, "[ %s ] Cannot get host info for %s\n", rn,
3764 strncpy(curr_FS->hostName, he->h_name, HOST_NAME_LEN); /* complete name */
3765 memcpy(&(curr_skt->sin_addr.s_addr), he->h_addr, 4);
3766 curr_skt->sin_family = AF_INET; /*Internet family */
3767 curr_skt->sin_port = htons(7000); /*FileServer port */
3768 #ifdef STRUCT_SOCKADDR_HAS_SA_LEN
3769 curr_skt->sin_len = sizeof(struct sockaddr_in);
3772 /* get the next dude */
3774 curr_FS = curr_FS->next;
3777 /* Initialize collection IDs, depending on the data requested. */
3778 num_fs_collections = 0;
3779 for (i = 0; i < fs_DisplayItems_count; i++) {
3780 index = fs_Display_map[i];
3781 if (FS_FULLPERF_ENTRY_START <= index && index <= FS_FULLPERF_ENTRY_END) {
3782 collIDs[num_fs_collections++] = AFS_XSTATSCOLL_FULL_PERF_INFO;
3786 for (i = 0; i < fs_DisplayItems_count; i++) {
3787 index = fs_Display_map[i];
3788 if (FS_CB_ENTRY_START <= index && index <= FS_CB_ENTRY_END) {
3789 collIDs[num_fs_collections++] = AFS_XSTATSCOLL_CBSTATS;
3797 fprintf(debugFD, "[ %s ] Calling xstat_fs_Init \n", rn);
3801 code = xstat_fs_Init(numFS, /*Num servers */
3802 FSSktArray, /*File Server socket array */
3803 afsmon_probefreq, /*probe frequency */
3804 afsmon_FS_Handler, /*Handler routine */
3805 FSinitFlags, /*Initialization flags */
3806 num_fs_collections, /*Number of collection IDs */
3807 collIDs); /*Ptr to collection ID */
3810 fprintf(stderr, "[ %s ] xstat_fs_init returned error\n", rn);
3817 /* end of process fileserver entries */
3818 /* process cache manager entries */
3820 afs_int32 collIDs[MAX_NUM_CM_COLLECTIONS];
3822 /* Allocate an array of sockets for each cache manager we monitor */
3824 CMsktbytes = numCM * sizeof(struct sockaddr_in);
3825 CMSktArray = malloc(CMsktbytes);
3826 if (CMSktArray == (struct sockaddr_in *)0) {
3828 "[ %s ] cannot malloc %d sockaddr_ins for CM entries\n",
3833 memset(CMSktArray, 0, CMsktbytes);
3835 /* Fill in the socket information for each CM */
3837 curr_skt = CMSktArray;
3838 curr_CM = CMnameList; /* CM name list header */
3840 strncpy(fullhostname, curr_CM->hostName, sizeof(fullhostname));
3841 he = GetHostByName(fullhostname);
3843 fprintf(stderr, "[ %s ] Cannot get host info for %s\n", rn,
3847 strncpy(curr_CM->hostName, he->h_name, HOST_NAME_LEN); /* complete name */
3848 memcpy(&(curr_skt->sin_addr.s_addr), he->h_addr, 4);
3849 curr_skt->sin_family = AF_INET;
3850 curr_skt->sin_port = htons(7001); /* Cache Manager port */
3851 #ifdef STRUCT_SOCKADDR_HAS_SA_LEN
3852 curr_skt->sin_len = sizeof(struct sockaddr_in);
3855 /* get the next dude */
3857 curr_CM = curr_CM->next;
3860 /* initialize collection IDs. We need only one entry since we collect
3861 * all the information from xstat */
3862 num_cm_collections = 0;
3863 collIDs[num_cm_collections++] = AFSCB_XSTATSCOLL_FULL_PERF_INFO;
3868 fprintf(debugFD, "[ %s ] Calling xstat_cm_Init \n", rn);
3872 code = xstat_cm_Init(numCM, /*Num servers */
3873 CMSktArray, /*Cache Manager socket array */
3874 afsmon_probefreq, /*probe frequency */
3875 afsmon_CM_Handler, /*Handler routine */
3876 CMinitFlags, /*Initialization flags */
3877 num_cm_collections, /*Number of collection IDs */
3878 collIDs); /*Ptr to collection ID */
3881 fprintf(stderr, "[ %s ] xstat_cm_init returned error\n", rn);
3888 /* end of process cache manager entries */
3890 /* start the gtx input server */
3891 code = (intptr_t)gtx_InputServer(afsmon_win);
3893 fprintf(stderr, "[ %s ] Failed to start input server \n", rn);
3897 /* This part of the code is reached only if the input server is not started
3898 * for debugging purposes */
3899 xstat_cm_Wait(0); /* sleep forever */
3904 /*-----------------------------------------------------------------------
3908 * Afsmonitor initialization routine.
3909 * - processes command line parameters
3910 * - call functions to:
3911 * - process config file
3912 * - initialize circular buffers and display buffers
3914 * - execute afsmonitor
3915 * - initialize the display maps [fs/cm]_Display_map[].
3918 * Success: Does not return from the call to afsmon_execute().
3919 * Failure: Exits afsmonitor.
3920 *----------------------------------------------------------------------*/
3923 afsmonInit(struct cmd_syndesc *as, void *arock)
3924 { /* afsmonInit() */
3926 static char rn[] = "afsmonInit"; /* Routine name */
3927 char *debug_filename; /* pointer to debug filename */
3928 FILE *outputFD; /* output file descriptor */
3929 struct cmd_item *hostPtr; /* ptr to parse command line args */
3930 char buf[256]; /* buffer for processing hostnames */
3935 fprintf(debugFD, "[ %s ] Called, as= %p\n", rn, as);
3939 /* Open the debug file if -debug option is specified */
3940 if (as->parms[P_DEBUG].items != 0) {
3942 debug_filename = as->parms[P_DEBUG].items->data;
3943 debugFD = fopen(debug_filename, "w");
3944 if (debugFD == (FILE *) 0) {
3945 printf("[ %s ] Failed to open debugging file %s for writing\n",
3953 fprintf(debugFD, "[ %s ] Called\n", rn);
3957 /* use curses always until we support other packages */
3958 wpkg_to_use = GATOR_WIN_CURSES;
3960 /* get probe frequency . We check for meaningful bounds on the frequency
3961 * and reset to the default value if needed. The upper bound of 24
3962 * hours looks ridiculous though! */
3964 afsmon_probefreq = 0;
3965 if (as->parms[P_FREQUENCY].items != 0)
3966 afsmon_probefreq = atoi(as->parms[P_FREQUENCY].items->data);
3968 afsmon_probefreq = DEFAULT_FREQUENCY;
3970 if (afsmon_probefreq <= 0 || afsmon_probefreq > 24 * 60 * 60) {
3971 afsmon_probefreq = DEFAULT_FREQUENCY;
3974 "[ %s ] Invalid probe frequency %s specified, resetting to default value %d seconds\n",
3975 rn, as->parms[P_FREQUENCY].items->data, afsmon_probefreq);
3979 "Invalid probe frequency %s specified, resetting to default value %d seconds\n",
3980 as->parms[P_FREQUENCY].items->data, afsmon_probefreq);
3985 /* make sure output file is writable, else complain now */
3986 /* we will open and close it as needed after probes */
3988 if (as->parms[P_OUTPUT].items != 0) {
3989 afsmon_output = 1; /* output flag */
3990 strncpy(output_filename, as->parms[P_OUTPUT].items->data, 80);
3991 outputFD = fopen(output_filename, "a");
3992 if (outputFD == (FILE *) 0) {
3993 fprintf(stderr, "Failed to open output file %s \n",
3996 fprintf(debugFD, "[ %s ] Failed to open output file %s \n",
3997 rn, output_filename);
4002 fprintf(debugFD, "[ %s ] output file is %s\n", rn,
4008 /* detailed statistics to storage file */
4009 if (as->parms[P_DETAILED].items != 0) {
4010 if (as->parms[P_OUTPUT].items == 0) {
4012 "-detailed switch can be used only with -output\n");
4015 afsmon_detOutput = 1;
4018 /* Initialize host list headers */
4019 FSnameList = (struct afsmon_hostEntry *)0;
4020 CMnameList = (struct afsmon_hostEntry *)0;
4022 /* The -config option is mutually exclusive with the -fshosts,-cmhosts
4025 if (as->parms[P_CONFIG].items) {
4026 if (as->parms[P_FSHOSTS].items || as->parms[P_CMHOSTS].items) {
4028 "Cannot use -config option with -fshosts or -cmhosts\n");
4032 if (!as->parms[P_FSHOSTS].items && !as->parms[P_CMHOSTS].items) {
4034 "Must specify either -config or (-fshosts and/or -cmhosts) options \n");
4040 /* If a file server host is specified on the command line we reuse
4041 * parse_hostEntry() function . Just the pass the info as if it were
4042 * read off the config file */
4044 if (as->parms[P_FSHOSTS].items) {
4045 hostPtr = as->parms[P_FSHOSTS].items;
4046 while (hostPtr != (struct cmd_item *)0) {
4047 sprintf(buf, "fs %s", hostPtr->data);
4048 code = parse_hostEntry(buf);
4050 fprintf(stderr, "Could not parse %s\n", hostPtr->data);
4054 hostPtr = hostPtr->next;
4058 /* same as above for -cmhosts */
4059 if (as->parms[P_CMHOSTS].items) {
4060 hostPtr = as->parms[P_CMHOSTS].items;
4061 while (hostPtr != (struct cmd_item *)0) {
4062 sprintf(buf, "cm %s", hostPtr->data);
4063 code = parse_hostEntry(buf);
4065 fprintf(stderr, "Could not parse %s\n", hostPtr->data);
4069 hostPtr = hostPtr->next;
4073 /* number of slots in circular buffers */
4074 if (as->parms[P_BUFFERS].items)
4075 num_bufSlots = atoi(as->parms[P_BUFFERS].items->data);
4077 num_bufSlots = DEFAULT_BUFSLOTS;
4079 /* Initialize xx_showFlags[]. This array is used solely for processing the
4080 * "show" directives in the config file in parse_showEntries() */
4081 for (i = 0; i < NUM_FS_STAT_ENTRIES; i++)
4082 fs_showFlags[i] = 0;
4083 for (i = 0; i < NUM_CM_STAT_ENTRIES; i++)
4084 cm_showFlags[i] = 0;
4087 /* Process the configuration file if given. This initializes among other
4088 * things, the list of FS & CM names in FSnameList and CMnameList */
4090 if (as->parms[P_CONFIG].items)
4091 process_config_file(as->parms[P_CONFIG].items->data);
4093 /* print out the FS and CM lists */
4097 /* Initialize the FS results-to-screen map array if there were no "show fs"
4098 * directives in the config file */
4099 if (fs_showDefault) {
4100 for (i = 0; i < NUM_FS_STAT_ENTRIES; i++)
4101 fs_Display_map[i] = i;
4102 fs_DisplayItems_count = NUM_FS_STAT_ENTRIES;
4105 /* Initialize the CM results-to-screen map array if there were no "show cm"
4106 * directives in the config file */
4107 if (cm_showDefault) {
4108 for (i = 0; i < NUM_CM_STAT_ENTRIES; i++)
4109 cm_Display_map[i] = i;
4110 cm_DisplayItems_count = NUM_CM_STAT_ENTRIES;
4115 /* setup an interrupt signal handler; we ain't wanna leak core */
4116 /* this binding is useful only until gtx is initialized after which the
4117 * keyboard input server takes over. */
4118 if ((signal(SIGINT, quit_signal)) == SIG_ERR) {
4119 perror("signal() failed.");
4124 /* init error message buffers. these will be used to print error messages
4125 * once gtx is initialized and there is no access to stderr/stdout */
4131 /* initialize fs and cm circular buffers before initiating probes */
4133 code = init_fs_buffers();
4135 fprintf(stderr, "[ %s ] init_fs_buffers returned %d\n", rn,
4142 code = init_cm_buffers();
4144 fprintf(stderr, "[ %s ] init_cm_buffers returned %d\n", rn,
4151 /* allocate and initialize buffers for holding fs & cm results in ascii
4152 * format suitable for updating the screen */
4153 code = init_print_buffers();
4155 fprintf(stderr, "[ %s ] init_print_buffers returned %d\n", rn, code);
4159 /* perform gtx initializations */
4160 code = gtx_initialize();
4162 fprintf(stderr, "[ %s ] gtx_initialize returned %d\n", rn, code);
4166 /* start xstat probes */
4169 return (0); /* will not return from the call to afsmon_execute() */
4171 } /* afsmonInit() */
4174 /*-----------------------------------------------------------------------
4176 ------------------------------------------------------------------------*/
4178 #include "AFS_component_version_number.c"
4181 main(int argc, char **argv)
4183 afs_int32 code; /*Return code */
4184 struct cmd_syndesc *ts; /*Ptr to cmd line syntax descriptor */
4186 #ifdef AFS_AIX32_ENV
4188 * The following signal action for AIX is necessary so that in case of a
4189 * crash (i.e. core is generated) we can include the user's data section
4190 * in the core dump. Unfortunately, by default, only a partial core is
4191 * generated which, in many cases, isn't too useful.
4193 struct sigaction nsa;
4195 sigemptyset(&nsa.sa_mask);
4196 nsa.sa_handler = SIG_DFL;
4197 nsa.sa_flags = SA_FULLDUMP;
4198 sigaction(SIGSEGV, &nsa, NULL);
4202 * Set up the commands we understand.
4204 ts = cmd_CreateSyntax("initcmd", afsmonInit, NULL, 0, "initialize the program");
4205 cmd_AddParm(ts, "-config", CMD_SINGLE, CMD_OPTIONAL,
4206 "configuration file");
4207 cmd_AddParm(ts, "-frequency", CMD_SINGLE, CMD_OPTIONAL,
4208 "poll frequency, in seconds");
4209 cmd_AddParm(ts, "-output", CMD_SINGLE, CMD_OPTIONAL, "storage file name");
4210 cmd_AddParm(ts, "-detailed", CMD_FLAG, CMD_OPTIONAL,
4211 "output detailed statistics to storage file");
4212 cmd_AddParm(ts, "-debug", CMD_SINGLE, CMD_OPTIONAL,
4213 "turn debugging output on to the named file");
4214 cmd_AddParm(ts, "-fshosts", CMD_LIST, CMD_OPTIONAL,
4215 "list of file servers to monitor");
4216 cmd_AddParm(ts, "-cmhosts", CMD_LIST, CMD_OPTIONAL,
4217 "list of cache managers to monitor");
4218 cmd_AddParm(ts, "-buffers", CMD_SINGLE, CMD_OPTIONAL,
4219 "number of buffer slots");
4222 * Parse command-line switches & execute afsmonitor
4225 code = cmd_Dispatch(argc, argv);
4231 exit(0); /* redundant, but gets rid of warning */