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