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