2 * Copyright 2000, International Business Machines Corporation and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
9 * Portions Copyright (c) 2003 Apple Computer, Inc.
13 * Afsmonitor: An AFS Performance Monitoring Tool
15 *-------------------------------------------------------------------------*/
18 #include <afsconfig.h>
19 #include <afs/param.h>
29 #include <sys/types.h>
30 #include <netinet/in.h>
31 #include <sys/socket.h>
35 #include <gtxwindows.h> /*Generic window package */
36 #include <gtxobjects.h> /*Object definitions */
37 #include <gtxlightobj.h> /*Light object interface */
38 #include <gtxcurseswin.h> /*Curses window package */
39 #include <gtxdumbwin.h> /*Dumb terminal window package */
40 #include <gtxX11win.h> /*X11 window package */
41 #include <gtxframe.h> /*Frame package */
44 #include <afs/xstat_fs.h>
45 #include <afs/xstat_cm.h>
47 #include "afsmonitor.h"
49 /* command line parameter indices */
55 /* #define P_PACKAGE X */
62 int afsmon_debug = 0; /* debug info to file ? */
63 FILE *debugFD; /* debugging file descriptor */
64 static int afsmon_output = 0; /* output to file ? */
65 static int afsmon_detOutput = 0; /* detailed output ? */
66 static int afsmon_onceOnly = 0; /* probe once only ? (not implemented) */
67 int afsmon_probefreq; /* probe frequency */
68 static int wpkg_to_use; /* graphics package to use */
69 static char output_filename[80]; /* output filename */
70 char errMsg[256]; /* buffers used to print error messages after */
71 char errMsg1[256]; /* gtx is initialized (stderr/stdout gone !) */
72 int num_bufSlots = 0; /* number of slots in fs & cm circular buffers */
74 /* Flags used to process "show" directives in config file */
75 short fs_showFlags[NUM_FS_STAT_ENTRIES];
76 short cm_showFlags[NUM_CM_STAT_ENTRIES];
79 /* afsmonitor misc definitions */
81 #define DEFAULT_FREQUENCY 60 /* default proble frequency in seconds */
82 #define DEFAULT_BUFSLOTS 0 /* default number of buffer slots */
83 #define CFG_STR_LEN 80 /* max length of config file fields */
84 #define FS 1 /* for misc. use */
85 #define CM 2 /* for misc. use */
88 #define NUM_XSTAT_FS_AFS_PERFSTATS_LONGS 66 /* number of fields (longs) in struct afs_PerfStats that we display */
89 #define NUM_AFS_STATS_CMPERF_LONGS 40 /* number of longs in struct afs_stats_CMPerf excluding up/down stats and fields we dont display */
92 /* variables used for exec'ing user provided threshold handlers */
93 char *fsHandler_argv[20]; /* *argv[] for the handler */
94 char fsHandler_args[20][256]; /* buffer space for arguments */
95 int exec_fsThreshHandler = 0; /* execute fs threshold handler ? */
98 /* THRESHOLD STRUCTURE DEFINITIONS */
100 /* flag to indicate that threshold entries apply to all hosts. these will
101 be turned off when the first fs or cm host entry is processed */
102 static int global_ThreshFlag = 1;
103 static int global_fsThreshCount = 0; /* number of global fs thresholds */
104 static int global_cmThreshCount = 0; /* number of global cm thresholds */
108 /* Linked lists of file server and cache manager host names are made from
109 the entries in the config file. Head pointers to FS and CM server name lists. */
110 static struct afsmon_hostEntry *FSnameList;
111 static struct afsmon_hostEntry *CMnameList;
113 /* number of fileservers and cache managers to monitor */
117 /* variables used for processing config file */
118 /* ptr to the hostEntry structure of the last "fs" or "cm" entry processed
119 in the config file */
120 static struct afsmon_hostEntry *last_hostEntry;
121 /* names of the last host processed in the config file */
122 static char last_fsHost[HOST_NAME_LEN];
123 static char last_cmHost[HOST_NAME_LEN];
124 static int lastHostType = 0; /* 0 = no host entries processed
125 * 1 = last host was file server
126 * 2 = last host was cache manager. */
129 /* FILE SERVER CIRCULAR BUFFER VARIABLES */
131 struct afsmon_fs_Results_list {
132 struct xstat_fs_ProbeResults *fsResults; /* ptr to results struct */
133 int empty; /* fsResults empty ? */
134 struct afsmon_fs_Results_list *next;
137 struct afsmon_fs_Results_CBuffer {
138 int probeNum; /* probe number of entries in this slot */
139 struct afsmon_fs_Results_list *list; /* ptr to list of results */
142 /* buffer for FS probe results */
143 struct afsmon_fs_Results_CBuffer *afsmon_fs_ResultsCB;
145 int afsmon_fs_curr_CBindex = 0; /* current fs CB slot */
147 /* Probe number variables. The current probe number is incremented
148 when the first probe from a new probe cycle is received. The prev probe
149 number is incremented when the last probe of the current cycle is
150 received. This difference is because of the purpose for which these
153 int afsmon_fs_curr_probeNum = 1; /* current fs probe number */
154 int afsmon_fs_prev_probeNum = 0; /* previous fs probe number */
157 /* CACHE MANAGER CIRCULAR BUFFER VARIABLES */
159 struct afsmon_cm_Results_list {
160 struct xstat_cm_ProbeResults *cmResults; /* ptr to results struct */
161 int empty; /* cmResults empty ? */
162 struct afsmon_cm_Results_list *next;
165 struct afsmon_cm_Results_CBuffer {
166 int probeNum; /* probe number of entries in this slot */
167 struct afsmon_cm_Results_list *list; /* ptr to list of results */
170 /* buffer for CM probe results */
171 struct afsmon_cm_Results_CBuffer *afsmon_cm_ResultsCB;
173 int afsmon_cm_curr_CBindex = 0; /* current cm CB slot */
176 /* Probe number variables. The current probe number is incremented
177 when the first probe from a new probe cycle is received. The prev probe
178 number is incremented when the last probe of the current cycle is
179 received. This difference is because of the purpose for which these
182 int afsmon_cm_curr_probeNum = 1; /* current cm probe number */
183 int afsmon_cm_prev_probeNum = 0; /* previous cm probe number */
186 /* Structures to hold FS & CM results in string format(suitable for display ) */
188 /* ptr to array holding the results of FS probes in ascii format */
189 /* for current probe cycle */
190 struct fs_Display_Data *curr_fsData = (struct fs_Display_Data *)0;
191 /* for previous probe cycle */
192 struct fs_Display_Data *prev_fsData = (struct fs_Display_Data *)0;
195 /* ptr to array holding the results of CM probes in ascii format */
196 /* for current probe cycle */
197 struct cm_Display_Data *curr_cmData = (struct cm_Display_Data *)0;
198 /* for previous probe cycle */
199 struct cm_Display_Data *prev_cmData = (struct cm_Display_Data *)0;
201 /* EXTERN DEFINITIONS */
203 /* file server and cache manager variable names (from afsmon_labels.h) */
204 extern char *fs_varNames[];
205 extern char *cm_varNames[];
207 /* GTX & MISC VARIABLES */
209 /* afsmonitor window */
210 extern struct gwin *afsmon_win;
212 /* current page number in the overview frame */
213 extern int ovw_currPage;
215 /* number of FS alerts and number of hosts on FS alerts */
217 int numHosts_onfs_alerts;
219 /* number of CM alerts and number of hosts on FS alerts */
221 int numHosts_oncm_alerts;
223 /* flag to indicate that atleast one probe cycle has completed and
224 data is available for updating the display */
225 extern int fs_Data_Available;
226 extern int cm_Data_Available;
228 extern int gtx_initialized; /* gtx initialized ? */
230 /* This array contains the indices of the file server data items that
231 are to be displayed on the File Servers screen. For example, suppose the
232 user wishes to display only the vcache statistics then the following array
233 will contain indices 2 to 14 corresponding to the position of the
234 vcache data items in the fs_varNames[] array. If the config file contains
235 no "show fs .." directives, it will contain the indices of all the
236 items in the fs_varNames[] array */
238 short fs_Display_map[XSTAT_FS_FULLPERF_RESULTS_LEN];
239 int fs_DisplayItems_count = 0; /* number of items to display */
240 int fs_showDefault = 1; /* show all of FS data ? */
243 /* same use as above for Cache Managers */
244 short cm_Display_map[XSTAT_CM_FULLPERF_RESULTS_LEN];
245 int cm_DisplayItems_count = 0; /* number of items to display */
246 int cm_showDefault = 1; /* show all of CM data ? */
248 extern int fs_currPage; /* current page number in the File Servers frame */
249 extern int fs_curr_LCol; /* current leftmost column on display on FS frame */
251 extern int cm_currPage; /* current page number in the Cache Managers frame */
252 extern int cm_curr_LCol; /* current leftmost column on display on CM frame */
254 /* File server and Cache manager data is classified into sections &
255 groups to help the user choose what he wants displayed */
256 extern char *fs_categories[]; /* file server data category names */
257 extern char *cm_categories[]; /* cache manager data category names */
261 #ifdef HAVE_STRCASESTR
262 extern char * strcasestr(const char *, const char *);
265 strcasestr(): Return first occurence of pattern s2 in s1, case
268 This routine is required since I made pattern matching of the
269 config file to be case insensitive.
284 return ((char *)NULL);
288 while (len1 >= len2 && len1 > 0) {
289 if ((strncasecmp(ptr, s2, len2)) == 0)
294 return ((char *)NULL);
299 GetHostByName(char *name)
306 he = gethostbyname(name);
308 /* On solaris the above does not resolve hostnames to full names */
310 memcpy(ip_addr, he->h_addr, he->h_length);
311 he = gethostbyaddr(ip_addr, he->h_length, he->h_addrtype);
318 /*-----------------------------------------------------------------------
322 * Exit gracefully from the afsmonitor. Frees memory where appropriate,
323 * cleans up after gtx and closes all open file descriptors. If a user
324 * provided threshold handler is to be exec'ed then gtx cleanup is
325 * not performed and an exec() is made instead of an exit().
331 * This function is called to execute a user handler only
332 * by a child process.
334 *----------------------------------------------------------------------*/
337 afsmon_Exit(int a_exitVal) /* exit code */
339 static char rn[] = "afsmon_Exit";
340 struct afsmon_fs_Results_list *tmp_fslist;
341 struct afsmon_fs_Results_list *next_fslist;
342 struct xstat_fs_ProbeResults *tmp_xstat_fsPR;
343 struct afsmon_cm_Results_list *tmp_cmlist;
344 struct afsmon_cm_Results_list *next_cmlist;
345 struct xstat_cm_ProbeResults *tmp_xstat_cmPR;
346 struct afsmon_hostEntry *curr_hostEntry;
347 struct afsmon_hostEntry *prev_hostEntry;
354 fprintf(debugFD, "[ %s ] Called with exit code %d\n", rn, a_exitVal);
358 /* get out of curses first, but not if we are here to exec a threshold
359 * handler. If we do, the screen gets messed up */
360 if (gtx_initialized && !exec_fsThreshHandler)
361 gator_cursesgwin_cleanup(afsmon_win);
363 /* print the error message buffer */
364 if (errMsg[0] != '\0')
365 fprintf(stderr, "%s", errMsg);
366 if (errMsg1[0] != '\0')
367 fprintf(stderr, "%s", errMsg1);
369 /* deallocate file server circular buffers */
370 if (numFS && num_bufSlots) {
372 fprintf(debugFD, "freeing FS circular buffers ");
376 for (bufslot = 0; bufslot < num_bufSlots; bufslot++) {
378 fprintf(debugFD, " %d) ", bufslot);
379 if (afsmon_fs_ResultsCB[bufslot].list !=
380 (struct afsmon_fs_Results_list *)0) {
381 tmp_fslist = afsmon_fs_ResultsCB[bufslot].list;
384 /* make sure we do not go astray */
388 "[ %s ] error in deallocating fs CB\n",
392 next_fslist = tmp_fslist->next;
393 tmp_xstat_fsPR = tmp_fslist->fsResults;
396 fprintf(debugFD, "%d ", numFS - j);
398 /* free xstat_fs_Results data */
399 free(tmp_xstat_fsPR->data.AFS_CollData_val);
400 free(tmp_xstat_fsPR->connP);
401 free(tmp_xstat_fsPR);
403 /* free the fs list item */
405 tmp_fslist = next_fslist;
407 } /* while fs list items in this slot */
408 } /* if entries in this buffer slot */
409 } /* for each fs buffer slot */
411 fprintf(debugFD, "\n");
416 /* deallocate cache manager curcular buffers */
417 if (numCM && num_bufSlots) {
419 fprintf(debugFD, "freeing CM curcular buffers ");
420 for (bufslot = 0; bufslot < num_bufSlots; bufslot++) {
422 fprintf(debugFD, " %d) ", bufslot);
423 if (afsmon_cm_ResultsCB[bufslot].list !=
424 (struct afsmon_cm_Results_list *)0) {
425 tmp_cmlist = afsmon_cm_ResultsCB[bufslot].list;
428 /* make sure we do not go astray */
432 "[ %s ] error in deallocating cm CB\n",
436 next_cmlist = tmp_cmlist->next;
437 tmp_xstat_cmPR = tmp_cmlist->cmResults;
440 fprintf(debugFD, "%d ", numCM - j);
441 /* make sure data is ok */
442 /* Print_cm_FullPerfInfo(tmp_xstat_cmPR); */
444 /* free xstat_cm_Results data */
445 free(tmp_xstat_cmPR->data.AFSCB_CollData_val);
446 free(tmp_xstat_cmPR->connP);
447 free(tmp_xstat_cmPR);
449 /* free the cm list item */
451 tmp_cmlist = next_cmlist;
453 } /* while cm list items in this slot */
454 } /* if entries in this buffer slot */
455 } /* for each cm buffer slot */
457 fprintf(debugFD, "\n");
461 /* deallocate FS & CM Print buffers */
462 if (curr_fsData != (struct fs_Display_Data *)0) {
464 fprintf(debugFD, "Deallocating FS Print Buffers .... curr");
467 if (prev_fsData != (struct fs_Display_Data *)0) {
469 fprintf(debugFD, ", prev \n");
472 if (prev_cmData != (struct cm_Display_Data *)0) {
474 fprintf(debugFD, "Deallocating CM Print Buffers .... curr");
477 if (prev_cmData != (struct cm_Display_Data *)0) {
479 fprintf(debugFD, ", prev \n");
483 /* deallocate hostEntry lists */
486 fprintf(debugFD, "Deallocating FS hostEntries ..");
487 curr_hostEntry = FSnameList;
488 for (i = 0; i < numFS; i++) {
489 prev_hostEntry = curr_hostEntry;
490 if (curr_hostEntry->thresh != NULL)
491 free(curr_hostEntry->thresh);
492 free(curr_hostEntry);
494 fprintf(debugFD, " %d", i);
495 curr_hostEntry = prev_hostEntry->next;
498 fprintf(debugFD, "\n");
502 fprintf(debugFD, "Deallocating CM hostEntries ..");
503 curr_hostEntry = CMnameList;
504 for (i = 0; i < numCM; i++) {
505 prev_hostEntry = curr_hostEntry;
506 if (curr_hostEntry->thresh != NULL)
507 free(curr_hostEntry->thresh);
508 free(curr_hostEntry);
510 fprintf(debugFD, " %d", i);
511 curr_hostEntry = prev_hostEntry->next;
514 fprintf(debugFD, "\n");
517 /* close debug file */
523 if (exec_fsThreshHandler) {
524 code = execvp(fsHandler_argv[0], fsHandler_argv);
526 fprintf(stderr, "execvp() of %s returned %d, errno %d\n",
527 fsHandler_argv[0], code, errno);
535 /*-----------------------------------------------------------------------
539 * Insert a hostname in the file server names list.
544 *----------------------------------------------------------------------*/
547 insert_FS(char *a_hostName) /* name of cache manager to be inserted in list */
549 static struct afsmon_hostEntry *curr_item;
550 static struct afsmon_hostEntry *prev_item;
552 if (*a_hostName == '\0')
554 curr_item = (struct afsmon_hostEntry *)
555 malloc(sizeof(struct afsmon_hostEntry));
556 if (curr_item == (struct afsmon_hostEntry *)0) {
557 fprintf(stderr, "Failed to allocate space for FS nameList\n");
561 strncpy(curr_item->hostName, a_hostName, CFG_STR_LEN);
562 curr_item->next = (struct afsmon_hostEntry *)0;
563 curr_item->numThresh = 0;
564 curr_item->thresh = NULL;
566 if (FSnameList == (struct afsmon_hostEntry *)0)
567 FSnameList = curr_item;
569 prev_item->next = curr_item;
571 prev_item = curr_item;
572 /* record the address of this entry so that its threshold
573 * count can be incremented during the first pass of the config file */
574 last_hostEntry = curr_item;
579 /*-----------------------------------------------------------------------
584 * Prints the file server names linked list.
588 *----------------------------------------------------------------------*/
592 static char rn[] = "print_FS";
593 struct afsmon_hostEntry *tempFS;
594 struct Threshold *threshP;
598 fprintf(debugFD, "[ %s ] Called\n", rn);
604 fprintf(debugFD, "No of File Servers: %d\n", numFS);
607 fprintf(debugFD, "\t %s threshCount = %d\n", tempFS->hostName,
609 threshP = tempFS->thresh;
610 for (i = 0; i < tempFS->numThresh; i++, threshP++)
611 fprintf(debugFD, "\t thresh (%2d) %s %s %s\n",
612 threshP->index, threshP->itemName,
613 threshP->threshVal, threshP->handler);
614 } while ((tempFS = tempFS->next) != (struct afsmon_hostEntry *)0);
616 fprintf(debugFD, "\t\t-----End of List-----\n");
622 /*-----------------------------------------------------------------------
626 * Insert a hostname in the cache manager names list.
631 *----------------------------------------------------------------------*/
634 insert_CM(char *a_hostName) /* name of cache manager to be inserted in list */
636 static struct afsmon_hostEntry *curr_item;
637 static struct afsmon_hostEntry *prev_item;
639 if (*a_hostName == '\0')
641 curr_item = (struct afsmon_hostEntry *)
642 malloc(sizeof(struct afsmon_hostEntry));
643 if (curr_item == (struct afsmon_hostEntry *)0) {
644 fprintf(stderr, "Failed to allocate space for CM nameList\n");
648 strncpy(curr_item->hostName, a_hostName, CFG_STR_LEN);
649 curr_item->next = (struct afsmon_hostEntry *)0;
650 curr_item->numThresh = 0;
651 curr_item->thresh = NULL;
653 if (CMnameList == (struct afsmon_hostEntry *)0)
654 CMnameList = curr_item;
656 prev_item->next = curr_item;
658 prev_item = curr_item;
659 /* side effect. note the address of this entry so that its threshold
660 * count can be incremented during the first pass of the config file */
661 last_hostEntry = curr_item;
667 /*-----------------------------------------------------------------------
672 * Prints the cache manager names linked list.
676 *----------------------------------------------------------------------*/
680 static char rn[] = "print_CM";
681 struct afsmon_hostEntry *tempCM;
682 struct Threshold *threshP;
686 fprintf(debugFD, "[ %s ] Called\n", rn);
692 fprintf(debugFD, "No of Cache Managers: %d\n", numCM);
695 fprintf(debugFD, "\t %s threshCount = %d\n", tempCM->hostName,
697 threshP = tempCM->thresh;
698 for (i = 0; i < tempCM->numThresh; i++, threshP++)
699 fprintf(debugFD, "\t thresh (%2d) %s %s %s\n",
700 threshP->index, threshP->itemName,
701 threshP->threshVal, threshP->handler);
702 } while ((tempCM = tempCM->next) != (struct afsmon_hostEntry *)0);
704 fprintf(debugFD, "\t\t-----End of List-----\n");
711 /*-----------------------------------------------------------------------
715 * Parse the host entry line in the config file. Check the syntax,
716 * and inserts the host name in the FS ot CM linked list. Also
717 * remember if this entry was an fs or cm & the ptr to its hostEntry
718 * structure. The threshold entries in the config file are dependent
719 * on their position relative to the hostname entries. Hence it is
720 * required to remember the names of the last file server and cache
721 * manager entries that were processed.
727 *----------------------------------------------------------------------*/
730 parse_hostEntry(char *a_line)
731 { /* parse_hostEntry */
733 static char rn[] = "parse_hostEntry"; /* routine name */
734 char opcode[CFG_STR_LEN]; /* specifies type of config entry */
735 char arg1[CFG_STR_LEN]; /* hostname or qualifier (fs/cm?) */
736 char arg2[CFG_STR_LEN]; /* threshold variable */
737 char arg3[CFG_STR_LEN]; /* threshold value */
738 char arg4[CFG_STR_LEN]; /* user's handler */
739 struct hostent *he; /* host entry */
742 fprintf(debugFD, "[ %s ] Called, a_line = %s\n", rn, a_line);
752 sscanf(a_line, "%s %s %s %s %s", opcode, arg1, arg2, arg3, arg4);
753 /* syntax is "opcode hostname" */
754 if ((strlen(arg2)) != 0) {
755 fprintf(stderr, "[ %s ] Extraneous characters at end of line\n", rn);
760 he = GetHostByName(arg1);
762 fprintf(stderr, "[ %s ] Unable to resolve hostname %s\n", rn, arg1);
766 if ((strcasecmp(opcode, "fs")) == 0) {
767 /* use the complete host name to insert in the file server names list */
768 insert_FS(he->h_name);
769 /* note that last host entry in the config file was fs */
772 /* threholds are not global anymore */
773 if (global_ThreshFlag)
774 global_ThreshFlag = 0;
775 } else if ((strcasecmp(opcode, "cm")) == 0) {
776 /* use the complete host name to insert in the CM names list */
777 insert_CM(he->h_name);
778 /* last host entry in the config file was cm */
781 /* threholds are not global anymore */
782 if (global_ThreshFlag)
783 global_ThreshFlag = 0;
790 /*-----------------------------------------------------------------------
791 * parse_threshEntry()
794 * Parse the threshold entry line in the config file. This function is
795 * called in the the first pass of the config file. It checks the syntax
796 * of the config lines and verifies their positional validity - eg.,
797 * a cm threshold cannot appear after a fs hostname entry, etc.
798 * It also counts the thresholds applicable to each host.
804 *----------------------------------------------------------------------*/
807 parse_threshEntry(char *a_line)
808 { /* parse_threshEntry */
809 static char rn[] = "parse_threshEntry"; /* routine name */
810 char opcode[CFG_STR_LEN]; /* specifies type of config entry */
811 char arg1[CFG_STR_LEN]; /* hostname or qualifier (fs/cm?) */
812 char arg2[CFG_STR_LEN]; /* threshold variable */
813 char arg3[CFG_STR_LEN]; /* threshold value */
814 char arg4[CFG_STR_LEN]; /* user's handler */
815 char arg5[CFG_STR_LEN]; /* junk characters */
818 fprintf(debugFD, "[ %s ] Called, a_line = %s\n", rn, a_line);
829 sscanf(a_line, "%s %s %s %s %s %s", opcode, arg1, arg2, arg3, arg4, arg5);
831 /* syntax is "thresh fs/cm variable_name threshold_value [handler] " */
832 if (((strlen(arg1)) == 0) || ((strlen(arg2)) == 0)
833 || ((strlen(arg3)) == 0)) {
834 fprintf(stderr, "[ %s ] Incomplete line\n", rn);
837 if (strlen(arg3) > THRESH_VAR_LEN - 2) {
838 fprintf(stderr, "[%s ] threshold value too long\n", rn);
842 if ((strcasecmp(arg1, "fs")) == 0) {
843 switch (lastHostType) {
844 case 0: /* its a global threshold */
845 global_fsThreshCount++;
847 case 1: /* inc thresh count of last file server */
848 last_hostEntry->numThresh++;
852 "[ %s ] A threshold for a File Server cannot be placed after a Cache Manager host entry in the config file \n",
856 fprintf(stderr, "[ %s ] Programming error 1\n", rn);
859 } else if ((strcasecmp(arg1, "cm")) == 0) {
860 switch (lastHostType) {
861 case 0: /* its a global threshold */
862 global_cmThreshCount++;
864 case 2: /* inc thresh count of last cache manager */
865 last_hostEntry->numThresh++;
869 "[ %s ] A threshold for a Cache Manager cannot be placed after a File Server host entry in the config file \n",
873 fprintf(stderr, "[ %s ] Programming error 2\n", rn);
878 "[ %s ] Syntax error. Second argument should be \"fs\" or \"cm\" \n",
884 } /* parse_threshEntry */
887 /*-----------------------------------------------------------------------
891 * The thresholds applicable to each host machine are stored in the
892 * FSnameList and CMnameList. Threshold entries in the config file are
893 * context sensitive. The host to which this threshold is applicable
894 * is pointed to by last_fsHost (for file servers) and last_cmHost
895 * for cache managers. For global thresholds the info is recorded for
896 * all the hosts. This function is called in the second pass of the
897 * config file. In the first pass a count of the number of global
898 * thresholds is determined and this information is used in this
899 * routine. If threshold entries are duplicated the first entry is
901 * Each threshold entry also has an index field. This is a positional
902 * index to the corresponding variable in the prev_[fs/cm]Data arrays.
903 * This makes it easy to check the threshold for overflow.
908 *----------------------------------------------------------------------*/
911 store_threshold(int a_type, /* 1 = fs , 2 = cm */
912 char *a_varName, /* threshold name */
913 char *a_value, /* threshold value */
914 char *a_handler) /* threshold overflow handler */
915 { /* store_thresholds */
917 static char rn[] = "store_thresholds"; /* routine name */
918 struct afsmon_hostEntry *tmp_host; /* tmp ptr to hostEntry */
919 struct afsmon_hostEntry *Header; /* tmp ptr to hostEntry list header */
920 struct Threshold *threshP; /* tmp ptr to threshold list */
922 int index; /* index to fs_varNames or cm_varNames */
925 int srvCount; /* tmp count of host names */
926 int *global_TC; /* ptr to global_xxThreshCount */
931 "[ %s ] Called, a_type= %d, a_varName= %s, a_value= %s, a_handler=%s\n",
932 rn, a_type, a_varName, a_value, a_handler);
936 /* resolve the threshold variable name */
938 if (a_type == 1) { /* fs threshold */
939 for (index = 0; index < NUM_FS_STAT_ENTRIES; index++) {
940 if (strcasecmp(a_varName, fs_varNames[index]) == 0) {
946 fprintf(stderr, "[ %s ] Unknown FS threshold variable name %s\n",
952 hostname = last_fsHost;
953 global_TC = &global_fsThreshCount;
954 } else if (a_type == 2) { /* cm threshold */
955 for (index = 0; index < NUM_CM_STAT_ENTRIES; index++) {
956 if (strcasecmp(a_varName, cm_varNames[index]) == 0) {
962 fprintf(stderr, "[ %s ] Unknown CM threshold variable name %s\n",
968 hostname = last_cmHost;
969 global_TC = &global_cmThreshCount;
975 /* if the global thresh count is not zero, place this threshold on
976 * all the host entries */
980 for (i = 0; i < srvCount; i++) {
981 threshP = tmp_host->thresh;
983 for (j = 0; j < tmp_host->numThresh; j++) {
984 if ((threshP->itemName[0] == '\0')
985 || (strcasecmp(threshP->itemName, a_varName) == 0)) {
986 strncpy(threshP->itemName, a_varName,
987 THRESH_VAR_NAME_LEN);
988 strncpy(threshP->threshVal, a_value, THRESH_VAR_LEN);
989 strcpy(threshP->handler, a_handler);
990 threshP->index = index;
997 fprintf(stderr, "[ %s ] Could not insert threshold entry",
999 fprintf(stderr, "for %s in thresh list of host %s \n",
1000 a_varName, tmp_host->hostName);
1003 tmp_host = tmp_host->next;
1009 /* it is not a global threshold, insert it in the thresh list of this
1010 * host only. We overwrite the global threshold if it was alread set */
1012 if (*hostname == '\0') {
1013 fprintf(stderr, "[ %s ] Programming error 3\n", rn);
1017 /* get the hostEntry that this threshold belongs to */
1020 for (i = 0; i < srvCount; i++) {
1021 if (strcasecmp(tmp_host->hostName, hostname) == 0) {
1025 tmp_host = tmp_host->next;
1028 fprintf(stderr, "[ %s ] Unable to find host %s in %s hostEntry list",
1029 rn, hostname, (a_type - 1) ? "CM" : "FS");
1033 /* put this entry on the thresh list of this host, overwrite global value
1036 threshP = tmp_host->thresh;
1038 for (i = 0; i < tmp_host->numThresh; i++) {
1039 if ((threshP->itemName[0] == '\0')
1040 || (strcasecmp(threshP->itemName, a_varName) == 0)) {
1041 strncpy(threshP->itemName, a_varName, THRESH_VAR_NAME_LEN);
1042 strncpy(threshP->threshVal, a_value, THRESH_VAR_LEN);
1043 strcpy(threshP->handler, a_handler);
1044 threshP->index = index;
1053 "[ %s ] Unable to insert threshold %s for %s host %s\n", rn,
1054 a_varName, (a_type - 1) ? "CM" : "FS", tmp_host->hostName);
1060 } /* store_thresholds */
1063 /*-----------------------------------------------------------------------
1067 * This function process a "show" entry in the config file. A "show"
1068 * entry specifies what statistics the user wants to see. File
1069 * server and Cache Manager data is divided into sections. Each section
1070 * is made up of one or more groups. If a group name is specified only
1071 * those statistics under that group are shown. If a section name is
1072 * specified all the groups under this section are shown.
1073 * Data as obtained from the xstat probes is considered to be ordered.
1074 * This data is mapped to the screen thru fs_Display_map[] and
1075 * cm_Display_map[]. This routine parses the "show" entry against the
1076 * section/group names in the [fs/cm]_categories[] array. If there is
1077 * no match it tries to match it against a variable name in
1078 * [fs/cm]_varNames[] array. In each case the corresponding indices to
1079 * the data is the [fs/cm]_displayInfo[] is recorded.
1083 * Failure: -1 (invalid entry)
1084 * > -1 (programming error)
1085 *----------------------------------------------------------------------*/
1088 parse_showEntry(char *a_line)
1089 { /* parse_showEntry */
1090 static char rn[] = "parse_showEntry";
1091 char opcode[CFG_STR_LEN]; /* specifies type of config entry */
1092 char arg1[CFG_STR_LEN]; /* show fs or cm entry ? */
1093 char arg2[CFG_STR_LEN]; /* what we gotta show */
1094 char arg3[CFG_STR_LEN]; /* junk */
1095 char catName[CFG_STR_LEN]; /* for category names */
1096 int numGroups; /* number of groups in a section */
1100 int idx = 0; /* index to fs_categories[] */
1106 fprintf(debugFD, "[ %s ] Called, a_line= %s\n", rn, a_line);
1113 sscanf(a_line, "%s %s %s %s", opcode, arg1, arg2, arg3);
1115 if (arg3[0] != '\0') {
1116 fprintf(stderr, "[ %s ] Extraneous characters at end of line\n", rn);
1120 if ((strcasecmp(arg1, "fs") != 0) && (strcasecmp(arg1, "cm") != 0)) {
1122 "[ %s ] Second argument of \"show\" directive should be \"fs\" or \"cm\" \n",
1127 /* Each entry can either be a variable name or a section/group name. Variable
1128 * names are listed in xx_varNames[] and section/group names in xx_categories[].
1129 * The section/group names in xx_categiries[] also give the starting/ending
1130 * indices of the variables belonging to that section/group. These indices
1131 * are stored in order in xx_Display_map[] and displayed to the screen in that
1134 /* To handle duplicate "show" entries we keep track of what what we have
1135 * already marked to show in the xx_showFlags[] */
1137 if (strcasecmp(arg1, "fs") == 0) { /* its a File Server entry */
1139 /* mark that we have to show only what the user wants */
1142 /* if it is a section/group name, find it in the fs_categories[] array */
1145 if (strcasestr(arg2, "_section") != (char *)NULL
1146 || strcasestr(arg2, "_group") != (char *)NULL) {
1148 while (idx < FS_NUM_DATA_CATEGORIES) {
1149 sscanf(fs_categories[idx], "%s %d %d", catName, &fromIdx,
1152 if (strcasecmp(arg2, catName) == 0) {
1158 if (!found) { /* typo in section/group name */
1160 "[ %s ] Could not find section/group name %s\n", rn,
1166 /* if it is a group name, read its start/end indices and fill in the
1167 * fs_Display_map[]. */
1169 if (strcasestr(arg2, "_group") != (char *)NULL) {
1171 if (fromIdx < 0 || toIdx < 0 || fromIdx > NUM_FS_STAT_ENTRIES
1172 || toIdx > NUM_FS_STAT_ENTRIES)
1174 for (j = fromIdx; j <= toIdx; j++) {
1175 if (!fs_showFlags[j]) {
1176 fs_Display_map[fs_DisplayItems_count] = j;
1177 fs_DisplayItems_count++;
1178 fs_showFlags[j] = 1;
1180 if (fs_DisplayItems_count > NUM_FS_STAT_ENTRIES) {
1181 fprintf(stderr, "[ %s ] fs_DisplayItems_count ovf\n", rn);
1186 /* if it is a section name, get the count of number of groups in it and
1187 * for each group fill in the start/end indices in the fs_Display_map[] */
1189 if (strcasestr(arg2, "_section") != (char *)NULL) {
1190 /* fromIdx is actually the number of groups in thi section */
1191 numGroups = fromIdx;
1192 /* for each group in section */
1193 while (idx < FS_NUM_DATA_CATEGORIES && numGroups) {
1194 sscanf(fs_categories[idx], "%s %d %d", catName, &fromIdx,
1197 if (strcasestr(catName, "_group") != NULL) {
1198 if (fromIdx < 0 || toIdx < 0
1199 || fromIdx > NUM_FS_STAT_ENTRIES
1200 || toIdx > NUM_FS_STAT_ENTRIES)
1202 for (j = fromIdx; j <= toIdx; j++) {
1203 if (!fs_showFlags[j]) {
1204 fs_Display_map[fs_DisplayItems_count] = j;
1205 fs_DisplayItems_count++;
1206 fs_showFlags[j] = 1;
1208 if (fs_DisplayItems_count > NUM_FS_STAT_ENTRIES) {
1210 "[ %s ] fs_DisplayItems_count ovf\n", rn);
1215 fprintf(stderr, "[ %s ] Error parsing groups for %s\n",
1221 } /* for each group in section */
1224 } else { /* it is a variable name */
1226 for (i = 0; i < NUM_FS_STAT_ENTRIES; i++) {
1227 if (strcasecmp(arg2, fs_varNames[i]) == 0) {
1228 if (!fs_showFlags[i]) {
1229 fs_Display_map[fs_DisplayItems_count] = i;
1230 fs_DisplayItems_count++;
1231 fs_showFlags[i] = 1;
1233 if (fs_DisplayItems_count >= NUM_FS_STAT_ENTRIES) {
1234 fprintf(stderr, "[ %s ] fs_DisplayItems_count ovf\n",
1241 if (!found) { /* typo in section/group name */
1242 fprintf(stderr, "[ %s ] Could not find variable name %s\n",
1246 } /* its a variable name */
1250 /* it is an fs entry */
1251 if (strcasecmp(arg1, "cm") == 0) { /* its a Cache Manager entry */
1254 /* mark that we have to show only what the user wants */
1257 /* if it is a section/group name, find it in the cm_categories[] array */
1260 if (strcasestr(arg2, "_section") != (char *)NULL
1261 || strcasestr(arg2, "_group") != (char *)NULL) {
1263 while (idx < CM_NUM_DATA_CATEGORIES) {
1264 sscanf(cm_categories[idx], "%s %d %d", catName, &fromIdx,
1267 if (strcasecmp(arg2, catName) == 0) {
1273 if (!found) { /* typo in section/group name */
1275 "[ %s ] Could not find section/group name %s\n", rn,
1281 /* if it is a group name, read its start/end indices and fill in the
1282 * cm_Display_map[]. */
1284 if (strcasestr(arg2, "_group") != (char *)NULL) {
1286 if (fromIdx < 0 || toIdx < 0 || fromIdx > NUM_CM_STAT_ENTRIES
1287 || toIdx > NUM_CM_STAT_ENTRIES)
1289 for (j = fromIdx; j <= toIdx; j++) {
1290 if (!cm_showFlags[j]) {
1291 cm_Display_map[cm_DisplayItems_count] = j;
1292 cm_DisplayItems_count++;
1293 cm_showFlags[j] = 1;
1295 if (cm_DisplayItems_count > NUM_CM_STAT_ENTRIES) {
1296 fprintf(stderr, "[ %s ] cm_DisplayItems_count ovf\n", rn);
1301 /* if it is a section name, get the count of number of groups in it and
1302 * for each group fill in the start/end indices in the cm_Display_map[] */
1304 if (strcasestr(arg2, "_section") != (char *)NULL) {
1305 /* fromIdx is actually the number of groups in thi section */
1306 numGroups = fromIdx;
1307 /* for each group in section */
1308 while (idx < CM_NUM_DATA_CATEGORIES && numGroups) {
1309 sscanf(cm_categories[idx], "%s %d %d", catName, &fromIdx,
1312 if (strcasestr(catName, "_group") != NULL) {
1313 if (fromIdx < 0 || toIdx < 0
1314 || fromIdx > NUM_CM_STAT_ENTRIES
1315 || toIdx > NUM_CM_STAT_ENTRIES)
1317 for (j = fromIdx; j <= toIdx; j++) {
1318 if (!cm_showFlags[j]) {
1319 cm_Display_map[cm_DisplayItems_count] = j;
1320 cm_DisplayItems_count++;
1321 cm_showFlags[j] = 1;
1323 if (cm_DisplayItems_count > NUM_CM_STAT_ENTRIES) {
1325 "[ %s ] cm_DisplayItems_count ovf\n", rn);
1330 fprintf(stderr, "[ %s ] Error parsing groups for %s\n",
1336 } /* for each group in section */
1337 } else { /* it is a variable name */
1339 for (i = 0; i < NUM_CM_STAT_ENTRIES; i++) {
1340 if (strcasecmp(arg2, cm_varNames[i]) == 0) {
1341 if (!cm_showFlags[i]) {
1342 cm_Display_map[cm_DisplayItems_count] = i;
1343 cm_DisplayItems_count++;
1344 cm_showFlags[i] = 1;
1346 if (cm_DisplayItems_count >= NUM_CM_STAT_ENTRIES) {
1347 fprintf(stderr, "[ %s ] cm_DisplayItems_count ovf\n",
1354 if (!found) { /* typo in section/group name */
1355 fprintf(stderr, "[ %s ] Could not find variable name %s\n",
1359 } /* its a variable name */
1362 /* it is an cm entry */
1364 } /* parse_showEntry */
1367 /*-----------------------------------------------------------------------
1368 * process_config_file()
1371 * Parse config file entries in two passes. In the first pass:
1372 * - the syntax of all the entries is checked
1373 * - host names are noted and the FSnamesList and CMnamesList
1375 * - a count of the global thresholds and local thresholds of
1376 * each host are counted.
1377 * - "show" entries are processed.
1378 * In the second pass:
1379 * - thresholds are stored
1383 * Failure: Exits afsmonitor showing error and line.
1384 *----------------------------------------------------------------------*/
1387 process_config_file(char *a_config_filename)
1388 { /* process_config_file() */
1389 static char rn[] = "process_config_file"; /* routine name */
1390 FILE *configFD; /* config file descriptor */
1391 char line[4 * CFG_STR_LEN]; /* a line of config file */
1392 char opcode[CFG_STR_LEN]; /* specifies type of config entry */
1393 char arg1[CFG_STR_LEN]; /* hostname or qualifier (fs/cm?) */
1394 char arg2[CFG_STR_LEN]; /* threshold variable */
1395 char arg3[CFG_STR_LEN]; /* threshold value */
1396 char arg4[CFG_STR_LEN]; /* user's handler */
1397 struct afsmon_hostEntry *curr_host;
1398 struct hostent *he; /* hostentry to resolve host name */
1399 char *handlerPtr; /* ptr to pass theresh handler string */
1400 int code = 0; /* error code */
1401 int linenum = 0; /* config file line number */
1402 int threshCount; /* count of thresholds for each server */
1403 int error_in_config; /* syntax errors in config file ?? */
1408 fprintf(debugFD, "[ %s ] Called, a_config_filename= %s\n", rn,
1413 /* open config file */
1415 configFD = fopen(a_config_filename, "r");
1416 if (configFD == (FILE *) 0) {
1417 fprintf(stderr, "Failed to open config file %s \n",
1420 fprintf(debugFD, "[ %s ] Failed to open config file %s \n", rn,
1427 /* parse config file */
1429 /* We process the config file in two passes. In the first pass we check
1430 * for correct syntax and for valid entries and also keep count of the
1431 * number of servers and thresholds to monitor. This the data strctures
1432 * can be arrays instead of link lists since we would know their sizes. */
1439 error_in_config = 0; /* flag to note if config file has syntax errors */
1441 while ((fgets(line, CFG_STR_LEN, configFD)) != NULL) {
1447 sscanf(line, "%s %s %s %s %s", opcode, arg1, arg2, arg3, arg4);
1449 /* skip blank lines and comment lines */
1450 if ((strlen(opcode) == 0) || line[0] == '#')
1453 if ((strcasecmp(opcode, "fs") == 0)
1454 || (strcasecmp(opcode, "cm")) == 0) {
1455 code = parse_hostEntry(line);
1456 } else if ((strcasecmp(opcode, "thresh")) == 0) {
1457 code = parse_threshEntry(line);
1458 } else if ((strcasecmp(opcode, "show")) == 0) {
1459 code = parse_showEntry(line);
1461 fprintf(stderr, "[ %s ] Unknown opcode %s\n", rn, opcode);
1466 fprintf(stderr, "[ %s ] Error in line:\n %d: %s\n", rn, linenum,
1468 error_in_config = 1;
1472 if (error_in_config)
1476 fprintf(debugFD, "Global FS thresholds count = %d\n",
1477 global_fsThreshCount);
1478 fprintf(debugFD, "Global CM thresholds count = %d\n",
1479 global_cmThreshCount);
1483 /* the threshold count of all hosts in increased by 1 for each global
1484 * threshold. If one of the hosts has a local threshold for the same
1485 * variable it would end up being counted twice. whats a few bytes of memory
1486 * wasted anyway ? */
1488 if (global_fsThreshCount) {
1489 curr_host = FSnameList;
1490 for (i = 0; i < numFS; i++) {
1491 curr_host->numThresh += global_fsThreshCount;
1492 curr_host = curr_host->next;
1495 if (global_cmThreshCount) {
1496 curr_host = CMnameList;
1497 for (i = 0; i < numCM; i++) {
1498 curr_host->numThresh += global_cmThreshCount;
1499 curr_host = curr_host->next;
1504 /* make sure we have something to monitor */
1505 if (numFS == 0 && numCM == 0) {
1507 "\nConfig file must specify atleast one File Server or Cache Manager host to monitor.\n");
1514 fseek(configFD, 0, 0); /* seek to the beginning */
1517 /* allocate memory for threshold lists */
1518 curr_host = FSnameList;
1519 for (i = 0; i < numFS; i++) {
1520 if (curr_host->hostName[0] == '\0') {
1521 fprintf(stderr, "[ %s ] Programming error 4\n", rn);
1524 if (curr_host->numThresh) {
1525 numBytes = curr_host->numThresh * sizeof(struct Threshold);
1526 curr_host->thresh = (struct Threshold *)malloc(numBytes);
1527 if (curr_host->thresh == NULL) {
1528 fprintf(stderr, "[ %s ] Memory Allocation error 1", rn);
1531 memset(curr_host->thresh, 0, numBytes);
1533 curr_host = curr_host->next;;
1536 curr_host = CMnameList;
1537 for (i = 0; i < numCM; i++) {
1538 if (curr_host->hostName[0] == '\0') {
1539 fprintf(stderr, "[ %s ] Programming error 5\n", rn);
1542 if (curr_host->numThresh) {
1543 numBytes = curr_host->numThresh * sizeof(struct Threshold);
1544 curr_host->thresh = (struct Threshold *)malloc(numBytes);
1545 if (curr_host->thresh == NULL) {
1546 fprintf(stderr, "[ %s ] Memory Allocation error 2", rn);
1549 memset(curr_host->thresh, 0, numBytes);
1551 curr_host = curr_host->next;;
1560 last_fsHost[0] = '\0';
1561 last_cmHost[0] = '\0';
1563 while ((fgets(line, CFG_STR_LEN, configFD)) != NULL) {
1569 sscanf(line, "%s %s %s %s %s", opcode, arg1, arg2, arg3, arg4);
1572 /* if we have a host entry, remember the host name */
1573 if (strcasecmp(opcode, "fs") == 0) {
1574 he = GetHostByName(arg1);
1575 strncpy(last_fsHost, he->h_name, HOST_NAME_LEN);
1576 } else if (strcasecmp(opcode, "cm") == 0) {
1577 he = GetHostByName(arg1);
1578 strncpy(last_cmHost, he->h_name, HOST_NAME_LEN);
1579 } else if (strcasecmp(opcode, "thresh") == 0) {
1580 /* if we have a threshold handler it may have arguments
1581 * and the sscanf() above would not get them, so do the
1585 /* now skip over 4 words - this is done by first
1586 * skipping leading blanks then skipping a word */
1587 for (i = 0; i < 4; i++) {
1588 while (isspace(*handlerPtr))
1590 while (!isspace(*handlerPtr))
1593 while (isspace(*handlerPtr))
1595 /* we how have a pointer to the start of the handler
1598 handlerPtr = arg4; /* empty string */
1601 if (strcasecmp(arg1, "fs") == 0)
1602 code = store_threshold(1, /* 1 = fs */
1603 arg2, arg3, handlerPtr);
1605 else if (strcasecmp(arg1, "cm") == 0)
1606 code = store_threshold(2, /* 2 = fs */
1607 arg2, arg3, handlerPtr);
1610 fprintf(stderr, "[ %s ] Programming error 6\n", rn);
1614 fprintf(stderr, "[ %s ] Failed to store threshold\n", rn);
1615 fprintf(stderr, "[ %s ] Error processing line:\n%d: %s", rn,
1627 /*-----------------------------------------------------------------------
1632 * Print the File Server circular buffer.
1636 *----------------------------------------------------------------------*/
1640 { /* Print_FS_CB() */
1642 struct afsmon_fs_Results_list *fslist;
1646 /* print valid info in the fs CB */
1650 "==================== FS Buffer ========================\n");
1651 fprintf(debugFD, "afsmon_fs_curr_CBindex = %d\n",
1652 afsmon_fs_curr_CBindex);
1653 fprintf(debugFD, "afsmon_fs_curr_probeNum = %d\n\n",
1654 afsmon_fs_curr_probeNum);
1656 for (i = 0; i < num_bufSlots; i++) {
1657 fprintf(debugFD, "\t--------- slot %d ----------\n", i);
1658 fslist = afsmon_fs_ResultsCB[i].list;
1661 if (!fslist->empty) {
1662 fprintf(debugFD, "\t %d) probeNum = %d host = %s", j,
1663 fslist->fsResults->probeNum,
1664 fslist->fsResults->connP->hostName);
1665 if (fslist->fsResults->probeOK)
1666 fprintf(debugFD, " NOTOK\n");
1668 fprintf(debugFD, " OK\n");
1670 fprintf(debugFD, "\t %d) -- empty --\n", j);
1671 fslist = fslist->next;
1674 if (fslist != (struct afsmon_fs_Results_list *)0)
1675 fprintf(debugFD, "dangling last next ptr fs CB\n");
1678 } /* Print_FS_CB() */
1680 /*-----------------------------------------------------------------------
1681 * save_FS_results_inCB()
1684 * Saves the results of the latest FS probe in the fs circular
1685 * buffers. If the current probe cycle is in progress the contents
1686 * of xstat_fs_Results are copied to the end of the list of results
1687 * in the current slot (pointed to by afsmon_fs_curr_CBindex). If
1688 * a new probe cycle has started the next slot in the circular buffer
1689 * is initialized and the results copied. Note that the Rx related
1690 * information available in xstat_fs_Results is not copied.
1694 * Failure: Exits afsmonitor.
1695 *----------------------------------------------------------------------*/
1697 save_FS_results_inCB(int a_newProbeCycle) /* start of a new probe cycle ? */
1698 { /* save_FS_results_inCB() */
1699 static char rn[] = "save_FS_results_inCB"; /* routine name */
1700 struct afsmon_fs_Results_list *tmp_fslist_item; /* temp fs list item */
1701 struct xstat_fs_ProbeResults *tmp_fsPR; /* temp ptr */
1705 fprintf(debugFD, "[ %s ] Called, a_newProbeCycle= %d\n", rn,
1711 /* If a new probe cycle started, mark the list in the current buffer
1712 * slot empty for resuse. Note that afsmon_fs_curr_CBindex was appropriately
1713 * incremented in afsmon_FS_Handler() */
1715 if (a_newProbeCycle) {
1716 tmp_fslist_item = afsmon_fs_ResultsCB[afsmon_fs_curr_CBindex].list;
1717 for (i = 0; i < numFS; i++) {
1718 tmp_fslist_item->empty = 1;
1719 tmp_fslist_item = tmp_fslist_item->next;
1723 /* locate last unused item in list */
1724 tmp_fslist_item = afsmon_fs_ResultsCB[afsmon_fs_curr_CBindex].list;
1725 for (i = 0; i < numFS; i++) {
1726 if (tmp_fslist_item->empty)
1728 tmp_fslist_item = tmp_fslist_item->next;
1731 /* if we could not find one we have an inconsistent list */
1732 if (!tmp_fslist_item->empty) {
1734 "[ %s ] list inconsistency 1. unable to find an empty slot to store results of probenum %d of %s\n",
1735 rn, xstat_fs_Results.probeNum,
1736 xstat_fs_Results.connP->hostName);
1740 tmp_fsPR = tmp_fslist_item->fsResults;
1742 /* copy hostname and probe number and probe time and probe status.
1743 * if the probe failed return now */
1745 memcpy(tmp_fsPR->connP->hostName, xstat_fs_Results.connP->hostName,
1746 sizeof(xstat_fs_Results.connP->hostName));
1747 tmp_fsPR->probeNum = xstat_fs_Results.probeNum;
1748 tmp_fsPR->probeTime = xstat_fs_Results.probeTime;
1749 tmp_fsPR->probeOK = xstat_fs_Results.probeOK;
1750 if (xstat_fs_Results.probeOK) { /* probeOK = 1 => notOK */
1751 /* we have a nonempty results structure so mark the list item used */
1752 tmp_fslist_item->empty = 0;
1756 /* copy connection information */
1757 memcpy(&(tmp_fsPR->connP->skt), &(xstat_fs_Results.connP->skt),
1758 sizeof(struct sockaddr_in));
1760 memcpy(tmp_fsPR->connP->hostName, xstat_fs_Results.connP->hostName,
1761 sizeof(xstat_fs_Results.connP->hostName));
1762 tmp_fsPR->collectionNumber = xstat_fs_Results.collectionNumber;
1764 /* copy the probe data information */
1765 tmp_fsPR->data.AFS_CollData_len = xstat_fs_Results.data.AFS_CollData_len;
1766 memcpy(tmp_fsPR->data.AFS_CollData_val,
1767 xstat_fs_Results.data.AFS_CollData_val,
1768 xstat_fs_Results.data.AFS_CollData_len * sizeof(afs_int32));
1771 /* we have a valid results structure so mark the list item used */
1772 tmp_fslist_item->empty = 0;
1774 /* Print the fs circular buffer */
1778 } /* save_FS_results_inCB() */
1781 /*-----------------------------------------------------------------------
1785 * The results of xstat probes are stored in a string format in
1786 * the arrays curr_fsData and prev_fsData. The information stored in
1787 * prev_fsData is copied to the screen.
1788 * This function converts xstat FS results from longs to strings and
1789 * place them in the given buffer (a pointer to an item in curr_fsData).
1790 * When a probe cycle completes, curr_fsData is copied to prev_fsData
1791 * in afsmon_FS_Hnadler().
1795 *----------------------------------------------------------------------*/
1798 fs_Results_ltoa(struct fs_Display_Data *a_fsData, /* target buffer */
1799 struct xstat_fs_ProbeResults *a_fsResults) /* ptr to xstat fs Results */
1800 { /* fs_Results_ltoa */
1802 static char rn[] = "fs_Results_ltoa"; /* routine name */
1804 struct fs_stats_FullPerfStats *fullPerfP;
1810 fprintf(debugFD, "[ %s ] Called, a_fsData= %p, a_fsResults= %p\n", rn,
1811 a_fsData, a_fsResults);
1815 fullPerfP = (struct fs_stats_FullPerfStats *)
1816 (a_fsResults->data.AFS_CollData_val);
1818 /* there are two parts to the xstat FS statistics
1819 * - fullPerfP->overall which give the overall performance statistics, and
1820 * - fullPerfP->det which gives detailed info about file server operation
1821 * execution times */
1823 /* copy overall performance statistics */
1824 srcbuf = (afs_int32 *) & (fullPerfP->overall);
1826 for (i = 0; i < NUM_XSTAT_FS_AFS_PERFSTATS_LONGS; i++) {
1827 sprintf(a_fsData->data[idx], "%d", *srcbuf);
1833 srcbuf = (afs_int32 *) & (fullPerfP->det.epoch);
1834 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* epoch */
1837 /* copy fs operation timing */
1839 srcbuf = (afs_int32 *) (fullPerfP->det.rpcOpTimes);
1841 for (i = 0; i < FS_STATS_NUM_RPC_OPS; i++) {
1842 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* numOps */
1845 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* numSuccesses */
1848 tmpbuf = srcbuf++; /* sum time */
1849 sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1852 tmpbuf = srcbuf++; /* sqr time */
1853 sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1856 tmpbuf = srcbuf++; /* min time */
1857 sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1860 tmpbuf = srcbuf++; /* max time */
1861 sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1866 /* copy fs transfer timings */
1868 srcbuf = (afs_int32 *) (fullPerfP->det.xferOpTimes);
1869 for (i = 0; i < FS_STATS_NUM_XFER_OPS; i++) {
1870 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* numOps */
1873 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* numSuccesses */
1876 tmpbuf = srcbuf++; /* sum time */
1877 sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1880 tmpbuf = srcbuf++; /* sqr time */
1881 sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1884 tmpbuf = srcbuf++; /* min time */
1885 sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1888 tmpbuf = srcbuf++; /* max time */
1889 sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1892 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* sum bytes */
1895 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* min bytes */
1898 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* max bytes */
1901 for (j = 0; j < FS_STATS_NUM_XFER_BUCKETS; j++) {
1902 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* bucket[j] */
1909 } /* fs_Results_ltoa */
1913 /*-----------------------------------------------------------------------
1914 * execute_thresh_handler()
1917 * Execute a threshold handler. An agrv[] array of pointers is
1918 * constructed from the given data. A child process is forked
1919 * which immediately calls afsmon_Exit() with indication that a
1920 * threshold handler is to be exec'ed insted of exiting.
1924 * Failure: Afsmonitor exits if threshold handler has more than 20 args.
1925 *----------------------------------------------------------------------*/
1928 execute_thresh_handler(char *a_handler, /* ptr to handler function + args */
1929 char *a_hostName, /* host name for which threshold crossed */
1930 int a_hostType, /* fs or cm ? */
1931 char *a_threshName, /* threshold variable name */
1932 char *a_threshValue, /* threshold value */
1933 char *a_actValue) /* actual value */
1934 { /* execute_thresh_handler */
1936 static char rn[] = "execute_thresh_handler";
1937 char fileName[256]; /* file name to execute */
1942 int anotherArg; /* boolean used to flag if another arg is available */
1946 "[ %s ] Called, a_handler= %s, a_hostName= %s, a_hostType= %d, a_threshName= %s, a_threshValue= %s, a_actValue= %s\n",
1947 rn, a_handler, a_hostName, a_hostType, a_threshName,
1948 a_threshValue, a_actValue);
1953 /* get the filename to execute - the first argument */
1954 sscanf(a_handler, "%s", fileName);
1956 /* construct the contents of *argv[] */
1958 strncpy(fsHandler_args[0], fileName, 256);
1959 strncpy(fsHandler_args[1], a_hostName, HOST_NAME_LEN);
1960 if (a_hostType == FS)
1961 strcpy(fsHandler_args[2], "fs");
1963 strcpy(fsHandler_args[2], "cm");
1964 strncpy(fsHandler_args[3], a_threshName, THRESH_VAR_NAME_LEN);
1965 strncpy(fsHandler_args[4], a_threshValue, THRESH_VAR_LEN);
1966 strncpy(fsHandler_args[5], a_actValue, THRESH_VAR_LEN);
1973 /* we have already extracted the file name so skip to the 1st arg */
1974 while (isspace(*ch)) /* leading blanks */
1976 while (!isspace(*ch) && *ch != '\0') /* handler filename */
1979 while (*ch != '\0') {
1982 } else if (anotherArg) {
1984 sscanf(ch, "%s", fsHandler_args[argNum]);
1990 "Threshold handlers cannot have more than 20 arguments\n");
1996 fsHandler_argv[argNum] = NULL;
1997 for (i = 0; i < argNum; i++)
1998 fsHandler_argv[i] = fsHandler_args[i];
2001 /* exec the threshold handler */
2004 exec_fsThreshHandler = 1;
2005 code = afsmon_Exit(60);
2009 } /* execute_thresh_handler */
2013 /*-----------------------------------------------------------------------
2014 * check_fs_thresholds()
2017 * Checks the thresholds and sets the overflow flag. Recall that the
2018 * thresholds for each host are stored in the hostEntry lists
2019 * [fs/cm]nameList arrays. The probe results are passed to this
2020 * function in the display-ready format - ie., as strings. Though
2021 * this looks stupid the overhead incurred in converting the strings
2022 * back to floats and comparing them is insignificant and
2023 * programming is easier this way.
2024 * The threshold flags are a part of the display structures
2029 *----------------------------------------------------------------------*/
2032 check_fs_thresholds(struct afsmon_hostEntry *a_hostEntry, /* ptr to hostEntry */
2033 struct fs_Display_Data *a_Data) /* ptr to fs data to be displayed */
2034 { /* check_fs_thresholds */
2036 static char rn[] = "check_fs_thresholds";
2037 struct Threshold *threshP;
2038 double tValue; /* threshold value */
2039 double pValue; /* probe value */
2042 int count; /* number of thresholds exceeded */
2045 fprintf(debugFD, "[ %s ] Called, a_hostEntry= %p, a_Data= %p\n", rn,
2046 a_hostEntry, a_Data);
2050 if (a_hostEntry->numThresh == 0) {
2051 /* store in ovf count ?? */
2056 threshP = a_hostEntry->thresh;
2057 for (i = 0; i < a_hostEntry->numThresh; i++) {
2058 if (threshP->itemName[0] == '\0') {
2062 idx = threshP->index; /* positional index to the data array */
2063 tValue = atof(threshP->threshVal); /* threshold value */
2064 pValue = atof(a_Data->data[idx]); /* probe value */
2065 if (pValue > tValue) {
2069 "[ %s ] fs = %s, thresh ovf for %s, threshold= %s, probevalue= %s\n",
2070 rn, a_hostEntry->hostName, threshP->itemName,
2071 threshP->threshVal, a_Data->data[idx]);
2074 /* if the threshold is crossed, call the handler function
2075 * only if this was a transition -ie, if the threshold was
2076 * crossed in the last probe too just count & keep quite! */
2078 if (!a_Data->threshOvf[idx]) {
2079 a_Data->threshOvf[idx] = 1;
2080 /* call the threshold handler if provided */
2081 if (threshP->handler[0] != '\0') {
2083 fprintf(debugFD, "[ %s ] Calling ovf handler %s\n",
2084 rn, threshP->handler);
2087 execute_thresh_handler(threshP->handler, a_Data->hostName,
2088 FS, threshP->itemName,
2096 /* in case threshold was previously crossed, blank it out */
2097 a_Data->threshOvf[idx] = 0;
2100 /* store the overflow count */
2101 a_Data->ovfCount = count;
2104 } /* check_fs_thresholds */
2107 /*-----------------------------------------------------------------------
2108 * save_FS_data_forDisplay()
2111 * Does the following:
2112 * - if the probe number changed (ie, a cycle completed) curr_fsData
2113 * is copied to prev_fsData, curr_fsData zeroed and refresh the
2114 * overview screen and file server screen with the new data.
2115 * - store the results of the current probe from xstat_fs_Results into
2116 * curr_fsData. ie., convert longs to strings.
2117 * - check the thresholds
2121 * Failure: Exits afsmonitor.
2122 *----------------------------------------------------------------------*/
2125 save_FS_data_forDisplay(struct xstat_fs_ProbeResults *a_fsResults)
2126 { /* save_FS_data_forDisplay */
2128 static char rn[] = "save_FS_data_forDisplay"; /* routine name */
2129 struct fs_Display_Data *curr_fsDataP; /* tmp ptr to curr_fsData */
2130 struct fs_Display_Data *prev_fsDataP; /* tmp ptr to prev_fsData */
2131 struct afsmon_hostEntry *curr_host;
2132 static int probes_Received = 0; /* number of probes reveived in
2133 * the current cycle. If this is equal to numFS we got all
2134 * the data we want in this cycle and can now display it */
2143 fprintf(debugFD, "[ %s ] Called, a_fsResults= %p\n", rn, a_fsResults);
2147 /* store results in the display array */
2150 curr_fsDataP = curr_fsData;
2151 for (i = 0; i < numFS; i++) {
2152 if ((strcasecmp(curr_fsDataP->hostName, a_fsResults->connP->hostName))
2162 "[ %s ] Could not insert FS probe results for host %s in fs display array\n",
2163 rn, a_fsResults->connP->hostName);
2167 /* Check the status of the probe. If it succeeded, we store its
2168 * results in the display data structure. If it failed we only mark
2169 * the failed status in the display data structure. */
2171 if (a_fsResults->probeOK) { /* 1 => notOK the xstat results */
2172 curr_fsDataP->probeOK = 0;
2174 /* print the probe status */
2176 fprintf(debugFD, "\n\t\t ----- fs display data ------\n");
2177 fprintf(debugFD, "HostName = %s PROBE FAILED \n",
2178 curr_fsDataP->hostName);
2182 } else { /* probe succeeded, update display data structures */
2183 curr_fsDataP->probeOK = 1;
2185 /* covert longs to strings and place them in curr_fsDataP */
2186 fs_Results_ltoa(curr_fsDataP, a_fsResults);
2188 /* compare with thresholds and set the overflow flags.
2189 * note that the threshold information is in the hostEntry structure and
2190 * each threshold item has a positional index associated with it */
2192 /* locate the hostEntry for this host */
2194 curr_host = FSnameList;
2195 for (i = 0; i < numFS; i++) {
2196 if (strcasecmp(curr_host->hostName, a_fsResults->connP->hostName)
2201 curr_host = curr_host->next;;
2206 code = check_fs_thresholds(curr_host, curr_fsDataP);
2208 fprintf(stderr, "[ %s ] Error in checking thresholds\n", rn);
2212 /* print the info we just saved */
2215 fprintf(debugFD, "\n\t\t ----- fs display data ------\n");
2216 fprintf(debugFD, "HostName = %s\n", curr_fsDataP->hostName);
2217 for (i = 0; i < NUM_FS_STAT_ENTRIES; i++)
2218 fprintf(debugFD, "%20s %30s %s\n", curr_fsDataP->data[i],
2220 curr_fsDataP->threshOvf[i] ? "(ovf)" : "");
2222 fprintf(debugFD, "\t\t--------------------------------\n\n");
2226 } /* the probe succeeded, so we store the data in the display structure */
2229 /* if we have received a reply from all the hosts for this probe cycle,
2230 * it is time to display the data */
2233 if (probes_Received == numFS) {
2234 probes_Received = 0;
2236 if (afsmon_fs_curr_probeNum != afsmon_fs_prev_probeNum + 1) {
2237 sprintf(errMsg, "[ %s ] Probe number %d missed! \n", rn,
2238 afsmon_fs_prev_probeNum + 1);
2241 afsmon_fs_prev_probeNum++;
2243 /* backup the display data of the probe cycle that just completed -
2244 * ie., store curr_fsData in prev_fsData */
2246 memcpy((char *)prev_fsData, (char *)curr_fsData,
2247 (numFS * sizeof(struct fs_Display_Data)));
2250 /* initialize curr_fsData but retain the threshold flag information.
2251 * The previous state of threshold flags is used in check_fs_thresholds() */
2253 numBytes = NUM_FS_STAT_ENTRIES * CM_STAT_STRING_LEN;
2254 curr_fsDataP = curr_fsData;
2255 for (i = 0; i < numFS; i++) {
2256 curr_fsDataP->probeOK = 0;
2257 curr_fsDataP->ovfCount = 0;
2258 memset((char *)curr_fsDataP->data, 0, numBytes);
2263 /* prev_fsData now contains all the information for the probe cycle
2264 * that just completed. Now count the number of threshold overflows for
2265 * use in the overview screen */
2267 prev_fsDataP = prev_fsData;
2269 numHosts_onfs_alerts = 0;
2270 for (i = 0; i < numFS; i++) {
2271 if (!prev_fsDataP->probeOK) { /* if probe failed */
2273 numHosts_onfs_alerts++;
2275 if (prev_fsDataP->ovfCount) { /* overflows ?? */
2276 num_fs_alerts += prev_fsDataP->ovfCount;
2277 numHosts_onfs_alerts++;
2282 fprintf(debugFD, "Number of FS alerts = %d (on %d hosts)\n",
2283 num_fs_alerts, numHosts_onfs_alerts);
2285 /* flag that the data is now ready to be displayed */
2286 fs_Data_Available = 1;
2288 /* call the Overview frame update routine (update only FS info) */
2289 ovw_refresh(ovw_currPage, OVW_UPDATE_FS);
2291 /* call the File Servers frame update routine */
2292 fs_refresh(fs_currPage, fs_curr_LCol);
2297 } /* save_FS_data_forDisplay */
2302 /*-----------------------------------------------------------------------
2303 * afsmon_FS_Handler()
2306 * This is the File Server probe Handler. It updates the afsmonitor
2307 * probe counts, fs circular buffer indices and calls the functions
2308 * to process the results of this probe.
2312 * Failure: Exits afsmonitor.
2313 *----------------------------------------------------------------------*/
2316 afsmon_FS_Handler(void)
2317 { /* afsmon_FS_Handler() */
2318 static char rn[] = "afsmon_FS_Handler"; /* routine name */
2319 int newProbeCycle; /* start of new probe cycle ? */
2320 int code; /* return status */
2325 "[ %s ] Called, hostName= %s, probeNum= %d, status=%s\n", rn,
2326 xstat_fs_Results.connP->hostName, xstat_fs_Results.probeNum,
2327 xstat_fs_Results.probeOK ? "FAILED" : "OK");
2332 /* print the probe results to output file */
2333 if (afsmon_output) {
2334 code = afsmon_fsOutput(output_filename, afsmon_detOutput);
2337 "[ %s ] output to file %s returned error code=%d\n", rn,
2338 output_filename, code);
2342 /* Update current probe number and circular buffer index. if current
2343 * probenum changed make sure it is only by 1 */
2346 if (xstat_fs_Results.probeNum != afsmon_fs_curr_probeNum) {
2347 if (xstat_fs_Results.probeNum == afsmon_fs_curr_probeNum + 1) {
2348 afsmon_fs_curr_probeNum++;
2351 afsmon_fs_curr_CBindex =
2352 (afsmon_fs_curr_probeNum - 1) % num_bufSlots;
2354 fprintf(stderr, "[ %s ] probe number %d-1 missed\n", rn,
2355 xstat_fs_Results.probeNum);
2360 /* store the results of this probe in the FS circular buffer */
2362 save_FS_results_inCB(newProbeCycle);
2365 /* store the results of the current probe in the fs data display structure.
2366 * if the current probe number changed, swap the current and previous display
2367 * structures. note that the display screen is updated from these structures
2368 * and should start showing the data of the just completed probe cycle */
2370 save_FS_data_forDisplay(&xstat_fs_Results);
2377 /*----------------------------------------------------------------------- *
2382 * Prints the Cache Manager circular buffer
2383 *----------------------------------------------------------------------*/
2387 { /* Print_CM_CB() */
2389 struct afsmon_cm_Results_list *cmlist;
2393 /* print valid info in the cm CB */
2397 "==================== CM Buffer ========================\n");
2398 fprintf(debugFD, "afsmon_cm_curr_CBindex = %d\n",
2399 afsmon_cm_curr_CBindex);
2400 fprintf(debugFD, "afsmon_cm_curr_probeNum = %d\n\n",
2401 afsmon_cm_curr_probeNum);
2403 for (i = 0; i < num_bufSlots; i++) {
2404 fprintf(debugFD, "\t--------- slot %d ----------\n", i);
2405 cmlist = afsmon_cm_ResultsCB[i].list;
2408 if (!cmlist->empty) {
2409 fprintf(debugFD, "\t %d) probeNum = %d host = %s", j,
2410 cmlist->cmResults->probeNum,
2411 cmlist->cmResults->connP->hostName);
2412 if (cmlist->cmResults->probeOK)
2413 fprintf(debugFD, " NOTOK\n");
2415 fprintf(debugFD, " OK\n");
2417 fprintf(debugFD, "\t %d) -- empty --\n", j);
2418 cmlist = cmlist->next;
2421 if (cmlist != (struct afsmon_cm_Results_list *)0)
2422 fprintf(debugFD, "dangling last next ptr cm CB\n");
2428 /*-----------------------------------------------------------------------
2429 * save_CM_results_inCB()
2432 * Saves the results of the latest CM probe in the cm circular
2433 * buffers. If the current probe cycle is in progress the contents
2434 * of xstat_cm_Results are copied to the end of the list of results
2435 * in the current slot (pointed to by afsmon_cm_curr_CBindex). If
2436 * a new probe cycle has started the next slot in the circular buffer
2437 * is initialized and the results copied. Note that the Rx related
2438 * information available in xstat_cm_Results is not copied.
2442 * Failure: Exits afsmonitor.
2443 *----------------------------------------------------------------------*/
2446 save_CM_results_inCB(int a_newProbeCycle) /* start of new probe cycle ? */
2447 { /* save_CM_results_inCB() */
2448 static char rn[] = "save_CM_results_inCB"; /* routine name */
2449 struct afsmon_cm_Results_list *tmp_cmlist_item; /* temp cm list item */
2450 struct xstat_cm_ProbeResults *tmp_cmPR; /* temp ptr */
2455 fprintf(debugFD, "[ %s ] Called, a_newProbeCycle= %d\n", rn,
2460 /* If a new probe cycle started, mark the list in the current buffer
2461 * slot empty for resuse. Note that afsmon_cm_curr_CBindex was appropriately
2462 * incremented in afsmon_CM_Handler() */
2464 if (a_newProbeCycle) {
2465 tmp_cmlist_item = afsmon_cm_ResultsCB[afsmon_cm_curr_CBindex].list;
2466 for (i = 0; i < numCM; i++) {
2467 tmp_cmlist_item->empty = 1;
2468 tmp_cmlist_item = tmp_cmlist_item->next;
2472 /* locate last unused item in list */
2473 tmp_cmlist_item = afsmon_cm_ResultsCB[afsmon_cm_curr_CBindex].list;
2474 for (i = 0; i < numCM; i++) {
2475 if (tmp_cmlist_item->empty)
2477 tmp_cmlist_item = tmp_cmlist_item->next;
2480 /* if we could not find one we have an inconsistent list */
2481 if (!tmp_cmlist_item->empty) {
2483 "[ %s ] list inconsistency 1. unable to find an empty slot to store results of probenum %d of %s\n",
2484 rn, xstat_cm_Results.probeNum,
2485 xstat_cm_Results.connP->hostName);
2489 tmp_cmPR = tmp_cmlist_item->cmResults;
2491 /* copy hostname and probe number and probe time and probe status.
2492 * if the probe failed return now */
2494 memcpy(tmp_cmPR->connP->hostName, xstat_cm_Results.connP->hostName,
2495 sizeof(xstat_cm_Results.connP->hostName));
2496 tmp_cmPR->probeNum = xstat_cm_Results.probeNum;
2497 tmp_cmPR->probeTime = xstat_cm_Results.probeTime;
2498 tmp_cmPR->probeOK = xstat_cm_Results.probeOK;
2499 if (xstat_cm_Results.probeOK) { /* probeOK = 1 => notOK */
2500 /* we have a nonempty results structure so mark the list item used */
2501 tmp_cmlist_item->empty = 0;
2506 /* copy connection information */
2507 memcpy(&(tmp_cmPR->connP->skt), &(xstat_cm_Results.connP->skt),
2508 sizeof(struct sockaddr_in));
2510 /**** NEED TO COPY rx_connection INFORMATION HERE ******/
2512 memcpy(tmp_cmPR->connP->hostName, xstat_cm_Results.connP->hostName,
2513 sizeof(xstat_cm_Results.connP->hostName));
2514 tmp_cmPR->collectionNumber = xstat_cm_Results.collectionNumber;
2516 /* copy the probe data information */
2517 tmp_cmPR->data.AFSCB_CollData_len =
2518 xstat_cm_Results.data.AFSCB_CollData_len;
2519 memcpy(tmp_cmPR->data.AFSCB_CollData_val,
2520 xstat_cm_Results.data.AFSCB_CollData_val,
2521 xstat_cm_Results.data.AFSCB_CollData_len * sizeof(afs_int32));
2524 /* we have a valid results structure so mark the list item used */
2525 tmp_cmlist_item->empty = 0;
2527 /* print the stored info - to make sure we copied it right */
2528 /* Print_cm_FullPerfInfo(tmp_cmPR); */
2529 /* Print the cm circular buffer */
2532 } /* save_CM_results_inCB */
2536 /*-----------------------------------------------------------------------
2540 * The results of xstat probes are stored in a string format in
2541 * the arrays curr_cmData and prev_cmData. The information stored in
2542 * prev_cmData is copied to the screen.
2543 * This function converts xstat FS results from longs to strings and
2544 * places them in the given buffer (a pointer to an item in curr_cmData).
2545 * When a probe cycle completes, curr_cmData is copied to prev_cmData
2546 * in afsmon_CM_Handler().
2550 *----------------------------------------------------------------------*/
2553 cm_Results_ltoa(struct cm_Display_Data *a_cmData, /* target buffer */
2554 struct xstat_cm_ProbeResults *a_cmResults) /* ptr to xstat cm Results */
2555 { /* cm_Results_ltoa */
2557 static char rn[] = "cm_Results_ltoa"; /* routine name */
2558 struct afs_stats_CMFullPerf *fullP; /* ptr to complete CM stats */
2566 fprintf(debugFD, "[ %s ] Called, a_cmData= %p, a_cmResults= %p\n", rn,
2567 a_cmData, a_cmResults);
2572 fullP = (struct afs_stats_CMFullPerf *)
2573 (a_cmResults->data.AFSCB_CollData_val);
2575 /* There are 4 parts to CM statistics
2576 * - Overall performance statistics (including up/down statistics)
2577 * - This CMs FS RPC operations info
2578 * - This CMs FS RPC errors info
2579 * - This CMs FS transfers info
2580 * - Authentication info
2581 * - [Un]Replicated access info
2584 /* copy overall performance statistics */
2585 srcbuf = (afs_int32 *) & (fullP->perf);
2587 /* we skip the 19 entry, ProtServAddr, so the index must account for this */
2588 for (i = 0; i < NUM_AFS_STATS_CMPERF_LONGS + 1; i++) {
2591 continue; /* skip ProtServerAddr */
2593 sprintf(a_cmData->data[idx], "%d", *srcbuf);
2598 /*printf("Ending index value = %d\n",idx-1); */
2600 /* server up/down statistics */
2601 /* copy file server up/down stats */
2602 srcbuf = (afs_int32 *) (fullP->perf.fs_UpDown);
2604 2 * (sizeof(struct afs_stats_SrvUpDownInfo) / sizeof(afs_int32));
2605 for (i = 0; i < numLongs; i++) {
2606 sprintf(a_cmData->data[idx], "%d", *srcbuf);
2611 /*printf("Ending index value = %d\n",idx-1); */
2613 /* copy volume location server up/down stats */
2614 srcbuf = (afs_int32 *) (fullP->perf.vl_UpDown);
2616 2 * (sizeof(struct afs_stats_SrvUpDownInfo) / sizeof(afs_int32));
2617 for (i = 0; i < numLongs; i++) {
2618 sprintf(a_cmData->data[idx], "%d", *srcbuf);
2623 /*printf("Ending index value = %d\n",idx-1); */
2625 /* copy CMs individual FS RPC operations info */
2626 srcbuf = (afs_int32 *) (fullP->rpc.fsRPCTimes);
2627 for (i = 0; i < AFS_STATS_NUM_FS_RPC_OPS; i++) {
2628 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* numOps */
2631 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* numSuccesses */
2634 tmpbuf = srcbuf++; /* sum time */
2635 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2638 tmpbuf = srcbuf++; /* sqr time */
2639 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2642 tmpbuf = srcbuf++; /* min time */
2643 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2646 tmpbuf = srcbuf++; /* max time */
2647 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2652 /*printf("Ending index value = %d\n",idx-1); */
2654 /* copy CMs individual FS RPC errors info */
2656 srcbuf = (afs_int32 *) (fullP->rpc.fsRPCErrors);
2657 for (i = 0; i < AFS_STATS_NUM_FS_RPC_OPS; i++) {
2658 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* server */
2661 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* network */
2664 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* prot */
2667 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* vol */
2670 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* busies */
2673 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* other */
2678 /*printf("Ending index value = %d\n",idx-1); */
2680 /* copy CMs individual RPC transfers info */
2682 srcbuf = (afs_int32 *) (fullP->rpc.fsXferTimes);
2683 for (i = 0; i < AFS_STATS_NUM_FS_XFER_OPS; i++) {
2684 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* numOps */
2687 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* numSuccesses */
2690 tmpbuf = srcbuf++; /* sum time */
2691 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2694 tmpbuf = srcbuf++; /* sqr time */
2695 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2698 tmpbuf = srcbuf++; /* min time */
2699 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2702 tmpbuf = srcbuf++; /* max time */
2703 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2706 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* sum bytes */
2709 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* min bytes */
2712 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* max bytes */
2715 for (j = 0; j < AFS_STATS_NUM_XFER_BUCKETS; j++) {
2716 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* bucket[j] */
2722 /*printf("Ending index value = %d\n",idx-1); */
2724 /* copy CM operations timings */
2726 srcbuf = (afs_int32 *) (fullP->rpc.cmRPCTimes);
2727 for (i = 0; i < AFS_STATS_NUM_CM_RPC_OPS; i++) {
2728 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* numOps */
2731 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* numSuccesses */
2734 tmpbuf = srcbuf++; /* sum time */
2735 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2738 tmpbuf = srcbuf++; /* sqr time */
2739 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2742 tmpbuf = srcbuf++; /* min time */
2743 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2746 tmpbuf = srcbuf++; /* max time */
2747 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2752 /*printf("Ending index value = %d\n",idx-1); */
2754 /* copy authentication info */
2756 srcbuf = (afs_int32 *) & (fullP->authent);
2757 numLongs = sizeof(struct afs_stats_AuthentInfo) / sizeof(afs_int32);
2758 for (i = 0; i < numLongs; i++) {
2759 sprintf(a_cmData->data[idx], "%d", *srcbuf);
2764 /*printf("Ending index value = %d\n",idx-1); */
2766 /* copy CM [un]replicated access info */
2768 srcbuf = (afs_int32 *) & (fullP->accessinf);
2769 numLongs = sizeof(struct afs_stats_AccessInfo) / sizeof(afs_int32);
2770 for (i = 0; i < numLongs; i++) {
2771 sprintf(a_cmData->data[idx], "%d", *srcbuf);
2776 /*printf("Ending index value = %d\n",idx-1); */
2779 } /* cm_Results_ltoa */
2782 /*-----------------------------------------------------------------------
2783 * Function: check_cm_thresholds()
2786 * Checks the thresholds and sets the overflow flag. Recall that the
2787 * thresholds for each host are stored in the hostEntry lists
2788 * [fs/cm]nameList arrays. The probe results are passed to this
2789 * function in the display-ready format - ie., as strings. Though
2790 * this looks stupid the overhead incurred in converting the strings
2791 * back to floats and comparing them is insignificant and
2792 * programming is easier this way.
2793 * The threshold flags are a part of the display structures
2798 *----------------------------------------------------------------------*/
2801 check_cm_thresholds(struct afsmon_hostEntry *a_hostEntry, /* ptr to hostEntry */
2802 struct cm_Display_Data *a_Data) /* ptr to cm data to be displayed */
2803 { /* check_cm_thresholds */
2805 static char rn[] = "check_cm_thresholds";
2806 struct Threshold *threshP;
2807 double tValue; /* threshold value */
2808 double pValue; /* probe value */
2811 int count; /* number of thresholds exceeded */
2814 fprintf(debugFD, "[ %s ] Called, a_hostEntry= %p, a_Data= %p\n", rn,
2815 a_hostEntry, a_Data);
2819 if (a_hostEntry->numThresh == 0) {
2820 /* store in ovf count ?? */
2825 threshP = a_hostEntry->thresh;
2826 for (i = 0; i < a_hostEntry->numThresh; i++) {
2827 if (threshP->itemName[0] == '\0') {
2831 idx = threshP->index; /* positional index to the data array */
2832 tValue = atof(threshP->threshVal); /* threshold value */
2833 pValue = atof(a_Data->data[idx]); /* probe value */
2834 if (pValue > tValue) {
2838 "[ %s ] cm = %s, thresh ovf for %s, threshold= %s, probevalue= %s\n",
2839 rn, a_hostEntry->hostName, threshP->itemName,
2840 threshP->threshVal, a_Data->data[idx]);
2844 /* if the threshold is crossed, call the handler function
2845 * only if this was a transition -ie, if the threshold was
2846 * crossed in the last probe too just count & keep quite! */
2848 if (!a_Data->threshOvf[idx]) {
2849 a_Data->threshOvf[idx] = 1;
2850 /* call the threshold handler if provided */
2851 if (threshP->handler[0] != '\0') {
2853 fprintf(debugFD, "[ %s ] Calling ovf handler %s\n",
2854 rn, threshP->handler);
2857 execute_thresh_handler(threshP->handler, a_Data->hostName,
2858 CM, threshP->itemName,
2866 /* in case threshold was previously crossed, blank it out */
2867 a_Data->threshOvf[idx] = 0;
2870 /* store the overflow count */
2871 a_Data->ovfCount = count;
2874 } /* check_cm_thresholds */
2877 /*-----------------------------------------------------------------------
2878 * save_CM_data_forDisplay()
2881 * Does the following:
2882 * - if the probe number changed (ie, a cycle completed) curr_cmData
2883 * is copied to prev_cmData, curr_cmData zeroed and refresh the
2884 * overview screen and file server screen with the new data.
2885 * - store the results of the current probe from xstat_cm_Results into
2886 * curr_cmData. ie., convert longs to strings.
2887 * - check the thresholds
2891 * Failure: Exits afsmonitor.
2893 *----------------------------------------------------------------------*/
2896 save_CM_data_forDisplay(struct xstat_cm_ProbeResults *a_cmResults)
2897 { /* save_CM_data_forDisplay */
2899 static char rn[] = "save_CM_data_forDisplay"; /* routine name */
2900 struct cm_Display_Data *curr_cmDataP;
2901 struct cm_Display_Data *prev_cmDataP;
2902 struct afsmon_hostEntry *curr_host;
2903 static int probes_Received = 0; /* number of probes reveived in
2904 * the current cycle. If this is equal to numFS we got all
2905 * the data we want in this cycle and can now display it */
2913 fprintf(debugFD, "[ %s ] Called, a_cmResults= %p\n", rn, a_cmResults);
2917 /* store results in the display array */
2920 curr_cmDataP = curr_cmData;
2921 for (i = 0; i < numCM; i++) {
2922 if ((strcasecmp(curr_cmDataP->hostName, a_cmResults->connP->hostName))
2932 "[ %s ] Could not insert CM probe results for host %s in cm display array\n",
2933 rn, a_cmResults->connP->hostName);
2937 /* Check the status of the probe. If it succeeded, we store its
2938 * results in the display data structure. If it failed we only mark
2939 * the failed status in the display data structure. */
2942 if (a_cmResults->probeOK) { /* 1 => notOK the xstat results */
2943 curr_cmDataP->probeOK = 0;
2945 /* print the probe status */
2947 fprintf(debugFD, "\n\t\t ----- cm display data ------\n");
2948 fprintf(debugFD, "HostName = %s PROBE FAILED \n",
2949 curr_cmDataP->hostName);
2953 } else { /* probe succeeded, update display data structures */
2954 curr_cmDataP->probeOK = 1;
2957 /* covert longs to strings and place them in curr_cmDataP */
2958 cm_Results_ltoa(curr_cmDataP, a_cmResults);
2960 /* compare with thresholds and set the overflow flags.
2961 * note that the threshold information is in the hostEntry structure and
2962 * each threshold item has a positional index associated with it */
2964 /* locate the hostEntry for this host */
2966 curr_host = CMnameList;
2967 for (i = 0; i < numCM; i++) {
2968 if (strcasecmp(curr_host->hostName, a_cmResults->connP->hostName)
2973 curr_host = curr_host->next;
2978 code = check_cm_thresholds(curr_host, curr_cmDataP);
2980 fprintf(stderr, "[ %s ] Error in checking thresholds\n", rn);
2984 /* print the info we just saved */
2986 fprintf(debugFD, "\n\t\t ----- CM display data ------\n");
2987 fprintf(debugFD, "HostName = %s\n", curr_cmDataP->hostName);
2988 for (i = 0; i < NUM_CM_STAT_ENTRIES; i++) {
2991 fprintf(debugFD, "\t -- Overall Perf Info --\n");
2995 "\t -- File Server up/down stats - same cell --\n");
2999 "\t -- File Server up/down stats - diff cell --\n");
3003 "\t -- VL server up/down stats - same cell --\n");
3007 "\t -- VL server up/down stats - diff cell --\n");
3010 fprintf(debugFD, "\t -- FS Operation Timings --\n");
3013 fprintf(debugFD, "\t -- FS Error Info --\n");
3016 fprintf(debugFD, "\t -- FS Transfer Timings --\n");
3019 fprintf(debugFD, "\t -- CM Operations Timings --\n");
3022 fprintf(debugFD, "\t -- Authentication Info --\n");
3025 fprintf(debugFD, "\t -- Access Info --\n");
3031 fprintf(debugFD, "%20s %30s %s\n", curr_cmDataP->data[i],
3033 curr_cmDataP->threshOvf[i] ? "(ovf)" : "");
3035 fprintf(debugFD, "\t\t--------------------------------\n\n");
3038 } /* if the probe succeeded, update the display data structures */
3040 /* if we have received a reply from all the hosts for this probe cycle,
3041 * it is time to display the data */
3044 if (probes_Received == numCM) {
3045 probes_Received = 0;
3047 if (afsmon_cm_curr_probeNum != afsmon_cm_prev_probeNum + 1) {
3048 sprintf(errMsg, "[ %s ] Probe number %d missed! \n", rn,
3049 afsmon_cm_prev_probeNum + 1);
3052 afsmon_cm_prev_probeNum++;
3055 /* backup the display data of the probe cycle that just completed -
3056 * ie., store curr_cmData in prev_cmData */
3058 memcpy((char *)prev_cmData, (char *)curr_cmData,
3059 (numCM * sizeof(struct cm_Display_Data)));
3062 /* initialize curr_cmData but retain the threshold flag information.
3063 * The previous state of threshold flags is used in check_cm_thresholds() */
3065 curr_cmDataP = curr_cmData;
3066 numBytes = NUM_CM_STAT_ENTRIES * CM_STAT_STRING_LEN;
3067 for (i = 0; i < numCM; i++) {
3068 curr_cmDataP->probeOK = 0;
3069 curr_cmDataP->ovfCount = 0;
3070 memset((char *)curr_cmDataP->data, 0, numBytes);
3074 /* prev_cmData now contains all the information for the probe cycle
3075 * that just completed. Now count the number of threshold overflows for
3076 * use in the overview screen */
3078 prev_cmDataP = prev_cmData;
3080 numHosts_oncm_alerts = 0;
3081 for (i = 0; i < numCM; i++) {
3082 if (!prev_cmDataP->probeOK) { /* if probe failed */
3084 numHosts_oncm_alerts++;
3085 } else if (prev_cmDataP->ovfCount) { /* overflows ?? */
3086 num_cm_alerts += prev_cmDataP->ovfCount;
3087 numHosts_oncm_alerts++;
3092 fprintf(debugFD, "Number of CM alerts = %d (on %d hosts)\n",
3093 num_cm_alerts, numHosts_oncm_alerts);
3096 /* flag that the data is now ready to be displayed */
3097 cm_Data_Available = 1;
3099 /* update the Overview frame (only CM info) */
3100 ovw_refresh(ovw_currPage, OVW_UPDATE_CM);
3102 /* update the Cache Managers frame */
3103 cm_refresh(cm_currPage, cm_curr_LCol);
3109 } /* save_CM_data_forDisplay */
3113 /*-----------------------------------------------------------------------
3114 * afsmon_CM_Handler()
3117 * This is the Cache Manager probe Handler. It updates the afsmonitor
3118 * probe counts, cm circular buffer indices and calls the functions
3119 * to process the results of this probe.
3123 * Failure: Exits afsmonitor.
3124 *----------------------------------------------------------------------*/
3127 afsmon_CM_Handler(void)
3128 { /* afsmon_CM_Handler() */
3129 static char rn[] = "afsmon_CM_Handler"; /* routine name */
3130 int code; /* return status */
3131 int newProbeCycle; /* start of new probe cycle ? */
3135 "[ %s ] Called, hostName= %s, probeNum= %d, status= %s\n", rn,
3136 xstat_cm_Results.connP->hostName, xstat_cm_Results.probeNum,
3137 xstat_cm_Results.probeOK ? "FAILED" : "OK");
3142 /* print the probe results to output file */
3143 if (afsmon_output) {
3144 code = afsmon_cmOutput(output_filename, afsmon_detOutput);
3147 "[ %s ] output to file %s returned error code=%d\n", rn,
3148 output_filename, code);
3152 /* Update current probe number and circular buffer index. if current
3153 * probenum changed make sure it is only by 1 */
3156 if (xstat_cm_Results.probeNum != afsmon_cm_curr_probeNum) {
3157 if (xstat_cm_Results.probeNum == afsmon_cm_curr_probeNum + 1) {
3158 afsmon_cm_curr_probeNum++;
3161 afsmon_cm_curr_CBindex =
3162 (afsmon_cm_curr_probeNum - 1) % num_bufSlots;
3164 fprintf(stderr, "[ %s ] probe number %d-1 missed\n", rn,
3165 xstat_cm_Results.probeNum);
3170 /* save the results of this probe in the CM buffer */
3172 save_CM_results_inCB(newProbeCycle);
3174 /* store the results of the current probe in the cm data display structure.
3175 * if the current probe number changed, swap the current and previous display
3176 * structures. note that the display screen is updated from these structures
3177 * and should start showing the data of the just completed probe cycle */
3179 save_CM_data_forDisplay(&xstat_cm_Results);
3184 /*-----------------------------------------------------------------------
3188 * Allocate and Initialize circular buffers for file servers.
3192 * Failure to allocate memory: exits afsmonitor.
3193 *----------------------------------------------------------------------*/
3196 init_fs_buffers(void)
3197 { /* init_fs_buffers() */
3198 static char rn[] = "init_fs_buffers"; /* routine name */
3199 struct afsmon_fs_Results_list *new_fslist_item; /* ptr for new struct */
3200 struct afsmon_fs_Results_list *tmp_fslist_item; /* temp ptr */
3201 struct xstat_fs_ProbeResults *new_fsPR; /* ptr for new struct */
3208 fprintf(debugFD, "[ %s ] Called\n", rn);
3212 /* allocate memory for the circular buffer of pointers */
3214 afsmon_fs_ResultsCB = (struct afsmon_fs_Results_CBuffer *)
3215 malloc(sizeof(struct afsmon_fs_Results_CBuffer) * num_bufSlots);
3217 /* initialize the fs circular buffer */
3218 for (i = 0; i < num_bufSlots; i++) {
3219 afsmon_fs_ResultsCB[i].list = (struct afsmon_fs_Results_list *)0;
3220 afsmon_fs_ResultsCB[i].probeNum = 0;
3223 /* create a list of numFS items to store fs probe results for
3224 * each slot in CB */
3226 if (numFS) { /* if we have file servers to monitor */
3227 for (bufslot = 0; bufslot < num_bufSlots; bufslot++) {
3228 numfs = numFS; /* get the number of servers */
3231 /* if any of these mallocs fail we only need to free the memory we
3232 * have allocated in this iteration. the rest of it which is in a
3233 * proper linked list will be freed in afsmon_Exit */
3235 /* allocate memory for an fs list item */
3236 new_fslist_item = (struct afsmon_fs_Results_list *)
3237 malloc(sizeof(struct afsmon_fs_Results_list));
3238 if (new_fslist_item == (struct afsmon_fs_Results_list *)0)
3241 /* allocate memory to store xstat_fs_Results */
3242 new_fsPR = (struct xstat_fs_ProbeResults *)
3243 malloc(sizeof(struct xstat_fs_ProbeResults));
3244 if (new_fsPR == (struct xstat_fs_ProbeResults *)0) {
3245 free(new_fslist_item);
3248 new_fsPR->connP = (struct xstat_fs_ConnectionInfo *)
3249 malloc(sizeof(struct xstat_fs_ConnectionInfo));
3250 if (new_fsPR->connP == (struct xstat_fs_ConnectionInfo *)0) {
3251 free(new_fslist_item);
3256 /* >>> need to allocate rx connection info structure here <<< */
3258 new_fsPR->data.AFS_CollData_val =
3259 (afs_int32 *) malloc(XSTAT_FS_FULLPERF_RESULTS_LEN *
3261 if (new_fsPR->data.AFS_CollData_val == NULL) {
3262 free(new_fslist_item);
3263 free(new_fsPR->connP);
3268 /* initialize this list entry */
3269 new_fslist_item->fsResults = new_fsPR;
3270 new_fslist_item->empty = 1;
3271 new_fslist_item->next = (struct afsmon_fs_Results_list *)0;
3273 /* store it at the end of the fs list in the current CB slot */
3274 if (afsmon_fs_ResultsCB[bufslot].list ==
3275 (struct afsmon_fs_Results_list *)0)
3276 afsmon_fs_ResultsCB[bufslot].list = new_fslist_item;
3278 tmp_fslist_item = afsmon_fs_ResultsCB[bufslot].list;
3280 while (tmp_fslist_item !=
3281 (struct afsmon_fs_Results_list *)0) {
3282 if (tmp_fslist_item->next ==
3283 (struct afsmon_fs_Results_list *)0)
3285 tmp_fslist_item = tmp_fslist_item->next;
3287 /* something goofed. exit */
3288 fprintf(stderr, "[ %s ] list creation error\n",
3293 tmp_fslist_item->next = new_fslist_item;
3296 } /* while servers */
3297 } /* for each buffer slot */
3298 } /* if we have file servers to monitor */
3302 /*-----------------------------------------------------------------------
3306 * Allocate and Initialize circular buffers for cache managers.
3310 * Failure to allocate memory: exits afsmonitor.
3311 *----------------------------------------------------------------------*/
3314 init_cm_buffers(void)
3315 { /* init_cm_buffers() */
3316 static char rn[] = "init_cm_buffers"; /* routine name */
3317 struct afsmon_cm_Results_list *new_cmlist_item; /* ptr for new struct */
3318 struct afsmon_cm_Results_list *tmp_cmlist_item; /* temp ptr */
3319 struct xstat_cm_ProbeResults *new_cmPR; /* ptr for new struct */
3325 fprintf(debugFD, "[ %s ] Called\n", rn);
3329 /* allocate memory for the circular buffer of pointers */
3330 afsmon_cm_ResultsCB = (struct afsmon_cm_Results_CBuffer *)
3331 malloc(sizeof(struct afsmon_cm_Results_CBuffer) * num_bufSlots);
3333 /* initialize the fs circular buffer */
3334 for (i = 0; i < num_bufSlots; i++) {
3335 afsmon_cm_ResultsCB[i].list = (struct afsmon_cm_Results_list *)0;
3336 afsmon_cm_ResultsCB[i].probeNum = 0;
3339 /* create a list of numCM items to store fs probe results for
3340 * each slot in CB */
3342 if (numCM) { /* if we have file servers to monitor */
3343 for (bufslot = 0; bufslot < num_bufSlots; bufslot++) {
3344 numcm = numCM; /* get the number of servers */
3347 /* if any of these mallocs fail we only need to free the memory we
3348 * have allocated in this iteration. the rest of it which is in a
3349 * proper linked list will be freed in afsmon_Exit */
3351 /* allocate memory for an fs list item */
3352 new_cmlist_item = (struct afsmon_cm_Results_list *)
3353 malloc(sizeof(struct afsmon_cm_Results_list));
3354 if (new_cmlist_item == (struct afsmon_cm_Results_list *)0)
3357 /* allocate memory to store xstat_cm_Results */
3358 new_cmPR = (struct xstat_cm_ProbeResults *)
3359 malloc(sizeof(struct xstat_cm_ProbeResults));
3360 if (new_cmPR == (struct xstat_cm_ProbeResults *)0) {
3361 free(new_cmlist_item);
3364 new_cmPR->connP = (struct xstat_cm_ConnectionInfo *)
3365 malloc(sizeof(struct xstat_cm_ConnectionInfo));
3366 if (new_cmPR->connP == (struct xstat_cm_ConnectionInfo *)0) {
3367 free(new_cmlist_item);
3372 /* >>> need to allocate rx connection info structure here <<< */
3374 new_cmPR->data.AFSCB_CollData_val =
3375 (afs_int32 *) malloc(XSTAT_CM_FULLPERF_RESULTS_LEN *
3377 if (new_cmPR->data.AFSCB_CollData_val == NULL) {
3378 free(new_cmlist_item);
3379 free(new_cmPR->connP);
3384 /* initialize this list entry */
3385 new_cmlist_item->cmResults = new_cmPR;
3386 new_cmlist_item->empty = 1;
3387 new_cmlist_item->next = (struct afsmon_cm_Results_list *)0;
3389 /* store it at the end of the cm list in the current CB slot */
3390 if (afsmon_cm_ResultsCB[bufslot].list ==
3391 (struct afsmon_cm_Results_list *)0)
3392 afsmon_cm_ResultsCB[bufslot].list = new_cmlist_item;
3394 tmp_cmlist_item = afsmon_cm_ResultsCB[bufslot].list;
3396 while (tmp_cmlist_item !=
3397 (struct afsmon_cm_Results_list *)0) {
3398 if (tmp_cmlist_item->next ==
3399 (struct afsmon_cm_Results_list *)0)
3401 tmp_cmlist_item = tmp_cmlist_item->next;
3403 /* something goofed. exit */
3404 fprintf(stderr, "[ %s ] list creation error\n",
3409 tmp_cmlist_item->next = new_cmlist_item;
3412 } /* while servers */
3413 } /* for each buffer slot */
3415 /* if we have file servers to monitor */
3416 /* print the CB to make sure it is right */
3420 } /* init_cm_buffers() */
3423 /*-------------------------------------------------------------------------
3424 * init_print_buffers()
3427 * Allocate and initialize the buffers used for printing results
3428 * to the display screen. These buffers store the current and
3429 * previous probe results in ascii format.
3434 *------------------------------------------------------------------------*/
3437 init_print_buffers(void)
3438 { /* init_print_buffers */
3440 static char rn[] = "init_print_buffers"; /* routine name */
3441 struct fs_Display_Data *tmp_fsData1; /* temp pointers */
3442 struct fs_Display_Data *tmp_fsData2;
3443 struct cm_Display_Data *tmp_cmData1;
3444 struct cm_Display_Data *tmp_cmData2;
3445 struct afsmon_hostEntry *tmp_fsNames;
3446 struct afsmon_hostEntry *tmp_cmNames;
3451 fprintf(debugFD, "[ %s ] Called\n", rn);
3455 /* allocate numFS blocks of the FS print structure. */
3457 /* we need two instances of this structure - one (curr_fsData) for storing
3458 * the results of the fs probes currently in progress and another (prev_fsData)
3459 * for the last completed probe. The display is updated from the contents of
3460 * prev_fsData. The pointers curr_fsData & prev_fsData are switched whenever
3461 * the probe number changes */
3464 numBytes = numFS * sizeof(struct fs_Display_Data);
3465 curr_fsData = (struct fs_Display_Data *)malloc(numBytes);
3466 if (curr_fsData == (struct fs_Display_Data *)0) {
3467 fprintf(stderr, "[ %s ] Memory allocation failure\n", rn);
3470 memset(curr_fsData, 0, numBytes);
3472 numBytes = numFS * sizeof(struct fs_Display_Data);
3473 prev_fsData = (struct fs_Display_Data *)malloc(numBytes);
3474 if (prev_fsData == (struct fs_Display_Data *)0) {
3475 fprintf(stderr, "[ %s ] Memory allocation failure\n", rn);
3478 memset(prev_fsData, 0, numBytes);
3480 /* fill in the host names */
3481 tmp_fsData1 = curr_fsData;
3482 tmp_fsData2 = curr_fsData;
3483 tmp_fsNames = FSnameList;
3484 for (i = 0; i < numFS; i++) {
3485 strncpy(tmp_fsData1->hostName, tmp_fsNames->hostName,
3487 strncpy(tmp_fsData2->hostName, tmp_fsNames->hostName,
3491 tmp_fsNames = tmp_fsNames->next;;
3496 /* if file servers to monitor */
3497 /* allocate numCM blocks of the CM print structure */
3498 /* we need two instances of this structure for the same reasons as above */
3500 numBytes = numCM * sizeof(struct cm_Display_Data);
3502 curr_cmData = (struct cm_Display_Data *)malloc(numBytes);
3503 if (curr_cmData == (struct cm_Display_Data *)0) {
3504 fprintf(stderr, "[ %s ] Memory allocation failure\n", rn);
3507 memset(curr_cmData, 0, numBytes);
3509 numBytes = numCM * sizeof(struct cm_Display_Data);
3510 prev_cmData = (struct cm_Display_Data *)malloc(numBytes);
3511 if (prev_cmData == (struct cm_Display_Data *)0) {
3512 fprintf(stderr, "[ %s ] Memory allocation failure\n", rn);
3515 memset(prev_cmData, 0, numBytes);
3517 /* fill in the host names */
3518 tmp_cmData1 = curr_cmData;
3519 tmp_cmData2 = curr_cmData;
3520 tmp_cmNames = CMnameList;
3521 for (i = 0; i < numCM; i++) {
3522 strncpy(tmp_cmData1->hostName, tmp_cmNames->hostName,
3524 strncpy(tmp_cmData2->hostName, tmp_cmNames->hostName,
3528 tmp_cmNames = tmp_cmNames->next;;
3532 /* if cache managers to monitor */
3535 } /* init_print_buffers */
3537 /*-----------------------------------------------------------------------
3541 * Trap the interrupt signal. This function is useful only until
3542 * gtx is initialized.
3543 *----------------------------------------------------------------------*/
3546 quit_signal(int sig)
3548 fprintf(stderr, "Received signal %d \n", sig);
3554 /*-----------------------------------------------------------------------
3558 * This is where we start it all. Initialize an array of sockets for
3559 * file servers and cache cache managers and call the xstat_[fs/cm]_Init
3560 * routines. The last step is to call the gtx input server which
3561 * grabs control of the keyboard.
3564 * Does not return. Control is periodically returned to the afsmonitor
3565 * thru afsmon_[FS/CM]_Handler() routines and also through the gtx
3566 * keyboard handler calls.
3568 *----------------------------------------------------------------------*/
3571 afsmon_execute(void)
3572 { /* afsmon_execute() */
3573 static char rn[] = "afsmon_execute"; /* routine name */
3574 static char fullhostname[128]; /* full host name */
3575 struct sockaddr_in *FSSktArray; /* fs socket array */
3576 int FSsktbytes; /* num bytes in above */
3577 struct sockaddr_in *CMSktArray; /* cm socket array */
3578 int CMsktbytes; /* num bytes in above */
3579 struct sockaddr_in *curr_skt; /* ptr to current socket */
3580 struct afsmon_hostEntry *curr_FS; /* ptr to FS name list */
3581 struct afsmon_hostEntry *curr_CM; /* ptr to CM name list */
3582 struct hostent *he; /* host entry */
3583 afs_int32 *collIDP; /* ptr to collection ID */
3584 int numCollIDs; /* number of collection IDs */
3585 int FSinitFlags = 0; /* flags for xstat_fs_Init */
3586 int CMinitFlags = 0; /* flags for xstat_cm_Init */
3587 int code; /* function return code */
3588 struct timeval tv; /* time structure */
3591 fprintf(debugFD, "[ %s ] Called\n", rn);
3596 /* process file server entries */
3598 /* Allocate an array of sockets for each fileserver we monitor */
3600 FSsktbytes = numFS * sizeof(struct sockaddr_in);
3601 FSSktArray = (struct sockaddr_in *)malloc(FSsktbytes);
3602 if (FSSktArray == (struct sockaddr_in *)0) {
3604 "[ %s ] cannot malloc %d sockaddr_ins for fileservers\n",
3609 memset(FSSktArray, 0, FSsktbytes);
3611 /* Fill in the socket information for each fileserve */
3613 curr_skt = FSSktArray;
3614 curr_FS = FSnameList; /* FS name list header */
3616 strncpy(fullhostname, curr_FS->hostName, sizeof(fullhostname));
3617 he = GetHostByName(fullhostname);
3619 fprintf(stderr, "[ %s ] Cannot get host info for %s\n", rn,
3623 strncpy(curr_FS->hostName, he->h_name, HOST_NAME_LEN); /* complete name */
3624 memcpy(&(curr_skt->sin_addr.s_addr), he->h_addr, 4);
3625 curr_skt->sin_family = AF_INET; /*Internet family */
3626 curr_skt->sin_port = htons(7000); /*FileServer port */
3627 #ifdef STRUCT_SOCKADDR_HAS_SA_LEN
3628 curr_skt->sin_len = sizeof(struct sockaddr_in);
3631 /* get the next dude */
3633 curr_FS = curr_FS->next;
3636 /* initialize collection IDs. We need only one entry since we collect
3637 * all the information from xstat */
3640 collIDP = (afs_int32 *) malloc(sizeof(afs_int32));
3641 if (collIDP == NULL) {
3643 "[ %s ] failed to allocate a measely afs_int32 word.Argh!\n",
3647 *collIDP = 2; /* USE A macro for this */
3650 if (afsmon_onceOnly) /* option not provided at this time */
3651 FSinitFlags |= XSTAT_FS_INITFLAG_ONE_SHOT;
3654 fprintf(debugFD, "[ %s ] Calling xstat_fs_Init \n", rn);
3658 code = xstat_fs_Init(numFS, /*Num servers */
3659 FSSktArray, /*File Server socket array */
3660 afsmon_probefreq, /*probe frequency */
3661 afsmon_FS_Handler, /*Handler routine */
3662 FSinitFlags, /*Initialization flags */
3663 numCollIDs, /*Number of collection IDs */
3664 collIDP); /*Ptr to collection ID */
3667 fprintf(stderr, "[ %s ] xstat_fs_init returned error\n", rn);
3674 /* end of process fileserver entries */
3675 /* process cache manager entries */
3677 /* Allocate an array of sockets for each cache manager we monitor */
3679 CMsktbytes = numCM * sizeof(struct sockaddr_in);
3680 CMSktArray = (struct sockaddr_in *)malloc(CMsktbytes);
3681 if (CMSktArray == (struct sockaddr_in *)0) {
3683 "[ %s ] cannot malloc %d sockaddr_ins for CM entries\n",
3688 memset(CMSktArray, 0, CMsktbytes);
3690 /* Fill in the socket information for each CM */
3692 curr_skt = CMSktArray;
3693 curr_CM = CMnameList; /* CM name list header */
3695 strncpy(fullhostname, curr_CM->hostName, sizeof(fullhostname));
3696 he = GetHostByName(fullhostname);
3698 fprintf(stderr, "[ %s ] Cannot get host info for %s\n", rn,
3702 strncpy(curr_CM->hostName, he->h_name, HOST_NAME_LEN); /* complete name */
3703 memcpy(&(curr_skt->sin_addr.s_addr), he->h_addr, 4);
3704 #if defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
3705 curr_skt->sin_family = AF_INET; /*Internet family */
3707 curr_skt->sin_family = htons(AF_INET); /*Internet family */
3709 curr_skt->sin_port = htons(7001); /*Cache Manager port */
3710 #ifdef STRUCT_SOCKADDR_HAS_SA_LEN
3711 curr_skt->sin_len = sizeof(struct sockaddr_in);
3714 /* get the next dude */
3716 curr_CM = curr_CM->next;
3719 /* initialize collection IDs. We need only one entry since we collect
3720 * all the information from xstat */
3723 collIDP = (afs_int32 *) malloc(sizeof(afs_int32));
3724 if (collIDP == NULL) {
3726 "[ %s ] failed to allocate a measely long word.Argh!\n",
3730 *collIDP = 2; /* USE A macro for this */
3733 if (afsmon_onceOnly) /* once only ? */
3734 CMinitFlags |= XSTAT_CM_INITFLAG_ONE_SHOT;
3737 fprintf(debugFD, "[ %s ] Calling xstat_cm_Init \n", rn);
3741 code = xstat_cm_Init(numCM, /*Num servers */
3742 CMSktArray, /*Cache Manager socket array */
3743 afsmon_probefreq, /*probe frequency */
3744 afsmon_CM_Handler, /*Handler routine */
3745 CMinitFlags, /*Initialization flags */
3746 numCollIDs, /*Number of collection IDs */
3747 collIDP); /*Ptr to collection ID */
3750 fprintf(stderr, "[ %s ] xstat_cm_init returned error\n", rn);
3757 /* end of process cache manager entries */
3758 /* if only one probe was required setup a waiting process for the
3759 * termination signal */
3760 if (afsmon_onceOnly) {
3761 code = LWP_WaitProcess(&terminationEvent);
3764 fprintf(debugFD, "LWP_WaitProcess() returned error %d\n",
3772 /* start the gtx input server */
3773 code = (intptr_t)gtx_InputServer(afsmon_win);
3775 fprintf(stderr, "[ %s ] Failed to start input server \n", rn);
3779 /* This part of the code is reached only if the input server is not started
3780 * for debugging purposes */
3783 tv.tv_sec = 24 * 60;
3785 fprintf(stderr, "[ %s ] going to sleep ...\n", rn);
3787 code = IOMGR_Select(0, /*Num fds */
3788 0, /*Descriptors ready for reading */
3789 0, /*Descriptors ready for writing */
3790 0, /*Descriptors with exceptional conditions */
3791 &tv); /*Timeout structure */
3794 "[ %s ] IOMGR_Select() returned non-zero value %d\n", rn,
3802 /*-----------------------------------------------------------------------
3806 * Afsmonitor initialization routine.
3807 * - processes command line parameters
3808 * - call functions to:
3809 * - process config file
3810 * - initialize circular buffers and display buffers
3812 * - execute afsmonitor
3813 * - initialize the display maps [fs/cm]_Display_map[].
3816 * Success: Does not return from the call to afsmon_execute().
3817 * Failure: Exits afsmonitor.
3818 *----------------------------------------------------------------------*/
3821 afsmonInit(struct cmd_syndesc *as, void *arock)
3822 { /* afsmonInit() */
3824 static char rn[] = "afsmonInit"; /* Routine name */
3825 char *debug_filename; /* pointer to debug filename */
3826 FILE *outputFD; /* output file descriptor */
3827 struct cmd_item *hostPtr; /* ptr to parse command line args */
3828 char buf[256]; /* buffer for processing hostnames */
3833 fprintf(debugFD, "[ %s ] Called, as= %p\n", rn, as);
3837 /* Open the debug file if -debug option is specified */
3838 if (as->parms[P_DEBUG].items != 0) {
3840 debug_filename = as->parms[P_DEBUG].items->data;
3841 debugFD = fopen(debug_filename, "w");
3842 if (debugFD == (FILE *) 0) {
3843 printf("[ %s ] Failed to open debugging file %s for writing\n",
3851 fprintf(debugFD, "[ %s ] Called\n", rn);
3855 /* use curses always until we support other packages */
3857 wpkg_to_use = atoi(as->parms[P_PACKAGE].items->data);
3859 switch (wpkg_to_use) {
3860 case GATOR_WIN_CURSES:
3861 fprintf(stderr, "curses\n");
3863 case GATOR_WIN_DUMB:
3864 fprintf(stderr, "dumb terminal\n");
3867 fprintf(stderr, "X11\n");
3870 fprintf(stderr, "Illegal graphics package: %d\n", wpkg_to_use);
3872 } /*end switch (wpkg_to_use) */
3875 wpkg_to_use = GATOR_WIN_CURSES;
3877 /* get probe frequency . We check for meaningful bounds on the frequency
3878 * and reset to the default value if needed. The upper bound of 24
3879 * hours looks ridiculous though! */
3881 afsmon_probefreq = 0;
3882 if (as->parms[P_FREQUENCY].items != 0)
3883 afsmon_probefreq = atoi(as->parms[P_FREQUENCY].items->data);
3885 afsmon_probefreq = DEFAULT_FREQUENCY;
3887 if (afsmon_probefreq <= 0 || afsmon_probefreq > 24 * 60 * 60) {
3888 afsmon_probefreq = DEFAULT_FREQUENCY;
3891 "[ %s ] Invalid probe frequency %s specified, resetting to default value %d seconds\n",
3892 rn, as->parms[P_FREQUENCY].items->data, afsmon_probefreq);
3896 "Invalid probe frequency %s specified, resetting to default value %d seconds\n",
3897 as->parms[P_FREQUENCY].items->data, afsmon_probefreq);
3902 /* make sure output file is writable, else complain now */
3903 /* we will open and close it as needed after probes */
3905 if (as->parms[P_OUTPUT].items != 0) {
3906 afsmon_output = 1; /* output flag */
3907 strncpy(output_filename, as->parms[P_OUTPUT].items->data, 80);
3908 outputFD = fopen(output_filename, "a");
3909 if (outputFD == (FILE *) 0) {
3910 fprintf(stderr, "Failed to open output file %s \n",
3913 fprintf(debugFD, "[ %s ] Failed to open output file %s \n",
3914 rn, output_filename);
3919 fprintf(debugFD, "[ %s ] output file is %s\n", rn,
3925 /* detailed statistics to storage file */
3926 if (as->parms[P_DETAILED].items != 0) {
3927 if (as->parms[P_OUTPUT].items == 0) {
3929 "-detailed switch can be used only with -output\n");
3932 afsmon_detOutput = 1;
3935 /* Initialize host list headers */
3936 FSnameList = (struct afsmon_hostEntry *)0;
3937 CMnameList = (struct afsmon_hostEntry *)0;
3939 /* The -config option is mutually exclusive with the -fshosts,-cmhosts
3942 if (as->parms[P_CONFIG].items) {
3943 if (as->parms[P_FSHOSTS].items || as->parms[P_CMHOSTS].items) {
3945 "Cannot use -config option with -fshosts or -cmhosts\n");
3949 if (!as->parms[P_FSHOSTS].items && !as->parms[P_CMHOSTS].items) {
3951 "Must specify either -config or (-fshosts and/or -cmhosts) options \n");
3957 /* If a file server host is specified on the command line we reuse
3958 * parse_hostEntry() function . Just the pass the info as if it were
3959 * read off the config file */
3961 if (as->parms[P_FSHOSTS].items) {
3962 hostPtr = as->parms[P_FSHOSTS].items;
3963 while (hostPtr != (struct cmd_item *)0) {
3964 sprintf(buf, "fs %s", hostPtr->data);
3965 code = parse_hostEntry(buf);
3967 fprintf(stderr, "Could not parse %s\n", hostPtr->data);
3971 hostPtr = hostPtr->next;
3975 /* same as above for -cmhosts */
3976 if (as->parms[P_CMHOSTS].items) {
3977 hostPtr = as->parms[P_CMHOSTS].items;
3978 while (hostPtr != (struct cmd_item *)0) {
3979 sprintf(buf, "cm %s", hostPtr->data);
3980 code = parse_hostEntry(buf);
3982 fprintf(stderr, "Could not parse %s\n", hostPtr->data);
3986 hostPtr = hostPtr->next;
3990 /* number of slots in circular buffers */
3991 if (as->parms[P_BUFFERS].items)
3992 num_bufSlots = atoi(as->parms[P_BUFFERS].items->data);
3994 num_bufSlots = DEFAULT_BUFSLOTS;
3996 /* Initialize xx_showFlags[]. This array is used solely for processing the
3997 * "show" directives in the config file in parse_showEntries() */
3998 for (i = 0; i < NUM_FS_STAT_ENTRIES; i++)
3999 fs_showFlags[i] = 0;
4000 for (i = 0; i < NUM_CM_STAT_ENTRIES; i++)
4001 cm_showFlags[i] = 0;
4004 /* Process the configuration file if given. This initializes among other
4005 * things, the list of FS & CM names in FSnameList and CMnameList */
4007 if (as->parms[P_CONFIG].items)
4008 process_config_file(as->parms[P_CONFIG].items->data);
4010 /* print out the FS and CM lists */
4014 /* Initialize the FS results-to-screen map array if there were no "show fs"
4015 * directives in the config file */
4016 if (fs_showDefault) {
4017 for (i = 0; i < NUM_FS_STAT_ENTRIES; i++)
4018 fs_Display_map[i] = i;
4019 fs_DisplayItems_count = NUM_FS_STAT_ENTRIES;
4022 /* Initialize the CM results-to-screen map array if there were no "show cm"
4023 * directives in the config file */
4024 if (cm_showDefault) {
4025 for (i = 0; i < NUM_CM_STAT_ENTRIES; i++)
4026 cm_Display_map[i] = i;
4027 cm_DisplayItems_count = NUM_CM_STAT_ENTRIES;
4032 /* setup an interrupt signal handler; we ain't wanna leak core */
4033 /* this binding is useful only until gtx is initialized after which the
4034 * keyboard input server takes over. */
4035 if ((signal(SIGINT, quit_signal)) == SIG_ERR) {
4036 perror("signal() failed.");
4041 /* init error message buffers. these will be used to print error messages
4042 * once gtx is initialized and there is no access to stderr/stdout */
4048 /* initialize fs and cm circular buffers before initiating probes */
4050 code = init_fs_buffers();
4052 fprintf(stderr, "[ %s ] init_fs_buffers returned %d\n", rn,
4059 code = init_cm_buffers();
4061 fprintf(stderr, "[ %s ] init_cm_buffers returned %d\n", rn,
4068 /* allocate and initialize buffers for holding fs & cm results in ascii
4069 * format suitable for updating the screen */
4070 code = init_print_buffers();
4072 fprintf(stderr, "[ %s ] init_print_buffers returned %d\n", rn, code);
4076 /* perform gtx initializations */
4077 code = gtx_initialize();
4079 fprintf(stderr, "[ %s ] gtx_initialize returned %d\n", rn, code);
4083 /* start xstat probes */
4086 return (0); /* will not return from the call to afsmon_execute() */
4088 } /* afsmonInit() */
4091 /*-----------------------------------------------------------------------
4093 ------------------------------------------------------------------------*/
4095 #include "AFS_component_version_number.c"
4098 main(int argc, char **argv)
4100 afs_int32 code; /*Return code */
4101 struct cmd_syndesc *ts; /*Ptr to cmd line syntax descriptor */
4103 #ifdef AFS_AIX32_ENV
4105 * The following signal action for AIX is necessary so that in case of a
4106 * crash (i.e. core is generated) we can include the user's data section
4107 * in the core dump. Unfortunately, by default, only a partial core is
4108 * generated which, in many cases, isn't too useful.
4110 struct sigaction nsa;
4112 sigemptyset(&nsa.sa_mask);
4113 nsa.sa_handler = SIG_DFL;
4114 nsa.sa_flags = SA_FULLDUMP;
4115 sigaction(SIGSEGV, &nsa, NULL);
4119 * Set up the commands we understand.
4121 ts = cmd_CreateSyntax("initcmd", afsmonInit, NULL, "initialize the program");
4122 cmd_AddParm(ts, "-config", CMD_SINGLE, CMD_OPTIONAL,
4123 "configuration file");
4124 cmd_AddParm(ts, "-frequency", CMD_SINGLE, CMD_OPTIONAL,
4125 "poll frequency, in seconds");
4126 cmd_AddParm(ts, "-output", CMD_SINGLE, CMD_OPTIONAL, "storage file name");
4127 cmd_AddParm(ts, "-detailed", CMD_FLAG, CMD_OPTIONAL,
4128 "output detailed statistics to storage file");
4130 /* we hope to use this .... eventually! */
4131 cmd_AddParm(ts, "-package", CMD_SINGLE, CMD_REQUIRED,
4132 "Graphics Package to use");
4134 cmd_AddParm(ts, "-debug", CMD_SINGLE, CMD_OPTIONAL,
4135 "turn debugging output on to the named file");
4136 cmd_AddParm(ts, "-fshosts", CMD_LIST, CMD_OPTIONAL,
4137 "list of file servers to monitor");
4138 cmd_AddParm(ts, "-cmhosts", CMD_LIST, CMD_OPTIONAL,
4139 "list of cache managers to monitor");
4140 cmd_AddParm(ts, "-buffers", CMD_SINGLE, CMD_OPTIONAL,
4141 "number of buffer slots");
4144 * Parse command-line switches & execute afsmonitor
4147 code = cmd_Dispatch(argc, argv);
4153 exit(0); /* redundant, but gets rid of warning */