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