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