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