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>
31 #include <sys/types.h>
32 #include <netinet/in.h>
33 #include <sys/socket.h>
37 #include <gtxwindows.h> /*Generic window package */
38 #include <gtxobjects.h> /*Object definitions */
39 #include <gtxlightobj.h> /*Light object interface */
40 #include <gtxcurseswin.h> /*Curses window package */
41 #include <gtxdumbwin.h> /*Dumb terminal window package */
42 #include <gtxX11win.h> /*X11 window package */
43 #include <gtxframe.h> /*Frame package */
47 #include <afs/xstat_fs.h>
48 #include <afs/xstat_cm.h>
51 #include "afsmonitor.h"
54 /* command line parameter indices */
60 /* #define P_PACKAGE X */
67 int afsmon_debug = 0; /* debug info to file ? */
68 FILE *debugFD; /* debugging file descriptor */
69 static int afsmon_output = 0; /* output to file ? */
70 static int afsmon_detOutput = 0; /* detailed output ? */
71 static int afsmon_onceOnly = 0; /* probe once only ? (not implemented) */
72 int afsmon_probefreq; /* probe frequency */
73 static int wpkg_to_use; /* graphics package to use */
74 static char output_filename[80]; /* output filename */
75 char errMsg[256]; /* buffers used to print error messages after */
76 char errMsg1[256]; /* gtx is initialized (stderr/stdout gone !) */
77 int num_bufSlots = 0; /* number of slots in fs & cm circular buffers */
79 /* Flags used to process "show" directives in config file */
80 short fs_showFlags[NUM_FS_STAT_ENTRIES];
81 short cm_showFlags[NUM_CM_STAT_ENTRIES];
84 /* afsmonitor misc definitions */
86 #define DEFAULT_FREQUENCY 60 /* default proble frequency in seconds */
87 #define DEFAULT_BUFSLOTS 0 /* default number of buffer slots */
88 #define CFG_STR_LEN 80 /* max length of config file fields */
89 #define FS 1 /* for misc. use */
90 #define CM 2 /* for misc. use */
93 #define NUM_XSTAT_FS_AFS_PERFSTATS_LONGS 66 /* number of fields (longs) in struct afs_PerfStats that we display */
94 #define NUM_AFS_STATS_CMPERF_LONGS 40 /* number of longs in struct afs_stats_CMPerf excluding up/down stats and fields we dont display */
97 /* variables used for exec'ing user provided threshold handlers */
98 char *fsHandler_argv[20]; /* *argv[] for the handler */
99 char fsHandler_args[20][256]; /* buffer space for arguments */
100 int exec_fsThreshHandler = 0; /* execute fs threshold handler ? */
103 /* THRESHOLD STRUCTURE DEFINITIONS */
105 /* flag to indicate that threshold entries apply to all hosts. these will
106 be turned off when the first fs or cm host entry is processed */
107 static int global_ThreshFlag = 1;
108 static int global_fsThreshCount = 0; /* number of global fs thresholds */
109 static int global_cmThreshCount = 0; /* number of global cm thresholds */
113 /* Linked lists of file server and cache manager host names are made from
114 the entries in the config file. Head pointers to FS and CM server name lists. */
115 static struct afsmon_hostEntry *FSnameList;
116 static struct afsmon_hostEntry *CMnameList;
118 /* number of fileservers and cache managers to monitor */
122 /* variables used for processing config file */
123 /* ptr to the hostEntry structure of the last "fs" or "cm" entry processed
124 in the config file */
125 static struct afsmon_hostEntry *last_hostEntry;
126 /* names of the last host processed in the config file */
127 static char last_fsHost[HOST_NAME_LEN];
128 static char last_cmHost[HOST_NAME_LEN];
129 static lastHostType = 0; /* 0 = no host entries processed
130 * 1 = last host was file server
131 * 2 = last host was cache manager. */
134 /* FILE SERVER CIRCULAR BUFFER VARIABLES */
136 struct afsmon_fs_Results_list {
137 struct xstat_fs_ProbeResults *fsResults; /* ptr to results struct */
138 int empty; /* fsResults empty ? */
139 struct afsmon_fs_Results_list *next;
142 struct afsmon_fs_Results_CBuffer {
143 int probeNum; /* probe number of entries in this slot */
144 struct afsmon_fs_Results_list *list; /* ptr to list of results */
147 /* buffer for FS probe results */
148 struct afsmon_fs_Results_CBuffer *afsmon_fs_ResultsCB;
150 int afsmon_fs_curr_CBindex = 0; /* current fs CB slot */
152 /* Probe number variables. The current probe number is incremented
153 when the first probe from a new probe cycle is received. The prev probe
154 number is incremented when the last probe of the current cycle is
155 received. This difference is because of the purpose for which these
158 int afsmon_fs_curr_probeNum = 1; /* current fs probe number */
159 int afsmon_fs_prev_probeNum = 0; /* previous fs probe number */
162 /* CACHE MANAGER CIRCULAR BUFFER VARIABLES */
164 struct afsmon_cm_Results_list {
165 struct xstat_cm_ProbeResults *cmResults; /* ptr to results struct */
166 int empty; /* cmResults empty ? */
167 struct afsmon_cm_Results_list *next;
170 struct afsmon_cm_Results_CBuffer {
171 int probeNum; /* probe number of entries in this slot */
172 struct afsmon_cm_Results_list *list; /* ptr to list of results */
175 /* buffer for CM probe results */
176 struct afsmon_cm_Results_CBuffer *afsmon_cm_ResultsCB;
178 int afsmon_cm_curr_CBindex = 0; /* current cm CB slot */
181 /* Probe number variables. The current probe number is incremented
182 when the first probe from a new probe cycle is received. The prev probe
183 number is incremented when the last probe of the current cycle is
184 received. This difference is because of the purpose for which these
187 int afsmon_cm_curr_probeNum = 1; /* current cm probe number */
188 int afsmon_cm_prev_probeNum = 0; /* previous cm probe number */
191 /* Structures to hold FS & CM results in string format(suitable for display ) */
193 /* ptr to array holding the results of FS probes in ascii format */
194 /* for current probe cycle */
195 struct fs_Display_Data *curr_fsData = (struct fs_Display_Data *)0;
196 /* for previous probe cycle */
197 struct fs_Display_Data *prev_fsData = (struct fs_Display_Data *)0;
200 /* ptr to array holding the results of CM probes in ascii format */
201 /* for current probe cycle */
202 struct cm_Display_Data *curr_cmData = (struct cm_Display_Data *)0;
203 /* for previous probe cycle */
204 struct cm_Display_Data *prev_cmData = (struct cm_Display_Data *)0;
207 /* EXTERN DEFINITIONS */
209 extern struct hostent *hostutil_GetHostByName();
213 /* routines from afsmon-output.c */
214 extern int afsmon_fsOutput();
215 extern int afsmon_cmOutput();
217 /* file server and cache manager variable names (from afsmon_labels.h) */
218 extern char *fs_varNames[];
219 extern char *cm_varNames[];
221 /* GTX & MISC VARIABLES */
223 /* afsmonitor window */
224 extern struct gwin *afsmon_win;
226 /* current page number in the overview frame */
227 extern int ovw_currPage;
229 /* number of FS alerts and number of hosts on FS alerts */
231 int numHosts_onfs_alerts;
233 /* number of CM alerts and number of hosts on FS alerts */
235 int numHosts_oncm_alerts;
237 /* flag to indicate that atleast one probe cycle has completed and
238 data is available for updating the display */
239 extern fs_Data_Available;
240 extern cm_Data_Available;
242 extern int gtx_initialized; /* gtx initialized ? */
244 /* This array contains the indices of the file server data items that
245 are to be displayed on the File Servers screen. For example, suppose the
246 user wishes to display only the vcache statistics then the following array
247 will contain indices 2 to 14 corresponding to the position of the
248 vcache data items in the fs_varNames[] array. If the config file contains
249 no "show fs .." directives, it will contain the indices of all the
250 items in the fs_varNames[] array */
252 short fs_Display_map[XSTAT_FS_FULLPERF_RESULTS_LEN];
253 int fs_DisplayItems_count = 0; /* number of items to display */
254 int fs_showDefault = 1; /* show all of FS data ? */
257 /* same use as above for Cache Managers */
258 short cm_Display_map[XSTAT_CM_FULLPERF_RESULTS_LEN];
259 int cm_DisplayItems_count = 0; /* number of items to display */
260 int cm_showDefault = 1; /* show all of CM data ? */
262 extern int fs_currPage; /* current page number in the File Servers frame */
263 extern int fs_curr_LCol; /* current leftmost column on display on FS frame */
265 extern int cm_currPage; /* current page number in the Cache Managers frame */
266 extern int cm_curr_LCol; /* current leftmost column on display on CM frame */
268 /* File server and Cache manager data is classified into sections &
269 groups to help the user choose what he wants displayed */
270 extern char *fs_categories[]; /* file server data category names */
271 extern char *cm_categories[]; /* cache manager data category names */
275 #ifndef HAVE_STRCASESTR
277 strcasestr(): Return first occurence of pattern s2 in s1, case
280 This routine is required since I made pattern matching of the
281 config file to be case insensitive.
296 return ((char *)NULL);
300 while (len1 >= len2 && len1 > 0) {
301 if ((strncasecmp(ptr, s2, len2)) == 0)
306 return ((char *)NULL);
319 he = gethostbyname(name);
321 /* On solaris the above does not resolve hostnames to full names */
323 memcpy(ip_addr, he->h_addr, he->h_length);
324 he = gethostbyaddr(ip_addr, he->h_length, he->h_addrtype);
331 /*-----------------------------------------------------------------------
335 * Exit gracefully from the afsmonitor. Frees memory where appropriate,
336 * cleans up after gtx and closes all open file descriptors. If a user
337 * provided threshold handler is to be exec'ed then gtx cleanup is
338 * not performed and an exec() is made instead of an exit().
344 * This function is called to execute a user handler only
345 * by a child process.
347 *----------------------------------------------------------------------*/
350 afsmon_Exit(a_exitVal)
351 int a_exitVal; /* exit code */
353 static char rn[] = "afsmon_Exit";
354 struct afsmon_fs_Results_list *tmp_fslist;
355 struct afsmon_fs_Results_list *next_fslist;
356 struct xstat_fs_ProbeResults *tmp_xstat_fsPR;
357 struct afsmon_cm_Results_list *tmp_cmlist;
358 struct afsmon_cm_Results_list *next_cmlist;
359 struct xstat_cm_ProbeResults *tmp_xstat_cmPR;
360 struct afsmon_hostEntry *curr_hostEntry;
361 struct afsmon_hostEntry *prev_hostEntry;
368 fprintf(debugFD, "[ %s ] Called with exit code %d\n", rn, a_exitVal);
372 /* get out of curses first, but not if we are here to exec a threshold
373 * handler. If we do, the screen gets messed up */
374 if (gtx_initialized && !exec_fsThreshHandler)
375 gator_cursesgwin_cleanup(afsmon_win);
377 /* print the error message buffer */
378 if (errMsg[0] != '\0')
379 fprintf(stderr, "%s", errMsg);
380 if (errMsg1[0] != '\0')
381 fprintf(stderr, "%s", errMsg1);
383 /* deallocate file server circular buffers */
384 if (numFS && num_bufSlots) {
386 fprintf(debugFD, "freeing FS circular buffers ");
390 for (bufslot = 0; bufslot < num_bufSlots; bufslot++) {
392 fprintf(debugFD, " %d) ", bufslot);
393 if (afsmon_fs_ResultsCB[bufslot].list !=
394 (struct afsmon_fs_Results_list *)0) {
395 tmp_fslist = afsmon_fs_ResultsCB[bufslot].list;
398 /* make sure we do not go astray */
402 "[ %s ] error in deallocating fs CB\n",
406 next_fslist = tmp_fslist->next;
407 tmp_xstat_fsPR = tmp_fslist->fsResults;
410 fprintf(debugFD, "%d ", numFS - j);
412 /* free xstat_fs_Results data */
413 free(tmp_xstat_fsPR->data.AFS_CollData_val);
414 free(tmp_xstat_fsPR->connP);
415 free(tmp_xstat_fsPR);
417 /* free the fs list item */
419 tmp_fslist = next_fslist;
421 } /* while fs list items in this slot */
422 } /* if entries in this buffer slot */
423 } /* for each fs buffer slot */
425 fprintf(debugFD, "\n");
430 /* deallocate cache manager curcular buffers */
431 if (numCM && num_bufSlots) {
433 fprintf(debugFD, "freeing CM curcular buffers ");
434 for (bufslot = 0; bufslot < num_bufSlots; bufslot++) {
436 fprintf(debugFD, " %d) ", bufslot);
437 if (afsmon_cm_ResultsCB[bufslot].list !=
438 (struct afsmon_cm_Results_list *)0) {
439 tmp_cmlist = afsmon_cm_ResultsCB[bufslot].list;
442 /* make sure we do not go astray */
446 "[ %s ] error in deallocating cm CB\n",
450 next_cmlist = tmp_cmlist->next;
451 tmp_xstat_cmPR = tmp_cmlist->cmResults;
454 fprintf(debugFD, "%d ", numCM - j);
455 /* make sure data is ok */
456 /* Print_cm_FullPerfInfo(tmp_xstat_cmPR); */
458 /* free xstat_cm_Results data */
459 free(tmp_xstat_cmPR->data.AFSCB_CollData_val);
460 free(tmp_xstat_cmPR->connP);
461 free(tmp_xstat_cmPR);
463 /* free the cm list item */
465 tmp_cmlist = next_cmlist;
467 } /* while cm list items in this slot */
468 } /* if entries in this buffer slot */
469 } /* for each cm buffer slot */
471 fprintf(debugFD, "\n");
475 /* deallocate FS & CM Print buffers */
476 if (curr_fsData != (struct fs_Display_Data *)0) {
478 fprintf(debugFD, "Deallocating FS Print Buffers .... curr");
481 if (prev_fsData != (struct fs_Display_Data *)0) {
483 fprintf(debugFD, ", prev \n");
486 if (prev_cmData != (struct cm_Display_Data *)0) {
488 fprintf(debugFD, "Deallocating CM Print Buffers .... curr");
491 if (prev_cmData != (struct cm_Display_Data *)0) {
493 fprintf(debugFD, ", prev \n");
497 /* deallocate hostEntry lists */
500 fprintf(debugFD, "Deallocating FS hostEntries ..");
501 curr_hostEntry = FSnameList;
502 for (i = 0; i < numFS; i++) {
503 prev_hostEntry = curr_hostEntry;
504 if (curr_hostEntry->thresh != NULL)
505 free(curr_hostEntry->thresh);
506 free(curr_hostEntry);
508 fprintf(debugFD, " %d", i);
509 curr_hostEntry = prev_hostEntry->next;
512 fprintf(debugFD, "\n");
516 fprintf(debugFD, "Deallocating CM hostEntries ..");
517 curr_hostEntry = CMnameList;
518 for (i = 0; i < numCM; i++) {
519 prev_hostEntry = curr_hostEntry;
520 if (curr_hostEntry->thresh != NULL)
521 free(curr_hostEntry->thresh);
522 free(curr_hostEntry);
524 fprintf(debugFD, " %d", i);
525 curr_hostEntry = prev_hostEntry->next;
528 fprintf(debugFD, "\n");
531 /* close debug file */
537 if (exec_fsThreshHandler) {
538 code = execvp(fsHandler_argv[0], fsHandler_argv);
540 fprintf(stderr, "execvp() of %s returned %d, errno %d\n",
541 fsHandler_argv[0], code, errno);
549 /*-----------------------------------------------------------------------
553 * Insert a hostname in the file server names list.
558 *----------------------------------------------------------------------*/
561 insert_FS(a_hostName)
562 char *a_hostName; /* name of cache manager to be inserted in list */
564 static char rn[] = "insert_FS"; /* routine name */
565 static struct afsmon_hostEntry *curr_item;
566 static struct afsmon_hostEntry *prev_item;
568 if (*a_hostName == '\0')
570 curr_item = (struct afsmon_hostEntry *)
571 malloc(sizeof(struct afsmon_hostEntry));
572 if (curr_item == (struct afsmon_hostEntry *)0) {
573 fprintf(stderr, "Failed to allocate space for FS nameList\n");
577 strncpy(curr_item->hostName, a_hostName, CFG_STR_LEN);
578 curr_item->next = (struct afsmon_hostEntry *)0;
579 curr_item->numThresh = 0;
580 curr_item->thresh = NULL;
582 if (FSnameList == (struct afsmon_hostEntry *)0)
583 FSnameList = curr_item;
585 prev_item->next = curr_item;
587 prev_item = curr_item;
588 /* record the address of this entry so that its threshold
589 * count can be incremented during the first pass of the config file */
590 last_hostEntry = curr_item;
595 /*-----------------------------------------------------------------------
600 * Prints the file server names linked list.
604 *----------------------------------------------------------------------*/
608 static char rn[] = "print_FS";
609 struct afsmon_hostEntry *tempFS;
610 struct Threshold *threshP;
614 fprintf(debugFD, "[ %s ] Called\n", rn);
620 fprintf(debugFD, "No of File Servers: %d\n", numFS);
623 fprintf(debugFD, "\t %s threshCount = %d\n", tempFS->hostName,
625 threshP = tempFS->thresh;
626 for (i = 0; i < tempFS->numThresh; i++, threshP++)
627 fprintf(debugFD, "\t thresh (%2d) %s %s %s\n",
628 threshP->index, threshP->itemName,
629 threshP->threshVal, threshP->handler);
630 } while ((tempFS = tempFS->next) != (struct afsmon_hostEntry *)0);
632 fprintf(debugFD, "\t\t-----End of List-----\n");
638 /*-----------------------------------------------------------------------
642 * Insert a hostname in the cache manager names list.
647 *----------------------------------------------------------------------*/
650 insert_CM(a_hostName)
651 char *a_hostName; /* name of cache manager to be inserted in list */
653 static char rn[] = "insert_CM"; /* routine name */
654 static struct afsmon_hostEntry *curr_item;
655 static struct afsmon_hostEntry *prev_item;
657 if (*a_hostName == '\0')
659 curr_item = (struct afsmon_hostEntry *)
660 malloc(sizeof(struct afsmon_hostEntry));
661 if (curr_item == (struct afsmon_hostEntry *)0) {
662 fprintf(stderr, "Failed to allocate space for CM nameList\n");
666 strncpy(curr_item->hostName, a_hostName, CFG_STR_LEN);
667 curr_item->next = (struct afsmon_hostEntry *)0;
668 curr_item->numThresh = 0;
669 curr_item->thresh = NULL;
671 if (CMnameList == (struct afsmon_hostEntry *)0)
672 CMnameList = curr_item;
674 prev_item->next = curr_item;
676 prev_item = curr_item;
677 /* side effect. note the address of this entry so that its threshold
678 * count can be incremented during the first pass of the config file */
679 last_hostEntry = curr_item;
685 /*-----------------------------------------------------------------------
690 * Prints the cache manager names linked list.
694 *----------------------------------------------------------------------*/
698 static char rn[] = "print_CM";
699 struct afsmon_hostEntry *tempCM;
700 struct Threshold *threshP;
704 fprintf(debugFD, "[ %s ] Called\n", rn);
710 fprintf(debugFD, "No of Cache Managers: %d\n", numCM);
713 fprintf(debugFD, "\t %s threshCount = %d\n", tempCM->hostName,
715 threshP = tempCM->thresh;
716 for (i = 0; i < tempCM->numThresh; i++, threshP++)
717 fprintf(debugFD, "\t thresh (%2d) %s %s %s\n",
718 threshP->index, threshP->itemName,
719 threshP->threshVal, threshP->handler);
720 } while ((tempCM = tempCM->next) != (struct afsmon_hostEntry *)0);
722 fprintf(debugFD, "\t\t-----End of List-----\n");
729 /*-----------------------------------------------------------------------
733 * Parse the host entry line in the config file. Check the syntax,
734 * and inserts the host name in the FS ot CM linked list. Also
735 * remember if this entry was an fs or cm & the ptr to its hostEntry
736 * structure. The threshold entries in the config file are dependent
737 * on their position relative to the hostname entries. Hence it is
738 * required to remember the names of the last file server and cache
739 * manager entries that were processed.
745 *----------------------------------------------------------------------*/
748 parse_hostEntry(a_line)
750 { /* parse_hostEntry */
752 static char rn[] = "parse_hostEntry"; /* routine name */
753 char opcode[CFG_STR_LEN]; /* specifies type of config entry */
754 char arg1[CFG_STR_LEN]; /* hostname or qualifier (fs/cm?) */
755 char arg2[CFG_STR_LEN]; /* threshold variable */
756 char arg3[CFG_STR_LEN]; /* threshold value */
757 char arg4[CFG_STR_LEN]; /* user's handler */
758 struct hostent *he; /* host entry */
761 fprintf(debugFD, "[ %s ] Called, a_line = %s\n", rn, a_line);
771 sscanf(a_line, "%s %s %s %s %s", opcode, arg1, arg2, arg3, arg4);
772 /* syntax is "opcode hostname" */
773 if ((strlen(arg2)) != 0) {
774 fprintf(stderr, "[ %s ] Extraneous characters at end of line\n", rn);
779 he = GetHostByName(arg1);
781 fprintf(stderr, "[ %s ] Unable to resolve hostname %s\n", rn, arg1);
785 if ((strcasecmp(opcode, "fs")) == 0) {
786 /* use the complete host name to insert in the file server names list */
787 insert_FS(he->h_name);
788 /* note that last host entry in the config file was fs */
791 /* threholds are not global anymore */
792 if (global_ThreshFlag)
793 global_ThreshFlag = 0;
794 } else if ((strcasecmp(opcode, "cm")) == 0) {
795 /* use the complete host name to insert in the CM names list */
796 insert_CM(he->h_name);
797 /* last host entry in the config file was cm */
800 /* threholds are not global anymore */
801 if (global_ThreshFlag)
802 global_ThreshFlag = 0;
809 /*-----------------------------------------------------------------------
810 * parse_threshEntry()
813 * Parse the threshold entry line in the config file. This function is
814 * called in the the first pass of the config file. It checks the syntax
815 * of the config lines and verifies their positional validity - eg.,
816 * a cm threshold cannot appear after a fs hostname entry, etc.
817 * It also counts the thresholds applicable to each host.
823 *----------------------------------------------------------------------*/
826 parse_threshEntry(a_line)
828 { /* parse_threshEntry */
829 static char rn[] = "parse_threshEntry"; /* routine name */
830 char opcode[CFG_STR_LEN]; /* specifies type of config entry */
831 char arg1[CFG_STR_LEN]; /* hostname or qualifier (fs/cm?) */
832 char arg2[CFG_STR_LEN]; /* threshold variable */
833 char arg3[CFG_STR_LEN]; /* threshold value */
834 char arg4[CFG_STR_LEN]; /* user's handler */
835 char arg5[CFG_STR_LEN]; /* junk characters */
838 fprintf(debugFD, "[ %s ] Called, a_line = %s\n", rn, a_line);
849 sscanf(a_line, "%s %s %s %s %s %s", opcode, arg1, arg2, arg3, arg4, arg5);
851 /* syntax is "thresh fs/cm variable_name threshold_value [handler] " */
852 if (((strlen(arg1)) == 0) || ((strlen(arg2)) == 0)
853 || ((strlen(arg3)) == 0)) {
854 fprintf(stderr, "[ %s ] Incomplete line\n", rn);
857 if (strlen(arg3) > THRESH_VAR_LEN - 2) {
858 fprintf(stderr, "[%s ] threshold value too long\n", rn);
862 if ((strcasecmp(arg1, "fs")) == 0) {
863 switch (lastHostType) {
864 case 0: /* its a global threshold */
865 global_fsThreshCount++;
867 case 1: /* inc thresh count of last file server */
868 last_hostEntry->numThresh++;
872 "[ %s ] A threshold for a File Server cannot be placed after a Cache Manager host entry in the config file \n",
876 fprintf(stderr, "[ %s ] Programming error 1\n", rn);
879 } else if ((strcasecmp(arg1, "cm")) == 0) {
880 switch (lastHostType) {
881 case 0: /* its a global threshold */
882 global_cmThreshCount++;
884 case 2: /* inc thresh count of last cache manager */
885 last_hostEntry->numThresh++;
889 "[ %s ] A threshold for a Cache Manager cannot be placed after a File Server host entry in the config file \n",
893 fprintf(stderr, "[ %s ] Programming error 2\n", rn);
898 "[ %s ] Syntax error. Second argument should be \"fs\" or \"cm\" \n",
904 } /* parse_threshEntry */
907 /*-----------------------------------------------------------------------
911 * The thresholds applicable to each host machine are stored in the
912 * FSnameList and CMnameList. Threshold entries in the config file are
913 * context sensitive. The host to which this threshold is applicable
914 * is pointed to by last_fsHost (for file servers) and last_cmHost
915 * for cache managers. For global thresholds the info is recorded for
916 * all the hosts. This function is called in the second pass of the
917 * config file. In the first pass a count of the number of global
918 * thresholds is determined and this information is used in this
919 * routine. If threshold entries are duplicated the first entry is
921 * Each threshold entry also has an index field. This is a positional
922 * index to the corresponding variable in the prev_[fs/cm]Data arrays.
923 * This makes it easy to check the threshold for overflow.
928 *----------------------------------------------------------------------*/
931 store_threshold(a_type, a_varName, a_value, a_handler)
932 int a_type; /* 1 = fs , 2 = cm */
933 char *a_varName; /* threshold name */
934 char *a_value; /* threshold value */
935 char *a_handler; /* threshold overflow handler */
937 { /* store_thresholds */
939 static char rn[] = "store_thresholds"; /* routine name */
940 struct afsmon_hostEntry *tmp_host; /* tmp ptr to hostEntry */
941 struct afsmon_hostEntry *Header; /* tmp ptr to hostEntry list header */
942 struct Threshold *threshP; /* tmp ptr to threshold list */
944 int index; /* index to fs_varNames or cm_varNames */
947 int srvCount; /* tmp count of host names */
948 int *global_TC; /* ptr to global_xxThreshCount */
953 "[ %s ] Called, a_type= %d, a_varName= %s, a_value= %s, a_handler=%s\n",
954 rn, a_type, a_varName, a_value, a_handler);
958 /* resolve the threshold variable name */
960 if (a_type == 1) { /* fs threshold */
961 for (index = 0; index < NUM_FS_STAT_ENTRIES; index++) {
962 if (strcasecmp(a_varName, fs_varNames[index]) == 0) {
968 fprintf(stderr, "[ %s ] Unknown FS threshold variable name %s\n",
974 hostname = last_fsHost;
975 global_TC = &global_fsThreshCount;
976 } else if (a_type == 2) { /* cm threshold */
977 for (index = 0; index < NUM_CM_STAT_ENTRIES; index++) {
978 if (strcasecmp(a_varName, cm_varNames[index]) == 0) {
984 fprintf(stderr, "[ %s ] Unknown CM threshold variable name %s\n",
990 hostname = last_cmHost;
991 global_TC = &global_cmThreshCount;
997 /* if the global thresh count is not zero, place this threshold on
998 * all the host entries */
1002 for (i = 0; i < srvCount; i++) {
1003 threshP = tmp_host->thresh;
1005 for (j = 0; j < tmp_host->numThresh; j++) {
1006 if ((threshP->itemName[0] == '\0')
1007 || (strcasecmp(threshP->itemName, a_varName) == 0)) {
1008 strncpy(threshP->itemName, a_varName,
1009 THRESH_VAR_NAME_LEN);
1010 strncpy(threshP->threshVal, a_value, THRESH_VAR_LEN);
1011 strcpy(threshP->handler, a_handler);
1012 threshP->index = index;
1019 fprintf(stderr, "[ %s ] Could not insert threshold entry",
1021 fprintf(stderr, "for %s in thresh list of host %s \n",
1022 a_varName, tmp_host->hostName);
1025 tmp_host = tmp_host->next;
1031 /* it is not a global threshold, insert it in the thresh list of this
1032 * host only. We overwrite the global threshold if it was alread set */
1034 if (*hostname == '\0') {
1035 fprintf(stderr, "[ %s ] Programming error 3\n", rn);
1039 /* get the hostEntry that this threshold belongs to */
1042 for (i = 0; i < srvCount; i++) {
1043 if (strcasecmp(tmp_host->hostName, hostname) == 0) {
1047 tmp_host = tmp_host->next;
1050 fprintf(stderr, "[ %s ] Unable to find host %s in %s hostEntry list",
1051 rn, hostname, (a_type - 1) ? "CM" : "FS");
1055 /* put this entry on the thresh list of this host, overwrite global value
1058 threshP = tmp_host->thresh;
1060 for (i = 0; i < tmp_host->numThresh; i++) {
1061 if ((threshP->itemName[0] == '\0')
1062 || (strcasecmp(threshP->itemName, a_varName) == 0)) {
1063 strncpy(threshP->itemName, a_varName, THRESH_VAR_NAME_LEN);
1064 strncpy(threshP->threshVal, a_value, THRESH_VAR_LEN);
1065 strcpy(threshP->handler, a_handler);
1066 threshP->index = index;
1075 "[ %s ] Unable to insert threshold %s for %s host %s\n", rn,
1076 a_varName, (a_type - 1) ? "CM" : "FS", tmp_host->hostName);
1082 } /* store_thresholds */
1085 /*-----------------------------------------------------------------------
1089 * This function process a "show" entry in the config file. A "show"
1090 * entry specifies what statistics the user wants to see. File
1091 * server and Cache Manager data is divided into sections. Each section
1092 * is made up of one or more groups. If a group name is specified only
1093 * those statistics under that group are shown. If a section name is
1094 * specified all the groups under this section are shown.
1095 * Data as obtained from the xstat probes is considered to be ordered.
1096 * This data is mapped to the screen thru fs_Display_map[] and
1097 * cm_Display_map[]. This routine parses the "show" entry against the
1098 * section/group names in the [fs/cm]_categories[] array. If there is
1099 * no match it tries to match it against a variable name in
1100 * [fs/cm]_varNames[] array. In each case the corresponding indices to
1101 * the data is the [fs/cm]_displayInfo[] is recorded.
1105 * Failure: -1 (invalid entry)
1106 * > -1 (programming error)
1107 *----------------------------------------------------------------------*/
1110 parse_showEntry(a_line)
1112 { /* parse_showEntry */
1113 static char rn[] = "parse_showEntry";
1114 char opcode[CFG_STR_LEN]; /* specifies type of config entry */
1115 char arg1[CFG_STR_LEN]; /* show fs or cm entry ? */
1116 char arg2[CFG_STR_LEN]; /* what we gotta show */
1117 char arg3[CFG_STR_LEN]; /* junk */
1118 char catName[CFG_STR_LEN]; /* for category names */
1119 int numGroups; /* number of groups in a section */
1123 int idx = 0; /* index to fs_categories[] */
1129 fprintf(debugFD, "[ %s ] Called, a_line= %s\n", rn, a_line);
1136 sscanf(a_line, "%s %s %s %s", opcode, arg1, arg2, arg3);
1138 if (arg3[0] != '\0') {
1139 fprintf(stderr, "[ %s ] Extraneous characters at end of line\n", rn);
1143 if ((strcasecmp(arg1, "fs") != 0) && (strcasecmp(arg1, "cm") != 0)) {
1145 "[ %s ] Second argument of \"show\" directive should be \"fs\" or \"cm\" \n",
1150 /* Each entry can either be a variable name or a section/group name. Variable
1151 * names are listed in xx_varNames[] and section/group names in xx_categories[].
1152 * The section/group names in xx_categiries[] also give the starting/ending
1153 * indices of the variables belonging to that section/group. These indices
1154 * are stored in order in xx_Display_map[] and displayed to the screen in that
1157 /* To handle duplicate "show" entries we keep track of what what we have
1158 * already marked to show in the xx_showFlags[] */
1160 if (strcasecmp(arg1, "fs") == 0) { /* its a File Server entry */
1162 /* mark that we have to show only what the user wants */
1165 /* if it is a section/group name, find it in the fs_categories[] array */
1168 if (strcasestr(arg2, "_section") != (char *)NULL
1169 || strcasestr(arg2, "_group") != (char *)NULL) {
1171 while (idx < FS_NUM_DATA_CATEGORIES) {
1172 sscanf(fs_categories[idx], "%s %d %d", catName, &fromIdx,
1175 if (strcasecmp(arg2, catName) == 0) {
1181 if (!found) { /* typo in section/group name */
1183 "[ %s ] Could not find section/group name %s\n", rn,
1189 /* if it is a group name, read its start/end indices and fill in the
1190 * fs_Display_map[]. */
1192 if (strcasestr(arg2, "_group") != (char *)NULL) {
1194 if (fromIdx < 0 || toIdx < 0 || fromIdx > NUM_FS_STAT_ENTRIES
1195 || toIdx > NUM_FS_STAT_ENTRIES)
1197 for (j = fromIdx; j <= toIdx; j++) {
1198 if (!fs_showFlags[j]) {
1199 fs_Display_map[fs_DisplayItems_count] = j;
1200 fs_DisplayItems_count++;
1201 fs_showFlags[j] = 1;
1203 if (fs_DisplayItems_count > NUM_FS_STAT_ENTRIES) {
1204 fprintf(stderr, "[ %s ] fs_DisplayItems_count ovf\n", rn);
1209 /* if it is a section name, get the count of number of groups in it and
1210 * for each group fill in the start/end indices in the fs_Display_map[] */
1212 if (strcasestr(arg2, "_section") != (char *)NULL) {
1213 /* fromIdx is actually the number of groups in thi section */
1214 numGroups = fromIdx;
1215 /* for each group in section */
1216 while (idx < FS_NUM_DATA_CATEGORIES && numGroups) {
1217 sscanf(fs_categories[idx], "%s %d %d", catName, &fromIdx,
1220 if (strcasestr(catName, "_group") != NULL) {
1221 if (fromIdx < 0 || toIdx < 0
1222 || fromIdx > NUM_FS_STAT_ENTRIES
1223 || toIdx > NUM_FS_STAT_ENTRIES)
1225 for (j = fromIdx; j <= toIdx; j++) {
1226 if (!fs_showFlags[j]) {
1227 fs_Display_map[fs_DisplayItems_count] = j;
1228 fs_DisplayItems_count++;
1229 fs_showFlags[j] = 1;
1231 if (fs_DisplayItems_count > NUM_FS_STAT_ENTRIES) {
1233 "[ %s ] fs_DisplayItems_count ovf\n", rn);
1238 fprintf(stderr, "[ %s ] Error parsing groups for %s\n",
1244 } /* for each group in section */
1247 } else { /* it is a variable name */
1249 for (i = 0; i < NUM_FS_STAT_ENTRIES; i++) {
1250 if (strcasecmp(arg2, fs_varNames[i]) == 0) {
1251 if (!fs_showFlags[i]) {
1252 fs_Display_map[fs_DisplayItems_count] = i;
1253 fs_DisplayItems_count++;
1254 fs_showFlags[i] = 1;
1256 if (fs_DisplayItems_count >= NUM_FS_STAT_ENTRIES) {
1257 fprintf(stderr, "[ %s ] fs_DisplayItems_count ovf\n",
1264 if (!found) { /* typo in section/group name */
1265 fprintf(stderr, "[ %s ] Could not find variable name %s\n",
1269 } /* its a variable name */
1273 /* it is an fs entry */
1274 if (strcasecmp(arg1, "cm") == 0) { /* its a Cache Manager entry */
1277 /* mark that we have to show only what the user wants */
1280 /* if it is a section/group name, find it in the cm_categories[] array */
1283 if (strcasestr(arg2, "_section") != (char *)NULL
1284 || strcasestr(arg2, "_group") != (char *)NULL) {
1286 while (idx < CM_NUM_DATA_CATEGORIES) {
1287 sscanf(cm_categories[idx], "%s %d %d", catName, &fromIdx,
1290 if (strcasecmp(arg2, catName) == 0) {
1296 if (!found) { /* typo in section/group name */
1298 "[ %s ] Could not find section/group name %s\n", rn,
1304 /* if it is a group name, read its start/end indices and fill in the
1305 * cm_Display_map[]. */
1307 if (strcasestr(arg2, "_group") != (char *)NULL) {
1309 if (fromIdx < 0 || toIdx < 0 || fromIdx > NUM_CM_STAT_ENTRIES
1310 || toIdx > NUM_CM_STAT_ENTRIES)
1312 for (j = fromIdx; j <= toIdx; j++) {
1313 if (!cm_showFlags[j]) {
1314 cm_Display_map[cm_DisplayItems_count] = j;
1315 cm_DisplayItems_count++;
1316 cm_showFlags[j] = 1;
1318 if (cm_DisplayItems_count > NUM_CM_STAT_ENTRIES) {
1319 fprintf(stderr, "[ %s ] cm_DisplayItems_count ovf\n", rn);
1324 /* if it is a section name, get the count of number of groups in it and
1325 * for each group fill in the start/end indices in the cm_Display_map[] */
1327 if (strcasestr(arg2, "_section") != (char *)NULL) {
1328 /* fromIdx is actually the number of groups in thi section */
1329 numGroups = fromIdx;
1330 /* for each group in section */
1331 while (idx < CM_NUM_DATA_CATEGORIES && numGroups) {
1332 sscanf(cm_categories[idx], "%s %d %d", catName, &fromIdx,
1335 if (strcasestr(catName, "_group") != NULL) {
1336 if (fromIdx < 0 || toIdx < 0
1337 || fromIdx > NUM_CM_STAT_ENTRIES
1338 || toIdx > NUM_CM_STAT_ENTRIES)
1340 for (j = fromIdx; j <= toIdx; j++) {
1341 if (!cm_showFlags[j]) {
1342 cm_Display_map[cm_DisplayItems_count] = j;
1343 cm_DisplayItems_count++;
1344 cm_showFlags[j] = 1;
1346 if (cm_DisplayItems_count > NUM_CM_STAT_ENTRIES) {
1348 "[ %s ] cm_DisplayItems_count ovf\n", rn);
1353 fprintf(stderr, "[ %s ] Error parsing groups for %s\n",
1359 } /* for each group in section */
1366 } else { /* it is a variable name */
1368 for (i = 0; i < NUM_CM_STAT_ENTRIES; i++) {
1369 if (strcasecmp(arg2, cm_varNames[i]) == 0) {
1370 if (!cm_showFlags[i]) {
1371 cm_Display_map[cm_DisplayItems_count] = i;
1372 cm_DisplayItems_count++;
1373 cm_showFlags[i] = 1;
1375 if (cm_DisplayItems_count >= NUM_CM_STAT_ENTRIES) {
1376 fprintf(stderr, "[ %s ] cm_DisplayItems_count ovf\n",
1383 if (!found) { /* typo in section/group name */
1384 fprintf(stderr, "[ %s ] Could not find variable name %s\n",
1388 } /* its a variable name */
1391 /* it is an cm entry */
1395 } /* parse_showEntry */
1398 /*-----------------------------------------------------------------------
1399 * process_config_file()
1402 * Parse config file entries in two passes. In the first pass:
1403 * - the syntax of all the entries is checked
1404 * - host names are noted and the FSnamesList and CMnamesList
1406 * - a count of the global thresholds and local thresholds of
1407 * each host are counted.
1408 * - "show" entries are processed.
1409 * In the second pass:
1410 * - thresholds are stored
1414 * Failure: Exits afsmonitor showing error and line.
1415 *----------------------------------------------------------------------*/
1418 process_config_file(a_config_filename)
1419 char *a_config_filename;
1420 { /* process_config_file() */
1421 static char rn[] = "process_config_file"; /* routine name */
1422 FILE *configFD; /* config file descriptor */
1423 char line[4 * CFG_STR_LEN]; /* a line of config file */
1424 char opcode[CFG_STR_LEN]; /* specifies type of config entry */
1425 char arg1[CFG_STR_LEN]; /* hostname or qualifier (fs/cm?) */
1426 char arg2[CFG_STR_LEN]; /* threshold variable */
1427 char arg3[CFG_STR_LEN]; /* threshold value */
1428 char arg4[CFG_STR_LEN]; /* user's handler */
1429 struct afsmon_hostEntry *curr_host;
1430 struct hostent *he; /* hostentry to resolve host name */
1431 char *handlerPtr; /* ptr to pass theresh handler string */
1432 int code = 0; /* error code */
1433 int linenum = 0; /* config file line number */
1434 int threshCount; /* count of thresholds for each server */
1435 int error_in_config; /* syntax errors in config file ?? */
1440 fprintf(debugFD, "[ %s ] Called, a_config_filename= %s\n", rn,
1445 /* open config file */
1447 configFD = fopen(a_config_filename, "r");
1448 if (configFD == (FILE *) 0) {
1449 fprintf(stderr, "Failed to open config file %s \n",
1452 fprintf(debugFD, "[ %s ] Failed to open config file %s \n", rn,
1459 /* parse config file */
1461 /* We process the config file in two passes. In the first pass we check
1462 * for correct syntax and for valid entries and also keep count of the
1463 * number of servers and thresholds to monitor. This the data strctures
1464 * can be arrays instead of link lists since we would know their sizes. */
1471 error_in_config = 0; /* flag to note if config file has syntax errors */
1473 while ((fgets(line, CFG_STR_LEN, configFD)) != NULL) {
1479 sscanf(line, "%s %s %s %s %s", opcode, arg1, arg2, arg3, arg4);
1481 /* skip blank lines and comment lines */
1482 if ((strlen(opcode) == 0) || line[0] == '#')
1485 if ((strcasecmp(opcode, "fs") == 0)
1486 || (strcasecmp(opcode, "cm")) == 0) {
1487 code = parse_hostEntry(line);
1488 } else if ((strcasecmp(opcode, "thresh")) == 0) {
1489 code = parse_threshEntry(line);
1490 } else if ((strcasecmp(opcode, "show")) == 0) {
1491 code = parse_showEntry(line);
1493 fprintf(stderr, "[ %s ] Unknown opcode %s\n", rn, opcode);
1498 fprintf(stderr, "[ %s ] Error in line:\n %d: %s\n", rn, linenum,
1500 error_in_config = 1;
1504 if (error_in_config)
1508 fprintf(debugFD, "Global FS thresholds count = %d\n",
1509 global_fsThreshCount);
1510 fprintf(debugFD, "Global CM thresholds count = %d\n",
1511 global_cmThreshCount);
1515 /* the threshold count of all hosts in increased by 1 for each global
1516 * threshold. If one of the hosts has a local threshold for the same
1517 * variable it would end up being counted twice. whats a few bytes of memory
1518 * wasted anyway ? */
1520 if (global_fsThreshCount) {
1521 curr_host = FSnameList;
1522 for (i = 0; i < numFS; i++) {
1523 curr_host->numThresh += global_fsThreshCount;
1524 curr_host = curr_host->next;
1527 if (global_cmThreshCount) {
1528 curr_host = CMnameList;
1529 for (i = 0; i < numCM; i++) {
1530 curr_host->numThresh += global_cmThreshCount;
1531 curr_host = curr_host->next;
1536 /* make sure we have something to monitor */
1537 if (numFS == 0 && numCM == 0) {
1539 "\nConfig file must specify atleast one File Server or Cache Manager host to monitor.\n");
1546 fseek(configFD, 0, 0); /* seek to the beginning */
1549 /* allocate memory for threshold lists */
1550 curr_host = FSnameList;
1551 for (i = 0; i < numFS; i++) {
1552 if (curr_host->hostName[0] == '\0') {
1553 fprintf(stderr, "[ %s ] Programming error 4\n", rn);
1556 if (curr_host->numThresh) {
1557 numBytes = curr_host->numThresh * sizeof(struct Threshold);
1558 curr_host->thresh = (struct Threshold *)malloc(numBytes);
1559 if (curr_host->thresh == NULL) {
1560 fprintf(stderr, "[ %s ] Memory Allocation error 1", rn);
1563 memset(curr_host->thresh, 0, numBytes);
1565 curr_host = curr_host->next;;
1568 curr_host = CMnameList;
1569 for (i = 0; i < numCM; i++) {
1570 if (curr_host->hostName[0] == '\0') {
1571 fprintf(stderr, "[ %s ] Programming error 5\n", rn);
1574 if (curr_host->numThresh) {
1575 numBytes = curr_host->numThresh * sizeof(struct Threshold);
1576 curr_host->thresh = (struct Threshold *)malloc(numBytes);
1577 if (curr_host->thresh == NULL) {
1578 fprintf(stderr, "[ %s ] Memory Allocation error 2", rn);
1581 memset(curr_host->thresh, 0, numBytes);
1583 curr_host = curr_host->next;;
1592 last_fsHost[0] = '\0';
1593 last_cmHost[0] = '\0';
1595 while ((fgets(line, CFG_STR_LEN, configFD)) != NULL) {
1601 sscanf(line, "%s %s %s %s %s", opcode, arg1, arg2, arg3, arg4);
1604 /* if we have a host entry, remember the host name */
1605 if (strcasecmp(opcode, "fs") == 0) {
1606 he = GetHostByName(arg1);
1607 strncpy(last_fsHost, he->h_name, HOST_NAME_LEN);
1608 } else if (strcasecmp(opcode, "cm") == 0) {
1609 he = GetHostByName(arg1);
1610 strncpy(last_cmHost, he->h_name, HOST_NAME_LEN);
1611 } else if (strcasecmp(opcode, "thresh") == 0) {
1612 /* if we have a threshold handler it may have arguments
1613 * and the sscanf() above would not get them, so do the
1617 /* now skip over 4 words - this is done by first
1618 * skipping leading blanks then skipping a word */
1619 for (i = 0; i < 4; i++) {
1620 while (isspace(*handlerPtr))
1622 while (!isspace(*handlerPtr))
1625 while (isspace(*handlerPtr))
1627 /* we how have a pointer to the start of the handler
1630 handlerPtr = arg4; /* empty string */
1633 if (strcasecmp(arg1, "fs") == 0)
1634 code = store_threshold(1, /* 1 = fs */
1635 arg2, arg3, handlerPtr);
1637 else if (strcasecmp(arg1, "cm") == 0)
1638 code = store_threshold(2, /* 2 = fs */
1639 arg2, arg3, handlerPtr);
1642 fprintf(stderr, "[ %s ] Programming error 6\n", rn);
1646 fprintf(stderr, "[ %s ] Failed to store threshold\n", rn);
1647 fprintf(stderr, "[ %s ] Error processing line:\n%d: %s", rn,
1659 /*-----------------------------------------------------------------------
1664 * Print the File Server circular buffer.
1668 *----------------------------------------------------------------------*/
1672 { /* Print_FS_CB() */
1674 struct afsmon_fs_Results_list *fslist;
1678 /* print valid info in the fs CB */
1682 "==================== FS Buffer ========================\n");
1683 fprintf(debugFD, "afsmon_fs_curr_CBindex = %d\n",
1684 afsmon_fs_curr_CBindex);
1685 fprintf(debugFD, "afsmon_fs_curr_probeNum = %d\n\n",
1686 afsmon_fs_curr_probeNum);
1688 for (i = 0; i < num_bufSlots; i++) {
1689 fprintf(debugFD, "\t--------- slot %d ----------\n", i);
1690 fslist = afsmon_fs_ResultsCB[i].list;
1693 if (!fslist->empty) {
1694 fprintf(debugFD, "\t %d) probeNum = %d host = %s", j,
1695 fslist->fsResults->probeNum,
1696 fslist->fsResults->connP->hostName);
1697 if (fslist->fsResults->probeOK)
1698 fprintf(debugFD, " NOTOK\n");
1700 fprintf(debugFD, " OK\n");
1702 fprintf(debugFD, "\t %d) -- empty --\n", j);
1703 fslist = fslist->next;
1706 if (fslist != (struct afsmon_fs_Results_list *)0)
1707 fprintf(debugFD, "dangling last next ptr fs CB\n");
1710 } /* Print_FS_CB() */
1712 /*-----------------------------------------------------------------------
1713 * save_FS_results_inCB()
1716 * Saves the results of the latest FS probe in the fs circular
1717 * buffers. If the current probe cycle is in progress the contents
1718 * of xstat_fs_Results are copied to the end of the list of results
1719 * in the current slot (pointed to by afsmon_fs_curr_CBindex). If
1720 * a new probe cycle has started the next slot in the circular buffer
1721 * is initialized and the results copied. Note that the Rx related
1722 * information available in xstat_fs_Results is not copied.
1726 * Failure: Exits afsmonitor.
1727 *----------------------------------------------------------------------*/
1729 save_FS_results_inCB(a_newProbeCycle)
1730 int a_newProbeCycle; /* start of a new probe cycle ? */
1732 { /* save_FS_results_inCB() */
1733 static char rn[] = "save_FS_results_inCB"; /* routine name */
1734 struct afsmon_fs_Results_list *tmp_fslist_item; /* temp fs list item */
1735 struct xstat_fs_ProbeResults *tmp_fsPR; /* temp ptr */
1739 fprintf(debugFD, "[ %s ] Called, a_newProbeCycle= %d\n", rn,
1745 /* If a new probe cycle started, mark the list in the current buffer
1746 * slot empty for resuse. Note that afsmon_fs_curr_CBindex was appropriately
1747 * incremented in afsmon_FS_Handler() */
1749 if (a_newProbeCycle) {
1750 tmp_fslist_item = afsmon_fs_ResultsCB[afsmon_fs_curr_CBindex].list;
1751 for (i = 0; i < numFS; i++) {
1752 tmp_fslist_item->empty = 1;
1753 tmp_fslist_item = tmp_fslist_item->next;
1757 /* locate last unused item in list */
1758 tmp_fslist_item = afsmon_fs_ResultsCB[afsmon_fs_curr_CBindex].list;
1759 for (i = 0; i < numFS; i++) {
1760 if (tmp_fslist_item->empty)
1762 tmp_fslist_item = tmp_fslist_item->next;
1765 /* if we could not find one we have an inconsistent list */
1766 if (!tmp_fslist_item->empty) {
1768 "[ %s ] list inconsistency 1. unable to find an empty slot to store results of probenum %d of %s\n",
1769 rn, xstat_fs_Results.probeNum,
1770 xstat_fs_Results.connP->hostName);
1774 tmp_fsPR = tmp_fslist_item->fsResults;
1776 /* copy hostname and probe number and probe time and probe status.
1777 * if the probe failed return now */
1779 memcpy(tmp_fsPR->connP->hostName, xstat_fs_Results.connP->hostName,
1780 sizeof(xstat_fs_Results.connP->hostName));
1781 tmp_fsPR->probeNum = xstat_fs_Results.probeNum;
1782 tmp_fsPR->probeTime = xstat_fs_Results.probeTime;
1783 tmp_fsPR->probeOK = xstat_fs_Results.probeOK;
1784 if (xstat_fs_Results.probeOK) { /* probeOK = 1 => notOK */
1785 /* we have a nonempty results structure so mark the list item used */
1786 tmp_fslist_item->empty = 0;
1790 /* copy connection information */
1791 memcpy(&(tmp_fsPR->connP->skt), &(xstat_fs_Results.connP->skt),
1792 sizeof(struct sockaddr_in));
1794 memcpy(tmp_fsPR->connP->hostName, xstat_fs_Results.connP->hostName,
1795 sizeof(xstat_fs_Results.connP->hostName));
1796 tmp_fsPR->collectionNumber = xstat_fs_Results.collectionNumber;
1798 /* copy the probe data information */
1799 tmp_fsPR->data.AFS_CollData_len = xstat_fs_Results.data.AFS_CollData_len;
1800 memcpy(tmp_fsPR->data.AFS_CollData_val,
1801 xstat_fs_Results.data.AFS_CollData_val,
1802 xstat_fs_Results.data.AFS_CollData_len * sizeof(afs_int32));
1805 /* we have a valid results structure so mark the list item used */
1806 tmp_fslist_item->empty = 0;
1808 /* Print the fs circular buffer */
1812 } /* save_FS_results_inCB() */
1815 /*-----------------------------------------------------------------------
1819 * The results of xstat probes are stored in a string format in
1820 * the arrays curr_fsData and prev_fsData. The information stored in
1821 * prev_fsData is copied to the screen.
1822 * This function converts xstat FS results from longs to strings and
1823 * place them in the given buffer (a pointer to an item in curr_fsData).
1824 * When a probe cycle completes, curr_fsData is copied to prev_fsData
1825 * in afsmon_FS_Hnadler().
1829 *----------------------------------------------------------------------*/
1832 fs_Results_ltoa(a_fsData, a_fsResults)
1833 struct fs_Display_Data *a_fsData; /* target buffer */
1834 struct xstat_fs_ProbeResults *a_fsResults; /* ptr to xstat fs Results */
1835 { /* fs_Results_ltoa */
1837 static char rn[] = "fs_Results_ltoa"; /* routine name */
1839 struct fs_stats_FullPerfStats *fullPerfP;
1845 fprintf(debugFD, "[ %s ] Called, a_fsData= %d, a_fsResults= %d\n", rn,
1846 a_fsData, a_fsResults);
1850 fullPerfP = (struct fs_stats_FullPerfStats *)
1851 (a_fsResults->data.AFS_CollData_val);
1853 /* there are two parts to the xstat FS statistics
1854 * - fullPerfP->overall which give the overall performance statistics, and
1855 * - fullPerfP->det which gives detailed info about file server operation
1856 * execution times */
1858 /* copy overall performance statistics */
1859 srcbuf = (afs_int32 *) & (fullPerfP->overall);
1861 for (i = 0; i < NUM_XSTAT_FS_AFS_PERFSTATS_LONGS; i++) {
1862 sprintf(a_fsData->data[idx], "%d", *srcbuf);
1868 srcbuf = (afs_int32 *) & (fullPerfP->det.epoch);
1869 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* epoch */
1872 /* copy fs operation timing */
1874 srcbuf = (afs_int32 *) (fullPerfP->det.rpcOpTimes);
1876 for (i = 0; i < FS_STATS_NUM_RPC_OPS; i++) {
1877 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* numOps */
1880 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* numSuccesses */
1883 tmpbuf = srcbuf++; /* sum time */
1884 sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1887 tmpbuf = srcbuf++; /* sqr time */
1888 sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1891 tmpbuf = srcbuf++; /* min time */
1892 sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1895 tmpbuf = srcbuf++; /* max time */
1896 sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1901 /* copy fs transfer timings */
1903 srcbuf = (afs_int32 *) (fullPerfP->det.xferOpTimes);
1904 for (i = 0; i < FS_STATS_NUM_XFER_OPS; i++) {
1905 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* numOps */
1908 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* numSuccesses */
1911 tmpbuf = srcbuf++; /* sum time */
1912 sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1915 tmpbuf = srcbuf++; /* sqr time */
1916 sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1919 tmpbuf = srcbuf++; /* min time */
1920 sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1923 tmpbuf = srcbuf++; /* max time */
1924 sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1927 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* sum bytes */
1930 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* min bytes */
1933 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* max bytes */
1936 for (j = 0; j < FS_STATS_NUM_XFER_BUCKETS; j++) {
1937 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* bucket[j] */
1944 } /* fs_Results_ltoa */
1948 /*-----------------------------------------------------------------------
1949 * execute_thresh_handler()
1952 * Execute a threshold handler. An agrv[] array of pointers is
1953 * constructed from the given data. A child process is forked
1954 * which immediately calls afsmon_Exit() with indication that a
1955 * threshold handler is to be exec'ed insted of exiting.
1959 * Failure: Afsmonitor exits if threshold handler has more than 20 args.
1960 *----------------------------------------------------------------------*/
1963 execute_thresh_handler(a_handler, a_hostName, a_hostType, a_threshName,
1964 a_threshValue, a_actValue)
1965 char *a_handler; /* ptr to handler function + args */
1966 char *a_hostName; /* host name for which threshold crossed */
1967 int a_hostType; /* fs or cm ? */
1968 char *a_threshName; /* threshold variable name */
1969 char *a_threshValue; /* threshold value */
1970 char *a_actValue; /* actual value */
1972 { /* execute_thresh_handler */
1974 static char rn[] = "execute_thresh_handler";
1975 char fileName[256]; /* file name to execute */
1980 int anotherArg; /* boolean used to flag if another arg is available */
1984 "[ %s ] Called, a_handler= %s, a_hostName= %s, a_hostType= %d, a_threshName= %s, a_threshValue= %s, a_actValue= %s\n",
1985 rn, a_handler, a_hostName, a_hostType, a_threshName,
1986 a_threshValue, a_actValue);
1991 /* get the filename to execute - the first argument */
1992 sscanf(a_handler, "%s", fileName);
1994 /* construct the contents of *argv[] */
1996 strncpy(fsHandler_args[0], fileName, 256);
1997 strncpy(fsHandler_args[1], a_hostName, HOST_NAME_LEN);
1998 if (a_hostType == FS)
1999 strcpy(fsHandler_args[2], "fs");
2001 strcpy(fsHandler_args[2], "cm");
2002 strncpy(fsHandler_args[3], a_threshName, THRESH_VAR_NAME_LEN);
2003 strncpy(fsHandler_args[4], a_threshValue, THRESH_VAR_LEN);
2004 strncpy(fsHandler_args[5], a_actValue, THRESH_VAR_LEN);
2011 /* we have already extracted the file name so skip to the 1st arg */
2012 while (isspace(*ch)) /* leading blanks */
2014 while (!isspace(*ch) && *ch != '\0') /* handler filename */
2017 while (*ch != '\0') {
2020 } else if (anotherArg) {
2022 sscanf(ch, "%s", fsHandler_args[argNum]);
2028 "Threshold handlers cannot have more than 20 arguments\n");
2034 fsHandler_argv[argNum] = NULL;
2035 for (i = 0; i < argNum; i++)
2036 fsHandler_argv[i] = fsHandler_args[i];
2039 /* exec the threshold handler */
2042 exec_fsThreshHandler = 1;
2043 code = afsmon_Exit(60);
2047 } /* execute_thresh_handler */
2051 /*-----------------------------------------------------------------------
2052 * check_fs_thresholds()
2055 * Checks the thresholds and sets the overflow flag. Recall that the
2056 * thresholds for each host are stored in the hostEntry lists
2057 * [fs/cm]nameList arrays. The probe results are passed to this
2058 * function in the display-ready format - ie., as strings. Though
2059 * this looks stupid the overhead incurred in converting the strings
2060 * back to floats and comparing them is insignificant and
2061 * programming is easier this way.
2062 * The threshold flags are a part of the display structures
2067 *----------------------------------------------------------------------*/
2070 check_fs_thresholds(a_hostEntry, a_Data)
2071 struct afsmon_hostEntry *a_hostEntry; /* ptr to hostEntry */
2072 struct fs_Display_Data *a_Data; /* ptr to fs data to be displayed */
2074 { /* check_fs_thresholds */
2076 static char rn[] = "check_fs_thresholds";
2077 struct Threshold *threshP;
2078 double tValue; /* threshold value */
2079 double pValue; /* probe value */
2082 int count; /* number of thresholds exceeded */
2085 fprintf(debugFD, "[ %s ] Called, a_hostEntry= %d, a_Data= %d\n", rn,
2086 a_hostEntry, a_Data);
2090 if (a_hostEntry->numThresh == 0) {
2091 /* store in ovf count ?? */
2096 threshP = a_hostEntry->thresh;
2097 for (i = 0; i < a_hostEntry->numThresh; i++) {
2098 if (threshP->itemName[0] == '\0') {
2102 idx = threshP->index; /* positional index to the data array */
2103 tValue = atof(threshP->threshVal); /* threshold value */
2104 pValue = atof(a_Data->data[idx]); /* probe value */
2105 if (pValue > tValue) {
2109 "[ %s ] fs = %s, thresh ovf for %s, threshold= %s, probevalue= %s\n",
2110 rn, a_hostEntry->hostName, threshP->itemName,
2111 threshP->threshVal, a_Data->data[idx]);
2114 /* if the threshold is crossed, call the handler function
2115 * only if this was a transition -ie, if the threshold was
2116 * crossed in the last probe too just count & keep quite! */
2118 if (!a_Data->threshOvf[idx]) {
2119 a_Data->threshOvf[idx] = 1;
2120 /* call the threshold handler if provided */
2121 if (threshP->handler[0] != '\0') {
2123 fprintf(debugFD, "[ %s ] Calling ovf handler %s\n",
2124 rn, threshP->handler);
2127 execute_thresh_handler(threshP->handler, a_Data->hostName,
2128 FS, threshP->itemName,
2136 /* in case threshold was previously crossed, blank it out */
2137 a_Data->threshOvf[idx] = 0;
2140 /* store the overflow count */
2141 a_Data->ovfCount = count;
2144 } /* check_fs_thresholds */
2147 /*-----------------------------------------------------------------------
2148 * save_FS_data_forDisplay()
2151 * Does the following:
2152 * - if the probe number changed (ie, a cycle completed) curr_fsData
2153 * is copied to prev_fsData, curr_fsData zeroed and refresh the
2154 * overview screen and file server screen with the new data.
2155 * - store the results of the current probe from xstat_fs_Results into
2156 * curr_fsData. ie., convert longs to strings.
2157 * - check the thresholds
2161 * Failure: Exits afsmonitor.
2162 *----------------------------------------------------------------------*/
2165 save_FS_data_forDisplay(a_fsResults)
2166 struct xstat_fs_ProbeResults *a_fsResults;
2167 { /* save_FS_data_forDisplay */
2169 static char rn[] = "save_FS_data_forDisplay"; /* routine name */
2170 struct fs_Display_Data *curr_fsDataP; /* tmp ptr to curr_fsData */
2171 struct fs_Display_Data *prev_fsDataP; /* tmp ptr to prev_fsData */
2172 struct afsmon_hostEntry *curr_host;
2173 static int probes_Received = 0; /* number of probes reveived in
2174 * the current cycle. If this is equal to numFS we got all
2175 * the data we want in this cycle and can now display it */
2184 fprintf(debugFD, "[ %s ] Called, a_fsResults= %d\n", rn, a_fsResults);
2190 /* store results in the display array */
2193 curr_fsDataP = curr_fsData;
2194 for (i = 0; i < numFS; i++) {
2195 if ((strcasecmp(curr_fsDataP->hostName, a_fsResults->connP->hostName))
2205 "[ %s ] Could not insert FS probe results for host %s in fs display array\n",
2206 rn, a_fsResults->connP->hostName);
2210 /* Check the status of the probe. If it succeeded, we store its
2211 * results in the display data structure. If it failed we only mark
2212 * the failed status in the display data structure. */
2214 if (a_fsResults->probeOK) { /* 1 => notOK the xstat results */
2215 curr_fsDataP->probeOK = 0;
2217 /* print the probe status */
2219 fprintf(debugFD, "\n\t\t ----- fs display data ------\n");
2220 fprintf(debugFD, "HostName = %s PROBE FAILED \n",
2221 curr_fsDataP->hostName);
2225 } else { /* probe succeeded, update display data structures */
2226 curr_fsDataP->probeOK = 1;
2228 /* covert longs to strings and place them in curr_fsDataP */
2229 fs_Results_ltoa(curr_fsDataP, a_fsResults);
2231 /* compare with thresholds and set the overflow flags.
2232 * note that the threshold information is in the hostEntry structure and
2233 * each threshold item has a positional index associated with it */
2235 /* locate the hostEntry for this host */
2237 curr_host = FSnameList;
2238 for (i = 0; i < numFS; i++) {
2239 if (strcasecmp(curr_host->hostName, a_fsResults->connP->hostName)
2244 curr_host = curr_host->next;;
2249 code = check_fs_thresholds(curr_host, curr_fsDataP);
2251 fprintf(stderr, "[ %s ] Error in checking thresholds\n", rn);
2258 /* print the info we just saved */
2261 fprintf(debugFD, "\n\t\t ----- fs display data ------\n");
2262 fprintf(debugFD, "HostName = %s\n", curr_fsDataP->hostName);
2263 for (i = 0; i < NUM_FS_STAT_ENTRIES; i++)
2264 fprintf(debugFD, "%20s %30s %s\n", curr_fsDataP->data[i],
2266 curr_fsDataP->threshOvf[i] ? "(ovf)" : "");
2268 fprintf(debugFD, "\t\t--------------------------------\n\n");
2272 } /* the probe succeeded, so we store the data in the display structure */
2275 /* if we have received a reply from all the hosts for this probe cycle,
2276 * it is time to display the data */
2279 if (probes_Received == numFS) {
2280 probes_Received = 0;
2282 if (afsmon_fs_curr_probeNum != afsmon_fs_prev_probeNum + 1) {
2283 sprintf(errMsg, "[ %s ] Probe number %d missed! \n", rn,
2284 afsmon_fs_prev_probeNum + 1);
2287 afsmon_fs_prev_probeNum++;
2289 /* backup the display data of the probe cycle that just completed -
2290 * ie., store curr_fsData in prev_fsData */
2292 memcpy((char *)prev_fsData, (char *)curr_fsData,
2293 (numFS * sizeof(struct fs_Display_Data)));
2296 /* initialize curr_fsData but retain the threshold flag information.
2297 * The previous state of threshold flags is used in check_fs_thresholds() */
2299 numBytes = NUM_FS_STAT_ENTRIES * CM_STAT_STRING_LEN;
2300 curr_fsDataP = curr_fsData;
2301 for (i = 0; i < numFS; i++) {
2302 curr_fsDataP->probeOK = 0;
2303 curr_fsDataP->ovfCount = 0;
2304 memset((char *)curr_fsDataP->data, 0, numBytes);
2309 /* prev_fsData now contains all the information for the probe cycle
2310 * that just completed. Now count the number of threshold overflows for
2311 * use in the overview screen */
2313 prev_fsDataP = prev_fsData;
2315 numHosts_onfs_alerts = 0;
2316 for (i = 0; i < numFS; i++) {
2317 if (!prev_fsDataP->probeOK) { /* if probe failed */
2319 numHosts_onfs_alerts++;
2321 if (prev_fsDataP->ovfCount) { /* overflows ?? */
2322 num_fs_alerts += prev_fsDataP->ovfCount;
2323 numHosts_onfs_alerts++;
2328 fprintf(debugFD, "Number of FS alerts = %d (on %d hosts)\n",
2329 num_fs_alerts, numHosts_onfs_alerts);
2331 /* flag that the data is now ready to be displayed */
2332 fs_Data_Available = 1;
2334 /* call the Overview frame update routine (update only FS info) */
2335 ovw_refresh(ovw_currPage, OVW_UPDATE_FS);
2337 /* call the File Servers frame update routine */
2338 fs_refresh(fs_currPage, fs_curr_LCol);
2343 } /* save_FS_data_forDisplay */
2348 /*-----------------------------------------------------------------------
2349 * afsmon_FS_Handler()
2352 * This is the File Server probe Handler. It updates the afsmonitor
2353 * probe counts, fs circular buffer indices and calls the functions
2354 * to process the results of this probe.
2358 * Failure: Exits afsmonitor.
2359 *----------------------------------------------------------------------*/
2363 { /* afsmon_FS_Handler() */
2364 static char rn[] = "afsmon_FS_Handler"; /* routine name */
2365 int newProbeCycle; /* start of new probe cycle ? */
2366 int code; /* return status */
2371 "[ %s ] Called, hostName= %s, probeNum= %d, status=%s\n", rn,
2372 xstat_fs_Results.connP->hostName, xstat_fs_Results.probeNum,
2373 xstat_fs_Results.probeOK ? "FAILED" : "OK");
2378 /* print the probe results to output file */
2379 if (afsmon_output) {
2380 code = afsmon_fsOutput(output_filename, afsmon_detOutput);
2383 "[ %s ] output to file %s returned error code=%d\n", rn,
2384 output_filename, code);
2388 /* Update current probe number and circular buffer index. if current
2389 * probenum changed make sure it is only by 1 */
2392 if (xstat_fs_Results.probeNum != afsmon_fs_curr_probeNum) {
2393 if (xstat_fs_Results.probeNum == afsmon_fs_curr_probeNum + 1) {
2394 afsmon_fs_curr_probeNum++;
2397 afsmon_fs_curr_CBindex =
2398 (afsmon_fs_curr_probeNum - 1) % num_bufSlots;
2400 fprintf(stderr, "[ %s ] probe number %d-1 missed\n", rn,
2401 xstat_fs_Results.probeNum);
2406 /* store the results of this probe in the FS circular buffer */
2408 save_FS_results_inCB(newProbeCycle);
2411 /* store the results of the current probe in the fs data display structure.
2412 * if the current probe number changed, swap the current and previous display
2413 * structures. note that the display screen is updated from these structures
2414 * and should start showing the data of the just completed probe cycle */
2416 save_FS_data_forDisplay(&xstat_fs_Results);
2423 /*----------------------------------------------------------------------- *
2428 * Prints the Cache Manager circular buffer
2429 *----------------------------------------------------------------------*/
2433 { /* Print_CM_CB() */
2435 struct afsmon_cm_Results_list *cmlist;
2439 /* print valid info in the cm CB */
2443 "==================== CM Buffer ========================\n");
2444 fprintf(debugFD, "afsmon_cm_curr_CBindex = %d\n",
2445 afsmon_cm_curr_CBindex);
2446 fprintf(debugFD, "afsmon_cm_curr_probeNum = %d\n\n",
2447 afsmon_cm_curr_probeNum);
2449 for (i = 0; i < num_bufSlots; i++) {
2450 fprintf(debugFD, "\t--------- slot %d ----------\n", i);
2451 cmlist = afsmon_cm_ResultsCB[i].list;
2454 if (!cmlist->empty) {
2455 fprintf(debugFD, "\t %d) probeNum = %d host = %s", j,
2456 cmlist->cmResults->probeNum,
2457 cmlist->cmResults->connP->hostName);
2458 if (cmlist->cmResults->probeOK)
2459 fprintf(debugFD, " NOTOK\n");
2461 fprintf(debugFD, " OK\n");
2463 fprintf(debugFD, "\t %d) -- empty --\n", j);
2464 cmlist = cmlist->next;
2467 if (cmlist != (struct afsmon_cm_Results_list *)0)
2468 fprintf(debugFD, "dangling last next ptr cm CB\n");
2474 /*-----------------------------------------------------------------------
2475 * save_CM_results_inCB()
2478 * Saves the results of the latest CM probe in the cm circular
2479 * buffers. If the current probe cycle is in progress the contents
2480 * of xstat_cm_Results are copied to the end of the list of results
2481 * in the current slot (pointed to by afsmon_cm_curr_CBindex). If
2482 * a new probe cycle has started the next slot in the circular buffer
2483 * is initialized and the results copied. Note that the Rx related
2484 * information available in xstat_cm_Results is not copied.
2488 * Failure: Exits afsmonitor.
2489 *----------------------------------------------------------------------*/
2492 save_CM_results_inCB(a_newProbeCycle)
2493 int a_newProbeCycle; /* start of new probe cycle ? */
2495 { /* save_CM_results_inCB() */
2496 static char rn[] = "save_CM_results_inCB"; /* routine name */
2497 struct afsmon_cm_Results_list *tmp_cmlist_item; /* temp cm list item */
2498 struct xstat_cm_ProbeResults *tmp_cmPR; /* temp ptr */
2503 fprintf(debugFD, "[ %s ] Called, a_newProbeCycle= %d\n", rn,
2508 /* If a new probe cycle started, mark the list in the current buffer
2509 * slot empty for resuse. Note that afsmon_cm_curr_CBindex was appropriately
2510 * incremented in afsmon_CM_Handler() */
2512 if (a_newProbeCycle) {
2513 tmp_cmlist_item = afsmon_cm_ResultsCB[afsmon_cm_curr_CBindex].list;
2514 for (i = 0; i < numCM; i++) {
2515 tmp_cmlist_item->empty = 1;
2516 tmp_cmlist_item = tmp_cmlist_item->next;
2520 /* locate last unused item in list */
2521 tmp_cmlist_item = afsmon_cm_ResultsCB[afsmon_cm_curr_CBindex].list;
2522 for (i = 0; i < numCM; i++) {
2523 if (tmp_cmlist_item->empty)
2525 tmp_cmlist_item = tmp_cmlist_item->next;
2528 /* if we could not find one we have an inconsistent list */
2529 if (!tmp_cmlist_item->empty) {
2531 "[ %s ] list inconsistency 1. unable to find an empty slot to store results of probenum %d of %s\n",
2532 rn, xstat_cm_Results.probeNum,
2533 xstat_cm_Results.connP->hostName);
2537 tmp_cmPR = tmp_cmlist_item->cmResults;
2539 /* copy hostname and probe number and probe time and probe status.
2540 * if the probe failed return now */
2542 memcpy(tmp_cmPR->connP->hostName, xstat_cm_Results.connP->hostName,
2543 sizeof(xstat_cm_Results.connP->hostName));
2544 tmp_cmPR->probeNum = xstat_cm_Results.probeNum;
2545 tmp_cmPR->probeTime = xstat_cm_Results.probeTime;
2546 tmp_cmPR->probeOK = xstat_cm_Results.probeOK;
2547 if (xstat_cm_Results.probeOK) { /* probeOK = 1 => notOK */
2548 /* we have a nonempty results structure so mark the list item used */
2549 tmp_cmlist_item->empty = 0;
2554 /* copy connection information */
2555 memcpy(&(tmp_cmPR->connP->skt), &(xstat_cm_Results.connP->skt),
2556 sizeof(struct sockaddr_in));
2558 /**** NEED TO COPY rx_connection INFORMATION HERE ******/
2560 memcpy(tmp_cmPR->connP->hostName, xstat_cm_Results.connP->hostName,
2561 sizeof(xstat_cm_Results.connP->hostName));
2562 tmp_cmPR->collectionNumber = xstat_cm_Results.collectionNumber;
2564 /* copy the probe data information */
2565 tmp_cmPR->data.AFSCB_CollData_len =
2566 xstat_cm_Results.data.AFSCB_CollData_len;
2567 memcpy(tmp_cmPR->data.AFSCB_CollData_val,
2568 xstat_cm_Results.data.AFSCB_CollData_val,
2569 xstat_cm_Results.data.AFSCB_CollData_len * sizeof(afs_int32));
2572 /* we have a valid results structure so mark the list item used */
2573 tmp_cmlist_item->empty = 0;
2575 /* print the stored info - to make sure we copied it right */
2576 /* Print_cm_FullPerfInfo(tmp_cmPR); */
2577 /* Print the cm circular buffer */
2580 } /* save_CM_results_inCB */
2584 /*-----------------------------------------------------------------------
2588 * The results of xstat probes are stored in a string format in
2589 * the arrays curr_cmData and prev_cmData. The information stored in
2590 * prev_cmData is copied to the screen.
2591 * This function converts xstat FS results from longs to strings and
2592 * places them in the given buffer (a pointer to an item in curr_cmData).
2593 * When a probe cycle completes, curr_cmData is copied to prev_cmData
2594 * in afsmon_CM_Handler().
2598 *----------------------------------------------------------------------*/
2601 cm_Results_ltoa(a_cmData, a_cmResults)
2602 struct cm_Display_Data *a_cmData; /* target buffer */
2603 struct xstat_cm_ProbeResults *a_cmResults; /* ptr to xstat cm Results */
2604 { /* cm_Results_ltoa */
2606 static char rn[] = "cm_Results_ltoa"; /* routine name */
2607 struct afs_stats_CMFullPerf *fullP; /* ptr to complete CM stats */
2615 fprintf(debugFD, "[ %s ] Called, a_cmData= %d, a_cmResults= %d\n", rn,
2616 a_cmData, a_cmResults);
2621 fullP = (struct afs_stats_CMFullPerf *)
2622 (a_cmResults->data.AFSCB_CollData_val);
2624 /* There are 4 parts to CM statistics
2625 * - Overall performance statistics (including up/down statistics)
2626 * - This CMs FS RPC operations info
2627 * - This CMs FS RPC errors info
2628 * - This CMs FS transfers info
2629 * - Authentication info
2630 * - [Un]Replicated access info
2633 /* copy overall performance statistics */
2634 srcbuf = (afs_int32 *) & (fullP->perf);
2636 /* we skip the 19 entry, ProtServAddr, so the index must account for this */
2637 for (i = 0; i < NUM_AFS_STATS_CMPERF_LONGS + 1; i++) {
2640 continue; /* skip ProtServerAddr */
2642 sprintf(a_cmData->data[idx], "%d", *srcbuf);
2647 /*printf("Ending index value = %d\n",idx-1); */
2649 /* server up/down statistics */
2650 /* copy file server up/down stats */
2651 srcbuf = (afs_int32 *) (fullP->perf.fs_UpDown);
2653 2 * (sizeof(struct afs_stats_SrvUpDownInfo) / sizeof(afs_int32));
2654 for (i = 0; i < numLongs; i++) {
2655 sprintf(a_cmData->data[idx], "%d", *srcbuf);
2660 /*printf("Ending index value = %d\n",idx-1); */
2662 /* copy volume location server up/down stats */
2663 srcbuf = (afs_int32 *) (fullP->perf.vl_UpDown);
2665 2 * (sizeof(struct afs_stats_SrvUpDownInfo) / sizeof(afs_int32));
2666 for (i = 0; i < numLongs; i++) {
2667 sprintf(a_cmData->data[idx], "%d", *srcbuf);
2672 /*printf("Ending index value = %d\n",idx-1); */
2674 /* copy CMs individual FS RPC operations info */
2675 srcbuf = (afs_int32 *) (fullP->rpc.fsRPCTimes);
2676 for (i = 0; i < AFS_STATS_NUM_FS_RPC_OPS; i++) {
2677 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* numOps */
2680 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* numSuccesses */
2683 tmpbuf = srcbuf++; /* sum time */
2684 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2687 tmpbuf = srcbuf++; /* sqr time */
2688 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2691 tmpbuf = srcbuf++; /* min time */
2692 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2695 tmpbuf = srcbuf++; /* max time */
2696 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2701 /*printf("Ending index value = %d\n",idx-1); */
2703 /* copy CMs individual FS RPC errors info */
2705 srcbuf = (afs_int32 *) (fullP->rpc.fsRPCErrors);
2706 for (i = 0; i < AFS_STATS_NUM_FS_RPC_OPS; i++) {
2707 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* server */
2710 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* network */
2713 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* prot */
2716 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* vol */
2719 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* busies */
2722 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* other */
2727 /*printf("Ending index value = %d\n",idx-1); */
2729 /* copy CMs individual RPC transfers info */
2731 srcbuf = (afs_int32 *) (fullP->rpc.fsXferTimes);
2732 for (i = 0; i < AFS_STATS_NUM_FS_XFER_OPS; i++) {
2733 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* numOps */
2736 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* numSuccesses */
2739 tmpbuf = srcbuf++; /* sum time */
2740 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2743 tmpbuf = srcbuf++; /* sqr time */
2744 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2747 tmpbuf = srcbuf++; /* min time */
2748 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2751 tmpbuf = srcbuf++; /* max time */
2752 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2755 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* sum bytes */
2758 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* min bytes */
2761 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* max bytes */
2764 for (j = 0; j < AFS_STATS_NUM_XFER_BUCKETS; j++) {
2765 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* bucket[j] */
2771 /*printf("Ending index value = %d\n",idx-1); */
2773 /* copy CM operations timings */
2775 srcbuf = (afs_int32 *) (fullP->rpc.cmRPCTimes);
2776 for (i = 0; i < AFS_STATS_NUM_CM_RPC_OPS; i++) {
2777 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* numOps */
2780 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* numSuccesses */
2783 tmpbuf = srcbuf++; /* sum time */
2784 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2787 tmpbuf = srcbuf++; /* sqr time */
2788 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2791 tmpbuf = srcbuf++; /* min time */
2792 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2795 tmpbuf = srcbuf++; /* max time */
2796 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2801 /*printf("Ending index value = %d\n",idx-1); */
2803 /* copy authentication info */
2805 srcbuf = (afs_int32 *) & (fullP->authent);
2806 numLongs = sizeof(struct afs_stats_AuthentInfo) / sizeof(afs_int32);
2807 for (i = 0; i < numLongs; i++) {
2808 sprintf(a_cmData->data[idx], "%d", *srcbuf);
2813 /*printf("Ending index value = %d\n",idx-1); */
2815 /* copy CM [un]replicated access info */
2817 srcbuf = (afs_int32 *) & (fullP->accessinf);
2818 numLongs = sizeof(struct afs_stats_AccessInfo) / sizeof(afs_int32);
2819 for (i = 0; i < numLongs; i++) {
2820 sprintf(a_cmData->data[idx], "%d", *srcbuf);
2825 /*printf("Ending index value = %d\n",idx-1); */
2828 } /* cm_Results_ltoa */
2831 /*-----------------------------------------------------------------------
2832 * Function: check_cm_thresholds()
2835 * Checks the thresholds and sets the overflow flag. Recall that the
2836 * thresholds for each host are stored in the hostEntry lists
2837 * [fs/cm]nameList arrays. The probe results are passed to this
2838 * function in the display-ready format - ie., as strings. Though
2839 * this looks stupid the overhead incurred in converting the strings
2840 * back to floats and comparing them is insignificant and
2841 * programming is easier this way.
2842 * The threshold flags are a part of the display structures
2847 *----------------------------------------------------------------------*/
2850 check_cm_thresholds(a_hostEntry, a_Data)
2851 struct afsmon_hostEntry *a_hostEntry; /* ptr to hostEntry */
2852 struct cm_Display_Data *a_Data; /* ptr to cm data to be displayed */
2854 { /* check_cm_thresholds */
2856 static char rn[] = "check_cm_thresholds";
2857 struct Threshold *threshP;
2858 double tValue; /* threshold value */
2859 double pValue; /* probe value */
2862 int count; /* number of thresholds exceeded */
2865 fprintf(debugFD, "[ %s ] Called, a_hostEntry= %d, a_Data= %d\n", rn,
2866 a_hostEntry, a_Data);
2870 if (a_hostEntry->numThresh == 0) {
2871 /* store in ovf count ?? */
2876 threshP = a_hostEntry->thresh;
2877 for (i = 0; i < a_hostEntry->numThresh; i++) {
2878 if (threshP->itemName[0] == '\0') {
2882 idx = threshP->index; /* positional index to the data array */
2883 tValue = atof(threshP->threshVal); /* threshold value */
2884 pValue = atof(a_Data->data[idx]); /* probe value */
2885 if (pValue > tValue) {
2889 "[ %s ] cm = %s, thresh ovf for %s, threshold= %s, probevalue= %s\n",
2890 rn, a_hostEntry->hostName, threshP->itemName,
2891 threshP->threshVal, a_Data->data[idx]);
2895 /* if the threshold is crossed, call the handler function
2896 * only if this was a transition -ie, if the threshold was
2897 * crossed in the last probe too just count & keep quite! */
2899 if (!a_Data->threshOvf[idx]) {
2900 a_Data->threshOvf[idx] = 1;
2901 /* call the threshold handler if provided */
2902 if (threshP->handler[0] != '\0') {
2904 fprintf(debugFD, "[ %s ] Calling ovf handler %s\n",
2905 rn, threshP->handler);
2908 execute_thresh_handler(threshP->handler, a_Data->hostName,
2909 CM, threshP->itemName,
2917 /* in case threshold was previously crossed, blank it out */
2918 a_Data->threshOvf[idx] = 0;
2921 /* store the overflow count */
2922 a_Data->ovfCount = count;
2925 } /* check_cm_thresholds */
2928 /*-----------------------------------------------------------------------
2929 * save_CM_data_forDisplay()
2932 * Does the following:
2933 * - if the probe number changed (ie, a cycle completed) curr_cmData
2934 * is copied to prev_cmData, curr_cmData zeroed and refresh the
2935 * overview screen and file server screen with the new data.
2936 * - store the results of the current probe from xstat_cm_Results into
2937 * curr_cmData. ie., convert longs to strings.
2938 * - check the thresholds
2942 * Failure: Exits afsmonitor.
2944 *----------------------------------------------------------------------*/
2947 save_CM_data_forDisplay(a_cmResults)
2948 struct xstat_cm_ProbeResults *a_cmResults;
2949 { /* save_CM_data_forDisplay */
2951 static char rn[] = "save_CM_data_forDisplay"; /* routine name */
2952 struct cm_Display_Data *curr_cmDataP;
2953 struct cm_Display_Data *prev_cmDataP;
2954 struct afsmon_hostEntry *curr_host;
2955 static int probes_Received = 0; /* number of probes reveived in
2956 * the current cycle. If this is equal to numFS we got all
2957 * the data we want in this cycle and can now display it */
2965 fprintf(debugFD, "[ %s ] Called, a_cmResults= %d\n", rn, a_cmResults);
2969 /* store results in the display array */
2972 curr_cmDataP = curr_cmData;
2973 for (i = 0; i < numCM; i++) {
2974 if ((strcasecmp(curr_cmDataP->hostName, a_cmResults->connP->hostName))
2984 "[ %s ] Could not insert CM probe results for host %s in cm display array\n",
2985 rn, a_cmResults->connP->hostName);
2989 /* Check the status of the probe. If it succeeded, we store its
2990 * results in the display data structure. If it failed we only mark
2991 * the failed status in the display data structure. */
2994 if (a_cmResults->probeOK) { /* 1 => notOK the xstat results */
2995 curr_cmDataP->probeOK = 0;
2997 /* print the probe status */
2999 fprintf(debugFD, "\n\t\t ----- cm display data ------\n");
3000 fprintf(debugFD, "HostName = %s PROBE FAILED \n",
3001 curr_cmDataP->hostName);
3005 } else { /* probe succeeded, update display data structures */
3006 curr_cmDataP->probeOK = 1;
3009 /* covert longs to strings and place them in curr_cmDataP */
3010 cm_Results_ltoa(curr_cmDataP, a_cmResults);
3012 /* compare with thresholds and set the overflow flags.
3013 * note that the threshold information is in the hostEntry structure and
3014 * each threshold item has a positional index associated with it */
3016 /* locate the hostEntry for this host */
3018 curr_host = CMnameList;
3019 for (i = 0; i < numCM; i++) {
3020 if (strcasecmp(curr_host->hostName, a_cmResults->connP->hostName)
3025 curr_host = curr_host->next;
3030 code = check_cm_thresholds(curr_host, curr_cmDataP);
3032 fprintf(stderr, "[ %s ] Error in checking thresholds\n", rn);
3037 /* print the info we just saved */
3039 fprintf(debugFD, "\n\t\t ----- CM display data ------\n");
3040 fprintf(debugFD, "HostName = %s\n", curr_cmDataP->hostName);
3041 for (i = 0; i < NUM_CM_STAT_ENTRIES; i++) {
3044 fprintf(debugFD, "\t -- Overall Perf Info --\n");
3048 "\t -- File Server up/down stats - same cell --\n");
3052 "\t -- File Server up/down stats - diff cell --\n");
3056 "\t -- VL server up/down stats - same cell --\n");
3060 "\t -- VL server up/down stats - diff cell --\n");
3063 fprintf(debugFD, "\t -- FS Operation Timings --\n");
3066 fprintf(debugFD, "\t -- FS Error Info --\n");
3069 fprintf(debugFD, "\t -- FS Transfer Timings --\n");
3072 fprintf(debugFD, "\t -- CM Operations Timings --\n");
3075 fprintf(debugFD, "\t -- Authentication Info --\n");
3078 fprintf(debugFD, "\t -- Access Info --\n");
3084 fprintf(debugFD, "%20s %30s %s\n", curr_cmDataP->data[i],
3086 curr_cmDataP->threshOvf[i] ? "(ovf)" : "");
3088 fprintf(debugFD, "\t\t--------------------------------\n\n");
3091 } /* if the probe succeeded, update the display data structures */
3093 /* if we have received a reply from all the hosts for this probe cycle,
3094 * it is time to display the data */
3097 if (probes_Received == numCM) {
3098 probes_Received = 0;
3100 if (afsmon_cm_curr_probeNum != afsmon_cm_prev_probeNum + 1) {
3101 sprintf(errMsg, "[ %s ] Probe number %d missed! \n", rn,
3102 afsmon_cm_prev_probeNum + 1);
3105 afsmon_cm_prev_probeNum++;
3108 /* backup the display data of the probe cycle that just completed -
3109 * ie., store curr_cmData in prev_cmData */
3111 memcpy((char *)prev_cmData, (char *)curr_cmData,
3112 (numCM * sizeof(struct cm_Display_Data)));
3115 /* initialize curr_cmData but retain the threshold flag information.
3116 * The previous state of threshold flags is used in check_cm_thresholds() */
3118 curr_cmDataP = curr_cmData;
3119 numBytes = NUM_CM_STAT_ENTRIES * CM_STAT_STRING_LEN;
3120 for (i = 0; i < numCM; i++) {
3121 curr_cmDataP->probeOK = 0;
3122 curr_cmDataP->ovfCount = 0;
3123 memset((char *)curr_cmDataP->data, 0, numBytes);
3127 /* prev_cmData now contains all the information for the probe cycle
3128 * that just completed. Now count the number of threshold overflows for
3129 * use in the overview screen */
3131 prev_cmDataP = prev_cmData;
3133 numHosts_oncm_alerts = 0;
3134 for (i = 0; i < numCM; i++) {
3135 if (!prev_cmDataP->probeOK) { /* if probe failed */
3137 numHosts_oncm_alerts++;
3138 } else if (prev_cmDataP->ovfCount) { /* overflows ?? */
3139 num_cm_alerts += prev_cmDataP->ovfCount;
3140 numHosts_oncm_alerts++;
3145 fprintf(debugFD, "Number of CM alerts = %d (on %d hosts)\n",
3146 num_cm_alerts, numHosts_oncm_alerts);
3149 /* flag that the data is now ready to be displayed */
3150 cm_Data_Available = 1;
3152 /* update the Overview frame (only CM info) */
3153 ovw_refresh(ovw_currPage, OVW_UPDATE_CM);
3155 /* update the Cache Managers frame */
3156 cm_refresh(cm_currPage, cm_curr_LCol);
3162 } /* save_CM_data_forDisplay */
3166 /*-----------------------------------------------------------------------
3167 * afsmon_CM_Handler()
3170 * This is the Cache Manager probe Handler. It updates the afsmonitor
3171 * probe counts, cm circular buffer indices and calls the functions
3172 * to process the results of this probe.
3176 * Failure: Exits afsmonitor.
3177 *----------------------------------------------------------------------*/
3181 { /* afsmon_CM_Handler() */
3182 static char rn[] = "afsmon_CM_Handler"; /* routine name */
3183 int code; /* return status */
3184 int newProbeCycle; /* start of new probe cycle ? */
3188 "[ %s ] Called, hostName= %s, probeNum= %d, status= %s\n", rn,
3189 xstat_cm_Results.connP->hostName, xstat_cm_Results.probeNum,
3190 xstat_cm_Results.probeOK ? "FAILED" : "OK");
3195 /* print the probe results to output file */
3196 if (afsmon_output) {
3197 code = afsmon_cmOutput(output_filename, afsmon_detOutput);
3200 "[ %s ] output to file %s returned error code=%d\n", rn,
3201 output_filename, code);
3205 /* Update current probe number and circular buffer index. if current
3206 * probenum changed make sure it is only by 1 */
3209 if (xstat_cm_Results.probeNum != afsmon_cm_curr_probeNum) {
3210 if (xstat_cm_Results.probeNum == afsmon_cm_curr_probeNum + 1) {
3211 afsmon_cm_curr_probeNum++;
3214 afsmon_cm_curr_CBindex =
3215 (afsmon_cm_curr_probeNum - 1) % num_bufSlots;
3217 fprintf(stderr, "[ %s ] probe number %d-1 missed\n", rn,
3218 xstat_cm_Results.probeNum);
3223 /* save the results of this probe in the CM buffer */
3225 save_CM_results_inCB(newProbeCycle);
3227 /* store the results of the current probe in the cm data display structure.
3228 * if the current probe number changed, swap the current and previous display
3229 * structures. note that the display screen is updated from these structures
3230 * and should start showing the data of the just completed probe cycle */
3232 save_CM_data_forDisplay(&xstat_cm_Results);
3237 /*-----------------------------------------------------------------------
3241 * Allocate and Initialize circular buffers for file servers.
3245 * Failure to allocate memory: exits afsmonitor.
3246 *----------------------------------------------------------------------*/
3250 { /* init_fs_buffers() */
3251 static char rn[] = "init_fs_buffers"; /* routine name */
3252 struct afsmon_fs_Results_list *new_fslist_item; /* ptr for new struct */
3253 struct afsmon_fs_Results_list *tmp_fslist_item; /* temp ptr */
3254 struct xstat_fs_ProbeResults *new_fsPR; /* ptr for new struct */
3261 fprintf(debugFD, "[ %s ] Called\n", rn);
3265 /* allocate memory for the circular buffer of pointers */
3267 afsmon_fs_ResultsCB = (struct afsmon_fs_Results_CBuffer *)
3268 malloc(sizeof(struct afsmon_fs_Results_CBuffer) * num_bufSlots);
3270 /* initialize the fs circular buffer */
3271 for (i = 0; i < num_bufSlots; i++) {
3272 afsmon_fs_ResultsCB[i].list = (struct afsmon_fs_Results_list *)0;
3273 afsmon_fs_ResultsCB[i].probeNum = 0;
3276 /* create a list of numFS items to store fs probe results for
3277 * each slot in CB */
3279 if (numFS) { /* if we have file servers to monitor */
3280 for (bufslot = 0; bufslot < num_bufSlots; bufslot++) {
3281 numfs = numFS; /* get the number of servers */
3284 /* if any of these mallocs fail we only need to free the memory we
3285 * have allocated in this iteration. the rest of it which is in a
3286 * proper linked list will be freed in afsmon_Exit */
3288 /* allocate memory for an fs list item */
3289 new_fslist_item = (struct afsmon_fs_Results_list *)
3290 malloc(sizeof(struct afsmon_fs_Results_list));
3291 if (new_fslist_item == (struct afsmon_fs_Results_list *)0)
3294 /* allocate memory to store xstat_fs_Results */
3295 new_fsPR = (struct xstat_fs_ProbeResults *)
3296 malloc(sizeof(struct xstat_fs_ProbeResults));
3297 if (new_fsPR == (struct xstat_fs_ProbeResults *)0) {
3298 free(new_fslist_item);
3301 new_fsPR->connP = (struct xstat_fs_ConnectionInfo *)
3302 malloc(sizeof(struct xstat_fs_ConnectionInfo));
3303 if (new_fsPR->connP == (struct xstat_fs_ConnectionInfo *)0) {
3304 free(new_fslist_item);
3309 /* >>> need to allocate rx connection info structure here <<< */
3311 new_fsPR->data.AFS_CollData_val =
3312 (afs_int32 *) malloc(XSTAT_FS_FULLPERF_RESULTS_LEN *
3314 if (new_fsPR->data.AFS_CollData_val == NULL) {
3315 free(new_fslist_item);
3316 free(new_fsPR->connP);
3321 /* initialize this list entry */
3322 new_fslist_item->fsResults = new_fsPR;
3323 new_fslist_item->empty = 1;
3324 new_fslist_item->next = (struct afsmon_fs_Results_list *)0;
3326 /* store it at the end of the fs list in the current CB slot */
3327 if (afsmon_fs_ResultsCB[bufslot].list ==
3328 (struct afsmon_fs_Results_list *)0)
3329 afsmon_fs_ResultsCB[bufslot].list = new_fslist_item;
3331 tmp_fslist_item = afsmon_fs_ResultsCB[bufslot].list;
3333 while (tmp_fslist_item !=
3334 (struct afsmon_fs_Results_list *)0) {
3335 if (tmp_fslist_item->next ==
3336 (struct afsmon_fs_Results_list *)0)
3338 tmp_fslist_item = tmp_fslist_item->next;
3340 /* something goofed. exit */
3341 fprintf(stderr, "[ %s ] list creation error\n",
3346 tmp_fslist_item->next = new_fslist_item;
3349 } /* while servers */
3350 } /* for each buffer slot */
3351 } /* if we have file servers to monitor */
3355 /*-----------------------------------------------------------------------
3359 * Allocate and Initialize circular buffers for cache managers.
3363 * Failure to allocate memory: exits afsmonitor.
3364 *----------------------------------------------------------------------*/
3368 { /* init_cm_buffers() */
3369 static char rn[] = "init_cm_buffers"; /* routine name */
3370 struct afsmon_cm_Results_list *new_cmlist_item; /* ptr for new struct */
3371 struct afsmon_cm_Results_list *tmp_cmlist_item; /* temp ptr */
3372 struct xstat_cm_ProbeResults *new_cmPR; /* ptr for new struct */
3378 fprintf(debugFD, "[ %s ] Called\n", rn);
3382 /* allocate memory for the circular buffer of pointers */
3383 afsmon_cm_ResultsCB = (struct afsmon_cm_Results_CBuffer *)
3384 malloc(sizeof(struct afsmon_cm_Results_CBuffer) * num_bufSlots);
3386 /* initialize the fs circular buffer */
3387 for (i = 0; i < num_bufSlots; i++) {
3388 afsmon_cm_ResultsCB[i].list = (struct afsmon_cm_Results_list *)0;
3389 afsmon_cm_ResultsCB[i].probeNum = 0;
3392 /* create a list of numCM items to store fs probe results for
3393 * each slot in CB */
3395 if (numCM) { /* if we have file servers to monitor */
3396 for (bufslot = 0; bufslot < num_bufSlots; bufslot++) {
3397 numcm = numCM; /* get the number of servers */
3400 /* if any of these mallocs fail we only need to free the memory we
3401 * have allocated in this iteration. the rest of it which is in a
3402 * proper linked list will be freed in afsmon_Exit */
3404 /* allocate memory for an fs list item */
3405 new_cmlist_item = (struct afsmon_cm_Results_list *)
3406 malloc(sizeof(struct afsmon_cm_Results_list));
3407 if (new_cmlist_item == (struct afsmon_cm_Results_list *)0)
3410 /* allocate memory to store xstat_cm_Results */
3411 new_cmPR = (struct xstat_cm_ProbeResults *)
3412 malloc(sizeof(struct xstat_cm_ProbeResults));
3413 if (new_cmPR == (struct xstat_cm_ProbeResults *)0) {
3414 free(new_cmlist_item);
3417 new_cmPR->connP = (struct xstat_cm_ConnectionInfo *)
3418 malloc(sizeof(struct xstat_cm_ConnectionInfo));
3419 if (new_cmPR->connP == (struct xstat_cm_ConnectionInfo *)0) {
3420 free(new_cmlist_item);
3425 /* >>> need to allocate rx connection info structure here <<< */
3427 new_cmPR->data.AFSCB_CollData_val =
3428 (afs_int32 *) malloc(XSTAT_CM_FULLPERF_RESULTS_LEN *
3430 if (new_cmPR->data.AFSCB_CollData_val == NULL) {
3431 free(new_cmlist_item);
3432 free(new_cmPR->connP);
3437 /* initialize this list entry */
3438 new_cmlist_item->cmResults = new_cmPR;
3439 new_cmlist_item->empty = 1;
3440 new_cmlist_item->next = (struct afsmon_cm_Results_list *)0;
3442 /* store it at the end of the cm list in the current CB slot */
3443 if (afsmon_cm_ResultsCB[bufslot].list ==
3444 (struct afsmon_cm_Results_list *)0)
3445 afsmon_cm_ResultsCB[bufslot].list = new_cmlist_item;
3447 tmp_cmlist_item = afsmon_cm_ResultsCB[bufslot].list;
3449 while (tmp_cmlist_item !=
3450 (struct afsmon_cm_Results_list *)0) {
3451 if (tmp_cmlist_item->next ==
3452 (struct afsmon_cm_Results_list *)0)
3454 tmp_cmlist_item = tmp_cmlist_item->next;
3456 /* something goofed. exit */
3457 fprintf(stderr, "[ %s ] list creation error\n",
3462 tmp_cmlist_item->next = new_cmlist_item;
3465 } /* while servers */
3466 } /* for each buffer slot */
3468 /* if we have file servers to monitor */
3469 /* print the CB to make sure it is right */
3473 } /* init_cm_buffers() */
3476 /*-------------------------------------------------------------------------
3477 * init_print_buffers()
3480 * Allocate and initialize the buffers used for printing results
3481 * to the display screen. These buffers store the current and
3482 * previous probe results in ascii format.
3487 *------------------------------------------------------------------------*/
3490 init_print_buffers()
3491 { /* init_print_buffers */
3493 static char rn[] = "init_print_buffers"; /* routine name */
3494 struct fs_Display_Data *tmp_fsData1; /* temp pointers */
3495 struct fs_Display_Data *tmp_fsData2;
3496 struct cm_Display_Data *tmp_cmData1;
3497 struct cm_Display_Data *tmp_cmData2;
3498 struct afsmon_hostEntry *tmp_fsNames;
3499 struct afsmon_hostEntry *tmp_cmNames;
3504 fprintf(debugFD, "[ %s ] Called\n", rn);
3508 /* allocate numFS blocks of the FS print structure. */
3510 /* we need two instances of this structure - one (curr_fsData) for storing
3511 * the results of the fs probes currently in progress and another (prev_fsData)
3512 * for the last completed probe. The display is updated from the contents of
3513 * prev_fsData. The pointers curr_fsData & prev_fsData are switched whenever
3514 * the probe number changes */
3517 numBytes = numFS * sizeof(struct fs_Display_Data);
3518 curr_fsData = (struct fs_Display_Data *)malloc(numBytes);
3519 if (curr_fsData == (struct fs_Display_Data *)0) {
3520 fprintf(stderr, "[ %s ] Memory allocation failure\n", rn);
3523 memset(curr_fsData, 0, numBytes);
3525 numBytes = numFS * sizeof(struct fs_Display_Data);
3526 prev_fsData = (struct fs_Display_Data *)malloc(numBytes);
3527 if (prev_fsData == (struct fs_Display_Data *)0) {
3528 fprintf(stderr, "[ %s ] Memory allocation failure\n", rn);
3531 memset(prev_fsData, 0, numBytes);
3533 /* fill in the host names */
3534 tmp_fsData1 = curr_fsData;
3535 tmp_fsData2 = curr_fsData;
3536 tmp_fsNames = FSnameList;
3537 for (i = 0; i < numFS; i++) {
3538 strncpy(tmp_fsData1->hostName, tmp_fsNames->hostName,
3540 strncpy(tmp_fsData2->hostName, tmp_fsNames->hostName,
3544 tmp_fsNames = tmp_fsNames->next;;
3551 /* if file servers to monitor */
3552 /* allocate numCM blocks of the CM print structure */
3553 /* we need two instances of this structure for the same reasons as above */
3555 numBytes = numCM * sizeof(struct cm_Display_Data);
3557 curr_cmData = (struct cm_Display_Data *)malloc(numBytes);
3558 if (curr_cmData == (struct cm_Display_Data *)0) {
3559 fprintf(stderr, "[ %s ] Memory allocation failure\n", rn);
3562 memset(curr_cmData, 0, numBytes);
3564 numBytes = numCM * sizeof(struct cm_Display_Data);
3565 prev_cmData = (struct cm_Display_Data *)malloc(numBytes);
3566 if (prev_cmData == (struct cm_Display_Data *)0) {
3567 fprintf(stderr, "[ %s ] Memory allocation failure\n", rn);
3570 memset(prev_cmData, 0, numBytes);
3572 /* fill in the host names */
3573 tmp_cmData1 = curr_cmData;
3574 tmp_cmData2 = curr_cmData;
3575 tmp_cmNames = CMnameList;
3576 for (i = 0; i < numCM; i++) {
3577 strncpy(tmp_cmData1->hostName, tmp_cmNames->hostName,
3579 strncpy(tmp_cmData2->hostName, tmp_cmNames->hostName,
3583 tmp_cmNames = tmp_cmNames->next;;
3587 /* if cache managers to monitor */
3590 } /* init_print_buffers */
3592 /*-----------------------------------------------------------------------
3596 * Trap the interrupt signal. This function is useful only until
3597 * gtx is initialized.
3598 *----------------------------------------------------------------------*/
3604 static char *rn = "quit_signal"; /* routine name */
3606 fprintf(stderr, "Received signal %d \n", sig);
3612 /*-----------------------------------------------------------------------
3616 * This is where we start it all. Initialize an array of sockets for
3617 * file servers and cache cache managers and call the xstat_[fs/cm]_Init
3618 * routines. The last step is to call the gtx input server which
3619 * grabs control of the keyboard.
3622 * Does not return. Control is periodically returned to the afsmonitor
3623 * thru afsmon_[FS/CM]_Handler() routines and also through the gtx
3624 * keyboard handler calls.
3626 *----------------------------------------------------------------------*/
3630 { /* afsmon_execute() */
3631 static char rn[] = "afsmon_execute"; /* routine name */
3632 static char fullhostname[128]; /* full host name */
3633 struct sockaddr_in *FSSktArray; /* fs socket array */
3634 int FSsktbytes; /* num bytes in above */
3635 struct sockaddr_in *CMSktArray; /* cm socket array */
3636 int CMsktbytes; /* num bytes in above */
3637 struct sockaddr_in *curr_skt; /* ptr to current socket */
3638 struct afsmon_hostEntry *curr_FS; /* ptr to FS name list */
3639 struct afsmon_hostEntry *curr_CM; /* ptr to CM name list */
3640 struct hostent *he; /* host entry */
3641 afs_int32 *collIDP; /* ptr to collection ID */
3642 int numCollIDs; /* number of collection IDs */
3643 int FSinitFlags = 0; /* flags for xstat_fs_Init */
3644 int CMinitFlags = 0; /* flags for xstat_cm_Init */
3645 int code; /* function return code */
3646 struct timeval tv; /* time structure */
3649 fprintf(debugFD, "[ %s ] Called\n", rn);
3654 /* process file server entries */
3656 /* Allocate an array of sockets for each fileserver we monitor */
3658 FSsktbytes = numFS * sizeof(struct sockaddr_in);
3659 FSSktArray = (struct sockaddr_in *)malloc(FSsktbytes);
3660 if (FSSktArray == (struct sockaddr_in *)0) {
3662 "[ %s ] cannot malloc %d sockaddr_ins for fileservers\n",
3667 memset(FSSktArray, 0, FSsktbytes);
3669 /* Fill in the socket information for each fileserve */
3671 curr_skt = FSSktArray;
3672 curr_FS = FSnameList; /* FS name list header */
3674 strncpy(fullhostname, curr_FS->hostName, sizeof(fullhostname));
3675 he = GetHostByName(fullhostname);
3677 fprintf(stderr, "[ %s ] Cannot get host info for %s\n", rn,
3681 strncpy(curr_FS->hostName, he->h_name, HOST_NAME_LEN); /* complete name */
3682 memcpy(&(curr_skt->sin_addr.s_addr), he->h_addr, 4);
3683 curr_skt->sin_family = htons(AF_INET); /*Internet family */
3684 curr_skt->sin_port = htons(7000); /*FileServer port */
3685 #ifdef STRUCT_SOCKADDR_HAS_SA_LEN
3686 curr_skt->sin_len = sizeof(struct sockaddr_in);
3689 /* get the next dude */
3691 curr_FS = curr_FS->next;
3694 /* initialize collection IDs. We need only one entry since we collect
3695 * all the information from xstat */
3698 collIDP = (afs_int32 *) malloc(sizeof(afs_int32));
3699 if (collIDP == NULL) {
3701 "[ %s ] failed to allocate a measely afs_int32 word.Argh!\n",
3705 *collIDP = 2; /* USE A macro for this */
3708 if (afsmon_onceOnly) /* option not provided at this time */
3709 FSinitFlags |= XSTAT_FS_INITFLAG_ONE_SHOT;
3712 fprintf(debugFD, "[ %s ] Calling xstat_fs_Init \n", rn);
3716 code = xstat_fs_Init(numFS, /*Num servers */
3717 FSSktArray, /*File Server socket array */
3718 afsmon_probefreq, /*probe frequency */
3719 afsmon_FS_Handler, /*Handler routine */
3720 FSinitFlags, /*Initialization flags */
3721 numCollIDs, /*Number of collection IDs */
3722 collIDP); /*Ptr to collection ID */
3725 fprintf(stderr, "[ %s ] xstat_fs_init returned error\n", rn);
3732 /* end of process fileserver entries */
3733 /* process cache manager entries */
3735 /* Allocate an array of sockets for each cache manager we monitor */
3737 CMsktbytes = numCM * sizeof(struct sockaddr_in);
3738 CMSktArray = (struct sockaddr_in *)malloc(CMsktbytes);
3739 if (CMSktArray == (struct sockaddr_in *)0) {
3741 "[ %s ] cannot malloc %d sockaddr_ins for CM entries\n",
3746 memset(CMSktArray, 0, CMsktbytes);
3748 /* Fill in the socket information for each CM */
3750 curr_skt = CMSktArray;
3751 curr_CM = CMnameList; /* CM name list header */
3753 strncpy(fullhostname, curr_CM->hostName, sizeof(fullhostname));
3754 he = GetHostByName(fullhostname);
3756 fprintf(stderr, "[ %s ] Cannot get host info for %s\n", rn,
3760 strncpy(curr_CM->hostName, he->h_name, HOST_NAME_LEN); /* complete name */
3761 memcpy(&(curr_skt->sin_addr.s_addr), he->h_addr, 4);
3762 curr_skt->sin_family = htons(AF_INET); /*Internet family */
3763 curr_skt->sin_port = htons(7001); /*Cache Manager port */
3764 #ifdef STRUCT_SOCKADDR_HAS_SA_LEN
3765 curr_skt->sin_len = sizeof(struct sockaddr_in);
3768 /* get the next dude */
3770 curr_CM = curr_CM->next;
3773 /* initialize collection IDs. We need only one entry since we collect
3774 * all the information from xstat */
3777 collIDP = (afs_int32 *) malloc(sizeof(afs_int32));
3778 if (collIDP == NULL) {
3780 "[ %s ] failed to allocate a measely long word.Argh!\n",
3784 *collIDP = 2; /* USE A macro for this */
3787 if (afsmon_onceOnly) /* once only ? */
3788 CMinitFlags |= XSTAT_CM_INITFLAG_ONE_SHOT;
3791 fprintf(debugFD, "[ %s ] Calling xstat_cm_Init \n", rn);
3795 code = xstat_cm_Init(numCM, /*Num servers */
3796 CMSktArray, /*Cache Manager socket array */
3797 afsmon_probefreq, /*probe frequency */
3798 afsmon_CM_Handler, /*Handler routine */
3799 CMinitFlags, /*Initialization flags */
3800 numCollIDs, /*Number of collection IDs */
3801 collIDP); /*Ptr to collection ID */
3804 fprintf(stderr, "[ %s ] xstat_cm_init returned error\n", rn);
3811 /* end of process cache manager entries */
3812 /* if only one probe was required setup a waiting process for the
3813 * termination signal */
3814 if (afsmon_onceOnly) {
3815 code = LWP_WaitProcess(&terminationEvent);
3818 fprintf(debugFD, "LWP_WaitProcess() returned error %d\n",
3826 /* start the gtx input server */
3827 code = gtx_InputServer(afsmon_win);
3829 fprintf(stderr, "[ %s ] Failed to start input server \n", rn);
3833 /* This part of the code is reached only if the input server is not started
3834 * for debugging purposes */
3837 tv.tv_sec = 24 * 60;
3839 fprintf(stderr, "[ %s ] going to sleep ...\n", rn);
3841 code = IOMGR_Select(0, /*Num fds */
3842 0, /*Descriptors ready for reading */
3843 0, /*Descriptors ready for writing */
3844 0, /*Descriptors with exceptional conditions */
3845 &tv); /*Timeout structure */
3848 "[ %s ] IOMGR_Select() returned non-zero value %d\n", rn,
3856 /*-----------------------------------------------------------------------
3860 * Afsmonitor initialization routine.
3861 * - processes command line parameters
3862 * - call functions to:
3863 * - process config file
3864 * - initialize circular buffers and display buffers
3866 * - execute afsmonitor
3867 * - initialize the display maps [fs/cm]_Display_map[].
3870 * Success: Does not return from the call to afsmon_execute().
3871 * Failure: Exits afsmonitor.
3872 *----------------------------------------------------------------------*/
3876 struct cmd_syndesc *as;
3877 { /* afsmonInit() */
3879 static char rn[] = "afsmonInit"; /* Routine name */
3880 char *debug_filename; /* pointer to debug filename */
3881 FILE *outputFD; /* output file descriptor */
3882 struct cmd_item *hostPtr; /* ptr to parse command line args */
3883 char buf[256]; /* buffer for processing hostnames */
3888 fprintf(debugFD, "[ %s ] Called, as= %d\n", rn, as);
3892 /* Open the debug file if -debug option is specified */
3893 if (as->parms[P_DEBUG].items != 0) {
3895 debug_filename = as->parms[P_DEBUG].items->data;
3896 debugFD = fopen(debug_filename, "w");
3897 if (debugFD == (FILE *) 0) {
3898 printf("[ %s ] Failed to open debugging file %s for writing\n",
3906 fprintf(debugFD, "[ %s ] Called\n", rn);
3910 /* use curses always until we support other packages */
3912 wpkg_to_use = atoi(as->parms[P_PACKAGE].items->data);
3914 switch (wpkg_to_use) {
3915 case GATOR_WIN_CURSES:
3916 fprintf(stderr, "curses\n");
3918 case GATOR_WIN_DUMB:
3919 fprintf(stderr, "dumb terminal\n");
3922 fprintf(stderr, "X11\n");
3925 fprintf(stderr, "Illegal graphics package: %d\n", wpkg_to_use);
3927 } /*end switch (wpkg_to_use) */
3930 wpkg_to_use = GATOR_WIN_CURSES;
3932 /* get probe frequency . We check for meaningful bounds on the frequency
3933 * and reset to the default value if needed. The upper bound of 24
3934 * hours looks ridiculous though! */
3936 afsmon_probefreq = 0;
3937 if (as->parms[P_FREQUENCY].items != 0)
3938 afsmon_probefreq = atoi(as->parms[P_FREQUENCY].items->data);
3940 afsmon_probefreq = DEFAULT_FREQUENCY;
3942 if (afsmon_probefreq <= 0 || afsmon_probefreq > 24 * 60 * 60) {
3943 afsmon_probefreq = DEFAULT_FREQUENCY;
3946 "[ %s ] Invalid probe frequency %s specified, resetting to default value %d seconds\n",
3947 rn, as->parms[P_FREQUENCY].items->data, afsmon_probefreq);
3951 "Invalid probe frequency %s specified, resetting to default value %d seconds\n",
3952 as->parms[P_FREQUENCY].items->data, afsmon_probefreq);
3957 /* make sure output file is writable, else complain now */
3958 /* we will open and close it as needed after probes */
3960 if (as->parms[P_OUTPUT].items != 0) {
3961 afsmon_output = 1; /* output flag */
3962 strncpy(output_filename, as->parms[P_OUTPUT].items->data, 80);
3963 outputFD = fopen(output_filename, "a");
3964 if (outputFD == (FILE *) 0) {
3965 fprintf(stderr, "Failed to open output file %s \n",
3968 fprintf(debugFD, "[ %s ] Failed to open output file %s \n",
3969 rn, output_filename);
3974 fprintf(debugFD, "[ %s ] output file is %s\n", rn,
3980 /* detailed statistics to storage file */
3981 if (as->parms[P_DETAILED].items != 0) {
3982 if (as->parms[P_OUTPUT].items == 0) {
3984 "-detailed switch can be used only with -output\n");
3987 afsmon_detOutput = 1;
3990 /* Initialize host list headers */
3991 FSnameList = (struct afsmon_hostEntry *)0;
3992 CMnameList = (struct afsmon_hostEntry *)0;
3994 /* The -config option is mutually exclusive with the -fshosts,-cmhosts
3997 if (as->parms[P_CONFIG].items) {
3998 if (as->parms[P_FSHOSTS].items || as->parms[P_CMHOSTS].items) {
4000 "Cannot use -config option with -fshosts or -cmhosts\n");
4004 if (!as->parms[P_FSHOSTS].items && !as->parms[P_CMHOSTS].items) {
4006 "Must specify either -config or (-fshosts and/or -cmhosts) options \n");
4012 /* If a file server host is specified on the command line we reuse
4013 * parse_hostEntry() function . Just the pass the info as if it were
4014 * read off the config file */
4016 if (as->parms[P_FSHOSTS].items) {
4017 hostPtr = as->parms[P_FSHOSTS].items;
4018 while (hostPtr != (struct cmd_item *)0) {
4019 sprintf(buf, "fs %s", hostPtr->data);
4020 code = parse_hostEntry(buf);
4022 fprintf(stderr, "Could not parse %s\n", hostPtr->data);
4026 hostPtr = hostPtr->next;
4030 /* same as above for -cmhosts */
4031 if (as->parms[P_CMHOSTS].items) {
4032 hostPtr = as->parms[P_CMHOSTS].items;
4033 while (hostPtr != (struct cmd_item *)0) {
4034 sprintf(buf, "cm %s", hostPtr->data);
4035 code = parse_hostEntry(buf);
4037 fprintf(stderr, "Could not parse %s\n", hostPtr->data);
4041 hostPtr = hostPtr->next;
4045 /* number of slots in circular buffers */
4046 if (as->parms[P_BUFFERS].items)
4047 num_bufSlots = atoi(as->parms[P_BUFFERS].items->data);
4049 num_bufSlots = DEFAULT_BUFSLOTS;
4051 /* Initialize xx_showFlags[]. This array is used solely for processing the
4052 * "show" directives in the config file in parse_showEntries() */
4053 for (i = 0; i < NUM_FS_STAT_ENTRIES; i++)
4054 fs_showFlags[i] = 0;
4055 for (i = 0; i < NUM_CM_STAT_ENTRIES; i++)
4056 cm_showFlags[i] = 0;
4059 /* Process the configuration file if given. This initializes among other
4060 * things, the list of FS & CM names in FSnameList and CMnameList */
4062 if (as->parms[P_CONFIG].items)
4063 process_config_file(as->parms[P_CONFIG].items->data);
4065 /* print out the FS and CM lists */
4069 /* Initialize the FS results-to-screen map array if there were no "show fs"
4070 * directives in the config file */
4071 if (fs_showDefault) {
4072 for (i = 0; i < NUM_FS_STAT_ENTRIES; i++)
4073 fs_Display_map[i] = i;
4074 fs_DisplayItems_count = NUM_FS_STAT_ENTRIES;
4077 /* Initialize the CM results-to-screen map array if there were no "show cm"
4078 * directives in the config file */
4079 if (cm_showDefault) {
4080 for (i = 0; i < NUM_CM_STAT_ENTRIES; i++)
4081 cm_Display_map[i] = i;
4082 cm_DisplayItems_count = NUM_CM_STAT_ENTRIES;
4087 /* setup an interrupt signal handler; we ain't wanna leak core */
4088 /* this binding is useful only until gtx is initialized after which the
4089 * keyboard input server takes over. */
4090 if ((signal(SIGINT, quit_signal)) == SIG_ERR) {
4091 perror("signal() failed.");
4096 /* init error message buffers. these will be used to print error messages
4097 * once gtx is initialized and there is no access to stderr/stdout */
4103 /* initialize fs and cm circular buffers before initiating probes */
4105 code = init_fs_buffers();
4107 fprintf(stderr, "[ %s ] init_fs_buffers returned %d\n", rn,
4114 code = init_cm_buffers();
4116 fprintf(stderr, "[ %s ] init_cm_buffers returned %d\n", rn,
4123 /* allocate and initialize buffers for holding fs & cm results in ascii
4124 * format suitable for updating the screen */
4125 code = init_print_buffers();
4127 fprintf(stderr, "[ %s ] init_print_buffers returned %d\n", rn, code);
4131 /* perform gtx initializations */
4132 code = gtx_initialize();
4134 fprintf(stderr, "[ %s ] gtx_initialize returned %d\n", rn, code);
4138 /* start xstat probes */
4141 return (0); /* will not return from the call to afsmon_execute() */
4143 } /* afsmonInit() */
4146 /*-----------------------------------------------------------------------
4148 ------------------------------------------------------------------------*/
4150 #include "AFS_component_version_number.c"
4158 static char rn[] = "main"; /* routine name */
4159 afs_int32 code; /*Return code */
4160 struct cmd_syndesc *ts; /*Ptr to cmd line syntax descriptor */
4162 #ifdef AFS_AIX32_ENV
4164 * The following signal action for AIX is necessary so that in case of a
4165 * crash (i.e. core is generated) we can include the user's data section
4166 * in the core dump. Unfortunately, by default, only a partial core is
4167 * generated which, in many cases, isn't too useful.
4169 struct sigaction nsa;
4171 sigemptyset(&nsa.sa_mask);
4172 nsa.sa_handler = SIG_DFL;
4173 nsa.sa_flags = SA_FULLDUMP;
4174 sigaction(SIGSEGV, &nsa, NULL);
4178 * Set up the commands we understand.
4180 ts = cmd_CreateSyntax("initcmd", afsmonInit, 0, "initialize the program");
4181 cmd_AddParm(ts, "-config", CMD_SINGLE, CMD_OPTIONAL,
4182 "configuration file");
4183 cmd_AddParm(ts, "-frequency", CMD_SINGLE, CMD_OPTIONAL,
4184 "poll frequency, in seconds");
4185 cmd_AddParm(ts, "-output", CMD_SINGLE, CMD_OPTIONAL, "storage file name");
4186 cmd_AddParm(ts, "-detailed", CMD_FLAG, CMD_OPTIONAL,
4187 "output detailed statistics to storage file");
4189 /* we hope to use this .... eventually! */
4190 cmd_AddParm(ts, "-package", CMD_SINGLE, CMD_REQUIRED,
4191 "Graphics Package to use");
4193 cmd_AddParm(ts, "-debug", CMD_SINGLE, CMD_OPTIONAL,
4194 "turn debugging output on to the named file");
4195 cmd_AddParm(ts, "-fshosts", CMD_LIST, CMD_OPTIONAL,
4196 "list of file servers to monitor");
4197 cmd_AddParm(ts, "-cmhosts", CMD_LIST, CMD_OPTIONAL,
4198 "list of cache managers to monitor");
4199 cmd_AddParm(ts, "-buffers", CMD_SINGLE, CMD_OPTIONAL,
4200 "number of buffer slots");
4203 * Parse command-line switches & execute afsmonitor
4206 code = cmd_Dispatch(argc, argv);
4212 exit(0); /* redundant, but gets rid of warning */