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