Import Upstream version 1.8.5
[hcoop/debian/openafs.git] / src / afsmonitor / afsmonitor.c
1 /*
2 * Copyright 2000, International Business Machines Corporation and others.
3 * All Rights Reserved.
4 *
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
8 *
9 * Portions Copyright (c) 2003 Apple Computer, Inc.
10 */
11
12 /*
13 * Afsmonitor: An AFS Performance Monitoring Tool
14 *
15 *-------------------------------------------------------------------------*/
16
17
18 #include <afsconfig.h>
19 #include <afs/param.h>
20
21 #include <roken.h>
22
23 #include <math.h>
24 #include <ctype.h>
25
26 #include <afs/cmd.h>
27
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>
36
37 #include <afs/xstat_fs.h>
38 #include <afs/xstat_cm.h>
39
40 #include "afsmonitor.h"
41
42 /* command line parameter indices */
43
44 #define P_CONFIG 0
45 #define P_FREQUENCY 1
46 #define P_OUTPUT 2
47 #define P_DETAILED 3
48 /* #define P_PACKAGE X */
49 #define P_DEBUG 4
50 #define P_FSHOSTS 5
51 #define P_CMHOSTS 6
52 #define P_BUFFERS 7
53
54
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 */
66
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];
70
71
72 /* afsmonitor misc definitions */
73
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 */
79
80
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 */
83
84
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 ? */
89
90
91 /* THRESHOLD STRUCTURE DEFINITIONS */
92
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 */
98
99
100
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;
105
106 /* number of fileservers and cache managers to monitor */
107 int numFS = 0;
108 int numCM = 0;
109
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;
115
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. */
126
127
128 /* FILE SERVER CIRCULAR BUFFER VARIABLES */
129
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;
134 };
135
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 */
139 };
140
141 int afsmon_fs_results_length[] =
142 { XSTAT_FS_FULLPERF_RESULTS_LEN, XSTAT_FS_CBSTATS_RESULTS_LEN };
143
144 /* buffer for FS probe results */
145 struct afsmon_fs_Results_CBuffer *afsmon_fs_ResultsCB;
146
147 int afsmon_fs_curr_CBindex = 0; /* current fs CB slot */
148
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
153 counters are used */
154
155 int afsmon_fs_curr_probeNum = 1; /* current fs probe number */
156 int afsmon_fs_prev_probeNum = 0; /* previous fs probe number */
157
158
159 /* CACHE MANAGER CIRCULAR BUFFER VARIABLES */
160
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;
165 };
166
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 */
170 };
171
172 int afsmon_cm_results_length[] = { XSTAT_CM_FULLPERF_RESULTS_LEN };
173
174 /* buffer for CM probe results */
175 struct afsmon_cm_Results_CBuffer *afsmon_cm_ResultsCB;
176
177 int afsmon_cm_curr_CBindex = 0; /* current cm CB slot */
178
179
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
184 counters are used */
185
186 int afsmon_cm_curr_probeNum = 1; /* current cm probe number */
187 int afsmon_cm_prev_probeNum = 0; /* previous cm probe number */
188
189
190 /* Structures to hold FS & CM results in string format(suitable for display ) */
191
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;
197
198
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;
204
205 /* EXTERN DEFINITIONS */
206
207 /* file server and cache manager variable names (from afsmon_labels.h) */
208 extern char *fs_varNames[];
209 extern char *cm_varNames[];
210
211 /* GTX & MISC VARIABLES */
212
213 /* afsmonitor window */
214 extern struct gwin *afsmon_win;
215
216 /* current page number in the overview frame */
217 extern int ovw_currPage;
218
219 /* number of FS alerts and number of hosts on FS alerts */
220 int num_fs_alerts;
221 int numHosts_onfs_alerts;
222
223 /* number of CM alerts and number of hosts on FS alerts */
224 int num_cm_alerts;
225 int numHosts_oncm_alerts;
226
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;
231
232 extern int gtx_initialized; /* gtx initialized ? */
233
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 */
241
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 ? */
245
246
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 ? */
251
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 */
254
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 */
257
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 */
262
263
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);
268
269 #ifdef HAVE_STRCASESTR
270 extern char * strcasestr(const char *, const char *);
271 #else
272 /*
273 strcasestr(): Return first occurence of pattern s2 in s1, case
274 insensitive.
275
276 This routine is required since I made pattern matching of the
277 config file to be case insensitive.
278 */
279
280 char *
281 strcasestr(s1, s2)
282 char *s1;
283 char *s2;
284 {
285 char *ptr;
286 int len1, len2;
287
288 len1 = strlen(s1);
289 len2 = strlen(s2);
290
291 if (len1 < len2)
292 return (NULL);
293
294 ptr = s1;
295
296 while (len1 >= len2 && len1 > 0) {
297 if ((strncasecmp(ptr, s2, len2)) == 0)
298 return (ptr);
299 ptr++;
300 len1--;
301 }
302 return (NULL);
303 }
304 #endif
305
306 struct hostent *
307 GetHostByName(char *name)
308 {
309 struct hostent *he;
310 #ifdef AFS_SUN5_ENV
311 char ip_addr[32];
312 #endif
313
314 he = gethostbyname(name);
315 #ifdef AFS_SUN5_ENV
316 /* On solaris the above does not resolve hostnames to full names */
317 if (he != NULL) {
318 memcpy(ip_addr, he->h_addr, he->h_length);
319 he = gethostbyaddr(ip_addr, he->h_length, he->h_addrtype);
320 }
321 #endif
322 return (he);
323 }
324
325
326 /*-----------------------------------------------------------------------
327 * afsmon_Exit()
328 *
329 * Description
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().
334 *
335 * Returns
336 * Nothing.
337 *
338 * Comments
339 * This function is called to execute a user handler only
340 * by a child process.
341 *
342 *----------------------------------------------------------------------*/
343
344 int
345 afsmon_Exit(int a_exitVal) /* exit code */
346 { /* afsmon_Exit */
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;
356 int i;
357 int j;
358 int bufslot;
359 int code;
360
361 if (afsmon_debug) {
362 fprintf(debugFD, "[ %s ] Called with exit code %d\n", rn, a_exitVal);
363 fflush(debugFD);
364 }
365
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);
370
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);
376
377 /* deallocate file server circular buffers */
378 if (numFS && num_bufSlots) {
379 if (afsmon_debug) {
380 fprintf(debugFD, "freeing FS circular buffers ");
381 fflush(debugFD);
382 }
383
384 for (bufslot = 0; bufslot < num_bufSlots; bufslot++) {
385 if (afsmon_debug)
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;
390 j = numFS;
391 while (tmp_fslist) {
392 /* make sure we do not go astray */
393 if (--j < 0) {
394 if (afsmon_debug)
395 fprintf(debugFD,
396 "[ %s ] error in deallocating fs CB\n",
397 rn);
398 break;
399 }
400 next_fslist = tmp_fslist->next;
401 for (i = 0; i < MAX_NUM_FS_COLLECTIONS; i++) {
402 tmp_xstat_fsPR = tmp_fslist->fsResults[i];
403
404 if (afsmon_debug)
405 fprintf(debugFD, "%d ", numFS - j);
406
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);
411 }
412
413 /* free the fs list item */
414 free(tmp_fslist);
415 tmp_fslist = next_fslist;
416
417 } /* while fs list items in this slot */
418 } /* if entries in this buffer slot */
419 } /* for each fs buffer slot */
420 if (afsmon_debug)
421 fprintf(debugFD, "\n");
422 }
423
424 if (afsmon_debug)
425 fflush(debugFD);
426 /* deallocate cache manager curcular buffers */
427 if (numCM && num_bufSlots) {
428 if (afsmon_debug)
429 fprintf(debugFD, "freeing CM curcular buffers ");
430 for (bufslot = 0; bufslot < num_bufSlots; bufslot++) {
431 if (afsmon_debug)
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;
436 j = numCM;
437 while (tmp_cmlist) {
438 /* make sure we do not go astray */
439 if (--j < 0) {
440 if (afsmon_debug)
441 fprintf(debugFD,
442 "[ %s ] error in deallocating cm CB\n",
443 rn);
444 break;
445 }
446 next_cmlist = tmp_cmlist->next;
447 for (i = 0; i < MAX_NUM_CM_COLLECTIONS; i++) {
448 tmp_xstat_cmPR = tmp_cmlist->cmResults[i];
449
450 if (afsmon_debug)
451 fprintf(debugFD, "%d ", numCM - j);
452 /* make sure data is ok */
453 /* Print_cm_FullPerfInfo(tmp_xstat_cmPR); */
454
455 /* free xstat_cm_Results data */
456 free(tmp_xstat_cmPR->data.AFSCB_CollData_val);
457 free(tmp_xstat_cmPR->connP);
458 }
459 free(tmp_cmlist->cmResults);
460
461 /* free the cm list item */
462 free(tmp_cmlist);
463 tmp_cmlist = next_cmlist;
464
465 } /* while cm list items in this slot */
466 } /* if entries in this buffer slot */
467 } /* for each cm buffer slot */
468 if (afsmon_debug)
469 fprintf(debugFD, "\n");
470 }
471
472
473 /* deallocate FS & CM Print buffers */
474 if (curr_fsData != NULL) {
475 if (afsmon_debug)
476 fprintf(debugFD, "Deallocating FS Print Buffers .... curr");
477 free(curr_fsData);
478 }
479 if (prev_fsData != NULL) {
480 if (afsmon_debug)
481 fprintf(debugFD, ", prev \n");
482 free(prev_fsData);
483 }
484 if (curr_cmData != NULL) {
485 if (afsmon_debug)
486 fprintf(debugFD, "Deallocating CM Print Buffers .... curr");
487 free(curr_cmData);
488 }
489 if (prev_cmData != NULL) {
490 if (afsmon_debug)
491 fprintf(debugFD, ", prev \n");
492 free(prev_cmData);
493 }
494
495 /* deallocate hostEntry lists */
496 if (numFS) {
497 if (afsmon_debug)
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;
506 }
507 if (afsmon_debug)
508 fprintf(debugFD, "\n");
509 }
510 if (numCM) {
511 if (afsmon_debug)
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;
520 }
521 if (afsmon_debug)
522 fprintf(debugFD, "\n");
523 }
524
525 /* close debug file */
526 if (afsmon_debug) {
527 fflush(debugFD);
528 fclose(debugFD);
529 }
530
531 if (exec_fsThreshHandler) {
532 code = execvp(fsHandler_argv[0], fsHandler_argv);
533 if (code == -1) {
534 fprintf(stderr, "execvp() of %s returned %d, errno %d\n",
535 fsHandler_argv[0], code, errno);
536 exit(-1);
537 }
538 }
539
540 exit(a_exitVal);
541 } /* afsmon_Exit */
542
543 /*-----------------------------------------------------------------------
544 * insert_FS()
545 *
546 * Description:
547 * Insert a hostname in the file server names list.
548 *
549 * Returns:
550 * Success: 0
551 * Failure: -1
552 *----------------------------------------------------------------------*/
553
554 int
555 insert_FS(char *a_hostName) /* name of cache manager to be inserted in list */
556 { /* insert_FS() */
557 static struct afsmon_hostEntry *curr_item;
558 static struct afsmon_hostEntry *prev_item;
559
560 if (*a_hostName == '\0')
561 return (-1);
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");
565 return (-1);
566 }
567
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;
572
573 if (FSnameList == (struct afsmon_hostEntry *)0)
574 FSnameList = curr_item;
575 else
576 prev_item->next = curr_item;
577
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;
582
583 return (0);
584 }
585
586 /*-----------------------------------------------------------------------
587 * print_FS()
588 *
589 * Description:
590 * Debug routine.
591 * Prints the file server names linked list.
592 *
593 * Returns:
594 * Nothing.
595 *----------------------------------------------------------------------*/
596 void
597 print_FS(void)
598 { /* print_FS() */
599 static char rn[] = "print_FS";
600 struct afsmon_hostEntry *tempFS;
601 struct Threshold *threshP;
602 int i;
603
604 if (afsmon_debug) {
605 fprintf(debugFD, "[ %s ] Called\n", rn);
606 fflush(debugFD);
607 }
608
609 if (afsmon_debug) {
610 tempFS = FSnameList;
611 fprintf(debugFD, "No of File Servers: %d\n", numFS);
612 if (numFS) {
613 do {
614 fprintf(debugFD, "\t %s threshCount = %d\n", tempFS->hostName,
615 tempFS->numThresh);
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);
622 }
623 fprintf(debugFD, "\t\t-----End of List-----\n");
624 fflush(debugFD);
625 }
626
627 }
628
629 /*-----------------------------------------------------------------------
630 * insert_CM()
631 *
632 * Description:
633 * Insert a hostname in the cache manager names list.
634 *
635 * Returns:
636 * Success: 0
637 * Failure: -1
638 *----------------------------------------------------------------------*/
639
640 int
641 insert_CM(char *a_hostName) /* name of cache manager to be inserted in list */
642 { /* insert_CM */
643 static struct afsmon_hostEntry *curr_item;
644 static struct afsmon_hostEntry *prev_item;
645
646 if (*a_hostName == '\0')
647 return (-1);
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");
651 return (-1);
652 }
653
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;
658
659 if (CMnameList == (struct afsmon_hostEntry *)0)
660 CMnameList = curr_item;
661 else
662 prev_item->next = curr_item;
663
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;
668
669 return (0);
670 }
671
672
673 /*-----------------------------------------------------------------------
674 * print_CM()
675 *
676 * Description:
677 * Debug routine.
678 * Prints the cache manager names linked list.
679 *
680 * Returns:
681 * Nothing.
682 *----------------------------------------------------------------------*/
683 int
684 print_CM(void)
685 { /* print_CM() */
686 static char rn[] = "print_CM";
687 struct afsmon_hostEntry *tempCM;
688 struct Threshold *threshP;
689 int i;
690
691 if (afsmon_debug) {
692 fprintf(debugFD, "[ %s ] Called\n", rn);
693 fflush(debugFD);
694 }
695
696 if (afsmon_debug) {
697 tempCM = CMnameList;
698 fprintf(debugFD, "No of Cache Managers: %d\n", numCM);
699 if (numCM) {
700 do {
701 fprintf(debugFD, "\t %s threshCount = %d\n", tempCM->hostName,
702 tempCM->numThresh);
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);
709 }
710 fprintf(debugFD, "\t\t-----End of List-----\n");
711 }
712 return (0);
713 } /* print_CM() */
714
715
716
717 /*-----------------------------------------------------------------------
718 * parse_hostEntry()
719 *
720 * Description:
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.
728 *
729 * Returns:
730 * Success: 0
731 * Failure: -1
732 *
733 *----------------------------------------------------------------------*/
734
735 int
736 parse_hostEntry(char *a_line)
737 { /* parse_hostEntry */
738
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 */
746
747 if (afsmon_debug) {
748 fprintf(debugFD, "[ %s ] Called, a_line = %s\n", rn, a_line);
749 fflush(debugFD);
750 }
751
752 /* break it up */
753 opcode[0] = 0;
754 arg1[0] = 0;
755 arg2[0] = 0;
756 arg3[0] = 0;
757 arg4[0] = 0;
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);
762 return (-1);
763 }
764
765 /* good host ? */
766 he = GetHostByName(arg1);
767 if (he == NULL) {
768 fprintf(stderr, "[ %s ] Unable to resolve hostname %s\n", rn, arg1);
769 return (-1);
770 }
771
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 */
776 lastHostType = 1;
777 numFS++;
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 */
785 lastHostType = 2;
786 numCM++;
787 /* threholds are not global anymore */
788 if (global_ThreshFlag)
789 global_ThreshFlag = 0;
790 } else
791 return (-1);
792
793 return (0);
794 }
795
796 /*-----------------------------------------------------------------------
797 * parse_threshEntry()
798 *
799 * Description
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.
805 *
806 * Returns
807 * Success: 0
808 * Failure: -1
809 *
810 *----------------------------------------------------------------------*/
811
812 int
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 */
822
823 if (afsmon_debug) {
824 fprintf(debugFD, "[ %s ] Called, a_line = %s\n", rn, a_line);
825 fflush(debugFD);
826 }
827
828 /* break it up */
829 opcode[0] = 0;
830 arg1[0] = 0;
831 arg2[0] = 0;
832 arg3[0] = 0;
833 arg4[0] = 0;
834 arg5[0] = 0;
835 sscanf(a_line, "%s %s %s %s %s %s", opcode, arg1, arg2, arg3, arg4, arg5);
836
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);
841 return (-1);
842 }
843 if (strlen(arg3) > THRESH_VAR_LEN - 2) {
844 fprintf(stderr, "[%s ] threshold value too long\n", rn);
845 return (-1);
846 }
847
848 if ((strcasecmp(arg1, "fs")) == 0) {
849 switch (lastHostType) {
850 case 0: /* its a global threshold */
851 global_fsThreshCount++;
852 break;
853 case 1: /* inc thresh count of last file server */
854 last_hostEntry->numThresh++;
855 break;
856 case 2:
857 fprintf(stderr,
858 "[ %s ] A threshold for a File Server cannot be placed after a Cache Manager host entry in the config file \n",
859 rn);
860 return (-1);
861 default:
862 fprintf(stderr, "[ %s ] Programming error 1\n", rn);
863 return (-1);
864 }
865 } else if ((strcasecmp(arg1, "cm")) == 0) {
866 switch (lastHostType) {
867 case 0: /* its a global threshold */
868 global_cmThreshCount++;
869 break;
870 case 2: /* inc thresh count of last cache manager */
871 last_hostEntry->numThresh++;
872 break;
873 case 1:
874 fprintf(stderr,
875 "[ %s ] A threshold for a Cache Manager cannot be placed after a File Server host entry in the config file \n",
876 rn);
877 return (-1);
878 default:
879 fprintf(stderr, "[ %s ] Programming error 2\n", rn);
880 return (-1);
881 }
882 } else {
883 fprintf(stderr,
884 "[ %s ] Syntax error. Second argument should be \"fs\" or \"cm\" \n",
885 rn);
886 return (-1);
887 }
888
889 return (0);
890 } /* parse_threshEntry */
891
892
893 /*-----------------------------------------------------------------------
894 * store_threshold()
895 *
896 * Description
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
906 * overwritten.
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.
910 *
911 * Returns:
912 * Success: 0
913 * Failure: -1
914 *----------------------------------------------------------------------*/
915
916 int
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 */
922
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 */
927 char *hostname;
928 int index; /* index to fs_varNames or cm_varNames */
929 int found;
930 int done;
931 int srvCount; /* tmp count of host names */
932 int *global_TC; /* ptr to global_xxThreshCount */
933 int i, j;
934
935 if (afsmon_debug) {
936 fprintf(debugFD,
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);
939 fflush(debugFD);
940 }
941
942 /* resolve the threshold variable name */
943 found = 0;
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) {
947 found = 1;
948 break;
949 }
950 }
951 if (!found) {
952 fprintf(stderr, "[ %s ] Unknown FS threshold variable name %s\n",
953 rn, a_varName);
954 return (-1);
955 }
956 Header = FSnameList;
957 srvCount = numFS;
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) {
963 found = 1;
964 break;
965 }
966 }
967 if (!found) {
968 fprintf(stderr, "[ %s ] Unknown CM threshold variable name %s\n",
969 rn, a_varName);
970 return (-1);
971 }
972 Header = CMnameList;
973 srvCount = numCM;
974 hostname = last_cmHost;
975 global_TC = &global_cmThreshCount;
976 } else
977 return (-1);
978
979
980
981 /* if the global thresh count is not zero, place this threshold on
982 * all the host entries */
983
984 if (*global_TC) {
985 tmp_host = Header;
986 for (i = 0; i < srvCount; i++) {
987 threshP = tmp_host->thresh;
988 done = 0;
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;
999 done = 1;
1000 break;
1001 }
1002 threshP++;
1003 }
1004 if (!done) {
1005 fprintf(stderr, "[ %s ] Could not insert threshold entry",
1006 rn);
1007 fprintf(stderr, "for %s in thresh list of host %s \n",
1008 a_varName, tmp_host->hostName);
1009 return (-1);
1010 }
1011 tmp_host = tmp_host->next;
1012 }
1013 (*global_TC)--;
1014 return (0);
1015 }
1016
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 */
1019
1020 if (*hostname == '\0') {
1021 fprintf(stderr, "[ %s ] Programming error 3\n", rn);
1022 return (-1);
1023 }
1024
1025 /* get the hostEntry that this threshold belongs to */
1026 tmp_host = Header;
1027 found = 0;
1028 for (i = 0; i < srvCount; i++) {
1029 if (strcasecmp(tmp_host->hostName, hostname) == 0) {
1030 found = 1;
1031 break;
1032 }
1033 tmp_host = tmp_host->next;
1034 }
1035 if (!found) {
1036 fprintf(stderr, "[ %s ] Unable to find host %s in %s hostEntry list",
1037 rn, hostname, (a_type - 1) ? "CM" : "FS");
1038 return (-1);
1039 }
1040
1041 /* put this entry on the thresh list of this host, overwrite global value
1042 * if needed */
1043
1044 threshP = tmp_host->thresh;
1045 done = 0;
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;
1053 done = 1;
1054 break;
1055 }
1056 threshP++;
1057 }
1058
1059 if (!done) {
1060 fprintf(stderr,
1061 "[ %s ] Unable to insert threshold %s for %s host %s\n", rn,
1062 a_varName, (a_type - 1) ? "CM" : "FS", tmp_host->hostName);
1063 return (-1);
1064 }
1065
1066 return (0);
1067
1068 } /* store_thresholds */
1069
1070
1071 /*-----------------------------------------------------------------------
1072 * parse_showEntry()
1073 *
1074 * Description:
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.
1088 *
1089 * Returns:
1090 * Success: 0
1091 * Failure: -1 (invalid entry)
1092 * > -1 (programming error)
1093 *----------------------------------------------------------------------*/
1094
1095 int
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 */
1105 int fromIdx;
1106 int toIdx;
1107 int found;
1108 int idx = 0; /* index to fs_categories[] */
1109 int i;
1110 int j;
1111
1112
1113 if (afsmon_debug) {
1114 fprintf(debugFD, "[ %s ] Called, a_line= %s\n", rn, a_line);
1115 fflush(debugFD);
1116 }
1117 opcode[0] = 0;
1118 arg1[0] = 0;
1119 arg2[0] = 0;
1120 arg3[0] = 0;
1121 sscanf(a_line, "%s %s %s %s", opcode, arg1, arg2, arg3);
1122
1123 if (arg3[0] != '\0') {
1124 fprintf(stderr, "[ %s ] Extraneous characters at end of line\n", rn);
1125 return (-1);
1126 }
1127
1128 if ((strcasecmp(arg1, "fs") != 0) && (strcasecmp(arg1, "cm") != 0)) {
1129 fprintf(stderr,
1130 "[ %s ] Second argument of \"show\" directive should be \"fs\" or \"cm\" \n",
1131 rn);
1132 return (-1);
1133 }
1134
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
1140 * order. */
1141
1142 /* To handle duplicate "show" entries we keep track of what what we have
1143 * already marked to show in the xx_showFlags[] */
1144
1145 if (strcasecmp(arg1, "fs") == 0) { /* its a File Server entry */
1146
1147 /* mark that we have to show only what the user wants */
1148 fs_showDefault = 0;
1149
1150 /* if it is a section/group name, find it in the fs_categories[] array */
1151
1152 found = 0;
1153 if (strcasestr(arg2, "_section") != NULL
1154 || strcasestr(arg2, "_group") != NULL) {
1155 idx = 0;
1156 while (idx < FS_NUM_DATA_CATEGORIES) {
1157 sscanf(fs_categories[idx], "%s %d %d", catName, &fromIdx,
1158 &toIdx);
1159 idx++;
1160 if (strcasecmp(arg2, catName) == 0) {
1161 found = 1;
1162 break;
1163 }
1164 }
1165
1166 if (!found) { /* typo in section/group name */
1167 fprintf(stderr,
1168 "[ %s ] Could not find section/group name %s\n", rn,
1169 arg2);
1170 return (-1);
1171 }
1172 }
1173
1174 /* if it is a group name, read its start/end indices and fill in the
1175 * fs_Display_map[]. */
1176
1177 if (strcasestr(arg2, "_group") != NULL) {
1178
1179 if (fromIdx < 0 || toIdx < 0 || fromIdx >= NUM_FS_STAT_ENTRIES
1180 || toIdx >= NUM_FS_STAT_ENTRIES)
1181 return (-2);
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;
1187 }
1188 if (fs_DisplayItems_count >= NUM_FS_STAT_ENTRIES) {
1189 fprintf(stderr, "[ %s ] fs_DisplayItems_count ovf\n", rn);
1190 return (-3);
1191 }
1192 }
1193 } else
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[] */
1196
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,
1203 &toIdx);
1204
1205 if (strcasestr(catName, "_group") != NULL) {
1206 if (fromIdx < 0 || toIdx < 0
1207 || fromIdx >= NUM_FS_STAT_ENTRIES
1208 || toIdx >= NUM_FS_STAT_ENTRIES)
1209 return (-4);
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;
1215 }
1216 if (fs_DisplayItems_count >= NUM_FS_STAT_ENTRIES) {
1217 fprintf(stderr,
1218 "[ %s ] fs_DisplayItems_count ovf\n", rn);
1219 return (-5);
1220 }
1221 }
1222 } else {
1223 fprintf(stderr, "[ %s ] Error parsing groups for %s\n",
1224 rn, arg2);
1225 return (-6);
1226 }
1227 idx++;
1228 numGroups--;
1229 } /* for each group in section */
1230
1231
1232 } else { /* it is a variable name */
1233
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;
1240 }
1241 if (fs_DisplayItems_count >= NUM_FS_STAT_ENTRIES) {
1242 fprintf(stderr, "[ %s ] fs_DisplayItems_count ovf\n",
1243 rn);
1244 return (-25);
1245 }
1246 found = 1;
1247 }
1248 }
1249 if (!found) { /* typo in section/group name */
1250 fprintf(stderr, "[ %s ] Could not find variable name %s\n",
1251 rn, arg2);
1252 return (-1);
1253 }
1254 } /* its a variable name */
1255
1256 }
1257
1258 /* it is an fs entry */
1259 if (strcasecmp(arg1, "cm") == 0) { /* its a Cache Manager entry */
1260
1261
1262 /* mark that we have to show only what the user wants */
1263 cm_showDefault = 0;
1264
1265 /* if it is a section/group name, find it in the cm_categories[] array */
1266
1267 found = 0;
1268 if (strcasestr(arg2, "_section") != NULL
1269 || strcasestr(arg2, "_group") != NULL) {
1270 idx = 0;
1271 while (idx < CM_NUM_DATA_CATEGORIES) {
1272 sscanf(cm_categories[idx], "%s %d %d", catName, &fromIdx,
1273 &toIdx);
1274 idx++;
1275 if (strcasecmp(arg2, catName) == 0) {
1276 found = 1;
1277 break;
1278 }
1279 }
1280
1281 if (!found) { /* typo in section/group name */
1282 fprintf(stderr,
1283 "[ %s ] Could not find section/group name %s\n", rn,
1284 arg2);
1285 return (-1);
1286 }
1287 }
1288
1289 /* if it is a group name, read its start/end indices and fill in the
1290 * cm_Display_map[]. */
1291
1292 if (strcasestr(arg2, "_group") != NULL) {
1293
1294 if (fromIdx < 0 || toIdx < 0 || fromIdx >= NUM_CM_STAT_ENTRIES
1295 || toIdx >= NUM_CM_STAT_ENTRIES)
1296 return (-10);
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;
1302 }
1303 if (cm_DisplayItems_count >= NUM_CM_STAT_ENTRIES) {
1304 fprintf(stderr, "[ %s ] cm_DisplayItems_count ovf\n", rn);
1305 return (-11);
1306 }
1307 }
1308 } else
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[] */
1311
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,
1318 &toIdx);
1319
1320 if (strcasestr(catName, "_group") != NULL) {
1321 if (fromIdx < 0 || toIdx < 0
1322 || fromIdx >= NUM_CM_STAT_ENTRIES
1323 || toIdx >= NUM_CM_STAT_ENTRIES)
1324 return (-12);
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;
1330 }
1331 if (cm_DisplayItems_count >= NUM_CM_STAT_ENTRIES) {
1332 fprintf(stderr,
1333 "[ %s ] cm_DisplayItems_count ovf\n", rn);
1334 return (-13);
1335 }
1336 }
1337 } else {
1338 fprintf(stderr, "[ %s ] Error parsing groups for %s\n",
1339 rn, arg2);
1340 return (-15);
1341 }
1342 idx++;
1343 numGroups--;
1344 } /* for each group in section */
1345 } else { /* it is a variable name */
1346
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;
1353 }
1354 if (cm_DisplayItems_count >= NUM_CM_STAT_ENTRIES) {
1355 fprintf(stderr, "[ %s ] cm_DisplayItems_count ovf\n",
1356 rn);
1357 return (-20);
1358 }
1359 found = 1;
1360 }
1361 }
1362 if (!found) { /* typo in section/group name */
1363 fprintf(stderr, "[ %s ] Could not find variable name %s\n",
1364 rn, arg2);
1365 return (-1);
1366 }
1367 } /* its a variable name */
1368
1369 }
1370 /* it is an cm entry */
1371 return (0);
1372 } /* parse_showEntry */
1373
1374
1375 /*-----------------------------------------------------------------------
1376 * process_config_file()
1377 *
1378 * Description:
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
1382 * constructed.
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
1388 *
1389 * Returns:
1390 * Success: 0
1391 * Failure: Exits afsmonitor showing error and line.
1392 *----------------------------------------------------------------------*/
1393
1394 int
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 ?? */
1411 int i;
1412 int numBytes;
1413
1414 if (afsmon_debug) {
1415 fprintf(debugFD, "[ %s ] Called, a_config_filename= %s\n", rn,
1416 a_config_filename);
1417 fflush(debugFD);
1418 }
1419
1420 /* open config file */
1421
1422 configFD = fopen(a_config_filename, "r");
1423 if (configFD == (FILE *) 0) {
1424 fprintf(stderr, "Failed to open config file %s \n",
1425 a_config_filename);
1426 if (afsmon_debug) {
1427 fprintf(debugFD, "[ %s ] Failed to open config file %s \n", rn,
1428 a_config_filename);
1429 }
1430 afsmon_Exit(5);
1431 }
1432
1433
1434 /* parse config file */
1435
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. */
1440
1441 /* First Pass */
1442
1443 numFS = 0;
1444 numCM = 0;
1445 error_in_config = 0; /* flag to note if config file has syntax errors */
1446
1447 while ((fgets(line, CFG_STR_LEN, configFD)) != NULL) {
1448 opcode[0] = 0;
1449 arg1[0] = 0;
1450 arg2[0] = 0;
1451 arg3[0] = 0;
1452 arg4[0] = 0;
1453 sscanf(line, "%s %s %s %s %s", opcode, arg1, arg2, arg3, arg4);
1454 linenum++;
1455 /* skip blank lines and comment lines */
1456 if ((strlen(opcode) == 0) || line[0] == '#')
1457 continue;
1458
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);
1466 } else {
1467 fprintf(stderr, "[ %s ] Unknown opcode %s\n", rn, opcode);
1468 code = 1;
1469 }
1470
1471 if (code) {
1472 fprintf(stderr, "[ %s ] Error in line:\n %d: %s\n", rn, linenum,
1473 line);
1474 error_in_config = 1;
1475 }
1476 }
1477
1478 if (error_in_config)
1479 afsmon_Exit(10);
1480
1481 if (afsmon_debug) {
1482 fprintf(debugFD, "Global FS thresholds count = %d\n",
1483 global_fsThreshCount);
1484 fprintf(debugFD, "Global CM thresholds count = %d\n",
1485 global_cmThreshCount);
1486 fflush(debugFD);
1487 }
1488
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 ? */
1493
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;
1499 }
1500 }
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;
1506 }
1507 }
1508
1509
1510 /* make sure we have something to monitor */
1511 if (numFS == 0 && numCM == 0) {
1512 fprintf(stderr,
1513 "\nConfig file must specify atleast one File Server or Cache Manager host to monitor.\n");
1514 fclose(configFD);
1515 afsmon_Exit(15);
1516 }
1517
1518 /* Second Pass */
1519
1520 fseek(configFD, 0, 0); /* seek to the beginning */
1521
1522
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);
1528 afsmon_Exit(20);
1529 }
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);
1535 afsmon_Exit(25);
1536 }
1537 memset(curr_host->thresh, 0, numBytes);
1538 }
1539 curr_host = curr_host->next;;
1540 }
1541
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);
1546 afsmon_Exit(30);
1547 }
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);
1553 afsmon_Exit(35);
1554 }
1555 memset(curr_host->thresh, 0, numBytes);
1556 }
1557 curr_host = curr_host->next;;
1558 }
1559
1560
1561 opcode[0] = 0;
1562 arg1[0] = 0;
1563 arg2[0] = 0;
1564 arg3[0] = 0;
1565 arg4[0] = 0;
1566 last_fsHost[0] = '\0';
1567 last_cmHost[0] = '\0';
1568 linenum = 0;
1569 while ((fgets(line, CFG_STR_LEN, configFD)) != NULL) {
1570 opcode[0] = 0;
1571 arg1[0] = 0;
1572 arg2[0] = 0;
1573 arg3[0] = 0;
1574 arg4[0] = 0;
1575 sscanf(line, "%s %s %s %s %s", opcode, arg1, arg2, arg3, arg4);
1576 linenum++;
1577
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
1588 * following */
1589 if (strlen(arg4)) {
1590 handlerPtr = line;
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))
1595 handlerPtr++;
1596 while (!isspace(*handlerPtr))
1597 handlerPtr++;
1598 }
1599 while (isspace(*handlerPtr))
1600 handlerPtr++;
1601 /* we how have a pointer to the start of the handler
1602 * name & args */
1603 } else
1604 handlerPtr = arg4; /* empty string */
1605
1606
1607 if (strcasecmp(arg1, "fs") == 0)
1608 code = store_threshold(1, /* 1 = fs */
1609 arg2, arg3, handlerPtr);
1610
1611 else if (strcasecmp(arg1, "cm") == 0)
1612 code = store_threshold(2, /* 2 = fs */
1613 arg2, arg3, handlerPtr);
1614
1615 else {
1616 fprintf(stderr, "[ %s ] Programming error 6\n", rn);
1617 afsmon_Exit(40);
1618 }
1619 if (code) {
1620 fprintf(stderr, "[ %s ] Failed to store threshold\n", rn);
1621 fprintf(stderr, "[ %s ] Error processing line:\n%d: %s", rn,
1622 linenum, line);
1623 afsmon_Exit(45);
1624 }
1625 }
1626 }
1627
1628
1629 fclose(configFD);
1630 return (0);
1631 }
1632
1633 /*-----------------------------------------------------------------------
1634 * Print_FS_CB
1635 *
1636 * Description:
1637 * Debug routine.
1638 * Print the File Server circular buffer.
1639 *
1640 * Returns:
1641 * Nothing.
1642 *----------------------------------------------------------------------*/
1643
1644 void
1645 Print_FS_CB(void)
1646 { /* Print_FS_CB() */
1647
1648 struct afsmon_fs_Results_list *fslist;
1649 int i;
1650 int j;
1651 int k;
1652
1653 /* print valid info in the fs CB */
1654
1655 if (afsmon_debug) {
1656 fprintf(debugFD,
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);
1662
1663 for (i = 0; i < num_bufSlots; i++) {
1664 fprintf(debugFD, "\t--------- slot %d ----------\n", i);
1665 fslist = afsmon_fs_ResultsCB[i].list;
1666 j = 0;
1667 while (j < numFS) {
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",
1671 j,
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");
1677 else
1678 fprintf(debugFD, " OK\n");
1679 } else
1680 fprintf(debugFD, "\t %d) -- empty --\n", j);
1681 }
1682 fslist = fslist->next;
1683 j++;
1684 }
1685 if (fslist != (struct afsmon_fs_Results_list *)0)
1686 fprintf(debugFD, "dangling last next ptr fs CB\n");
1687 }
1688 }
1689 } /* Print_FS_CB() */
1690
1691 /*-----------------------------------------------------------------------
1692 * save_FS_results_inCB()
1693 *
1694 * Description:
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.
1702 *
1703 * Returns:
1704 * Success: 0
1705 * Failure: Exits afsmonitor.
1706 *----------------------------------------------------------------------*/
1707 int
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 */
1713 int i;
1714 int index;
1715
1716 if (afsmon_debug) {
1717 fprintf(debugFD, "[ %s ] Called, a_newProbeCycle= %d\n", rn,
1718 a_newProbeCycle);
1719 fflush(debugFD);
1720 }
1721
1722 switch (xstat_fs_Results.collectionNumber) {
1723 case AFS_XSTATSCOLL_FULL_PERF_INFO:
1724 index = 0;
1725 break;
1726 case AFS_XSTATSCOLL_CBSTATS:
1727 index = 1;
1728 break;
1729 default:
1730 fprintf(stderr, "[ %s ] collection number %d is out of range.\n",
1731 rn, xstat_fs_Results.collectionNumber);
1732 afsmon_Exit(51);
1733 }
1734
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() */
1738
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;
1744 }
1745 }
1746
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])
1751 break;
1752 tmp_fslist_item = tmp_fslist_item->next;
1753 }
1754
1755 /* if we could not find one we have an inconsistent list */
1756 if (!tmp_fslist_item->empty[index]) {
1757 fprintf(stderr,
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);
1761 afsmon_Exit(50);
1762 }
1763
1764 tmp_fsPR = tmp_fslist_item->fsResults[index];
1765
1766 /* copy hostname and probe number and probe time and probe status.
1767 * if the probe failed return now */
1768
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;
1777 return (0);
1778 }
1779
1780 /* copy connection information */
1781 memcpy(&(tmp_fsPR->connP->skt), &(xstat_fs_Results.connP->skt),
1782 sizeof(struct sockaddr_in));
1783
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;
1787
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));
1795
1796
1797 /* we have a valid results structure so mark the list item used */
1798 tmp_fslist_item->empty[index] = 0;
1799
1800 /* Print the fs circular buffer */
1801 Print_FS_CB();
1802
1803 return (0);
1804 } /* save_FS_results_inCB() */
1805
1806
1807 /*-----------------------------------------------------------------------
1808 * fs_Results_ltoa()
1809 *
1810 * Description:
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().
1818 *
1819 * Returns:
1820 * Always returns 0.
1821 *----------------------------------------------------------------------*/
1822
1823 int
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 */
1827
1828 static char rn[] = "fs_Results_ltoa"; /* routine name */
1829
1830 if (afsmon_debug) {
1831 fprintf(debugFD, "[ %s ] Called, a_fsData= %p, a_fsResults= %p\n", rn,
1832 a_fsData, a_fsResults);
1833 fflush(debugFD);
1834 }
1835
1836 switch (a_fsResults->collectionNumber) {
1837 case AFS_XSTATSCOLL_FULL_PERF_INFO:
1838 fs_FullPerfs_ltoa(a_fsData, a_fsResults);
1839 break;
1840 case AFS_XSTATSCOLL_CBSTATS:
1841 fs_CallBackStats_ltoa(a_fsData, a_fsResults);
1842 break;
1843 default:
1844 if (afsmon_debug) {
1845 fprintf(debugFD, "[ %s ] Unexpected collection id %d\n",
1846 rn, a_fsResults->collectionNumber);
1847 }
1848 }
1849
1850 return (0);
1851 } /* fs_Results_ltoa */
1852
1853 /*-----------------------------------------------------------------------
1854 * fs_FullPerfs_ltoa()
1855 *
1856 * Description:
1857 * Convert the full perf xstat collection from int32s to strings.
1858 *
1859 * Returns:
1860 * Always returns 0.
1861 *----------------------------------------------------------------------*/
1862 static int
1863 fs_FullPerfs_ltoa(struct fs_Display_Data *a_fsData,
1864 struct xstat_fs_ProbeResults *a_fsResults)
1865 {
1866 afs_int32 *srcbuf;
1867 struct fs_stats_FullPerfStats *fullPerfP;
1868 struct fs_stats_FullPerfStats buffer;
1869 int idx;
1870 int i, j;
1871 afs_int32 *tmpbuf;
1872 int code;
1873 int large_time;
1874
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 */
1879
1880 code = xstat_fs_DecodeFullPerfStats(&fullPerfP,
1881 a_fsResults->data.AFS_CollData_val,
1882 a_fsResults->data.AFS_CollData_len,
1883 &buffer);
1884 if (code) {
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", "--");
1888 }
1889 return 0;
1890 }
1891
1892 /* copy overall performance statistics */
1893 srcbuf = (afs_int32 *) & (fullPerfP->overall);
1894 idx = 0;
1895 for (i = 0; i < NUM_XSTAT_FS_AFS_PERFSTATS_LONGS; i++) {
1896 sprintf(a_fsData->data[idx], "%d", *srcbuf);
1897 idx++;
1898 srcbuf++;
1899 }
1900
1901 /* copy epoch */
1902 srcbuf = (afs_int32 *) & (fullPerfP->det.epoch);
1903 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* epoch */
1904 idx++;
1905
1906 /* copy fs operation timing */
1907
1908 srcbuf = (afs_int32 *) (fullPerfP->det.rpcOpTimes);
1909
1910 /*
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
1913 */
1914 if (sizeof(struct timeval) == 16)
1915 large_time = 1;
1916 else
1917 large_time = 0;
1918
1919 for (i = 0; i < FS_STATS_NUM_RPC_OPS; i++) {
1920 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* numOps */
1921 idx++;
1922 srcbuf++;
1923 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* numSuccesses */
1924 idx++;
1925 srcbuf++;
1926 tmpbuf = srcbuf++; /* sum time */
1927 sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1928 idx++;
1929 srcbuf++;
1930 if (large_time)
1931 srcbuf += 2;
1932 tmpbuf = srcbuf++; /* sqr time */
1933 sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1934 idx++;
1935 srcbuf++;
1936 if (large_time)
1937 srcbuf += 2;
1938 tmpbuf = srcbuf++; /* min time */
1939 sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1940 idx++;
1941 srcbuf++;
1942 if (large_time)
1943 srcbuf += 2;
1944 tmpbuf = srcbuf++; /* max time */
1945 sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1946 idx++;
1947 srcbuf++;
1948 if (large_time)
1949 srcbuf += 2;
1950 }
1951
1952 /* copy fs transfer timings */
1953
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 */
1957 idx++;
1958 srcbuf++;
1959 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* numSuccesses */
1960 idx++;
1961 srcbuf++;
1962 tmpbuf = srcbuf++; /* sum time */
1963 sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1964 idx++;
1965 srcbuf++;
1966 if (large_time)
1967 srcbuf += 2;
1968 tmpbuf = srcbuf++; /* sqr time */
1969 sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1970 idx++;
1971 srcbuf++;
1972 if (large_time)
1973 srcbuf += 2;
1974 tmpbuf = srcbuf++; /* min time */
1975 sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1976 idx++;
1977 srcbuf++;
1978 if (large_time)
1979 srcbuf += 2;
1980 tmpbuf = srcbuf++; /* max time */
1981 sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1982 idx++;
1983 srcbuf++;
1984 if (large_time)
1985 srcbuf += 2;
1986 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* sum bytes */
1987 idx++;
1988 srcbuf++;
1989 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* min bytes */
1990 idx++;
1991 srcbuf++;
1992 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* max bytes */
1993 idx++;
1994 srcbuf++;
1995 for (j = 0; j < FS_STATS_NUM_XFER_BUCKETS; j++) {
1996 sprintf(a_fsData->data[idx], "%d", *srcbuf); /* bucket[j] */
1997 idx++;
1998 srcbuf++;
1999 }
2000 }
2001
2002 return (0);
2003 }
2004
2005 /*-----------------------------------------------------------------------
2006 * fs_CallBackStats_ltoa()
2007 *
2008 * Description:
2009 * Convert the callback counter xstat collection from
2010 * int32s to strings.
2011 *
2012 * Returns:
2013 * Always returns 0.
2014 *----------------------------------------------------------------------*/
2015
2016 static int
2017 fs_CallBackStats_ltoa(struct fs_Display_Data *a_fsData,
2018 struct xstat_fs_ProbeResults *a_fsResults)
2019 {
2020 int idx;
2021 int i;
2022 int len = a_fsResults->data.AFS_CollData_len;
2023 afs_int32 *val = a_fsResults->data.AFS_CollData_val;
2024
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]);
2029 }
2030 return 0;
2031 }
2032
2033 /*-----------------------------------------------------------------------
2034 * execute_thresh_handler()
2035 *
2036 * Description:
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.
2041 *
2042 * Returns:
2043 * Success: 0
2044 * Failure: Afsmonitor exits if threshold handler has more than 20 args.
2045 *----------------------------------------------------------------------*/
2046
2047 int
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 */
2055
2056 static char rn[] = "execute_thresh_handler";
2057 char fileName[256]; /* file name to execute */
2058 int i;
2059 char *ch;
2060 int argNum;
2061 int anotherArg; /* boolean used to flag if another arg is available */
2062
2063 if (afsmon_debug) {
2064 fprintf(debugFD,
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);
2068 fflush(debugFD);
2069 }
2070
2071
2072 /* get the filename to execute - the first argument */
2073 sscanf(a_handler, "%s", fileName);
2074
2075 /* construct the contents of *argv[] */
2076
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");
2081 else
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);
2086
2087
2088 argNum = 6;
2089 anotherArg = 1;
2090 ch = a_handler;
2091
2092 /* we have already extracted the file name so skip to the 1st arg */
2093 while (isspace(*ch)) /* leading blanks */
2094 ch++;
2095 while (!isspace(*ch) && *ch != '\0') /* handler filename */
2096 ch++;
2097
2098 while (*ch != '\0') {
2099 if (isspace(*ch)) {
2100 anotherArg = 1;
2101 } else if (anotherArg) {
2102 anotherArg = 0;
2103 sscanf(ch, "%s", fsHandler_args[argNum]);
2104 argNum++;
2105 }
2106 ch++;
2107 if (argNum >= 20) {
2108 sprintf(errMsg,
2109 "Threshold handlers cannot have more than 20 arguments\n");
2110 afsmon_Exit(55);
2111 }
2112
2113 }
2114
2115 fsHandler_argv[argNum] = NULL;
2116 for (i = 0; i < argNum; i++)
2117 fsHandler_argv[i] = fsHandler_args[i];
2118
2119
2120 /* exec the threshold handler */
2121
2122 if (fork() == 0) {
2123 exec_fsThreshHandler = 1;
2124 afsmon_Exit(60);
2125 }
2126
2127 return (0);
2128 } /* execute_thresh_handler */
2129
2130
2131
2132 /*-----------------------------------------------------------------------
2133 * check_fs_thresholds()
2134 *
2135 * Description:
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
2144 * curr_[fs/cm]Data.
2145 *
2146 * Returns:
2147 * 0
2148 *----------------------------------------------------------------------*/
2149
2150 int
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 */
2154
2155 static char rn[] = "check_fs_thresholds";
2156 struct Threshold *threshP;
2157 double tValue; /* threshold value */
2158 double pValue; /* probe value */
2159 int i;
2160 int idx;
2161 int count; /* number of thresholds exceeded */
2162
2163 if (afsmon_debug) {
2164 fprintf(debugFD, "[ %s ] Called, a_hostEntry= %p, a_Data= %p\n", rn,
2165 a_hostEntry, a_Data);
2166 fflush(debugFD);
2167 }
2168
2169 if (a_hostEntry->numThresh == 0) {
2170 /* store in ovf count ?? */
2171 return (0);
2172 }
2173
2174 count = 0;
2175 threshP = a_hostEntry->thresh;
2176 for (i = 0; i < a_hostEntry->numThresh; i++) {
2177 if (threshP->itemName[0] == '\0') {
2178 threshP++;
2179 continue;
2180 }
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) {
2185
2186 if (afsmon_debug) {
2187 fprintf(debugFD,
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]);
2191 fflush(debugFD);
2192 }
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! */
2196
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') {
2201 if (afsmon_debug) {
2202 fprintf(debugFD, "[ %s ] Calling ovf handler %s\n",
2203 rn, threshP->handler);
2204 fflush(debugFD);
2205 }
2206 execute_thresh_handler(threshP->handler, a_Data->hostName,
2207 FS, threshP->itemName,
2208 threshP->threshVal,
2209 a_Data->data[idx]);
2210 }
2211 }
2212
2213 count++;
2214 } else
2215 /* in case threshold was previously crossed, blank it out */
2216 a_Data->threshOvf[idx] = 0;
2217 threshP++;
2218 }
2219 /* store the overflow count */
2220 a_Data->ovfCount = count;
2221
2222 return (0);
2223 } /* check_fs_thresholds */
2224
2225
2226 /*-----------------------------------------------------------------------
2227 * save_FS_data_forDisplay()
2228 *
2229 * Description:
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
2237 *
2238 * Returns:
2239 * Success: 0
2240 * Failure: Exits afsmonitor.
2241 *----------------------------------------------------------------------*/
2242
2243 int
2244 save_FS_data_forDisplay(struct xstat_fs_ProbeResults *a_fsResults)
2245 { /* save_FS_data_forDisplay */
2246
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 */
2254 int numBytes;
2255 int okay;
2256 int i;
2257 int code;
2258 int done;
2259
2260
2261 if (afsmon_debug) {
2262 fprintf(debugFD, "[ %s ] Called, a_fsResults= %p\n", rn, a_fsResults);
2263 fflush(debugFD);
2264 }
2265
2266 /* store results in the display array */
2267
2268 okay = 0;
2269 curr_fsDataP = curr_fsData;
2270 for (i = 0; i < numFS; i++) {
2271 if ((strcasecmp(curr_fsDataP->hostName, a_fsResults->connP->hostName))
2272 == 0) {
2273 okay = 1;
2274 break;
2275 }
2276 curr_fsDataP++;
2277 }
2278
2279 if (!okay) {
2280 fprintf(stderr,
2281 "[ %s ] Could not insert FS probe results for host %s in fs display array\n",
2282 rn, a_fsResults->connP->hostName);
2283 afsmon_Exit(65);
2284 }
2285
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. */
2289
2290 if (a_fsResults->probeOK) { /* 1 => notOK the xstat results */
2291 curr_fsDataP->probeOK = 0;
2292
2293 /* print the probe status */
2294 if (afsmon_debug) {
2295 fprintf(debugFD, "\n\t\t ----- fs display data ------\n");
2296 fprintf(debugFD, "HostName = %s PROBE FAILED \n",
2297 curr_fsDataP->hostName);
2298 fflush(debugFD);
2299 }
2300
2301 } else { /* probe succeeded, update display data structures */
2302 curr_fsDataP->probeOK = 1;
2303
2304 /* convert longs to strings and place them in curr_fsDataP */
2305 fs_Results_ltoa(curr_fsDataP, a_fsResults);
2306
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 */
2310
2311 /* locate the hostEntry for this host */
2312 done = 0;
2313 curr_host = FSnameList;
2314 for (i = 0; i < numFS; i++) {
2315 if (strcasecmp(curr_host->hostName, a_fsResults->connP->hostName)
2316 == 0) {
2317 done = 1;
2318 break;
2319 }
2320 curr_host = curr_host->next;;
2321 }
2322 if (!done)
2323 afsmon_Exit(70);
2324
2325 code = check_fs_thresholds(curr_host, curr_fsDataP);
2326 if (code) {
2327 fprintf(stderr, "[ %s ] Error in checking thresholds\n", rn);
2328 afsmon_Exit(75);
2329 }
2330
2331 /* print the info we just saved */
2332
2333 if (afsmon_debug) {
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],
2338 fs_varNames[i],
2339 curr_fsDataP->threshOvf[i] ? "(ovf)" : "");
2340
2341 fprintf(debugFD, "\t\t--------------------------------\n\n");
2342 fflush(debugFD);
2343 }
2344
2345 } /* the probe succeeded, so we store the data in the display structure */
2346
2347
2348 /* if we have received a reply from all the hosts for this probe cycle,
2349 * it is time to display the data */
2350
2351 results_Received++;
2352 if (results_Received == numFS * num_fs_collections) {
2353 results_Received = 0;
2354
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);
2358 afsmon_Exit(80);
2359 } else
2360 afsmon_fs_prev_probeNum++;
2361
2362 /* backup the display data of the probe cycle that just completed -
2363 * ie., store curr_fsData in prev_fsData */
2364
2365 memcpy((char *)prev_fsData, (char *)curr_fsData,
2366 (numFS * sizeof(struct fs_Display_Data)));
2367
2368
2369 /* initialize curr_fsData but retain the threshold flag information.
2370 * The previous state of threshold flags is used in check_fs_thresholds() */
2371
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);
2378 curr_fsDataP++;
2379 }
2380
2381
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 */
2385
2386 prev_fsDataP = prev_fsData;
2387 num_fs_alerts = 0;
2388 numHosts_onfs_alerts = 0;
2389 for (i = 0; i < numFS; i++) {
2390 if (!prev_fsDataP->probeOK) { /* if probe failed */
2391 num_fs_alerts++;
2392 numHosts_onfs_alerts++;
2393 }
2394 if (prev_fsDataP->ovfCount) { /* overflows ?? */
2395 num_fs_alerts += prev_fsDataP->ovfCount;
2396 numHosts_onfs_alerts++;
2397 }
2398 prev_fsDataP++;
2399 }
2400 if (afsmon_debug)
2401 fprintf(debugFD, "Number of FS alerts = %d (on %d hosts)\n",
2402 num_fs_alerts, numHosts_onfs_alerts);
2403
2404 /* flag that the data is now ready to be displayed */
2405 fs_Data_Available = 1;
2406
2407 /* call the Overview frame update routine (update only FS info) */
2408 ovw_refresh(ovw_currPage, OVW_UPDATE_FS);
2409
2410 /* call the File Servers frame update routine */
2411 fs_refresh(fs_currPage, fs_curr_LCol);
2412
2413 }
2414 /* display data */
2415 return (0);
2416 } /* save_FS_data_forDisplay */
2417
2418
2419
2420
2421 /*-----------------------------------------------------------------------
2422 * afsmon_FS_Handler()
2423 *
2424 * Description:
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.
2428 *
2429 * Returns:
2430 * Success: 0
2431 * Failure: Exits afsmonitor.
2432 *----------------------------------------------------------------------*/
2433
2434 int
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 */
2440
2441
2442 if (afsmon_debug) {
2443 fprintf(debugFD,
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);
2448 fflush(debugFD);
2449 }
2450
2451
2452 /* print the probe results to output file */
2453 if (afsmon_output) {
2454 code = afsmon_fsOutput(output_filename, afsmon_detOutput);
2455 if (code) {
2456 fprintf(stderr,
2457 "[ %s ] output to file %s returned error code=%d\n", rn,
2458 output_filename, code);
2459 }
2460 }
2461
2462 /* Update current probe number and circular buffer index. if current
2463 * probenum changed make sure it is only by 1 */
2464
2465 newProbeCycle = 0;
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++;
2469 newProbeCycle = 1;
2470 if (num_bufSlots)
2471 afsmon_fs_curr_CBindex =
2472 (afsmon_fs_curr_probeNum - 1) % num_bufSlots;
2473 } else {
2474 fprintf(stderr, "[ %s ] probe number %d-1 missed\n", rn,
2475 xstat_fs_Results.probeNum);
2476 afsmon_Exit(85);
2477 }
2478 }
2479
2480
2481 /* store the results of this probe in the FS circular buffer */
2482 if (num_bufSlots)
2483 save_FS_results_inCB(newProbeCycle);
2484
2485
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 */
2490
2491 save_FS_data_forDisplay(&xstat_fs_Results);
2492
2493 return (0);
2494 }
2495
2496
2497
2498 /*----------------------------------------------------------------------- *
2499 * Print_CM_CB()
2500 *
2501 * Description:
2502 * Debug routine.
2503 * Prints the Cache Manager circular buffer
2504 *----------------------------------------------------------------------*/
2505
2506 void
2507 Print_CM_CB(void)
2508 { /* Print_CM_CB() */
2509
2510 struct afsmon_cm_Results_list *cmlist;
2511 int i;
2512 int j;
2513 int k;
2514
2515 /* print valid info in the cm CB */
2516
2517 if (afsmon_debug) {
2518 fprintf(debugFD,
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);
2524
2525 for (i = 0; i < num_bufSlots; i++) {
2526 fprintf(debugFD, "\t--------- slot %d ----------\n", i);
2527 cmlist = afsmon_cm_ResultsCB[i].list;
2528 j = 0;
2529 while (j < numCM) {
2530 for (k = 0; k < MAX_NUM_CM_COLLECTIONS; k++) {
2531 if (!cmlist->empty[k]) {
2532 fprintf(debugFD,
2533 "\t %d) probeNum = %d host = %s cn = %d",
2534 j,
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");
2540 else
2541 fprintf(debugFD, " OK\n");
2542 } else
2543 fprintf(debugFD, "\t %d) -- empty --\n", j);
2544 }
2545 cmlist = cmlist->next;
2546 j++;
2547 }
2548 if (cmlist != (struct afsmon_cm_Results_list *)0)
2549 fprintf(debugFD, "dangling last next ptr cm CB\n");
2550 }
2551 }
2552 }
2553
2554
2555 /*-----------------------------------------------------------------------
2556 * save_CM_results_inCB()
2557 *
2558 * Description:
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.
2566 *
2567 * Returns:
2568 * Success: 0
2569 * Failure: Exits afsmonitor.
2570 *----------------------------------------------------------------------*/
2571
2572 int
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 */
2578 int i;
2579 int index;
2580
2581
2582 if (afsmon_debug) {
2583 fprintf(debugFD, "[ %s ] Called, a_newProbeCycle= %d\n", rn,
2584 a_newProbeCycle);
2585 fflush(debugFD);
2586 }
2587
2588 if (xstat_cm_Results.collectionNumber == AFSCB_XSTATSCOLL_FULL_PERF_INFO) {
2589 index = 0;
2590 } else {
2591 fprintf(stderr, "[ %s ] collection number %d is out of range.\n",
2592 rn, xstat_cm_Results.collectionNumber);
2593 afsmon_Exit(91);
2594 }
2595
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() */
2599
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;
2605 }
2606 }
2607
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])
2612 break;
2613 tmp_cmlist_item = tmp_cmlist_item->next;
2614 }
2615
2616 /* if we could not find one we have an inconsistent list */
2617 if (!tmp_cmlist_item->empty[index]) {
2618 fprintf(stderr,
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);
2622 afsmon_Exit(90);
2623 }
2624
2625 tmp_cmPR = tmp_cmlist_item->cmResults[index];
2626
2627 /* copy hostname and probe number and probe time and probe status.
2628 * if the probe failed return now */
2629
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;
2638 return (0);
2639 }
2640
2641
2642 /* copy connection information */
2643 memcpy(&(tmp_cmPR->connP->skt), &(xstat_cm_Results.connP->skt),
2644 sizeof(struct sockaddr_in));
2645
2646 /**** NEED TO COPY rx_connection INFORMATION HERE ******/
2647
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;
2651
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));
2659
2660
2661 /* we have a valid results structure so mark the list item used */
2662 tmp_cmlist_item->empty[index] = 0;
2663
2664 /* print the stored info - to make sure we copied it right */
2665 /* Print_cm_FullPerfInfo(tmp_cmPR); */
2666 /* Print the cm circular buffer */
2667 Print_CM_CB();
2668 return (0);
2669 } /* save_CM_results_inCB */
2670
2671
2672
2673 /*-----------------------------------------------------------------------
2674 * cm_Results_ltoa()
2675 *
2676 * Description:
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().
2684 *
2685 * Returns:
2686 * Always returns 0.
2687 *----------------------------------------------------------------------*/
2688
2689 int
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 */
2693
2694 static char rn[] = "cm_Results_ltoa"; /* routine name */
2695 struct afs_stats_CMFullPerf *fullP; /* ptr to complete CM stats */
2696 afs_int32 *srcbuf;
2697 afs_int32 *tmpbuf;
2698 int i, j;
2699 int idx;
2700 afs_int32 numLongs;
2701
2702 if (afsmon_debug) {
2703 fprintf(debugFD, "[ %s ] Called, a_cmData= %p, a_cmResults= %p\n", rn,
2704 a_cmData, a_cmResults);
2705 fflush(debugFD);
2706 }
2707
2708
2709 fullP = (struct afs_stats_CMFullPerf *)
2710 (a_cmResults->data.AFSCB_CollData_val);
2711
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
2719 */
2720
2721 /* copy overall performance statistics */
2722 srcbuf = (afs_int32 *) & (fullP->perf);
2723 idx = 0;
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++) {
2726 if (i == 19) {
2727 srcbuf++;
2728 continue; /* skip ProtServerAddr */
2729 }
2730 sprintf(a_cmData->data[idx], "%d", *srcbuf);
2731 idx++;
2732 srcbuf++;
2733 }
2734
2735 /*printf("Ending index value = %d\n",idx-1); */
2736
2737 /* server up/down statistics */
2738 /* copy file server up/down stats */
2739 srcbuf = (afs_int32 *) (fullP->perf.fs_UpDown);
2740 numLongs =
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);
2744 idx++;
2745 srcbuf++;
2746 }
2747
2748 /*printf("Ending index value = %d\n",idx-1); */
2749
2750 /* copy volume location server up/down stats */
2751 srcbuf = (afs_int32 *) (fullP->perf.vl_UpDown);
2752 numLongs =
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);
2756 idx++;
2757 srcbuf++;
2758 }
2759
2760 /*printf("Ending index value = %d\n",idx-1); */
2761
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 */
2766 idx++;
2767 srcbuf++;
2768 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* numSuccesses */
2769 idx++;
2770 srcbuf++;
2771 tmpbuf = srcbuf++; /* sum time */
2772 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2773 idx++;
2774 srcbuf++;
2775 tmpbuf = srcbuf++; /* sqr time */
2776 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2777 idx++;
2778 srcbuf++;
2779 tmpbuf = srcbuf++; /* min time */
2780 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2781 idx++;
2782 srcbuf++;
2783 tmpbuf = srcbuf++; /* max time */
2784 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2785 idx++;
2786 srcbuf++;
2787 }
2788
2789 /*printf("Ending index value = %d\n",idx-1); */
2790
2791 /* copy CMs individual FS RPC errors info */
2792
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 */
2796 idx++;
2797 srcbuf++;
2798 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* network */
2799 idx++;
2800 srcbuf++;
2801 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* prot */
2802 idx++;
2803 srcbuf++;
2804 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* vol */
2805 idx++;
2806 srcbuf++;
2807 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* busies */
2808 idx++;
2809 srcbuf++;
2810 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* other */
2811 idx++;
2812 srcbuf++;
2813 }
2814
2815 /*printf("Ending index value = %d\n",idx-1); */
2816
2817 /* copy CMs individual RPC transfers info */
2818
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 */
2822 idx++;
2823 srcbuf++;
2824 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* numSuccesses */
2825 idx++;
2826 srcbuf++;
2827 tmpbuf = srcbuf++; /* sum time */
2828 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2829 idx++;
2830 srcbuf++;
2831 tmpbuf = srcbuf++; /* sqr time */
2832 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2833 idx++;
2834 srcbuf++;
2835 tmpbuf = srcbuf++; /* min time */
2836 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2837 idx++;
2838 srcbuf++;
2839 tmpbuf = srcbuf++; /* max time */
2840 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2841 idx++;
2842 srcbuf++;
2843 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* sum bytes */
2844 idx++;
2845 srcbuf++;
2846 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* min bytes */
2847 idx++;
2848 srcbuf++;
2849 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* max bytes */
2850 idx++;
2851 srcbuf++;
2852 for (j = 0; j < AFS_STATS_NUM_XFER_BUCKETS; j++) {
2853 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* bucket[j] */
2854 idx++;
2855 srcbuf++;
2856 }
2857 }
2858
2859 /*printf("Ending index value = %d\n",idx-1); */
2860
2861 /* copy CM operations timings */
2862
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 */
2866 idx++;
2867 srcbuf++;
2868 sprintf(a_cmData->data[idx], "%d", *srcbuf); /* numSuccesses */
2869 idx++;
2870 srcbuf++;
2871 tmpbuf = srcbuf++; /* sum time */
2872 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2873 idx++;
2874 srcbuf++;
2875 tmpbuf = srcbuf++; /* sqr time */
2876 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2877 idx++;
2878 srcbuf++;
2879 tmpbuf = srcbuf++; /* min time */
2880 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2881 idx++;
2882 srcbuf++;
2883 tmpbuf = srcbuf++; /* max time */
2884 sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2885 idx++;
2886 srcbuf++;
2887 }
2888
2889 /*printf("Ending index value = %d\n",idx-1); */
2890
2891 /* copy authentication info */
2892
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);
2897 idx++;
2898 srcbuf++;
2899 }
2900
2901 /*printf("Ending index value = %d\n",idx-1); */
2902
2903 /* copy CM [un]replicated access info */
2904
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);
2909 idx++;
2910 srcbuf++;
2911 }
2912
2913 /*printf("Ending index value = %d\n",idx-1); */
2914 return (0);
2915
2916 } /* cm_Results_ltoa */
2917
2918
2919 /*-----------------------------------------------------------------------
2920 * Function: check_cm_thresholds()
2921 *
2922 * Description:
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
2931 * curr_[fs/cm]Data.
2932 *
2933 * Returns:
2934 * 0
2935 *----------------------------------------------------------------------*/
2936
2937 int
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 */
2941
2942 static char rn[] = "check_cm_thresholds";
2943 struct Threshold *threshP;
2944 double tValue; /* threshold value */
2945 double pValue; /* probe value */
2946 int i;
2947 int idx;
2948 int count; /* number of thresholds exceeded */
2949
2950 if (afsmon_debug) {
2951 fprintf(debugFD, "[ %s ] Called, a_hostEntry= %p, a_Data= %p\n", rn,
2952 a_hostEntry, a_Data);
2953 fflush(debugFD);
2954 }
2955
2956 if (a_hostEntry->numThresh == 0) {
2957 /* store in ovf count ?? */
2958 return (0);
2959 }
2960
2961 count = 0;
2962 threshP = a_hostEntry->thresh;
2963 for (i = 0; i < a_hostEntry->numThresh; i++) {
2964 if (threshP->itemName[0] == '\0') {
2965 threshP++;
2966 continue;
2967 }
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) {
2972
2973 if (afsmon_debug) {
2974 fprintf(debugFD,
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]);
2978 fflush(debugFD);
2979 }
2980
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! */
2984
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') {
2989 if (afsmon_debug) {
2990 fprintf(debugFD, "[ %s ] Calling ovf handler %s\n",
2991 rn, threshP->handler);
2992 fflush(debugFD);
2993 }
2994 execute_thresh_handler(threshP->handler, a_Data->hostName,
2995 CM, threshP->itemName,
2996 threshP->threshVal,
2997 a_Data->data[idx]);
2998 }
2999 }
3000
3001 count++;
3002 } else
3003 /* in case threshold was previously crossed, blank it out */
3004 a_Data->threshOvf[idx] = 0;
3005 threshP++;
3006 }
3007 /* store the overflow count */
3008 a_Data->ovfCount = count;
3009
3010 return (0);
3011 } /* check_cm_thresholds */
3012
3013
3014 /*-----------------------------------------------------------------------
3015 * save_CM_data_forDisplay()
3016 *
3017 * Description:
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
3025 *
3026 * Returns:
3027 * Success: 0
3028 * Failure: Exits afsmonitor.
3029 *
3030 *----------------------------------------------------------------------*/
3031
3032 int
3033 save_CM_data_forDisplay(struct xstat_cm_ProbeResults *a_cmResults)
3034 { /* save_CM_data_forDisplay */
3035
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 */
3043 int numBytes;
3044 int done;
3045 int code;
3046 int okay;
3047 int i;
3048
3049 if (afsmon_debug) {
3050 fprintf(debugFD, "[ %s ] Called, a_cmResults= %p\n", rn, a_cmResults);
3051 fflush(debugFD);
3052 }
3053
3054 /* store results in the display array */
3055
3056 okay = 0;
3057 curr_cmDataP = curr_cmData;
3058 for (i = 0; i < numCM; i++) {
3059 if ((strcasecmp(curr_cmDataP->hostName, a_cmResults->connP->hostName))
3060 == 0) {
3061 okay = 1;
3062 break;
3063 }
3064 curr_cmDataP++;
3065 }
3066
3067 if (!okay) {
3068 fprintf(stderr,
3069 "[ %s ] Could not insert CM probe results for host %s in cm display array\n",
3070 rn, a_cmResults->connP->hostName);
3071 afsmon_Exit(95);
3072 }
3073
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. */
3077
3078
3079 if (a_cmResults->probeOK) { /* 1 => notOK the xstat results */
3080 curr_cmDataP->probeOK = 0;
3081
3082 /* print the probe status */
3083 if (afsmon_debug) {
3084 fprintf(debugFD, "\n\t\t ----- cm display data ------\n");
3085 fprintf(debugFD, "HostName = %s PROBE FAILED \n",
3086 curr_cmDataP->hostName);
3087 fflush(debugFD);
3088 }
3089
3090 } else { /* probe succeeded, update display data structures */
3091 curr_cmDataP->probeOK = 1;
3092
3093
3094 /* covert longs to strings and place them in curr_cmDataP */
3095 cm_Results_ltoa(curr_cmDataP, a_cmResults);
3096
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 */
3100
3101 /* locate the hostEntry for this host */
3102 done = 0;
3103 curr_host = CMnameList;
3104 for (i = 0; i < numCM; i++) {
3105 if (strcasecmp(curr_host->hostName, a_cmResults->connP->hostName)
3106 == 0) {
3107 done = 1;
3108 break;
3109 }
3110 curr_host = curr_host->next;
3111 }
3112 if (!done)
3113 afsmon_Exit(100);
3114
3115 code = check_cm_thresholds(curr_host, curr_cmDataP);
3116 if (code) {
3117 fprintf(stderr, "[ %s ] Error in checking thresholds\n", rn);
3118 afsmon_Exit(105);
3119 }
3120
3121 /* print the info we just saved */
3122 if (afsmon_debug) {
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++) {
3126 switch (i) {
3127 case 0:
3128 fprintf(debugFD, "\t -- Overall Perf Info --\n");
3129 break;
3130 case 39:
3131 fprintf(debugFD,
3132 "\t -- File Server up/down stats - same cell --\n");
3133 break;
3134 case 64:
3135 fprintf(debugFD,
3136 "\t -- File Server up/down stats - diff cell --\n");
3137 break;
3138 case 89:
3139 fprintf(debugFD,
3140 "\t -- VL server up/down stats - same cell --\n");
3141 break;
3142 case 114:
3143 fprintf(debugFD,
3144 "\t -- VL server up/down stats - diff cell --\n");
3145 break;
3146 case 139:
3147 fprintf(debugFD, "\t -- FS Operation Timings --\n");
3148 break;
3149 case 279:
3150 fprintf(debugFD, "\t -- FS Error Info --\n");
3151 break;
3152 case 447:
3153 fprintf(debugFD, "\t -- FS Transfer Timings --\n");
3154 break;
3155 case 475:
3156 fprintf(debugFD, "\t -- CM Operations Timings --\n");
3157 break;
3158 case 510:
3159 fprintf(debugFD, "\t -- Authentication Info --\n");
3160 break;
3161 case 522:
3162 fprintf(debugFD, "\t -- Access Info --\n");
3163 break;
3164 default:
3165 break;
3166 }
3167
3168 fprintf(debugFD, "%20s %30s %s\n", curr_cmDataP->data[i],
3169 cm_varNames[i],
3170 curr_cmDataP->threshOvf[i] ? "(ovf)" : "");
3171 }
3172 fprintf(debugFD, "\t\t--------------------------------\n\n");
3173 }
3174
3175 } /* if the probe succeeded, update the display data structures */
3176
3177 /* if we have received a reply from all the hosts for this probe cycle,
3178 * it is time to display the data */
3179
3180 results_Received++;
3181 if (results_Received == numCM * num_cm_collections) {
3182 results_Received = 0;
3183
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);
3187 afsmon_Exit(110);
3188 } else
3189 afsmon_cm_prev_probeNum++;
3190
3191
3192 /* backup the display data of the probe cycle that just completed -
3193 * ie., store curr_cmData in prev_cmData */
3194
3195 memcpy((char *)prev_cmData, (char *)curr_cmData,
3196 (numCM * sizeof(struct cm_Display_Data)));
3197
3198
3199 /* initialize curr_cmData but retain the threshold flag information.
3200 * The previous state of threshold flags is used in check_cm_thresholds() */
3201
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);
3208 curr_cmDataP++;
3209 }
3210
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 */
3214
3215 prev_cmDataP = prev_cmData;
3216 num_cm_alerts = 0;
3217 numHosts_oncm_alerts = 0;
3218 for (i = 0; i < numCM; i++) {
3219 if (!prev_cmDataP->probeOK) { /* if probe failed */
3220 num_cm_alerts++;
3221 numHosts_oncm_alerts++;
3222 } else if (prev_cmDataP->ovfCount) { /* overflows ?? */
3223 num_cm_alerts += prev_cmDataP->ovfCount;
3224 numHosts_oncm_alerts++;
3225 }
3226 prev_cmDataP++;
3227 }
3228 if (afsmon_debug)
3229 fprintf(debugFD, "Number of CM alerts = %d (on %d hosts)\n",
3230 num_cm_alerts, numHosts_oncm_alerts);
3231
3232
3233 /* flag that the data is now ready to be displayed */
3234 cm_Data_Available = 1;
3235
3236 /* update the Overview frame (only CM info) */
3237 ovw_refresh(ovw_currPage, OVW_UPDATE_CM);
3238
3239 /* update the Cache Managers frame */
3240 cm_refresh(cm_currPage, cm_curr_LCol);
3241
3242 }
3243
3244
3245 return (0);
3246 } /* save_CM_data_forDisplay */
3247
3248
3249
3250 /*-----------------------------------------------------------------------
3251 * afsmon_CM_Handler()
3252 *
3253 * Description:
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.
3257 *
3258 * Returns:
3259 * Success: 0
3260 * Failure: Exits afsmonitor.
3261 *----------------------------------------------------------------------*/
3262
3263 int
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 ? */
3269
3270 if (afsmon_debug) {
3271 fprintf(debugFD,
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");
3275 fflush(debugFD);
3276 }
3277
3278
3279 /* print the probe results to output file */
3280 if (afsmon_output) {
3281 code = afsmon_cmOutput(output_filename, afsmon_detOutput);
3282 if (code) {
3283 fprintf(stderr,
3284 "[ %s ] output to file %s returned error code=%d\n", rn,
3285 output_filename, code);
3286 }
3287 }
3288
3289 /* Update current probe number and circular buffer index. if current
3290 * probenum changed make sure it is only by 1 */
3291
3292 newProbeCycle = 0;
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++;
3296 newProbeCycle = 1;
3297 if (num_bufSlots)
3298 afsmon_cm_curr_CBindex =
3299 (afsmon_cm_curr_probeNum - 1) % num_bufSlots;
3300 } else {
3301 fprintf(stderr, "[ %s ] probe number %d-1 missed\n", rn,
3302 xstat_cm_Results.probeNum);
3303 afsmon_Exit(115);
3304 }
3305 }
3306
3307 /* save the results of this probe in the CM buffer */
3308 if (num_bufSlots)
3309 save_CM_results_inCB(newProbeCycle);
3310
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 */
3315
3316 save_CM_data_forDisplay(&xstat_cm_Results);
3317
3318 return (0);
3319 }
3320
3321 /*-----------------------------------------------------------------------
3322 * init_fs_buffers()
3323 *
3324 * Description:
3325 * Allocate and Initialize circular buffers for file servers.
3326 *
3327 * Returns:
3328 * Success: 0
3329 * Failure to allocate memory: exits afsmonitor.
3330 *----------------------------------------------------------------------*/
3331
3332 int
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 */
3339 int i, j;
3340 int bufslot;
3341 int numfs;
3342
3343
3344 if (afsmon_debug) {
3345 fprintf(debugFD, "[ %s ] Called\n", rn);
3346 fflush(debugFD);
3347 }
3348
3349 /* allocate memory for the circular buffer of pointers */
3350
3351 afsmon_fs_ResultsCB = (struct afsmon_fs_Results_CBuffer *)
3352 malloc(sizeof(struct afsmon_fs_Results_CBuffer) * num_bufSlots);
3353
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;
3358 }
3359
3360 /* create a list of numFS items to store fs probe results for
3361 * each slot in CB */
3362
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 */
3366 while (numfs--) {
3367
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 */
3371
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)
3376 return (-1);
3377
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));
3382 if (!new_fsPR) {
3383 free(new_fslist_item);
3384 return (-1);
3385 }
3386
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);
3391 free(new_fsPR);
3392 return (-1);
3393 }
3394
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);
3401 free(new_fsPR);
3402 return (-1);
3403 }
3404 new_fslist_item->fsResults[i] = new_fsPR;
3405 new_fslist_item->empty[i] = 1;
3406 }
3407
3408 /* initialize this list entry */
3409 new_fslist_item->next = (struct afsmon_fs_Results_list *)0;
3410
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;
3415 else {
3416 tmp_fslist_item = afsmon_fs_ResultsCB[bufslot].list;
3417 j = 0;
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)
3422 break;
3423 tmp_fslist_item = tmp_fslist_item->next;
3424 if (++j > numFS) {
3425 /* something goofed. exit */
3426 fprintf(stderr, "[ %s ] list creation error\n",
3427 rn);
3428 return (-1);
3429 }
3430 }
3431 tmp_fslist_item->next = new_fslist_item;
3432 }
3433
3434 } /* while servers */
3435 } /* for each buffer slot */
3436 } /* if we have file servers to monitor */
3437 return (0);
3438 }
3439
3440 /*-----------------------------------------------------------------------
3441 * init_cm_buffers()
3442 *
3443 * Description:
3444 * Allocate and Initialize circular buffers for cache managers.
3445 *
3446 * Returns:
3447 * Success: 0
3448 * Failure to allocate memory: exits afsmonitor.
3449 *----------------------------------------------------------------------*/
3450
3451 int
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 */
3458 int i, j;
3459 int bufslot;
3460 int numcm;
3461
3462 if (afsmon_debug) {
3463 fprintf(debugFD, "[ %s ] Called\n", rn);
3464 fflush(debugFD);
3465 }
3466
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);
3470
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;
3475 }
3476
3477 /* create a list of numCM items to store fs probe results for
3478 * each slot in CB */
3479
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 */
3483 while (numcm--) {
3484
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 */
3488
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)
3493 return (-1);
3494
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));
3499 if (!new_cmPR) {
3500 free(new_cmlist_item);
3501 return (-1);
3502 }
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);
3507 free(new_cmPR);
3508 return (-1);
3509 }
3510
3511 /* >>> need to allocate rx connection info structure here <<< */
3512
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);
3519 free(new_cmPR);
3520 return (-1);
3521 }
3522
3523 new_cmlist_item->cmResults[i] = new_cmPR;
3524 new_cmlist_item->empty[i] = 1;
3525 }
3526
3527 /* initialize this list entry */
3528 new_cmlist_item->next = (struct afsmon_cm_Results_list *)0;
3529
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;
3534 else {
3535 tmp_cmlist_item = afsmon_cm_ResultsCB[bufslot].list;
3536 j = 0;
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)
3541 break;
3542 tmp_cmlist_item = tmp_cmlist_item->next;
3543 if (++j > numCM) {
3544 /* something goofed. exit */
3545 fprintf(stderr, "[ %s ] list creation error\n",
3546 rn);
3547 return (-1);
3548 }
3549 }
3550 tmp_cmlist_item->next = new_cmlist_item;
3551 }
3552
3553 } /* while servers */
3554 } /* for each buffer slot */
3555 }
3556 /* if we have file servers to monitor */
3557 /* print the CB to make sure it is right */
3558 Print_CM_CB();
3559
3560 return (0);
3561 } /* init_cm_buffers() */
3562
3563
3564 /*-------------------------------------------------------------------------
3565 * init_print_buffers()
3566 *
3567 * Description:
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.
3571 *
3572 * Returns:
3573 * Success: 0
3574 * Failure: < 0
3575 *------------------------------------------------------------------------*/
3576
3577 int
3578 init_print_buffers(void)
3579 { /* init_print_buffers */
3580
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;
3588 int i;
3589 int numBytes;
3590
3591 if (afsmon_debug) {
3592 fprintf(debugFD, "[ %s ] Called\n", rn);
3593 fflush(debugFD);
3594 }
3595
3596 /* allocate numFS blocks of the FS print structure. */
3597
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 */
3603
3604 if (numFS) {
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);
3609 return (-1);
3610 }
3611 memset(curr_fsData, 0, numBytes);
3612
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);
3617 return (-5);
3618 }
3619 memset(prev_fsData, 0, numBytes);
3620
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,
3627 HOST_NAME_LEN);
3628 strncpy(tmp_fsData2->hostName, tmp_fsNames->hostName,
3629 HOST_NAME_LEN);
3630 tmp_fsData1++;
3631 tmp_fsData2++;
3632 tmp_fsNames = tmp_fsNames->next;;
3633 }
3634
3635 }
3636
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 */
3640 if (numCM) {
3641 numBytes = numCM * sizeof(struct cm_Display_Data);
3642
3643 curr_cmData = malloc(numBytes);
3644 if (curr_cmData == (struct cm_Display_Data *)0) {
3645 fprintf(stderr, "[ %s ] Memory allocation failure\n", rn);
3646 return (-10);
3647 }
3648 memset(curr_cmData, 0, numBytes);
3649
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);
3654 return (-15);
3655 }
3656 memset(prev_cmData, 0, numBytes);
3657
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,
3664 HOST_NAME_LEN);
3665 strncpy(tmp_cmData2->hostName, tmp_cmNames->hostName,
3666 HOST_NAME_LEN);
3667 tmp_cmData1++;
3668 tmp_cmData2++;
3669 tmp_cmNames = tmp_cmNames->next;;
3670 }
3671
3672 }
3673 /* if cache managers to monitor */
3674 return (0);
3675
3676 } /* init_print_buffers */
3677
3678 /*-----------------------------------------------------------------------
3679 * quit_signal()
3680 *
3681 * Description:
3682 * Trap the interrupt signal. This function is useful only until
3683 * gtx is initialized.
3684 *----------------------------------------------------------------------*/
3685
3686 void
3687 quit_signal(int sig)
3688 { /* quit_signal */
3689 fprintf(stderr, "Received signal %d \n", sig);
3690 afsmon_Exit(120);
3691 } /* quit_signal */
3692
3693
3694
3695 /*-----------------------------------------------------------------------
3696 * afsmon_execute()
3697 *
3698 * Description:
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.
3703 *
3704 * Returns:
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.
3708 *
3709 *----------------------------------------------------------------------*/
3710
3711 int
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 */
3728 int i;
3729 short index;
3730
3731 if (afsmon_debug) {
3732 fprintf(debugFD, "[ %s ] Called\n", rn);
3733 fflush(debugFD);
3734 }
3735
3736
3737 /* process file server entries */
3738 if (numFS) {
3739 afs_int32 collIDs[MAX_NUM_FS_COLLECTIONS];
3740
3741 /* Allocate an array of sockets for each fileserver we monitor */
3742
3743 FSsktbytes = numFS * sizeof(struct sockaddr_in);
3744 FSSktArray = malloc(FSsktbytes);
3745 if (FSSktArray == (struct sockaddr_in *)0) {
3746 fprintf(stderr,
3747 "[ %s ] cannot malloc %d sockaddr_ins for fileservers\n",
3748 rn, numFS);
3749 return (-1);
3750 }
3751
3752 memset(FSSktArray, 0, FSsktbytes);
3753
3754 /* Fill in the socket information for each fileserve */
3755
3756 curr_skt = FSSktArray;
3757 curr_FS = FSnameList; /* FS name list header */
3758 while (curr_FS) {
3759 strncpy(fullhostname, curr_FS->hostName, sizeof(fullhostname));
3760 he = GetHostByName(fullhostname);
3761 if (he == NULL) {
3762 fprintf(stderr, "[ %s ] Cannot get host info for %s\n", rn,
3763 fullhostname);
3764 return (-1);
3765 }
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);
3772 #endif
3773
3774 /* get the next dude */
3775 curr_skt++;
3776 curr_FS = curr_FS->next;
3777 }
3778
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;
3785 break;
3786 }
3787 }
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;
3792 break;
3793 }
3794 }
3795
3796 FSinitFlags = 0;
3797 if (afsmon_onceOnly) /* option not provided at this time */
3798 FSinitFlags |= XSTAT_FS_INITFLAG_ONE_SHOT;
3799
3800 if (afsmon_debug) {
3801 fprintf(debugFD, "[ %s ] Calling xstat_fs_Init \n", rn);
3802 fflush(debugFD);
3803 }
3804
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 */
3812
3813 if (code) {
3814 fprintf(stderr, "[ %s ] xstat_fs_init returned error\n", rn);
3815 afsmon_Exit(125);
3816 }
3817
3818 }
3819
3820
3821 /* end of process fileserver entries */
3822 /* process cache manager entries */
3823 if (numCM) {
3824 afs_int32 collIDs[MAX_NUM_CM_COLLECTIONS];
3825
3826 /* Allocate an array of sockets for each cache manager we monitor */
3827
3828 CMsktbytes = numCM * sizeof(struct sockaddr_in);
3829 CMSktArray = malloc(CMsktbytes);
3830 if (CMSktArray == (struct sockaddr_in *)0) {
3831 fprintf(stderr,
3832 "[ %s ] cannot malloc %d sockaddr_ins for CM entries\n",
3833 rn, numCM);
3834 return (-1);
3835 }
3836
3837 memset(CMSktArray, 0, CMsktbytes);
3838
3839 /* Fill in the socket information for each CM */
3840
3841 curr_skt = CMSktArray;
3842 curr_CM = CMnameList; /* CM name list header */
3843 while (curr_CM) {
3844 strncpy(fullhostname, curr_CM->hostName, sizeof(fullhostname));
3845 he = GetHostByName(fullhostname);
3846 if (he == NULL) {
3847 fprintf(stderr, "[ %s ] Cannot get host info for %s\n", rn,
3848 fullhostname);
3849 return (-1);
3850 }
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);
3857 #endif
3858
3859 /* get the next dude */
3860 curr_skt++;
3861 curr_CM = curr_CM->next;
3862 }
3863
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;
3868
3869 CMinitFlags = 0;
3870 if (afsmon_onceOnly) /* once only ? */
3871 CMinitFlags |= XSTAT_CM_INITFLAG_ONE_SHOT;
3872
3873 if (afsmon_debug) {
3874 fprintf(debugFD, "[ %s ] Calling xstat_cm_Init \n", rn);
3875 fflush(debugFD);
3876 }
3877
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 */
3885
3886 if (code) {
3887 fprintf(stderr, "[ %s ] xstat_cm_init returned error\n", rn);
3888 afsmon_Exit(130);
3889 }
3890 }
3891
3892
3893
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);
3899 if (code) {
3900 if (afsmon_debug) {
3901 fprintf(debugFD, "LWP_WaitProcess() returned error %d\n",
3902 code);
3903 fflush(debugFD);
3904 }
3905 afsmon_Exit(135);
3906 }
3907 }
3908
3909 /* start the gtx input server */
3910 code = (intptr_t)gtx_InputServer(afsmon_win);
3911 if (code) {
3912 fprintf(stderr, "[ %s ] Failed to start input server \n", rn);
3913 afsmon_Exit(140);
3914 }
3915
3916 /* This part of the code is reached only if the input server is not started
3917 * for debugging purposes */
3918
3919 /* sleep forever */
3920 tv.tv_sec = 24 * 60;
3921 tv.tv_usec = 0;
3922 fprintf(stderr, "[ %s ] going to sleep ...\n", rn);
3923 while (1) {
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 */
3929 if (code) {
3930 fprintf(stderr,
3931 "[ %s ] IOMGR_Select() returned non-zero value %d\n", rn,
3932 code);
3933 afsmon_Exit(145);
3934 }
3935 } /* while sleep */
3936 }
3937
3938
3939 /*-----------------------------------------------------------------------
3940 * afsmonInit()
3941 *
3942 * Description:
3943 * Afsmonitor initialization routine.
3944 * - processes command line parameters
3945 * - call functions to:
3946 * - process config file
3947 * - initialize circular buffers and display buffers
3948 * - initialize gtx
3949 * - execute afsmonitor
3950 * - initialize the display maps [fs/cm]_Display_map[].
3951 *
3952 * Returns:
3953 * Success: Does not return from the call to afsmon_execute().
3954 * Failure: Exits afsmonitor.
3955 *----------------------------------------------------------------------*/
3956
3957 int
3958 afsmonInit(struct cmd_syndesc *as, void *arock)
3959 { /* afsmonInit() */
3960
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 */
3966 int code;
3967 int i;
3968
3969 if (afsmon_debug) {
3970 fprintf(debugFD, "[ %s ] Called, as= %p\n", rn, as);
3971 fflush(debugFD);
3972 }
3973
3974 /* Open the debug file if -debug option is specified */
3975 if (as->parms[P_DEBUG].items != 0) {
3976 afsmon_debug = 1;
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",
3981 rn, "log");
3982 afsmon_debug = 0;
3983 afsmon_Exit(150);
3984 }
3985 }
3986
3987 if (afsmon_debug) {
3988 fprintf(debugFD, "[ %s ] Called\n", rn);
3989 }
3990
3991
3992 /* use curses always until we support other packages */
3993 #ifdef notdef
3994 wpkg_to_use = atoi(as->parms[P_PACKAGE].items->data);
3995
3996 switch (wpkg_to_use) {
3997 case GATOR_WIN_CURSES:
3998 fprintf(stderr, "curses\n");
3999 break;
4000 case GATOR_WIN_DUMB:
4001 fprintf(stderr, "dumb terminal\n");
4002 break;
4003 case GATOR_WIN_X11:
4004 fprintf(stderr, "X11\n");
4005 break;
4006 default:
4007 fprintf(stderr, "Illegal graphics package: %d\n", wpkg_to_use);
4008 afsmon_Exit(155);
4009 } /*end switch (wpkg_to_use) */
4010 #endif
4011
4012 wpkg_to_use = GATOR_WIN_CURSES;
4013
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! */
4017
4018 afsmon_probefreq = 0;
4019 if (as->parms[P_FREQUENCY].items != 0)
4020 afsmon_probefreq = atoi(as->parms[P_FREQUENCY].items->data);
4021 else
4022 afsmon_probefreq = DEFAULT_FREQUENCY;
4023
4024 if (afsmon_probefreq <= 0 || afsmon_probefreq > 24 * 60 * 60) {
4025 afsmon_probefreq = DEFAULT_FREQUENCY;
4026 if (afsmon_debug) {
4027 fprintf(debugFD,
4028 "[ %s ] Invalid probe frequency %s specified, resetting to default value %d seconds\n",
4029 rn, as->parms[P_FREQUENCY].items->data, afsmon_probefreq);
4030 fflush(debugFD);
4031 }
4032 fprintf(stderr,
4033 "Invalid probe frequency %s specified, resetting to default value %d seconds\n",
4034 as->parms[P_FREQUENCY].items->data, afsmon_probefreq);
4035 sleep(3);
4036 }
4037
4038
4039 /* make sure output file is writable, else complain now */
4040 /* we will open and close it as needed after probes */
4041
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",
4048 output_filename);
4049 if (afsmon_debug) {
4050 fprintf(debugFD, "[ %s ] Failed to open output file %s \n",
4051 rn, output_filename);
4052 afsmon_Exit(160);
4053 }
4054 }
4055 if (afsmon_debug) {
4056 fprintf(debugFD, "[ %s ] output file is %s\n", rn,
4057 output_filename);
4058 }
4059 fclose(outputFD);
4060 }
4061
4062 /* detailed statistics to storage file */
4063 if (as->parms[P_DETAILED].items != 0) {
4064 if (as->parms[P_OUTPUT].items == 0) {
4065 fprintf(stderr,
4066 "-detailed switch can be used only with -output\n");
4067 afsmon_Exit(165);
4068 }
4069 afsmon_detOutput = 1;
4070 }
4071
4072 /* Initialize host list headers */
4073 FSnameList = (struct afsmon_hostEntry *)0;
4074 CMnameList = (struct afsmon_hostEntry *)0;
4075
4076 /* The -config option is mutually exclusive with the -fshosts,-cmhosts
4077 * options */
4078
4079 if (as->parms[P_CONFIG].items) {
4080 if (as->parms[P_FSHOSTS].items || as->parms[P_CMHOSTS].items) {
4081 fprintf(stderr,
4082 "Cannot use -config option with -fshosts or -cmhosts\n");
4083 afsmon_Exit(170);
4084 }
4085 } else {
4086 if (!as->parms[P_FSHOSTS].items && !as->parms[P_CMHOSTS].items) {
4087 fprintf(stderr,
4088 "Must specify either -config or (-fshosts and/or -cmhosts) options \n");
4089 afsmon_Exit(175);
4090 }
4091 }
4092
4093
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 */
4097
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);
4103 if (code) {
4104 fprintf(stderr, "Could not parse %s\n", hostPtr->data);
4105 afsmon_Exit(180);
4106 }
4107
4108 hostPtr = hostPtr->next;
4109 }
4110 }
4111
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);
4118 if (code) {
4119 fprintf(stderr, "Could not parse %s\n", hostPtr->data);
4120 afsmon_Exit(185);
4121 }
4122
4123 hostPtr = hostPtr->next;
4124 }
4125 }
4126
4127 /* number of slots in circular buffers */
4128 if (as->parms[P_BUFFERS].items)
4129 num_bufSlots = atoi(as->parms[P_BUFFERS].items->data);
4130 else
4131 num_bufSlots = DEFAULT_BUFSLOTS;
4132
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;
4139
4140
4141 /* Process the configuration file if given. This initializes among other
4142 * things, the list of FS & CM names in FSnameList and CMnameList */
4143
4144 if (as->parms[P_CONFIG].items)
4145 process_config_file(as->parms[P_CONFIG].items->data);
4146
4147 /* print out the FS and CM lists */
4148 print_FS();
4149 print_CM();
4150
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;
4157 }
4158
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;
4165 }
4166
4167
4168
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.");
4174 afsmon_Exit(190);
4175 }
4176
4177
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 */
4180 errMsg[0] = '\0';
4181 errMsg1[0] = '\0';
4182
4183 if (num_bufSlots) {
4184
4185 /* initialize fs and cm circular buffers before initiating probes */
4186 if (numFS) {
4187 code = init_fs_buffers();
4188 if (code) {
4189 fprintf(stderr, "[ %s ] init_fs_buffers returned %d\n", rn,
4190 code);
4191 afsmon_Exit(195);
4192 }
4193 }
4194
4195 if (numCM) {
4196 code = init_cm_buffers();
4197 if (code) {
4198 fprintf(stderr, "[ %s ] init_cm_buffers returned %d\n", rn,
4199 code);
4200 afsmon_Exit(200);
4201 }
4202 }
4203 }
4204
4205 /* allocate and initialize buffers for holding fs & cm results in ascii
4206 * format suitable for updating the screen */
4207 code = init_print_buffers();
4208 if (code) {
4209 fprintf(stderr, "[ %s ] init_print_buffers returned %d\n", rn, code);
4210 afsmon_Exit(205);
4211 }
4212
4213 /* perform gtx initializations */
4214 code = gtx_initialize();
4215 if (code) {
4216 fprintf(stderr, "[ %s ] gtx_initialize returned %d\n", rn, code);
4217 afsmon_Exit(210);
4218 }
4219
4220 /* start xstat probes */
4221 afsmon_execute();
4222
4223 return (0); /* will not return from the call to afsmon_execute() */
4224
4225 } /* afsmonInit() */
4226
4227
4228 /*-----------------------------------------------------------------------
4229 * Function: main()
4230 ------------------------------------------------------------------------*/
4231
4232 #include "AFS_component_version_number.c"
4233
4234 int
4235 main(int argc, char **argv)
4236 { /* main() */
4237 afs_int32 code; /*Return code */
4238 struct cmd_syndesc *ts; /*Ptr to cmd line syntax descriptor */
4239
4240 #ifdef AFS_AIX32_ENV
4241 /*
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.
4246 */
4247 struct sigaction nsa;
4248
4249 sigemptyset(&nsa.sa_mask);
4250 nsa.sa_handler = SIG_DFL;
4251 nsa.sa_flags = SA_FULLDUMP;
4252 sigaction(SIGSEGV, &nsa, NULL);
4253 #endif
4254
4255 /*
4256 * Set up the commands we understand.
4257 */
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");
4266 #ifdef notdef
4267 /* we hope to use this .... eventually! */
4268 cmd_AddParm(ts, "-package", CMD_SINGLE, CMD_REQUIRED,
4269 "Graphics Package to use");
4270 #endif
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");
4279
4280 /*
4281 * Parse command-line switches & execute afsmonitor
4282 */
4283
4284 code = cmd_Dispatch(argc, argv);
4285 if (code)
4286 afsmon_Exit(1);
4287 else
4288 afsmon_Exit(2);
4289
4290 exit(0); /* redundant, but gets rid of warning */
4291 } /*main */