2 * Copyright 2000, International Business Machines Corporation and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
9 * Portions Copyright (c) 2003 Apple Computer, Inc.
13 * Afsmonitor: An AFS Performance Monitoring Tool
15 *-------------------------------------------------------------------------*/
18 #include <afsconfig.h>
19 #include <afs/param.h>
28 #include <afs/gtxwindows.h> /*Generic window package */
29 #include <afs/gtxobjects.h> /*Object definitions */
30 #include <afs/gtxlightobj.h> /*Light object interface */
31 #include <afs/gtxcurseswin.h> /*Curses window package */
32 #include <afs/gtxdumbwin.h> /*Dumb terminal window package */
33 #include <afs/gtxX11win.h> /*X11 window package */
34 #include <afs/gtxframe.h> /*Frame package */
35 #include <afs/gtxinput.h>
37 #include <afs/xstat_fs.h>
38 #include <afs/xstat_cm.h>
40 #include "afsmonitor.h"
42 /* command line parameter indices */
48 /* #define P_PACKAGE X */
55 int afsmon_debug
= 0; /* debug info to file ? */
56 FILE *debugFD
; /* debugging file descriptor */
57 static int afsmon_output
= 0; /* output to file ? */
58 static int afsmon_detOutput
= 0; /* detailed output ? */
59 static int afsmon_onceOnly
= 0; /* probe once only ? (not implemented) */
60 int afsmon_probefreq
; /* probe frequency */
61 static int wpkg_to_use
; /* graphics package to use */
62 static char output_filename
[80]; /* output filename */
63 char errMsg
[256]; /* buffers used to print error messages after */
64 char errMsg1
[256]; /* gtx is initialized (stderr/stdout gone !) */
65 int num_bufSlots
= 0; /* number of slots in fs & cm circular buffers */
67 /* Flags used to process "show" directives in config file */
68 short fs_showFlags
[NUM_FS_STAT_ENTRIES
];
69 short cm_showFlags
[NUM_CM_STAT_ENTRIES
];
72 /* afsmonitor misc definitions */
74 #define DEFAULT_FREQUENCY 60 /* default proble frequency in seconds */
75 #define DEFAULT_BUFSLOTS 0 /* default number of buffer slots */
76 #define CFG_STR_LEN 80 /* max length of config file fields */
77 #define FS 1 /* for misc. use */
78 #define CM 2 /* for misc. use */
81 #define NUM_XSTAT_FS_AFS_PERFSTATS_LONGS 70 /* number of fields from struct afs_PerfStats that we display */
82 #define NUM_AFS_STATS_CMPERF_LONGS 40 /* number of longs in struct afs_stats_CMPerf excluding up/down stats and fields we dont display */
85 /* variables used for exec'ing user provided threshold handlers */
86 char *fsHandler_argv
[20]; /* *argv[] for the handler */
87 char fsHandler_args
[20][256]; /* buffer space for arguments */
88 int exec_fsThreshHandler
= 0; /* execute fs threshold handler ? */
91 /* THRESHOLD STRUCTURE DEFINITIONS */
93 /* flag to indicate that threshold entries apply to all hosts. these will
94 be turned off when the first fs or cm host entry is processed */
95 static int global_ThreshFlag
= 1;
96 static int global_fsThreshCount
= 0; /* number of global fs thresholds */
97 static int global_cmThreshCount
= 0; /* number of global cm thresholds */
101 /* Linked lists of file server and cache manager host names are made from
102 the entries in the config file. Head pointers to FS and CM server name lists. */
103 static struct afsmon_hostEntry
*FSnameList
;
104 static struct afsmon_hostEntry
*CMnameList
;
106 /* number of fileservers and cache managers to monitor */
110 /* number of xstat collection ids */
111 #define MAX_NUM_FS_COLLECTIONS 2
112 #define MAX_NUM_CM_COLLECTIONS 1
113 int num_fs_collections
= 0;
114 int num_cm_collections
= 0;
116 /* variables used for processing config file */
117 /* ptr to the hostEntry structure of the last "fs" or "cm" entry processed
118 in the config file */
119 static struct afsmon_hostEntry
*last_hostEntry
;
120 /* names of the last host processed in the config file */
121 static char last_fsHost
[HOST_NAME_LEN
];
122 static char last_cmHost
[HOST_NAME_LEN
];
123 static int lastHostType
= 0; /* 0 = no host entries processed
124 * 1 = last host was file server
125 * 2 = last host was cache manager. */
128 /* FILE SERVER CIRCULAR BUFFER VARIABLES */
130 struct afsmon_fs_Results_list
{
131 struct xstat_fs_ProbeResults
*fsResults
[MAX_NUM_FS_COLLECTIONS
];
132 int empty
[MAX_NUM_FS_COLLECTIONS
];
133 struct afsmon_fs_Results_list
*next
;
136 struct afsmon_fs_Results_CBuffer
{
137 int probeNum
; /* probe number of entries in this slot */
138 struct afsmon_fs_Results_list
*list
; /* ptr to list of results */
141 int afsmon_fs_results_length
[] =
142 { XSTAT_FS_FULLPERF_RESULTS_LEN
, XSTAT_FS_CBSTATS_RESULTS_LEN
};
144 /* buffer for FS probe results */
145 struct afsmon_fs_Results_CBuffer
*afsmon_fs_ResultsCB
;
147 int afsmon_fs_curr_CBindex
= 0; /* current fs CB slot */
149 /* Probe number variables. The current probe number is incremented
150 when the first probe from a new probe cycle is received. The prev probe
151 number is incremented when the last probe of the current cycle is
152 received. This difference is because of the purpose for which these
155 int afsmon_fs_curr_probeNum
= 1; /* current fs probe number */
156 int afsmon_fs_prev_probeNum
= 0; /* previous fs probe number */
159 /* CACHE MANAGER CIRCULAR BUFFER VARIABLES */
161 struct afsmon_cm_Results_list
{
162 struct xstat_cm_ProbeResults
*cmResults
[MAX_NUM_CM_COLLECTIONS
];
163 int empty
[MAX_NUM_CM_COLLECTIONS
];
164 struct afsmon_cm_Results_list
*next
;
167 struct afsmon_cm_Results_CBuffer
{
168 int probeNum
; /* probe number of entries in this slot */
169 struct afsmon_cm_Results_list
*list
; /* ptr to list of results */
172 int afsmon_cm_results_length
[] = { XSTAT_CM_FULLPERF_RESULTS_LEN
};
174 /* buffer for CM probe results */
175 struct afsmon_cm_Results_CBuffer
*afsmon_cm_ResultsCB
;
177 int afsmon_cm_curr_CBindex
= 0; /* current cm CB slot */
180 /* Probe number variables. The current probe number is incremented
181 when the first probe from a new probe cycle is received. The prev probe
182 number is incremented when the last probe of the current cycle is
183 received. This difference is because of the purpose for which these
186 int afsmon_cm_curr_probeNum
= 1; /* current cm probe number */
187 int afsmon_cm_prev_probeNum
= 0; /* previous cm probe number */
190 /* Structures to hold FS & CM results in string format(suitable for display ) */
192 /* ptr to array holding the results of FS probes in ascii format */
193 /* for current probe cycle */
194 struct fs_Display_Data
*curr_fsData
= (struct fs_Display_Data
*)0;
195 /* for previous probe cycle */
196 struct fs_Display_Data
*prev_fsData
= (struct fs_Display_Data
*)0;
199 /* ptr to array holding the results of CM probes in ascii format */
200 /* for current probe cycle */
201 struct cm_Display_Data
*curr_cmData
= (struct cm_Display_Data
*)0;
202 /* for previous probe cycle */
203 struct cm_Display_Data
*prev_cmData
= (struct cm_Display_Data
*)0;
205 /* EXTERN DEFINITIONS */
207 /* file server and cache manager variable names (from afsmon_labels.h) */
208 extern char *fs_varNames
[];
209 extern char *cm_varNames
[];
211 /* GTX & MISC VARIABLES */
213 /* afsmonitor window */
214 extern struct gwin
*afsmon_win
;
216 /* current page number in the overview frame */
217 extern int ovw_currPage
;
219 /* number of FS alerts and number of hosts on FS alerts */
221 int numHosts_onfs_alerts
;
223 /* number of CM alerts and number of hosts on FS alerts */
225 int numHosts_oncm_alerts
;
227 /* flag to indicate that atleast one probe cycle has completed and
228 data is available for updating the display */
229 extern int fs_Data_Available
;
230 extern int cm_Data_Available
;
232 extern int gtx_initialized
; /* gtx initialized ? */
234 /* This array contains the indices of the file server data items that
235 are to be displayed on the File Servers screen. For example, suppose the
236 user wishes to display only the vcache statistics then the following array
237 will contain indices 2 to 14 corresponding to the position of the
238 vcache data items in the fs_varNames[] array. If the config file contains
239 no "show fs .." directives, it will contain the indices of all the
240 items in the fs_varNames[] array */
242 short fs_Display_map
[NUM_FS_STAT_ENTRIES
];
243 int fs_DisplayItems_count
= 0; /* number of items to display */
244 int fs_showDefault
= 1; /* show all of FS data ? */
247 /* same use as above for Cache Managers */
248 short cm_Display_map
[NUM_CM_STAT_ENTRIES
];
249 int cm_DisplayItems_count
= 0; /* number of items to display */
250 int cm_showDefault
= 1; /* show all of CM data ? */
252 extern int fs_currPage
; /* current page number in the File Servers frame */
253 extern int fs_curr_LCol
; /* current leftmost column on display on FS frame */
255 extern int cm_currPage
; /* current page number in the Cache Managers frame */
256 extern int cm_curr_LCol
; /* current leftmost column on display on CM frame */
258 /* File server and Cache manager data is classified into sections &
259 groups to help the user choose what he wants displayed */
260 extern char *fs_categories
[]; /* file server data category names */
261 extern char *cm_categories
[]; /* cache manager data category names */
264 static int fs_FullPerfs_ltoa(struct fs_Display_Data
*a_fsData
,
265 struct xstat_fs_ProbeResults
*a_fsResults
);
266 static int fs_CallBackStats_ltoa(struct fs_Display_Data
*a_fsData
,
267 struct xstat_fs_ProbeResults
*a_fsResults
);
269 #ifdef HAVE_STRCASESTR
270 extern char * strcasestr(const char *, const char *);
273 strcasestr(): Return first occurence of pattern s2 in s1, case
276 This routine is required since I made pattern matching of the
277 config file to be case insensitive.
296 while (len1
>= len2
&& len1
> 0) {
297 if ((strncasecmp(ptr
, s2
, len2
)) == 0)
307 GetHostByName(char *name
)
314 he
= gethostbyname(name
);
316 /* On solaris the above does not resolve hostnames to full names */
318 memcpy(ip_addr
, he
->h_addr
, he
->h_length
);
319 he
= gethostbyaddr(ip_addr
, he
->h_length
, he
->h_addrtype
);
326 /*-----------------------------------------------------------------------
330 * Exit gracefully from the afsmonitor. Frees memory where appropriate,
331 * cleans up after gtx and closes all open file descriptors. If a user
332 * provided threshold handler is to be exec'ed then gtx cleanup is
333 * not performed and an exec() is made instead of an exit().
339 * This function is called to execute a user handler only
340 * by a child process.
342 *----------------------------------------------------------------------*/
345 afsmon_Exit(int a_exitVal
) /* exit code */
347 static char rn
[] = "afsmon_Exit";
348 struct afsmon_fs_Results_list
*tmp_fslist
;
349 struct afsmon_fs_Results_list
*next_fslist
;
350 struct xstat_fs_ProbeResults
*tmp_xstat_fsPR
;
351 struct afsmon_cm_Results_list
*tmp_cmlist
;
352 struct afsmon_cm_Results_list
*next_cmlist
;
353 struct xstat_cm_ProbeResults
*tmp_xstat_cmPR
;
354 struct afsmon_hostEntry
*curr_hostEntry
;
355 struct afsmon_hostEntry
*next_hostEntry
;
362 fprintf(debugFD
, "[ %s ] Called with exit code %d\n", rn
, a_exitVal
);
366 /* get out of curses first, but not if we are here to exec a threshold
367 * handler. If we do, the screen gets messed up */
368 if (gtx_initialized
&& !exec_fsThreshHandler
)
369 gator_cursesgwin_cleanup(afsmon_win
);
371 /* print the error message buffer */
372 if (errMsg
[0] != '\0')
373 fprintf(stderr
, "%s", errMsg
);
374 if (errMsg1
[0] != '\0')
375 fprintf(stderr
, "%s", errMsg1
);
377 /* deallocate file server circular buffers */
378 if (numFS
&& num_bufSlots
) {
380 fprintf(debugFD
, "freeing FS circular buffers ");
384 for (bufslot
= 0; bufslot
< num_bufSlots
; bufslot
++) {
386 fprintf(debugFD
, " %d) ", bufslot
);
387 if (afsmon_fs_ResultsCB
[bufslot
].list
!=
388 (struct afsmon_fs_Results_list
*)0) {
389 tmp_fslist
= afsmon_fs_ResultsCB
[bufslot
].list
;
392 /* make sure we do not go astray */
396 "[ %s ] error in deallocating fs CB\n",
400 next_fslist
= tmp_fslist
->next
;
401 for (i
= 0; i
< MAX_NUM_FS_COLLECTIONS
; i
++) {
402 tmp_xstat_fsPR
= tmp_fslist
->fsResults
[i
];
405 fprintf(debugFD
, "%d ", numFS
- j
);
407 /* free xstat_fs_Results data */
408 free(tmp_xstat_fsPR
->data
.AFS_CollData_val
);
409 free(tmp_xstat_fsPR
->connP
);
410 free(tmp_xstat_fsPR
);
413 /* free the fs list item */
415 tmp_fslist
= next_fslist
;
417 } /* while fs list items in this slot */
418 } /* if entries in this buffer slot */
419 } /* for each fs buffer slot */
421 fprintf(debugFD
, "\n");
426 /* deallocate cache manager curcular buffers */
427 if (numCM
&& num_bufSlots
) {
429 fprintf(debugFD
, "freeing CM curcular buffers ");
430 for (bufslot
= 0; bufslot
< num_bufSlots
; bufslot
++) {
432 fprintf(debugFD
, " %d) ", bufslot
);
433 if (afsmon_cm_ResultsCB
[bufslot
].list
!=
434 (struct afsmon_cm_Results_list
*)0) {
435 tmp_cmlist
= afsmon_cm_ResultsCB
[bufslot
].list
;
438 /* make sure we do not go astray */
442 "[ %s ] error in deallocating cm CB\n",
446 next_cmlist
= tmp_cmlist
->next
;
447 for (i
= 0; i
< MAX_NUM_CM_COLLECTIONS
; i
++) {
448 tmp_xstat_cmPR
= tmp_cmlist
->cmResults
[i
];
451 fprintf(debugFD
, "%d ", numCM
- j
);
452 /* make sure data is ok */
453 /* Print_cm_FullPerfInfo(tmp_xstat_cmPR); */
455 /* free xstat_cm_Results data */
456 free(tmp_xstat_cmPR
->data
.AFSCB_CollData_val
);
457 free(tmp_xstat_cmPR
->connP
);
459 free(tmp_cmlist
->cmResults
);
461 /* free the cm list item */
463 tmp_cmlist
= next_cmlist
;
465 } /* while cm list items in this slot */
466 } /* if entries in this buffer slot */
467 } /* for each cm buffer slot */
469 fprintf(debugFD
, "\n");
473 /* deallocate FS & CM Print buffers */
474 if (curr_fsData
!= NULL
) {
476 fprintf(debugFD
, "Deallocating FS Print Buffers .... curr");
479 if (prev_fsData
!= NULL
) {
481 fprintf(debugFD
, ", prev \n");
484 if (curr_cmData
!= NULL
) {
486 fprintf(debugFD
, "Deallocating CM Print Buffers .... curr");
489 if (prev_cmData
!= NULL
) {
491 fprintf(debugFD
, ", prev \n");
495 /* deallocate hostEntry lists */
498 fprintf(debugFD
, "Deallocating FS hostEntries ..");
499 curr_hostEntry
= FSnameList
;
500 while (curr_hostEntry
) {
501 next_hostEntry
= curr_hostEntry
->next
;
502 if (curr_hostEntry
->thresh
!= NULL
)
503 free(curr_hostEntry
->thresh
);
504 free(curr_hostEntry
);
505 curr_hostEntry
= next_hostEntry
;
508 fprintf(debugFD
, "\n");
512 fprintf(debugFD
, "Deallocating CM hostEntries ..");
513 curr_hostEntry
= CMnameList
;
514 while (curr_hostEntry
) {
515 next_hostEntry
= curr_hostEntry
->next
;
516 if (curr_hostEntry
->thresh
!= NULL
)
517 free(curr_hostEntry
->thresh
);
518 free(curr_hostEntry
);
519 curr_hostEntry
= next_hostEntry
;
522 fprintf(debugFD
, "\n");
525 /* close debug file */
531 if (exec_fsThreshHandler
) {
532 code
= execvp(fsHandler_argv
[0], fsHandler_argv
);
534 fprintf(stderr
, "execvp() of %s returned %d, errno %d\n",
535 fsHandler_argv
[0], code
, errno
);
543 /*-----------------------------------------------------------------------
547 * Insert a hostname in the file server names list.
552 *----------------------------------------------------------------------*/
555 insert_FS(char *a_hostName
) /* name of cache manager to be inserted in list */
557 static struct afsmon_hostEntry
*curr_item
;
558 static struct afsmon_hostEntry
*prev_item
;
560 if (*a_hostName
== '\0')
562 curr_item
= malloc(sizeof(struct afsmon_hostEntry
));
563 if (curr_item
== (struct afsmon_hostEntry
*)0) {
564 fprintf(stderr
, "Failed to allocate space for FS nameList\n");
568 strncpy(curr_item
->hostName
, a_hostName
, CFG_STR_LEN
);
569 curr_item
->next
= (struct afsmon_hostEntry
*)0;
570 curr_item
->numThresh
= 0;
571 curr_item
->thresh
= NULL
;
573 if (FSnameList
== (struct afsmon_hostEntry
*)0)
574 FSnameList
= curr_item
;
576 prev_item
->next
= curr_item
;
578 prev_item
= curr_item
;
579 /* record the address of this entry so that its threshold
580 * count can be incremented during the first pass of the config file */
581 last_hostEntry
= curr_item
;
586 /*-----------------------------------------------------------------------
591 * Prints the file server names linked list.
595 *----------------------------------------------------------------------*/
599 static char rn
[] = "print_FS";
600 struct afsmon_hostEntry
*tempFS
;
601 struct Threshold
*threshP
;
605 fprintf(debugFD
, "[ %s ] Called\n", rn
);
611 fprintf(debugFD
, "No of File Servers: %d\n", numFS
);
614 fprintf(debugFD
, "\t %s threshCount = %d\n", tempFS
->hostName
,
616 threshP
= tempFS
->thresh
;
617 for (i
= 0; i
< tempFS
->numThresh
; i
++, threshP
++)
618 fprintf(debugFD
, "\t thresh (%2d) %s %s %s\n",
619 threshP
->index
, threshP
->itemName
,
620 threshP
->threshVal
, threshP
->handler
);
621 } while ((tempFS
= tempFS
->next
) != (struct afsmon_hostEntry
*)0);
623 fprintf(debugFD
, "\t\t-----End of List-----\n");
629 /*-----------------------------------------------------------------------
633 * Insert a hostname in the cache manager names list.
638 *----------------------------------------------------------------------*/
641 insert_CM(char *a_hostName
) /* name of cache manager to be inserted in list */
643 static struct afsmon_hostEntry
*curr_item
;
644 static struct afsmon_hostEntry
*prev_item
;
646 if (*a_hostName
== '\0')
648 curr_item
= malloc(sizeof(struct afsmon_hostEntry
));
649 if (curr_item
== (struct afsmon_hostEntry
*)0) {
650 fprintf(stderr
, "Failed to allocate space for CM nameList\n");
654 strncpy(curr_item
->hostName
, a_hostName
, CFG_STR_LEN
);
655 curr_item
->next
= (struct afsmon_hostEntry
*)0;
656 curr_item
->numThresh
= 0;
657 curr_item
->thresh
= NULL
;
659 if (CMnameList
== (struct afsmon_hostEntry
*)0)
660 CMnameList
= curr_item
;
662 prev_item
->next
= curr_item
;
664 prev_item
= curr_item
;
665 /* side effect. note the address of this entry so that its threshold
666 * count can be incremented during the first pass of the config file */
667 last_hostEntry
= curr_item
;
673 /*-----------------------------------------------------------------------
678 * Prints the cache manager names linked list.
682 *----------------------------------------------------------------------*/
686 static char rn
[] = "print_CM";
687 struct afsmon_hostEntry
*tempCM
;
688 struct Threshold
*threshP
;
692 fprintf(debugFD
, "[ %s ] Called\n", rn
);
698 fprintf(debugFD
, "No of Cache Managers: %d\n", numCM
);
701 fprintf(debugFD
, "\t %s threshCount = %d\n", tempCM
->hostName
,
703 threshP
= tempCM
->thresh
;
704 for (i
= 0; i
< tempCM
->numThresh
; i
++, threshP
++)
705 fprintf(debugFD
, "\t thresh (%2d) %s %s %s\n",
706 threshP
->index
, threshP
->itemName
,
707 threshP
->threshVal
, threshP
->handler
);
708 } while ((tempCM
= tempCM
->next
) != (struct afsmon_hostEntry
*)0);
710 fprintf(debugFD
, "\t\t-----End of List-----\n");
717 /*-----------------------------------------------------------------------
721 * Parse the host entry line in the config file. Check the syntax,
722 * and inserts the host name in the FS ot CM linked list. Also
723 * remember if this entry was an fs or cm & the ptr to its hostEntry
724 * structure. The threshold entries in the config file are dependent
725 * on their position relative to the hostname entries. Hence it is
726 * required to remember the names of the last file server and cache
727 * manager entries that were processed.
733 *----------------------------------------------------------------------*/
736 parse_hostEntry(char *a_line
)
737 { /* parse_hostEntry */
739 static char rn
[] = "parse_hostEntry"; /* routine name */
740 char opcode
[CFG_STR_LEN
]; /* specifies type of config entry */
741 char arg1
[CFG_STR_LEN
]; /* hostname or qualifier (fs/cm?) */
742 char arg2
[CFG_STR_LEN
]; /* threshold variable */
743 char arg3
[CFG_STR_LEN
]; /* threshold value */
744 char arg4
[CFG_STR_LEN
]; /* user's handler */
745 struct hostent
*he
; /* host entry */
748 fprintf(debugFD
, "[ %s ] Called, a_line = %s\n", rn
, a_line
);
758 sscanf(a_line
, "%s %s %s %s %s", opcode
, arg1
, arg2
, arg3
, arg4
);
759 /* syntax is "opcode hostname" */
760 if ((strlen(arg2
)) != 0) {
761 fprintf(stderr
, "[ %s ] Extraneous characters at end of line\n", rn
);
766 he
= GetHostByName(arg1
);
768 fprintf(stderr
, "[ %s ] Unable to resolve hostname %s\n", rn
, arg1
);
772 if ((strcasecmp(opcode
, "fs")) == 0) {
773 /* use the complete host name to insert in the file server names list */
774 insert_FS(he
->h_name
);
775 /* note that last host entry in the config file was fs */
778 /* threholds are not global anymore */
779 if (global_ThreshFlag
)
780 global_ThreshFlag
= 0;
781 } else if ((strcasecmp(opcode
, "cm")) == 0) {
782 /* use the complete host name to insert in the CM names list */
783 insert_CM(he
->h_name
);
784 /* last host entry in the config file was cm */
787 /* threholds are not global anymore */
788 if (global_ThreshFlag
)
789 global_ThreshFlag
= 0;
796 /*-----------------------------------------------------------------------
797 * parse_threshEntry()
800 * Parse the threshold entry line in the config file. This function is
801 * called in the the first pass of the config file. It checks the syntax
802 * of the config lines and verifies their positional validity - eg.,
803 * a cm threshold cannot appear after a fs hostname entry, etc.
804 * It also counts the thresholds applicable to each host.
810 *----------------------------------------------------------------------*/
813 parse_threshEntry(char *a_line
)
814 { /* parse_threshEntry */
815 static char rn
[] = "parse_threshEntry"; /* routine name */
816 char opcode
[CFG_STR_LEN
]; /* specifies type of config entry */
817 char arg1
[CFG_STR_LEN
]; /* hostname or qualifier (fs/cm?) */
818 char arg2
[CFG_STR_LEN
]; /* threshold variable */
819 char arg3
[CFG_STR_LEN
]; /* threshold value */
820 char arg4
[CFG_STR_LEN
]; /* user's handler */
821 char arg5
[CFG_STR_LEN
]; /* junk characters */
824 fprintf(debugFD
, "[ %s ] Called, a_line = %s\n", rn
, a_line
);
835 sscanf(a_line
, "%s %s %s %s %s %s", opcode
, arg1
, arg2
, arg3
, arg4
, arg5
);
837 /* syntax is "thresh fs/cm variable_name threshold_value [handler] " */
838 if (((strlen(arg1
)) == 0) || ((strlen(arg2
)) == 0)
839 || ((strlen(arg3
)) == 0)) {
840 fprintf(stderr
, "[ %s ] Incomplete line\n", rn
);
843 if (strlen(arg3
) > THRESH_VAR_LEN
- 2) {
844 fprintf(stderr
, "[%s ] threshold value too long\n", rn
);
848 if ((strcasecmp(arg1
, "fs")) == 0) {
849 switch (lastHostType
) {
850 case 0: /* its a global threshold */
851 global_fsThreshCount
++;
853 case 1: /* inc thresh count of last file server */
854 last_hostEntry
->numThresh
++;
858 "[ %s ] A threshold for a File Server cannot be placed after a Cache Manager host entry in the config file \n",
862 fprintf(stderr
, "[ %s ] Programming error 1\n", rn
);
865 } else if ((strcasecmp(arg1
, "cm")) == 0) {
866 switch (lastHostType
) {
867 case 0: /* its a global threshold */
868 global_cmThreshCount
++;
870 case 2: /* inc thresh count of last cache manager */
871 last_hostEntry
->numThresh
++;
875 "[ %s ] A threshold for a Cache Manager cannot be placed after a File Server host entry in the config file \n",
879 fprintf(stderr
, "[ %s ] Programming error 2\n", rn
);
884 "[ %s ] Syntax error. Second argument should be \"fs\" or \"cm\" \n",
890 } /* parse_threshEntry */
893 /*-----------------------------------------------------------------------
897 * The thresholds applicable to each host machine are stored in the
898 * FSnameList and CMnameList. Threshold entries in the config file are
899 * context sensitive. The host to which this threshold is applicable
900 * is pointed to by last_fsHost (for file servers) and last_cmHost
901 * for cache managers. For global thresholds the info is recorded for
902 * all the hosts. This function is called in the second pass of the
903 * config file. In the first pass a count of the number of global
904 * thresholds is determined and this information is used in this
905 * routine. If threshold entries are duplicated the first entry is
907 * Each threshold entry also has an index field. This is a positional
908 * index to the corresponding variable in the prev_[fs/cm]Data arrays.
909 * This makes it easy to check the threshold for overflow.
914 *----------------------------------------------------------------------*/
917 store_threshold(int a_type
, /* 1 = fs , 2 = cm */
918 char *a_varName
, /* threshold name */
919 char *a_value
, /* threshold value */
920 char *a_handler
) /* threshold overflow handler */
921 { /* store_thresholds */
923 static char rn
[] = "store_thresholds"; /* routine name */
924 struct afsmon_hostEntry
*tmp_host
; /* tmp ptr to hostEntry */
925 struct afsmon_hostEntry
*Header
; /* tmp ptr to hostEntry list header */
926 struct Threshold
*threshP
; /* tmp ptr to threshold list */
928 int index
; /* index to fs_varNames or cm_varNames */
931 int srvCount
; /* tmp count of host names */
932 int *global_TC
; /* ptr to global_xxThreshCount */
937 "[ %s ] Called, a_type= %d, a_varName= %s, a_value= %s, a_handler=%s\n",
938 rn
, a_type
, a_varName
, a_value
, a_handler
);
942 /* resolve the threshold variable name */
944 if (a_type
== 1) { /* fs threshold */
945 for (index
= 0; index
< NUM_FS_STAT_ENTRIES
; index
++) {
946 if (strcasecmp(a_varName
, fs_varNames
[index
]) == 0) {
952 fprintf(stderr
, "[ %s ] Unknown FS threshold variable name %s\n",
958 hostname
= last_fsHost
;
959 global_TC
= &global_fsThreshCount
;
960 } else if (a_type
== 2) { /* cm threshold */
961 for (index
= 0; index
< NUM_CM_STAT_ENTRIES
; index
++) {
962 if (strcasecmp(a_varName
, cm_varNames
[index
]) == 0) {
968 fprintf(stderr
, "[ %s ] Unknown CM threshold variable name %s\n",
974 hostname
= last_cmHost
;
975 global_TC
= &global_cmThreshCount
;
981 /* if the global thresh count is not zero, place this threshold on
982 * all the host entries */
986 for (i
= 0; i
< srvCount
; i
++) {
987 threshP
= tmp_host
->thresh
;
989 for (j
= 0; j
< tmp_host
->numThresh
; j
++) {
990 if ((threshP
->itemName
[0] == '\0')
991 || (strcasecmp(threshP
->itemName
, a_varName
) == 0)) {
992 strlcpy(threshP
->itemName
, a_varName
,
993 sizeof(threshP
->itemName
));
994 strlcpy(threshP
->threshVal
, a_value
,
995 sizeof(threshP
->threshVal
));
996 strlcpy(threshP
->handler
, a_handler
,
997 sizeof(threshP
->handler
));
998 threshP
->index
= index
;
1005 fprintf(stderr
, "[ %s ] Could not insert threshold entry",
1007 fprintf(stderr
, "for %s in thresh list of host %s \n",
1008 a_varName
, tmp_host
->hostName
);
1011 tmp_host
= tmp_host
->next
;
1017 /* it is not a global threshold, insert it in the thresh list of this
1018 * host only. We overwrite the global threshold if it was alread set */
1020 if (*hostname
== '\0') {
1021 fprintf(stderr
, "[ %s ] Programming error 3\n", rn
);
1025 /* get the hostEntry that this threshold belongs to */
1028 for (i
= 0; i
< srvCount
; i
++) {
1029 if (strcasecmp(tmp_host
->hostName
, hostname
) == 0) {
1033 tmp_host
= tmp_host
->next
;
1036 fprintf(stderr
, "[ %s ] Unable to find host %s in %s hostEntry list",
1037 rn
, hostname
, (a_type
- 1) ? "CM" : "FS");
1041 /* put this entry on the thresh list of this host, overwrite global value
1044 threshP
= tmp_host
->thresh
;
1046 for (i
= 0; i
< tmp_host
->numThresh
; i
++) {
1047 if ((threshP
->itemName
[0] == '\0')
1048 || (strcasecmp(threshP
->itemName
, a_varName
) == 0)) {
1049 strlcpy(threshP
->itemName
, a_varName
, sizeof(threshP
->itemName
));
1050 strlcpy(threshP
->threshVal
, a_value
, sizeof(threshP
->threshVal
));
1051 strlcpy(threshP
->handler
, a_handler
, sizeof(threshP
->handler
));
1052 threshP
->index
= index
;
1061 "[ %s ] Unable to insert threshold %s for %s host %s\n", rn
,
1062 a_varName
, (a_type
- 1) ? "CM" : "FS", tmp_host
->hostName
);
1068 } /* store_thresholds */
1071 /*-----------------------------------------------------------------------
1075 * This function process a "show" entry in the config file. A "show"
1076 * entry specifies what statistics the user wants to see. File
1077 * server and Cache Manager data is divided into sections. Each section
1078 * is made up of one or more groups. If a group name is specified only
1079 * those statistics under that group are shown. If a section name is
1080 * specified all the groups under this section are shown.
1081 * Data as obtained from the xstat probes is considered to be ordered.
1082 * This data is mapped to the screen thru fs_Display_map[] and
1083 * cm_Display_map[]. This routine parses the "show" entry against the
1084 * section/group names in the [fs/cm]_categories[] array. If there is
1085 * no match it tries to match it against a variable name in
1086 * [fs/cm]_varNames[] array. In each case the corresponding indices to
1087 * the data is the [fs/cm]_displayInfo[] is recorded.
1091 * Failure: -1 (invalid entry)
1092 * > -1 (programming error)
1093 *----------------------------------------------------------------------*/
1096 parse_showEntry(char *a_line
)
1097 { /* parse_showEntry */
1098 static char rn
[] = "parse_showEntry";
1099 char opcode
[CFG_STR_LEN
]; /* specifies type of config entry */
1100 char arg1
[CFG_STR_LEN
]; /* show fs or cm entry ? */
1101 char arg2
[CFG_STR_LEN
]; /* what we gotta show */
1102 char arg3
[CFG_STR_LEN
]; /* junk */
1103 char catName
[CFG_STR_LEN
]; /* for category names */
1104 int numGroups
; /* number of groups in a section */
1108 int idx
= 0; /* index to fs_categories[] */
1114 fprintf(debugFD
, "[ %s ] Called, a_line= %s\n", rn
, a_line
);
1121 sscanf(a_line
, "%s %s %s %s", opcode
, arg1
, arg2
, arg3
);
1123 if (arg3
[0] != '\0') {
1124 fprintf(stderr
, "[ %s ] Extraneous characters at end of line\n", rn
);
1128 if ((strcasecmp(arg1
, "fs") != 0) && (strcasecmp(arg1
, "cm") != 0)) {
1130 "[ %s ] Second argument of \"show\" directive should be \"fs\" or \"cm\" \n",
1135 /* Each entry can either be a variable name or a section/group name. Variable
1136 * names are listed in xx_varNames[] and section/group names in xx_categories[].
1137 * The section/group names in xx_categiries[] also give the starting/ending
1138 * indices of the variables belonging to that section/group. These indices
1139 * are stored in order in xx_Display_map[] and displayed to the screen in that
1142 /* To handle duplicate "show" entries we keep track of what what we have
1143 * already marked to show in the xx_showFlags[] */
1145 if (strcasecmp(arg1
, "fs") == 0) { /* its a File Server entry */
1147 /* mark that we have to show only what the user wants */
1150 /* if it is a section/group name, find it in the fs_categories[] array */
1153 if (strcasestr(arg2
, "_section") != NULL
1154 || strcasestr(arg2
, "_group") != NULL
) {
1156 while (idx
< FS_NUM_DATA_CATEGORIES
) {
1157 sscanf(fs_categories
[idx
], "%s %d %d", catName
, &fromIdx
,
1160 if (strcasecmp(arg2
, catName
) == 0) {
1166 if (!found
) { /* typo in section/group name */
1168 "[ %s ] Could not find section/group name %s\n", rn
,
1174 /* if it is a group name, read its start/end indices and fill in the
1175 * fs_Display_map[]. */
1177 if (strcasestr(arg2
, "_group") != NULL
) {
1179 if (fromIdx
< 0 || toIdx
< 0 || fromIdx
>= NUM_FS_STAT_ENTRIES
1180 || toIdx
>= NUM_FS_STAT_ENTRIES
)
1182 for (j
= fromIdx
; j
<= toIdx
; j
++) {
1183 if (!fs_showFlags
[j
]) {
1184 fs_Display_map
[fs_DisplayItems_count
] = j
;
1185 fs_DisplayItems_count
++;
1186 fs_showFlags
[j
] = 1;
1188 if (fs_DisplayItems_count
>= NUM_FS_STAT_ENTRIES
) {
1189 fprintf(stderr
, "[ %s ] fs_DisplayItems_count ovf\n", rn
);
1194 /* if it is a section name, get the count of number of groups in it and
1195 * for each group fill in the start/end indices in the fs_Display_map[] */
1197 if (strcasestr(arg2
, "_section") != NULL
) {
1198 /* fromIdx is actually the number of groups in thi section */
1199 numGroups
= fromIdx
;
1200 /* for each group in section */
1201 while (idx
< FS_NUM_DATA_CATEGORIES
&& numGroups
) {
1202 sscanf(fs_categories
[idx
], "%s %d %d", catName
, &fromIdx
,
1205 if (strcasestr(catName
, "_group") != NULL
) {
1206 if (fromIdx
< 0 || toIdx
< 0
1207 || fromIdx
>= NUM_FS_STAT_ENTRIES
1208 || toIdx
>= NUM_FS_STAT_ENTRIES
)
1210 for (j
= fromIdx
; j
<= toIdx
; j
++) {
1211 if (!fs_showFlags
[j
]) {
1212 fs_Display_map
[fs_DisplayItems_count
] = j
;
1213 fs_DisplayItems_count
++;
1214 fs_showFlags
[j
] = 1;
1216 if (fs_DisplayItems_count
>= NUM_FS_STAT_ENTRIES
) {
1218 "[ %s ] fs_DisplayItems_count ovf\n", rn
);
1223 fprintf(stderr
, "[ %s ] Error parsing groups for %s\n",
1229 } /* for each group in section */
1232 } else { /* it is a variable name */
1234 for (i
= 0; i
< NUM_FS_STAT_ENTRIES
; i
++) {
1235 if (strcasecmp(arg2
, fs_varNames
[i
]) == 0) {
1236 if (!fs_showFlags
[i
]) {
1237 fs_Display_map
[fs_DisplayItems_count
] = i
;
1238 fs_DisplayItems_count
++;
1239 fs_showFlags
[i
] = 1;
1241 if (fs_DisplayItems_count
>= NUM_FS_STAT_ENTRIES
) {
1242 fprintf(stderr
, "[ %s ] fs_DisplayItems_count ovf\n",
1249 if (!found
) { /* typo in section/group name */
1250 fprintf(stderr
, "[ %s ] Could not find variable name %s\n",
1254 } /* its a variable name */
1258 /* it is an fs entry */
1259 if (strcasecmp(arg1
, "cm") == 0) { /* its a Cache Manager entry */
1262 /* mark that we have to show only what the user wants */
1265 /* if it is a section/group name, find it in the cm_categories[] array */
1268 if (strcasestr(arg2
, "_section") != NULL
1269 || strcasestr(arg2
, "_group") != NULL
) {
1271 while (idx
< CM_NUM_DATA_CATEGORIES
) {
1272 sscanf(cm_categories
[idx
], "%s %d %d", catName
, &fromIdx
,
1275 if (strcasecmp(arg2
, catName
) == 0) {
1281 if (!found
) { /* typo in section/group name */
1283 "[ %s ] Could not find section/group name %s\n", rn
,
1289 /* if it is a group name, read its start/end indices and fill in the
1290 * cm_Display_map[]. */
1292 if (strcasestr(arg2
, "_group") != NULL
) {
1294 if (fromIdx
< 0 || toIdx
< 0 || fromIdx
>= NUM_CM_STAT_ENTRIES
1295 || toIdx
>= NUM_CM_STAT_ENTRIES
)
1297 for (j
= fromIdx
; j
<= toIdx
; j
++) {
1298 if (!cm_showFlags
[j
]) {
1299 cm_Display_map
[cm_DisplayItems_count
] = j
;
1300 cm_DisplayItems_count
++;
1301 cm_showFlags
[j
] = 1;
1303 if (cm_DisplayItems_count
>= NUM_CM_STAT_ENTRIES
) {
1304 fprintf(stderr
, "[ %s ] cm_DisplayItems_count ovf\n", rn
);
1309 /* if it is a section name, get the count of number of groups in it and
1310 * for each group fill in the start/end indices in the cm_Display_map[] */
1312 if (strcasestr(arg2
, "_section") != NULL
) {
1313 /* fromIdx is actually the number of groups in thi section */
1314 numGroups
= fromIdx
;
1315 /* for each group in section */
1316 while (idx
< CM_NUM_DATA_CATEGORIES
&& numGroups
) {
1317 sscanf(cm_categories
[idx
], "%s %d %d", catName
, &fromIdx
,
1320 if (strcasestr(catName
, "_group") != NULL
) {
1321 if (fromIdx
< 0 || toIdx
< 0
1322 || fromIdx
>= NUM_CM_STAT_ENTRIES
1323 || toIdx
>= NUM_CM_STAT_ENTRIES
)
1325 for (j
= fromIdx
; j
<= toIdx
; j
++) {
1326 if (!cm_showFlags
[j
]) {
1327 cm_Display_map
[cm_DisplayItems_count
] = j
;
1328 cm_DisplayItems_count
++;
1329 cm_showFlags
[j
] = 1;
1331 if (cm_DisplayItems_count
>= NUM_CM_STAT_ENTRIES
) {
1333 "[ %s ] cm_DisplayItems_count ovf\n", rn
);
1338 fprintf(stderr
, "[ %s ] Error parsing groups for %s\n",
1344 } /* for each group in section */
1345 } else { /* it is a variable name */
1347 for (i
= 0; i
< NUM_CM_STAT_ENTRIES
; i
++) {
1348 if (strcasecmp(arg2
, cm_varNames
[i
]) == 0) {
1349 if (!cm_showFlags
[i
]) {
1350 cm_Display_map
[cm_DisplayItems_count
] = i
;
1351 cm_DisplayItems_count
++;
1352 cm_showFlags
[i
] = 1;
1354 if (cm_DisplayItems_count
>= NUM_CM_STAT_ENTRIES
) {
1355 fprintf(stderr
, "[ %s ] cm_DisplayItems_count ovf\n",
1362 if (!found
) { /* typo in section/group name */
1363 fprintf(stderr
, "[ %s ] Could not find variable name %s\n",
1367 } /* its a variable name */
1370 /* it is an cm entry */
1372 } /* parse_showEntry */
1375 /*-----------------------------------------------------------------------
1376 * process_config_file()
1379 * Parse config file entries in two passes. In the first pass:
1380 * - the syntax of all the entries is checked
1381 * - host names are noted and the FSnamesList and CMnamesList
1383 * - a count of the global thresholds and local thresholds of
1384 * each host are counted.
1385 * - "show" entries are processed.
1386 * In the second pass:
1387 * - thresholds are stored
1391 * Failure: Exits afsmonitor showing error and line.
1392 *----------------------------------------------------------------------*/
1395 process_config_file(char *a_config_filename
)
1396 { /* process_config_file() */
1397 static char rn
[] = "process_config_file"; /* routine name */
1398 FILE *configFD
; /* config file descriptor */
1399 char line
[4 * CFG_STR_LEN
]; /* a line of config file */
1400 char opcode
[CFG_STR_LEN
]; /* specifies type of config entry */
1401 char arg1
[CFG_STR_LEN
]; /* hostname or qualifier (fs/cm?) */
1402 char arg2
[CFG_STR_LEN
]; /* threshold variable */
1403 char arg3
[CFG_STR_LEN
]; /* threshold value */
1404 char arg4
[CFG_STR_LEN
]; /* user's handler */
1405 struct afsmon_hostEntry
*curr_host
;
1406 struct hostent
*he
; /* hostentry to resolve host name */
1407 char *handlerPtr
; /* ptr to pass theresh handler string */
1408 int code
= 0; /* error code */
1409 int linenum
= 0; /* config file line number */
1410 int error_in_config
; /* syntax errors in config file ?? */
1415 fprintf(debugFD
, "[ %s ] Called, a_config_filename= %s\n", rn
,
1420 /* open config file */
1422 configFD
= fopen(a_config_filename
, "r");
1423 if (configFD
== (FILE *) 0) {
1424 fprintf(stderr
, "Failed to open config file %s \n",
1427 fprintf(debugFD
, "[ %s ] Failed to open config file %s \n", rn
,
1434 /* parse config file */
1436 /* We process the config file in two passes. In the first pass we check
1437 * for correct syntax and for valid entries and also keep count of the
1438 * number of servers and thresholds to monitor. This the data strctures
1439 * can be arrays instead of link lists since we would know their sizes. */
1445 error_in_config
= 0; /* flag to note if config file has syntax errors */
1447 while ((fgets(line
, CFG_STR_LEN
, configFD
)) != NULL
) {
1453 sscanf(line
, "%s %s %s %s %s", opcode
, arg1
, arg2
, arg3
, arg4
);
1455 /* skip blank lines and comment lines */
1456 if ((strlen(opcode
) == 0) || line
[0] == '#')
1459 if ((strcasecmp(opcode
, "fs") == 0)
1460 || (strcasecmp(opcode
, "cm")) == 0) {
1461 code
= parse_hostEntry(line
);
1462 } else if ((strcasecmp(opcode
, "thresh")) == 0) {
1463 code
= parse_threshEntry(line
);
1464 } else if ((strcasecmp(opcode
, "show")) == 0) {
1465 code
= parse_showEntry(line
);
1467 fprintf(stderr
, "[ %s ] Unknown opcode %s\n", rn
, opcode
);
1472 fprintf(stderr
, "[ %s ] Error in line:\n %d: %s\n", rn
, linenum
,
1474 error_in_config
= 1;
1478 if (error_in_config
)
1482 fprintf(debugFD
, "Global FS thresholds count = %d\n",
1483 global_fsThreshCount
);
1484 fprintf(debugFD
, "Global CM thresholds count = %d\n",
1485 global_cmThreshCount
);
1489 /* the threshold count of all hosts in increased by 1 for each global
1490 * threshold. If one of the hosts has a local threshold for the same
1491 * variable it would end up being counted twice. whats a few bytes of memory
1492 * wasted anyway ? */
1494 if (global_fsThreshCount
) {
1495 curr_host
= FSnameList
;
1496 for (i
= 0; i
< numFS
; i
++) {
1497 curr_host
->numThresh
+= global_fsThreshCount
;
1498 curr_host
= curr_host
->next
;
1501 if (global_cmThreshCount
) {
1502 curr_host
= CMnameList
;
1503 for (i
= 0; i
< numCM
; i
++) {
1504 curr_host
->numThresh
+= global_cmThreshCount
;
1505 curr_host
= curr_host
->next
;
1510 /* make sure we have something to monitor */
1511 if (numFS
== 0 && numCM
== 0) {
1513 "\nConfig file must specify atleast one File Server or Cache Manager host to monitor.\n");
1520 fseek(configFD
, 0, 0); /* seek to the beginning */
1523 /* allocate memory for threshold lists */
1524 curr_host
= FSnameList
;
1525 for (i
= 0; i
< numFS
; i
++) {
1526 if (curr_host
->hostName
[0] == '\0') {
1527 fprintf(stderr
, "[ %s ] Programming error 4\n", rn
);
1530 if (curr_host
->numThresh
) {
1531 numBytes
= curr_host
->numThresh
* sizeof(struct Threshold
);
1532 curr_host
->thresh
= malloc(numBytes
);
1533 if (curr_host
->thresh
== NULL
) {
1534 fprintf(stderr
, "[ %s ] Memory Allocation error 1", rn
);
1537 memset(curr_host
->thresh
, 0, numBytes
);
1539 curr_host
= curr_host
->next
;;
1542 curr_host
= CMnameList
;
1543 for (i
= 0; i
< numCM
; i
++) {
1544 if (curr_host
->hostName
[0] == '\0') {
1545 fprintf(stderr
, "[ %s ] Programming error 5\n", rn
);
1548 if (curr_host
->numThresh
) {
1549 numBytes
= curr_host
->numThresh
* sizeof(struct Threshold
);
1550 curr_host
->thresh
= malloc(numBytes
);
1551 if (curr_host
->thresh
== NULL
) {
1552 fprintf(stderr
, "[ %s ] Memory Allocation error 2", rn
);
1555 memset(curr_host
->thresh
, 0, numBytes
);
1557 curr_host
= curr_host
->next
;;
1566 last_fsHost
[0] = '\0';
1567 last_cmHost
[0] = '\0';
1569 while ((fgets(line
, CFG_STR_LEN
, configFD
)) != NULL
) {
1575 sscanf(line
, "%s %s %s %s %s", opcode
, arg1
, arg2
, arg3
, arg4
);
1578 /* if we have a host entry, remember the host name */
1579 if (strcasecmp(opcode
, "fs") == 0) {
1580 he
= GetHostByName(arg1
);
1581 strncpy(last_fsHost
, he
->h_name
, HOST_NAME_LEN
);
1582 } else if (strcasecmp(opcode
, "cm") == 0) {
1583 he
= GetHostByName(arg1
);
1584 strncpy(last_cmHost
, he
->h_name
, HOST_NAME_LEN
);
1585 } else if (strcasecmp(opcode
, "thresh") == 0) {
1586 /* if we have a threshold handler it may have arguments
1587 * and the sscanf() above would not get them, so do the
1591 /* now skip over 4 words - this is done by first
1592 * skipping leading blanks then skipping a word */
1593 for (i
= 0; i
< 4; i
++) {
1594 while (isspace(*handlerPtr
))
1596 while (!isspace(*handlerPtr
))
1599 while (isspace(*handlerPtr
))
1601 /* we how have a pointer to the start of the handler
1604 handlerPtr
= arg4
; /* empty string */
1607 if (strcasecmp(arg1
, "fs") == 0)
1608 code
= store_threshold(1, /* 1 = fs */
1609 arg2
, arg3
, handlerPtr
);
1611 else if (strcasecmp(arg1
, "cm") == 0)
1612 code
= store_threshold(2, /* 2 = fs */
1613 arg2
, arg3
, handlerPtr
);
1616 fprintf(stderr
, "[ %s ] Programming error 6\n", rn
);
1620 fprintf(stderr
, "[ %s ] Failed to store threshold\n", rn
);
1621 fprintf(stderr
, "[ %s ] Error processing line:\n%d: %s", rn
,
1633 /*-----------------------------------------------------------------------
1638 * Print the File Server circular buffer.
1642 *----------------------------------------------------------------------*/
1646 { /* Print_FS_CB() */
1648 struct afsmon_fs_Results_list
*fslist
;
1653 /* print valid info in the fs CB */
1657 "==================== FS Buffer ========================\n");
1658 fprintf(debugFD
, "afsmon_fs_curr_CBindex = %d\n",
1659 afsmon_fs_curr_CBindex
);
1660 fprintf(debugFD
, "afsmon_fs_curr_probeNum = %d\n\n",
1661 afsmon_fs_curr_probeNum
);
1663 for (i
= 0; i
< num_bufSlots
; i
++) {
1664 fprintf(debugFD
, "\t--------- slot %d ----------\n", i
);
1665 fslist
= afsmon_fs_ResultsCB
[i
].list
;
1668 for (k
= 0; k
< MAX_NUM_FS_COLLECTIONS
; k
++) {
1669 if (!(fslist
->empty
[k
])) {
1670 fprintf(debugFD
, "\t %d) probeNum = %d host = %s cn = %d",
1672 fslist
->fsResults
[k
]->probeNum
,
1673 fslist
->fsResults
[k
]->connP
->hostName
,
1674 fslist
->fsResults
[k
]->collectionNumber
);
1675 if (fslist
->fsResults
[k
]->probeOK
)
1676 fprintf(debugFD
, " NOTOK\n");
1678 fprintf(debugFD
, " OK\n");
1680 fprintf(debugFD
, "\t %d) -- empty --\n", j
);
1682 fslist
= fslist
->next
;
1685 if (fslist
!= (struct afsmon_fs_Results_list
*)0)
1686 fprintf(debugFD
, "dangling last next ptr fs CB\n");
1689 } /* Print_FS_CB() */
1691 /*-----------------------------------------------------------------------
1692 * save_FS_results_inCB()
1695 * Saves the results of the latest FS probe in the fs circular
1696 * buffers. If the current probe cycle is in progress the contents
1697 * of xstat_fs_Results are copied to the end of the list of results
1698 * in the current slot (pointed to by afsmon_fs_curr_CBindex). If
1699 * a new probe cycle has started the next slot in the circular buffer
1700 * is initialized and the results copied. Note that the Rx related
1701 * information available in xstat_fs_Results is not copied.
1705 * Failure: Exits afsmonitor.
1706 *----------------------------------------------------------------------*/
1708 save_FS_results_inCB(int a_newProbeCycle
) /* start of a new probe cycle ? */
1709 { /* save_FS_results_inCB() */
1710 static char rn
[] = "save_FS_results_inCB"; /* routine name */
1711 struct afsmon_fs_Results_list
*tmp_fslist_item
; /* temp fs list item */
1712 struct xstat_fs_ProbeResults
*tmp_fsPR
; /* temp ptr */
1717 fprintf(debugFD
, "[ %s ] Called, a_newProbeCycle= %d\n", rn
,
1722 switch (xstat_fs_Results
.collectionNumber
) {
1723 case AFS_XSTATSCOLL_FULL_PERF_INFO
:
1726 case AFS_XSTATSCOLL_CBSTATS
:
1730 fprintf(stderr
, "[ %s ] collection number %d is out of range.\n",
1731 rn
, xstat_fs_Results
.collectionNumber
);
1735 /* If a new probe cycle started, mark the list in the current buffer
1736 * slot empty for resuse. Note that afsmon_fs_curr_CBindex was appropriately
1737 * incremented in afsmon_FS_Handler() */
1739 if (a_newProbeCycle
) {
1740 tmp_fslist_item
= afsmon_fs_ResultsCB
[afsmon_fs_curr_CBindex
].list
;
1741 for (i
= 0; i
< numFS
; i
++) {
1742 tmp_fslist_item
->empty
[index
] = 1;
1743 tmp_fslist_item
= tmp_fslist_item
->next
;
1747 /* locate last unused item in list */
1748 tmp_fslist_item
= afsmon_fs_ResultsCB
[afsmon_fs_curr_CBindex
].list
;
1749 for (i
= 0; i
< numFS
; i
++) {
1750 if (tmp_fslist_item
->empty
[index
])
1752 tmp_fslist_item
= tmp_fslist_item
->next
;
1755 /* if we could not find one we have an inconsistent list */
1756 if (!tmp_fslist_item
->empty
[index
]) {
1758 "[ %s ] list inconsistency 1. unable to find an empty slot to store results of probenum %d of %s\n",
1759 rn
, xstat_fs_Results
.probeNum
,
1760 xstat_fs_Results
.connP
->hostName
);
1764 tmp_fsPR
= tmp_fslist_item
->fsResults
[index
];
1766 /* copy hostname and probe number and probe time and probe status.
1767 * if the probe failed return now */
1769 memcpy(tmp_fsPR
->connP
->hostName
, xstat_fs_Results
.connP
->hostName
,
1770 sizeof(xstat_fs_Results
.connP
->hostName
));
1771 tmp_fsPR
->probeNum
= xstat_fs_Results
.probeNum
;
1772 tmp_fsPR
->probeTime
= xstat_fs_Results
.probeTime
;
1773 tmp_fsPR
->probeOK
= xstat_fs_Results
.probeOK
;
1774 if (xstat_fs_Results
.probeOK
) { /* probeOK = 1 => notOK */
1775 /* we have a nonempty results structure so mark the list item used */
1776 tmp_fslist_item
->empty
[index
] = 0;
1780 /* copy connection information */
1781 memcpy(&(tmp_fsPR
->connP
->skt
), &(xstat_fs_Results
.connP
->skt
),
1782 sizeof(struct sockaddr_in
));
1784 memcpy(tmp_fsPR
->connP
->hostName
, xstat_fs_Results
.connP
->hostName
,
1785 sizeof(xstat_fs_Results
.connP
->hostName
));
1786 tmp_fsPR
->collectionNumber
= xstat_fs_Results
.collectionNumber
;
1788 /* copy the probe data information */
1789 tmp_fsPR
->data
.AFS_CollData_len
=
1790 min(xstat_fs_Results
.data
.AFS_CollData_len
,
1791 afsmon_fs_results_length
[index
]);
1792 memcpy(tmp_fsPR
->data
.AFS_CollData_val
,
1793 xstat_fs_Results
.data
.AFS_CollData_val
,
1794 tmp_fsPR
->data
.AFS_CollData_len
* sizeof(afs_int32
));
1797 /* we have a valid results structure so mark the list item used */
1798 tmp_fslist_item
->empty
[index
] = 0;
1800 /* Print the fs circular buffer */
1804 } /* save_FS_results_inCB() */
1807 /*-----------------------------------------------------------------------
1811 * The results of xstat probes are stored in a string format in
1812 * the arrays curr_fsData and prev_fsData. The information stored in
1813 * prev_fsData is copied to the screen.
1814 * This function converts xstat FS results from longs to strings and
1815 * place them in the given buffer (a pointer to an item in curr_fsData).
1816 * When a probe cycle completes, curr_fsData is copied to prev_fsData
1817 * in afsmon_FS_Hnadler().
1821 *----------------------------------------------------------------------*/
1824 fs_Results_ltoa(struct fs_Display_Data
*a_fsData
, /* target buffer */
1825 struct xstat_fs_ProbeResults
*a_fsResults
) /* ptr to xstat fs Results */
1826 { /* fs_Results_ltoa */
1828 static char rn
[] = "fs_Results_ltoa"; /* routine name */
1831 fprintf(debugFD
, "[ %s ] Called, a_fsData= %p, a_fsResults= %p\n", rn
,
1832 a_fsData
, a_fsResults
);
1836 switch (a_fsResults
->collectionNumber
) {
1837 case AFS_XSTATSCOLL_FULL_PERF_INFO
:
1838 fs_FullPerfs_ltoa(a_fsData
, a_fsResults
);
1840 case AFS_XSTATSCOLL_CBSTATS
:
1841 fs_CallBackStats_ltoa(a_fsData
, a_fsResults
);
1845 fprintf(debugFD
, "[ %s ] Unexpected collection id %d\n",
1846 rn
, a_fsResults
->collectionNumber
);
1851 } /* fs_Results_ltoa */
1853 /*-----------------------------------------------------------------------
1854 * fs_FullPerfs_ltoa()
1857 * Convert the full perf xstat collection from int32s to strings.
1861 *----------------------------------------------------------------------*/
1863 fs_FullPerfs_ltoa(struct fs_Display_Data
*a_fsData
,
1864 struct xstat_fs_ProbeResults
*a_fsResults
)
1867 struct fs_stats_FullPerfStats
*fullPerfP
;
1868 struct fs_stats_FullPerfStats buffer
;
1875 /* there are two parts to the xstat FS statistics
1876 * - fullPerfP->overall which give the overall performance statistics, and
1877 * - fullPerfP->det which gives detailed info about file server operation
1878 * execution times */
1880 code
= xstat_fs_DecodeFullPerfStats(&fullPerfP
,
1881 a_fsResults
->data
.AFS_CollData_val
,
1882 a_fsResults
->data
.AFS_CollData_len
,
1885 /* Not able to decode the full perf stats. Avoid displaying garbage. */
1886 for (i
= 0; i
< NUM_FS_STAT_ENTRIES
; i
++) {
1887 sprintf(a_fsData
->data
[i
], "%s", "--");
1892 /* copy overall performance statistics */
1893 srcbuf
= (afs_int32
*) & (fullPerfP
->overall
);
1895 for (i
= 0; i
< NUM_XSTAT_FS_AFS_PERFSTATS_LONGS
; i
++) {
1896 sprintf(a_fsData
->data
[idx
], "%d", *srcbuf
);
1902 srcbuf
= (afs_int32
*) & (fullPerfP
->det
.epoch
);
1903 sprintf(a_fsData
->data
[idx
], "%d", *srcbuf
); /* epoch */
1906 /* copy fs operation timing */
1908 srcbuf
= (afs_int32
*) (fullPerfP
->det
.rpcOpTimes
);
1911 * For every time value below, we'll have to skip an additional
1912 * 64 bits of input if struct timeval uses 64-bit values
1914 if (sizeof(struct timeval
) == 16)
1919 for (i
= 0; i
< FS_STATS_NUM_RPC_OPS
; i
++) {
1920 sprintf(a_fsData
->data
[idx
], "%d", *srcbuf
); /* numOps */
1923 sprintf(a_fsData
->data
[idx
], "%d", *srcbuf
); /* numSuccesses */
1926 tmpbuf
= srcbuf
++; /* sum time */
1927 sprintf(a_fsData
->data
[idx
], "%d.%06d", *tmpbuf
, *srcbuf
);
1932 tmpbuf
= srcbuf
++; /* sqr time */
1933 sprintf(a_fsData
->data
[idx
], "%d.%06d", *tmpbuf
, *srcbuf
);
1938 tmpbuf
= srcbuf
++; /* min time */
1939 sprintf(a_fsData
->data
[idx
], "%d.%06d", *tmpbuf
, *srcbuf
);
1944 tmpbuf
= srcbuf
++; /* max time */
1945 sprintf(a_fsData
->data
[idx
], "%d.%06d", *tmpbuf
, *srcbuf
);
1952 /* copy fs transfer timings */
1954 srcbuf
= (afs_int32
*) (fullPerfP
->det
.xferOpTimes
);
1955 for (i
= 0; i
< FS_STATS_NUM_XFER_OPS
; i
++) {
1956 sprintf(a_fsData
->data
[idx
], "%d", *srcbuf
); /* numOps */
1959 sprintf(a_fsData
->data
[idx
], "%d", *srcbuf
); /* numSuccesses */
1962 tmpbuf
= srcbuf
++; /* sum time */
1963 sprintf(a_fsData
->data
[idx
], "%d.%06d", *tmpbuf
, *srcbuf
);
1968 tmpbuf
= srcbuf
++; /* sqr time */
1969 sprintf(a_fsData
->data
[idx
], "%d.%06d", *tmpbuf
, *srcbuf
);
1974 tmpbuf
= srcbuf
++; /* min time */
1975 sprintf(a_fsData
->data
[idx
], "%d.%06d", *tmpbuf
, *srcbuf
);
1980 tmpbuf
= srcbuf
++; /* max time */
1981 sprintf(a_fsData
->data
[idx
], "%d.%06d", *tmpbuf
, *srcbuf
);
1986 sprintf(a_fsData
->data
[idx
], "%d", *srcbuf
); /* sum bytes */
1989 sprintf(a_fsData
->data
[idx
], "%d", *srcbuf
); /* min bytes */
1992 sprintf(a_fsData
->data
[idx
], "%d", *srcbuf
); /* max bytes */
1995 for (j
= 0; j
< FS_STATS_NUM_XFER_BUCKETS
; j
++) {
1996 sprintf(a_fsData
->data
[idx
], "%d", *srcbuf
); /* bucket[j] */
2005 /*-----------------------------------------------------------------------
2006 * fs_CallBackStats_ltoa()
2009 * Convert the callback counter xstat collection from
2010 * int32s to strings.
2014 *----------------------------------------------------------------------*/
2017 fs_CallBackStats_ltoa(struct fs_Display_Data
*a_fsData
,
2018 struct xstat_fs_ProbeResults
*a_fsResults
)
2022 int len
= a_fsResults
->data
.AFS_CollData_len
;
2023 afs_int32
*val
= a_fsResults
->data
.AFS_CollData_val
;
2025 /* place callback stats after the full perf stats */
2026 idx
= NUM_FS_FULLPERF_ENTRIES
;
2027 for (i
=0; i
< len
&& i
< NUM_FS_CB_ENTRIES
; i
++) {
2028 sprintf(a_fsData
->data
[idx
++], "%u", val
[i
]);
2033 /*-----------------------------------------------------------------------
2034 * execute_thresh_handler()
2037 * Execute a threshold handler. An agrv[] array of pointers is
2038 * constructed from the given data. A child process is forked
2039 * which immediately calls afsmon_Exit() with indication that a
2040 * threshold handler is to be exec'ed insted of exiting.
2044 * Failure: Afsmonitor exits if threshold handler has more than 20 args.
2045 *----------------------------------------------------------------------*/
2048 execute_thresh_handler(char *a_handler
, /* ptr to handler function + args */
2049 char *a_hostName
, /* host name for which threshold crossed */
2050 int a_hostType
, /* fs or cm ? */
2051 char *a_threshName
, /* threshold variable name */
2052 char *a_threshValue
, /* threshold value */
2053 char *a_actValue
) /* actual value */
2054 { /* execute_thresh_handler */
2056 static char rn
[] = "execute_thresh_handler";
2057 char fileName
[256]; /* file name to execute */
2061 int anotherArg
; /* boolean used to flag if another arg is available */
2065 "[ %s ] Called, a_handler= %s, a_hostName= %s, a_hostType= %d, a_threshName= %s, a_threshValue= %s, a_actValue= %s\n",
2066 rn
, a_handler
, a_hostName
, a_hostType
, a_threshName
,
2067 a_threshValue
, a_actValue
);
2072 /* get the filename to execute - the first argument */
2073 sscanf(a_handler
, "%s", fileName
);
2075 /* construct the contents of *argv[] */
2077 strncpy(fsHandler_args
[0], fileName
, 256);
2078 strncpy(fsHandler_args
[1], a_hostName
, HOST_NAME_LEN
);
2079 if (a_hostType
== FS
)
2080 strcpy(fsHandler_args
[2], "fs");
2082 strcpy(fsHandler_args
[2], "cm");
2083 strncpy(fsHandler_args
[3], a_threshName
, THRESH_VAR_NAME_LEN
);
2084 strncpy(fsHandler_args
[4], a_threshValue
, THRESH_VAR_LEN
);
2085 strncpy(fsHandler_args
[5], a_actValue
, THRESH_VAR_LEN
);
2092 /* we have already extracted the file name so skip to the 1st arg */
2093 while (isspace(*ch
)) /* leading blanks */
2095 while (!isspace(*ch
) && *ch
!= '\0') /* handler filename */
2098 while (*ch
!= '\0') {
2101 } else if (anotherArg
) {
2103 sscanf(ch
, "%s", fsHandler_args
[argNum
]);
2109 "Threshold handlers cannot have more than 20 arguments\n");
2115 fsHandler_argv
[argNum
] = NULL
;
2116 for (i
= 0; i
< argNum
; i
++)
2117 fsHandler_argv
[i
] = fsHandler_args
[i
];
2120 /* exec the threshold handler */
2123 exec_fsThreshHandler
= 1;
2128 } /* execute_thresh_handler */
2132 /*-----------------------------------------------------------------------
2133 * check_fs_thresholds()
2136 * Checks the thresholds and sets the overflow flag. Recall that the
2137 * thresholds for each host are stored in the hostEntry lists
2138 * [fs/cm]nameList arrays. The probe results are passed to this
2139 * function in the display-ready format - ie., as strings. Though
2140 * this looks stupid the overhead incurred in converting the strings
2141 * back to floats and comparing them is insignificant and
2142 * programming is easier this way.
2143 * The threshold flags are a part of the display structures
2148 *----------------------------------------------------------------------*/
2151 check_fs_thresholds(struct afsmon_hostEntry
*a_hostEntry
, /* ptr to hostEntry */
2152 struct fs_Display_Data
*a_Data
) /* ptr to fs data to be displayed */
2153 { /* check_fs_thresholds */
2155 static char rn
[] = "check_fs_thresholds";
2156 struct Threshold
*threshP
;
2157 double tValue
; /* threshold value */
2158 double pValue
; /* probe value */
2161 int count
; /* number of thresholds exceeded */
2164 fprintf(debugFD
, "[ %s ] Called, a_hostEntry= %p, a_Data= %p\n", rn
,
2165 a_hostEntry
, a_Data
);
2169 if (a_hostEntry
->numThresh
== 0) {
2170 /* store in ovf count ?? */
2175 threshP
= a_hostEntry
->thresh
;
2176 for (i
= 0; i
< a_hostEntry
->numThresh
; i
++) {
2177 if (threshP
->itemName
[0] == '\0') {
2181 idx
= threshP
->index
; /* positional index to the data array */
2182 tValue
= atof(threshP
->threshVal
); /* threshold value */
2183 pValue
= atof(a_Data
->data
[idx
]); /* probe value */
2184 if (pValue
> tValue
) {
2188 "[ %s ] fs = %s, thresh ovf for %s, threshold= %s, probevalue= %s\n",
2189 rn
, a_hostEntry
->hostName
, threshP
->itemName
,
2190 threshP
->threshVal
, a_Data
->data
[idx
]);
2193 /* if the threshold is crossed, call the handler function
2194 * only if this was a transition -ie, if the threshold was
2195 * crossed in the last probe too just count & keep quite! */
2197 if (!a_Data
->threshOvf
[idx
]) {
2198 a_Data
->threshOvf
[idx
] = 1;
2199 /* call the threshold handler if provided */
2200 if (threshP
->handler
[0] != '\0') {
2202 fprintf(debugFD
, "[ %s ] Calling ovf handler %s\n",
2203 rn
, threshP
->handler
);
2206 execute_thresh_handler(threshP
->handler
, a_Data
->hostName
,
2207 FS
, threshP
->itemName
,
2215 /* in case threshold was previously crossed, blank it out */
2216 a_Data
->threshOvf
[idx
] = 0;
2219 /* store the overflow count */
2220 a_Data
->ovfCount
= count
;
2223 } /* check_fs_thresholds */
2226 /*-----------------------------------------------------------------------
2227 * save_FS_data_forDisplay()
2230 * Does the following:
2231 * - if the probe number changed (ie, a cycle completed) curr_fsData
2232 * is copied to prev_fsData, curr_fsData zeroed and refresh the
2233 * overview screen and file server screen with the new data.
2234 * - store the results of the current probe from xstat_fs_Results into
2235 * curr_fsData. ie., convert longs to strings.
2236 * - check the thresholds
2240 * Failure: Exits afsmonitor.
2241 *----------------------------------------------------------------------*/
2244 save_FS_data_forDisplay(struct xstat_fs_ProbeResults
*a_fsResults
)
2245 { /* save_FS_data_forDisplay */
2247 static char rn
[] = "save_FS_data_forDisplay"; /* routine name */
2248 struct fs_Display_Data
*curr_fsDataP
; /* tmp ptr to curr_fsData */
2249 struct fs_Display_Data
*prev_fsDataP
; /* tmp ptr to prev_fsData */
2250 struct afsmon_hostEntry
*curr_host
;
2251 static int results_Received
= 0; /* number of probes reveived in
2252 * the current cycle. If this is equal to numFS we got all
2253 * the data we want in this cycle and can now display it */
2262 fprintf(debugFD
, "[ %s ] Called, a_fsResults= %p\n", rn
, a_fsResults
);
2266 /* store results in the display array */
2269 curr_fsDataP
= curr_fsData
;
2270 for (i
= 0; i
< numFS
; i
++) {
2271 if ((strcasecmp(curr_fsDataP
->hostName
, a_fsResults
->connP
->hostName
))
2281 "[ %s ] Could not insert FS probe results for host %s in fs display array\n",
2282 rn
, a_fsResults
->connP
->hostName
);
2286 /* Check the status of the probe. If it succeeded, we store its
2287 * results in the display data structure. If it failed we only mark
2288 * the failed status in the display data structure. */
2290 if (a_fsResults
->probeOK
) { /* 1 => notOK the xstat results */
2291 curr_fsDataP
->probeOK
= 0;
2293 /* print the probe status */
2295 fprintf(debugFD
, "\n\t\t ----- fs display data ------\n");
2296 fprintf(debugFD
, "HostName = %s PROBE FAILED \n",
2297 curr_fsDataP
->hostName
);
2301 } else { /* probe succeeded, update display data structures */
2302 curr_fsDataP
->probeOK
= 1;
2304 /* convert longs to strings and place them in curr_fsDataP */
2305 fs_Results_ltoa(curr_fsDataP
, a_fsResults
);
2307 /* compare with thresholds and set the overflow flags.
2308 * note that the threshold information is in the hostEntry structure and
2309 * each threshold item has a positional index associated with it */
2311 /* locate the hostEntry for this host */
2313 curr_host
= FSnameList
;
2314 for (i
= 0; i
< numFS
; i
++) {
2315 if (strcasecmp(curr_host
->hostName
, a_fsResults
->connP
->hostName
)
2320 curr_host
= curr_host
->next
;;
2325 code
= check_fs_thresholds(curr_host
, curr_fsDataP
);
2327 fprintf(stderr
, "[ %s ] Error in checking thresholds\n", rn
);
2331 /* print the info we just saved */
2334 fprintf(debugFD
, "\n\t\t ----- fs display data ------\n");
2335 fprintf(debugFD
, "HostName = %s\n", curr_fsDataP
->hostName
);
2336 for (i
= 0; i
< NUM_FS_STAT_ENTRIES
; i
++)
2337 fprintf(debugFD
, "%20s %30s %s\n", curr_fsDataP
->data
[i
],
2339 curr_fsDataP
->threshOvf
[i
] ? "(ovf)" : "");
2341 fprintf(debugFD
, "\t\t--------------------------------\n\n");
2345 } /* the probe succeeded, so we store the data in the display structure */
2348 /* if we have received a reply from all the hosts for this probe cycle,
2349 * it is time to display the data */
2352 if (results_Received
== numFS
* num_fs_collections
) {
2353 results_Received
= 0;
2355 if (afsmon_fs_curr_probeNum
!= afsmon_fs_prev_probeNum
+ 1) {
2356 sprintf(errMsg
, "[ %s ] Probe number %d missed! \n", rn
,
2357 afsmon_fs_prev_probeNum
+ 1);
2360 afsmon_fs_prev_probeNum
++;
2362 /* backup the display data of the probe cycle that just completed -
2363 * ie., store curr_fsData in prev_fsData */
2365 memcpy((char *)prev_fsData
, (char *)curr_fsData
,
2366 (numFS
* sizeof(struct fs_Display_Data
)));
2369 /* initialize curr_fsData but retain the threshold flag information.
2370 * The previous state of threshold flags is used in check_fs_thresholds() */
2372 numBytes
= NUM_FS_STAT_ENTRIES
* FS_STAT_STRING_LEN
;
2373 curr_fsDataP
= curr_fsData
;
2374 for (i
= 0; i
< numFS
; i
++) {
2375 curr_fsDataP
->probeOK
= 0;
2376 curr_fsDataP
->ovfCount
= 0;
2377 memset(curr_fsDataP
->data
, 0, numBytes
);
2382 /* prev_fsData now contains all the information for the probe cycle
2383 * that just completed. Now count the number of threshold overflows for
2384 * use in the overview screen */
2386 prev_fsDataP
= prev_fsData
;
2388 numHosts_onfs_alerts
= 0;
2389 for (i
= 0; i
< numFS
; i
++) {
2390 if (!prev_fsDataP
->probeOK
) { /* if probe failed */
2392 numHosts_onfs_alerts
++;
2394 if (prev_fsDataP
->ovfCount
) { /* overflows ?? */
2395 num_fs_alerts
+= prev_fsDataP
->ovfCount
;
2396 numHosts_onfs_alerts
++;
2401 fprintf(debugFD
, "Number of FS alerts = %d (on %d hosts)\n",
2402 num_fs_alerts
, numHosts_onfs_alerts
);
2404 /* flag that the data is now ready to be displayed */
2405 fs_Data_Available
= 1;
2407 /* call the Overview frame update routine (update only FS info) */
2408 ovw_refresh(ovw_currPage
, OVW_UPDATE_FS
);
2410 /* call the File Servers frame update routine */
2411 fs_refresh(fs_currPage
, fs_curr_LCol
);
2416 } /* save_FS_data_forDisplay */
2421 /*-----------------------------------------------------------------------
2422 * afsmon_FS_Handler()
2425 * This is the File Server probe Handler. It updates the afsmonitor
2426 * probe counts, fs circular buffer indices and calls the functions
2427 * to process the results of this probe.
2431 * Failure: Exits afsmonitor.
2432 *----------------------------------------------------------------------*/
2435 afsmon_FS_Handler(void)
2436 { /* afsmon_FS_Handler() */
2437 static char rn
[] = "afsmon_FS_Handler"; /* routine name */
2438 int newProbeCycle
; /* start of new probe cycle ? */
2439 int code
; /* return status */
2444 "[ %s ] Called, hostName= %s, probeNum= %d, status=%s, collection=%d\n", rn
,
2445 xstat_fs_Results
.connP
->hostName
, xstat_fs_Results
.probeNum
,
2446 xstat_fs_Results
.probeOK
? "FAILED" : "OK",
2447 xstat_fs_Results
.collectionNumber
);
2452 /* print the probe results to output file */
2453 if (afsmon_output
) {
2454 code
= afsmon_fsOutput(output_filename
, afsmon_detOutput
);
2457 "[ %s ] output to file %s returned error code=%d\n", rn
,
2458 output_filename
, code
);
2462 /* Update current probe number and circular buffer index. if current
2463 * probenum changed make sure it is only by 1 */
2466 if (xstat_fs_Results
.probeNum
!= afsmon_fs_curr_probeNum
) {
2467 if (xstat_fs_Results
.probeNum
== afsmon_fs_curr_probeNum
+ 1) {
2468 afsmon_fs_curr_probeNum
++;
2471 afsmon_fs_curr_CBindex
=
2472 (afsmon_fs_curr_probeNum
- 1) % num_bufSlots
;
2474 fprintf(stderr
, "[ %s ] probe number %d-1 missed\n", rn
,
2475 xstat_fs_Results
.probeNum
);
2481 /* store the results of this probe in the FS circular buffer */
2483 save_FS_results_inCB(newProbeCycle
);
2486 /* store the results of the current probe in the fs data display structure.
2487 * if the current probe number changed, swap the current and previous display
2488 * structures. note that the display screen is updated from these structures
2489 * and should start showing the data of the just completed probe cycle */
2491 save_FS_data_forDisplay(&xstat_fs_Results
);
2498 /*----------------------------------------------------------------------- *
2503 * Prints the Cache Manager circular buffer
2504 *----------------------------------------------------------------------*/
2508 { /* Print_CM_CB() */
2510 struct afsmon_cm_Results_list
*cmlist
;
2515 /* print valid info in the cm CB */
2519 "==================== CM Buffer ========================\n");
2520 fprintf(debugFD
, "afsmon_cm_curr_CBindex = %d\n",
2521 afsmon_cm_curr_CBindex
);
2522 fprintf(debugFD
, "afsmon_cm_curr_probeNum = %d\n\n",
2523 afsmon_cm_curr_probeNum
);
2525 for (i
= 0; i
< num_bufSlots
; i
++) {
2526 fprintf(debugFD
, "\t--------- slot %d ----------\n", i
);
2527 cmlist
= afsmon_cm_ResultsCB
[i
].list
;
2530 for (k
= 0; k
< MAX_NUM_CM_COLLECTIONS
; k
++) {
2531 if (!cmlist
->empty
[k
]) {
2533 "\t %d) probeNum = %d host = %s cn = %d",
2535 cmlist
->cmResults
[k
]->probeNum
,
2536 cmlist
->cmResults
[k
]->connP
->hostName
,
2537 cmlist
->cmResults
[k
]->collectionNumber
);
2538 if (cmlist
->cmResults
[k
]->probeOK
)
2539 fprintf(debugFD
, " NOTOK\n");
2541 fprintf(debugFD
, " OK\n");
2543 fprintf(debugFD
, "\t %d) -- empty --\n", j
);
2545 cmlist
= cmlist
->next
;
2548 if (cmlist
!= (struct afsmon_cm_Results_list
*)0)
2549 fprintf(debugFD
, "dangling last next ptr cm CB\n");
2555 /*-----------------------------------------------------------------------
2556 * save_CM_results_inCB()
2559 * Saves the results of the latest CM probe in the cm circular
2560 * buffers. If the current probe cycle is in progress the contents
2561 * of xstat_cm_Results are copied to the end of the list of results
2562 * in the current slot (pointed to by afsmon_cm_curr_CBindex). If
2563 * a new probe cycle has started the next slot in the circular buffer
2564 * is initialized and the results copied. Note that the Rx related
2565 * information available in xstat_cm_Results is not copied.
2569 * Failure: Exits afsmonitor.
2570 *----------------------------------------------------------------------*/
2573 save_CM_results_inCB(int a_newProbeCycle
) /* start of new probe cycle ? */
2574 { /* save_CM_results_inCB() */
2575 static char rn
[] = "save_CM_results_inCB"; /* routine name */
2576 struct afsmon_cm_Results_list
*tmp_cmlist_item
; /* temp cm list item */
2577 struct xstat_cm_ProbeResults
*tmp_cmPR
; /* temp ptr */
2583 fprintf(debugFD
, "[ %s ] Called, a_newProbeCycle= %d\n", rn
,
2588 if (xstat_cm_Results
.collectionNumber
== AFSCB_XSTATSCOLL_FULL_PERF_INFO
) {
2591 fprintf(stderr
, "[ %s ] collection number %d is out of range.\n",
2592 rn
, xstat_cm_Results
.collectionNumber
);
2596 /* If a new probe cycle started, mark the list in the current buffer
2597 * slot empty for resuse. Note that afsmon_cm_curr_CBindex was appropriately
2598 * incremented in afsmon_CM_Handler() */
2600 if (a_newProbeCycle
) {
2601 tmp_cmlist_item
= afsmon_cm_ResultsCB
[afsmon_cm_curr_CBindex
].list
;
2602 for (i
= 0; i
< numCM
; i
++) {
2603 tmp_cmlist_item
->empty
[index
] = 1;
2604 tmp_cmlist_item
= tmp_cmlist_item
->next
;
2608 /* locate last unused item in list */
2609 tmp_cmlist_item
= afsmon_cm_ResultsCB
[afsmon_cm_curr_CBindex
].list
;
2610 for (i
= 0; i
< numCM
; i
++) {
2611 if (tmp_cmlist_item
->empty
[index
])
2613 tmp_cmlist_item
= tmp_cmlist_item
->next
;
2616 /* if we could not find one we have an inconsistent list */
2617 if (!tmp_cmlist_item
->empty
[index
]) {
2619 "[ %s ] list inconsistency 1. unable to find an empty slot to store results of probenum %d of %s\n",
2620 rn
, xstat_cm_Results
.probeNum
,
2621 xstat_cm_Results
.connP
->hostName
);
2625 tmp_cmPR
= tmp_cmlist_item
->cmResults
[index
];
2627 /* copy hostname and probe number and probe time and probe status.
2628 * if the probe failed return now */
2630 memcpy(tmp_cmPR
->connP
->hostName
, xstat_cm_Results
.connP
->hostName
,
2631 sizeof(xstat_cm_Results
.connP
->hostName
));
2632 tmp_cmPR
->probeNum
= xstat_cm_Results
.probeNum
;
2633 tmp_cmPR
->probeTime
= xstat_cm_Results
.probeTime
;
2634 tmp_cmPR
->probeOK
= xstat_cm_Results
.probeOK
;
2635 if (xstat_cm_Results
.probeOK
) { /* probeOK = 1 => notOK */
2636 /* we have a nonempty results structure so mark the list item used */
2637 tmp_cmlist_item
->empty
[index
] = 0;
2642 /* copy connection information */
2643 memcpy(&(tmp_cmPR
->connP
->skt
), &(xstat_cm_Results
.connP
->skt
),
2644 sizeof(struct sockaddr_in
));
2646 /**** NEED TO COPY rx_connection INFORMATION HERE ******/
2648 memcpy(tmp_cmPR
->connP
->hostName
, xstat_cm_Results
.connP
->hostName
,
2649 sizeof(xstat_cm_Results
.connP
->hostName
));
2650 tmp_cmPR
->collectionNumber
= xstat_cm_Results
.collectionNumber
;
2652 /* copy the probe data information */
2653 tmp_cmPR
->data
.AFSCB_CollData_len
=
2654 min(xstat_cm_Results
.data
.AFSCB_CollData_len
,
2655 afsmon_cm_results_length
[index
]);
2656 memcpy(tmp_cmPR
->data
.AFSCB_CollData_val
,
2657 xstat_cm_Results
.data
.AFSCB_CollData_val
,
2658 tmp_cmPR
->data
.AFSCB_CollData_len
* sizeof(afs_int32
));
2661 /* we have a valid results structure so mark the list item used */
2662 tmp_cmlist_item
->empty
[index
] = 0;
2664 /* print the stored info - to make sure we copied it right */
2665 /* Print_cm_FullPerfInfo(tmp_cmPR); */
2666 /* Print the cm circular buffer */
2669 } /* save_CM_results_inCB */
2673 /*-----------------------------------------------------------------------
2677 * The results of xstat probes are stored in a string format in
2678 * the arrays curr_cmData and prev_cmData. The information stored in
2679 * prev_cmData is copied to the screen.
2680 * This function converts xstat FS results from longs to strings and
2681 * places them in the given buffer (a pointer to an item in curr_cmData).
2682 * When a probe cycle completes, curr_cmData is copied to prev_cmData
2683 * in afsmon_CM_Handler().
2687 *----------------------------------------------------------------------*/
2690 cm_Results_ltoa(struct cm_Display_Data
*a_cmData
, /* target buffer */
2691 struct xstat_cm_ProbeResults
*a_cmResults
) /* ptr to xstat cm Results */
2692 { /* cm_Results_ltoa */
2694 static char rn
[] = "cm_Results_ltoa"; /* routine name */
2695 struct afs_stats_CMFullPerf
*fullP
; /* ptr to complete CM stats */
2703 fprintf(debugFD
, "[ %s ] Called, a_cmData= %p, a_cmResults= %p\n", rn
,
2704 a_cmData
, a_cmResults
);
2709 fullP
= (struct afs_stats_CMFullPerf
*)
2710 (a_cmResults
->data
.AFSCB_CollData_val
);
2712 /* There are 4 parts to CM statistics
2713 * - Overall performance statistics (including up/down statistics)
2714 * - This CMs FS RPC operations info
2715 * - This CMs FS RPC errors info
2716 * - This CMs FS transfers info
2717 * - Authentication info
2718 * - [Un]Replicated access info
2721 /* copy overall performance statistics */
2722 srcbuf
= (afs_int32
*) & (fullP
->perf
);
2724 /* we skip the 19 entry, ProtServAddr, so the index must account for this */
2725 for (i
= 0; i
< NUM_AFS_STATS_CMPERF_LONGS
+ 1; i
++) {
2728 continue; /* skip ProtServerAddr */
2730 sprintf(a_cmData
->data
[idx
], "%d", *srcbuf
);
2735 /*printf("Ending index value = %d\n",idx-1); */
2737 /* server up/down statistics */
2738 /* copy file server up/down stats */
2739 srcbuf
= (afs_int32
*) (fullP
->perf
.fs_UpDown
);
2741 2 * (sizeof(struct afs_stats_SrvUpDownInfo
) / sizeof(afs_int32
));
2742 for (i
= 0; i
< numLongs
; i
++) {
2743 sprintf(a_cmData
->data
[idx
], "%d", *srcbuf
);
2748 /*printf("Ending index value = %d\n",idx-1); */
2750 /* copy volume location server up/down stats */
2751 srcbuf
= (afs_int32
*) (fullP
->perf
.vl_UpDown
);
2753 2 * (sizeof(struct afs_stats_SrvUpDownInfo
) / sizeof(afs_int32
));
2754 for (i
= 0; i
< numLongs
; i
++) {
2755 sprintf(a_cmData
->data
[idx
], "%d", *srcbuf
);
2760 /*printf("Ending index value = %d\n",idx-1); */
2762 /* copy CMs individual FS RPC operations info */
2763 srcbuf
= (afs_int32
*) (fullP
->rpc
.fsRPCTimes
);
2764 for (i
= 0; i
< AFS_STATS_NUM_FS_RPC_OPS
; i
++) {
2765 sprintf(a_cmData
->data
[idx
], "%d", *srcbuf
); /* numOps */
2768 sprintf(a_cmData
->data
[idx
], "%d", *srcbuf
); /* numSuccesses */
2771 tmpbuf
= srcbuf
++; /* sum time */
2772 sprintf(a_cmData
->data
[idx
], "%d.%06d", *tmpbuf
, *srcbuf
);
2775 tmpbuf
= srcbuf
++; /* sqr time */
2776 sprintf(a_cmData
->data
[idx
], "%d.%06d", *tmpbuf
, *srcbuf
);
2779 tmpbuf
= srcbuf
++; /* min time */
2780 sprintf(a_cmData
->data
[idx
], "%d.%06d", *tmpbuf
, *srcbuf
);
2783 tmpbuf
= srcbuf
++; /* max time */
2784 sprintf(a_cmData
->data
[idx
], "%d.%06d", *tmpbuf
, *srcbuf
);
2789 /*printf("Ending index value = %d\n",idx-1); */
2791 /* copy CMs individual FS RPC errors info */
2793 srcbuf
= (afs_int32
*) (fullP
->rpc
.fsRPCErrors
);
2794 for (i
= 0; i
< AFS_STATS_NUM_FS_RPC_OPS
; i
++) {
2795 sprintf(a_cmData
->data
[idx
], "%d", *srcbuf
); /* server */
2798 sprintf(a_cmData
->data
[idx
], "%d", *srcbuf
); /* network */
2801 sprintf(a_cmData
->data
[idx
], "%d", *srcbuf
); /* prot */
2804 sprintf(a_cmData
->data
[idx
], "%d", *srcbuf
); /* vol */
2807 sprintf(a_cmData
->data
[idx
], "%d", *srcbuf
); /* busies */
2810 sprintf(a_cmData
->data
[idx
], "%d", *srcbuf
); /* other */
2815 /*printf("Ending index value = %d\n",idx-1); */
2817 /* copy CMs individual RPC transfers info */
2819 srcbuf
= (afs_int32
*) (fullP
->rpc
.fsXferTimes
);
2820 for (i
= 0; i
< AFS_STATS_NUM_FS_XFER_OPS
; i
++) {
2821 sprintf(a_cmData
->data
[idx
], "%d", *srcbuf
); /* numOps */
2824 sprintf(a_cmData
->data
[idx
], "%d", *srcbuf
); /* numSuccesses */
2827 tmpbuf
= srcbuf
++; /* sum time */
2828 sprintf(a_cmData
->data
[idx
], "%d.%06d", *tmpbuf
, *srcbuf
);
2831 tmpbuf
= srcbuf
++; /* sqr time */
2832 sprintf(a_cmData
->data
[idx
], "%d.%06d", *tmpbuf
, *srcbuf
);
2835 tmpbuf
= srcbuf
++; /* min time */
2836 sprintf(a_cmData
->data
[idx
], "%d.%06d", *tmpbuf
, *srcbuf
);
2839 tmpbuf
= srcbuf
++; /* max time */
2840 sprintf(a_cmData
->data
[idx
], "%d.%06d", *tmpbuf
, *srcbuf
);
2843 sprintf(a_cmData
->data
[idx
], "%d", *srcbuf
); /* sum bytes */
2846 sprintf(a_cmData
->data
[idx
], "%d", *srcbuf
); /* min bytes */
2849 sprintf(a_cmData
->data
[idx
], "%d", *srcbuf
); /* max bytes */
2852 for (j
= 0; j
< AFS_STATS_NUM_XFER_BUCKETS
; j
++) {
2853 sprintf(a_cmData
->data
[idx
], "%d", *srcbuf
); /* bucket[j] */
2859 /*printf("Ending index value = %d\n",idx-1); */
2861 /* copy CM operations timings */
2863 srcbuf
= (afs_int32
*) (fullP
->rpc
.cmRPCTimes
);
2864 for (i
= 0; i
< AFS_STATS_NUM_CM_RPC_OPS
; i
++) {
2865 sprintf(a_cmData
->data
[idx
], "%d", *srcbuf
); /* numOps */
2868 sprintf(a_cmData
->data
[idx
], "%d", *srcbuf
); /* numSuccesses */
2871 tmpbuf
= srcbuf
++; /* sum time */
2872 sprintf(a_cmData
->data
[idx
], "%d.%06d", *tmpbuf
, *srcbuf
);
2875 tmpbuf
= srcbuf
++; /* sqr time */
2876 sprintf(a_cmData
->data
[idx
], "%d.%06d", *tmpbuf
, *srcbuf
);
2879 tmpbuf
= srcbuf
++; /* min time */
2880 sprintf(a_cmData
->data
[idx
], "%d.%06d", *tmpbuf
, *srcbuf
);
2883 tmpbuf
= srcbuf
++; /* max time */
2884 sprintf(a_cmData
->data
[idx
], "%d.%06d", *tmpbuf
, *srcbuf
);
2889 /*printf("Ending index value = %d\n",idx-1); */
2891 /* copy authentication info */
2893 srcbuf
= (afs_int32
*) & (fullP
->authent
);
2894 numLongs
= sizeof(struct afs_stats_AuthentInfo
) / sizeof(afs_int32
);
2895 for (i
= 0; i
< numLongs
; i
++) {
2896 sprintf(a_cmData
->data
[idx
], "%d", *srcbuf
);
2901 /*printf("Ending index value = %d\n",idx-1); */
2903 /* copy CM [un]replicated access info */
2905 srcbuf
= (afs_int32
*) & (fullP
->accessinf
);
2906 numLongs
= sizeof(struct afs_stats_AccessInfo
) / sizeof(afs_int32
);
2907 for (i
= 0; i
< numLongs
; i
++) {
2908 sprintf(a_cmData
->data
[idx
], "%d", *srcbuf
);
2913 /*printf("Ending index value = %d\n",idx-1); */
2916 } /* cm_Results_ltoa */
2919 /*-----------------------------------------------------------------------
2920 * Function: check_cm_thresholds()
2923 * Checks the thresholds and sets the overflow flag. Recall that the
2924 * thresholds for each host are stored in the hostEntry lists
2925 * [fs/cm]nameList arrays. The probe results are passed to this
2926 * function in the display-ready format - ie., as strings. Though
2927 * this looks stupid the overhead incurred in converting the strings
2928 * back to floats and comparing them is insignificant and
2929 * programming is easier this way.
2930 * The threshold flags are a part of the display structures
2935 *----------------------------------------------------------------------*/
2938 check_cm_thresholds(struct afsmon_hostEntry
*a_hostEntry
, /* ptr to hostEntry */
2939 struct cm_Display_Data
*a_Data
) /* ptr to cm data to be displayed */
2940 { /* check_cm_thresholds */
2942 static char rn
[] = "check_cm_thresholds";
2943 struct Threshold
*threshP
;
2944 double tValue
; /* threshold value */
2945 double pValue
; /* probe value */
2948 int count
; /* number of thresholds exceeded */
2951 fprintf(debugFD
, "[ %s ] Called, a_hostEntry= %p, a_Data= %p\n", rn
,
2952 a_hostEntry
, a_Data
);
2956 if (a_hostEntry
->numThresh
== 0) {
2957 /* store in ovf count ?? */
2962 threshP
= a_hostEntry
->thresh
;
2963 for (i
= 0; i
< a_hostEntry
->numThresh
; i
++) {
2964 if (threshP
->itemName
[0] == '\0') {
2968 idx
= threshP
->index
; /* positional index to the data array */
2969 tValue
= atof(threshP
->threshVal
); /* threshold value */
2970 pValue
= atof(a_Data
->data
[idx
]); /* probe value */
2971 if (pValue
> tValue
) {
2975 "[ %s ] cm = %s, thresh ovf for %s, threshold= %s, probevalue= %s\n",
2976 rn
, a_hostEntry
->hostName
, threshP
->itemName
,
2977 threshP
->threshVal
, a_Data
->data
[idx
]);
2981 /* if the threshold is crossed, call the handler function
2982 * only if this was a transition -ie, if the threshold was
2983 * crossed in the last probe too just count & keep quite! */
2985 if (!a_Data
->threshOvf
[idx
]) {
2986 a_Data
->threshOvf
[idx
] = 1;
2987 /* call the threshold handler if provided */
2988 if (threshP
->handler
[0] != '\0') {
2990 fprintf(debugFD
, "[ %s ] Calling ovf handler %s\n",
2991 rn
, threshP
->handler
);
2994 execute_thresh_handler(threshP
->handler
, a_Data
->hostName
,
2995 CM
, threshP
->itemName
,
3003 /* in case threshold was previously crossed, blank it out */
3004 a_Data
->threshOvf
[idx
] = 0;
3007 /* store the overflow count */
3008 a_Data
->ovfCount
= count
;
3011 } /* check_cm_thresholds */
3014 /*-----------------------------------------------------------------------
3015 * save_CM_data_forDisplay()
3018 * Does the following:
3019 * - if the probe number changed (ie, a cycle completed) curr_cmData
3020 * is copied to prev_cmData, curr_cmData zeroed and refresh the
3021 * overview screen and file server screen with the new data.
3022 * - store the results of the current probe from xstat_cm_Results into
3023 * curr_cmData. ie., convert longs to strings.
3024 * - check the thresholds
3028 * Failure: Exits afsmonitor.
3030 *----------------------------------------------------------------------*/
3033 save_CM_data_forDisplay(struct xstat_cm_ProbeResults
*a_cmResults
)
3034 { /* save_CM_data_forDisplay */
3036 static char rn
[] = "save_CM_data_forDisplay"; /* routine name */
3037 struct cm_Display_Data
*curr_cmDataP
;
3038 struct cm_Display_Data
*prev_cmDataP
;
3039 struct afsmon_hostEntry
*curr_host
;
3040 static int results_Received
= 0; /* number of probes reveived in
3041 * the current cycle. If this is equal to numFS we got all
3042 * the data we want in this cycle and can now display it */
3050 fprintf(debugFD
, "[ %s ] Called, a_cmResults= %p\n", rn
, a_cmResults
);
3054 /* store results in the display array */
3057 curr_cmDataP
= curr_cmData
;
3058 for (i
= 0; i
< numCM
; i
++) {
3059 if ((strcasecmp(curr_cmDataP
->hostName
, a_cmResults
->connP
->hostName
))
3069 "[ %s ] Could not insert CM probe results for host %s in cm display array\n",
3070 rn
, a_cmResults
->connP
->hostName
);
3074 /* Check the status of the probe. If it succeeded, we store its
3075 * results in the display data structure. If it failed we only mark
3076 * the failed status in the display data structure. */
3079 if (a_cmResults
->probeOK
) { /* 1 => notOK the xstat results */
3080 curr_cmDataP
->probeOK
= 0;
3082 /* print the probe status */
3084 fprintf(debugFD
, "\n\t\t ----- cm display data ------\n");
3085 fprintf(debugFD
, "HostName = %s PROBE FAILED \n",
3086 curr_cmDataP
->hostName
);
3090 } else { /* probe succeeded, update display data structures */
3091 curr_cmDataP
->probeOK
= 1;
3094 /* covert longs to strings and place them in curr_cmDataP */
3095 cm_Results_ltoa(curr_cmDataP
, a_cmResults
);
3097 /* compare with thresholds and set the overflow flags.
3098 * note that the threshold information is in the hostEntry structure and
3099 * each threshold item has a positional index associated with it */
3101 /* locate the hostEntry for this host */
3103 curr_host
= CMnameList
;
3104 for (i
= 0; i
< numCM
; i
++) {
3105 if (strcasecmp(curr_host
->hostName
, a_cmResults
->connP
->hostName
)
3110 curr_host
= curr_host
->next
;
3115 code
= check_cm_thresholds(curr_host
, curr_cmDataP
);
3117 fprintf(stderr
, "[ %s ] Error in checking thresholds\n", rn
);
3121 /* print the info we just saved */
3123 fprintf(debugFD
, "\n\t\t ----- CM display data ------\n");
3124 fprintf(debugFD
, "HostName = %s\n", curr_cmDataP
->hostName
);
3125 for (i
= 0; i
< NUM_CM_STAT_ENTRIES
; i
++) {
3128 fprintf(debugFD
, "\t -- Overall Perf Info --\n");
3132 "\t -- File Server up/down stats - same cell --\n");
3136 "\t -- File Server up/down stats - diff cell --\n");
3140 "\t -- VL server up/down stats - same cell --\n");
3144 "\t -- VL server up/down stats - diff cell --\n");
3147 fprintf(debugFD
, "\t -- FS Operation Timings --\n");
3150 fprintf(debugFD
, "\t -- FS Error Info --\n");
3153 fprintf(debugFD
, "\t -- FS Transfer Timings --\n");
3156 fprintf(debugFD
, "\t -- CM Operations Timings --\n");
3159 fprintf(debugFD
, "\t -- Authentication Info --\n");
3162 fprintf(debugFD
, "\t -- Access Info --\n");
3168 fprintf(debugFD
, "%20s %30s %s\n", curr_cmDataP
->data
[i
],
3170 curr_cmDataP
->threshOvf
[i
] ? "(ovf)" : "");
3172 fprintf(debugFD
, "\t\t--------------------------------\n\n");
3175 } /* if the probe succeeded, update the display data structures */
3177 /* if we have received a reply from all the hosts for this probe cycle,
3178 * it is time to display the data */
3181 if (results_Received
== numCM
* num_cm_collections
) {
3182 results_Received
= 0;
3184 if (afsmon_cm_curr_probeNum
!= afsmon_cm_prev_probeNum
+ 1) {
3185 sprintf(errMsg
, "[ %s ] Probe number %d missed! \n", rn
,
3186 afsmon_cm_prev_probeNum
+ 1);
3189 afsmon_cm_prev_probeNum
++;
3192 /* backup the display data of the probe cycle that just completed -
3193 * ie., store curr_cmData in prev_cmData */
3195 memcpy((char *)prev_cmData
, (char *)curr_cmData
,
3196 (numCM
* sizeof(struct cm_Display_Data
)));
3199 /* initialize curr_cmData but retain the threshold flag information.
3200 * The previous state of threshold flags is used in check_cm_thresholds() */
3202 curr_cmDataP
= curr_cmData
;
3203 numBytes
= NUM_CM_STAT_ENTRIES
* CM_STAT_STRING_LEN
;
3204 for (i
= 0; i
< numCM
; i
++) {
3205 curr_cmDataP
->probeOK
= 0;
3206 curr_cmDataP
->ovfCount
= 0;
3207 memset(curr_cmDataP
->data
, 0, numBytes
);
3211 /* prev_cmData now contains all the information for the probe cycle
3212 * that just completed. Now count the number of threshold overflows for
3213 * use in the overview screen */
3215 prev_cmDataP
= prev_cmData
;
3217 numHosts_oncm_alerts
= 0;
3218 for (i
= 0; i
< numCM
; i
++) {
3219 if (!prev_cmDataP
->probeOK
) { /* if probe failed */
3221 numHosts_oncm_alerts
++;
3222 } else if (prev_cmDataP
->ovfCount
) { /* overflows ?? */
3223 num_cm_alerts
+= prev_cmDataP
->ovfCount
;
3224 numHosts_oncm_alerts
++;
3229 fprintf(debugFD
, "Number of CM alerts = %d (on %d hosts)\n",
3230 num_cm_alerts
, numHosts_oncm_alerts
);
3233 /* flag that the data is now ready to be displayed */
3234 cm_Data_Available
= 1;
3236 /* update the Overview frame (only CM info) */
3237 ovw_refresh(ovw_currPage
, OVW_UPDATE_CM
);
3239 /* update the Cache Managers frame */
3240 cm_refresh(cm_currPage
, cm_curr_LCol
);
3246 } /* save_CM_data_forDisplay */
3250 /*-----------------------------------------------------------------------
3251 * afsmon_CM_Handler()
3254 * This is the Cache Manager probe Handler. It updates the afsmonitor
3255 * probe counts, cm circular buffer indices and calls the functions
3256 * to process the results of this probe.
3260 * Failure: Exits afsmonitor.
3261 *----------------------------------------------------------------------*/
3264 afsmon_CM_Handler(void)
3265 { /* afsmon_CM_Handler() */
3266 static char rn
[] = "afsmon_CM_Handler"; /* routine name */
3267 int code
; /* return status */
3268 int newProbeCycle
; /* start of new probe cycle ? */
3272 "[ %s ] Called, hostName= %s, probeNum= %d, status= %s\n", rn
,
3273 xstat_cm_Results
.connP
->hostName
, xstat_cm_Results
.probeNum
,
3274 xstat_cm_Results
.probeOK
? "FAILED" : "OK");
3279 /* print the probe results to output file */
3280 if (afsmon_output
) {
3281 code
= afsmon_cmOutput(output_filename
, afsmon_detOutput
);
3284 "[ %s ] output to file %s returned error code=%d\n", rn
,
3285 output_filename
, code
);
3289 /* Update current probe number and circular buffer index. if current
3290 * probenum changed make sure it is only by 1 */
3293 if (xstat_cm_Results
.probeNum
!= afsmon_cm_curr_probeNum
) {
3294 if (xstat_cm_Results
.probeNum
== afsmon_cm_curr_probeNum
+ 1) {
3295 afsmon_cm_curr_probeNum
++;
3298 afsmon_cm_curr_CBindex
=
3299 (afsmon_cm_curr_probeNum
- 1) % num_bufSlots
;
3301 fprintf(stderr
, "[ %s ] probe number %d-1 missed\n", rn
,
3302 xstat_cm_Results
.probeNum
);
3307 /* save the results of this probe in the CM buffer */
3309 save_CM_results_inCB(newProbeCycle
);
3311 /* store the results of the current probe in the cm data display structure.
3312 * if the current probe number changed, swap the current and previous display
3313 * structures. note that the display screen is updated from these structures
3314 * and should start showing the data of the just completed probe cycle */
3316 save_CM_data_forDisplay(&xstat_cm_Results
);
3321 /*-----------------------------------------------------------------------
3325 * Allocate and Initialize circular buffers for file servers.
3329 * Failure to allocate memory: exits afsmonitor.
3330 *----------------------------------------------------------------------*/
3333 init_fs_buffers(void)
3334 { /* init_fs_buffers() */
3335 static char rn
[] = "init_fs_buffers"; /* routine name */
3336 struct afsmon_fs_Results_list
*new_fslist_item
; /* ptr for new struct */
3337 struct afsmon_fs_Results_list
*tmp_fslist_item
; /* temp ptr */
3338 struct xstat_fs_ProbeResults
*new_fsPR
; /* ptr for new struct */
3345 fprintf(debugFD
, "[ %s ] Called\n", rn
);
3349 /* allocate memory for the circular buffer of pointers */
3351 afsmon_fs_ResultsCB
= (struct afsmon_fs_Results_CBuffer
*)
3352 malloc(sizeof(struct afsmon_fs_Results_CBuffer
) * num_bufSlots
);
3354 /* initialize the fs circular buffer */
3355 for (i
= 0; i
< num_bufSlots
; i
++) {
3356 afsmon_fs_ResultsCB
[i
].list
= (struct afsmon_fs_Results_list
*)0;
3357 afsmon_fs_ResultsCB
[i
].probeNum
= 0;
3360 /* create a list of numFS items to store fs probe results for
3361 * each slot in CB */
3363 if (numFS
) { /* if we have file servers to monitor */
3364 for (bufslot
= 0; bufslot
< num_bufSlots
; bufslot
++) {
3365 numfs
= numFS
; /* get the number of servers */
3368 /* if any of these mallocs fail we only need to free the memory we
3369 * have allocated in this iteration. the rest of it which is in a
3370 * proper linked list will be freed in afsmon_Exit */
3372 /* allocate memory for an fs list item */
3373 new_fslist_item
= (struct afsmon_fs_Results_list
*)
3374 malloc(sizeof(struct afsmon_fs_Results_list
));
3375 if (new_fslist_item
== (struct afsmon_fs_Results_list
*)0)
3378 for (i
= 0; i
< MAX_NUM_FS_COLLECTIONS
; i
++) {
3379 /* allocate memory to store xstat_fs_Results */
3380 new_fsPR
= (struct xstat_fs_ProbeResults
*)
3381 malloc(sizeof(struct xstat_fs_ProbeResults
));
3383 free(new_fslist_item
);
3387 new_fsPR
->connP
= (struct xstat_fs_ConnectionInfo
*)
3388 malloc(sizeof(struct xstat_fs_ConnectionInfo
));
3389 if (new_fsPR
->connP
== (struct xstat_fs_ConnectionInfo
*)0) {
3390 free(new_fslist_item
);
3395 /* >>> need to allocate rx connection info structure here <<< */
3396 new_fsPR
->data
.AFS_CollData_val
= (afs_int32
*)
3397 malloc(afsmon_fs_results_length
[i
] * sizeof(afs_int32
));
3398 if (new_fsPR
->data
.AFS_CollData_val
== NULL
) {
3399 free(new_fslist_item
);
3400 free(new_fsPR
->connP
);
3404 new_fslist_item
->fsResults
[i
] = new_fsPR
;
3405 new_fslist_item
->empty
[i
] = 1;
3408 /* initialize this list entry */
3409 new_fslist_item
->next
= (struct afsmon_fs_Results_list
*)0;
3411 /* store it at the end of the fs list in the current CB slot */
3412 if (afsmon_fs_ResultsCB
[bufslot
].list
==
3413 (struct afsmon_fs_Results_list
*)0)
3414 afsmon_fs_ResultsCB
[bufslot
].list
= new_fslist_item
;
3416 tmp_fslist_item
= afsmon_fs_ResultsCB
[bufslot
].list
;
3418 while (tmp_fslist_item
!=
3419 (struct afsmon_fs_Results_list
*)0) {
3420 if (tmp_fslist_item
->next
==
3421 (struct afsmon_fs_Results_list
*)0)
3423 tmp_fslist_item
= tmp_fslist_item
->next
;
3425 /* something goofed. exit */
3426 fprintf(stderr
, "[ %s ] list creation error\n",
3431 tmp_fslist_item
->next
= new_fslist_item
;
3434 } /* while servers */
3435 } /* for each buffer slot */
3436 } /* if we have file servers to monitor */
3440 /*-----------------------------------------------------------------------
3444 * Allocate and Initialize circular buffers for cache managers.
3448 * Failure to allocate memory: exits afsmonitor.
3449 *----------------------------------------------------------------------*/
3452 init_cm_buffers(void)
3453 { /* init_cm_buffers() */
3454 static char rn
[] = "init_cm_buffers"; /* routine name */
3455 struct afsmon_cm_Results_list
*new_cmlist_item
; /* ptr for new struct */
3456 struct afsmon_cm_Results_list
*tmp_cmlist_item
; /* temp ptr */
3457 struct xstat_cm_ProbeResults
*new_cmPR
; /* ptr for new struct */
3463 fprintf(debugFD
, "[ %s ] Called\n", rn
);
3467 /* allocate memory for the circular buffer of pointers */
3468 afsmon_cm_ResultsCB
= (struct afsmon_cm_Results_CBuffer
*)
3469 malloc(sizeof(struct afsmon_cm_Results_CBuffer
) * num_bufSlots
);
3471 /* initialize the fs circular buffer */
3472 for (i
= 0; i
< num_bufSlots
; i
++) {
3473 afsmon_cm_ResultsCB
[i
].list
= (struct afsmon_cm_Results_list
*)0;
3474 afsmon_cm_ResultsCB
[i
].probeNum
= 0;
3477 /* create a list of numCM items to store fs probe results for
3478 * each slot in CB */
3480 if (numCM
) { /* if we have file servers to monitor */
3481 for (bufslot
= 0; bufslot
< num_bufSlots
; bufslot
++) {
3482 numcm
= numCM
; /* get the number of servers */
3485 /* if any of these mallocs fail we only need to free the memory we
3486 * have allocated in this iteration. the rest of it which is in a
3487 * proper linked list will be freed in afsmon_Exit */
3489 /* allocate memory for an fs list item */
3490 new_cmlist_item
= (struct afsmon_cm_Results_list
*)
3491 malloc(sizeof(struct afsmon_cm_Results_list
));
3492 if (new_cmlist_item
== (struct afsmon_cm_Results_list
*)0)
3495 for (i
= 0; i
< MAX_NUM_CM_COLLECTIONS
; i
++) {
3496 /* allocate memory to store xstat_cm_Results */
3497 new_cmPR
= (struct xstat_cm_ProbeResults
*)
3498 malloc(sizeof(struct xstat_cm_ProbeResults
));
3500 free(new_cmlist_item
);
3503 new_cmPR
->connP
= (struct xstat_cm_ConnectionInfo
*)
3504 malloc(sizeof(struct xstat_cm_ConnectionInfo
));
3505 if (!new_cmPR
->connP
) {
3506 free(new_cmlist_item
);
3511 /* >>> need to allocate rx connection info structure here <<< */
3513 new_cmPR
->data
.AFSCB_CollData_val
=
3514 malloc(XSTAT_CM_FULLPERF_RESULTS_LEN
3515 *sizeof(afs_int32
));
3516 if (new_cmPR
->data
.AFSCB_CollData_val
== NULL
) {
3517 free(new_cmlist_item
);
3518 free(new_cmPR
->connP
);
3523 new_cmlist_item
->cmResults
[i
] = new_cmPR
;
3524 new_cmlist_item
->empty
[i
] = 1;
3527 /* initialize this list entry */
3528 new_cmlist_item
->next
= (struct afsmon_cm_Results_list
*)0;
3530 /* store it at the end of the cm list in the current CB slot */
3531 if (afsmon_cm_ResultsCB
[bufslot
].list
==
3532 (struct afsmon_cm_Results_list
*)0)
3533 afsmon_cm_ResultsCB
[bufslot
].list
= new_cmlist_item
;
3535 tmp_cmlist_item
= afsmon_cm_ResultsCB
[bufslot
].list
;
3537 while (tmp_cmlist_item
!=
3538 (struct afsmon_cm_Results_list
*)0) {
3539 if (tmp_cmlist_item
->next
==
3540 (struct afsmon_cm_Results_list
*)0)
3542 tmp_cmlist_item
= tmp_cmlist_item
->next
;
3544 /* something goofed. exit */
3545 fprintf(stderr
, "[ %s ] list creation error\n",
3550 tmp_cmlist_item
->next
= new_cmlist_item
;
3553 } /* while servers */
3554 } /* for each buffer slot */
3556 /* if we have file servers to monitor */
3557 /* print the CB to make sure it is right */
3561 } /* init_cm_buffers() */
3564 /*-------------------------------------------------------------------------
3565 * init_print_buffers()
3568 * Allocate and initialize the buffers used for printing results
3569 * to the display screen. These buffers store the current and
3570 * previous probe results in ascii format.
3575 *------------------------------------------------------------------------*/
3578 init_print_buffers(void)
3579 { /* init_print_buffers */
3581 static char rn
[] = "init_print_buffers"; /* routine name */
3582 struct fs_Display_Data
*tmp_fsData1
; /* temp pointers */
3583 struct fs_Display_Data
*tmp_fsData2
;
3584 struct cm_Display_Data
*tmp_cmData1
;
3585 struct cm_Display_Data
*tmp_cmData2
;
3586 struct afsmon_hostEntry
*tmp_fsNames
;
3587 struct afsmon_hostEntry
*tmp_cmNames
;
3592 fprintf(debugFD
, "[ %s ] Called\n", rn
);
3596 /* allocate numFS blocks of the FS print structure. */
3598 /* we need two instances of this structure - one (curr_fsData) for storing
3599 * the results of the fs probes currently in progress and another (prev_fsData)
3600 * for the last completed probe. The display is updated from the contents of
3601 * prev_fsData. The pointers curr_fsData & prev_fsData are switched whenever
3602 * the probe number changes */
3605 numBytes
= numFS
* sizeof(struct fs_Display_Data
);
3606 curr_fsData
= malloc(numBytes
);
3607 if (curr_fsData
== (struct fs_Display_Data
*)0) {
3608 fprintf(stderr
, "[ %s ] Memory allocation failure\n", rn
);
3611 memset(curr_fsData
, 0, numBytes
);
3613 numBytes
= numFS
* sizeof(struct fs_Display_Data
);
3614 prev_fsData
= malloc(numBytes
);
3615 if (prev_fsData
== (struct fs_Display_Data
*)0) {
3616 fprintf(stderr
, "[ %s ] Memory allocation failure\n", rn
);
3619 memset(prev_fsData
, 0, numBytes
);
3621 /* fill in the host names */
3622 tmp_fsData1
= curr_fsData
;
3623 tmp_fsData2
= curr_fsData
;
3624 tmp_fsNames
= FSnameList
;
3625 for (i
= 0; i
< numFS
; i
++) {
3626 strncpy(tmp_fsData1
->hostName
, tmp_fsNames
->hostName
,
3628 strncpy(tmp_fsData2
->hostName
, tmp_fsNames
->hostName
,
3632 tmp_fsNames
= tmp_fsNames
->next
;;
3637 /* if file servers to monitor */
3638 /* allocate numCM blocks of the CM print structure */
3639 /* we need two instances of this structure for the same reasons as above */
3641 numBytes
= numCM
* sizeof(struct cm_Display_Data
);
3643 curr_cmData
= malloc(numBytes
);
3644 if (curr_cmData
== (struct cm_Display_Data
*)0) {
3645 fprintf(stderr
, "[ %s ] Memory allocation failure\n", rn
);
3648 memset(curr_cmData
, 0, numBytes
);
3650 numBytes
= numCM
* sizeof(struct cm_Display_Data
);
3651 prev_cmData
= malloc(numBytes
);
3652 if (prev_cmData
== (struct cm_Display_Data
*)0) {
3653 fprintf(stderr
, "[ %s ] Memory allocation failure\n", rn
);
3656 memset(prev_cmData
, 0, numBytes
);
3658 /* fill in the host names */
3659 tmp_cmData1
= curr_cmData
;
3660 tmp_cmData2
= curr_cmData
;
3661 tmp_cmNames
= CMnameList
;
3662 for (i
= 0; i
< numCM
; i
++) {
3663 strncpy(tmp_cmData1
->hostName
, tmp_cmNames
->hostName
,
3665 strncpy(tmp_cmData2
->hostName
, tmp_cmNames
->hostName
,
3669 tmp_cmNames
= tmp_cmNames
->next
;;
3673 /* if cache managers to monitor */
3676 } /* init_print_buffers */
3678 /*-----------------------------------------------------------------------
3682 * Trap the interrupt signal. This function is useful only until
3683 * gtx is initialized.
3684 *----------------------------------------------------------------------*/
3687 quit_signal(int sig
)
3689 fprintf(stderr
, "Received signal %d \n", sig
);
3695 /*-----------------------------------------------------------------------
3699 * This is where we start it all. Initialize an array of sockets for
3700 * file servers and cache cache managers and call the xstat_[fs/cm]_Init
3701 * routines. The last step is to call the gtx input server which
3702 * grabs control of the keyboard.
3705 * Does not return. Control is periodically returned to the afsmonitor
3706 * thru afsmon_[FS/CM]_Handler() routines and also through the gtx
3707 * keyboard handler calls.
3709 *----------------------------------------------------------------------*/
3712 afsmon_execute(void)
3713 { /* afsmon_execute() */
3714 static char rn
[] = "afsmon_execute"; /* routine name */
3715 static char fullhostname
[128]; /* full host name */
3716 struct sockaddr_in
*FSSktArray
; /* fs socket array */
3717 int FSsktbytes
; /* num bytes in above */
3718 struct sockaddr_in
*CMSktArray
; /* cm socket array */
3719 int CMsktbytes
; /* num bytes in above */
3720 struct sockaddr_in
*curr_skt
; /* ptr to current socket */
3721 struct afsmon_hostEntry
*curr_FS
; /* ptr to FS name list */
3722 struct afsmon_hostEntry
*curr_CM
; /* ptr to CM name list */
3723 struct hostent
*he
; /* host entry */
3724 int FSinitFlags
= 0; /* flags for xstat_fs_Init */
3725 int CMinitFlags
= 0; /* flags for xstat_cm_Init */
3726 int code
; /* function return code */
3727 struct timeval tv
; /* time structure */
3732 fprintf(debugFD
, "[ %s ] Called\n", rn
);
3737 /* process file server entries */
3739 afs_int32 collIDs
[MAX_NUM_FS_COLLECTIONS
];
3741 /* Allocate an array of sockets for each fileserver we monitor */
3743 FSsktbytes
= numFS
* sizeof(struct sockaddr_in
);
3744 FSSktArray
= malloc(FSsktbytes
);
3745 if (FSSktArray
== (struct sockaddr_in
*)0) {
3747 "[ %s ] cannot malloc %d sockaddr_ins for fileservers\n",
3752 memset(FSSktArray
, 0, FSsktbytes
);
3754 /* Fill in the socket information for each fileserve */
3756 curr_skt
= FSSktArray
;
3757 curr_FS
= FSnameList
; /* FS name list header */
3759 strncpy(fullhostname
, curr_FS
->hostName
, sizeof(fullhostname
));
3760 he
= GetHostByName(fullhostname
);
3762 fprintf(stderr
, "[ %s ] Cannot get host info for %s\n", rn
,
3766 strncpy(curr_FS
->hostName
, he
->h_name
, HOST_NAME_LEN
); /* complete name */
3767 memcpy(&(curr_skt
->sin_addr
.s_addr
), he
->h_addr
, 4);
3768 curr_skt
->sin_family
= AF_INET
; /*Internet family */
3769 curr_skt
->sin_port
= htons(7000); /*FileServer port */
3770 #ifdef STRUCT_SOCKADDR_HAS_SA_LEN
3771 curr_skt
->sin_len
= sizeof(struct sockaddr_in
);
3774 /* get the next dude */
3776 curr_FS
= curr_FS
->next
;
3779 /* Initialize collection IDs, depending on the data requested. */
3780 num_fs_collections
= 0;
3781 for (i
= 0; i
< fs_DisplayItems_count
; i
++) {
3782 index
= fs_Display_map
[i
];
3783 if (FS_FULLPERF_ENTRY_START
<= index
&& index
<= FS_FULLPERF_ENTRY_END
) {
3784 collIDs
[num_fs_collections
++] = AFS_XSTATSCOLL_FULL_PERF_INFO
;
3788 for (i
= 0; i
< fs_DisplayItems_count
; i
++) {
3789 index
= fs_Display_map
[i
];
3790 if (FS_CB_ENTRY_START
<= index
&& index
<= FS_CB_ENTRY_END
) {
3791 collIDs
[num_fs_collections
++] = AFS_XSTATSCOLL_CBSTATS
;
3797 if (afsmon_onceOnly
) /* option not provided at this time */
3798 FSinitFlags
|= XSTAT_FS_INITFLAG_ONE_SHOT
;
3801 fprintf(debugFD
, "[ %s ] Calling xstat_fs_Init \n", rn
);
3805 code
= xstat_fs_Init(numFS
, /*Num servers */
3806 FSSktArray
, /*File Server socket array */
3807 afsmon_probefreq
, /*probe frequency */
3808 afsmon_FS_Handler
, /*Handler routine */
3809 FSinitFlags
, /*Initialization flags */
3810 num_fs_collections
, /*Number of collection IDs */
3811 collIDs
); /*Ptr to collection ID */
3814 fprintf(stderr
, "[ %s ] xstat_fs_init returned error\n", rn
);
3821 /* end of process fileserver entries */
3822 /* process cache manager entries */
3824 afs_int32 collIDs
[MAX_NUM_CM_COLLECTIONS
];
3826 /* Allocate an array of sockets for each cache manager we monitor */
3828 CMsktbytes
= numCM
* sizeof(struct sockaddr_in
);
3829 CMSktArray
= malloc(CMsktbytes
);
3830 if (CMSktArray
== (struct sockaddr_in
*)0) {
3832 "[ %s ] cannot malloc %d sockaddr_ins for CM entries\n",
3837 memset(CMSktArray
, 0, CMsktbytes
);
3839 /* Fill in the socket information for each CM */
3841 curr_skt
= CMSktArray
;
3842 curr_CM
= CMnameList
; /* CM name list header */
3844 strncpy(fullhostname
, curr_CM
->hostName
, sizeof(fullhostname
));
3845 he
= GetHostByName(fullhostname
);
3847 fprintf(stderr
, "[ %s ] Cannot get host info for %s\n", rn
,
3851 strncpy(curr_CM
->hostName
, he
->h_name
, HOST_NAME_LEN
); /* complete name */
3852 memcpy(&(curr_skt
->sin_addr
.s_addr
), he
->h_addr
, 4);
3853 curr_skt
->sin_family
= AF_INET
;
3854 curr_skt
->sin_port
= htons(7001); /* Cache Manager port */
3855 #ifdef STRUCT_SOCKADDR_HAS_SA_LEN
3856 curr_skt
->sin_len
= sizeof(struct sockaddr_in
);
3859 /* get the next dude */
3861 curr_CM
= curr_CM
->next
;
3864 /* initialize collection IDs. We need only one entry since we collect
3865 * all the information from xstat */
3866 num_cm_collections
= 0;
3867 collIDs
[num_cm_collections
++] = AFSCB_XSTATSCOLL_FULL_PERF_INFO
;
3870 if (afsmon_onceOnly
) /* once only ? */
3871 CMinitFlags
|= XSTAT_CM_INITFLAG_ONE_SHOT
;
3874 fprintf(debugFD
, "[ %s ] Calling xstat_cm_Init \n", rn
);
3878 code
= xstat_cm_Init(numCM
, /*Num servers */
3879 CMSktArray
, /*Cache Manager socket array */
3880 afsmon_probefreq
, /*probe frequency */
3881 afsmon_CM_Handler
, /*Handler routine */
3882 CMinitFlags
, /*Initialization flags */
3883 num_cm_collections
, /*Number of collection IDs */
3884 collIDs
); /*Ptr to collection ID */
3887 fprintf(stderr
, "[ %s ] xstat_cm_init returned error\n", rn
);
3894 /* end of process cache manager entries */
3895 /* if only one probe was required setup a waiting process for the
3896 * termination signal */
3897 if (afsmon_onceOnly
) {
3898 code
= LWP_WaitProcess(&terminationEvent
);
3901 fprintf(debugFD
, "LWP_WaitProcess() returned error %d\n",
3909 /* start the gtx input server */
3910 code
= (intptr_t)gtx_InputServer(afsmon_win
);
3912 fprintf(stderr
, "[ %s ] Failed to start input server \n", rn
);
3916 /* This part of the code is reached only if the input server is not started
3917 * for debugging purposes */
3920 tv
.tv_sec
= 24 * 60;
3922 fprintf(stderr
, "[ %s ] going to sleep ...\n", rn
);
3924 code
= IOMGR_Select(0, /*Num fds */
3925 0, /*Descriptors ready for reading */
3926 0, /*Descriptors ready for writing */
3927 0, /*Descriptors with exceptional conditions */
3928 &tv
); /*Timeout structure */
3931 "[ %s ] IOMGR_Select() returned non-zero value %d\n", rn
,
3939 /*-----------------------------------------------------------------------
3943 * Afsmonitor initialization routine.
3944 * - processes command line parameters
3945 * - call functions to:
3946 * - process config file
3947 * - initialize circular buffers and display buffers
3949 * - execute afsmonitor
3950 * - initialize the display maps [fs/cm]_Display_map[].
3953 * Success: Does not return from the call to afsmon_execute().
3954 * Failure: Exits afsmonitor.
3955 *----------------------------------------------------------------------*/
3958 afsmonInit(struct cmd_syndesc
*as
, void *arock
)
3959 { /* afsmonInit() */
3961 static char rn
[] = "afsmonInit"; /* Routine name */
3962 char *debug_filename
; /* pointer to debug filename */
3963 FILE *outputFD
; /* output file descriptor */
3964 struct cmd_item
*hostPtr
; /* ptr to parse command line args */
3965 char buf
[256]; /* buffer for processing hostnames */
3970 fprintf(debugFD
, "[ %s ] Called, as= %p\n", rn
, as
);
3974 /* Open the debug file if -debug option is specified */
3975 if (as
->parms
[P_DEBUG
].items
!= 0) {
3977 debug_filename
= as
->parms
[P_DEBUG
].items
->data
;
3978 debugFD
= fopen(debug_filename
, "w");
3979 if (debugFD
== (FILE *) 0) {
3980 printf("[ %s ] Failed to open debugging file %s for writing\n",
3988 fprintf(debugFD
, "[ %s ] Called\n", rn
);
3992 /* use curses always until we support other packages */
3994 wpkg_to_use
= atoi(as
->parms
[P_PACKAGE
].items
->data
);
3996 switch (wpkg_to_use
) {
3997 case GATOR_WIN_CURSES
:
3998 fprintf(stderr
, "curses\n");
4000 case GATOR_WIN_DUMB
:
4001 fprintf(stderr
, "dumb terminal\n");
4004 fprintf(stderr
, "X11\n");
4007 fprintf(stderr
, "Illegal graphics package: %d\n", wpkg_to_use
);
4009 } /*end switch (wpkg_to_use) */
4012 wpkg_to_use
= GATOR_WIN_CURSES
;
4014 /* get probe frequency . We check for meaningful bounds on the frequency
4015 * and reset to the default value if needed. The upper bound of 24
4016 * hours looks ridiculous though! */
4018 afsmon_probefreq
= 0;
4019 if (as
->parms
[P_FREQUENCY
].items
!= 0)
4020 afsmon_probefreq
= atoi(as
->parms
[P_FREQUENCY
].items
->data
);
4022 afsmon_probefreq
= DEFAULT_FREQUENCY
;
4024 if (afsmon_probefreq
<= 0 || afsmon_probefreq
> 24 * 60 * 60) {
4025 afsmon_probefreq
= DEFAULT_FREQUENCY
;
4028 "[ %s ] Invalid probe frequency %s specified, resetting to default value %d seconds\n",
4029 rn
, as
->parms
[P_FREQUENCY
].items
->data
, afsmon_probefreq
);
4033 "Invalid probe frequency %s specified, resetting to default value %d seconds\n",
4034 as
->parms
[P_FREQUENCY
].items
->data
, afsmon_probefreq
);
4039 /* make sure output file is writable, else complain now */
4040 /* we will open and close it as needed after probes */
4042 if (as
->parms
[P_OUTPUT
].items
!= 0) {
4043 afsmon_output
= 1; /* output flag */
4044 strncpy(output_filename
, as
->parms
[P_OUTPUT
].items
->data
, 80);
4045 outputFD
= fopen(output_filename
, "a");
4046 if (outputFD
== (FILE *) 0) {
4047 fprintf(stderr
, "Failed to open output file %s \n",
4050 fprintf(debugFD
, "[ %s ] Failed to open output file %s \n",
4051 rn
, output_filename
);
4056 fprintf(debugFD
, "[ %s ] output file is %s\n", rn
,
4062 /* detailed statistics to storage file */
4063 if (as
->parms
[P_DETAILED
].items
!= 0) {
4064 if (as
->parms
[P_OUTPUT
].items
== 0) {
4066 "-detailed switch can be used only with -output\n");
4069 afsmon_detOutput
= 1;
4072 /* Initialize host list headers */
4073 FSnameList
= (struct afsmon_hostEntry
*)0;
4074 CMnameList
= (struct afsmon_hostEntry
*)0;
4076 /* The -config option is mutually exclusive with the -fshosts,-cmhosts
4079 if (as
->parms
[P_CONFIG
].items
) {
4080 if (as
->parms
[P_FSHOSTS
].items
|| as
->parms
[P_CMHOSTS
].items
) {
4082 "Cannot use -config option with -fshosts or -cmhosts\n");
4086 if (!as
->parms
[P_FSHOSTS
].items
&& !as
->parms
[P_CMHOSTS
].items
) {
4088 "Must specify either -config or (-fshosts and/or -cmhosts) options \n");
4094 /* If a file server host is specified on the command line we reuse
4095 * parse_hostEntry() function . Just the pass the info as if it were
4096 * read off the config file */
4098 if (as
->parms
[P_FSHOSTS
].items
) {
4099 hostPtr
= as
->parms
[P_FSHOSTS
].items
;
4100 while (hostPtr
!= (struct cmd_item
*)0) {
4101 sprintf(buf
, "fs %s", hostPtr
->data
);
4102 code
= parse_hostEntry(buf
);
4104 fprintf(stderr
, "Could not parse %s\n", hostPtr
->data
);
4108 hostPtr
= hostPtr
->next
;
4112 /* same as above for -cmhosts */
4113 if (as
->parms
[P_CMHOSTS
].items
) {
4114 hostPtr
= as
->parms
[P_CMHOSTS
].items
;
4115 while (hostPtr
!= (struct cmd_item
*)0) {
4116 sprintf(buf
, "cm %s", hostPtr
->data
);
4117 code
= parse_hostEntry(buf
);
4119 fprintf(stderr
, "Could not parse %s\n", hostPtr
->data
);
4123 hostPtr
= hostPtr
->next
;
4127 /* number of slots in circular buffers */
4128 if (as
->parms
[P_BUFFERS
].items
)
4129 num_bufSlots
= atoi(as
->parms
[P_BUFFERS
].items
->data
);
4131 num_bufSlots
= DEFAULT_BUFSLOTS
;
4133 /* Initialize xx_showFlags[]. This array is used solely for processing the
4134 * "show" directives in the config file in parse_showEntries() */
4135 for (i
= 0; i
< NUM_FS_STAT_ENTRIES
; i
++)
4136 fs_showFlags
[i
] = 0;
4137 for (i
= 0; i
< NUM_CM_STAT_ENTRIES
; i
++)
4138 cm_showFlags
[i
] = 0;
4141 /* Process the configuration file if given. This initializes among other
4142 * things, the list of FS & CM names in FSnameList and CMnameList */
4144 if (as
->parms
[P_CONFIG
].items
)
4145 process_config_file(as
->parms
[P_CONFIG
].items
->data
);
4147 /* print out the FS and CM lists */
4151 /* Initialize the FS results-to-screen map array if there were no "show fs"
4152 * directives in the config file */
4153 if (fs_showDefault
) {
4154 for (i
= 0; i
< NUM_FS_STAT_ENTRIES
; i
++)
4155 fs_Display_map
[i
] = i
;
4156 fs_DisplayItems_count
= NUM_FS_STAT_ENTRIES
;
4159 /* Initialize the CM results-to-screen map array if there were no "show cm"
4160 * directives in the config file */
4161 if (cm_showDefault
) {
4162 for (i
= 0; i
< NUM_CM_STAT_ENTRIES
; i
++)
4163 cm_Display_map
[i
] = i
;
4164 cm_DisplayItems_count
= NUM_CM_STAT_ENTRIES
;
4169 /* setup an interrupt signal handler; we ain't wanna leak core */
4170 /* this binding is useful only until gtx is initialized after which the
4171 * keyboard input server takes over. */
4172 if ((signal(SIGINT
, quit_signal
)) == SIG_ERR
) {
4173 perror("signal() failed.");
4178 /* init error message buffers. these will be used to print error messages
4179 * once gtx is initialized and there is no access to stderr/stdout */
4185 /* initialize fs and cm circular buffers before initiating probes */
4187 code
= init_fs_buffers();
4189 fprintf(stderr
, "[ %s ] init_fs_buffers returned %d\n", rn
,
4196 code
= init_cm_buffers();
4198 fprintf(stderr
, "[ %s ] init_cm_buffers returned %d\n", rn
,
4205 /* allocate and initialize buffers for holding fs & cm results in ascii
4206 * format suitable for updating the screen */
4207 code
= init_print_buffers();
4209 fprintf(stderr
, "[ %s ] init_print_buffers returned %d\n", rn
, code
);
4213 /* perform gtx initializations */
4214 code
= gtx_initialize();
4216 fprintf(stderr
, "[ %s ] gtx_initialize returned %d\n", rn
, code
);
4220 /* start xstat probes */
4223 return (0); /* will not return from the call to afsmon_execute() */
4225 } /* afsmonInit() */
4228 /*-----------------------------------------------------------------------
4230 ------------------------------------------------------------------------*/
4232 #include "AFS_component_version_number.c"
4235 main(int argc
, char **argv
)
4237 afs_int32 code
; /*Return code */
4238 struct cmd_syndesc
*ts
; /*Ptr to cmd line syntax descriptor */
4240 #ifdef AFS_AIX32_ENV
4242 * The following signal action for AIX is necessary so that in case of a
4243 * crash (i.e. core is generated) we can include the user's data section
4244 * in the core dump. Unfortunately, by default, only a partial core is
4245 * generated which, in many cases, isn't too useful.
4247 struct sigaction nsa
;
4249 sigemptyset(&nsa
.sa_mask
);
4250 nsa
.sa_handler
= SIG_DFL
;
4251 nsa
.sa_flags
= SA_FULLDUMP
;
4252 sigaction(SIGSEGV
, &nsa
, NULL
);
4256 * Set up the commands we understand.
4258 ts
= cmd_CreateSyntax("initcmd", afsmonInit
, NULL
, 0, "initialize the program");
4259 cmd_AddParm(ts
, "-config", CMD_SINGLE
, CMD_OPTIONAL
,
4260 "configuration file");
4261 cmd_AddParm(ts
, "-frequency", CMD_SINGLE
, CMD_OPTIONAL
,
4262 "poll frequency, in seconds");
4263 cmd_AddParm(ts
, "-output", CMD_SINGLE
, CMD_OPTIONAL
, "storage file name");
4264 cmd_AddParm(ts
, "-detailed", CMD_FLAG
, CMD_OPTIONAL
,
4265 "output detailed statistics to storage file");
4267 /* we hope to use this .... eventually! */
4268 cmd_AddParm(ts
, "-package", CMD_SINGLE
, CMD_REQUIRED
,
4269 "Graphics Package to use");
4271 cmd_AddParm(ts
, "-debug", CMD_SINGLE
, CMD_OPTIONAL
,
4272 "turn debugging output on to the named file");
4273 cmd_AddParm(ts
, "-fshosts", CMD_LIST
, CMD_OPTIONAL
,
4274 "list of file servers to monitor");
4275 cmd_AddParm(ts
, "-cmhosts", CMD_LIST
, CMD_OPTIONAL
,
4276 "list of cache managers to monitor");
4277 cmd_AddParm(ts
, "-buffers", CMD_SINGLE
, CMD_OPTIONAL
,
4278 "number of buffer slots");
4281 * Parse command-line switches & execute afsmonitor
4284 code
= cmd_Dispatch(argc
, argv
);
4290 exit(0); /* redundant, but gets rid of warning */