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