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