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