scout-prototypes-20090316
[openafs.git] / src / scout / scout.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
10 /*
11  * Scout: A quick and (semi-)dirty attempt at the old CMU vopcon.
12  *------------------------------------------------------------------------*/
13
14 #include <afsconfig.h>
15 #include <afs/param.h>
16
17 RCSID
18     ("$Header$");
19
20 #undef  IN
21 #ifdef  AFS_AIX32_ENV
22 #include <signal.h>
23 #endif
24 #include <string.h>
25 #undef IN
26 #include <gtxwindows.h>         /*Generic window package */
27 #include <gtxobjects.h>         /*Object definitions */
28 #include <gtxtextobj.h>         /*Text object interface */
29 #include <gtxlightobj.h>        /*Light object interface */
30 #include <gtxcurseswin.h>       /*Curses window package */
31 #include <gtxdumbwin.h>         /*Dumb terminal window package */
32 #include <gtxX11win.h>          /*X11 window package */
33 #include <gtxframe.h>           /*Frame package */
34 #include <gtxinput.h>
35 #include <stdio.h>              /*Standard I/O stuff */
36 #include <cmd.h>                /*Command interpretation library */
37 #include <fsprobe.h>            /*Interface for fsprobe module */
38 #include <errno.h>
39 #include <afs/afsutil.h>
40 #include <netdb.h>
41
42 /*
43  * Command line parameter indicies.
44  */
45 #define P_SERVER    0
46 #define P_BASE      1
47 #if 0
48 #define P_PACKAGE   2
49 #endif /* 0 */
50 #define P_FREQ      2
51 #define P_HOST      3
52 #define P_ATTENTION 4
53 #define P_DEBUG     5
54
55 /*
56   * Define the width in chars for each light object on the mini-line.
57   */
58 #define LIGHTOBJ_CONN_WIDTH      5
59 #define LIGHTOBJ_FETCH_WIDTH    10
60 #define LIGHTOBJ_STORE_WIDTH    10
61 #define LIGHTOBJ_WK_WIDTH        5
62 #define LIGHTOBJ_SRVNAME_WIDTH  13
63 #define LIGHTOBJ_DISK_WIDTH     12
64
65 /*
66  * Define the types of justification we can perform.
67  */
68 #define SCOUT_RIGHT_JUSTIFY     0
69 #define SCOUT_LEFT_JUSTIFY      1
70 #define SCOUT_CENTER            2
71
72 /*
73  * Define the types of truncation we can perform.
74  */
75 #define SCOUT_LEFT_TRUNC        0
76 #define SCOUT_RIGHT_TRUNC       1
77
78 /*
79  * Define whether the value passed is a labeled disk quantity.
80  */
81 #define SCOUT_ISNT_LDISK        0
82 #define SCOUT_IS_LDISK          1
83
84 /*
85   * We sometimes use index-base pointers, so we need a distinguished
86   * NIL value.
87   */
88 #define SCOUT_NIL  (-1)
89
90 /*
91   * Structure describing everything you want to know about a FileServer
92   * disk.
93   */
94 struct scout_disk {
95     int prev;                   /*Index of previous list entry */
96     int next;                   /*Index of next list entry */
97     int active;                 /*Is this disk known to exist? */
98     char *name;                 /*Single-letter disk name */
99     struct onode *disk_lp;      /*Ptr to disk light object */
100 };
101
102 /*
103   * Structure defining all the objects in the Scout line (or lines)
104   * for each server being watched.  Note that scout_disk linked list
105   * for used disks is ordered alphabetically.
106   */
107 struct mini_line {
108     /*
109      * Information on server location & configuration.
110      */
111     struct sockaddr_in skt;     /*Server's socket info */
112     int numDisks;               /*Number of disks used */
113     /*
114      * Screen location info.
115      */
116     int base_line;              /*Line number on the screen */
117     int num_lines;              /*Number of lines of info */
118     /*
119      * Associated light objects.
120      */
121     struct onode *currConns_lp; /*Number of current connections */
122     struct onode *fetches_lp;   /*Number of data fetches */
123     struct onode *stores_lp;    /*Number of data stores */
124     struct onode *workstations_lp;      /*Workstation info */
125     struct onode *srvName_lp;   /*Server name */
126     struct scout_disk disks[VOLMAXPARTS];       /*Info on all the disks */
127     int used_head;              /*Index of first used disk struct */
128     int used_tail;              /*Index of last used disk struct */
129     int free_head;              /*Index of first free disk struct */
130     int free_tail;              /*Index of last free disk struct */
131 };
132
133 /*
134   * Structure defining the contents of the Scout screen.
135   */
136 struct mini_screen {
137     int numServers;             /*Number of servers being watched */
138     int base_line_num;          /*Base mini-line number */
139     struct mini_line *line;     /*Array of screen lines */
140 };
141
142 static char pn[] = "scout";     /*Program name */
143 static int scout_debug = 0;     /*Is debugging turned on? */
144 static FILE *scout_debugfd;     /*Debugging file descriptor */
145 static int scout_gtx_initialized = 0;   /*Has gtx been initialized? */
146 static struct mini_screen scout_screen; /*Mini-screen itself */
147 static int scout_probefreq;     /*Probe frequency in seconds */
148 static char scout_basename[64]; /*Base server name */
149 static char scout_hostname[128];        /*Name of machine we're running on */
150 static int scout_showhostname = 0;      /*Show name of machine we're on? */
151 static char scout_blankline[256];       /*Blank line */
152 static struct gwin *scout_gwin; /*Window to use */
153 static struct gtx_frame *scout_frame;   /*Frame to use */
154 static struct onode *scout_banner0_lp;  /*Banner light, line 0 */
155 static struct onode *scout_banner1_lp;  /*Banner light, line 1 */
156 static struct onode *scout_banner2_lp;  /*Banner light, line 2 */
157 static int scout_DiskLightLeftCol = 0;  /*Column for leftmost disk light */
158 static struct gwin_sizeparams scout_frameDims;  /*Frame dimensions */
159
160 /*
161   * Attention thresholds & modes.
162   */
163 #define SCOUT_ATTN_NOTUSED  (-1)
164 #define SCOUT_DISKM_PCUSED    0
165 #define SCOUT_DISKM_MINFREE   1
166
167 static int scout_attn_conn = SCOUT_ATTN_NOTUSED;
168 static int scout_attn_fetch = SCOUT_ATTN_NOTUSED;
169 static int scout_attn_store = SCOUT_ATTN_NOTUSED;
170 static int scout_attn_workstations = SCOUT_ATTN_NOTUSED;
171 static int scout_attn_disk_mode = SCOUT_DISKM_PCUSED;
172 static int scout_attn_disk_minfree = 1000;
173 static float scout_attn_disk_pcused = 0.95;
174 static char scout_attn_disk_pcusedstr[8] = "95";
175
176 /*
177   * Some strings we'll be using over and over again.
178   */
179 static char scout_Banner[256];
180 static char scout_LightLabels[] =
181     "Conn      Fetch      Store    Ws                Disk attn:";
182 static char scout_LightLabelUnd[] =
183     "----   --------   -------- -----                ----------";
184
185
186 /*------------------------------------------------------------------------
187  * scout_CleanExit
188  *
189  * Description:
190  *      Exits cleanly from the Scout.  If gtx has not yet been initialized,
191  *      then we simply call exit() with the value provided.  Otherwise,
192  *      we call the appropriate gtx routine to exit cleanly from gtx, which
193  *      must reset the terminal or window.  We also close the debugging
194  *      file descriptor, if one has been opened.
195  *
196  * Arguments:
197  *      int a_exitval : Value with which to exit the program.
198  *
199  * Returns:
200  *      Void.
201  *
202  * Environment:
203  *      Actions depend on scout_gtx_initialized.  
204  *
205  * Side Effects:
206  *      This routine will always exit Scout.
207  *------------------------------------------------------------------------*/
208
209 static void
210 scout_CleanExit(int a_exitval)
211 {                               /*scout_CleanExit */
212
213     static char rn[] = "scout_CleanExit";       /*Routine name */
214
215     if (scout_debugfd != (FILE *) 0) {
216         fprintf(scout_debugfd, "[%s] Closing debugging file\n", rn);
217         fclose(scout_debugfd);
218     }
219
220     if (scout_gtx_initialized) {
221         gtxframe_exitValue = a_exitval;
222         gtxframe_ExitCmd((char *)(&gtxframe_exitValue));
223     } else
224         exit(a_exitval);
225
226 }                               /*scout_CleanExit */
227
228 /*------------------------------------------------------------------------
229  * mini_initLightObject
230  *
231  * Description:
232  *      Create and initialize a light onode according to the given
233  *      parameters.
234  *
235  * Arguments:
236  *      char *a_name       : Ptr to the light's string name.
237  *      int a_x            : X offset.
238  *      int a_y            : Y offset.
239  *      int a_width        : Width in chars.
240  *      struct gwin *a_win : Ptr to window structure.
241  *
242  * Returns:
243  *      Ptr to new light onode on success,
244  *      A null pointer otherwise.
245  *
246  * Environment:
247  *      See above.
248  *
249  * Side Effects:
250  *      As advertised.
251  *------------------------------------------------------------------------*/
252
253 static struct onode *
254 mini_initLightObject(char *a_name, int a_x, int a_y, int a_width, struct gwin *a_win)
255 {                               /*mini_initLightObject */
256
257     static char rn[] = "mini_initLightObject";  /*Routine name */
258     struct onode *newlightp;    /*Ptr to new light onode */
259     /*We only support curses right now */
260     struct gator_light_crparams light_crparams; /*Light creation params */
261     char *truncname;            /*Truncated name, if needed */
262     int name_len;               /*True length of name */
263
264     if (scout_debug) {
265         fprintf(scout_debugfd,
266                 "[%s] Called for name '%s', [%d, %d], %d-char field\n", rn,
267                 a_name, a_x, a_y, a_width);
268         fflush(scout_debugfd);
269     }
270     newlightp = NULL;
271
272     /*
273      * Set up the creation parameters according to the information we've
274      * received.
275      */
276     light_crparams.onode_params.cr_type = GATOR_OBJ_LIGHT;
277     name_len = strlen(a_name);
278     if (scout_debug)
279         fprintf(scout_debugfd, "[%s] Name '%s' has %d chars\n", rn, a_name,
280                 name_len);
281     if (name_len <= a_width)
282         sprintf(light_crparams.onode_params.cr_name, "%s", a_name);
283     else {
284         /*
285          * We need to truncate the given name, leaving a `*' at the end to
286          * show us it's been truncated.
287          */
288         truncname = light_crparams.onode_params.cr_name;
289         strncpy(truncname, a_name, a_width - 1);
290         truncname[a_width - 1] = '*';
291         truncname[a_width] = 0;
292     }
293     light_crparams.onode_params.cr_x = a_x;
294     light_crparams.onode_params.cr_y = a_y;
295     light_crparams.onode_params.cr_width = a_width;
296     light_crparams.onode_params.cr_height = 1;
297     light_crparams.onode_params.cr_window = a_win;
298     light_crparams.onode_params.cr_home_obj = NULL;
299     light_crparams.onode_params.cr_prev_obj = NULL;
300     light_crparams.onode_params.cr_parent_obj = NULL;
301     light_crparams.onode_params.cr_helpstring = NULL;
302
303     light_crparams.appearance = 0;
304     light_crparams.flashfreq = 0;
305     sprintf(light_crparams.label, "%s", a_name);
306     light_crparams.label_x = 0;
307     light_crparams.label_y = 0;
308
309     newlightp =
310         gator_objects_create((struct onode_createparams *)(&light_crparams));
311
312     /*
313      * Return the news, happy or not.
314      */
315     return (newlightp);
316
317 }                               /*mini_initLightObject */
318
319 /*------------------------------------------------------------------------
320  * scout_initDiskLightObjects
321  *
322  * Description:
323  *      Create and initialize all Scout light objects for a server's
324  *      disks.
325  *
326  * Arguments:
327  *      struct scout_disk *a_line : Ptr to the server object line.
328  *      struct gwin *a_win        : Ptr to window structure.
329  *
330  * Returns:
331  *      0 on success,
332  *      -1 otherwise.
333  *
334  * Environment:
335  *      See above.
336  *
337  * Side Effects:
338  *      As advertised.
339  *------------------------------------------------------------------------*/
340
341 static int
342 scout_initDiskLightObjects(struct mini_line *a_line, struct gwin *a_win)
343 {                               /*scout_initDiskLightObjects */
344
345     static char rn[] = "scout_initDiskLightObjects";    /*Routine name */
346     struct scout_disk *curr_disk;       /*Ptr to current disk being set up */
347     int i;                      /*Loop variable */
348
349     if (scout_debug) {
350         fprintf(scout_debugfd, "[%s] Called\n", rn);
351         fflush(scout_debugfd);
352     }
353
354     /*
355      * Set up the base linked list fields.
356      */
357     a_line->used_head = SCOUT_NIL;
358     a_line->used_tail = SCOUT_NIL;
359     a_line->free_head = 0;
360     a_line->free_tail = VOLMAXPARTS - 1;
361
362     /*
363      * Sweep through the disk structures, creating the light objects and
364      * marking them all as free.
365      */
366     curr_disk = a_line->disks;
367     for (i = 0; i < VOLMAXPARTS; i++) {
368         /*
369          * Create the disk light object.
370          */
371         if ((curr_disk->disk_lp = mini_initLightObject("Disk",  /*Object name */
372                                                        0,       /*X value */
373                                                        0,       /*Y value */
374                                                        LIGHTOBJ_DISK_WIDTH,     /*Width */
375                                                        a_win))  /*Window */
376             == NULL) {
377             fprintf(stderr, "[%s:%s] Can't create disk %d light object\n", pn,
378                     rn, i);
379             return (-1);
380         }
381
382         /*
383          * Set the other fields in the disk records; Note that in the
384          * fencepost cases, the prev and next pointers will have to be
385          * fixed.
386          */
387         curr_disk->prev = i - 1;
388         curr_disk->next = i + 1;
389         curr_disk->active = 0;
390         curr_disk->name = '\0';
391
392         /*
393          * Bump up to the next disk structure.
394          */
395         curr_disk++;
396
397     }                           /*for each disk structure */
398
399     /*
400      * We made it all the way through.  Fix the fencepost pointers, set
401      * the overall pointers, then return success.
402      */
403     a_line->disks[0].prev = SCOUT_NIL;
404     a_line->disks[VOLMAXPARTS - 1].next = SCOUT_NIL;
405
406     return (0);
407
408 }                               /*scout_initDiskLightObjects */
409
410
411 /*------------------------------------------------------------------------
412  * mini_justify
413  *
414  * Description:
415  *      Place the chars in the source buffer into the target buffer
416  *      with the desired justification, either centered, left-justified
417  *      or right-justified.  Also, support inidication of truncation
418  *      with a star (*), either on the left or right of the string,
419  *      and whether we're justifying a labeled disk quantity.
420  *
421  * Arguments:
422  *      char *a_srcbuff     : Ptr to source char buffer.
423  *      char *a_dstbuff     : Ptr to dest char buffer.
424  *      int a_dstwidth      : Width of dest buffer in chars.
425  *      int a_justification : Kind of justification.
426  *      int a_rightTrunc    : If non-zero, place the truncation char
427  *                            on the right of the string.  Otherwise,
428  *                            place it on the left.
429  *      int a_isLabeledDisk : Is this a labeled disk quantity?
430  *
431  * Returns:
432  *      0 on success,
433  *      -1 otherwise.
434  *
435  * Environment:
436  *      All it needs to know is exported by the fsprobe module, namely
437  *      the data structure where the probe results are stored.
438  *
439  * Side Effects:
440  *      As advertised.
441  *------------------------------------------------------------------------*/
442
443 int
444 mini_justify(char *a_srcbuff, char *a_dstbuff, int a_dstwidth, 
445              int a_justification, int a_rightTrunc,
446              int a_isLabeledDisk)
447 {                               /*mini_justify */
448
449     static char rn[] = "mini_justify";  /*Routine name */
450     int leftpad_chars;          /*# of chars for left-padding */
451     int num_src_chars;          /*# of chars in source */
452     int true_num_src_chars;     /*# src chars before truncation */
453     int trunc_needed;           /*Is truncation needed? */
454     char diskChar = 0;          /*Disk name prefix */
455
456     if (scout_debug) {
457         fprintf(scout_debugfd, "[%s] Called with '%s', dest width=%d\n", rn,
458                 a_srcbuff, a_dstwidth);
459         fflush(scout_debugfd);
460     }
461
462     /*
463      * Remember the disk label, if we've been passed such a thing.
464      */
465     if (a_isLabeledDisk)
466         diskChar = *a_srcbuff;
467
468     /*
469      * If the destination width will overrun the gtx string storage,
470      * we automatically shorten up.
471      */
472     if (a_dstwidth > GATOR_LABEL_CHARS) {
473         if (scout_debug) {
474             fprintf(scout_debugfd,
475                     "[%s] Dest width (%d) > gtx buflen (%d), shrinking dest width\n",
476                     rn, a_dstwidth, GATOR_LABEL_CHARS);
477             fflush(scout_debugfd);
478         }
479         a_dstwidth = GATOR_LABEL_CHARS;
480     }
481
482     /*
483      * If our source string is too long, prepare for truncation.
484      */
485     true_num_src_chars = strlen(a_srcbuff);
486     if (true_num_src_chars >= a_dstwidth) {
487         trunc_needed = 1;
488         num_src_chars = a_dstwidth - 1;
489         leftpad_chars = 0;
490         if (!a_rightTrunc)
491             a_srcbuff += (true_num_src_chars - num_src_chars);
492     } else {
493         trunc_needed = 0;
494         num_src_chars = true_num_src_chars;
495
496         /*
497          * Compute the necessary left-padding.
498          */
499         switch (a_justification) {
500
501         case SCOUT_RIGHT_JUSTIFY:
502             leftpad_chars = (a_dstwidth - 1) - num_src_chars;
503             break;
504
505         case SCOUT_LEFT_JUSTIFY:
506             /*
507              * This is the really easy one.
508              */
509             leftpad_chars = 0;
510             break;
511
512         case SCOUT_CENTER:
513             leftpad_chars = ((a_dstwidth - 1) - num_src_chars) / 2;
514             break;
515
516         default:
517             fprintf(stderr, "[%s] Illegal justification command: %d", rn,
518                     a_justification);
519             return (-1);
520         }                       /*Switch on justification type */
521     }
522
523     /*
524      * Clear out the dest buffer, then place the source string at the
525      * appropriate padding location.  Remember to place a string
526      * terminator at the end of the dest buffer, plus whatever truncation
527      * may be needed.  If we're left-truncating, we've already shifted
528      * the src buffer appropriately.
529      */
530     strncpy(a_dstbuff, scout_blankline, a_dstwidth);
531     strncpy(a_dstbuff + leftpad_chars, a_srcbuff, num_src_chars);
532     *(a_dstbuff + a_dstwidth - 1) = '\0';
533     if (trunc_needed) {
534         if (a_rightTrunc)
535             *(a_dstbuff + a_dstwidth - 2) = '*';        /*Truncate on the right */
536         else {
537             if (a_isLabeledDisk) {
538                 *a_dstbuff = diskChar;
539                 *(a_dstbuff + 1) = ':';
540                 *(a_dstbuff + 2) = '*'; /*Truncate on the left, disk */
541             } else
542                 *a_dstbuff = '*';       /*Truncate on the left, non-disk */
543         }
544     }
545
546     /*Handle truncations */
547     /*
548      * Return the good news.
549      */
550     return (0);
551
552 }                               /*mini_justify */
553
554 /*------------------------------------------------------------------------
555  * scout_SetNonDiskLightLine
556  *
557  * Description:
558  *      Given a mini-line and a line number, place all non-disk lights
559  *      on that line.
560  *
561  * Arguments:
562  *      struct mini_line *a_srvline : Ptr to server descriptor.
563  *      int a_linenum               : Line number to move to.
564  *
565  * Returns:
566  *      Nothing.
567  *
568  * Environment:
569  *      The light's location is stored not only in the onode, but in
570  *      the light's rock, so we have to change both sets of value.
571  *
572  * Side Effects:
573  *      As described.
574  *------------------------------------------------------------------------*/
575
576 static void
577 scout_SetNonDiskLightLine(struct mini_line *a_srvline, int a_linenum)
578 {                               /*scout_SetNonDiskLightLine */
579
580     struct gator_lightobj *nondisk_lightdata;   /*Non-disk light data field */
581     struct gwin_strparams *nondisk_strparams;   /*Associated string params */
582
583     /*
584      * Do the exact same operation for each non-disk light in the record.
585      */
586     a_srvline->currConns_lp->o_y = a_linenum;
587     nondisk_lightdata =
588         (struct gator_lightobj *)(a_srvline->currConns_lp->o_data);
589     nondisk_strparams = (struct gwin_strparams *)(nondisk_lightdata->llrock);
590     nondisk_strparams->y = a_linenum;
591
592     a_srvline->fetches_lp->o_y = a_linenum;
593     nondisk_lightdata =
594         (struct gator_lightobj *)(a_srvline->fetches_lp->o_data);
595     nondisk_strparams = (struct gwin_strparams *)(nondisk_lightdata->llrock);
596     nondisk_strparams->y = a_linenum;
597
598     a_srvline->stores_lp->o_y = a_linenum;
599     nondisk_lightdata =
600         (struct gator_lightobj *)(a_srvline->stores_lp->o_data);
601     nondisk_strparams = (struct gwin_strparams *)(nondisk_lightdata->llrock);
602     nondisk_strparams->y = a_linenum;
603
604     a_srvline->workstations_lp->o_y = a_linenum;
605     nondisk_lightdata =
606         (struct gator_lightobj *)(a_srvline->workstations_lp->o_data);
607     nondisk_strparams = (struct gwin_strparams *)(nondisk_lightdata->llrock);
608     nondisk_strparams->y = a_linenum;
609
610     a_srvline->srvName_lp->o_y = a_linenum;
611     nondisk_lightdata =
612         (struct gator_lightobj *)(a_srvline->srvName_lp->o_data);
613     nondisk_strparams = (struct gwin_strparams *)(nondisk_lightdata->llrock);
614     nondisk_strparams->y = a_linenum;
615
616 }                               /*scout_SetNonDiskLightLine */
617
618 /*------------------------------------------------------------------------
619  * scout_RecomputeLightLocs
620  *
621  * Description:
622  *      Given a pointer to a server record, recompute its disk light
623  *      locations (and keep proper track of the number of screen lines
624  *      required for the server record).
625  *
626  * Arguments:
627  *      struct mini_line *a_srvline : Ptr to server descriptor.
628  *
629  * Returns:
630  *      0 if anything went wrong,
631  *      else the number of lines used by this server record.
632  *
633  * Environment:
634  *      One or more records have joined or left the used light list
635  *      for this server.  We're not sure which ones, so we recompute
636  *      them all.  We may also have had a width change in the gtx
637  *      frame.  The base_line field in the server record is guaranteed
638  *      to be correct at this point.
639  *
640  * Side Effects:
641  *      As described.
642  *------------------------------------------------------------------------*/
643
644 static int
645 scout_RecomputeLightLocs(struct mini_line *a_srvline)
646 {                               /*scout_RecomputeLightLocs */
647
648     static char rn[] = "scout_RecomputeLightLocs";      /*Routine name */
649     int lights_per_line;        /*# lights/line */
650     int lights_this_line;       /*# lights on cur line */
651     int curr_idx;               /*Current disk light idx */
652     struct scout_disk *sc_disk; /*Ptr to disk record array */
653     int lines_for_server;       /*Num lines in server record */
654     int curr_line;              /*Current line being filled */
655     int curr_x;                 /*Current x value for light */
656     struct gator_lightobj *disk_lightdata;      /*Disk light data field */
657     struct gwin_strparams *disk_strparams;      /*String params for disk light */
658
659     if (scout_debug) {
660         fprintf(scout_debugfd, "[%s] Called\n", rn);
661         fflush(scout_debugfd);
662     }
663
664     /*
665      * If we haven't yet computed the column for the leftmost disk light,
666      * do it now.
667      */
668     if (scout_DiskLightLeftCol == 0)
669         scout_DiskLightLeftCol =
670             LIGHTOBJ_CONN_WIDTH + LIGHTOBJ_FETCH_WIDTH +
671             LIGHTOBJ_STORE_WIDTH + LIGHTOBJ_WK_WIDTH +
672             LIGHTOBJ_SRVNAME_WIDTH + 5;
673
674     /*
675      * Calculate how many disk light objects can fit in one line.
676      */
677     lights_per_line =
678         (scout_frameDims.maxx -
679          scout_DiskLightLeftCol) / (LIGHTOBJ_DISK_WIDTH + 1);
680     if (scout_debug) {
681         fprintf(scout_debugfd, "[%s] %d lights per line\n", rn,
682                 lights_per_line);
683         fflush(scout_debugfd);
684     }
685
686     /*
687      * Sweep through the used disk light list, computing the location
688      * for each.
689      */
690     lights_this_line = 0;
691     curr_idx = a_srvline->used_head;
692     lines_for_server = 1;
693     curr_line = a_srvline->base_line;
694     curr_x = scout_DiskLightLeftCol;
695
696     while (curr_idx != SCOUT_NIL) {
697         /*
698          * Bump the number of lines for the server if we've already
699          * filled up the current line.
700          */
701         if (lights_this_line >= lights_per_line) {
702             lights_this_line = 0;
703             lines_for_server++;
704             curr_line++;
705             curr_x = scout_DiskLightLeftCol;
706         }
707
708         /*Current line filled up */
709         /*
710          * Set the current disk light's location.
711          */
712         sc_disk = a_srvline->disks;
713         sc_disk[curr_idx].disk_lp->o_x = curr_x;
714         sc_disk[curr_idx].disk_lp->o_y = curr_line;
715         disk_lightdata =
716             (struct gator_lightobj *)(sc_disk[curr_idx].disk_lp->o_data);
717         disk_strparams = (struct gwin_strparams *)(disk_lightdata->llrock);
718         disk_strparams->x = curr_x;
719         disk_strparams->y = curr_line;
720         if (scout_debug) {
721             fprintf(scout_debugfd,
722                     "[%s] Disk light at index %d located at [%d, %d]\n", rn,
723                     curr_idx, curr_x, curr_line);
724             fflush(scout_debugfd);
725         }
726
727         /*
728          * Record the inclusion of the light and move on to the next
729          * light, if any.
730          */
731         lights_this_line++;
732         curr_x += LIGHTOBJ_DISK_WIDTH + 1;
733         curr_idx = sc_disk[curr_idx].next;
734
735     }                           /*Update each used disk light */
736
737     /*
738      * Remember to record the (possibly new) number of lines in the
739      * server record before returning the value of that field.
740      */
741     if (a_srvline->num_lines != lines_for_server) {
742         if (scout_debug) {
743             fprintf(scout_debugfd,
744                     "[%s] Server previously had %d screen lines; now changed\n",
745                     rn, a_srvline->num_lines);
746             fflush(scout_debugfd);
747         }
748         a_srvline->num_lines = lines_for_server;
749     }
750
751     if (scout_debug) {
752         fprintf(scout_debugfd, "[%s] Server has %d screen lines\n", rn,
753                 a_srvline->num_lines);
754         fflush(scout_debugfd);
755     }
756     return (a_srvline->num_lines);
757
758 }                               /*scout_RecomputeLightLocs */
759
760 /*------------------------------------------------------------------------
761  * scout_FindUsedDisk
762  *
763  * Description:
764  *      Given a single-letter disk name and a pointer to the current server
765  *      record, look for a used disk record with that name within the server.
766  *      If we can't find one, we create and incorporate one, and return that
767  *      fact to our caller.
768  *
769  * Arguments:
770  *      char a_diskname             : Single-char disk name.
771  *      struct mini_line *a_srvline : Ptr to server descriptor.
772  *      int *a_record_added         : Was a new record added?
773  *
774  * Returns:
775  *      Index of matching used disk record,
776  *      SCOUT_NIL otherwise.
777  *
778  * Return via parameter:
779  *      a_record_added set to 1 iff record was added to the used disk list.
780  *
781  * Environment:
782  *      Used disk records are kept in alphabetical order by the single-char
783  *      disk name.  Should a matching used disk record not be found, one is
784  *      pulled from the free pool.
785  *
786  * Side Effects:
787  *      An entry may be pulled off the free list and inserted into the
788  *      used list.  This entry is placed in the update list for the
789  *      current gtx frame (at least not by this routine).
790  *------------------------------------------------------------------------*/
791
792 static int
793 scout_FindUsedDisk(char *a_diskname, struct mini_line *a_srvline, int *a_record_added)
794 {                               /*scout_FindUsedDisk */
795
796     static char rn[] = "scout_FindUsedDisk";    /*Routine name */
797     int curr_idx;               /*Disk record index */
798     int append_idx;             /*Index to append after */
799     int new_idx;                /*Index of new used record */
800     struct scout_disk *sc_disk; /*Ptr to disk record */
801     int code;                   /*Function return value */
802
803     if (scout_debug) {
804         fprintf(scout_debugfd, "[%s] Called\n", rn);
805         fflush(scout_debugfd);
806     }
807
808     /*
809      * Sweep through the used disk records, looking for a match.
810      */
811     curr_idx = a_srvline->used_head;
812     append_idx = SCOUT_NIL;
813     sc_disk = a_srvline->disks;
814     if (scout_debug) {
815         fprintf(scout_debugfd,
816                 "[%s] Scanning existing used disk entries for disk '%s'\n",
817                 rn, a_diskname);
818         fflush(scout_debugfd);
819     }
820     while (curr_idx != SCOUT_NIL) {
821         if (scout_debug) {
822             fprintf(scout_debugfd, "[%s] Disk %d is named '%s'\n", rn,
823                     curr_idx, sc_disk[curr_idx].name);
824             fflush(scout_debugfd);
825         }
826         if (strcmp(sc_disk[curr_idx].name, a_diskname) == 0) {
827             /*
828              * We found it!  Bug out.
829              */
830             if (scout_debug) {
831                 fprintf(scout_debugfd, "[%s] Match found\n", rn);
832                 fflush(scout_debugfd);
833             }
834             return (curr_idx);
835         }
836
837         /*
838          * If we are alphabetically past the given disk name, we
839          * know that we won't find it in the used disk list; we
840          * also have the append index set correctly.
841          */
842         if (strcmp(a_diskname, sc_disk[curr_idx].name) < 0) {
843             if (scout_debug) {
844                 fprintf(scout_debugfd, "[%s] Disk '%s' can't be here\n", rn,
845                         a_diskname);
846                 fflush(scout_debugfd);
847             }
848             break;
849         }
850
851         /*
852          * There's still hope we'll find it.  Move on to the next used
853          * disk record, keeping this index as the best candidate so far
854          * for appending a missing entry.
855          */
856         append_idx = curr_idx;
857         curr_idx = sc_disk[curr_idx].next;
858     }                           /*Look for match */
859
860     /*
861      * We didn't find the record we wanted, which means we'll pull a
862      * record out of the free pool for it.  If we didn't find a place
863      * to append it, we then insert it at the beginning of the queue.
864      */
865     if (a_srvline->free_head == SCOUT_NIL)
866         return (SCOUT_NIL);
867     *a_record_added = 1;
868     new_idx = a_srvline->free_head;
869     if (scout_debug) {
870         fprintf(scout_debugfd, "[%s] Choosing free index %d for new entry\n",
871                 rn, new_idx);
872         fflush(scout_debugfd);
873     }
874     a_srvline->free_head = sc_disk[new_idx].next;
875     if (a_srvline->free_head == SCOUT_NIL)
876         a_srvline->free_tail = SCOUT_NIL;
877
878     /*
879      * Fill in the new record.
880      */
881     sc_disk[new_idx].active = 0;
882     sc_disk[new_idx].name = a_diskname;
883
884     /*
885      * Insert the new record where it belongs on the used disk list.
886      */
887     if (append_idx == SCOUT_NIL) {
888         /*
889          * It belongs at the beginning of the list.
890          */
891         if (scout_debug) {
892             fprintf(scout_debugfd, "[%s] Inserted at used disk head\n", rn);
893             fflush(scout_debugfd);
894         }
895         sc_disk[new_idx].next = a_srvline->used_head;
896         sc_disk[new_idx].prev = SCOUT_NIL;
897         a_srvline->used_head = new_idx;
898         if (a_srvline->used_tail == SCOUT_NIL)
899             a_srvline->used_tail = new_idx;
900     } else {
901         if (scout_debug) {
902             fprintf(scout_debugfd, "[%s] Entry appended after index %d\n", rn,
903                     append_idx);
904             fflush(scout_debugfd);
905         }
906         sc_disk[new_idx].prev = append_idx;
907         sc_disk[new_idx].next = sc_disk[append_idx].next;
908         sc_disk[append_idx].next = new_idx;
909         if (sc_disk[new_idx].next == SCOUT_NIL)
910             a_srvline->used_tail = new_idx;
911         else
912             sc_disk[sc_disk[new_idx].next].prev = new_idx;
913     };
914
915     /*
916      * Add the new used disk light object to the display list for
917      * the scout frame.
918      */
919     if (scout_debug) {
920         fprintf(scout_debugfd,
921                 "[%s] Adding disk light at index %d to display list\n", rn,
922                 new_idx);
923         fflush(scout_debugfd);
924     }
925     code = gtxframe_AddToList(scout_frame, sc_disk[new_idx].disk_lp);
926     if (code) {
927         if (scout_debug) {
928             fprintf(scout_debugfd,
929                     "[%s] Can't add to display list, code is %d\n", rn, code);
930             fflush(scout_debugfd);
931         }
932     }
933     return (new_idx);
934
935 }                               /*scout_FindUsedDisk */
936
937 /*------------------------------------------------------------------------
938  * scout_RemoveInactiveDisk
939  *
940  * Description:
941  *      Given a server record and a used disk index, remove the disk
942  *      record from the used list, put it on the free list, and remove
943  *      it from the gtx frame update list.
944  *
945  * Arguments:
946  *      struct mini_line *a_srvline     : Ptr to server descriptor.
947  *      int a_used_idx                  : Index of used disk record.
948  *
949  * Returns:
950  *      Nothing.
951  *
952  * Environment:
953  *      Formerly-used disk records are returned to the free pool.
954  *
955  * Side Effects:
956  *      Free and used disk record lists are modified for this server.
957  *      The disk record in question is pulled off the gtx update list
958  *      for the frame.
959  *------------------------------------------------------------------------*/
960
961 static void
962 scout_RemoveInactiveDisk(struct mini_line *a_srvline, int a_used_idx)
963 {                               /*scout_RemoveInactiveDisk */
964
965     static char rn[] = "scout_RemoveInactiveDisk";      /*Routine name */
966
967     if (scout_debug) {
968         fprintf(scout_debugfd, "[%s] Called\n", rn);
969         fflush(scout_debugfd);
970     }
971
972     /*code = gtxframe_RemoveFromList(scout_frame->window, lightobj); */
973
974 }                               /*scout_RemoveInactiveDisk */
975
976 /*------------------------------------------------------------------------
977  * mini_PrintDiskStats
978  *
979  * Description:
980  *      Given server indexing and light object information, a pointer
981  *      to a set of statistics, and whether the probe that produced these
982  *      stats succeeded or not, print out the stats in a nice way.
983  *
984  * Arguments:
985  *      struct mini_line *a_srvline     : Ptr to server descriptor.
986  *      struct ProbeViceStatistics *a_stats     : Ptr to current stats.
987  *      int a_probeOK                   : Was the probe OK?
988  *      int a_width_changed             : Has the frame width changed?
989  *      int a_fix_line_num              : Is the line number wrong?
990  *      int a_delta_line_num            : Change in line number.
991  *
992  * Returns:
993  *      0 if something went wrong,
994  *      else the number of lines taken up by this server record.
995  *
996  * Environment:
997  *      Nothing interesting.
998  *
999  * Side Effects:
1000  *      As advertised.
1001  *------------------------------------------------------------------------*/
1002
1003 static int
1004 mini_PrintDiskStats(struct mini_line *a_srvline, 
1005                     struct ProbeViceStatistics *a_stats, 
1006                     int a_probeOK, int a_width_changed,
1007                     int a_fix_line_num, int a_delta_line_num)
1008 {                               /*mini_PrintDiskStats */
1009
1010     static char rn[] = "mini_PrintDiskStats";   /*Routine name */
1011     int code;                   /*Return code */
1012     char s[128];                /*String buffer */
1013     struct onode *curr_disklight;       /*Ptr to current disk light */
1014     struct onode *srvname_light;        /*Ptr to server name light */
1015     ViceDisk *curr_diskstat;    /*Ptr to current disk stat */
1016     int curr_disk;              /*Current disk stat number */
1017     int used_disk_idx;          /*Used disk index */
1018     int next_used_idx;          /*Ditto */
1019     int pastthreshold;          /*Was disk past threshold? */
1020     struct gator_lightobj *diskdata;    /*Private light data */
1021     struct gwin_strparams *disk_strparams;      /*String params for disk light */
1022     char *diskname = 0;         /*Name of disk */
1023     int found_idx;              /*Idx of matching disk */
1024     char *srv_name;             /*Server name */
1025     struct scout_disk *sc_disk; /*Ptr to scout disk desc */
1026     int fix_light_locs;         /*Recompute disk light locs? */
1027
1028     if (scout_debug) {
1029         fprintf(scout_debugfd, "[%s] Called\n", rn);
1030         fflush(scout_debugfd);
1031     }
1032
1033     /*
1034      * Remember the current server's print name, don't recompute light
1035      * locations yet.
1036      */
1037     srvname_light = a_srvline->srvName_lp;
1038     srv_name = ((struct gator_lightobj *)(srvname_light->o_data))->label;
1039     fix_light_locs = 0;
1040     if (scout_debug) {
1041         fprintf(scout_debugfd, "[%s] Value of a_delta_line_num is %d\n", rn,
1042                 a_delta_line_num);
1043         fflush(scout_debugfd);
1044     }
1045
1046     /*
1047      * If the probe failed, we simply blank out all the used disk
1048      * objects.  Note: a NON-ZERO value of a_probeOK implies failure.
1049      */
1050     if (a_probeOK) {
1051         used_disk_idx = a_srvline->used_head;
1052         while (used_disk_idx != SCOUT_NIL) {
1053             /*
1054              * Point to the current used disk's light, blank out its
1055              * contents, and make sure highlighting is turned off.  We
1056              * also take this opportunity to fix the line numbers if
1057              * needed.
1058              */
1059             curr_disklight = a_srvline->disks[used_disk_idx].disk_lp;
1060             diskdata = (struct gator_lightobj *)(curr_disklight->o_data);
1061             if (scout_debug) {
1062                 fprintf(scout_debugfd,
1063                         "[%s] Prev value of disk light %d: '%s'\n", rn,
1064                         used_disk_idx, diskdata->label);
1065                 fflush(scout_debugfd);
1066             }
1067             code = mini_justify(" ",    /*Src buffer */
1068                                 diskdata->label,        /*Dest buffer */
1069                                 LIGHTOBJ_DISK_WIDTH,    /*Dest's width */
1070                                 SCOUT_RIGHT_JUSTIFY,    /*Right-justify */
1071                                 SCOUT_LEFT_TRUNC,       /*Left-truncate */
1072                                 SCOUT_ISNT_LDISK);      /*Not a labeled disk */
1073             code = gator_light_set(curr_disklight, 0);
1074             if (a_fix_line_num) {
1075                 curr_disklight->o_y += a_delta_line_num;
1076                 disk_strparams = (struct gwin_strparams *)(diskdata->llrock);
1077                 disk_strparams->y += a_delta_line_num;
1078             }
1079
1080             /*
1081              * Advance to next used disk, if any.
1082              */
1083             used_disk_idx = a_srvline->disks[used_disk_idx].next;
1084
1085         }                       /*Blank out disk name field */
1086
1087         /*
1088          * If the frame width has changed, we have to recompute all disk
1089          * light locations.  After that, the number of lines in the server
1090          * record will be accurate, and we return them.
1091          */
1092         if (a_width_changed)
1093             scout_RecomputeLightLocs(a_srvline);
1094
1095         return (a_srvline->num_lines);
1096
1097     }
1098
1099     /*Probe failed for the server */
1100     /*
1101      * Probe was successful.  Sweep through the statistics records,
1102      * and put up all values having to do with AFS partitions.  First,
1103      * mark all used disk objects for this server as inactive and fix
1104      * their line numbers if needed.
1105      */
1106     sc_disk = a_srvline->disks;
1107     used_disk_idx = a_srvline->used_head;
1108     while (used_disk_idx != SCOUT_NIL) {
1109         if (scout_debug) {
1110             fprintf(scout_debugfd, "[%s] Marking used disk %d inactive\n", rn,
1111                     used_disk_idx);
1112             fflush(scout_debugfd);
1113         }
1114         sc_disk = (a_srvline->disks) + used_disk_idx;
1115         sc_disk->active = 0;
1116         used_disk_idx = sc_disk->next;
1117         if (a_fix_line_num) {
1118             sc_disk->disk_lp->o_y += a_delta_line_num;
1119             diskdata = (struct gator_lightobj *)(sc_disk->disk_lp->o_data);
1120             disk_strparams = (struct gwin_strparams *)(diskdata->llrock);
1121             disk_strparams->y += a_delta_line_num;
1122         }
1123     }                           /*Mark used disks inactive */
1124
1125     curr_diskstat = (ViceDisk *) a_stats->Disk;
1126     for (curr_disk = 0; curr_disk < VOLMAXPARTS; curr_disk++) {
1127         /*
1128          * An AFS partition name must be prefixed by `/vicep`.
1129          */
1130         if (scout_debug) {
1131             fprintf(scout_debugfd, "[%s] Disk stats at %p for disk '%s'\n",
1132                     rn, curr_diskstat, curr_diskstat->Name);
1133             fflush(scout_debugfd);
1134         }
1135         if (strncmp("/vice", curr_diskstat->Name, 5) == 0) {
1136             /*
1137              * Pull out the single-letter name (actually, abbreviation)
1138              * of the disk and look for such an entry in the used disks.
1139              */
1140             diskname = &curr_diskstat->Name[6];
1141             found_idx = scout_FindUsedDisk(diskname,    /*1-char name */
1142                                            a_srvline,   /*Server record */
1143                                            &fix_light_locs);    /*Recompute? */
1144             if (found_idx == SCOUT_NIL) {
1145                 fprintf(stderr,
1146                         "[%s] Can't display /vicep%s on server '%s'\n", rn,
1147                         diskname, srv_name);
1148             } else {
1149                 /*
1150                  * Found (or created) record for this disk.  Fill in the single-
1151                  * letter name of the disk followed by the number of free blocks.
1152                  * Turn the disk light on if the number of free blocks exceeds
1153                  * the threshold the user set, either % used or min free blocks.
1154                  */
1155                 sprintf(s, "%s:%d", diskname, curr_diskstat->BlocksAvailable);
1156                 if (scout_attn_disk_mode == SCOUT_DISKM_PCUSED) {
1157                     if ((float)
1158                         (curr_diskstat->TotalBlocks -
1159                          curr_diskstat->BlocksAvailable) /
1160                         (float)(curr_diskstat->TotalBlocks) >
1161                         scout_attn_disk_pcused)
1162                         pastthreshold = 1;
1163                     else
1164                         pastthreshold = 0;
1165                 } else
1166                     pastthreshold =
1167                         (curr_diskstat->BlocksAvailable <
1168                          scout_attn_disk_minfree) ? 1 : 0;
1169                 sc_disk = (a_srvline->disks) + found_idx;
1170                 sc_disk->active = 1;
1171                 diskdata =
1172                     (struct gator_lightobj *)(sc_disk->disk_lp->o_data);
1173                 if (scout_debug) {
1174                     fprintf(scout_debugfd,
1175                             "[%s] Justifying %s for disk idx %d (prev value: '%s')\n",
1176                             rn, s, found_idx, diskdata->label);
1177                     fflush(scout_debugfd);
1178                 }
1179                 code = mini_justify(s,  /*Src buffer */
1180                                     diskdata->label,    /*Dest buffer */
1181                                     LIGHTOBJ_DISK_WIDTH,        /*Dest's width */
1182                                     SCOUT_LEFT_JUSTIFY, /*Left-justify */
1183                                     SCOUT_LEFT_TRUNC,   /*Left-truncate */
1184                                     SCOUT_IS_LDISK);    /*Labeled disk */
1185
1186                 code = gator_light_set(sc_disk->disk_lp, pastthreshold);
1187
1188             }                   /*Found disk record */
1189         }
1190
1191         /*Found AFS disk name */
1192         /*
1193          * Advance to the next disk statistics record.
1194          */
1195         curr_diskstat++;
1196     }                           /*For each statistics record */
1197
1198     /*
1199      * We've now pulled out all the disk statistics from the probe.
1200      * See if any used disks that were there from the last time are
1201      * now gone.  If so, we remove them.
1202      */
1203     if (scout_debug) {
1204         fprintf(scout_debugfd,
1205                 "[%s] Scanning used disk records for inactive entries\n", rn);
1206         fflush(scout_debugfd);
1207     }
1208     used_disk_idx = a_srvline->used_head;
1209     while (used_disk_idx != SCOUT_NIL) {
1210         if (scout_debug) {
1211             fprintf(scout_debugfd, "[%s] Examining entry at index %d\n", rn,
1212                     used_disk_idx);
1213             fflush(scout_debugfd);
1214         }
1215         sc_disk = (a_srvline->disks) + used_disk_idx;
1216         next_used_idx = sc_disk->next;
1217         if (!(sc_disk->active)) {
1218             scout_RemoveInactiveDisk(a_srvline, /*Server record */
1219                                      used_disk_idx);    /*Disk index to nuke */
1220             fix_light_locs = 1;
1221         }
1222         used_disk_idx = next_used_idx;
1223
1224     }                           /*Remove inactive used disks */
1225
1226     /*
1227      * If we've had to add or remove disks to/from the used list,
1228      * or if the frame width has changed, we recompute the light
1229      * locations before returning.
1230      */
1231     if (fix_light_locs || a_width_changed)
1232         scout_RecomputeLightLocs(a_srvline);
1233
1234     /*
1235      * Return the (possibly new) size of the current server record.
1236      */
1237     return (a_srvline->num_lines);
1238
1239 }                               /*mini_PrintDiskStats */
1240
1241 /*------------------------------------------------------------------------
1242  * FS_Handler
1243  *
1244  * Description:
1245  *      Handler routine passed to the fsprobe module.  This handler is
1246  *      called immediately after a poll of all the FileServers has taken
1247  *      place.  Its job is to write out selected data to the scout
1248  *      screen.
1249  *
1250  * Arguments:
1251  *      None.
1252  *
1253  * Returns:
1254  *      0 on success,
1255  *      -1 otherwise.
1256  *
1257  * Environment:
1258  *      All it needs to know is exported by the fsprobe module, namely
1259  *      the data structure where the probe results are stored.
1260  *
1261  * Side Effects:
1262  *      Recomputes disk light locations in response to reshaping the
1263  *      scout window or from adding/deleting disk lights to/from
1264  *      individual servers.
1265  *------------------------------------------------------------------------*/
1266
1267 int
1268 FS_Handler(void)
1269 {                               /*FS_Handler */
1270
1271     static char rn[] = "FS_Handler";    /*Routine name */
1272     int code;                   /*Return code */
1273     struct ProbeViceStatistics *curr_stats;     /*Ptr to current stats */
1274     int *curr_probeOK;          /*Ptr to current probeOK field */
1275     int curr_srvidx;            /*Current server index */
1276     char s[128];                /*String buffer */
1277     static char sblank[] = " "; /*Blank string buffer */
1278     char *sp;                   /*Ptr to string buffer */
1279     struct mini_line *curr_line;        /*Current mini-line */
1280     int curr_line_num;          /*Current line number */
1281     struct gator_lightobj *lightdata;   /*Private light data */
1282     int setting;                /*Light setting (on or off) */
1283     int old_width;              /*Keep the old width value */
1284     int width_changed;          /*Has the frame width changed? */
1285     int fix_line_num;           /*Line number needs fixing */
1286     int delta_line_num;         /*Change in line number */
1287
1288     /*
1289      * See if the size of the scout frame has changed since the last
1290      * time.
1291      */
1292     old_width = scout_frameDims.maxx;
1293     if (scout_debug) {
1294         fprintf(scout_debugfd, "[%s] Calling wop_getdimensions\n", rn);
1295         fflush(scout_debugfd);
1296     }
1297     WOP_GETDIMENSIONS(scout_frame->window, &scout_frameDims);
1298     width_changed = (old_width == scout_frameDims.maxx) ? 0 : 1;
1299     if (scout_debug) {
1300         fprintf(scout_debugfd,
1301                 "[%s] Frame dimensions are %d rows, %d columns\n", rn,
1302                 scout_frameDims.maxy, scout_frameDims.maxx);
1303         if (width_changed)
1304             fprintf(scout_debugfd, "[%s] Width has changed from %d columns\n",
1305                     rn, old_width);
1306         fflush(scout_debugfd);
1307     }
1308
1309     /*
1310      * Print out the selected fields for each server.  We actually change
1311      * the light's label to the new data.
1312      */
1313     curr_line = scout_screen.line;
1314     curr_stats = fsprobe_Results.stats;
1315     curr_probeOK = fsprobe_Results.probeOK;
1316     curr_line_num = curr_line->base_line;
1317
1318     setting = 0;
1319     for (curr_srvidx = 0; curr_srvidx < scout_screen.numServers;
1320          curr_srvidx++) {
1321         /*
1322          * If the current server record is set up on the wrong line, fix
1323          * the non-disk light objects directly, and remember to fix the
1324          * disk light objects later on.
1325          */
1326         if (curr_line->base_line != curr_line_num) {
1327             fix_line_num = 1;
1328             delta_line_num = curr_line_num - curr_line->base_line;
1329             curr_line->base_line = curr_line_num;
1330             scout_SetNonDiskLightLine(curr_line, curr_line_num);
1331         } else {
1332             fix_line_num = 0;
1333             delta_line_num = 0;
1334         }
1335
1336         lightdata =
1337             (struct gator_lightobj *)(curr_line->currConns_lp->o_data);
1338         if (*curr_probeOK == 0) {
1339             sp = s;
1340             sprintf(sp, "%d", curr_stats->CurrentConnections);
1341         } else
1342             sp = sblank;
1343         code = mini_justify(sp, /*Src buffer */
1344                             lightdata->label,   /*Dest buffer */
1345                             LIGHTOBJ_CONN_WIDTH,        /*Dest's width */
1346                             SCOUT_RIGHT_JUSTIFY,        /*Right-justify */
1347                             SCOUT_LEFT_TRUNC,   /*Left-truncate */
1348                             SCOUT_ISNT_LDISK);  /*Not a labeled disk */
1349         if (scout_attn_conn != SCOUT_ATTN_NOTUSED
1350             && curr_stats->CurrentConnections >= scout_attn_conn)
1351             setting = 1;
1352         else
1353             setting = 0;
1354         code = gator_light_set(curr_line->currConns_lp, setting);
1355
1356         lightdata = (struct gator_lightobj *)(curr_line->fetches_lp->o_data);
1357         if (*curr_probeOK == 0) {
1358             sp = s;
1359             sprintf(sp, "%d", curr_stats->TotalFetchs);
1360         } else
1361             sp = sblank;
1362         code = mini_justify(sp, /*Src buffer */
1363                             lightdata->label,   /*Dest buffer */
1364                             LIGHTOBJ_FETCH_WIDTH,       /*Dest's width */
1365                             SCOUT_RIGHT_JUSTIFY,        /*Right-justify */
1366                             SCOUT_LEFT_TRUNC,   /*Left-truncate */
1367                             SCOUT_ISNT_LDISK);  /*Not a labeled disk */
1368         if (scout_attn_fetch != SCOUT_ATTN_NOTUSED
1369             && curr_stats->TotalFetchs >= scout_attn_fetch)
1370             setting = 1;
1371         else
1372             setting = 0;
1373         code = gator_light_set(curr_line->fetches_lp, setting);
1374
1375         lightdata = (struct gator_lightobj *)(curr_line->stores_lp->o_data);
1376         if (*curr_probeOK == 0) {
1377             sp = s;
1378             sprintf(sp, "%d", curr_stats->TotalStores);
1379         } else
1380             sp = sblank;
1381         code = mini_justify(sp, /*Src buffer */
1382                             lightdata->label,   /*Dest buffer */
1383                             LIGHTOBJ_STORE_WIDTH,       /*Dest's width */
1384                             SCOUT_RIGHT_JUSTIFY,        /*Right-justify */
1385                             SCOUT_LEFT_TRUNC,   /*Left-truncate */
1386                             SCOUT_ISNT_LDISK);  /*Not a labeled disk */
1387         if (scout_attn_store != SCOUT_ATTN_NOTUSED
1388             && curr_stats->TotalStores >= scout_attn_store)
1389             setting = 1;
1390         else
1391             setting = 0;
1392         code = gator_light_set(curr_line->stores_lp, setting);
1393
1394         lightdata =
1395             (struct gator_lightobj *)(curr_line->workstations_lp->o_data);
1396         if (*curr_probeOK == 0) {
1397             sp = s;
1398             sprintf(sp, "%d", curr_stats->WorkStations);
1399         } else
1400             sp = sblank;
1401         code = mini_justify(sp, /*Src buffer */
1402                             lightdata->label,   /*Dest buffer */
1403                             LIGHTOBJ_WK_WIDTH,  /*Dest's width */
1404                             SCOUT_RIGHT_JUSTIFY,        /*Right-justify */
1405                             SCOUT_LEFT_TRUNC,   /*Left-truncate */
1406                             SCOUT_ISNT_LDISK);  /*Not a labeled disk */
1407         if (scout_attn_workstations != SCOUT_ATTN_NOTUSED
1408             && curr_stats->WorkStations >= scout_attn_workstations)
1409             setting = 1;
1410         else
1411             setting = 0;
1412         code = gator_light_set(curr_line->workstations_lp, setting);
1413
1414         /*
1415          * We turn the server light on if there was an error in the
1416          * current probe (e.g., if the curr_probeOK field is non-zero.
1417          * (Don't forget to fix the light's line if it needs it).
1418          */
1419         setting = (*curr_probeOK) ? 1 : 0;
1420         code = gator_light_set(curr_line->srvName_lp, setting);
1421
1422         /*
1423          * Print out the disk statistics.  The value returned is the
1424          * number of lines taken up by the server record (or 0 if
1425          * something went wrong).
1426          */
1427         code = mini_PrintDiskStats(curr_line,   /*Ptr to server line */
1428                                    curr_stats,  /*Fresh disk stats */
1429                                    *curr_probeOK,       /*Was probe OK? */
1430                                    width_changed,       /*Has the width changed? */
1431                                    fix_line_num,        /*Fix the line number? */
1432                                    delta_line_num);     /*Change in line number */
1433         if (code == 0) {
1434             fprintf(stderr, "[%s] Error in printing out disk statistics\n",
1435                     rn);
1436             return (-1);
1437         } else
1438             curr_line_num += code;
1439
1440         /*
1441          * Advance the current mini_line, stats source, and probe success
1442          * indication.
1443          */
1444         curr_line++;
1445         curr_stats++;
1446         curr_probeOK++;
1447
1448     }                           /*for each server probed */
1449
1450     /*
1451      * Display the scout frame.
1452      */
1453     sprintf(s, "Probe %d results", fsprobe_Results.probeNum);
1454     gtxframe_DisplayString(scout_frame, s);
1455     WOP_DISPLAY(scout_gwin);
1456
1457     /*
1458      * Return the happy news.
1459      */
1460     return (0);
1461
1462 }                               /*FS_Handler */
1463
1464 /*------------------------------------------------------------------------
1465  * init_mini_line
1466  *
1467  * Description:
1468  *      Initialize each line in the mini_screen.
1469  *
1470  * Arguments:
1471  *      struct sockaddr_in *a_skt : Ptr to server socket info.
1472  *      int a_lineNum;            : Line number being created.
1473  *      struct mini_line *a_line  : Ptr to mini_line to set up.
1474  *      char *a_srvname           : Printable server name.
1475  *
1476  * Returns:
1477  *      0 on success,
1478  *      Error value otherwise.
1479  *
1480  * Environment:
1481  *      Nothing interesting.
1482  *
1483  * Side Effects:
1484  *      As advertised.
1485  *------------------------------------------------------------------------*/
1486
1487 static int
1488 init_mini_line(struct sockaddr_in *a_skt, int a_lineNum, 
1489                struct mini_line *a_line, char *a_srvname)
1490 {                               /*init_mini_line */
1491
1492     static char rn[] = "init_mini_line";        /*Routine name */
1493     int curr_x;                 /*Current X position */
1494     int curr_y;                 /*Current Y position */
1495     char s[128];                /*Scratch buffer */
1496     int code;                   /*Return code */
1497     struct gator_lightobj *lightdata;   /*Private light data */
1498
1499     if (scout_debug) {
1500         fprintf(scout_debugfd, "[%s] Called for base line %d\n", rn,
1501                 a_lineNum);
1502         fflush(scout_debugfd);
1503     }
1504
1505     /*
1506      * Fill in the top fields (except the disk fields, which will be
1507      * done elsewhere), then create the light onodes.
1508      */
1509     memcpy((char *)&(a_line->skt), (char *)a_skt, sizeof(struct sockaddr_in));
1510     a_line->numDisks = 0;
1511     a_line->base_line = a_lineNum + scout_screen.base_line_num;
1512     a_line->num_lines = 1;
1513
1514     curr_x = 0;
1515     curr_y = a_line->base_line;
1516     if ((a_line->currConns_lp =
1517          mini_initLightObject("Conns", curr_x, curr_y, LIGHTOBJ_CONN_WIDTH,
1518                               scout_gwin))
1519         == NULL) {
1520         fprintf(stderr, "[%s:%s] Can't create currConns light object\n", pn,
1521                 rn);
1522         return (-1);
1523     }
1524     curr_x += LIGHTOBJ_CONN_WIDTH + 1;
1525
1526     if ((a_line->fetches_lp =
1527          mini_initLightObject("Fetches", curr_x, curr_y, LIGHTOBJ_FETCH_WIDTH,
1528                               scout_frame->window))
1529         == NULL) {
1530         fprintf(stderr, "[%s:%s] Can't create fetches light object\n", pn,
1531                 rn);
1532         return (-1);
1533     }
1534     curr_x += LIGHTOBJ_FETCH_WIDTH + 1;
1535
1536     if ((a_line->stores_lp =
1537          mini_initLightObject("Stores", curr_x, curr_y, LIGHTOBJ_STORE_WIDTH,
1538                               scout_frame->window))
1539         == NULL) {
1540         fprintf(stderr, "[%s:%s] Can't create stores light object\n", pn, rn);
1541         return (-1);
1542     }
1543     curr_x += LIGHTOBJ_STORE_WIDTH + 1;
1544
1545     if ((a_line->workstations_lp =
1546          mini_initLightObject("WrkStn", curr_x, curr_y, LIGHTOBJ_WK_WIDTH,
1547                               scout_frame->window))
1548         == NULL) {
1549         fprintf(stderr, "[%s:%s] Can't create workstations light object\n",
1550                 pn, rn);
1551         return (-1);
1552     }
1553     curr_x += LIGHTOBJ_WK_WIDTH + 1;
1554
1555     if ((a_line->srvName_lp =
1556          mini_initLightObject(a_srvname, curr_x, curr_y,
1557                               LIGHTOBJ_SRVNAME_WIDTH, scout_frame->window))
1558         == NULL) {
1559         fprintf(stderr, "[%s:%s] Can't create server name light object\n", pn,
1560                 rn);
1561         return (-1);
1562     }
1563     sprintf(s, "%s", a_srvname);
1564     lightdata = (struct gator_lightobj *)(a_line->srvName_lp->o_data);
1565     code = mini_justify(s,      /*Src buffer */
1566                         lightdata->label,       /*Dest buffer */
1567                         LIGHTOBJ_SRVNAME_WIDTH, /*Dest's width */
1568                         SCOUT_CENTER,   /*Centered */
1569                         SCOUT_RIGHT_TRUNC,      /*Right-truncate */
1570                         SCOUT_ISNT_LDISK);      /*Not a labeled disk */
1571     if (code) {
1572         fprintf(stderr,
1573                 "[%s] Can't center server name inside of light object\n", rn);
1574         return (code);
1575     }
1576     curr_x += LIGHTOBJ_SRVNAME_WIDTH + 1;
1577
1578     if (scout_initDiskLightObjects(a_line, scout_frame->window)) {
1579         fprintf(stderr, "[%s:%s] Can't create disk light objects\n", pn, rn);
1580         return (-1);
1581     }
1582
1583     /*
1584      * Finally, return the happy news.
1585      */
1586     return (0);
1587
1588 }                               /*init_mini_line */
1589
1590 /*------------------------------------------------------------------------
1591  * execute_scout
1592  *
1593  * Description:
1594  *      Workhorse routine that starts up the FileServer probe.
1595  *
1596  * Arguments:
1597  *      int a_numservers                : Length of above list.
1598  *      struct cmd_item *a_srvname      : List of FileServer machines to
1599  *                                        monitor.
1600  *      int a_pkg                       : Window package to use.
1601  *
1602  * Returns:
1603  *      0 on success,
1604  *      Error value otherwise.
1605  *
1606  * Environment:
1607  *      Nothing interesting.
1608  *
1609  * Side Effects:
1610  *      As advertised.
1611  *------------------------------------------------------------------------*/
1612
1613 static int
1614 execute_scout(int a_numservers, struct cmd_item *a_srvname, int a_pkg)
1615 {                               /*execute_scout */
1616
1617     static char rn[] = "execute_scout"; /*Routine name */
1618     static char fullsrvname[128];       /*Full server name */
1619     register int code;          /*Return code */
1620     struct sockaddr_in *FSSktArray;     /*Server socket array */
1621     int sktbytes;               /*Num bytes in above */
1622     struct sockaddr_in *curr_skt;       /*Ptr to current socket */
1623     struct cmd_item *curr_item; /*Ptr to current cmd item */
1624     struct hostent *he;         /*Host entry */
1625     struct mini_line *mini_lines;       /*Ptr to all mini-lines */
1626     struct mini_line *curr_line;        /*Ptr to current line */
1627     int i;                      /*Generic loop variable */
1628     int mini_line_bytes;        /*Num bytes in mini_lines */
1629     struct timeval tv;          /*Time structure */
1630     int linenum;                /*Current mini-line number */
1631 #if 0
1632     PROCESS pid;                /*Main LWP process ID */
1633     PROCESS gxlistener_ID;      /*Input Server LWP process ID */
1634 #endif /* 0 */
1635     struct gator_lightobj *lightdata;   /*Private light data */
1636
1637     if (scout_debug) {
1638         fprintf(scout_debugfd, "[%s] Called\n", rn);
1639         fflush(scout_debugfd);
1640     }
1641
1642     /*
1643      * We have to initialize LWP support before we start up any of
1644      * our packages.
1645      */
1646 #if 0
1647     code = LWP_InitializeProcessSupport(LWP_NORMAL_PRIORITY, &pid);
1648     if (code) {
1649         fprintf(stderr, "[%s:%s] Can't initialize LWP\n", pn, rn);
1650         scout_CleanExit(code);
1651     }
1652 #endif /* 0 */
1653
1654     /*
1655      * Initialize the gtx package.
1656      */
1657 #if 0
1658     fprintf(stderr, "[%s:%s] Starting up gtx package\n", pn, rn);
1659 #endif /* 0 */
1660     scout_gwin = gtx_Init(0,    /*Don't start up InputServer yet */
1661                           -1);  /*Type of window package */
1662     if (scout_gwin == NULL) {
1663         fprintf(stderr, "[%s:%s] Call to gtx_Init() failed!\n", pn, rn);
1664         return (-1);
1665     }
1666
1667     /*
1668      * Remember we've set up gtx so we can exit cleanly from now on.
1669      */
1670     scout_gtx_initialized = 1;
1671
1672     /*
1673      * Create the frame everything will go into, set it up as our only
1674      * frame for this window.
1675      */
1676     scout_frame = gtxframe_Create();
1677     if (scout_frame == (struct gtx_frame *)0) {
1678         fprintf(stderr, "[%s:%s] Call to gtxframe_Create() failed!\n", pn,
1679                 rn);
1680         return (-1);
1681     }
1682     gtxframe_SetFrame(scout_gwin, scout_frame);
1683     WOP_GETDIMENSIONS(scout_frame->window, &scout_frameDims);
1684
1685     /*
1686      * Allocate an array of sockets to describe each FileServer we'll be
1687      * watching.
1688      */
1689     sktbytes = a_numservers * sizeof(struct sockaddr_in);
1690     FSSktArray = (struct sockaddr_in *)malloc(sktbytes);
1691     if (FSSktArray == (struct sockaddr_in *)0) {
1692         fprintf(stderr,
1693                 "[%s] Can't malloc() %d sockaddrs (%d bytes) for the given servers\n",
1694                 rn, a_numservers, sktbytes);
1695         scout_CleanExit(-1);
1696     }
1697     memset(FSSktArray, 0, sktbytes);
1698
1699     /*
1700      * Sweep through the server names provided, filling in the socket
1701      * info for each.  Take into account the fact that we may have a
1702      * base name associated for each.
1703      */
1704     curr_item = a_srvname;
1705     curr_skt = FSSktArray;
1706     while (curr_item) {
1707         if (*scout_basename == '\0')
1708             sprintf(fullsrvname, "%s", curr_item->data);
1709         else
1710             sprintf(fullsrvname, "%s.%s", curr_item->data, scout_basename);
1711         he = hostutil_GetHostByName(fullsrvname);
1712         if (he == NULL) {
1713             fprintf(stderr, "[%s] Can't get host info for '%s'\n", rn,
1714                     fullsrvname);
1715             return (-1);
1716         }
1717         memcpy(&(curr_skt->sin_addr.s_addr), he->h_addr, 4);
1718 #if defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
1719         curr_skt->sin_family = AF_INET;         /*Internet family */
1720 #else
1721         curr_skt->sin_family = htons(AF_INET);  /*Internet family */
1722 #endif
1723         curr_skt->sin_port = htons(7000);       /*FileServer port */
1724
1725         /*
1726          * Bump our pointers.
1727          */
1728         curr_item = curr_item->next;
1729         curr_skt++;
1730
1731     }                           /*Build socket entry for each server */
1732
1733     /*
1734      * Create the set of mini-lines, one per server.
1735      */
1736     mini_line_bytes = a_numservers * sizeof(struct mini_line);
1737     mini_lines = (struct mini_line *)malloc(mini_line_bytes);
1738     if (mini_lines == (struct mini_line *)0) {
1739         fprintf(stderr, "[%s] Can't malloc() %d bytes for %d screen lines\n",
1740                 rn, mini_line_bytes, a_numservers);
1741         return (-1);
1742     }
1743     memset(mini_lines, 0, mini_line_bytes);
1744
1745     /*
1746      * Set up each line in the mini_lines, creating and initializing
1747      * its light objects.
1748      */
1749     scout_screen.base_line_num = 4;
1750     curr_line = mini_lines;
1751     curr_skt = FSSktArray;
1752     linenum = 0;
1753     curr_item = a_srvname;
1754     gtxframe_ClearList(scout_frame);
1755
1756     /*
1757      * Create the light objects that server as banner lines.  Remember
1758      * to take into account the server basename, if any, and the name
1759      * of the host that scout if running on, if that's wanted.
1760      */
1761     if (scout_showhostname) {
1762         if (*scout_basename == '\0')
1763             sprintf(scout_Banner, "[%s] %s", scout_hostname, "Scout");
1764         else
1765             sprintf(scout_Banner, "[%s] Scout for %s", scout_hostname,
1766                     scout_basename);
1767     } else {
1768         if (*scout_basename == '\0')
1769             sprintf(scout_Banner, "%s", " Scout");
1770         else
1771             sprintf(scout_Banner, " Scout for %s", scout_basename);
1772     }
1773     scout_banner0_lp = mini_initLightObject("Banner 0", /*Light name */
1774                                             0, /*X*/ 0, /*Y*/ scout_frameDims.maxx,     /*Width */
1775                                             scout_gwin);        /*Window */
1776     if (scout_banner0_lp != NULL) {
1777         lightdata = (struct gator_lightobj *)(scout_banner0_lp->o_data);
1778         code =
1779             mini_justify(scout_Banner, lightdata->label, scout_frameDims.maxx,
1780                          SCOUT_CENTER, SCOUT_RIGHT_TRUNC, SCOUT_ISNT_LDISK);
1781         code = gator_light_set(scout_banner0_lp, 1);
1782         code = gtxframe_AddToList(scout_frame, scout_banner0_lp);
1783
1784         /*Debugging */
1785         if (scout_debug)
1786             fprintf(scout_debugfd, "[%s] Scout label is '%s', %lu chars\n", rn,
1787                     lightdata->label, strlen(lightdata->label));
1788     }
1789
1790     scout_banner1_lp = mini_initLightObject("Banner 1", /*Light name */
1791                                             0, /*X*/ 2, /*Y*/ scout_frameDims.maxx,     /*Width */
1792                                             scout_gwin);        /*Window */
1793     if (scout_banner1_lp != NULL) {
1794         if (scout_attn_disk_mode == SCOUT_DISKM_PCUSED) {
1795             sprintf(scout_Banner, "%s > %s%% used", scout_LightLabels,
1796                     scout_attn_disk_pcusedstr);
1797         } else {
1798             sprintf(scout_Banner, "%s < %d blocks free", scout_LightLabels,
1799                     scout_attn_disk_minfree);
1800         }
1801         lightdata = (struct gator_lightobj *)(scout_banner1_lp->o_data);
1802         code =
1803             mini_justify(scout_Banner, lightdata->label, scout_frameDims.maxx,
1804                          SCOUT_LEFT_JUSTIFY, SCOUT_RIGHT_TRUNC,
1805                          SCOUT_ISNT_LDISK);
1806
1807         code = gtxframe_AddToList(scout_frame, scout_banner1_lp);
1808     }
1809
1810     scout_banner2_lp = mini_initLightObject("Banner 2", /*Light name */
1811                                             0, /*X*/ 3, /*Y*/ scout_frameDims.maxx,     /*Width */
1812                                             scout_gwin);        /*Window */
1813     if (scout_banner2_lp != NULL) {
1814         lightdata = (struct gator_lightobj *)(scout_banner2_lp->o_data);
1815         code =
1816             mini_justify(scout_LightLabelUnd, lightdata->label,
1817                          scout_frameDims.maxx, SCOUT_LEFT_JUSTIFY,
1818                          SCOUT_RIGHT_TRUNC, SCOUT_ISNT_LDISK);
1819         code = gtxframe_AddToList(scout_frame, scout_banner2_lp);
1820     }
1821
1822     for (i = 0; i < a_numservers; i++) {
1823         code = init_mini_line(curr_skt, linenum, curr_line, curr_item->data);
1824         if (code) {
1825             fprintf(stderr, "[%s] Can't initialize line for server %d\n", rn,
1826                     i);
1827             return (-1);
1828         }
1829         curr_skt++;
1830         curr_line++;
1831         linenum++;
1832         curr_item = curr_item->next;
1833     }
1834
1835     /*
1836      * Now that all lines have been set up, we feed in the light items
1837      * created.  Note: the disk lights are entered at a later time,
1838      * as they enter the used disk list for each server.
1839      */
1840     curr_line = mini_lines;
1841     for (i = 0; i < a_numservers; i++) {
1842         code = gtxframe_AddToList(scout_frame, curr_line->currConns_lp);
1843         if (code) {
1844             fprintf(stderr,
1845                     "[%s] Can't add client connections light to display list\n",
1846                     rn);
1847             return (code);
1848         }
1849
1850         code = gtxframe_AddToList(scout_frame, curr_line->fetches_lp);
1851         if (code) {
1852             fprintf(stderr,
1853                     "[%s] Can't add fetches light to frame display list\n",
1854                     rn);
1855             return (code);
1856         }
1857
1858         code = gtxframe_AddToList(scout_frame, curr_line->stores_lp);
1859         if (code) {
1860             fprintf(stderr,
1861                     "[%s] Can't add stores light to frame display list\n",
1862                     rn);
1863             return (code);
1864         }
1865
1866         code = gtxframe_AddToList(scout_frame, curr_line->workstations_lp);
1867         if (code) {
1868             fprintf(stderr,
1869                     "[%s] Can't add workstation light to display list\n", rn);
1870             return (code);
1871         }
1872
1873         code = gtxframe_AddToList(scout_frame, curr_line->srvName_lp);
1874         if (code) {
1875             fprintf(stderr,
1876                     "[%s] Can't add server name light to display list\n", rn);
1877             return (code);
1878         }
1879
1880         /*
1881          * Move down to the next server record.
1882          */
1883         curr_line++;
1884
1885     }                           /*Add lights in server records to display list */
1886
1887 #if 0
1888     /*
1889      * Set up the minimal keymap.
1890      */
1891     code = keymap_BindToString(scout_frame->keymap,     /*Ptr to keymap */
1892                                "e",     /*Key to bind */
1893                                ExitCmd, /*Cmd to execute */
1894                                NULL,    /*Name */
1895                                NULL);   /*Ptr to rock */
1896     if (code) {
1897         fprintf(stderr, "[%s] Can't bind key `e', code is %d\n", rn, code);
1898         return (code);
1899     }
1900 #endif /* 0 */
1901
1902     /*
1903      * Finish setting up the overall mini_screen structure.
1904      */
1905     scout_screen.numServers = a_numservers;
1906     scout_screen.line = mini_lines;
1907     WOP_GETDIMENSIONS(scout_frame->window, &scout_frameDims);
1908
1909     /*
1910      * Start up the fsprobe package, which will gather FileServer
1911      * statistics for us on a regular basis.
1912      */
1913     gtxframe_DisplayString(scout_frame,
1914                            "Establishing File Server connection(s)...");
1915     code = fsprobe_Init(a_numservers,   /*Num FileServers to probe */
1916                         FSSktArray,     /*FileServer socket array */
1917                         scout_probefreq,        /*Probe frequency */
1918                         FS_Handler,     /*Handler routine */
1919                         0);     /*Turn debugging output off */
1920 #if 0
1921     scout_debug);               /*Turn debugging output off */
1922 #endif /* 0 */
1923     if (code) {
1924         fprintf(stderr, "[%s] Error returned by fsprobe_Init: %d\n", rn,
1925                 code);
1926         return (-1);
1927     }
1928
1929
1930     /*
1931      * Start up the input server LWP for our window.
1932      */
1933 #if 0
1934     code = LWP_CreateProcess(gtx_InputServer,   /*Fcn to start up */
1935                              8192,      /*Stack size in bytes */
1936                              LWP_NORMAL_PRIORITY,       /*Priority */
1937                              (void *)scout_gwin,        /*Params: Ptr to window */
1938                              "gx-listener",     /*Name to use */
1939                              &gxlistener_ID);   /*Returned LWP process ID */
1940 #endif /* 0 */
1941
1942     code = (int) gtx_InputServer(scout_gwin);
1943     if (code) {
1944         fprintf(stderr,
1945                 "[%s] Error exit from gtx_InputServer(), error is %d\n", rn,
1946                 code);
1947         scout_CleanExit(code);
1948     }
1949
1950     /*
1951      * We fall into a loop, sleeping forever.
1952      */
1953     while (1) {
1954         tv.tv_sec = 60 * 60;    /*Sleep for an hour at a time */
1955         tv.tv_usec = 0;
1956         code = select(0,        /*Num fds */
1957                       0,        /*Descriptors ready for reading */
1958                       0,        /*Descriptors ready for writing */
1959                       0,        /*Descriptors with exceptional conditions */
1960                       &tv);     /*Timeout structure */
1961     }                           /*Sleep forever */
1962
1963 #if 0
1964     /*
1965      * How did we get here?  Oh, well, clean up our windows and
1966      * return sweetness and light anyway.
1967      */
1968     WOP_CLEANUP(&scout_gwin);
1969     return (0);
1970 #endif /* 0 */
1971
1972 }                               /*execute_scout */
1973
1974 /*------------------------------------------------------------------------
1975  * countServers
1976  *
1977  * Description:
1978  *      Given a pointer to the list of servers we'll be polling,
1979  *      compute the length of the list.
1980  *
1981  * Arguments:
1982  *      struct cmd_item *a_firstItem : Ptr to first item in list.
1983  *
1984  * Returns:
1985  *      Length of the above list.
1986  *
1987  * Environment:
1988  *      Nothing interesting.
1989  *
1990  * Side Effects:
1991  *      As advertised.
1992  *------------------------------------------------------------------------*/
1993
1994 static int countServers(struct cmd_item *a_firstItem)
1995 {                               /*countServers */
1996
1997     int list_len;               /*List length */
1998     struct cmd_item *curr_item; /*Ptr to current item */
1999
2000     list_len = 0;
2001     curr_item = a_firstItem;
2002
2003     /*
2004      * Count 'em up.
2005      */
2006     while (curr_item) {
2007         list_len++;
2008         curr_item = curr_item->next;
2009     }
2010
2011     /*
2012      * Return our tally.
2013      */
2014     return (list_len);
2015
2016 }                               /*countServers */
2017
2018 /*------------------------------------------------------------------------
2019  * scout_AdoptThresholds
2020  *
2021  * Description:
2022  *      Parse and adopt one or more threshold values, as read off the
2023  *      command line.
2024  *
2025  * Arguments:
2026  *      struct cmd_item *a_thresh_item : Ptr to item on command-line
2027  *                                       threshold list.
2028  *
2029  * Returns:
2030  *      Nothing (but may exit the entire program on error!)
2031  *
2032  * Environment:
2033  *      Valid keywords are:
2034  *          conn, disk, fetch, store, ws
2035  *      The disk value, if it has a % sign, signifies that attention
2036  *      will be triggered when the disk is more than that percentage
2037  *      full; otherwise, it will specify the minimum number of free
2038  *      blocks.
2039  *
2040  * Side Effects:
2041  *      As specified.
2042  *------------------------------------------------------------------------*/
2043
2044 static void scout_AdoptThresholds(struct cmd_item *a_thresh_item)
2045 {                               /*scout_AdoptThresholds */
2046
2047     static char rn[] = "scout_AdoptThresholds"; /*Routine name */
2048     struct cmd_item *curr_item; /*Current item */
2049     char *curr_name;            /*Current name half of pair */
2050     char *curr_value;           /*Current value half of pair */
2051     int diskval_len;            /*Length of disk attn value */
2052
2053     curr_item = a_thresh_item;
2054     while (curr_item) {
2055         /*
2056          * If there isn't a corresponding value for the current
2057          * attention field, bitch & die.
2058          */
2059         if (curr_item->next == (struct cmd_item *)0) {
2060             printf("[%s] No threshold value given for '%s'\n", rn,
2061                    curr_item->data);
2062             scout_CleanExit(-1);
2063         }
2064
2065         curr_name = curr_item->data;
2066         curr_value = curr_item->next->data;
2067
2068         if (strcmp(curr_name, "conn") == 0) {
2069             if (scout_debug) {
2070                 fprintf(scout_debugfd,
2071                         "[%s] Setting conn attn value to %d (default %d)\n",
2072                         rn, atoi(curr_value), scout_attn_conn);
2073                 fflush(scout_debugfd);
2074             }
2075             scout_attn_conn = atoi(curr_value);
2076         } else if (strcmp(curr_name, "disk") == 0) {
2077             /*
2078              * If there's a '%' as the last character in the value,
2079              * we use percentage mode.
2080              */
2081             diskval_len = strlen(curr_value);
2082             if (curr_value[diskval_len - 1] == '%') {
2083                 curr_value[diskval_len - 1] = '\0';
2084                 if (scout_debug) {
2085                     fprintf(scout_debugfd,
2086                             "[%s] New disk attn value: 0.%s used (default %f)\n",
2087                             rn, curr_value, scout_attn_disk_pcused);
2088                     fflush(scout_debugfd);
2089                 }
2090                 sprintf(scout_attn_disk_pcusedstr, "%s", curr_value);
2091                 scout_attn_disk_pcused =
2092                     ((float)(atoi(curr_value))) / ((float)(100));
2093             } /*Percentage mode */
2094             else {
2095                 if (scout_debug) {
2096                     fprintf(scout_debugfd,
2097                             "[%s] New disk attn value: %s min free (default %f)\n",
2098                             rn, curr_value, scout_attn_disk_pcused);
2099                     fflush(scout_debugfd);
2100                 }
2101                 scout_attn_disk_mode = SCOUT_DISKM_MINFREE;
2102                 scout_attn_disk_minfree = atoi(curr_value);
2103             }                   /*Min free blocks mode */
2104         } else if (strcmp(curr_name, "fetch") == 0) {
2105             if (scout_debug) {
2106                 fprintf(scout_debugfd,
2107                         "[%s] Setting fetch attn value to %d (default %d)\n",
2108                         rn, atoi(curr_value), scout_attn_fetch);
2109                 fflush(scout_debugfd);
2110             }
2111             scout_attn_fetch = atoi(curr_value);
2112         } else if (strcmp(curr_name, "store") == 0) {
2113             if (scout_debug) {
2114                 fprintf(scout_debugfd,
2115                         "[%s] Setting store attn value to %d (default %d)\n",
2116                         rn, atoi(curr_value), scout_attn_store);
2117                 fflush(scout_debugfd);
2118             }
2119             scout_attn_store = atoi(curr_value);
2120         } else if (strcmp(curr_name, "ws") == 0) {
2121             if (scout_debug) {
2122                 fprintf(scout_debugfd,
2123                         "[%s] Setting workstation attn value to %d (default %d)\n",
2124                         rn, atoi(curr_value), scout_attn_workstations);
2125                 fflush(scout_debugfd);
2126             }
2127             scout_attn_workstations = atoi(curr_value);
2128         } else {
2129             printf("[%s] Unknown attention item: '%s'\n", rn,
2130                    curr_item->data);
2131             scout_CleanExit(-1);
2132         }
2133
2134         /*
2135          * Advance past the just-processed pair.
2136          */
2137         curr_item = curr_item->next->next;
2138
2139     }                           /*Interpret each name-value pair */
2140
2141 }                               /*scout_AdoptThresholds */
2142
2143 /*------------------------------------------------------------------------
2144  * scoutInit
2145  *
2146  * Description:
2147  *      Routine called when Scout is invoked, responsible for basic
2148  *      initialization, command line parsing, and calling the
2149  *      routine that does all the work.
2150  *
2151  * Arguments:
2152  *      as      : Command syntax descriptor.
2153  *      arock   : Associated rock (not used here).
2154  *
2155  * Returns:
2156  *      Zero (but may exit the entire program on error!)
2157  *
2158  * Environment:
2159  *      Nothing interesting.
2160  *
2161  * Side Effects:
2162  *      Initializes this program.
2163  *------------------------------------------------------------------------*/
2164
2165 static int scoutInit(struct cmd_syndesc *as, void *arock)
2166 {                               /*scoutInit */
2167
2168     static char rn[] = "scoutInit";     /*Routine name */
2169     int code;                   /*Return code */
2170     int wpkg_to_use;            /*Window package to use */
2171     int server_count;           /*Number of servers to watch */
2172     char *debug_filename;       /*Name of debugging output file */
2173
2174     if (scout_debug) {
2175         fprintf(scout_debugfd, "[%s] Called\n", rn);
2176         fflush(scout_debugfd);
2177     }
2178
2179     if (as->parms[P_DEBUG].items != 0) {
2180         scout_debug = 1;
2181         debug_filename = as->parms[P_DEBUG].items->data;
2182         scout_debugfd = fopen(debug_filename, "w");
2183         if (scout_debugfd == (FILE *) 0) {
2184             printf("[%s] Can't open debugging file '%s'!\n", rn,
2185                    debug_filename);
2186             scout_CleanExit(-1);
2187         }
2188         fprintf(scout_debugfd, "[%s] Writing to Scout debugging file '%s'\n",
2189                 rn, debug_filename);
2190     }
2191 #if 0
2192     wpkg_to_use = atoi(as->parms[P_PACKAGE].items->data);
2193 #endif /* 0 */
2194     wpkg_to_use = 2;            /*Always use curses for now */
2195 #if 0
2196     fprintf(stderr, "[%s:%s] Using graphics package %d: ", pn, rn,
2197             wpkg_to_use);
2198     switch (wpkg_to_use) {
2199     case GATOR_WIN_CURSES:
2200         fprintf(stderr, "curses\n");
2201         break;
2202     case GATOR_WIN_DUMB:
2203         fprintf(stderr, "dumb terminal\n");
2204         break;
2205     case GATOR_WIN_X11:
2206         fprintf(stderr, "X11\n");
2207         break;
2208     default:
2209         fprintf(stderr, "Illegal graphics package: %d\n", wpkg_to_use);
2210         scout_CleanExit(-1);
2211     }                           /*end switch (wpkg_to_use) */
2212 #endif /* 0 */
2213
2214     if (as->parms[P_FREQ].items != 0)
2215         scout_probefreq = atoi(as->parms[P_FREQ].items->data);
2216     else
2217         scout_probefreq = 60;
2218
2219     /*
2220      * See if we've been fed a base server name.
2221      */
2222     if (as->parms[P_BASE].items != 0)
2223         sprintf(scout_basename, "%s", as->parms[P_BASE].items->data);
2224     else
2225         *scout_basename = '\0';
2226
2227     /*
2228      * Count the number of servers we've been asked to monitor.
2229      */
2230     server_count = countServers(as->parms[P_SERVER].items);
2231
2232     /*
2233      * Create a line of blanks, a generally-useful thing.
2234      */
2235     sprintf(scout_blankline, "%255s", " ");
2236
2237     /*
2238      * Pull in the name of the host we're executing on if we've been
2239      * asked to.  If we can't get the name, we provide a default.
2240      */
2241     if (as->parms[P_HOST].items != 0) {
2242         scout_showhostname = 1;
2243         *scout_hostname = '\0';
2244         code = gethostname(scout_hostname, 128);
2245         if (code)
2246             sprintf(scout_hostname, "%s", "*No Hostname*");
2247     }
2248
2249     /*
2250      * Pull in any and all attention/highlighting thresholds.
2251      */
2252     if (as->parms[P_ATTENTION].items != 0)
2253         scout_AdoptThresholds(as->parms[P_ATTENTION].items);
2254
2255     /*
2256      * Now, drive the sucker.
2257      */
2258     code = execute_scout(server_count,  /*Num servers */
2259                          as->parms[P_SERVER].items,     /*Ptr to srv names */
2260                          wpkg_to_use);  /*Graphics pkg */
2261     if (code) {
2262         fprintf(stderr, "[%s] Error executing scout: %d\n", rn, code);
2263         scout_CleanExit(-1);
2264     }
2265
2266     /*
2267      * We initialized (and ran) correctly, so return the good news.
2268      */
2269     return (0);
2270
2271 }                               /*scoutInit */
2272
2273 #include "AFS_component_version_number.c"
2274
2275 int
2276 main(int argc, char **argv)
2277 {                               /*main */
2278
2279     register afs_int32 code;    /*Return code */
2280     register struct cmd_syndesc *ts;    /*Ptr to cmd line syntax descriptor */
2281
2282 #ifdef  AFS_AIX32_ENV
2283     /*
2284      * The following signal action for AIX is necessary so that in case of a 
2285      * crash (i.e. core is generated) we can include the user's data section 
2286      * in the core dump. Unfortunately, by default, only a partial core is
2287      * generated which, in many cases, isn't too useful.
2288      */
2289     struct sigaction nsa;
2290
2291     sigemptyset(&nsa.sa_mask);
2292     nsa.sa_handler = SIG_DFL;
2293     nsa.sa_flags = SA_FULLDUMP;
2294     sigaction(SIGSEGV, &nsa, NULL);
2295 #endif
2296     /*
2297      * Set up the commands we understand.
2298      */
2299     ts = cmd_CreateSyntax("initcmd", scoutInit, NULL, "initialize the program");
2300     cmd_AddParm(ts, "-server", CMD_LIST, CMD_REQUIRED,
2301                 "FileServer name(s) to monitor");
2302     cmd_AddParm(ts, "-basename", CMD_SINGLE, CMD_OPTIONAL,
2303                 "base server name");
2304 #if 0
2305     cmd_AddParm(ts, "-package", CMD_SINGLE, CMD_REQUIRED,
2306                 "Graphics package to use");
2307 #endif /* 0 */
2308     cmd_AddParm(ts, "-frequency", CMD_SINGLE, CMD_OPTIONAL,
2309                 "poll frequency, in seconds");
2310     cmd_AddParm(ts, "-host", CMD_FLAG, CMD_OPTIONAL,
2311                 "show name of host you're running on");
2312     cmd_AddParm(ts, "-attention", CMD_LIST, CMD_OPTIONAL,
2313                 "specify attention (highlighting) level");
2314     cmd_AddParm(ts, "-debug", CMD_SINGLE, CMD_OPTIONAL,
2315                 "turn debugging output on to the named file");
2316
2317     /*
2318      * Parse command-line switches & execute the test, then get the heck
2319      * out of here.
2320      */
2321     code = cmd_Dispatch(argc, argv);
2322     if (code) {
2323 #if 0
2324         fprintf(stderr, "[%s:%s] Call to cmd_Dispatch() failed; code is %d\n",
2325                 pn, rn, code);
2326 #endif /* 0 */
2327         scout_CleanExit(1);
2328     } else
2329         scout_CleanExit(0);
2330
2331     return 0; /* not reachable */
2332 }                               /*main */