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