b23da9cc34b2a644f7584aa9c4f9597bd6a7e023
[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 RCSID
22     ("$Header$");
23
24 #include <stdio.h>
25 #include <math.h>
26 #include <string.h>
27 #include <errno.h>
28 #include <cmd.h>
29 #include <signal.h>
30 #undef IN
31 #include <sys/types.h>
32 #include <netinet/in.h>
33 #include <sys/socket.h>
34 #include <netdb.h>
35 #include <ctype.h>
36
37 #include <gtxwindows.h>         /*Generic window package */
38 #include <gtxobjects.h>         /*Object definitions */
39 #include <gtxlightobj.h>        /*Light object interface */
40 #include <gtxcurseswin.h>       /*Curses window package */
41 #include <gtxdumbwin.h>         /*Dumb terminal window package */
42 #include <gtxX11win.h>          /*X11 window package */
43 #include <gtxframe.h>           /*Frame package */
44
45
46
47 #include <afs/xstat_fs.h>
48 #include <afs/xstat_cm.h>
49
50
51 #include "afsmonitor.h"
52
53
54 /* command line parameter indices */
55
56 #define P_CONFIG        0
57 #define P_FREQUENCY     1
58 #define P_OUTPUT        2
59 #define P_DETAILED      3
60 /* #define P_PACKAGE    X */
61 #define P_DEBUG         4
62 #define P_FSHOSTS       5
63 #define P_CMHOSTS       6
64 #define P_BUFFERS       7
65
66
67 int afsmon_debug = 0;           /* debug info to file ? */
68 FILE *debugFD;                  /* debugging file descriptor */
69 static int afsmon_output = 0;   /* output to file ? */
70 static int afsmon_detOutput = 0;        /* detailed output ? */
71 static int afsmon_onceOnly = 0; /* probe once only ? (not implemented) */
72 int afsmon_probefreq;           /* probe frequency */
73 static int wpkg_to_use;         /* graphics package to use */
74 static char output_filename[80];        /* output filename */
75 char errMsg[256];               /* buffers used to print error messages after */
76 char errMsg1[256];              /* gtx is initialized (stderr/stdout gone !) */
77 int num_bufSlots = 0;           /* number of slots in fs & cm circular buffers */
78
79 /* Flags used to process "show" directives in config file */
80 short fs_showFlags[NUM_FS_STAT_ENTRIES];
81 short cm_showFlags[NUM_CM_STAT_ENTRIES];
82
83
84 /* afsmonitor misc definitions */
85
86 #define DEFAULT_FREQUENCY 60    /* default proble frequency in seconds */
87 #define DEFAULT_BUFSLOTS  0     /* default number of buffer slots */
88 #define CFG_STR_LEN     80      /* max length of config file fields */
89 #define FS 1                    /* for misc. use */
90 #define CM 2                    /* for misc. use */
91
92
93 #define NUM_XSTAT_FS_AFS_PERFSTATS_LONGS 66     /* number of fields (longs) in struct afs_PerfStats that we display */
94 #define NUM_AFS_STATS_CMPERF_LONGS 40   /* number of longs in struct afs_stats_CMPerf excluding up/down stats and fields we dont display */
95
96
97 /* variables used for exec'ing user provided threshold handlers */
98 char *fsHandler_argv[20];       /* *argv[] for the handler */
99 char fsHandler_args[20][256];   /* buffer space for arguments */
100 int exec_fsThreshHandler = 0;   /* execute fs threshold handler ? */
101
102
103 /* THRESHOLD STRUCTURE DEFINITIONS */
104
105 /* flag to indicate that threshold entries apply to all hosts. these will
106    be turned off when the first fs or cm host entry is processed */
107 static int global_ThreshFlag = 1;
108 static int global_fsThreshCount = 0;    /* number of global fs thresholds */
109 static int global_cmThreshCount = 0;    /* number of global cm thresholds */
110
111
112
113 /* Linked lists of file server and cache manager host names are made from
114 the entries in the config file. Head pointers to FS and CM server name lists. */
115 static struct afsmon_hostEntry *FSnameList;
116 static struct afsmon_hostEntry *CMnameList;
117
118 /* number of fileservers and cache managers to monitor */
119 int numFS = 0;
120 int numCM = 0;
121
122 /* variables used for processing config file */
123 /* ptr to the hostEntry structure of the last "fs" or "cm" entry processed
124 in the config file */
125 static struct afsmon_hostEntry *last_hostEntry;
126 /* names of the last host processed in the config file */
127 static char last_fsHost[HOST_NAME_LEN];
128 static char last_cmHost[HOST_NAME_LEN];
129 static lastHostType = 0;        /* 0 = no host entries processed
130                                  * 1 = last host was file server
131                                  * 2 = last host was cache manager. */
132
133
134 /* FILE SERVER CIRCULAR BUFFER VARIABLES  */
135
136 struct afsmon_fs_Results_list {
137     struct xstat_fs_ProbeResults *fsResults;    /* ptr to results struct */
138     int empty;                  /* fsResults empty ? */
139     struct afsmon_fs_Results_list *next;
140 };
141
142 struct afsmon_fs_Results_CBuffer {
143     int probeNum;               /* probe number of entries in this slot */
144     struct afsmon_fs_Results_list *list;        /* ptr to list of results */
145 };
146
147 /* buffer for FS probe results */
148 struct afsmon_fs_Results_CBuffer *afsmon_fs_ResultsCB;
149
150 int afsmon_fs_curr_CBindex = 0; /* current fs CB slot */
151
152 /* Probe number variables. The current probe number is incremented 
153 when the first probe from a new probe cycle is received. The prev probe
154 number is incremented when the last probe of the current cycle is
155 received. This difference is because of the purpose for which these
156 counters are used */
157
158 int afsmon_fs_curr_probeNum = 1;        /* current fs probe number */
159 int afsmon_fs_prev_probeNum = 0;        /* previous fs probe number */
160
161
162 /* CACHE MANAGER CIRCULAR BUFFER VARIABLES  */
163
164 struct afsmon_cm_Results_list {
165     struct xstat_cm_ProbeResults *cmResults;    /* ptr to results struct */
166     int empty;                  /* cmResults empty ? */
167     struct afsmon_cm_Results_list *next;
168 };
169
170 struct afsmon_cm_Results_CBuffer {
171     int probeNum;               /* probe number of entries in this slot */
172     struct afsmon_cm_Results_list *list;        /* ptr to list of results */
173 };
174
175 /* buffer for CM probe results */
176 struct afsmon_cm_Results_CBuffer *afsmon_cm_ResultsCB;
177
178 int afsmon_cm_curr_CBindex = 0; /* current cm CB slot */
179
180
181 /* Probe number variables. The current probe number is incremented 
182 when the first probe from a new probe cycle is received. The prev probe
183 number is incremented when the last probe of the current cycle is
184 received. This difference is because of the purpose for which these
185 counters are used */
186
187 int afsmon_cm_curr_probeNum = 1;        /* current cm probe number */
188 int afsmon_cm_prev_probeNum = 0;        /* previous cm probe number */
189
190
191 /* Structures to hold FS & CM results in string format(suitable for display ) */
192
193 /* ptr to array holding the results of FS probes in ascii format */
194         /* for current probe cycle */
195 struct fs_Display_Data *curr_fsData = (struct fs_Display_Data *)0;
196         /* for previous probe cycle */
197 struct fs_Display_Data *prev_fsData = (struct fs_Display_Data *)0;
198
199
200 /* ptr to array holding the results of CM probes in ascii format */
201         /* for current probe cycle */
202 struct cm_Display_Data *curr_cmData = (struct cm_Display_Data *)0;
203         /* for previous probe cycle */
204 struct cm_Display_Data *prev_cmData = (struct cm_Display_Data *)0;
205
206
207 /* EXTERN DEFINITIONS */
208
209 extern struct hostent *hostutil_GetHostByName();
210
211
212
213 /* routines from afsmon-output.c */
214 extern int afsmon_fsOutput();
215 extern int afsmon_cmOutput();
216
217 /* file server and cache manager variable names (from afsmon_labels.h) */
218 extern char *fs_varNames[];
219 extern char *cm_varNames[];
220
221 /* GTX & MISC VARIABLES */
222
223 /* afsmonitor window */
224 extern struct gwin *afsmon_win;
225
226 /* current page number in the overview frame */
227 extern int ovw_currPage;
228
229 /* number of FS alerts and number of hosts on FS alerts */
230 int num_fs_alerts;
231 int numHosts_onfs_alerts;
232
233 /* number of CM alerts and number of hosts on FS alerts */
234 int num_cm_alerts;
235 int numHosts_oncm_alerts;
236
237 /* flag to indicate that atleast one probe cycle has completed and 
238 data is available for updating the display */
239 extern fs_Data_Available;
240 extern cm_Data_Available;
241
242 extern int gtx_initialized;     /* gtx initialized ? */
243
244 /* This array contains the indices of the file server data items that
245 are to be displayed on the File Servers screen. For example, suppose the
246 user wishes to display only the vcache statistics then the following array
247 will contain indices 2 to 14 corresponding to the position of the
248 vcache data items in the fs_varNames[] array. If the config file contains
249 no "show fs .." directives, it will contain the indices of all the 
250 items in the fs_varNames[] array */
251
252 short fs_Display_map[XSTAT_FS_FULLPERF_RESULTS_LEN];
253 int fs_DisplayItems_count = 0;  /* number of items to display */
254 int fs_showDefault = 1;         /* show all of FS data ? */
255
256
257 /* same use as above for Cache Managers  */
258 short cm_Display_map[XSTAT_CM_FULLPERF_RESULTS_LEN];
259 int cm_DisplayItems_count = 0;  /* number of items to display */
260 int cm_showDefault = 1;         /* show all of CM data ? */
261
262 extern int fs_currPage;         /* current page number in the File Servers frame */
263 extern int fs_curr_LCol;        /* current leftmost column on display on FS frame */
264
265 extern int cm_currPage;         /* current page number in the Cache Managers frame */
266 extern int cm_curr_LCol;        /* current leftmost column on display on CM frame */
267
268 /* File server and Cache manager data is classified into sections & 
269 groups to help the user choose what he wants displayed */
270 extern char *fs_categories[];   /* file server data category names */
271 extern char *cm_categories[];   /* cache manager data category names */
272
273
274
275 #ifndef HAVE_STRCASESTR
276 /*      
277         strcasestr(): Return first occurence of pattern s2 in s1, case 
278         insensitive. 
279
280         This routine is required since I made pattern matching of the
281         config file to be case insensitive. 
282 */
283
284 char *
285 strcasestr(s1, s2)
286      char *s1;
287      char *s2;
288 {
289     char *ptr;
290     int len1, len2;
291
292     len1 = strlen(s1);
293     len2 = strlen(s2);
294
295     if (len1 < len2)
296         return ((char *)NULL);
297
298     ptr = s1;
299
300     while (len1 >= len2 && len1 > 0) {
301         if ((strncasecmp(ptr, s2, len2)) == 0)
302             return (ptr);
303         ptr++;
304         len1--;
305     }
306     return ((char *)NULL);
307 }
308 #endif
309
310 struct hostent *
311 GetHostByName(name)
312      char *name;
313 {
314     struct hostent *he;
315 #ifdef AFS_SUN5_ENV
316     char ip_addr[32];
317 #endif
318
319     he = gethostbyname(name);
320 #ifdef AFS_SUN5_ENV
321     /* On solaris the above does not resolve hostnames to full names */
322     if (he != NULL) {
323         memcpy(ip_addr, he->h_addr, he->h_length);
324         he = gethostbyaddr(ip_addr, he->h_length, he->h_addrtype);
325     }
326 #endif
327     return (he);
328 }
329
330
331 /*-----------------------------------------------------------------------
332  * afsmon_Exit()
333  *
334  * Description
335  *      Exit gracefully from the afsmonitor. Frees memory where appropriate,
336  *      cleans up after gtx and closes all open file descriptors. If a user 
337  *      provided threshold handler is to be exec'ed then gtx cleanup is
338  *      not performed and an exec() is made instead of an exit(). 
339  *
340  * Returns
341  *      Nothing.
342  *
343  * Comments 
344  *      This function is called to execute a user handler only 
345  *      by a child process.
346  * 
347  *----------------------------------------------------------------------*/
348
349 int
350 afsmon_Exit(a_exitVal)
351      int a_exitVal;             /* exit code */
352 {                               /* afsmon_Exit */
353     static char rn[] = "afsmon_Exit";
354     struct afsmon_fs_Results_list *tmp_fslist;
355     struct afsmon_fs_Results_list *next_fslist;
356     struct xstat_fs_ProbeResults *tmp_xstat_fsPR;
357     struct afsmon_cm_Results_list *tmp_cmlist;
358     struct afsmon_cm_Results_list *next_cmlist;
359     struct xstat_cm_ProbeResults *tmp_xstat_cmPR;
360     struct afsmon_hostEntry *curr_hostEntry;
361     struct afsmon_hostEntry *prev_hostEntry;
362     int i;
363     int j;
364     int bufslot;
365     int code;
366
367     if (afsmon_debug) {
368         fprintf(debugFD, "[ %s ] Called with exit code %d\n", rn, a_exitVal);
369         fflush(debugFD);
370     }
371
372     /* get out of curses first, but not if we are here to exec a threshold
373      * handler. If we do, the screen gets messed up  */
374     if (gtx_initialized && !exec_fsThreshHandler)
375         gator_cursesgwin_cleanup(afsmon_win);
376
377     /* print the error message buffer */
378     if (errMsg[0] != '\0')
379         fprintf(stderr, "%s", errMsg);
380     if (errMsg1[0] != '\0')
381         fprintf(stderr, "%s", errMsg1);
382
383     /* deallocate file server circular buffers */
384     if (numFS && num_bufSlots) {
385         if (afsmon_debug) {
386             fprintf(debugFD, "freeing FS circular buffers ");
387             fflush(debugFD);
388         }
389
390         for (bufslot = 0; bufslot < num_bufSlots; bufslot++) {
391             if (afsmon_debug)
392                 fprintf(debugFD, " %d) ", bufslot);
393             if (afsmon_fs_ResultsCB[bufslot].list !=
394                 (struct afsmon_fs_Results_list *)0) {
395                 tmp_fslist = afsmon_fs_ResultsCB[bufslot].list;
396                 j = numFS;
397                 while (tmp_fslist) {
398                     /* make sure we do not go astray */
399                     if (--j < 0) {
400                         if (afsmon_debug)
401                             fprintf(debugFD,
402                                     "[ %s ] error in deallocating fs CB\n",
403                                     rn);
404                         break;
405                     }
406                     next_fslist = tmp_fslist->next;
407                     tmp_xstat_fsPR = tmp_fslist->fsResults;
408
409                     if (afsmon_debug)
410                         fprintf(debugFD, "%d ", numFS - j);
411
412                     /* free xstat_fs_Results data */
413                     free(tmp_xstat_fsPR->data.AFS_CollData_val);
414                     free(tmp_xstat_fsPR->connP);
415                     free(tmp_xstat_fsPR);
416
417                     /* free the fs list item */
418                     free(tmp_fslist);
419                     tmp_fslist = next_fslist;
420
421                 }               /* while fs list items in this slot */
422             }                   /* if entries in this buffer slot */
423         }                       /* for each fs buffer slot */
424         if (afsmon_debug)
425             fprintf(debugFD, "\n");
426     }
427
428     if (afsmon_debug)
429         fflush(debugFD);
430     /* deallocate cache manager curcular buffers */
431     if (numCM && num_bufSlots) {
432         if (afsmon_debug)
433             fprintf(debugFD, "freeing CM curcular buffers ");
434         for (bufslot = 0; bufslot < num_bufSlots; bufslot++) {
435             if (afsmon_debug)
436                 fprintf(debugFD, " %d) ", bufslot);
437             if (afsmon_cm_ResultsCB[bufslot].list !=
438                 (struct afsmon_cm_Results_list *)0) {
439                 tmp_cmlist = afsmon_cm_ResultsCB[bufslot].list;
440                 j = numCM;
441                 while (tmp_cmlist) {
442                     /* make sure we do not go astray */
443                     if (--j < 0) {
444                         if (afsmon_debug)
445                             fprintf(debugFD,
446                                     "[ %s ] error in deallocating cm CB\n",
447                                     rn);
448                         break;
449                     }
450                     next_cmlist = tmp_cmlist->next;
451                     tmp_xstat_cmPR = tmp_cmlist->cmResults;
452
453                     if (afsmon_debug)
454                         fprintf(debugFD, "%d ", numCM - j);
455                     /* make sure data is ok */
456                     /* Print_cm_FullPerfInfo(tmp_xstat_cmPR); */
457
458                     /* free xstat_cm_Results data */
459                     free(tmp_xstat_cmPR->data.AFSCB_CollData_val);
460                     free(tmp_xstat_cmPR->connP);
461                     free(tmp_xstat_cmPR);
462
463                     /* free the cm list item */
464                     free(tmp_cmlist);
465                     tmp_cmlist = next_cmlist;
466
467                 }               /* while cm list items in this slot */
468             }                   /* if entries in this buffer slot */
469         }                       /* for each cm buffer slot */
470         if (afsmon_debug)
471             fprintf(debugFD, "\n");
472     }
473
474
475     /* deallocate FS & CM Print buffers */
476     if (curr_fsData != (struct fs_Display_Data *)0) {
477         if (afsmon_debug)
478             fprintf(debugFD, "Deallocating FS Print Buffers .... curr");
479         free(curr_fsData);
480     }
481     if (prev_fsData != (struct fs_Display_Data *)0) {
482         if (afsmon_debug)
483             fprintf(debugFD, ", prev \n");
484         free(prev_fsData);
485     }
486     if (prev_cmData != (struct cm_Display_Data *)0) {
487         if (afsmon_debug)
488             fprintf(debugFD, "Deallocating CM Print Buffers .... curr");
489         free(curr_cmData);
490     }
491     if (prev_cmData != (struct cm_Display_Data *)0) {
492         if (afsmon_debug)
493             fprintf(debugFD, ", prev \n");
494         free(prev_cmData);
495     }
496
497     /* deallocate hostEntry lists */
498     if (numFS) {
499         if (afsmon_debug)
500             fprintf(debugFD, "Deallocating FS hostEntries ..");
501         curr_hostEntry = FSnameList;
502         for (i = 0; i < numFS; i++) {
503             prev_hostEntry = curr_hostEntry;
504             if (curr_hostEntry->thresh != NULL)
505                 free(curr_hostEntry->thresh);
506             free(curr_hostEntry);
507             if (afsmon_debug)
508                 fprintf(debugFD, " %d", i);
509             curr_hostEntry = prev_hostEntry->next;
510         }
511         if (afsmon_debug)
512             fprintf(debugFD, "\n");
513     }
514     if (numCM) {
515         if (afsmon_debug)
516             fprintf(debugFD, "Deallocating CM hostEntries ..");
517         curr_hostEntry = CMnameList;
518         for (i = 0; i < numCM; i++) {
519             prev_hostEntry = curr_hostEntry;
520             if (curr_hostEntry->thresh != NULL)
521                 free(curr_hostEntry->thresh);
522             free(curr_hostEntry);
523             if (afsmon_debug)
524                 fprintf(debugFD, " %d", i);
525             curr_hostEntry = prev_hostEntry->next;
526         }
527         if (afsmon_debug)
528             fprintf(debugFD, "\n");
529     }
530
531     /* close debug file */
532     if (afsmon_debug) {
533         fflush(debugFD);
534         fclose(debugFD);
535     }
536
537     if (exec_fsThreshHandler) {
538         code = execvp(fsHandler_argv[0], fsHandler_argv);
539         if (code == -1) {
540             fprintf(stderr, "execvp() of %s returned %d, errno %d\n",
541                     fsHandler_argv[0], code, errno);
542             exit(-1);
543         }
544     }
545
546     exit(a_exitVal);
547 }                               /* afsmon_Exit */
548
549 /*-----------------------------------------------------------------------
550  * insert_FS()
551  *
552  * Description:
553  *      Insert a hostname in the file server names list.
554  *
555  * Returns:
556  *      Success: 0
557  *      Failure: -1
558  *----------------------------------------------------------------------*/
559
560 int
561 insert_FS(a_hostName)
562      char *a_hostName;          /* name of cache manager to be inserted in list */
563 {                               /* insert_FS() */
564     static char rn[] = "insert_FS";     /* routine name */
565     static struct afsmon_hostEntry *curr_item;
566     static struct afsmon_hostEntry *prev_item;
567
568     if (*a_hostName == '\0')
569         return (-1);
570     curr_item = (struct afsmon_hostEntry *)
571         malloc(sizeof(struct afsmon_hostEntry));
572     if (curr_item == (struct afsmon_hostEntry *)0) {
573         fprintf(stderr, "Failed to allocate space for FS nameList\n");
574         return (-1);
575     }
576
577     strncpy(curr_item->hostName, a_hostName, CFG_STR_LEN);
578     curr_item->next = (struct afsmon_hostEntry *)0;
579     curr_item->numThresh = 0;
580     curr_item->thresh = NULL;
581
582     if (FSnameList == (struct afsmon_hostEntry *)0)
583         FSnameList = curr_item;
584     else
585         prev_item->next = curr_item;
586
587     prev_item = curr_item;
588     /*  record the address of this entry so that its threshold
589      * count can be incremented during  the first pass of the config file */
590     last_hostEntry = curr_item;
591
592     return (0);
593 }
594
595 /*-----------------------------------------------------------------------
596  * print_FS()
597  *
598  * Description:
599  *      Debug routine.
600  *      Prints the file server names linked list.
601  *
602  * Returns:
603  *      Nothing.
604  *----------------------------------------------------------------------*/
605 void
606 print_FS()
607 {                               /* print_FS() */
608     static char rn[] = "print_FS";
609     struct afsmon_hostEntry *tempFS;
610     struct Threshold *threshP;
611     int i;
612
613     if (afsmon_debug) {
614         fprintf(debugFD, "[ %s ] Called\n", rn);
615         fflush(debugFD);
616     }
617
618     if (afsmon_debug) {
619         tempFS = FSnameList;
620         fprintf(debugFD, "No of File Servers: %d\n", numFS);
621         if (numFS) {
622             do {
623                 fprintf(debugFD, "\t %s threshCount = %d\n", tempFS->hostName,
624                         tempFS->numThresh);
625                 threshP = tempFS->thresh;
626                 for (i = 0; i < tempFS->numThresh; i++, threshP++)
627                     fprintf(debugFD, "\t thresh (%2d) %s %s %s\n",
628                             threshP->index, threshP->itemName,
629                             threshP->threshVal, threshP->handler);
630             } while ((tempFS = tempFS->next) != (struct afsmon_hostEntry *)0);
631         }
632         fprintf(debugFD, "\t\t-----End of List-----\n");
633         fflush(debugFD);
634     }
635
636 }
637
638 /*-----------------------------------------------------------------------
639  * insert_CM()
640  *
641  * Description:
642  *      Insert a hostname in the cache manager names list.
643  *
644  * Returns:
645  *      Success: 0
646  *      Failure: -1
647  *----------------------------------------------------------------------*/
648
649 int
650 insert_CM(a_hostName)
651      char *a_hostName;          /* name of cache manager to be inserted in list */
652 {                               /* insert_CM */
653     static char rn[] = "insert_CM";     /* routine name */
654     static struct afsmon_hostEntry *curr_item;
655     static struct afsmon_hostEntry *prev_item;
656
657     if (*a_hostName == '\0')
658         return (-1);
659     curr_item = (struct afsmon_hostEntry *)
660         malloc(sizeof(struct afsmon_hostEntry));
661     if (curr_item == (struct afsmon_hostEntry *)0) {
662         fprintf(stderr, "Failed to allocate space for CM nameList\n");
663         return (-1);
664     }
665
666     strncpy(curr_item->hostName, a_hostName, CFG_STR_LEN);
667     curr_item->next = (struct afsmon_hostEntry *)0;
668     curr_item->numThresh = 0;
669     curr_item->thresh = NULL;
670
671     if (CMnameList == (struct afsmon_hostEntry *)0)
672         CMnameList = curr_item;
673     else
674         prev_item->next = curr_item;
675
676     prev_item = curr_item;
677     /* side effect. note the address of this entry so that its threshold
678      * count can be incremented during  the first pass of the config file */
679     last_hostEntry = curr_item;
680
681     return (0);
682 }
683
684
685 /*-----------------------------------------------------------------------
686  * print_CM()
687  *
688  * Description:
689  *      Debug routine.
690  *      Prints the cache manager names linked list.
691  *
692  * Returns:
693  *      Nothing.
694  *----------------------------------------------------------------------*/
695 int
696 print_CM()
697 {                               /* print_CM() */
698     static char rn[] = "print_CM";
699     struct afsmon_hostEntry *tempCM;
700     struct Threshold *threshP;
701     int i;
702
703     if (afsmon_debug) {
704         fprintf(debugFD, "[ %s ] Called\n", rn);
705         fflush(debugFD);
706     }
707
708     if (afsmon_debug) {
709         tempCM = CMnameList;
710         fprintf(debugFD, "No of Cache Managers: %d\n", numCM);
711         if (numCM) {
712             do {
713                 fprintf(debugFD, "\t %s threshCount = %d\n", tempCM->hostName,
714                         tempCM->numThresh);
715                 threshP = tempCM->thresh;
716                 for (i = 0; i < tempCM->numThresh; i++, threshP++)
717                     fprintf(debugFD, "\t thresh (%2d) %s %s %s\n",
718                             threshP->index, threshP->itemName,
719                             threshP->threshVal, threshP->handler);
720             } while ((tempCM = tempCM->next) != (struct afsmon_hostEntry *)0);
721         }
722         fprintf(debugFD, "\t\t-----End of List-----\n");
723     }
724     return (0);
725 }                               /* print_CM() */
726
727
728
729 /*-----------------------------------------------------------------------
730  * parse_hostEntry()
731  *
732  * Description:
733  *      Parse the host entry line in the config file. Check the syntax,
734  *      and inserts the host name in the FS ot CM linked list. Also
735  *      remember if this entry was an fs or cm & the ptr to its hostEntry
736  *      structure. The threshold entries in the config file are dependent
737  *      on their position relative to the hostname entries. Hence it is
738  *      required to remember the names of the last file server and cache
739  *      manager entries that were processed.
740  *
741  * Returns:
742  *      Success: 0
743  *      Failure: -1
744  *
745  *----------------------------------------------------------------------*/
746
747 int
748 parse_hostEntry(a_line)
749      char *a_line;
750 {                               /* parse_hostEntry */
751
752     static char rn[] = "parse_hostEntry";       /* routine name */
753     char opcode[CFG_STR_LEN];   /* specifies type of config entry */
754     char arg1[CFG_STR_LEN];     /* hostname or qualifier (fs/cm?)  */
755     char arg2[CFG_STR_LEN];     /* threshold variable */
756     char arg3[CFG_STR_LEN];     /* threshold value */
757     char arg4[CFG_STR_LEN];     /* user's handler  */
758     struct hostent *he;         /* host entry */
759
760     if (afsmon_debug) {
761         fprintf(debugFD, "[ %s ] Called, a_line = %s\n", rn, a_line);
762         fflush(debugFD);
763     }
764
765     /* break it up */
766     opcode[0] = 0;
767     arg1[0] = 0;
768     arg2[0] = 0;
769     arg3[0] = 0;
770     arg4[0] = 0;
771     sscanf(a_line, "%s %s %s %s %s", opcode, arg1, arg2, arg3, arg4);
772     /* syntax is "opcode hostname" */
773     if ((strlen(arg2)) != 0) {
774         fprintf(stderr, "[ %s ] Extraneous characters at end of line\n", rn);
775         return (-1);
776     }
777
778     /* good host ? */
779     he = GetHostByName(arg1);
780     if (he == NULL) {
781         fprintf(stderr, "[ %s ] Unable to resolve hostname %s\n", rn, arg1);
782         return (-1);
783     }
784
785     if ((strcasecmp(opcode, "fs")) == 0) {
786         /* use the complete host name to insert in the file server names list */
787         insert_FS(he->h_name);
788         /* note that last host entry in the config file was fs */
789         lastHostType = 1;
790         numFS++;
791         /* threholds are not global anymore */
792         if (global_ThreshFlag)
793             global_ThreshFlag = 0;
794     } else if ((strcasecmp(opcode, "cm")) == 0) {
795         /* use the complete host name to insert in the CM names list */
796         insert_CM(he->h_name);
797         /* last host entry in the config file was cm */
798         lastHostType = 2;
799         numCM++;
800         /* threholds are not global anymore */
801         if (global_ThreshFlag)
802             global_ThreshFlag = 0;
803     } else
804         return (-1);
805
806     return (0);
807 }
808
809 /*-----------------------------------------------------------------------
810  * parse_threshEntry()
811  *
812  * Description
813  *      Parse the threshold entry line in the config file. This function is
814  *      called in the the first pass of the config file. It checks the syntax 
815  *      of the config lines and verifies their positional validity - eg.,
816  *      a cm threshold cannot appear after a fs hostname entry, etc.
817  *      It also counts the thresholds applicable to each host.
818  *
819  * Returns
820  *      Success: 0
821  *      Failure: -1
822  *
823  *----------------------------------------------------------------------*/
824
825 int
826 parse_threshEntry(a_line)
827      char *a_line;
828 {                               /* parse_threshEntry */
829     static char rn[] = "parse_threshEntry";     /* routine name */
830     char opcode[CFG_STR_LEN];   /* specifies type of config entry */
831     char arg1[CFG_STR_LEN];     /* hostname or qualifier (fs/cm?)  */
832     char arg2[CFG_STR_LEN];     /* threshold variable */
833     char arg3[CFG_STR_LEN];     /* threshold value */
834     char arg4[CFG_STR_LEN];     /* user's handler  */
835     char arg5[CFG_STR_LEN];     /* junk characters */
836
837     if (afsmon_debug) {
838         fprintf(debugFD, "[ %s ] Called, a_line = %s\n", rn, a_line);
839         fflush(debugFD);
840     }
841
842     /* break it up */
843     opcode[0] = 0;
844     arg1[0] = 0;
845     arg2[0] = 0;
846     arg3[0] = 0;
847     arg4[0] = 0;
848     arg5[0] = 0;
849     sscanf(a_line, "%s %s %s %s %s %s", opcode, arg1, arg2, arg3, arg4, arg5);
850
851     /* syntax is "thresh fs/cm variable_name threshold_value [handler] " */
852     if (((strlen(arg1)) == 0) || ((strlen(arg2)) == 0)
853         || ((strlen(arg3)) == 0)) {
854         fprintf(stderr, "[ %s ] Incomplete line\n", rn);
855         return (-1);
856     }
857     if (strlen(arg3) > THRESH_VAR_LEN - 2) {
858         fprintf(stderr, "[%s ] threshold value too long\n", rn);
859         return (-1);
860     }
861
862     if ((strcasecmp(arg1, "fs")) == 0) {
863         switch (lastHostType) {
864         case 0:         /* its a global threshold */
865             global_fsThreshCount++;
866             break;
867         case 1:         /* inc thresh count of last file server */
868             last_hostEntry->numThresh++;
869             break;
870         case 2:
871             fprintf(stderr,
872                     "[ %s ] A threshold for a File Server cannot be placed after a Cache Manager host entry in the config file \n",
873                     rn);
874             return (-1);
875         default:
876             fprintf(stderr, "[ %s ] Programming error 1\n", rn);
877             return (-1);
878         }
879     } else if ((strcasecmp(arg1, "cm")) == 0) {
880         switch (lastHostType) {
881         case 0:         /* its a global threshold */
882             global_cmThreshCount++;
883             break;
884         case 2:         /* inc thresh count of last cache manager */
885             last_hostEntry->numThresh++;
886             break;
887         case 1:
888             fprintf(stderr,
889                     "[ %s ] A threshold for a Cache Manager cannot be placed after a File Server host entry in the config file \n",
890                     rn);
891             return (-1);
892         default:
893             fprintf(stderr, "[ %s ] Programming error 2\n", rn);
894             return (-1);
895         }
896     } else {
897         fprintf(stderr,
898                 "[ %s ] Syntax error. Second argument should be \"fs\" or \"cm\" \n",
899                 rn);
900         return (-1);
901     }
902
903     return (0);
904 }                               /* parse_threshEntry */
905
906
907 /*-----------------------------------------------------------------------
908  * store_threshold()
909  *
910  * Description
911  *      The thresholds applicable to each host machine are stored in the
912  *      FSnameList and CMnameList. Threshold entries in the config file are
913  *      context sensitive. The host to which this threshold is applicable
914  *      is pointed to by last_fsHost (for file servers) and last_cmHost
915  *      for cache managers. For global thresholds the info is recorded for
916  *      all the hosts. This function is called in the second pass of the
917  *      config file. In the first pass a count of the number of global
918  *      thresholds is determined and this information is used in this 
919  *      routine. If threshold entries are duplicated the first entry is
920  *      overwritten.
921  *      Each threshold entry also has an index field. This is a positional
922  *      index to the corresponding variable in the prev_[fs/cm]Data arrays.
923  *      This makes it easy to check the threshold for overflow.
924  *
925  * Returns:
926  *      Success: 0
927  *      Failure: -1
928  *----------------------------------------------------------------------*/
929
930 int
931 store_threshold(a_type, a_varName, a_value, a_handler)
932      int a_type;                /* 1 = fs , 2 = cm */
933      char *a_varName;           /* threshold name */
934      char *a_value;             /* threshold value */
935      char *a_handler;           /* threshold overflow handler */
936
937 {                               /* store_thresholds */
938
939     static char rn[] = "store_thresholds";      /* routine name */
940     struct afsmon_hostEntry *tmp_host;  /* tmp ptr to hostEntry */
941     struct afsmon_hostEntry *Header;    /* tmp ptr to hostEntry list header */
942     struct Threshold *threshP;  /* tmp ptr to threshold list */
943     char *hostname;
944     int index;                  /* index to fs_varNames or cm_varNames */
945     int found;
946     int done;
947     int srvCount;               /* tmp count of host names */
948     int *global_TC;             /* ptr to global_xxThreshCount */
949     int i, j;
950
951     if (afsmon_debug) {
952         fprintf(debugFD,
953                 "[ %s ] Called, a_type= %d, a_varName= %s, a_value= %s, a_handler=%s\n",
954                 rn, a_type, a_varName, a_value, a_handler);
955         fflush(debugFD);
956     }
957
958     /* resolve the threshold variable name */
959     found = 0;
960     if (a_type == 1) {          /* fs threshold */
961         for (index = 0; index < NUM_FS_STAT_ENTRIES; index++) {
962             if (strcasecmp(a_varName, fs_varNames[index]) == 0) {
963                 found = 1;
964                 break;
965             }
966         }
967         if (!found) {
968             fprintf(stderr, "[ %s ] Unknown FS threshold variable name %s\n",
969                     rn, a_varName);
970             return (-1);
971         }
972         Header = FSnameList;
973         srvCount = numFS;
974         hostname = last_fsHost;
975         global_TC = &global_fsThreshCount;
976     } else if (a_type == 2) {   /* cm threshold */
977         for (index = 0; index < NUM_CM_STAT_ENTRIES; index++) {
978             if (strcasecmp(a_varName, cm_varNames[index]) == 0) {
979                 found = 1;
980                 break;
981             }
982         }
983         if (!found) {
984             fprintf(stderr, "[ %s ] Unknown CM threshold variable name %s\n",
985                     rn, a_varName);
986             return (-1);
987         }
988         Header = CMnameList;
989         srvCount = numCM;
990         hostname = last_cmHost;
991         global_TC = &global_cmThreshCount;
992     } else
993         return (-1);
994
995
996
997     /* if the global thresh count is not zero, place this threshold on
998      * all the host entries  */
999
1000     if (*global_TC) {
1001         tmp_host = Header;
1002         for (i = 0; i < srvCount; i++) {
1003             threshP = tmp_host->thresh;
1004             done = 0;
1005             for (j = 0; j < tmp_host->numThresh; j++) {
1006                 if ((threshP->itemName[0] == '\0')
1007                     || (strcasecmp(threshP->itemName, a_varName) == 0)) {
1008                     strncpy(threshP->itemName, a_varName,
1009                             THRESH_VAR_NAME_LEN);
1010                     strncpy(threshP->threshVal, a_value, THRESH_VAR_LEN);
1011                     strcpy(threshP->handler, a_handler);
1012                     threshP->index = index;
1013                     done = 1;
1014                     break;
1015                 }
1016                 threshP++;
1017             }
1018             if (!done) {
1019                 fprintf(stderr, "[ %s ] Could not insert threshold entry",
1020                         rn);
1021                 fprintf(stderr, "for %s in thresh list of host %s \n",
1022                         a_varName, tmp_host->hostName);
1023                 return (-1);
1024             }
1025             tmp_host = tmp_host->next;
1026         }
1027         (*global_TC)--;
1028         return (0);
1029     }
1030
1031     /* it is not a global threshold, insert it in the thresh list of this
1032      * host only. We overwrite the global threshold if it was alread set */
1033
1034     if (*hostname == '\0') {
1035         fprintf(stderr, "[ %s ] Programming error 3\n", rn);
1036         return (-1);
1037     }
1038
1039     /* get the hostEntry that this threshold belongs to */
1040     tmp_host = Header;
1041     found = 0;
1042     for (i = 0; i < srvCount; i++) {
1043         if (strcasecmp(tmp_host->hostName, hostname) == 0) {
1044             found = 1;
1045             break;
1046         }
1047         tmp_host = tmp_host->next;
1048     }
1049     if (!found) {
1050         fprintf(stderr, "[ %s ] Unable to find host %s in %s hostEntry list",
1051                 rn, hostname, (a_type - 1) ? "CM" : "FS");
1052         return (-1);
1053     }
1054
1055     /* put this entry on the thresh list of this host, overwrite global value
1056      * if needed */
1057
1058     threshP = tmp_host->thresh;
1059     done = 0;
1060     for (i = 0; i < tmp_host->numThresh; i++) {
1061         if ((threshP->itemName[0] == '\0')
1062             || (strcasecmp(threshP->itemName, a_varName) == 0)) {
1063             strncpy(threshP->itemName, a_varName, THRESH_VAR_NAME_LEN);
1064             strncpy(threshP->threshVal, a_value, THRESH_VAR_LEN);
1065             strcpy(threshP->handler, a_handler);
1066             threshP->index = index;
1067             done = 1;
1068             break;
1069         }
1070         threshP++;
1071     }
1072
1073     if (!done) {
1074         fprintf(stderr,
1075                 "[ %s ] Unable to insert threshold %s for %s host %s\n", rn,
1076                 a_varName, (a_type - 1) ? "CM" : "FS", tmp_host->hostName);
1077         return (-1);
1078     }
1079
1080     return (0);
1081
1082 }                               /* store_thresholds */
1083
1084
1085 /*-----------------------------------------------------------------------
1086  * parse_showEntry()
1087  *
1088  * Description:
1089  *      This function process a "show" entry in the config file. A "show"
1090  *      entry specifies what statistics the user wants to see. File
1091  *      server and Cache Manager data is divided into sections. Each section
1092  *      is made up of one or more groups. If a group name is specified only
1093  *      those statistics under that group are shown. If a section name is
1094  *      specified all the groups under this section are shown.
1095  *      Data as obtained from the xstat probes is considered to be ordered.
1096  *      This data is mapped to the screen thru fs_Display_map[] and
1097  *      cm_Display_map[]. This routine parses the "show" entry against the
1098  *      section/group names in the [fs/cm]_categories[] array. If there is
1099  *      no match it tries to match it against a variable name in 
1100  *      [fs/cm]_varNames[] array. In each case the corresponding indices to
1101  *      the data is the [fs/cm]_displayInfo[] is recorded. 
1102  *
1103  * Returns:
1104  *      Success: 0
1105  *      Failure: -1 (invalid entry)
1106  *               > -1 (programming error)
1107  *----------------------------------------------------------------------*/
1108
1109 int
1110 parse_showEntry(a_line)
1111      char *a_line;
1112 {                               /* parse_showEntry */
1113     static char rn[] = "parse_showEntry";
1114     char opcode[CFG_STR_LEN];   /* specifies type of config entry */
1115     char arg1[CFG_STR_LEN];     /* show fs or cm entry ? */
1116     char arg2[CFG_STR_LEN];     /* what we gotta show  */
1117     char arg3[CFG_STR_LEN];     /* junk */
1118     char catName[CFG_STR_LEN];  /* for category names */
1119     int numGroups;              /* number of groups in a section */
1120     int fromIdx;
1121     int toIdx;
1122     int found;
1123     int idx = 0;                /* index to fs_categories[] */
1124     int i;
1125     int j;
1126
1127
1128     if (afsmon_debug) {
1129         fprintf(debugFD, "[ %s ] Called, a_line= %s\n", rn, a_line);
1130         fflush(debugFD);
1131     }
1132     opcode[0] = 0;
1133     arg1[0] = 0;
1134     arg2[0] = 0;
1135     arg3[0] = 0;
1136     sscanf(a_line, "%s %s %s %s", opcode, arg1, arg2, arg3);
1137
1138     if (arg3[0] != '\0') {
1139         fprintf(stderr, "[ %s ] Extraneous characters at end of line\n", rn);
1140         return (-1);
1141     }
1142
1143     if ((strcasecmp(arg1, "fs") != 0) && (strcasecmp(arg1, "cm") != 0)) {
1144         fprintf(stderr,
1145                 "[ %s ] Second argument of \"show\" directive should be \"fs\" or \"cm\" \n",
1146                 rn);
1147         return (-1);
1148     }
1149
1150     /* Each entry can either be a variable name or a section/group name. Variable
1151      * names are listed in xx_varNames[] and section/group names in xx_categories[].
1152      * The section/group names in xx_categiries[] also give the starting/ending
1153      * indices of the variables belonging to that section/group. These indices
1154      * are stored in order in xx_Display_map[] and displayed to the screen in that
1155      * order. */
1156
1157     /* To handle duplicate "show" entries we keep track of what what we have
1158      * already marked to show in the xx_showFlags[] */
1159
1160     if (strcasecmp(arg1, "fs") == 0) {  /* its a File Server entry */
1161
1162         /* mark that we have to show only what the user wants */
1163         fs_showDefault = 0;
1164
1165         /* if it is a section/group name, find it in the fs_categories[] array */
1166
1167         found = 0;
1168         if (strcasestr(arg2, "_section") != (char *)NULL
1169             || strcasestr(arg2, "_group") != (char *)NULL) {
1170             idx = 0;
1171             while (idx < FS_NUM_DATA_CATEGORIES) {
1172                 sscanf(fs_categories[idx], "%s %d %d", catName, &fromIdx,
1173                        &toIdx);
1174                 idx++;
1175                 if (strcasecmp(arg2, catName) == 0) {
1176                     found = 1;
1177                     break;
1178                 }
1179             }
1180
1181             if (!found) {       /* typo in section/group name */
1182                 fprintf(stderr,
1183                         "[ %s ] Could not find section/group name %s\n", rn,
1184                         arg2);
1185                 return (-1);
1186             }
1187         }
1188
1189         /* if it is a group name, read its start/end indices and fill in the
1190          * fs_Display_map[]. */
1191
1192         if (strcasestr(arg2, "_group") != (char *)NULL) {
1193
1194             if (fromIdx < 0 || toIdx < 0 || fromIdx > NUM_FS_STAT_ENTRIES
1195                 || toIdx > NUM_FS_STAT_ENTRIES)
1196                 return (-2);
1197             for (j = fromIdx; j <= toIdx; j++) {
1198                 if (!fs_showFlags[j]) {
1199                     fs_Display_map[fs_DisplayItems_count] = j;
1200                     fs_DisplayItems_count++;
1201                     fs_showFlags[j] = 1;
1202                 }
1203                 if (fs_DisplayItems_count > NUM_FS_STAT_ENTRIES) {
1204                     fprintf(stderr, "[ %s ] fs_DisplayItems_count ovf\n", rn);
1205                     return (-3);
1206                 }
1207             }
1208         } else
1209             /* if it is a section name, get the count of number of groups in it and
1210              * for each group fill in the start/end indices in the fs_Display_map[] */
1211
1212         if (strcasestr(arg2, "_section") != (char *)NULL) {
1213             /* fromIdx is actually the number of groups in thi section */
1214             numGroups = fromIdx;
1215             /* for each group in section */
1216             while (idx < FS_NUM_DATA_CATEGORIES && numGroups) {
1217                 sscanf(fs_categories[idx], "%s %d %d", catName, &fromIdx,
1218                        &toIdx);
1219
1220                 if (strcasestr(catName, "_group") != NULL) {
1221                     if (fromIdx < 0 || toIdx < 0
1222                         || fromIdx > NUM_FS_STAT_ENTRIES
1223                         || toIdx > NUM_FS_STAT_ENTRIES)
1224                         return (-4);
1225                     for (j = fromIdx; j <= toIdx; j++) {
1226                         if (!fs_showFlags[j]) {
1227                             fs_Display_map[fs_DisplayItems_count] = j;
1228                             fs_DisplayItems_count++;
1229                             fs_showFlags[j] = 1;
1230                         }
1231                         if (fs_DisplayItems_count > NUM_FS_STAT_ENTRIES) {
1232                             fprintf(stderr,
1233                                     "[ %s ] fs_DisplayItems_count ovf\n", rn);
1234                             return (-5);
1235                         }
1236                     }
1237                 } else {
1238                     fprintf(stderr, "[ %s ] Error parsing groups for %s\n",
1239                             rn, arg2);
1240                     return (-6);
1241                 }
1242                 idx++;
1243                 numGroups--;
1244             }                   /* for each group in section */
1245
1246
1247         } else {                /* it is a variable name */
1248
1249             for (i = 0; i < NUM_FS_STAT_ENTRIES; i++) {
1250                 if (strcasecmp(arg2, fs_varNames[i]) == 0) {
1251                     if (!fs_showFlags[i]) {
1252                         fs_Display_map[fs_DisplayItems_count] = i;
1253                         fs_DisplayItems_count++;
1254                         fs_showFlags[i] = 1;
1255                     }
1256                     if (fs_DisplayItems_count >= NUM_FS_STAT_ENTRIES) {
1257                         fprintf(stderr, "[ %s ] fs_DisplayItems_count ovf\n",
1258                                 rn);
1259                         return (-25);
1260                     }
1261                     found = 1;
1262                 }
1263             }
1264             if (!found) {       /* typo in section/group name */
1265                 fprintf(stderr, "[ %s ] Could not find variable name %s\n",
1266                         rn, arg2);
1267                 return (-1);
1268             }
1269         }                       /* its a variable name */
1270
1271     }
1272
1273     /* it is an fs entry */
1274     if (strcasecmp(arg1, "cm") == 0) {  /* its a Cache Manager entry */
1275
1276
1277         /* mark that we have to show only what the user wants */
1278         cm_showDefault = 0;
1279
1280         /* if it is a section/group name, find it in the cm_categories[] array */
1281
1282         found = 0;
1283         if (strcasestr(arg2, "_section") != (char *)NULL
1284             || strcasestr(arg2, "_group") != (char *)NULL) {
1285             idx = 0;
1286             while (idx < CM_NUM_DATA_CATEGORIES) {
1287                 sscanf(cm_categories[idx], "%s %d %d", catName, &fromIdx,
1288                        &toIdx);
1289                 idx++;
1290                 if (strcasecmp(arg2, catName) == 0) {
1291                     found = 1;
1292                     break;
1293                 }
1294             }
1295
1296             if (!found) {       /* typo in section/group name */
1297                 fprintf(stderr,
1298                         "[ %s ] Could not find section/group name %s\n", rn,
1299                         arg2);
1300                 return (-1);
1301             }
1302         }
1303
1304         /* if it is a group name, read its start/end indices and fill in the
1305          * cm_Display_map[]. */
1306
1307         if (strcasestr(arg2, "_group") != (char *)NULL) {
1308
1309             if (fromIdx < 0 || toIdx < 0 || fromIdx > NUM_CM_STAT_ENTRIES
1310                 || toIdx > NUM_CM_STAT_ENTRIES)
1311                 return (-10);
1312             for (j = fromIdx; j <= toIdx; j++) {
1313                 if (!cm_showFlags[j]) {
1314                     cm_Display_map[cm_DisplayItems_count] = j;
1315                     cm_DisplayItems_count++;
1316                     cm_showFlags[j] = 1;
1317                 }
1318                 if (cm_DisplayItems_count > NUM_CM_STAT_ENTRIES) {
1319                     fprintf(stderr, "[ %s ] cm_DisplayItems_count ovf\n", rn);
1320                     return (-11);
1321                 }
1322             }
1323         } else
1324             /* if it is a section name, get the count of number of groups in it and
1325              * for each group fill in the start/end indices in the cm_Display_map[] */
1326
1327         if (strcasestr(arg2, "_section") != (char *)NULL) {
1328             /* fromIdx is actually the number of groups in thi section */
1329             numGroups = fromIdx;
1330             /* for each group in section */
1331             while (idx < CM_NUM_DATA_CATEGORIES && numGroups) {
1332                 sscanf(cm_categories[idx], "%s %d %d", catName, &fromIdx,
1333                        &toIdx);
1334
1335                 if (strcasestr(catName, "_group") != NULL) {
1336                     if (fromIdx < 0 || toIdx < 0
1337                         || fromIdx > NUM_CM_STAT_ENTRIES
1338                         || toIdx > NUM_CM_STAT_ENTRIES)
1339                         return (-12);
1340                     for (j = fromIdx; j <= toIdx; j++) {
1341                         if (!cm_showFlags[j]) {
1342                             cm_Display_map[cm_DisplayItems_count] = j;
1343                             cm_DisplayItems_count++;
1344                             cm_showFlags[j] = 1;
1345                         }
1346                         if (cm_DisplayItems_count > NUM_CM_STAT_ENTRIES) {
1347                             fprintf(stderr,
1348                                     "[ %s ] cm_DisplayItems_count ovf\n", rn);
1349                             return (-13);
1350                         }
1351                     }
1352                 } else {
1353                     fprintf(stderr, "[ %s ] Error parsing groups for %s\n",
1354                             rn, arg2);
1355                     return (-15);
1356                 }
1357                 idx++;
1358                 numGroups--;
1359             }                   /* for each group in section */
1360
1361
1362
1363
1364
1365
1366         } else {                /* it is a variable name */
1367
1368             for (i = 0; i < NUM_CM_STAT_ENTRIES; i++) {
1369                 if (strcasecmp(arg2, cm_varNames[i]) == 0) {
1370                     if (!cm_showFlags[i]) {
1371                         cm_Display_map[cm_DisplayItems_count] = i;
1372                         cm_DisplayItems_count++;
1373                         cm_showFlags[i] = 1;
1374                     }
1375                     if (cm_DisplayItems_count >= NUM_CM_STAT_ENTRIES) {
1376                         fprintf(stderr, "[ %s ] cm_DisplayItems_count ovf\n",
1377                                 rn);
1378                         return (-20);
1379                     }
1380                     found = 1;
1381                 }
1382             }
1383             if (!found) {       /* typo in section/group name */
1384                 fprintf(stderr, "[ %s ] Could not find variable name %s\n",
1385                         rn, arg2);
1386                 return (-1);
1387             }
1388         }                       /* its a variable name */
1389
1390     }
1391     /* it is an cm entry */
1392     return (0);
1393
1394
1395 }                               /* parse_showEntry */
1396
1397
1398 /*-----------------------------------------------------------------------
1399  * process_config_file()
1400  *
1401  * Description:
1402  *      Parse config file entries in two passes. In the first pass: 
1403  *              - the syntax of all the entries is checked
1404  *              - host names are noted and the FSnamesList and CMnamesList 
1405  *                constructed. 
1406  *              - a count of the global thresholds and local thresholds of 
1407  *                each host are counted. 
1408  *              - "show" entries are processed.
1409  *      In the second pass:
1410  *              - thresholds are stored 
1411  *
1412  * Returns:
1413  *      Success: 0
1414  *      Failure: Exits afsmonitor showing error and line.
1415  *----------------------------------------------------------------------*/
1416
1417 int
1418 process_config_file(a_config_filename)
1419      char *a_config_filename;
1420 {                               /* process_config_file() */
1421     static char rn[] = "process_config_file";   /* routine name */
1422     FILE *configFD;             /* config file descriptor */
1423     char line[4 * CFG_STR_LEN]; /* a line of config file */
1424     char opcode[CFG_STR_LEN];   /* specifies type of config entry */
1425     char arg1[CFG_STR_LEN];     /* hostname or qualifier (fs/cm?)  */
1426     char arg2[CFG_STR_LEN];     /* threshold variable */
1427     char arg3[CFG_STR_LEN];     /* threshold value */
1428     char arg4[CFG_STR_LEN];     /* user's handler  */
1429     struct afsmon_hostEntry *curr_host;
1430     struct hostent *he;         /* hostentry to resolve host name */
1431     char *handlerPtr;           /* ptr to pass theresh handler string */
1432     int code = 0;               /* error code */
1433     int linenum = 0;            /* config file line number */
1434     int threshCount;            /* count of thresholds for each server */
1435     int error_in_config;        /* syntax errors in config file  ?? */
1436     int i;
1437     int numBytes;
1438
1439     if (afsmon_debug) {
1440         fprintf(debugFD, "[ %s ] Called, a_config_filename= %s\n", rn,
1441                 a_config_filename);
1442         fflush(debugFD);
1443     }
1444
1445     /* open config file */
1446
1447     configFD = fopen(a_config_filename, "r");
1448     if (configFD == (FILE *) 0) {
1449         fprintf(stderr, "Failed to open config file %s \n",
1450                 a_config_filename);
1451         if (afsmon_debug) {
1452             fprintf(debugFD, "[ %s ] Failed to open config file %s \n", rn,
1453                     a_config_filename);
1454         }
1455         afsmon_Exit(5);
1456     }
1457
1458
1459     /* parse config file */
1460
1461     /* We process the config file in two passes. In the first pass we check
1462      * for correct syntax and for valid entries and also keep count of the
1463      * number of servers and thresholds to monitor. This the data strctures
1464      * can be arrays instead of link lists since we would know their sizes. */
1465
1466     /* First Pass */
1467
1468     numFS = 0;
1469     numCM = 0;
1470     threshCount = 0;
1471     error_in_config = 0;        /* flag to note if config file has syntax errors */
1472
1473     while ((fgets(line, CFG_STR_LEN, configFD)) != NULL) {
1474         opcode[0] = 0;
1475         arg1[0] = 0;
1476         arg2[0] = 0;
1477         arg3[0] = 0;
1478         arg4[0] = 0;
1479         sscanf(line, "%s %s %s %s %s", opcode, arg1, arg2, arg3, arg4);
1480         linenum++;
1481         /* skip blank lines and comment lines */
1482         if ((strlen(opcode) == 0) || line[0] == '#')
1483             continue;
1484
1485         if ((strcasecmp(opcode, "fs") == 0)
1486             || (strcasecmp(opcode, "cm")) == 0) {
1487             code = parse_hostEntry(line);
1488         } else if ((strcasecmp(opcode, "thresh")) == 0) {
1489             code = parse_threshEntry(line);
1490         } else if ((strcasecmp(opcode, "show")) == 0) {
1491             code = parse_showEntry(line);
1492         } else {
1493             fprintf(stderr, "[ %s ] Unknown opcode %s\n", rn, opcode);
1494             code = 1;
1495         }
1496
1497         if (code) {
1498             fprintf(stderr, "[ %s ] Error in line:\n %d: %s\n", rn, linenum,
1499                     line);
1500             error_in_config = 1;
1501         }
1502     }
1503
1504     if (error_in_config)
1505         afsmon_Exit(10);
1506
1507     if (afsmon_debug) {
1508         fprintf(debugFD, "Global FS thresholds count = %d\n",
1509                 global_fsThreshCount);
1510         fprintf(debugFD, "Global CM thresholds count = %d\n",
1511                 global_cmThreshCount);
1512         fflush(debugFD);
1513     }
1514
1515     /* the threshold count of all hosts in increased by 1 for each global
1516      * threshold. If one of the hosts has a local threshold for the same 
1517      * variable it would end up being counted twice. whats a few bytes of memory
1518      * wasted anyway ? */
1519
1520     if (global_fsThreshCount) {
1521         curr_host = FSnameList;
1522         for (i = 0; i < numFS; i++) {
1523             curr_host->numThresh += global_fsThreshCount;
1524             curr_host = curr_host->next;
1525         }
1526     }
1527     if (global_cmThreshCount) {
1528         curr_host = CMnameList;
1529         for (i = 0; i < numCM; i++) {
1530             curr_host->numThresh += global_cmThreshCount;
1531             curr_host = curr_host->next;
1532         }
1533     }
1534
1535
1536     /* make sure we have something to monitor */
1537     if (numFS == 0 && numCM == 0) {
1538         fprintf(stderr,
1539                 "\nConfig file must specify atleast one File Server or Cache Manager host to monitor.\n");
1540         fclose(configFD);
1541         afsmon_Exit(15);
1542     }
1543
1544     /* Second Pass */
1545
1546     fseek(configFD, 0, 0);      /* seek to the beginning */
1547
1548
1549     /* allocate memory for threshold lists */
1550     curr_host = FSnameList;
1551     for (i = 0; i < numFS; i++) {
1552         if (curr_host->hostName[0] == '\0') {
1553             fprintf(stderr, "[ %s ] Programming error 4\n", rn);
1554             afsmon_Exit(20);
1555         }
1556         if (curr_host->numThresh) {
1557             numBytes = curr_host->numThresh * sizeof(struct Threshold);
1558             curr_host->thresh = (struct Threshold *)malloc(numBytes);
1559             if (curr_host->thresh == NULL) {
1560                 fprintf(stderr, "[ %s ] Memory Allocation error 1", rn);
1561                 afsmon_Exit(25);
1562             }
1563             memset(curr_host->thresh, 0, numBytes);
1564         }
1565         curr_host = curr_host->next;;
1566     }
1567
1568     curr_host = CMnameList;
1569     for (i = 0; i < numCM; i++) {
1570         if (curr_host->hostName[0] == '\0') {
1571             fprintf(stderr, "[ %s ] Programming error 5\n", rn);
1572             afsmon_Exit(30);
1573         }
1574         if (curr_host->numThresh) {
1575             numBytes = curr_host->numThresh * sizeof(struct Threshold);
1576             curr_host->thresh = (struct Threshold *)malloc(numBytes);
1577             if (curr_host->thresh == NULL) {
1578                 fprintf(stderr, "[ %s ] Memory Allocation error 2", rn);
1579                 afsmon_Exit(35);
1580             }
1581             memset(curr_host->thresh, 0, numBytes);
1582         }
1583         curr_host = curr_host->next;;
1584     }
1585
1586
1587     opcode[0] = 0;
1588     arg1[0] = 0;
1589     arg2[0] = 0;
1590     arg3[0] = 0;
1591     arg4[0] = 0;
1592     last_fsHost[0] = '\0';
1593     last_cmHost[0] = '\0';
1594     linenum = 0;
1595     while ((fgets(line, CFG_STR_LEN, configFD)) != NULL) {
1596         opcode[0] = 0;
1597         arg1[0] = 0;
1598         arg2[0] = 0;
1599         arg3[0] = 0;
1600         arg4[0] = 0;
1601         sscanf(line, "%s %s %s %s %s", opcode, arg1, arg2, arg3, arg4);
1602         linenum++;
1603
1604         /* if we have a host entry, remember the host name */
1605         if (strcasecmp(opcode, "fs") == 0) {
1606             he = GetHostByName(arg1);
1607             strncpy(last_fsHost, he->h_name, HOST_NAME_LEN);
1608         } else if (strcasecmp(opcode, "cm") == 0) {
1609             he = GetHostByName(arg1);
1610             strncpy(last_cmHost, he->h_name, HOST_NAME_LEN);
1611         } else if (strcasecmp(opcode, "thresh") == 0) {
1612             /* if we have a threshold handler it may have arguments
1613              * and the sscanf() above would not get them, so do the 
1614              * following */
1615             if (strlen(arg4)) {
1616                 handlerPtr = line;
1617                 /* now skip over 4 words - this is done by first
1618                  * skipping leading blanks then skipping a word */
1619                 for (i = 0; i < 4; i++) {
1620                     while (isspace(*handlerPtr))
1621                         handlerPtr++;
1622                     while (!isspace(*handlerPtr))
1623                         handlerPtr++;
1624                 }
1625                 while (isspace(*handlerPtr))
1626                     handlerPtr++;
1627                 /* we how have a pointer to the start of the handler
1628                  * name & args */
1629             } else
1630                 handlerPtr = arg4;      /* empty string */
1631
1632
1633             if (strcasecmp(arg1, "fs") == 0)
1634                 code = store_threshold(1,       /* 1 = fs */
1635                                        arg2, arg3, handlerPtr);
1636
1637             else if (strcasecmp(arg1, "cm") == 0)
1638                 code = store_threshold(2,       /* 2 = fs */
1639                                        arg2, arg3, handlerPtr);
1640
1641             else {
1642                 fprintf(stderr, "[ %s ] Programming error 6\n", rn);
1643                 afsmon_Exit(40);
1644             }
1645             if (code) {
1646                 fprintf(stderr, "[ %s ] Failed to store threshold\n", rn);
1647                 fprintf(stderr, "[ %s ] Error processing line:\n%d: %s", rn,
1648                         linenum, line);
1649                 afsmon_Exit(45);
1650             }
1651         }
1652     }
1653
1654
1655     fclose(configFD);
1656     return (0);
1657 }
1658
1659 /*-----------------------------------------------------------------------
1660  * Print_FS_CB
1661  *
1662  * Description:
1663  *      Debug routine.
1664  *      Print the File Server circular buffer.
1665  *
1666  * Returns:
1667  *      Nothing.
1668  *----------------------------------------------------------------------*/
1669
1670 void
1671 Print_FS_CB()
1672 {                               /* Print_FS_CB() */
1673
1674     struct afsmon_fs_Results_list *fslist;
1675     int i;
1676     int j;
1677
1678     /* print valid info in the fs CB */
1679
1680     if (afsmon_debug) {
1681         fprintf(debugFD,
1682                 "==================== FS Buffer ========================\n");
1683         fprintf(debugFD, "afsmon_fs_curr_CBindex = %d\n",
1684                 afsmon_fs_curr_CBindex);
1685         fprintf(debugFD, "afsmon_fs_curr_probeNum = %d\n\n",
1686                 afsmon_fs_curr_probeNum);
1687
1688         for (i = 0; i < num_bufSlots; i++) {
1689             fprintf(debugFD, "\t--------- slot %d ----------\n", i);
1690             fslist = afsmon_fs_ResultsCB[i].list;
1691             j = 0;
1692             while (j < numFS) {
1693                 if (!fslist->empty) {
1694                     fprintf(debugFD, "\t %d) probeNum = %d host = %s", j,
1695                             fslist->fsResults->probeNum,
1696                             fslist->fsResults->connP->hostName);
1697                     if (fslist->fsResults->probeOK)
1698                         fprintf(debugFD, " NOTOK\n");
1699                     else
1700                         fprintf(debugFD, " OK\n");
1701                 } else
1702                     fprintf(debugFD, "\t %d) -- empty --\n", j);
1703                 fslist = fslist->next;
1704                 j++;
1705             }
1706             if (fslist != (struct afsmon_fs_Results_list *)0)
1707                 fprintf(debugFD, "dangling last next ptr fs CB\n");
1708         }
1709     }
1710 }                               /* Print_FS_CB() */
1711
1712 /*-----------------------------------------------------------------------
1713  * save_FS_results_inCB()
1714  *
1715  * Description:
1716  *      Saves the results of the latest FS probe in the fs circular
1717  *      buffers. If the current probe cycle is in progress the contents
1718  *      of xstat_fs_Results are copied to the end of the list of results
1719  *      in the current slot (pointed to by afsmon_fs_curr_CBindex). If
1720  *      a new probe cycle has started the next slot in the circular buffer
1721  *      is initialized and the results copied. Note that the Rx related
1722  *      information available in xstat_fs_Results is not copied.
1723  *
1724  * Returns:
1725  *      Success: 0
1726  *      Failure: Exits afsmonitor.
1727  *----------------------------------------------------------------------*/
1728 int
1729 save_FS_results_inCB(a_newProbeCycle)
1730      int a_newProbeCycle;       /* start of a new probe cycle ? */
1731
1732 {                               /* save_FS_results_inCB() */
1733     static char rn[] = "save_FS_results_inCB";  /* routine name */
1734     struct afsmon_fs_Results_list *tmp_fslist_item;     /* temp fs list item */
1735     struct xstat_fs_ProbeResults *tmp_fsPR;     /* temp ptr */
1736     int i;
1737
1738     if (afsmon_debug) {
1739         fprintf(debugFD, "[ %s ] Called, a_newProbeCycle= %d\n", rn,
1740                 a_newProbeCycle);
1741         fflush(debugFD);
1742     }
1743
1744
1745     /* If a new probe cycle started, mark the list in the current buffer
1746      * slot empty for resuse. Note that afsmon_fs_curr_CBindex was appropriately
1747      * incremented in afsmon_FS_Handler() */
1748
1749     if (a_newProbeCycle) {
1750         tmp_fslist_item = afsmon_fs_ResultsCB[afsmon_fs_curr_CBindex].list;
1751         for (i = 0; i < numFS; i++) {
1752             tmp_fslist_item->empty = 1;
1753             tmp_fslist_item = tmp_fslist_item->next;
1754         }
1755     }
1756
1757     /* locate last unused item in list */
1758     tmp_fslist_item = afsmon_fs_ResultsCB[afsmon_fs_curr_CBindex].list;
1759     for (i = 0; i < numFS; i++) {
1760         if (tmp_fslist_item->empty)
1761             break;
1762         tmp_fslist_item = tmp_fslist_item->next;
1763     }
1764
1765     /* if we could not find one we have an inconsistent list */
1766     if (!tmp_fslist_item->empty) {
1767         fprintf(stderr,
1768                 "[ %s ] list inconsistency 1. unable to find an empty slot to store results of probenum %d of %s\n",
1769                 rn, xstat_fs_Results.probeNum,
1770                 xstat_fs_Results.connP->hostName);
1771         afsmon_Exit(50);
1772     }
1773
1774     tmp_fsPR = tmp_fslist_item->fsResults;
1775
1776     /* copy hostname and probe number and probe time and probe status.
1777      * if the probe failed return now */
1778
1779     memcpy(tmp_fsPR->connP->hostName, xstat_fs_Results.connP->hostName,
1780            sizeof(xstat_fs_Results.connP->hostName));
1781     tmp_fsPR->probeNum = xstat_fs_Results.probeNum;
1782     tmp_fsPR->probeTime = xstat_fs_Results.probeTime;
1783     tmp_fsPR->probeOK = xstat_fs_Results.probeOK;
1784     if (xstat_fs_Results.probeOK) {     /* probeOK = 1 => notOK */
1785         /* we have a nonempty results structure so mark the list item used */
1786         tmp_fslist_item->empty = 0;
1787         return (0);
1788     }
1789
1790     /* copy connection information */
1791     memcpy(&(tmp_fsPR->connP->skt), &(xstat_fs_Results.connP->skt),
1792            sizeof(struct sockaddr_in));
1793
1794     memcpy(tmp_fsPR->connP->hostName, xstat_fs_Results.connP->hostName,
1795            sizeof(xstat_fs_Results.connP->hostName));
1796     tmp_fsPR->collectionNumber = xstat_fs_Results.collectionNumber;
1797
1798     /* copy the probe data information */
1799     tmp_fsPR->data.AFS_CollData_len = xstat_fs_Results.data.AFS_CollData_len;
1800     memcpy(tmp_fsPR->data.AFS_CollData_val,
1801            xstat_fs_Results.data.AFS_CollData_val,
1802            xstat_fs_Results.data.AFS_CollData_len * sizeof(afs_int32));
1803
1804
1805     /* we have a valid results structure so mark the list item used */
1806     tmp_fslist_item->empty = 0;
1807
1808     /* Print the fs circular buffer */
1809     Print_FS_CB();
1810
1811     return (0);
1812 }                               /* save_FS_results_inCB() */
1813
1814
1815 /*-----------------------------------------------------------------------
1816  * fs_Results_ltoa()
1817  *
1818  * Description:
1819  *      The results of xstat probes are stored in a string format in 
1820  *      the arrays curr_fsData and prev_fsData. The information stored in
1821  *      prev_fsData is copied to the screen. 
1822  *      This function converts xstat FS results from longs to strings and 
1823  *      place them in the given buffer (a pointer to an item in curr_fsData).
1824  *      When a probe cycle completes, curr_fsData is copied to prev_fsData
1825  *      in afsmon_FS_Hnadler().
1826  *
1827  * Returns:
1828  *      Always returns 0.
1829  *----------------------------------------------------------------------*/
1830
1831 int
1832 fs_Results_ltoa(a_fsData, a_fsResults)
1833      struct fs_Display_Data *a_fsData;  /* target buffer */
1834      struct xstat_fs_ProbeResults *a_fsResults; /* ptr to xstat fs Results */
1835 {                               /* fs_Results_ltoa */
1836
1837     static char rn[] = "fs_Results_ltoa";       /* routine name */
1838     afs_int32 *srcbuf;
1839     struct fs_stats_FullPerfStats *fullPerfP;
1840     int idx;
1841     int i, j;
1842     afs_int32 *tmpbuf;
1843
1844     if (afsmon_debug) {
1845         fprintf(debugFD, "[ %s ] Called, a_fsData= %d, a_fsResults= %d\n", rn,
1846                 a_fsData, a_fsResults);
1847         fflush(debugFD);
1848     }
1849
1850     fullPerfP = (struct fs_stats_FullPerfStats *)
1851         (a_fsResults->data.AFS_CollData_val);
1852
1853     /* there are two parts to the xstat FS statistics 
1854      * - fullPerfP->overall which give the overall performance statistics, and
1855      * - fullPerfP->det which gives detailed info about file server operation
1856      * execution times */
1857
1858     /* copy overall performance statistics */
1859     srcbuf = (afs_int32 *) & (fullPerfP->overall);
1860     idx = 0;
1861     for (i = 0; i < NUM_XSTAT_FS_AFS_PERFSTATS_LONGS; i++) {
1862         sprintf(a_fsData->data[idx], "%d", *srcbuf);
1863         idx++;
1864         srcbuf++;
1865     }
1866
1867     /* copy epoch */
1868     srcbuf = (afs_int32 *) & (fullPerfP->det.epoch);
1869     sprintf(a_fsData->data[idx], "%d", *srcbuf);        /* epoch */
1870     idx++;
1871
1872     /* copy fs operation timing */
1873
1874     srcbuf = (afs_int32 *) (fullPerfP->det.rpcOpTimes);
1875
1876     for (i = 0; i < FS_STATS_NUM_RPC_OPS; i++) {
1877         sprintf(a_fsData->data[idx], "%d", *srcbuf);    /* numOps */
1878         idx++;
1879         srcbuf++;
1880         sprintf(a_fsData->data[idx], "%d", *srcbuf);    /* numSuccesses */
1881         idx++;
1882         srcbuf++;
1883         tmpbuf = srcbuf++;      /* sum time */
1884         sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1885         idx++;
1886         srcbuf++;
1887         tmpbuf = srcbuf++;      /* sqr time */
1888         sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1889         idx++;
1890         srcbuf++;
1891         tmpbuf = srcbuf++;      /* min time */
1892         sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1893         idx++;
1894         srcbuf++;
1895         tmpbuf = srcbuf++;      /* max time */
1896         sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1897         idx++;
1898         srcbuf++;
1899     }
1900
1901     /* copy fs transfer timings */
1902
1903     srcbuf = (afs_int32 *) (fullPerfP->det.xferOpTimes);
1904     for (i = 0; i < FS_STATS_NUM_XFER_OPS; i++) {
1905         sprintf(a_fsData->data[idx], "%d", *srcbuf);    /* numOps */
1906         idx++;
1907         srcbuf++;
1908         sprintf(a_fsData->data[idx], "%d", *srcbuf);    /* numSuccesses */
1909         idx++;
1910         srcbuf++;
1911         tmpbuf = srcbuf++;      /* sum time */
1912         sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1913         idx++;
1914         srcbuf++;
1915         tmpbuf = srcbuf++;      /* sqr time */
1916         sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1917         idx++;
1918         srcbuf++;
1919         tmpbuf = srcbuf++;      /* min time */
1920         sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1921         idx++;
1922         srcbuf++;
1923         tmpbuf = srcbuf++;      /* max time */
1924         sprintf(a_fsData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
1925         idx++;
1926         srcbuf++;
1927         sprintf(a_fsData->data[idx], "%d", *srcbuf);    /* sum bytes */
1928         idx++;
1929         srcbuf++;
1930         sprintf(a_fsData->data[idx], "%d", *srcbuf);    /* min bytes */
1931         idx++;
1932         srcbuf++;
1933         sprintf(a_fsData->data[idx], "%d", *srcbuf);    /* max bytes */
1934         idx++;
1935         srcbuf++;
1936         for (j = 0; j < FS_STATS_NUM_XFER_BUCKETS; j++) {
1937             sprintf(a_fsData->data[idx], "%d", *srcbuf);        /* bucket[j] */
1938             idx++;
1939             srcbuf++;
1940         }
1941     }
1942
1943     return (0);
1944 }                               /* fs_Results_ltoa */
1945
1946
1947
1948 /*-----------------------------------------------------------------------
1949  * execute_thresh_handler()
1950  *
1951  * Description:
1952  *      Execute a threshold handler. An agrv[] array of pointers is 
1953  *      constructed from the given data. A child process is forked 
1954  *      which immediately calls afsmon_Exit() with indication that a
1955  *      threshold handler is to be exec'ed insted of exiting. 
1956  *
1957  * Returns:
1958  *      Success: 0
1959  *      Failure: Afsmonitor exits if threshold handler has more than 20 args.
1960  *----------------------------------------------------------------------*/
1961
1962 int
1963 execute_thresh_handler(a_handler, a_hostName, a_hostType, a_threshName,
1964                        a_threshValue, a_actValue)
1965      char *a_handler;           /* ptr to handler function + args */
1966      char *a_hostName;          /* host name for which threshold crossed */
1967      int a_hostType;            /* fs or cm ? */
1968      char *a_threshName;        /* threshold variable name */
1969      char *a_threshValue;       /* threshold value */
1970      char *a_actValue;          /* actual value */
1971
1972 {                               /* execute_thresh_handler */
1973
1974     static char rn[] = "execute_thresh_handler";
1975     char fileName[256];         /* file name to execute */
1976     int i;
1977     char *ch;
1978     int code;
1979     int argNum;
1980     int anotherArg;             /* boolean used to flag if another arg is available */
1981
1982     if (afsmon_debug) {
1983         fprintf(debugFD,
1984                 "[ %s ] Called, a_handler= %s, a_hostName= %s, a_hostType= %d, a_threshName= %s, a_threshValue= %s, a_actValue= %s\n",
1985                 rn, a_handler, a_hostName, a_hostType, a_threshName,
1986                 a_threshValue, a_actValue);
1987         fflush(debugFD);
1988     }
1989
1990
1991     /* get the filename to execute - the first argument */
1992     sscanf(a_handler, "%s", fileName);
1993
1994     /* construct the contents of *argv[] */
1995
1996     strncpy(fsHandler_args[0], fileName, 256);
1997     strncpy(fsHandler_args[1], a_hostName, HOST_NAME_LEN);
1998     if (a_hostType == FS)
1999         strcpy(fsHandler_args[2], "fs");
2000     else
2001         strcpy(fsHandler_args[2], "cm");
2002     strncpy(fsHandler_args[3], a_threshName, THRESH_VAR_NAME_LEN);
2003     strncpy(fsHandler_args[4], a_threshValue, THRESH_VAR_LEN);
2004     strncpy(fsHandler_args[5], a_actValue, THRESH_VAR_LEN);
2005
2006
2007     argNum = 6;
2008     anotherArg = 1;
2009     ch = a_handler;
2010
2011     /* we have already extracted the file name so skip to the 1st arg */
2012     while (isspace(*ch))        /* leading blanks */
2013         ch++;
2014     while (!isspace(*ch) && *ch != '\0')        /* handler filename */
2015         ch++;
2016
2017     while (*ch != '\0') {
2018         if (isspace(*ch)) {
2019             anotherArg = 1;
2020         } else if (anotherArg) {
2021             anotherArg = 0;
2022             sscanf(ch, "%s", fsHandler_args[argNum]);
2023             argNum++;
2024         }
2025         ch++;
2026         if (argNum >= 20) {
2027             sprintf(errMsg,
2028                     "Threshold handlers cannot have more than 20 arguments\n");
2029             afsmon_Exit(55);
2030         }
2031
2032     }
2033
2034     fsHandler_argv[argNum] = NULL;
2035     for (i = 0; i < argNum; i++)
2036         fsHandler_argv[i] = fsHandler_args[i];
2037
2038
2039     /* exec the threshold handler */
2040
2041     if (fork() == 0) {
2042         exec_fsThreshHandler = 1;
2043         code = afsmon_Exit(60);
2044     }
2045
2046     return (0);
2047 }                               /* execute_thresh_handler */
2048
2049
2050
2051 /*-----------------------------------------------------------------------
2052  * check_fs_thresholds()
2053  *
2054  * Description:
2055  *      Checks the thresholds and sets the overflow flag. Recall that the
2056  *      thresholds for each host are stored in the hostEntry lists
2057  *      [fs/cm]nameList arrays. The probe results are passed to this 
2058  *      function in the display-ready format - ie., as strings. Though
2059  *      this looks stupid the overhead incurred in converting the strings
2060  *      back to floats and comparing them is insignificant and 
2061  *      programming is easier this way. 
2062  *      The threshold flags are a part of the display structures
2063  *      curr_[fs/cm]Data.
2064  *
2065  * Returns:
2066  *      0
2067  *----------------------------------------------------------------------*/
2068
2069 int
2070 check_fs_thresholds(a_hostEntry, a_Data)
2071      struct afsmon_hostEntry *a_hostEntry;      /* ptr to hostEntry */
2072      struct fs_Display_Data *a_Data;    /* ptr to fs data to be displayed */
2073
2074 {                               /* check_fs_thresholds */
2075
2076     static char rn[] = "check_fs_thresholds";
2077     struct Threshold *threshP;
2078     double tValue;              /* threshold value */
2079     double pValue;              /* probe value */
2080     int i;
2081     int idx;
2082     int count;                  /* number of thresholds exceeded */
2083
2084     if (afsmon_debug) {
2085         fprintf(debugFD, "[ %s ] Called, a_hostEntry= %d, a_Data= %d\n", rn,
2086                 a_hostEntry, a_Data);
2087         fflush(debugFD);
2088     }
2089
2090     if (a_hostEntry->numThresh == 0) {
2091         /* store in ovf count ?? */
2092         return (0);
2093     }
2094
2095     count = 0;
2096     threshP = a_hostEntry->thresh;
2097     for (i = 0; i < a_hostEntry->numThresh; i++) {
2098         if (threshP->itemName[0] == '\0') {
2099             threshP++;
2100             continue;
2101         }
2102         idx = threshP->index;   /* positional index to the data array */
2103         tValue = atof(threshP->threshVal);      /* threshold value */
2104         pValue = atof(a_Data->data[idx]);       /* probe value */
2105         if (pValue > tValue) {
2106
2107             if (afsmon_debug) {
2108                 fprintf(debugFD,
2109                         "[ %s ] fs = %s, thresh ovf for %s, threshold= %s, probevalue= %s\n",
2110                         rn, a_hostEntry->hostName, threshP->itemName,
2111                         threshP->threshVal, a_Data->data[idx]);
2112                 fflush(debugFD);
2113             }
2114             /* if the threshold is crossed, call the handler function
2115              * only if this was a transition -ie, if the threshold was
2116              * crossed in the last probe too just count & keep quite! */
2117
2118             if (!a_Data->threshOvf[idx]) {
2119                 a_Data->threshOvf[idx] = 1;
2120                 /* call the threshold handler if provided */
2121                 if (threshP->handler[0] != '\0') {
2122                     if (afsmon_debug) {
2123                         fprintf(debugFD, "[ %s ] Calling ovf handler %s\n",
2124                                 rn, threshP->handler);
2125                         fflush(debugFD);
2126                     }
2127                     execute_thresh_handler(threshP->handler, a_Data->hostName,
2128                                            FS, threshP->itemName,
2129                                            threshP->threshVal,
2130                                            a_Data->data[idx]);
2131                 }
2132             }
2133
2134             count++;
2135         } else
2136             /* in case threshold was previously crossed, blank it out */
2137             a_Data->threshOvf[idx] = 0;
2138         threshP++;
2139     }
2140     /* store the overflow count */
2141     a_Data->ovfCount = count;
2142
2143     return (0);
2144 }                               /* check_fs_thresholds */
2145
2146
2147 /*-----------------------------------------------------------------------
2148  * save_FS_data_forDisplay()
2149  *
2150  * Description:
2151  *      Does the following:
2152  *      - if the probe number changed (ie, a cycle completed) curr_fsData
2153  *      is copied to prev_fsData, curr_fsData zeroed and refresh the 
2154  *      overview screen and file server screen with the new data.
2155  *      - store the results of the current probe from xstat_fs_Results into
2156  *      curr_fsData. ie., convert longs to strings.
2157  *      - check the thresholds 
2158  *
2159  * Returns:
2160  *      Success: 0
2161  *      Failure: Exits afsmonitor.
2162  *----------------------------------------------------------------------*/
2163
2164 int
2165 save_FS_data_forDisplay(a_fsResults)
2166      struct xstat_fs_ProbeResults *a_fsResults;
2167 {                               /* save_FS_data_forDisplay */
2168
2169     static char rn[] = "save_FS_data_forDisplay";       /* routine name */
2170     struct fs_Display_Data *curr_fsDataP;       /* tmp ptr to curr_fsData */
2171     struct fs_Display_Data *prev_fsDataP;       /* tmp ptr to prev_fsData */
2172     struct afsmon_hostEntry *curr_host;
2173     static int probes_Received = 0;     /* number of probes reveived in
2174                                          * the current cycle. If this is equal to numFS we got all
2175                                          * the data we want in this cycle and can now display it */
2176     int numBytes;
2177     int okay;
2178     int i;
2179     int code;
2180     int done;
2181
2182
2183     if (afsmon_debug) {
2184         fprintf(debugFD, "[ %s ] Called, a_fsResults= %d\n", rn, a_fsResults);
2185         fflush(debugFD);
2186     }
2187
2188
2189
2190     /* store results in the display array */
2191
2192     okay = 0;
2193     curr_fsDataP = curr_fsData;
2194     for (i = 0; i < numFS; i++) {
2195         if ((strcasecmp(curr_fsDataP->hostName, a_fsResults->connP->hostName))
2196             == 0) {
2197             okay = 1;
2198             break;
2199         }
2200         curr_fsDataP++;
2201     }
2202
2203     if (!okay) {
2204         fprintf(stderr,
2205                 "[ %s ] Could not insert FS probe results for host %s in fs display array\n",
2206                 rn, a_fsResults->connP->hostName);
2207         afsmon_Exit(65);
2208     }
2209
2210     /*  Check the status of the probe. If it succeeded, we store its
2211      * results in the display data structure. If it failed we only mark 
2212      * the failed status in the display data structure. */
2213
2214     if (a_fsResults->probeOK) { /* 1 => notOK the xstat results */
2215         curr_fsDataP->probeOK = 0;
2216
2217         /* print the probe status */
2218         if (afsmon_debug) {
2219             fprintf(debugFD, "\n\t\t ----- fs display data ------\n");
2220             fprintf(debugFD, "HostName = %s  PROBE FAILED \n",
2221                     curr_fsDataP->hostName);
2222             fflush(debugFD);
2223         }
2224
2225     } else {                    /* probe succeeded, update display data structures */
2226         curr_fsDataP->probeOK = 1;
2227
2228         /* covert longs to strings and place them in curr_fsDataP */
2229         fs_Results_ltoa(curr_fsDataP, a_fsResults);
2230
2231         /* compare with thresholds and set the overflow flags.
2232          * note that the threshold information is in the hostEntry structure and 
2233          * each threshold item has a positional index associated with it */
2234
2235         /* locate the hostEntry for this host */
2236         done = 0;
2237         curr_host = FSnameList;
2238         for (i = 0; i < numFS; i++) {
2239             if (strcasecmp(curr_host->hostName, a_fsResults->connP->hostName)
2240                 == 0) {
2241                 done = 1;
2242                 break;
2243             }
2244             curr_host = curr_host->next;;
2245         }
2246         if (!done)
2247             afsmon_Exit(70);
2248
2249         code = check_fs_thresholds(curr_host, curr_fsDataP);
2250         if (code) {
2251             fprintf(stderr, "[ %s ] Error in checking thresholds\n", rn);
2252             afsmon_Exit(75);
2253         }
2254
2255
2256
2257
2258         /* print the info we just saved */
2259
2260         if (afsmon_debug) {
2261             fprintf(debugFD, "\n\t\t ----- fs display data ------\n");
2262             fprintf(debugFD, "HostName = %s\n", curr_fsDataP->hostName);
2263             for (i = 0; i < NUM_FS_STAT_ENTRIES; i++)
2264                 fprintf(debugFD, "%20s  %30s  %s\n", curr_fsDataP->data[i],
2265                         fs_varNames[i],
2266                         curr_fsDataP->threshOvf[i] ? "(ovf)" : "");
2267
2268             fprintf(debugFD, "\t\t--------------------------------\n\n");
2269             fflush(debugFD);
2270         }
2271
2272     }                           /* the probe succeeded, so we store the data in the display structure */
2273
2274
2275     /* if we have received a reply from all the hosts for this probe cycle,
2276      * it is time to display the data */
2277
2278     probes_Received++;
2279     if (probes_Received == numFS) {
2280         probes_Received = 0;
2281
2282         if (afsmon_fs_curr_probeNum != afsmon_fs_prev_probeNum + 1) {
2283             sprintf(errMsg, "[ %s ] Probe number %d missed! \n", rn,
2284                     afsmon_fs_prev_probeNum + 1);
2285             afsmon_Exit(80);
2286         } else
2287             afsmon_fs_prev_probeNum++;
2288
2289         /* backup the display data of the probe cycle that just completed -
2290          * ie., store curr_fsData in prev_fsData */
2291
2292         memcpy((char *)prev_fsData, (char *)curr_fsData,
2293                (numFS * sizeof(struct fs_Display_Data)));
2294
2295
2296         /* initialize curr_fsData but retain the threshold flag information.
2297          * The previous state of threshold flags is used in check_fs_thresholds() */
2298
2299         numBytes = NUM_FS_STAT_ENTRIES * CM_STAT_STRING_LEN;
2300         curr_fsDataP = curr_fsData;
2301         for (i = 0; i < numFS; i++) {
2302             curr_fsDataP->probeOK = 0;
2303             curr_fsDataP->ovfCount = 0;
2304             memset((char *)curr_fsDataP->data, 0, numBytes);
2305             curr_fsDataP++;
2306         }
2307
2308
2309         /* prev_fsData now contains all the information for the probe cycle
2310          * that just completed. Now count the number of threshold overflows for
2311          * use in the overview screen */
2312
2313         prev_fsDataP = prev_fsData;
2314         num_fs_alerts = 0;
2315         numHosts_onfs_alerts = 0;
2316         for (i = 0; i < numFS; i++) {
2317             if (!prev_fsDataP->probeOK) {       /* if probe failed */
2318                 num_fs_alerts++;
2319                 numHosts_onfs_alerts++;
2320             }
2321             if (prev_fsDataP->ovfCount) {       /* overflows ?? */
2322                 num_fs_alerts += prev_fsDataP->ovfCount;
2323                 numHosts_onfs_alerts++;
2324             }
2325             prev_fsDataP++;
2326         }
2327         if (afsmon_debug)
2328             fprintf(debugFD, "Number of FS alerts = %d (on %d hosts)\n",
2329                     num_fs_alerts, numHosts_onfs_alerts);
2330
2331         /* flag that the data is now ready to be displayed */
2332         fs_Data_Available = 1;
2333
2334         /* call the Overview frame update routine (update only FS info) */
2335         ovw_refresh(ovw_currPage, OVW_UPDATE_FS);
2336
2337         /* call the File Servers frame update routine */
2338         fs_refresh(fs_currPage, fs_curr_LCol);
2339
2340     }
2341     /* display data */
2342     return (0);
2343 }                               /* save_FS_data_forDisplay */
2344
2345
2346
2347
2348 /*-----------------------------------------------------------------------
2349  * afsmon_FS_Handler()
2350  *
2351  * Description:
2352  *      This is the File Server probe Handler. It updates the afsmonitor
2353  *      probe counts, fs circular buffer indices and calls the functions
2354  *      to process the results of this probe.
2355  *
2356  * Returns:
2357  *      Success: 0
2358  *      Failure: Exits afsmonitor.
2359  *----------------------------------------------------------------------*/
2360
2361 int
2362 afsmon_FS_Handler()
2363 {                               /* afsmon_FS_Handler() */
2364     static char rn[] = "afsmon_FS_Handler";     /* routine name */
2365     int newProbeCycle;          /* start of new probe cycle ? */
2366     int code;                   /* return status */
2367
2368
2369     if (afsmon_debug) {
2370         fprintf(debugFD,
2371                 "[ %s ] Called, hostName= %s, probeNum= %d, status=%s\n", rn,
2372                 xstat_fs_Results.connP->hostName, xstat_fs_Results.probeNum,
2373                 xstat_fs_Results.probeOK ? "FAILED" : "OK");
2374         fflush(debugFD);
2375     }
2376
2377
2378     /* print the probe results to output file */
2379     if (afsmon_output) {
2380         code = afsmon_fsOutput(output_filename, afsmon_detOutput);
2381         if (code) {
2382             fprintf(stderr,
2383                     "[ %s ] output to file %s returned error code=%d\n", rn,
2384                     output_filename, code);
2385         }
2386     }
2387
2388     /* Update current probe number and circular buffer index. if current 
2389      * probenum changed make sure it is only by 1 */
2390
2391     newProbeCycle = 0;
2392     if (xstat_fs_Results.probeNum != afsmon_fs_curr_probeNum) {
2393         if (xstat_fs_Results.probeNum == afsmon_fs_curr_probeNum + 1) {
2394             afsmon_fs_curr_probeNum++;
2395             newProbeCycle = 1;
2396             if (num_bufSlots)
2397                 afsmon_fs_curr_CBindex =
2398                     (afsmon_fs_curr_probeNum - 1) % num_bufSlots;
2399         } else {
2400             fprintf(stderr, "[ %s ] probe number %d-1 missed\n", rn,
2401                     xstat_fs_Results.probeNum);
2402             afsmon_Exit(85);
2403         }
2404     }
2405
2406     /* store the results of this probe in the FS circular buffer */
2407     if (num_bufSlots)
2408         save_FS_results_inCB(newProbeCycle);
2409
2410
2411     /* store the results of the current probe in the fs data display structure.
2412      * if the current probe number changed, swap the current and previous display
2413      * structures. note that the display screen is updated from these structures 
2414      * and should start showing the data of the just completed probe cycle */
2415
2416     save_FS_data_forDisplay(&xstat_fs_Results);
2417
2418     return (0);
2419 }
2420
2421
2422
2423 /*----------------------------------------------------------------------- * 
2424  * Print_CM_CB()     
2425  *
2426  * Description:
2427  *      Debug routine.
2428  *      Prints the  Cache Manager circular buffer 
2429  *----------------------------------------------------------------------*/
2430
2431 void
2432 Print_CM_CB()
2433 {                               /* Print_CM_CB() */
2434
2435     struct afsmon_cm_Results_list *cmlist;
2436     int i;
2437     int j;
2438
2439     /* print valid info in the cm CB */
2440
2441     if (afsmon_debug) {
2442         fprintf(debugFD,
2443                 "==================== CM Buffer ========================\n");
2444         fprintf(debugFD, "afsmon_cm_curr_CBindex = %d\n",
2445                 afsmon_cm_curr_CBindex);
2446         fprintf(debugFD, "afsmon_cm_curr_probeNum = %d\n\n",
2447                 afsmon_cm_curr_probeNum);
2448
2449         for (i = 0; i < num_bufSlots; i++) {
2450             fprintf(debugFD, "\t--------- slot %d ----------\n", i);
2451             cmlist = afsmon_cm_ResultsCB[i].list;
2452             j = 0;
2453             while (j < numCM) {
2454                 if (!cmlist->empty) {
2455                     fprintf(debugFD, "\t %d) probeNum = %d host = %s", j,
2456                             cmlist->cmResults->probeNum,
2457                             cmlist->cmResults->connP->hostName);
2458                     if (cmlist->cmResults->probeOK)
2459                         fprintf(debugFD, " NOTOK\n");
2460                     else
2461                         fprintf(debugFD, " OK\n");
2462                 } else
2463                     fprintf(debugFD, "\t %d) -- empty --\n", j);
2464                 cmlist = cmlist->next;
2465                 j++;
2466             }
2467             if (cmlist != (struct afsmon_cm_Results_list *)0)
2468                 fprintf(debugFD, "dangling last next ptr cm CB\n");
2469         }
2470     }
2471 }
2472
2473
2474 /*-----------------------------------------------------------------------
2475  * save_CM_results_inCB()
2476  *
2477  * Description:
2478  *      Saves the results of the latest CM probe in the cm circular
2479  *      buffers. If the current probe cycle is in progress the contents
2480  *      of xstat_cm_Results are copied to the end of the list of results
2481  *      in the current slot (pointed to by afsmon_cm_curr_CBindex). If
2482  *      a new probe cycle has started the next slot in the circular buffer
2483  *      is initialized and the results copied. Note that the Rx related
2484  *      information available in xstat_cm_Results is not copied.
2485  *
2486  * Returns:
2487  *      Success: 0
2488  *      Failure: Exits afsmonitor.
2489  *----------------------------------------------------------------------*/
2490
2491 int
2492 save_CM_results_inCB(a_newProbeCycle)
2493      int a_newProbeCycle;       /* start of new probe cycle ? */
2494
2495 {                               /* save_CM_results_inCB() */
2496     static char rn[] = "save_CM_results_inCB";  /* routine name */
2497     struct afsmon_cm_Results_list *tmp_cmlist_item;     /* temp cm list item */
2498     struct xstat_cm_ProbeResults *tmp_cmPR;     /* temp ptr */
2499     int i;
2500
2501
2502     if (afsmon_debug) {
2503         fprintf(debugFD, "[ %s ] Called, a_newProbeCycle= %d\n", rn,
2504                 a_newProbeCycle);
2505         fflush(debugFD);
2506     }
2507
2508     /* If a new probe cycle started, mark the list in the current buffer
2509      * slot empty for resuse. Note that afsmon_cm_curr_CBindex was appropriately
2510      * incremented in afsmon_CM_Handler() */
2511
2512     if (a_newProbeCycle) {
2513         tmp_cmlist_item = afsmon_cm_ResultsCB[afsmon_cm_curr_CBindex].list;
2514         for (i = 0; i < numCM; i++) {
2515             tmp_cmlist_item->empty = 1;
2516             tmp_cmlist_item = tmp_cmlist_item->next;
2517         }
2518     }
2519
2520     /* locate last unused item in list */
2521     tmp_cmlist_item = afsmon_cm_ResultsCB[afsmon_cm_curr_CBindex].list;
2522     for (i = 0; i < numCM; i++) {
2523         if (tmp_cmlist_item->empty)
2524             break;
2525         tmp_cmlist_item = tmp_cmlist_item->next;
2526     }
2527
2528     /* if we could not find one we have an inconsistent list */
2529     if (!tmp_cmlist_item->empty) {
2530         fprintf(stderr,
2531                 "[ %s ] list inconsistency 1. unable to find an empty slot to store results of probenum %d of %s\n",
2532                 rn, xstat_cm_Results.probeNum,
2533                 xstat_cm_Results.connP->hostName);
2534         afsmon_Exit(90);
2535     }
2536
2537     tmp_cmPR = tmp_cmlist_item->cmResults;
2538
2539     /* copy hostname and probe number and probe time and probe status.
2540      * if the probe failed return now */
2541
2542     memcpy(tmp_cmPR->connP->hostName, xstat_cm_Results.connP->hostName,
2543            sizeof(xstat_cm_Results.connP->hostName));
2544     tmp_cmPR->probeNum = xstat_cm_Results.probeNum;
2545     tmp_cmPR->probeTime = xstat_cm_Results.probeTime;
2546     tmp_cmPR->probeOK = xstat_cm_Results.probeOK;
2547     if (xstat_cm_Results.probeOK) {     /* probeOK = 1 => notOK */
2548         /* we have a nonempty results structure so mark the list item used */
2549         tmp_cmlist_item->empty = 0;
2550         return (0);
2551     }
2552
2553
2554     /* copy connection information */
2555     memcpy(&(tmp_cmPR->connP->skt), &(xstat_cm_Results.connP->skt),
2556            sizeof(struct sockaddr_in));
2557
2558    /**** NEED TO COPY rx_connection INFORMATION HERE ******/
2559
2560     memcpy(tmp_cmPR->connP->hostName, xstat_cm_Results.connP->hostName,
2561            sizeof(xstat_cm_Results.connP->hostName));
2562     tmp_cmPR->collectionNumber = xstat_cm_Results.collectionNumber;
2563
2564     /* copy the probe data information */
2565     tmp_cmPR->data.AFSCB_CollData_len =
2566         xstat_cm_Results.data.AFSCB_CollData_len;
2567     memcpy(tmp_cmPR->data.AFSCB_CollData_val,
2568            xstat_cm_Results.data.AFSCB_CollData_val,
2569            xstat_cm_Results.data.AFSCB_CollData_len * sizeof(afs_int32));
2570
2571
2572     /* we have a valid results structure so mark the list item used */
2573     tmp_cmlist_item->empty = 0;
2574
2575     /* print the stored info - to make sure we copied it right */
2576     /*   Print_cm_FullPerfInfo(tmp_cmPR);        */
2577     /* Print the cm circular buffer */
2578     Print_CM_CB();
2579     return (0);
2580 }                               /* save_CM_results_inCB */
2581
2582
2583
2584 /*-----------------------------------------------------------------------
2585  * cm_Results_ltoa()
2586  *
2587  * Description:
2588  *      The results of xstat probes are stored in a string format in 
2589  *      the arrays curr_cmData and prev_cmData. The information stored in
2590  *      prev_cmData is copied to the screen. 
2591  *      This function converts xstat FS results from longs to strings and 
2592  *      places them in the given buffer (a pointer to an item in curr_cmData).
2593  *      When a probe cycle completes, curr_cmData is copied to prev_cmData
2594  *      in afsmon_CM_Handler().
2595  *
2596  * Returns:
2597  *      Always returns 0.
2598  *----------------------------------------------------------------------*/
2599
2600 int
2601 cm_Results_ltoa(a_cmData, a_cmResults)
2602      struct cm_Display_Data *a_cmData;  /* target buffer */
2603      struct xstat_cm_ProbeResults *a_cmResults; /* ptr to xstat cm Results */
2604 {                               /* cm_Results_ltoa */
2605
2606     static char rn[] = "cm_Results_ltoa";       /* routine name */
2607     struct afs_stats_CMFullPerf *fullP; /* ptr to complete CM stats */
2608     afs_int32 *srcbuf;
2609     afs_int32 *tmpbuf;
2610     int i, j;
2611     int idx;
2612     afs_int32 numLongs;
2613
2614     if (afsmon_debug) {
2615         fprintf(debugFD, "[ %s ] Called, a_cmData= %d, a_cmResults= %d\n", rn,
2616                 a_cmData, a_cmResults);
2617         fflush(debugFD);
2618     }
2619
2620
2621     fullP = (struct afs_stats_CMFullPerf *)
2622         (a_cmResults->data.AFSCB_CollData_val);
2623
2624     /* There are 4 parts to CM statistics
2625      * - Overall performance statistics (including up/down statistics)
2626      * - This CMs FS RPC operations info 
2627      * - This CMs FS RPC errors info
2628      * - This CMs FS transfers info
2629      * - Authentication info
2630      * - [Un]Replicated access info
2631      */
2632
2633     /* copy overall performance statistics */
2634     srcbuf = (afs_int32 *) & (fullP->perf);
2635     idx = 0;
2636     /* we skip the 19 entry, ProtServAddr, so the index must account for this */
2637     for (i = 0; i < NUM_AFS_STATS_CMPERF_LONGS + 1; i++) {
2638         if (i == 19) {
2639             srcbuf++;
2640             continue;           /* skip ProtServerAddr */
2641         }
2642         sprintf(a_cmData->data[idx], "%d", *srcbuf);
2643         idx++;
2644         srcbuf++;
2645     }
2646
2647     /*printf("Ending index value = %d\n",idx-1); */
2648
2649     /* server up/down statistics */
2650     /* copy file server up/down stats */
2651     srcbuf = (afs_int32 *) (fullP->perf.fs_UpDown);
2652     numLongs =
2653         2 * (sizeof(struct afs_stats_SrvUpDownInfo) / sizeof(afs_int32));
2654     for (i = 0; i < numLongs; i++) {
2655         sprintf(a_cmData->data[idx], "%d", *srcbuf);
2656         idx++;
2657         srcbuf++;
2658     }
2659
2660     /*printf("Ending index value = %d\n",idx-1); */
2661
2662     /* copy volume location  server up/down stats */
2663     srcbuf = (afs_int32 *) (fullP->perf.vl_UpDown);
2664     numLongs =
2665         2 * (sizeof(struct afs_stats_SrvUpDownInfo) / sizeof(afs_int32));
2666     for (i = 0; i < numLongs; i++) {
2667         sprintf(a_cmData->data[idx], "%d", *srcbuf);
2668         idx++;
2669         srcbuf++;
2670     }
2671
2672     /*printf("Ending index value = %d\n",idx-1); */
2673
2674     /* copy CMs individual FS RPC operations info */
2675     srcbuf = (afs_int32 *) (fullP->rpc.fsRPCTimes);
2676     for (i = 0; i < AFS_STATS_NUM_FS_RPC_OPS; i++) {
2677         sprintf(a_cmData->data[idx], "%d", *srcbuf);    /* numOps */
2678         idx++;
2679         srcbuf++;
2680         sprintf(a_cmData->data[idx], "%d", *srcbuf);    /* numSuccesses */
2681         idx++;
2682         srcbuf++;
2683         tmpbuf = srcbuf++;      /* sum time */
2684         sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2685         idx++;
2686         srcbuf++;
2687         tmpbuf = srcbuf++;      /* sqr time */
2688         sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2689         idx++;
2690         srcbuf++;
2691         tmpbuf = srcbuf++;      /* min time */
2692         sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2693         idx++;
2694         srcbuf++;
2695         tmpbuf = srcbuf++;      /* max time */
2696         sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2697         idx++;
2698         srcbuf++;
2699     }
2700
2701     /*printf("Ending index value = %d\n",idx-1); */
2702
2703     /* copy CMs individual FS RPC errors info */
2704
2705     srcbuf = (afs_int32 *) (fullP->rpc.fsRPCErrors);
2706     for (i = 0; i < AFS_STATS_NUM_FS_RPC_OPS; i++) {
2707         sprintf(a_cmData->data[idx], "%d", *srcbuf);    /* server */
2708         idx++;
2709         srcbuf++;
2710         sprintf(a_cmData->data[idx], "%d", *srcbuf);    /* network */
2711         idx++;
2712         srcbuf++;
2713         sprintf(a_cmData->data[idx], "%d", *srcbuf);    /* prot */
2714         idx++;
2715         srcbuf++;
2716         sprintf(a_cmData->data[idx], "%d", *srcbuf);    /* vol */
2717         idx++;
2718         srcbuf++;
2719         sprintf(a_cmData->data[idx], "%d", *srcbuf);    /* busies */
2720         idx++;
2721         srcbuf++;
2722         sprintf(a_cmData->data[idx], "%d", *srcbuf);    /* other */
2723         idx++;
2724         srcbuf++;
2725     }
2726
2727     /*printf("Ending index value = %d\n",idx-1); */
2728
2729     /* copy CMs individual RPC transfers info */
2730
2731     srcbuf = (afs_int32 *) (fullP->rpc.fsXferTimes);
2732     for (i = 0; i < AFS_STATS_NUM_FS_XFER_OPS; i++) {
2733         sprintf(a_cmData->data[idx], "%d", *srcbuf);    /* numOps */
2734         idx++;
2735         srcbuf++;
2736         sprintf(a_cmData->data[idx], "%d", *srcbuf);    /* numSuccesses */
2737         idx++;
2738         srcbuf++;
2739         tmpbuf = srcbuf++;      /* sum time */
2740         sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2741         idx++;
2742         srcbuf++;
2743         tmpbuf = srcbuf++;      /* sqr time */
2744         sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2745         idx++;
2746         srcbuf++;
2747         tmpbuf = srcbuf++;      /* min time */
2748         sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2749         idx++;
2750         srcbuf++;
2751         tmpbuf = srcbuf++;      /* max time */
2752         sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2753         idx++;
2754         srcbuf++;
2755         sprintf(a_cmData->data[idx], "%d", *srcbuf);    /* sum bytes */
2756         idx++;
2757         srcbuf++;
2758         sprintf(a_cmData->data[idx], "%d", *srcbuf);    /* min bytes */
2759         idx++;
2760         srcbuf++;
2761         sprintf(a_cmData->data[idx], "%d", *srcbuf);    /* max bytes */
2762         idx++;
2763         srcbuf++;
2764         for (j = 0; j < AFS_STATS_NUM_XFER_BUCKETS; j++) {
2765             sprintf(a_cmData->data[idx], "%d", *srcbuf);        /* bucket[j] */
2766             idx++;
2767             srcbuf++;
2768         }
2769     }
2770
2771     /*printf("Ending index value = %d\n",idx-1); */
2772
2773     /* copy CM operations timings */
2774
2775     srcbuf = (afs_int32 *) (fullP->rpc.cmRPCTimes);
2776     for (i = 0; i < AFS_STATS_NUM_CM_RPC_OPS; i++) {
2777         sprintf(a_cmData->data[idx], "%d", *srcbuf);    /* numOps */
2778         idx++;
2779         srcbuf++;
2780         sprintf(a_cmData->data[idx], "%d", *srcbuf);    /* numSuccesses */
2781         idx++;
2782         srcbuf++;
2783         tmpbuf = srcbuf++;      /* sum time */
2784         sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2785         idx++;
2786         srcbuf++;
2787         tmpbuf = srcbuf++;      /* sqr time */
2788         sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2789         idx++;
2790         srcbuf++;
2791         tmpbuf = srcbuf++;      /* min time */
2792         sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2793         idx++;
2794         srcbuf++;
2795         tmpbuf = srcbuf++;      /* max time */
2796         sprintf(a_cmData->data[idx], "%d.%06d", *tmpbuf, *srcbuf);
2797         idx++;
2798         srcbuf++;
2799     }
2800
2801     /*printf("Ending index value = %d\n",idx-1); */
2802
2803     /* copy authentication info */
2804
2805     srcbuf = (afs_int32 *) & (fullP->authent);
2806     numLongs = sizeof(struct afs_stats_AuthentInfo) / sizeof(afs_int32);
2807     for (i = 0; i < numLongs; i++) {
2808         sprintf(a_cmData->data[idx], "%d", *srcbuf);
2809         idx++;
2810         srcbuf++;
2811     }
2812
2813     /*printf("Ending index value = %d\n",idx-1); */
2814
2815     /* copy CM [un]replicated access info */
2816
2817     srcbuf = (afs_int32 *) & (fullP->accessinf);
2818     numLongs = sizeof(struct afs_stats_AccessInfo) / sizeof(afs_int32);
2819     for (i = 0; i < numLongs; i++) {
2820         sprintf(a_cmData->data[idx], "%d", *srcbuf);
2821         idx++;
2822         srcbuf++;
2823     }
2824
2825     /*printf("Ending index value = %d\n",idx-1); */
2826     return (0);
2827
2828 }                               /* cm_Results_ltoa */
2829
2830
2831 /*-----------------------------------------------------------------------
2832  * Function:    check_cm_thresholds()
2833  *
2834  * Description:
2835  *      Checks the thresholds and sets the overflow flag. Recall that the
2836  *      thresholds for each host are stored in the hostEntry lists
2837  *      [fs/cm]nameList arrays. The probe results are passed to this 
2838  *      function in the display-ready format - ie., as strings. Though
2839  *      this looks stupid the overhead incurred in converting the strings
2840  *      back to floats and comparing them is insignificant and 
2841  *      programming is easier this way. 
2842  *      The threshold flags are a part of the display structures
2843  *      curr_[fs/cm]Data.
2844  *
2845  * Returns:
2846  *      0
2847  *----------------------------------------------------------------------*/
2848
2849 int
2850 check_cm_thresholds(a_hostEntry, a_Data)
2851      struct afsmon_hostEntry *a_hostEntry;      /* ptr to hostEntry */
2852      struct cm_Display_Data *a_Data;    /* ptr to cm data to be displayed */
2853
2854 {                               /* check_cm_thresholds */
2855
2856     static char rn[] = "check_cm_thresholds";
2857     struct Threshold *threshP;
2858     double tValue;              /* threshold value */
2859     double pValue;              /* probe value */
2860     int i;
2861     int idx;
2862     int count;                  /* number of thresholds exceeded */
2863
2864     if (afsmon_debug) {
2865         fprintf(debugFD, "[ %s ] Called, a_hostEntry= %d, a_Data= %d\n", rn,
2866                 a_hostEntry, a_Data);
2867         fflush(debugFD);
2868     }
2869
2870     if (a_hostEntry->numThresh == 0) {
2871         /* store in ovf count ?? */
2872         return (0);
2873     }
2874
2875     count = 0;
2876     threshP = a_hostEntry->thresh;
2877     for (i = 0; i < a_hostEntry->numThresh; i++) {
2878         if (threshP->itemName[0] == '\0') {
2879             threshP++;
2880             continue;
2881         }
2882         idx = threshP->index;   /* positional index to the data array */
2883         tValue = atof(threshP->threshVal);      /* threshold value */
2884         pValue = atof(a_Data->data[idx]);       /* probe value */
2885         if (pValue > tValue) {
2886
2887             if (afsmon_debug) {
2888                 fprintf(debugFD,
2889                         "[ %s ] cm = %s, thresh ovf for %s, threshold= %s, probevalue= %s\n",
2890                         rn, a_hostEntry->hostName, threshP->itemName,
2891                         threshP->threshVal, a_Data->data[idx]);
2892                 fflush(debugFD);
2893             }
2894
2895             /* if the threshold is crossed, call the handler function
2896              * only if this was a transition -ie, if the threshold was
2897              * crossed in the last probe too just count & keep quite! */
2898
2899             if (!a_Data->threshOvf[idx]) {
2900                 a_Data->threshOvf[idx] = 1;
2901                 /* call the threshold handler if provided */
2902                 if (threshP->handler[0] != '\0') {
2903                     if (afsmon_debug) {
2904                         fprintf(debugFD, "[ %s ] Calling ovf handler %s\n",
2905                                 rn, threshP->handler);
2906                         fflush(debugFD);
2907                     }
2908                     execute_thresh_handler(threshP->handler, a_Data->hostName,
2909                                            CM, threshP->itemName,
2910                                            threshP->threshVal,
2911                                            a_Data->data[idx]);
2912                 }
2913             }
2914
2915             count++;
2916         } else
2917             /* in case threshold was previously crossed, blank it out */
2918             a_Data->threshOvf[idx] = 0;
2919         threshP++;
2920     }
2921     /* store the overflow count */
2922     a_Data->ovfCount = count;
2923
2924     return (0);
2925 }                               /* check_cm_thresholds */
2926
2927
2928 /*-----------------------------------------------------------------------
2929  * save_CM_data_forDisplay()
2930  *
2931  * Description:
2932  *      Does the following:
2933  *      - if the probe number changed (ie, a cycle completed) curr_cmData
2934  *      is copied to prev_cmData, curr_cmData zeroed and refresh the 
2935  *      overview screen and file server screen with the new data.
2936  *      - store the results of the current probe from xstat_cm_Results into
2937  *      curr_cmData. ie., convert longs to strings.
2938  *      - check the thresholds 
2939  *
2940  * Returns:
2941  *      Success: 0
2942  *      Failure: Exits afsmonitor.
2943  *
2944  *----------------------------------------------------------------------*/
2945
2946 int
2947 save_CM_data_forDisplay(a_cmResults)
2948      struct xstat_cm_ProbeResults *a_cmResults;
2949 {                               /* save_CM_data_forDisplay */
2950
2951     static char rn[] = "save_CM_data_forDisplay";       /* routine name */
2952     struct cm_Display_Data *curr_cmDataP;
2953     struct cm_Display_Data *prev_cmDataP;
2954     struct afsmon_hostEntry *curr_host;
2955     static int probes_Received = 0;     /* number of probes reveived in
2956                                          * the current cycle. If this is equal to numFS we got all
2957                                          * the data we want in this cycle and can now display it */
2958     int numBytes;
2959     int done;
2960     int code;
2961     int okay;
2962     int i;
2963
2964     if (afsmon_debug) {
2965         fprintf(debugFD, "[ %s ] Called, a_cmResults= %d\n", rn, a_cmResults);
2966         fflush(debugFD);
2967     }
2968
2969     /* store results in the display array */
2970
2971     okay = 0;
2972     curr_cmDataP = curr_cmData;
2973     for (i = 0; i < numCM; i++) {
2974         if ((strcasecmp(curr_cmDataP->hostName, a_cmResults->connP->hostName))
2975             == 0) {
2976             okay = 1;
2977             break;
2978         }
2979         curr_cmDataP++;
2980     }
2981
2982     if (!okay) {
2983         fprintf(stderr,
2984                 "[ %s ] Could not insert CM probe results for host %s in cm display array\n",
2985                 rn, a_cmResults->connP->hostName);
2986         afsmon_Exit(95);
2987     }
2988
2989     /*  Check the status of the probe. If it succeeded, we store its
2990      * results in the display data structure. If it failed we only mark 
2991      * the failed status in the display data structure. */
2992
2993
2994     if (a_cmResults->probeOK) { /* 1 => notOK the xstat results */
2995         curr_cmDataP->probeOK = 0;
2996
2997         /* print the probe status */
2998         if (afsmon_debug) {
2999             fprintf(debugFD, "\n\t\t ----- cm display data ------\n");
3000             fprintf(debugFD, "HostName = %s  PROBE FAILED \n",
3001                     curr_cmDataP->hostName);
3002             fflush(debugFD);
3003         }
3004
3005     } else {                    /* probe succeeded, update display data structures */
3006         curr_cmDataP->probeOK = 1;
3007
3008
3009         /* covert longs to strings and place them in curr_cmDataP */
3010         cm_Results_ltoa(curr_cmDataP, a_cmResults);
3011
3012         /* compare with thresholds and set the overflow flags.
3013          * note that the threshold information is in the hostEntry structure and 
3014          * each threshold item has a positional index associated with it */
3015
3016         /* locate the hostEntry for this host */
3017         done = 0;
3018         curr_host = CMnameList;
3019         for (i = 0; i < numCM; i++) {
3020             if (strcasecmp(curr_host->hostName, a_cmResults->connP->hostName)
3021                 == 0) {
3022                 done = 1;
3023                 break;
3024             }
3025             curr_host = curr_host->next;
3026         }
3027         if (!done)
3028             afsmon_Exit(100);
3029
3030         code = check_cm_thresholds(curr_host, curr_cmDataP);
3031         if (code) {
3032             fprintf(stderr, "[ %s ] Error in checking thresholds\n", rn);
3033             afsmon_Exit(105);
3034         }
3035
3036
3037         /* print the info we just saved */
3038         if (afsmon_debug) {
3039             fprintf(debugFD, "\n\t\t ----- CM display data ------\n");
3040             fprintf(debugFD, "HostName = %s\n", curr_cmDataP->hostName);
3041             for (i = 0; i < NUM_CM_STAT_ENTRIES; i++) {
3042                 switch (i) {
3043                 case 0:
3044                     fprintf(debugFD, "\t -- Overall Perf Info --\n");
3045                     break;
3046                 case 39:
3047                     fprintf(debugFD,
3048                             "\t -- File Server up/down stats - same cell --\n");
3049                     break;
3050                 case 64:
3051                     fprintf(debugFD,
3052                             "\t -- File Server up/down stats - diff cell --\n");
3053                     break;
3054                 case 89:
3055                     fprintf(debugFD,
3056                             "\t -- VL server up/down stats - same cell --\n");
3057                     break;
3058                 case 114:
3059                     fprintf(debugFD,
3060                             "\t -- VL server up/down stats - diff cell --\n");
3061                     break;
3062                 case 139:
3063                     fprintf(debugFD, "\t -- FS Operation Timings --\n");
3064                     break;
3065                 case 279:
3066                     fprintf(debugFD, "\t -- FS Error Info --\n");
3067                     break;
3068                 case 447:
3069                     fprintf(debugFD, "\t -- FS Transfer Timings --\n");
3070                     break;
3071                 case 475:
3072                     fprintf(debugFD, "\t -- CM Operations Timings --\n");
3073                     break;
3074                 case 510:
3075                     fprintf(debugFD, "\t -- Authentication Info --\n");
3076                     break;
3077                 case 522:
3078                     fprintf(debugFD, "\t -- Access Info --\n");
3079                     break;
3080                 default:
3081                     break;
3082                 }
3083
3084                 fprintf(debugFD, "%20s  %30s %s\n", curr_cmDataP->data[i],
3085                         cm_varNames[i],
3086                         curr_cmDataP->threshOvf[i] ? "(ovf)" : "");
3087             }
3088             fprintf(debugFD, "\t\t--------------------------------\n\n");
3089         }
3090
3091     }                           /* if the probe succeeded, update the display data structures */
3092
3093     /* if we have received a reply from all the hosts for this probe cycle,
3094      * it is time to display the data */
3095
3096     probes_Received++;
3097     if (probes_Received == numCM) {
3098         probes_Received = 0;
3099
3100         if (afsmon_cm_curr_probeNum != afsmon_cm_prev_probeNum + 1) {
3101             sprintf(errMsg, "[ %s ] Probe number %d missed! \n", rn,
3102                     afsmon_cm_prev_probeNum + 1);
3103             afsmon_Exit(110);
3104         } else
3105             afsmon_cm_prev_probeNum++;
3106
3107
3108         /* backup the display data of the probe cycle that just completed -
3109          * ie., store curr_cmData in prev_cmData */
3110
3111         memcpy((char *)prev_cmData, (char *)curr_cmData,
3112                (numCM * sizeof(struct cm_Display_Data)));
3113
3114
3115         /* initialize curr_cmData but retain the threshold flag information.
3116          * The previous state of threshold flags is used in check_cm_thresholds() */
3117
3118         curr_cmDataP = curr_cmData;
3119         numBytes = NUM_CM_STAT_ENTRIES * CM_STAT_STRING_LEN;
3120         for (i = 0; i < numCM; i++) {
3121             curr_cmDataP->probeOK = 0;
3122             curr_cmDataP->ovfCount = 0;
3123             memset((char *)curr_cmDataP->data, 0, numBytes);
3124             curr_cmDataP++;
3125         }
3126
3127         /* prev_cmData now contains all the information for the probe cycle
3128          * that just completed. Now count the number of threshold overflows for
3129          * use in the overview screen */
3130
3131         prev_cmDataP = prev_cmData;
3132         num_cm_alerts = 0;
3133         numHosts_oncm_alerts = 0;
3134         for (i = 0; i < numCM; i++) {
3135             if (!prev_cmDataP->probeOK) {       /* if probe failed */
3136                 num_cm_alerts++;
3137                 numHosts_oncm_alerts++;
3138             } else if (prev_cmDataP->ovfCount) {        /* overflows ?? */
3139                 num_cm_alerts += prev_cmDataP->ovfCount;
3140                 numHosts_oncm_alerts++;
3141             }
3142             prev_cmDataP++;
3143         }
3144         if (afsmon_debug)
3145             fprintf(debugFD, "Number of CM alerts = %d (on %d hosts)\n",
3146                     num_cm_alerts, numHosts_oncm_alerts);
3147
3148
3149         /* flag that the data is now ready to be displayed */
3150         cm_Data_Available = 1;
3151
3152         /* update the Overview frame (only CM info) */
3153         ovw_refresh(ovw_currPage, OVW_UPDATE_CM);
3154
3155         /* update the Cache Managers frame */
3156         cm_refresh(cm_currPage, cm_curr_LCol);
3157
3158     }
3159
3160
3161     return (0);
3162 }                               /* save_CM_data_forDisplay */
3163
3164
3165
3166 /*-----------------------------------------------------------------------
3167  * afsmon_CM_Handler()
3168  *
3169  * Description:
3170  *      This is the Cache Manager probe Handler. It updates the afsmonitor
3171  *      probe counts, cm circular buffer indices and calls the functions
3172  *      to process the results of this probe.
3173  *
3174  * Returns:
3175  *      Success: 0
3176  *      Failure: Exits afsmonitor.
3177  *----------------------------------------------------------------------*/
3178
3179 int
3180 afsmon_CM_Handler()
3181 {                               /* afsmon_CM_Handler() */
3182     static char rn[] = "afsmon_CM_Handler";     /* routine name */
3183     int code;                   /* return status */
3184     int newProbeCycle;          /* start of new probe cycle ? */
3185
3186     if (afsmon_debug) {
3187         fprintf(debugFD,
3188                 "[ %s ] Called, hostName= %s, probeNum= %d, status= %s\n", rn,
3189                 xstat_cm_Results.connP->hostName, xstat_cm_Results.probeNum,
3190                 xstat_cm_Results.probeOK ? "FAILED" : "OK");
3191         fflush(debugFD);
3192     }
3193
3194
3195     /* print the probe results to output file */
3196     if (afsmon_output) {
3197         code = afsmon_cmOutput(output_filename, afsmon_detOutput);
3198         if (code) {
3199             fprintf(stderr,
3200                     "[ %s ] output to file %s returned error code=%d\n", rn,
3201                     output_filename, code);
3202         }
3203     }
3204
3205     /* Update current probe number and circular buffer index. if current 
3206      * probenum changed make sure it is only by 1 */
3207
3208     newProbeCycle = 0;
3209     if (xstat_cm_Results.probeNum != afsmon_cm_curr_probeNum) {
3210         if (xstat_cm_Results.probeNum == afsmon_cm_curr_probeNum + 1) {
3211             afsmon_cm_curr_probeNum++;
3212             newProbeCycle = 1;
3213             if (num_bufSlots)
3214                 afsmon_cm_curr_CBindex =
3215                     (afsmon_cm_curr_probeNum - 1) % num_bufSlots;
3216         } else {
3217             fprintf(stderr, "[ %s ] probe number %d-1 missed\n", rn,
3218                     xstat_cm_Results.probeNum);
3219             afsmon_Exit(115);
3220         }
3221     }
3222
3223     /* save the results of this probe in the CM buffer */
3224     if (num_bufSlots)
3225         save_CM_results_inCB(newProbeCycle);
3226
3227     /* store the results of the current probe in the cm data display structure.
3228      * if the current probe number changed, swap the current and previous display
3229      * structures. note that the display screen is updated from these structures 
3230      * and should start showing the data of the just completed probe cycle */
3231
3232     save_CM_data_forDisplay(&xstat_cm_Results);
3233
3234     return (0);
3235 }
3236
3237 /*-----------------------------------------------------------------------
3238  * init_fs_buffers()
3239  *
3240  * Description:
3241  *      Allocate and Initialize circular buffers for file servers.
3242  *
3243  * Returns:
3244  *      Success: 0
3245  *      Failure to allocate memory: exits afsmonitor.
3246  *----------------------------------------------------------------------*/
3247
3248 int
3249 init_fs_buffers()
3250 {                               /* init_fs_buffers() */
3251     static char rn[] = "init_fs_buffers";       /* routine name */
3252     struct afsmon_fs_Results_list *new_fslist_item;     /* ptr for new struct */
3253     struct afsmon_fs_Results_list *tmp_fslist_item;     /* temp ptr */
3254     struct xstat_fs_ProbeResults *new_fsPR;     /* ptr for new struct  */
3255     int i, j;
3256     int bufslot;
3257     int numfs;
3258
3259
3260     if (afsmon_debug) {
3261         fprintf(debugFD, "[ %s ] Called\n", rn);
3262         fflush(debugFD);
3263     }
3264
3265     /* allocate memory for the circular buffer of pointers */
3266
3267     afsmon_fs_ResultsCB = (struct afsmon_fs_Results_CBuffer *)
3268         malloc(sizeof(struct afsmon_fs_Results_CBuffer) * num_bufSlots);
3269
3270     /* initialize the fs circular buffer */
3271     for (i = 0; i < num_bufSlots; i++) {
3272         afsmon_fs_ResultsCB[i].list = (struct afsmon_fs_Results_list *)0;
3273         afsmon_fs_ResultsCB[i].probeNum = 0;
3274     }
3275
3276     /* create  a list of numFS items to store fs probe results for 
3277      * each slot in CB */
3278
3279     if (numFS) {                /* if we have file servers to monitor */
3280         for (bufslot = 0; bufslot < num_bufSlots; bufslot++) {
3281             numfs = numFS;      /* get the number of servers */
3282             while (numfs--) {
3283
3284                 /* if any of these mallocs fail we only need to free the memory we
3285                  * have allocated in this iteration. the rest of it which is in a 
3286                  * proper linked list will be freed in afsmon_Exit */
3287
3288                 /* allocate memory for an fs list item */
3289                 new_fslist_item = (struct afsmon_fs_Results_list *)
3290                     malloc(sizeof(struct afsmon_fs_Results_list));
3291                 if (new_fslist_item == (struct afsmon_fs_Results_list *)0)
3292                     return (-1);
3293
3294                 /* allocate memory to store xstat_fs_Results */
3295                 new_fsPR = (struct xstat_fs_ProbeResults *)
3296                     malloc(sizeof(struct xstat_fs_ProbeResults));
3297                 if (new_fsPR == (struct xstat_fs_ProbeResults *)0) {
3298                     free(new_fslist_item);
3299                     return (-1);
3300                 }
3301                 new_fsPR->connP = (struct xstat_fs_ConnectionInfo *)
3302                     malloc(sizeof(struct xstat_fs_ConnectionInfo));
3303                 if (new_fsPR->connP == (struct xstat_fs_ConnectionInfo *)0) {
3304                     free(new_fslist_item);
3305                     free(new_fsPR);
3306                     return (-1);
3307                 }
3308
3309                 /* >>>  need to allocate rx connection info structure here <<< */
3310
3311                 new_fsPR->data.AFS_CollData_val =
3312                     (afs_int32 *) malloc(XSTAT_FS_FULLPERF_RESULTS_LEN *
3313                                          sizeof(afs_int32));
3314                 if (new_fsPR->data.AFS_CollData_val == NULL) {
3315                     free(new_fslist_item);
3316                     free(new_fsPR->connP);
3317                     free(new_fsPR);
3318                     return (-1);
3319                 }
3320
3321                 /* initialize this list entry */
3322                 new_fslist_item->fsResults = new_fsPR;
3323                 new_fslist_item->empty = 1;
3324                 new_fslist_item->next = (struct afsmon_fs_Results_list *)0;
3325
3326                 /* store it at the end of the fs list in the current CB slot */
3327                 if (afsmon_fs_ResultsCB[bufslot].list ==
3328                     (struct afsmon_fs_Results_list *)0)
3329                     afsmon_fs_ResultsCB[bufslot].list = new_fslist_item;
3330                 else {
3331                     tmp_fslist_item = afsmon_fs_ResultsCB[bufslot].list;
3332                     j = 0;
3333                     while (tmp_fslist_item !=
3334                            (struct afsmon_fs_Results_list *)0) {
3335                         if (tmp_fslist_item->next ==
3336                             (struct afsmon_fs_Results_list *)0)
3337                             break;
3338                         tmp_fslist_item = tmp_fslist_item->next;
3339                         if (++j > numFS) {
3340                             /* something goofed. exit */
3341                             fprintf(stderr, "[ %s ] list creation error\n",
3342                                     rn);
3343                             return (-1);
3344                         }
3345                     }
3346                     tmp_fslist_item->next = new_fslist_item;
3347                 }
3348
3349             }                   /* while servers */
3350         }                       /* for each buffer slot */
3351     }                           /* if we have file servers to monitor */
3352     return (0);
3353 }
3354
3355 /*-----------------------------------------------------------------------
3356  * init_cm_buffers()
3357  *
3358  * Description:
3359  *      Allocate and Initialize circular buffers for cache managers.
3360  *
3361  * Returns:
3362  *      Success: 0
3363  *      Failure to allocate memory: exits afsmonitor.
3364  *----------------------------------------------------------------------*/
3365
3366 int
3367 init_cm_buffers()
3368 {                               /* init_cm_buffers() */
3369     static char rn[] = "init_cm_buffers";       /* routine name */
3370     struct afsmon_cm_Results_list *new_cmlist_item;     /* ptr for new struct */
3371     struct afsmon_cm_Results_list *tmp_cmlist_item;     /* temp ptr */
3372     struct xstat_cm_ProbeResults *new_cmPR;     /* ptr for new struct  */
3373     int i, j;
3374     int bufslot;
3375     int numcm;
3376
3377     if (afsmon_debug) {
3378         fprintf(debugFD, "[ %s ] Called\n", rn);
3379         fflush(debugFD);
3380     }
3381
3382     /* allocate memory for the circular buffer of pointers */
3383     afsmon_cm_ResultsCB = (struct afsmon_cm_Results_CBuffer *)
3384         malloc(sizeof(struct afsmon_cm_Results_CBuffer) * num_bufSlots);
3385
3386     /* initialize the fs circular buffer */
3387     for (i = 0; i < num_bufSlots; i++) {
3388         afsmon_cm_ResultsCB[i].list = (struct afsmon_cm_Results_list *)0;
3389         afsmon_cm_ResultsCB[i].probeNum = 0;
3390     }
3391
3392     /* create  a list of numCM items to store fs probe results for 
3393      * each slot in CB */
3394
3395     if (numCM) {                /* if we have file servers to monitor */
3396         for (bufslot = 0; bufslot < num_bufSlots; bufslot++) {
3397             numcm = numCM;      /* get the number of servers */
3398             while (numcm--) {
3399
3400                 /* if any of these mallocs fail we only need to free the memory we
3401                  * have allocated in this iteration. the rest of it which is in a 
3402                  * proper linked list will be freed in afsmon_Exit */
3403
3404                 /* allocate memory for an fs list item */
3405                 new_cmlist_item = (struct afsmon_cm_Results_list *)
3406                     malloc(sizeof(struct afsmon_cm_Results_list));
3407                 if (new_cmlist_item == (struct afsmon_cm_Results_list *)0)
3408                     return (-1);
3409
3410                 /* allocate memory to store xstat_cm_Results */
3411                 new_cmPR = (struct xstat_cm_ProbeResults *)
3412                     malloc(sizeof(struct xstat_cm_ProbeResults));
3413                 if (new_cmPR == (struct xstat_cm_ProbeResults *)0) {
3414                     free(new_cmlist_item);
3415                     return (-1);
3416                 }
3417                 new_cmPR->connP = (struct xstat_cm_ConnectionInfo *)
3418                     malloc(sizeof(struct xstat_cm_ConnectionInfo));
3419                 if (new_cmPR->connP == (struct xstat_cm_ConnectionInfo *)0) {
3420                     free(new_cmlist_item);
3421                     free(new_cmPR);
3422                     return (-1);
3423                 }
3424
3425                 /* >>>  need to allocate rx connection info structure here <<< */
3426
3427                 new_cmPR->data.AFSCB_CollData_val =
3428                     (afs_int32 *) malloc(XSTAT_CM_FULLPERF_RESULTS_LEN *
3429                                          sizeof(afs_int32));
3430                 if (new_cmPR->data.AFSCB_CollData_val == NULL) {
3431                     free(new_cmlist_item);
3432                     free(new_cmPR->connP);
3433                     free(new_cmPR);
3434                     return (-1);
3435                 }
3436
3437                 /* initialize this list entry */
3438                 new_cmlist_item->cmResults = new_cmPR;
3439                 new_cmlist_item->empty = 1;
3440                 new_cmlist_item->next = (struct afsmon_cm_Results_list *)0;
3441
3442                 /* store it at the end of the cm list in the current CB slot */
3443                 if (afsmon_cm_ResultsCB[bufslot].list ==
3444                     (struct afsmon_cm_Results_list *)0)
3445                     afsmon_cm_ResultsCB[bufslot].list = new_cmlist_item;
3446                 else {
3447                     tmp_cmlist_item = afsmon_cm_ResultsCB[bufslot].list;
3448                     j = 0;
3449                     while (tmp_cmlist_item !=
3450                            (struct afsmon_cm_Results_list *)0) {
3451                         if (tmp_cmlist_item->next ==
3452                             (struct afsmon_cm_Results_list *)0)
3453                             break;
3454                         tmp_cmlist_item = tmp_cmlist_item->next;
3455                         if (++j > numCM) {
3456                             /* something goofed. exit */
3457                             fprintf(stderr, "[ %s ] list creation error\n",
3458                                     rn);
3459                             return (-1);
3460                         }
3461                     }
3462                     tmp_cmlist_item->next = new_cmlist_item;
3463                 }
3464
3465             }                   /* while servers */
3466         }                       /* for each buffer slot */
3467     }
3468     /* if we have file servers to monitor */
3469     /* print the CB to make sure it is right */
3470     Print_CM_CB();
3471
3472     return (0);
3473 }                               /* init_cm_buffers() */
3474
3475
3476 /*-------------------------------------------------------------------------
3477  * init_print_buffers()
3478  *
3479  * Description:
3480  *      Allocate and initialize the buffers used for printing results
3481  *      to the display screen. These buffers store the current and 
3482  *      previous probe results in ascii format. 
3483  *
3484  * Returns:
3485  *      Success: 0
3486  *      Failure: < 0
3487  *------------------------------------------------------------------------*/
3488
3489 int
3490 init_print_buffers()
3491 {                               /* init_print_buffers */
3492
3493     static char rn[] = "init_print_buffers";    /* routine name */
3494     struct fs_Display_Data *tmp_fsData1;        /* temp pointers */
3495     struct fs_Display_Data *tmp_fsData2;
3496     struct cm_Display_Data *tmp_cmData1;
3497     struct cm_Display_Data *tmp_cmData2;
3498     struct afsmon_hostEntry *tmp_fsNames;
3499     struct afsmon_hostEntry *tmp_cmNames;
3500     int i;
3501     int numBytes;
3502
3503     if (afsmon_debug) {
3504         fprintf(debugFD, "[ %s ] Called\n", rn);
3505         fflush(debugFD);
3506     }
3507
3508     /* allocate numFS blocks of the FS print structure. */
3509
3510     /* we need two instances of this structure - one (curr_fsData) for storing
3511      * the results of the fs probes currently in progress and another (prev_fsData)
3512      * for the last completed probe. The display is updated from the contents of
3513      * prev_fsData. The pointers curr_fsData & prev_fsData are switched whenever 
3514      * the probe number changes */
3515
3516     if (numFS) {
3517         numBytes = numFS * sizeof(struct fs_Display_Data);
3518         curr_fsData = (struct fs_Display_Data *)malloc(numBytes);
3519         if (curr_fsData == (struct fs_Display_Data *)0) {
3520             fprintf(stderr, "[ %s ] Memory allocation failure\n", rn);
3521             return (-1);
3522         }
3523         memset(curr_fsData, 0, numBytes);
3524
3525         numBytes = numFS * sizeof(struct fs_Display_Data);
3526         prev_fsData = (struct fs_Display_Data *)malloc(numBytes);
3527         if (prev_fsData == (struct fs_Display_Data *)0) {
3528             fprintf(stderr, "[ %s ] Memory allocation failure\n", rn);
3529             return (-5);
3530         }
3531         memset(prev_fsData, 0, numBytes);
3532
3533         /* fill in the host names */
3534         tmp_fsData1 = curr_fsData;
3535         tmp_fsData2 = curr_fsData;
3536         tmp_fsNames = FSnameList;
3537         for (i = 0; i < numFS; i++) {
3538             strncpy(tmp_fsData1->hostName, tmp_fsNames->hostName,
3539                     HOST_NAME_LEN);
3540             strncpy(tmp_fsData2->hostName, tmp_fsNames->hostName,
3541                     HOST_NAME_LEN);
3542             tmp_fsData1++;
3543             tmp_fsData2++;
3544             tmp_fsNames = tmp_fsNames->next;;
3545         }
3546
3547     }
3548
3549
3550
3551     /* if file servers to monitor */
3552     /* allocate numCM blocks of the CM print structure */
3553     /* we need two instances of this structure for the same reasons as above */
3554     if (numCM) {
3555         numBytes = numCM * sizeof(struct cm_Display_Data);
3556
3557         curr_cmData = (struct cm_Display_Data *)malloc(numBytes);
3558         if (curr_cmData == (struct cm_Display_Data *)0) {
3559             fprintf(stderr, "[ %s ] Memory allocation failure\n", rn);
3560             return (-10);
3561         }
3562         memset(curr_cmData, 0, numBytes);
3563
3564         numBytes = numCM * sizeof(struct cm_Display_Data);
3565         prev_cmData = (struct cm_Display_Data *)malloc(numBytes);
3566         if (prev_cmData == (struct cm_Display_Data *)0) {
3567             fprintf(stderr, "[ %s ] Memory allocation failure\n", rn);
3568             return (-15);
3569         }
3570         memset(prev_cmData, 0, numBytes);
3571
3572         /* fill in the host names */
3573         tmp_cmData1 = curr_cmData;
3574         tmp_cmData2 = curr_cmData;
3575         tmp_cmNames = CMnameList;
3576         for (i = 0; i < numCM; i++) {
3577             strncpy(tmp_cmData1->hostName, tmp_cmNames->hostName,
3578                     HOST_NAME_LEN);
3579             strncpy(tmp_cmData2->hostName, tmp_cmNames->hostName,
3580                     HOST_NAME_LEN);
3581             tmp_cmData1++;
3582             tmp_cmData2++;
3583             tmp_cmNames = tmp_cmNames->next;;
3584         }
3585
3586     }
3587     /* if cache managers to monitor */
3588     return (0);
3589
3590 }                               /* init_print_buffers */
3591
3592 /*-----------------------------------------------------------------------
3593  * quit_signal()
3594  *
3595  * Description:
3596  *      Trap the interrupt signal. This function is useful only until
3597  *      gtx is initialized.
3598  *----------------------------------------------------------------------*/
3599
3600 void
3601 quit_signal(sig)
3602      int sig;
3603 {                               /* quit_signal */
3604     static char *rn = "quit_signal";    /* routine name */
3605
3606     fprintf(stderr, "Received signal %d \n", sig);
3607     afsmon_Exit(120);
3608 }                               /* quit_signal */
3609
3610
3611
3612 /*-----------------------------------------------------------------------
3613  * afsmon_execute()
3614  *
3615  * Description:
3616  *      This is where we start it all. Initialize an array of sockets for
3617  *      file servers and cache cache managers and call the xstat_[fs/cm]_Init
3618  *      routines. The last step is to call the gtx input server which 
3619  *      grabs control of the keyboard.
3620  *
3621  * Returns:
3622  *      Does not return. Control is periodically returned to the afsmonitor
3623  *      thru afsmon_[FS/CM]_Handler() routines and also through the gtx
3624  *      keyboard handler calls.
3625  *
3626  *----------------------------------------------------------------------*/
3627
3628 int
3629 afsmon_execute()
3630 {                               /* afsmon_execute() */
3631     static char rn[] = "afsmon_execute";        /* routine name */
3632     static char fullhostname[128];      /* full host name */
3633     struct sockaddr_in *FSSktArray;     /* fs socket array */
3634     int FSsktbytes;             /* num bytes in above */
3635     struct sockaddr_in *CMSktArray;     /* cm socket array */
3636     int CMsktbytes;             /* num bytes in above */
3637     struct sockaddr_in *curr_skt;       /* ptr to current socket */
3638     struct afsmon_hostEntry *curr_FS;   /* ptr to FS name list */
3639     struct afsmon_hostEntry *curr_CM;   /* ptr to CM name list */
3640     struct hostent *he;         /* host entry */
3641     afs_int32 *collIDP;         /* ptr to collection ID */
3642     int numCollIDs;             /* number of collection IDs */
3643     int FSinitFlags = 0;        /* flags for xstat_fs_Init */
3644     int CMinitFlags = 0;        /* flags for xstat_cm_Init */
3645     int code;                   /* function return code */
3646     struct timeval tv;          /* time structure */
3647
3648     if (afsmon_debug) {
3649         fprintf(debugFD, "[ %s ] Called\n", rn);
3650         fflush(debugFD);
3651     }
3652
3653
3654     /* process file server entries */
3655     if (numFS) {
3656         /* Allocate an array of sockets for each fileserver we monitor */
3657
3658         FSsktbytes = numFS * sizeof(struct sockaddr_in);
3659         FSSktArray = (struct sockaddr_in *)malloc(FSsktbytes);
3660         if (FSSktArray == (struct sockaddr_in *)0) {
3661             fprintf(stderr,
3662                     "[ %s ] cannot malloc %d sockaddr_ins for fileservers\n",
3663                     rn, numFS);
3664             return (-1);
3665         }
3666
3667         memset(FSSktArray, 0, FSsktbytes);
3668
3669         /* Fill in the socket information for each fileserve */
3670
3671         curr_skt = FSSktArray;
3672         curr_FS = FSnameList;   /* FS name list header */
3673         while (curr_FS) {
3674             strncpy(fullhostname, curr_FS->hostName, sizeof(fullhostname));
3675             he = GetHostByName(fullhostname);
3676             if (he == NULL) {
3677                 fprintf(stderr, "[ %s ] Cannot get host info for %s\n", rn,
3678                         fullhostname);
3679                 return (-1);
3680             }
3681             strncpy(curr_FS->hostName, he->h_name, HOST_NAME_LEN);      /* complete name */
3682             memcpy(&(curr_skt->sin_addr.s_addr), he->h_addr, 4);
3683             curr_skt->sin_family = AF_INET;             /*Internet family */
3684             curr_skt->sin_port = htons(7000);   /*FileServer port */
3685 #ifdef STRUCT_SOCKADDR_HAS_SA_LEN
3686             curr_skt->sin_len = sizeof(struct sockaddr_in);
3687 #endif
3688
3689             /* get the next dude */
3690             curr_skt++;
3691             curr_FS = curr_FS->next;
3692         }
3693
3694         /* initialize collection IDs. We need only one entry since we collect
3695          * all the information from xstat */
3696
3697         numCollIDs = 1;
3698         collIDP = (afs_int32 *) malloc(sizeof(afs_int32));
3699         if (collIDP == NULL) {
3700             fprintf(stderr,
3701                     "[ %s ] failed to allocate a measely afs_int32 word.Argh!\n",
3702                     rn);
3703             return (-1);
3704         }
3705         *collIDP = 2;           /* USE A macro for this */
3706
3707         FSinitFlags = 0;
3708         if (afsmon_onceOnly)    /* option not provided at this time */
3709             FSinitFlags |= XSTAT_FS_INITFLAG_ONE_SHOT;
3710
3711         if (afsmon_debug) {
3712             fprintf(debugFD, "[ %s ] Calling xstat_fs_Init \n", rn);
3713             fflush(debugFD);
3714         }
3715
3716         code = xstat_fs_Init(numFS,     /*Num servers */
3717                              FSSktArray,        /*File Server socket array */
3718                              afsmon_probefreq,  /*probe frequency */
3719                              afsmon_FS_Handler, /*Handler routine */
3720                              FSinitFlags,       /*Initialization flags */
3721                              numCollIDs,        /*Number of collection IDs */
3722                              collIDP);  /*Ptr to collection ID */
3723
3724         if (code) {
3725             fprintf(stderr, "[ %s ] xstat_fs_init returned error\n", rn);
3726             afsmon_Exit(125);
3727         }
3728
3729     }
3730
3731
3732     /* end of process fileserver entries */
3733     /* process cache manager entries */
3734     if (numCM) {
3735         /* Allocate an array of sockets for each cache manager we monitor */
3736
3737         CMsktbytes = numCM * sizeof(struct sockaddr_in);
3738         CMSktArray = (struct sockaddr_in *)malloc(CMsktbytes);
3739         if (CMSktArray == (struct sockaddr_in *)0) {
3740             fprintf(stderr,
3741                     "[ %s ] cannot malloc %d sockaddr_ins for CM entries\n",
3742                     rn, numCM);
3743             return (-1);
3744         }
3745
3746         memset(CMSktArray, 0, CMsktbytes);
3747
3748         /* Fill in the socket information for each CM        */
3749
3750         curr_skt = CMSktArray;
3751         curr_CM = CMnameList;   /* CM name list header */
3752         while (curr_CM) {
3753             strncpy(fullhostname, curr_CM->hostName, sizeof(fullhostname));
3754             he = GetHostByName(fullhostname);
3755             if (he == NULL) {
3756                 fprintf(stderr, "[ %s ] Cannot get host info for %s\n", rn,
3757                         fullhostname);
3758                 return (-1);
3759             }
3760             strncpy(curr_CM->hostName, he->h_name, HOST_NAME_LEN);      /* complete name */
3761             memcpy(&(curr_skt->sin_addr.s_addr), he->h_addr, 4);
3762 #if defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
3763             curr_skt->sin_family = AF_INET;             /*Internet family */
3764 #else
3765             curr_skt->sin_family = htons(AF_INET);      /*Internet family */
3766 #endif
3767             curr_skt->sin_port = htons(7001);   /*Cache Manager port */
3768 #ifdef STRUCT_SOCKADDR_HAS_SA_LEN
3769             curr_skt->sin_len = sizeof(struct sockaddr_in);
3770 #endif
3771
3772             /* get the next dude */
3773             curr_skt++;
3774             curr_CM = curr_CM->next;
3775         }
3776
3777         /* initialize collection IDs. We need only one entry since we collect
3778          * all the information from xstat */
3779
3780         numCollIDs = 1;
3781         collIDP = (afs_int32 *) malloc(sizeof(afs_int32));
3782         if (collIDP == NULL) {
3783             fprintf(stderr,
3784                     "[ %s ] failed to allocate a measely long word.Argh!\n",
3785                     rn);
3786             return (-1);
3787         }
3788         *collIDP = 2;           /* USE A macro for this */
3789
3790         CMinitFlags = 0;
3791         if (afsmon_onceOnly)    /* once only ? */
3792             CMinitFlags |= XSTAT_CM_INITFLAG_ONE_SHOT;
3793
3794         if (afsmon_debug) {
3795             fprintf(debugFD, "[ %s ] Calling xstat_cm_Init \n", rn);
3796             fflush(debugFD);
3797         }
3798
3799         code = xstat_cm_Init(numCM,     /*Num servers */
3800                              CMSktArray,        /*Cache Manager  socket array */
3801                              afsmon_probefreq,  /*probe frequency */
3802                              afsmon_CM_Handler, /*Handler routine */
3803                              CMinitFlags,       /*Initialization flags */
3804                              numCollIDs,        /*Number of collection IDs */
3805                              collIDP);  /*Ptr to collection ID */
3806
3807         if (code) {
3808             fprintf(stderr, "[ %s ] xstat_cm_init returned error\n", rn);
3809             afsmon_Exit(130);
3810         }
3811     }
3812
3813
3814
3815     /* end of process cache manager entries */
3816     /* if only one probe was required setup a waiting process for the 
3817      * termination signal */
3818     if (afsmon_onceOnly) {
3819         code = LWP_WaitProcess(&terminationEvent);
3820         if (code) {
3821             if (afsmon_debug) {
3822                 fprintf(debugFD, "LWP_WaitProcess() returned error %d\n",
3823                         code);
3824                 fflush(debugFD);
3825             }
3826             afsmon_Exit(135);
3827         }
3828     }
3829
3830     /* start the gtx input server */
3831     code = gtx_InputServer(afsmon_win);
3832     if (code) {
3833         fprintf(stderr, "[ %s ] Failed to start input server \n", rn);
3834         afsmon_Exit(140);
3835     }
3836
3837     /* This part of the code is reached only if the input server is not started
3838      * for debugging purposes */
3839
3840     /* sleep forever */
3841     tv.tv_sec = 24 * 60;
3842     tv.tv_usec = 0;
3843     fprintf(stderr, "[ %s ] going to sleep ...\n", rn);
3844     while (1) {
3845         code = IOMGR_Select(0,  /*Num fds */
3846                             0,  /*Descriptors ready for reading */
3847                             0,  /*Descriptors ready for writing */
3848                             0,  /*Descriptors with exceptional conditions */
3849                             &tv);       /*Timeout structure */
3850         if (code) {
3851             fprintf(stderr,
3852                     "[ %s ] IOMGR_Select() returned non-zero value %d\n", rn,
3853                     code);
3854             afsmon_Exit(145);
3855         }
3856     }                           /* while sleep */
3857 }
3858
3859
3860 /*-----------------------------------------------------------------------
3861  * afsmonInit()
3862  *
3863  * Description:
3864  *      Afsmonitor initialization routine.
3865  *      - processes command line parameters
3866  *      - call functions to:
3867  *              - process config file
3868  *              - initialize circular buffers and display buffers
3869  *              - initialize gtx
3870  *              - execute afsmonitor
3871  *      - initialize the display maps [fs/cm]_Display_map[].
3872  *
3873  * Returns:
3874  *      Success: Does not return from the call to afsmon_execute().
3875  *      Failure: Exits afsmonitor.
3876  *----------------------------------------------------------------------*/
3877
3878 int
3879 afsmonInit(struct cmd_syndesc *as, void *arock)
3880 {                               /* afsmonInit() */
3881
3882     static char rn[] = "afsmonInit";    /* Routine name */
3883     char *debug_filename;       /* pointer to debug filename */
3884     FILE *outputFD;             /* output file descriptor */
3885     struct cmd_item *hostPtr;   /* ptr to parse command line args */
3886     char buf[256];              /* buffer for processing hostnames */
3887     int code;
3888     int i;
3889
3890     if (afsmon_debug) {
3891         fprintf(debugFD, "[ %s ] Called, as= %d\n", rn, as);
3892         fflush(debugFD);
3893     }
3894
3895     /* Open  the debug file if -debug option is specified */
3896     if (as->parms[P_DEBUG].items != 0) {
3897         afsmon_debug = 1;
3898         debug_filename = as->parms[P_DEBUG].items->data;
3899         debugFD = fopen(debug_filename, "w");
3900         if (debugFD == (FILE *) 0) {
3901             printf("[ %s ] Failed to open debugging file %s for writing\n",
3902                    rn, "log");
3903             afsmon_debug = 0;
3904             afsmon_Exit(150);
3905         }
3906     }
3907
3908     if (afsmon_debug) {
3909         fprintf(debugFD, "[ %s ] Called\n", rn);
3910     }
3911
3912
3913     /* use curses always until we support other packages */
3914 #ifdef notdef
3915     wpkg_to_use = atoi(as->parms[P_PACKAGE].items->data);
3916
3917     switch (wpkg_to_use) {
3918     case GATOR_WIN_CURSES:
3919         fprintf(stderr, "curses\n");
3920         break;
3921     case GATOR_WIN_DUMB:
3922         fprintf(stderr, "dumb terminal\n");
3923         break;
3924     case GATOR_WIN_X11:
3925         fprintf(stderr, "X11\n");
3926         break;
3927     default:
3928         fprintf(stderr, "Illegal graphics package: %d\n", wpkg_to_use);
3929         afsmon_Exit(155);
3930     }                           /*end switch (wpkg_to_use) */
3931 #endif
3932
3933     wpkg_to_use = GATOR_WIN_CURSES;
3934
3935     /* get probe frequency . We check for meaningful bounds on the frequency
3936      * and reset to the default value if needed. The upper bound of 24
3937      * hours looks ridiculous though! */
3938
3939     afsmon_probefreq = 0;
3940     if (as->parms[P_FREQUENCY].items != 0)
3941         afsmon_probefreq = atoi(as->parms[P_FREQUENCY].items->data);
3942     else
3943         afsmon_probefreq = DEFAULT_FREQUENCY;
3944
3945     if (afsmon_probefreq <= 0 || afsmon_probefreq > 24 * 60 * 60) {
3946         afsmon_probefreq = DEFAULT_FREQUENCY;
3947         if (afsmon_debug) {
3948             fprintf(debugFD,
3949                     "[ %s ] Invalid probe frequency %s specified, resetting to default value %d seconds\n",
3950                     rn, as->parms[P_FREQUENCY].items->data, afsmon_probefreq);
3951             fflush(debugFD);
3952         }
3953         fprintf(stderr,
3954                 "Invalid probe frequency %s specified, resetting to default value %d seconds\n",
3955                 as->parms[P_FREQUENCY].items->data, afsmon_probefreq);
3956         sleep(3);
3957     }
3958
3959
3960     /* make sure output file is writable, else complain now */
3961     /* we will open and close it as needed after probes */
3962
3963     if (as->parms[P_OUTPUT].items != 0) {
3964         afsmon_output = 1;      /* output flag */
3965         strncpy(output_filename, as->parms[P_OUTPUT].items->data, 80);
3966         outputFD = fopen(output_filename, "a");
3967         if (outputFD == (FILE *) 0) {
3968             fprintf(stderr, "Failed to open output file %s \n",
3969                     output_filename);
3970             if (afsmon_debug) {
3971                 fprintf(debugFD, "[ %s ] Failed to open output file %s \n",
3972                         rn, output_filename);
3973                 afsmon_Exit(160);
3974             }
3975         }
3976         if (afsmon_debug) {
3977             fprintf(debugFD, "[ %s ] output file is %s\n", rn,
3978                     output_filename);
3979         }
3980         fclose(outputFD);
3981     }
3982
3983     /* detailed statistics to storage file */
3984     if (as->parms[P_DETAILED].items != 0) {
3985         if (as->parms[P_OUTPUT].items == 0) {
3986             fprintf(stderr,
3987                     "-detailed switch can be used only with -output\n");
3988             afsmon_Exit(165);
3989         }
3990         afsmon_detOutput = 1;
3991     }
3992
3993     /* Initialize host list headers */
3994     FSnameList = (struct afsmon_hostEntry *)0;
3995     CMnameList = (struct afsmon_hostEntry *)0;
3996
3997     /* The -config option is mutually exclusive with the -fshosts,-cmhosts 
3998      * options */
3999
4000     if (as->parms[P_CONFIG].items) {
4001         if (as->parms[P_FSHOSTS].items || as->parms[P_CMHOSTS].items) {
4002             fprintf(stderr,
4003                     "Cannot use -config option with -fshosts or -cmhosts\n");
4004             afsmon_Exit(170);
4005         }
4006     } else {
4007         if (!as->parms[P_FSHOSTS].items && !as->parms[P_CMHOSTS].items) {
4008             fprintf(stderr,
4009                     "Must specify either -config or (-fshosts and/or -cmhosts) options \n");
4010             afsmon_Exit(175);
4011         }
4012     }
4013
4014
4015     /* If a file server host is specified on the command line we reuse
4016      * parse_hostEntry() function . Just the pass the info as if it were 
4017      * read off the config file */
4018
4019     if (as->parms[P_FSHOSTS].items) {
4020         hostPtr = as->parms[P_FSHOSTS].items;
4021         while (hostPtr != (struct cmd_item *)0) {
4022             sprintf(buf, "fs %s", hostPtr->data);
4023             code = parse_hostEntry(buf);
4024             if (code) {
4025                 fprintf(stderr, "Could not parse %s\n", hostPtr->data);
4026                 afsmon_Exit(180);
4027             }
4028
4029             hostPtr = hostPtr->next;
4030         }
4031     }
4032
4033     /* same as above for -cmhosts */
4034     if (as->parms[P_CMHOSTS].items) {
4035         hostPtr = as->parms[P_CMHOSTS].items;
4036         while (hostPtr != (struct cmd_item *)0) {
4037             sprintf(buf, "cm %s", hostPtr->data);
4038             code = parse_hostEntry(buf);
4039             if (code) {
4040                 fprintf(stderr, "Could not parse %s\n", hostPtr->data);
4041                 afsmon_Exit(185);
4042             }
4043
4044             hostPtr = hostPtr->next;
4045         }
4046     }
4047
4048     /* number of slots in circular buffers */
4049     if (as->parms[P_BUFFERS].items)
4050         num_bufSlots = atoi(as->parms[P_BUFFERS].items->data);
4051     else
4052         num_bufSlots = DEFAULT_BUFSLOTS;
4053
4054     /* Initialize xx_showFlags[]. This array is used solely for processing the
4055      * "show" directives in the config file in parse_showEntries()  */
4056     for (i = 0; i < NUM_FS_STAT_ENTRIES; i++)
4057         fs_showFlags[i] = 0;
4058     for (i = 0; i < NUM_CM_STAT_ENTRIES; i++)
4059         cm_showFlags[i] = 0;
4060
4061
4062     /* Process the configuration file if given. This initializes among other
4063      * things, the list of FS & CM names in FSnameList and CMnameList */
4064
4065     if (as->parms[P_CONFIG].items)
4066         process_config_file(as->parms[P_CONFIG].items->data);
4067
4068     /* print out the FS and CM lists */
4069     print_FS();
4070     print_CM();
4071
4072     /* Initialize the FS results-to-screen map array if there were no "show fs"
4073      * directives in the config file */
4074     if (fs_showDefault) {
4075         for (i = 0; i < NUM_FS_STAT_ENTRIES; i++)
4076             fs_Display_map[i] = i;
4077         fs_DisplayItems_count = NUM_FS_STAT_ENTRIES;
4078     }
4079
4080     /* Initialize the CM results-to-screen map array if there were no "show cm"
4081      * directives in the config file */
4082     if (cm_showDefault) {
4083         for (i = 0; i < NUM_CM_STAT_ENTRIES; i++)
4084             cm_Display_map[i] = i;
4085         cm_DisplayItems_count = NUM_CM_STAT_ENTRIES;
4086     }
4087
4088
4089
4090     /* setup an interrupt signal handler; we ain't wanna leak core  */
4091     /* this binding is useful only until gtx is initialized after which the
4092      * keyboard input server takes over. */
4093     if ((signal(SIGINT, quit_signal)) == SIG_ERR) {
4094         perror("signal() failed.");
4095         afsmon_Exit(190);
4096     }
4097
4098
4099     /* init error message buffers. these will be used to print error messages
4100      * once gtx is initialized and there is no access to stderr/stdout */
4101     errMsg[0] = '\0';
4102     errMsg1[0] = '\0';
4103
4104     if (num_bufSlots) {
4105
4106         /* initialize fs and cm circular buffers before initiating probes */
4107         if (numFS) {
4108             code = init_fs_buffers();
4109             if (code) {
4110                 fprintf(stderr, "[ %s ] init_fs_buffers returned %d\n", rn,
4111                         code);
4112                 afsmon_Exit(195);
4113             }
4114         }
4115
4116         if (numCM) {
4117             code = init_cm_buffers();
4118             if (code) {
4119                 fprintf(stderr, "[ %s ] init_cm_buffers returned %d\n", rn,
4120                         code);
4121                 afsmon_Exit(200);
4122             }
4123         }
4124     }
4125
4126     /* allocate and initialize buffers for holding fs & cm results in ascii
4127      * format suitable for updating the screen */
4128     code = init_print_buffers();
4129     if (code) {
4130         fprintf(stderr, "[ %s ] init_print_buffers returned %d\n", rn, code);
4131         afsmon_Exit(205);
4132     }
4133
4134     /* perform gtx initializations */
4135     code = gtx_initialize();
4136     if (code) {
4137         fprintf(stderr, "[ %s ] gtx_initialize returned %d\n", rn, code);
4138         afsmon_Exit(210);
4139     }
4140
4141     /* start xstat probes */
4142     afsmon_execute();
4143
4144     return (0);                 /* will not return from the call to afsmon_execute() */
4145
4146 }                               /* afsmonInit() */
4147
4148
4149 /*-----------------------------------------------------------------------
4150  * Function:    main()
4151  ------------------------------------------------------------------------*/
4152
4153 #include "AFS_component_version_number.c"
4154
4155 int
4156 main(argc, argv)
4157      int argc;
4158      char **argv;
4159 {                               /* main() */
4160
4161     static char rn[] = "main";  /* routine name */
4162     afs_int32 code;             /*Return code */
4163     struct cmd_syndesc *ts;     /*Ptr to cmd line syntax descriptor */
4164
4165 #ifdef  AFS_AIX32_ENV
4166     /*
4167      * The following signal action for AIX is necessary so that in case of a
4168      * crash (i.e. core is generated) we can include the user's data section
4169      * in the core dump. Unfortunately, by default, only a partial core is
4170      * generated which, in many cases, isn't too useful.
4171      */
4172     struct sigaction nsa;
4173
4174     sigemptyset(&nsa.sa_mask);
4175     nsa.sa_handler = SIG_DFL;
4176     nsa.sa_flags = SA_FULLDUMP;
4177     sigaction(SIGSEGV, &nsa, NULL);
4178 #endif
4179
4180     /*
4181      * Set up the commands we understand.
4182      */
4183     ts = cmd_CreateSyntax("initcmd", afsmonInit, NULL, "initialize the program");
4184     cmd_AddParm(ts, "-config", CMD_SINGLE, CMD_OPTIONAL,
4185                 "configuration file");
4186     cmd_AddParm(ts, "-frequency", CMD_SINGLE, CMD_OPTIONAL,
4187                 "poll frequency, in seconds");
4188     cmd_AddParm(ts, "-output", CMD_SINGLE, CMD_OPTIONAL, "storage file name");
4189     cmd_AddParm(ts, "-detailed", CMD_FLAG, CMD_OPTIONAL,
4190                 "output detailed statistics to storage file");
4191 #ifdef notdef
4192     /* we hope to use this .... eventually! */
4193     cmd_AddParm(ts, "-package", CMD_SINGLE, CMD_REQUIRED,
4194                 "Graphics Package to use");
4195 #endif
4196     cmd_AddParm(ts, "-debug", CMD_SINGLE, CMD_OPTIONAL,
4197                 "turn debugging output on to the named file");
4198     cmd_AddParm(ts, "-fshosts", CMD_LIST, CMD_OPTIONAL,
4199                 "list of file servers to monitor");
4200     cmd_AddParm(ts, "-cmhosts", CMD_LIST, CMD_OPTIONAL,
4201                 "list of cache managers to monitor");
4202     cmd_AddParm(ts, "-buffers", CMD_SINGLE, CMD_OPTIONAL,
4203                 "number of buffer slots");
4204
4205     /*
4206      * Parse command-line switches & execute afsmonitor 
4207      */
4208
4209     code = cmd_Dispatch(argc, argv);
4210     if (code)
4211         afsmon_Exit(1);
4212     else
4213         afsmon_Exit(2);
4214
4215     exit(0);                    /* redundant, but gets rid of warning */
4216 }                               /*main */