2 * Copyright 2000, International Business Machines Corporation and others.
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
11 * Scout: A quick and (semi-)dirty attempt at the old CMU vopcon.
12 *------------------------------------------------------------------------*/
14 #include <afsconfig.h>
15 #include <afs/param.h>
24 #include <afs/gtxwindows.h> /*Generic window package */
25 #include <afs/gtxobjects.h> /*Object definitions */
26 #include <afs/gtxtextobj.h> /*Text object interface */
27 #include <afs/gtxlightobj.h> /*Light object interface */
28 #include <afs/gtxcurseswin.h> /*Curses window package */
29 #include <afs/gtxdumbwin.h> /*Dumb terminal window package */
30 #include <afs/gtxX11win.h> /*X11 window package */
31 #include <afs/gtxframe.h> /*Frame package */
32 #include <afs/gtxinput.h>
33 #include <stdio.h> /*Standard I/O stuff */
34 #include <afs/cmd.h> /*Command interpretation library */
35 #include <afs/fsprobe.h> /*Interface for fsprobe module */
37 #include <afs/afsutil.h>
44 * Command line parameter indicies.
58 * Define the default width in chars for each light object on the mini-line.
60 #define LIGHTOBJ_CONN_WIDTH 5
61 #define LIGHTOBJ_FETCH_WIDTH 10
62 #define LIGHTOBJ_STORE_WIDTH 10
63 #define LIGHTOBJ_WK_WIDTH 5
64 #define LIGHTOBJ_SRVNAME_WIDTH 13
65 #define LIGHTOBJ_DISK_WIDTH 12
68 * Define column width indices.
78 * Define the types of justification we can perform.
80 #define SCOUT_RIGHT_JUSTIFY 0
81 #define SCOUT_LEFT_JUSTIFY 1
82 #define SCOUT_CENTER 2
85 * Define the types of truncation we can perform.
87 #define SCOUT_LEFT_TRUNC 0
88 #define SCOUT_RIGHT_TRUNC 1
91 * Define whether the value passed is a labeled disk quantity.
93 #define SCOUT_ISNT_LDISK 0
94 #define SCOUT_IS_LDISK 1
97 * We sometimes use index-base pointers, so we need a distinguished
100 #define SCOUT_NIL (-1)
103 * Structure describing everything you want to know about a FileServer
107 int prev; /*Index of previous list entry */
108 int next; /*Index of next list entry */
109 int active; /*Is this disk known to exist? */
110 char *name; /*Single-letter disk name */
111 struct onode *disk_lp; /*Ptr to disk light object */
115 * Structure defining all the objects in the Scout line (or lines)
116 * for each server being watched. Note that scout_disk linked list
117 * for used disks is ordered alphabetically.
121 * Information on server location & configuration.
123 struct sockaddr_in skt; /*Server's socket info */
124 int numDisks; /*Number of disks used */
126 * Screen location info.
128 int base_line; /*Line number on the screen */
129 int num_lines; /*Number of lines of info */
131 * Associated light objects.
133 struct onode *currConns_lp; /*Number of current connections */
134 struct onode *fetches_lp; /*Number of data fetches */
135 struct onode *stores_lp; /*Number of data stores */
136 struct onode *workstations_lp; /*Workstation info */
137 struct onode *srvName_lp; /*Server name */
138 struct scout_disk disks[VOLMAXPARTS]; /*Info on all the disks */
139 int used_head; /*Index of first used disk struct */
140 int used_tail; /*Index of last used disk struct */
141 int free_head; /*Index of first free disk struct */
142 int free_tail; /*Index of last free disk struct */
146 * Structure defining the contents of the Scout screen.
149 int numServers; /*Number of servers being watched */
150 int base_line_num; /*Base mini-line number */
151 struct mini_line *line; /*Array of screen lines */
154 static char pn[] = "scout"; /*Program name */
155 static int scout_debug = 0; /*Is debugging turned on? */
156 static FILE *scout_debugfd; /*Debugging file descriptor */
157 static int scout_gtx_initialized = 0; /*Has gtx been initialized? */
158 static struct mini_screen scout_screen; /*Mini-screen itself */
159 static int scout_probefreq; /*Probe frequency in seconds */
160 static char scout_basename[64]; /*Base server name */
161 static char scout_hostname[128]; /*Name of machine we're running on */
162 static int scout_showhostname = 0; /*Show name of machine we're on? */
163 static char scout_blankline[256]; /*Blank line */
164 static struct gwin *scout_gwin; /*Window to use */
165 static struct gtx_frame *scout_frame; /*Frame to use */
166 static struct onode *scout_banner0_lp; /*Banner light, line 0 */
167 static struct onode *scout_banner1_lp; /*Banner light, line 1 */
168 static struct onode *scout_banner2_lp; /*Banner light, line 2 */
169 static int scout_DiskLightLeftCol = 0; /*Column for leftmost disk light */
170 static struct gwin_sizeparams scout_frameDims; /*Frame dimensions */
172 static int scout_col_width[] = { LIGHTOBJ_CONN_WIDTH,
173 LIGHTOBJ_FETCH_WIDTH,
174 LIGHTOBJ_STORE_WIDTH,
176 LIGHTOBJ_SRVNAME_WIDTH,
181 * Attention thresholds & modes.
183 #define SCOUT_ATTN_NOTUSED (-1)
184 #define SCOUT_DISKM_PCUSED 0
185 #define SCOUT_DISKM_MINFREE 1
187 static int scout_attn_conn = SCOUT_ATTN_NOTUSED;
188 static int scout_attn_fetch = SCOUT_ATTN_NOTUSED;
189 static int scout_attn_store = SCOUT_ATTN_NOTUSED;
190 static int scout_attn_workstations = SCOUT_ATTN_NOTUSED;
191 static int scout_attn_disk_mode = SCOUT_DISKM_PCUSED;
192 static int scout_attn_disk_minfree = 1000;
193 static float scout_attn_disk_pcused = 0.95;
194 static char scout_attn_disk_pcusedstr[8] = "95";
197 * Some strings we'll be using over and over again.
199 static char scout_Banner[256];
200 static const char *scout_label[] =
201 { "Conn", "Fetch", "Store", "Ws", "", "Disk attn" };
202 static const char *scout_underline[] =
203 { "----", "--------", "--------", "-----", "", "----------" };
206 /*------------------------------------------------------------------------
210 * Exits cleanly from the Scout. If gtx has not yet been initialized,
211 * then we simply call exit() with the value provided. Otherwise,
212 * we call the appropriate gtx routine to exit cleanly from gtx, which
213 * must reset the terminal or window. We also close the debugging
214 * file descriptor, if one has been opened.
217 * int a_exitval : Value with which to exit the program.
223 * Actions depend on scout_gtx_initialized.
226 * This routine will always exit Scout.
227 *------------------------------------------------------------------------*/
230 scout_CleanExit(int a_exitval)
231 { /*scout_CleanExit */
233 static char rn[] = "scout_CleanExit"; /*Routine name */
235 if (scout_debugfd != (FILE *) 0) {
236 fprintf(scout_debugfd, "[%s] Closing debugging file\n", rn);
237 fclose(scout_debugfd);
240 if (scout_gtx_initialized) {
241 gtxframe_exitValue = a_exitval;
242 gtxframe_ExitCmd((void *)(>xframe_exitValue), NULL);
246 } /*scout_CleanExit */
248 /*------------------------------------------------------------------------
249 * mini_initLightObject
252 * Create and initialize a light onode according to the given
256 * char *a_name : Ptr to the light's string name.
257 * int a_x : X offset.
258 * int a_y : Y offset.
259 * int a_width : Width in chars.
260 * struct gwin *a_win : Ptr to window structure.
263 * Ptr to new light onode on success,
264 * A null pointer otherwise.
271 *------------------------------------------------------------------------*/
273 static struct onode *
274 mini_initLightObject(char *a_name, int a_x, int a_y, int a_width, struct gwin *a_win)
275 { /*mini_initLightObject */
277 static char rn[] = "mini_initLightObject"; /*Routine name */
278 struct onode *newlightp; /*Ptr to new light onode */
279 /*We only support curses right now */
280 struct gator_light_crparams light_crparams; /*Light creation params */
281 char *truncname; /*Truncated name, if needed */
282 int name_len; /*True length of name */
285 fprintf(scout_debugfd,
286 "[%s] Called for name '%s', [%d, %d], %d-char field\n", rn,
287 a_name, a_x, a_y, a_width);
288 fflush(scout_debugfd);
293 * Set up the creation parameters according to the information we've
296 light_crparams.onode_params.cr_type = GATOR_OBJ_LIGHT;
297 name_len = strlen(a_name);
299 fprintf(scout_debugfd, "[%s] Name '%s' has %d chars\n", rn, a_name,
301 if (name_len <= a_width)
302 sprintf(light_crparams.onode_params.cr_name, "%s", a_name);
305 * We need to truncate the given name, leaving a `*' at the end to
306 * show us it's been truncated.
308 truncname = light_crparams.onode_params.cr_name;
309 strncpy(truncname, a_name, a_width - 1);
310 truncname[a_width - 1] = '*';
311 truncname[a_width] = 0;
313 light_crparams.onode_params.cr_x = a_x;
314 light_crparams.onode_params.cr_y = a_y;
315 light_crparams.onode_params.cr_width = a_width;
316 light_crparams.onode_params.cr_height = 1;
317 light_crparams.onode_params.cr_window = a_win;
318 light_crparams.onode_params.cr_home_obj = NULL;
319 light_crparams.onode_params.cr_prev_obj = NULL;
320 light_crparams.onode_params.cr_parent_obj = NULL;
321 light_crparams.onode_params.cr_helpstring = NULL;
323 light_crparams.appearance = 0;
324 light_crparams.flashfreq = 0;
325 sprintf(light_crparams.label, "%s", a_name);
326 light_crparams.label_x = 0;
327 light_crparams.label_y = 0;
330 gator_objects_create((struct onode_createparams *)(&light_crparams));
333 * Return the news, happy or not.
337 } /*mini_initLightObject */
339 /*------------------------------------------------------------------------
340 * scout_initDiskLightObjects
343 * Create and initialize all Scout light objects for a server's
347 * struct scout_disk *a_line : Ptr to the server object line.
348 * struct gwin *a_win : Ptr to window structure.
359 *------------------------------------------------------------------------*/
362 scout_initDiskLightObjects(struct mini_line *a_line, struct gwin *a_win)
363 { /*scout_initDiskLightObjects */
365 static char rn[] = "scout_initDiskLightObjects"; /*Routine name */
366 struct scout_disk *curr_disk; /*Ptr to current disk being set up */
367 int i; /*Loop variable */
370 fprintf(scout_debugfd, "[%s] Called\n", rn);
371 fflush(scout_debugfd);
375 * Set up the base linked list fields.
377 a_line->used_head = SCOUT_NIL;
378 a_line->used_tail = SCOUT_NIL;
379 a_line->free_head = 0;
380 a_line->free_tail = VOLMAXPARTS - 1;
383 * Sweep through the disk structures, creating the light objects and
384 * marking them all as free.
386 curr_disk = a_line->disks;
387 for (i = 0; i < VOLMAXPARTS; i++) {
389 * Create the disk light object.
391 if ((curr_disk->disk_lp = mini_initLightObject("Disk", /*Object name */
394 scout_col_width[COL_DISK], /*Width */
397 fprintf(stderr, "[%s:%s] Can't create disk %d light object\n", pn,
403 * Set the other fields in the disk records; Note that in the
404 * fencepost cases, the prev and next pointers will have to be
407 curr_disk->prev = i - 1;
408 curr_disk->next = i + 1;
409 curr_disk->active = 0;
410 curr_disk->name = '\0';
413 * Bump up to the next disk structure.
417 } /*for each disk structure */
420 * We made it all the way through. Fix the fencepost pointers, set
421 * the overall pointers, then return success.
423 a_line->disks[0].prev = SCOUT_NIL;
424 a_line->disks[VOLMAXPARTS - 1].next = SCOUT_NIL;
428 } /*scout_initDiskLightObjects */
431 /*------------------------------------------------------------------------
435 * Place the chars in the source buffer into the target buffer
436 * with the desired justification, either centered, left-justified
437 * or right-justified. Also, support inidication of truncation
438 * with a star (*), either on the left or right of the string,
439 * and whether we're justifying a labeled disk quantity.
442 * char *a_srcbuff : Ptr to source char buffer.
443 * char *a_dstbuff : Ptr to dest char buffer.
444 * int a_dstwidth : Width of dest buffer in chars.
445 * int a_justification : Kind of justification.
446 * int a_rightTrunc : If non-zero, place the truncation char
447 * on the right of the string. Otherwise,
448 * place it on the left.
449 * int a_isLabeledDisk : Is this a labeled disk quantity?
456 * All it needs to know is exported by the fsprobe module, namely
457 * the data structure where the probe results are stored.
461 *------------------------------------------------------------------------*/
464 mini_justify(char *a_srcbuff, char *a_dstbuff, int a_dstwidth,
465 int a_justification, int a_rightTrunc,
469 static char rn[] = "mini_justify"; /*Routine name */
470 int leftpad_chars; /*# of chars for left-padding */
471 int num_src_chars; /*# of chars in source */
472 int true_num_src_chars; /*# src chars before truncation */
473 int trunc_needed; /*Is truncation needed? */
474 char diskChar = 0; /*Disk name prefix */
477 fprintf(scout_debugfd, "[%s] Called with '%s', dest width=%d\n", rn,
478 a_srcbuff, a_dstwidth);
479 fflush(scout_debugfd);
483 * Remember the disk label, if we've been passed such a thing.
486 diskChar = *a_srcbuff;
489 * If the destination width will overrun the gtx string storage,
490 * we automatically shorten up.
492 if (a_dstwidth > GATOR_LABEL_CHARS) {
494 fprintf(scout_debugfd,
495 "[%s] Dest width (%d) > gtx buflen (%d), shrinking dest width\n",
496 rn, a_dstwidth, GATOR_LABEL_CHARS);
497 fflush(scout_debugfd);
499 a_dstwidth = GATOR_LABEL_CHARS;
503 * If our source string is too long, prepare for truncation.
505 true_num_src_chars = strlen(a_srcbuff);
506 if (true_num_src_chars >= a_dstwidth) {
508 num_src_chars = a_dstwidth - 1;
511 a_srcbuff += (true_num_src_chars - num_src_chars);
514 num_src_chars = true_num_src_chars;
517 * Compute the necessary left-padding.
519 switch (a_justification) {
521 case SCOUT_RIGHT_JUSTIFY:
522 leftpad_chars = (a_dstwidth - 1) - num_src_chars;
525 case SCOUT_LEFT_JUSTIFY:
527 * This is the really easy one.
533 leftpad_chars = ((a_dstwidth - 1) - num_src_chars) / 2;
537 fprintf(stderr, "[%s] Illegal justification command: %d", rn,
540 } /*Switch on justification type */
544 * Clear out the dest buffer, then place the source string at the
545 * appropriate padding location. Remember to place a string
546 * terminator at the end of the dest buffer, plus whatever truncation
547 * may be needed. If we're left-truncating, we've already shifted
548 * the src buffer appropriately.
550 strncpy(a_dstbuff, scout_blankline, a_dstwidth);
551 strncpy(a_dstbuff + leftpad_chars, a_srcbuff, num_src_chars);
552 *(a_dstbuff + a_dstwidth - 1) = '\0';
555 *(a_dstbuff + a_dstwidth - 2) = '*'; /*Truncate on the right */
557 if (a_isLabeledDisk) {
558 *a_dstbuff = diskChar;
559 *(a_dstbuff + 1) = ':';
560 *(a_dstbuff + 2) = '*'; /*Truncate on the left, disk */
562 *a_dstbuff = '*'; /*Truncate on the left, non-disk */
566 /*Handle truncations */
568 * Return the good news.
574 /*------------------------------------------------------------------------
575 * scout_SetNonDiskLightLine
578 * Given a mini-line and a line number, place all non-disk lights
582 * struct mini_line *a_srvline : Ptr to server descriptor.
583 * int a_linenum : Line number to move to.
589 * The light's location is stored not only in the onode, but in
590 * the light's rock, so we have to change both sets of value.
594 *------------------------------------------------------------------------*/
597 scout_SetNonDiskLightLine(struct mini_line *a_srvline, int a_linenum)
598 { /*scout_SetNonDiskLightLine */
600 struct gator_lightobj *nondisk_lightdata; /*Non-disk light data field */
601 struct gwin_strparams *nondisk_strparams; /*Associated string params */
604 * Do the exact same operation for each non-disk light in the record.
606 a_srvline->currConns_lp->o_y = a_linenum;
608 (struct gator_lightobj *)(a_srvline->currConns_lp->o_data);
609 nondisk_strparams = (struct gwin_strparams *)(nondisk_lightdata->llrock);
610 nondisk_strparams->y = a_linenum;
612 a_srvline->fetches_lp->o_y = a_linenum;
614 (struct gator_lightobj *)(a_srvline->fetches_lp->o_data);
615 nondisk_strparams = (struct gwin_strparams *)(nondisk_lightdata->llrock);
616 nondisk_strparams->y = a_linenum;
618 a_srvline->stores_lp->o_y = a_linenum;
620 (struct gator_lightobj *)(a_srvline->stores_lp->o_data);
621 nondisk_strparams = (struct gwin_strparams *)(nondisk_lightdata->llrock);
622 nondisk_strparams->y = a_linenum;
624 a_srvline->workstations_lp->o_y = a_linenum;
626 (struct gator_lightobj *)(a_srvline->workstations_lp->o_data);
627 nondisk_strparams = (struct gwin_strparams *)(nondisk_lightdata->llrock);
628 nondisk_strparams->y = a_linenum;
630 a_srvline->srvName_lp->o_y = a_linenum;
632 (struct gator_lightobj *)(a_srvline->srvName_lp->o_data);
633 nondisk_strparams = (struct gwin_strparams *)(nondisk_lightdata->llrock);
634 nondisk_strparams->y = a_linenum;
636 } /*scout_SetNonDiskLightLine */
638 /*------------------------------------------------------------------------
639 * scout_RecomputeLightLocs
642 * Given a pointer to a server record, recompute its disk light
643 * locations (and keep proper track of the number of screen lines
644 * required for the server record).
647 * struct mini_line *a_srvline : Ptr to server descriptor.
650 * 0 if anything went wrong,
651 * else the number of lines used by this server record.
654 * One or more records have joined or left the used light list
655 * for this server. We're not sure which ones, so we recompute
656 * them all. We may also have had a width change in the gtx
657 * frame. The base_line field in the server record is guaranteed
658 * to be correct at this point.
662 *------------------------------------------------------------------------*/
665 scout_RecomputeLightLocs(struct mini_line *a_srvline)
666 { /*scout_RecomputeLightLocs */
668 static char rn[] = "scout_RecomputeLightLocs"; /*Routine name */
669 int lights_per_line; /*# lights/line */
670 int lights_this_line; /*# lights on cur line */
671 int curr_idx; /*Current disk light idx */
672 struct scout_disk *sc_disk; /*Ptr to disk record array */
673 int lines_for_server; /*Num lines in server record */
674 int curr_line; /*Current line being filled */
675 int curr_x; /*Current x value for light */
676 struct gator_lightobj *disk_lightdata; /*Disk light data field */
677 struct gwin_strparams *disk_strparams; /*String params for disk light */
680 fprintf(scout_debugfd, "[%s] Called\n", rn);
681 fflush(scout_debugfd);
685 * If we haven't yet computed the column for the leftmost disk light,
688 if (scout_DiskLightLeftCol == 0) {
690 int num_cols = sizeof(scout_col_width) / sizeof(*scout_col_width);
691 scout_DiskLightLeftCol = 0;
692 for (i = 0; i < (num_cols - 1); i++) {
693 scout_DiskLightLeftCol += scout_col_width[i] + 1;
698 * Calculate how many disk light objects can fit in one line.
701 (scout_frameDims.maxx -
702 scout_DiskLightLeftCol) / (scout_col_width[COL_DISK] + 1);
704 fprintf(scout_debugfd, "[%s] %d lights per line\n", rn,
706 fflush(scout_debugfd);
710 * Sweep through the used disk light list, computing the location
713 lights_this_line = 0;
714 curr_idx = a_srvline->used_head;
715 lines_for_server = 1;
716 curr_line = a_srvline->base_line;
717 curr_x = scout_DiskLightLeftCol;
719 while (curr_idx != SCOUT_NIL) {
721 * Bump the number of lines for the server if we've already
722 * filled up the current line.
724 if (lights_this_line >= lights_per_line) {
725 lights_this_line = 0;
728 curr_x = scout_DiskLightLeftCol;
731 /*Current line filled up */
733 * Set the current disk light's location.
735 sc_disk = a_srvline->disks;
736 sc_disk[curr_idx].disk_lp->o_x = curr_x;
737 sc_disk[curr_idx].disk_lp->o_y = curr_line;
739 (struct gator_lightobj *)(sc_disk[curr_idx].disk_lp->o_data);
740 disk_strparams = (struct gwin_strparams *)(disk_lightdata->llrock);
741 disk_strparams->x = curr_x;
742 disk_strparams->y = curr_line;
744 fprintf(scout_debugfd,
745 "[%s] Disk light at index %d located at [%d, %d]\n", rn,
746 curr_idx, curr_x, curr_line);
747 fflush(scout_debugfd);
751 * Record the inclusion of the light and move on to the next
755 curr_x += scout_col_width[COL_DISK] + 1;
756 curr_idx = sc_disk[curr_idx].next;
758 } /*Update each used disk light */
761 * Remember to record the (possibly new) number of lines in the
762 * server record before returning the value of that field.
764 if (a_srvline->num_lines != lines_for_server) {
766 fprintf(scout_debugfd,
767 "[%s] Server previously had %d screen lines; now changed\n",
768 rn, a_srvline->num_lines);
769 fflush(scout_debugfd);
771 a_srvline->num_lines = lines_for_server;
775 fprintf(scout_debugfd, "[%s] Server has %d screen lines\n", rn,
776 a_srvline->num_lines);
777 fflush(scout_debugfd);
779 return (a_srvline->num_lines);
781 } /*scout_RecomputeLightLocs */
783 /*------------------------------------------------------------------------
787 * Given a single-letter disk name and a pointer to the current server
788 * record, look for a used disk record with that name within the server.
789 * If we can't find one, we create and incorporate one, and return that
790 * fact to our caller.
793 * char a_diskname : Single-char disk name.
794 * struct mini_line *a_srvline : Ptr to server descriptor.
795 * int *a_record_added : Was a new record added?
798 * Index of matching used disk record,
799 * SCOUT_NIL otherwise.
801 * Return via parameter:
802 * a_record_added set to 1 iff record was added to the used disk list.
805 * Used disk records are kept in alphabetical order by the single-char
806 * disk name. Should a matching used disk record not be found, one is
807 * pulled from the free pool.
810 * An entry may be pulled off the free list and inserted into the
811 * used list. This entry is placed in the update list for the
812 * current gtx frame (at least not by this routine).
813 *------------------------------------------------------------------------*/
816 scout_FindUsedDisk(char *a_diskname, struct mini_line *a_srvline, int *a_record_added)
817 { /*scout_FindUsedDisk */
819 static char rn[] = "scout_FindUsedDisk"; /*Routine name */
820 int curr_idx; /*Disk record index */
821 int append_idx; /*Index to append after */
822 int new_idx; /*Index of new used record */
823 struct scout_disk *sc_disk; /*Ptr to disk record */
824 int code; /*Function return value */
827 fprintf(scout_debugfd, "[%s] Called\n", rn);
828 fflush(scout_debugfd);
832 * Sweep through the used disk records, looking for a match.
834 curr_idx = a_srvline->used_head;
835 append_idx = SCOUT_NIL;
836 sc_disk = a_srvline->disks;
838 fprintf(scout_debugfd,
839 "[%s] Scanning existing used disk entries for disk '%s'\n",
841 fflush(scout_debugfd);
843 while (curr_idx != SCOUT_NIL) {
845 fprintf(scout_debugfd, "[%s] Disk %d is named '%s'\n", rn,
846 curr_idx, sc_disk[curr_idx].name);
847 fflush(scout_debugfd);
849 if (strcmp(sc_disk[curr_idx].name, a_diskname) == 0) {
851 * We found it! Bug out.
854 fprintf(scout_debugfd, "[%s] Match found\n", rn);
855 fflush(scout_debugfd);
861 * If we are alphabetically past the given disk name, we
862 * know that we won't find it in the used disk list; we
863 * also have the append index set correctly.
865 if (strcmp(a_diskname, sc_disk[curr_idx].name) < 0) {
867 fprintf(scout_debugfd, "[%s] Disk '%s' can't be here\n", rn,
869 fflush(scout_debugfd);
875 * There's still hope we'll find it. Move on to the next used
876 * disk record, keeping this index as the best candidate so far
877 * for appending a missing entry.
879 append_idx = curr_idx;
880 curr_idx = sc_disk[curr_idx].next;
881 } /*Look for match */
884 * We didn't find the record we wanted, which means we'll pull a
885 * record out of the free pool for it. If we didn't find a place
886 * to append it, we then insert it at the beginning of the queue.
888 if (a_srvline->free_head == SCOUT_NIL)
891 new_idx = a_srvline->free_head;
893 fprintf(scout_debugfd, "[%s] Choosing free index %d for new entry\n",
895 fflush(scout_debugfd);
897 a_srvline->free_head = sc_disk[new_idx].next;
898 if (a_srvline->free_head == SCOUT_NIL)
899 a_srvline->free_tail = SCOUT_NIL;
902 * Fill in the new record.
904 sc_disk[new_idx].active = 0;
905 sc_disk[new_idx].name = a_diskname;
908 * Insert the new record where it belongs on the used disk list.
910 if (append_idx == SCOUT_NIL) {
912 * It belongs at the beginning of the list.
915 fprintf(scout_debugfd, "[%s] Inserted at used disk head\n", rn);
916 fflush(scout_debugfd);
918 sc_disk[new_idx].next = a_srvline->used_head;
919 sc_disk[new_idx].prev = SCOUT_NIL;
920 a_srvline->used_head = new_idx;
921 if (a_srvline->used_tail == SCOUT_NIL)
922 a_srvline->used_tail = new_idx;
925 fprintf(scout_debugfd, "[%s] Entry appended after index %d\n", rn,
927 fflush(scout_debugfd);
929 sc_disk[new_idx].prev = append_idx;
930 sc_disk[new_idx].next = sc_disk[append_idx].next;
931 sc_disk[append_idx].next = new_idx;
932 if (sc_disk[new_idx].next == SCOUT_NIL)
933 a_srvline->used_tail = new_idx;
935 sc_disk[sc_disk[new_idx].next].prev = new_idx;
939 * Add the new used disk light object to the display list for
943 fprintf(scout_debugfd,
944 "[%s] Adding disk light at index %d to display list\n", rn,
946 fflush(scout_debugfd);
948 code = gtxframe_AddToList(scout_frame, sc_disk[new_idx].disk_lp);
951 fprintf(scout_debugfd,
952 "[%s] Can't add to display list, code is %d\n", rn, code);
953 fflush(scout_debugfd);
958 } /*scout_FindUsedDisk */
960 /*------------------------------------------------------------------------
961 * scout_RemoveInactiveDisk
964 * Given a server record and a used disk index, remove the disk
965 * record from the used list, put it on the free list, and remove
966 * it from the gtx frame update list.
969 * struct mini_line *a_srvline : Ptr to server descriptor.
970 * int a_used_idx : Index of used disk record.
976 * Formerly-used disk records are returned to the free pool.
979 * Free and used disk record lists are modified for this server.
980 * The disk record in question is pulled off the gtx update list
982 *------------------------------------------------------------------------*/
985 scout_RemoveInactiveDisk(struct mini_line *a_srvline, int a_used_idx)
986 { /*scout_RemoveInactiveDisk */
988 static char rn[] = "scout_RemoveInactiveDisk"; /*Routine name */
991 fprintf(scout_debugfd, "[%s] Called\n", rn);
992 fflush(scout_debugfd);
995 /*code = gtxframe_RemoveFromList(scout_frame->window, lightobj); */
997 } /*scout_RemoveInactiveDisk */
999 /*------------------------------------------------------------------------
1000 * mini_PrintDiskStats
1003 * Given server indexing and light object information, a pointer
1004 * to a set of statistics, and whether the probe that produced these
1005 * stats succeeded or not, print out the stats in a nice way.
1008 * struct mini_line *a_srvline : Ptr to server descriptor.
1009 * struct ProbeViceStatistics *a_stats : Ptr to current stats.
1010 * int a_probeOK : Was the probe OK?
1011 * int a_width_changed : Has the frame width changed?
1012 * int a_fix_line_num : Is the line number wrong?
1013 * int a_delta_line_num : Change in line number.
1016 * 0 if something went wrong,
1017 * else the number of lines taken up by this server record.
1020 * Nothing interesting.
1024 *------------------------------------------------------------------------*/
1027 mini_PrintDiskStats(struct mini_line *a_srvline,
1028 struct ProbeViceStatistics *a_stats,
1029 int a_probeOK, int a_width_changed,
1030 int a_fix_line_num, int a_delta_line_num)
1031 { /*mini_PrintDiskStats */
1033 static char rn[] = "mini_PrintDiskStats"; /*Routine name */
1034 int code; /*Return code */
1035 char s[128]; /*String buffer */
1036 struct onode *curr_disklight; /*Ptr to current disk light */
1037 struct onode *srvname_light; /*Ptr to server name light */
1038 ViceDisk *curr_diskstat; /*Ptr to current disk stat */
1039 int curr_disk; /*Current disk stat number */
1040 int used_disk_idx; /*Used disk index */
1041 int next_used_idx; /*Ditto */
1042 int pastthreshold; /*Was disk past threshold? */
1043 struct gator_lightobj *diskdata; /*Private light data */
1044 struct gwin_strparams *disk_strparams; /*String params for disk light */
1045 char *diskname = 0; /*Name of disk */
1046 int found_idx; /*Idx of matching disk */
1047 char *srv_name; /*Server name */
1048 struct scout_disk *sc_disk; /*Ptr to scout disk desc */
1049 int fix_light_locs; /*Recompute disk light locs? */
1052 fprintf(scout_debugfd, "[%s] Called\n", rn);
1053 fflush(scout_debugfd);
1057 * Remember the current server's print name, don't recompute light
1060 srvname_light = a_srvline->srvName_lp;
1061 srv_name = ((struct gator_lightobj *)(srvname_light->o_data))->label;
1064 fprintf(scout_debugfd, "[%s] Value of a_delta_line_num is %d\n", rn,
1066 fflush(scout_debugfd);
1070 * If the probe failed, we simply blank out all the used disk
1071 * objects. Note: a NON-ZERO value of a_probeOK implies failure.
1074 used_disk_idx = a_srvline->used_head;
1075 while (used_disk_idx != SCOUT_NIL) {
1077 * Point to the current used disk's light, blank out its
1078 * contents, and make sure highlighting is turned off. We
1079 * also take this opportunity to fix the line numbers if
1082 curr_disklight = a_srvline->disks[used_disk_idx].disk_lp;
1083 diskdata = (struct gator_lightobj *)(curr_disklight->o_data);
1085 fprintf(scout_debugfd,
1086 "[%s] Prev value of disk light %d: '%s'\n", rn,
1087 used_disk_idx, diskdata->label);
1088 fflush(scout_debugfd);
1090 code = mini_justify(" ", /*Src buffer */
1091 diskdata->label, /*Dest buffer */
1092 scout_col_width[COL_DISK], /*Dest's width */
1093 SCOUT_RIGHT_JUSTIFY, /*Right-justify */
1094 SCOUT_LEFT_TRUNC, /*Left-truncate */
1095 SCOUT_ISNT_LDISK); /*Not a labeled disk */
1096 code = gator_light_set(curr_disklight, 0);
1097 if (a_fix_line_num) {
1098 curr_disklight->o_y += a_delta_line_num;
1099 disk_strparams = (struct gwin_strparams *)(diskdata->llrock);
1100 disk_strparams->y += a_delta_line_num;
1104 * Advance to next used disk, if any.
1106 used_disk_idx = a_srvline->disks[used_disk_idx].next;
1108 } /*Blank out disk name field */
1111 * If the frame width has changed, we have to recompute all disk
1112 * light locations. After that, the number of lines in the server
1113 * record will be accurate, and we return them.
1115 if (a_width_changed)
1116 scout_RecomputeLightLocs(a_srvline);
1118 return (a_srvline->num_lines);
1122 /*Probe failed for the server */
1124 * Probe was successful. Sweep through the statistics records,
1125 * and put up all values having to do with AFS partitions. First,
1126 * mark all used disk objects for this server as inactive and fix
1127 * their line numbers if needed.
1129 sc_disk = a_srvline->disks;
1130 used_disk_idx = a_srvline->used_head;
1131 while (used_disk_idx != SCOUT_NIL) {
1133 fprintf(scout_debugfd, "[%s] Marking used disk %d inactive\n", rn,
1135 fflush(scout_debugfd);
1137 sc_disk = (a_srvline->disks) + used_disk_idx;
1138 sc_disk->active = 0;
1139 used_disk_idx = sc_disk->next;
1140 if (a_fix_line_num) {
1141 sc_disk->disk_lp->o_y += a_delta_line_num;
1142 diskdata = (struct gator_lightobj *)(sc_disk->disk_lp->o_data);
1143 disk_strparams = (struct gwin_strparams *)(diskdata->llrock);
1144 disk_strparams->y += a_delta_line_num;
1146 } /*Mark used disks inactive */
1148 curr_diskstat = (ViceDisk *) a_stats->Disk;
1149 for (curr_disk = 0; curr_disk < VOLMAXPARTS; curr_disk++) {
1151 * An AFS partition name must be prefixed by `/vicep`.
1154 fprintf(scout_debugfd, "[%s] Disk stats at %p for disk '%s'\n",
1155 rn, curr_diskstat, curr_diskstat->Name);
1156 fflush(scout_debugfd);
1158 if (strncmp("/vice", curr_diskstat->Name, 5) == 0) {
1160 * Pull out the single-letter name (actually, abbreviation)
1161 * of the disk and look for such an entry in the used disks.
1163 diskname = &curr_diskstat->Name[6];
1164 found_idx = scout_FindUsedDisk(diskname, /*1-char name */
1165 a_srvline, /*Server record */
1166 &fix_light_locs); /*Recompute? */
1167 if (found_idx == SCOUT_NIL) {
1169 "[%s] Can't display /vicep%s on server '%s'\n", rn,
1170 diskname, srv_name);
1173 * Found (or created) record for this disk. Fill in the single-
1174 * letter name of the disk followed by the number of free blocks.
1175 * Turn the disk light on if the number of free blocks exceeds
1176 * the threshold the user set, either % used or min free blocks.
1178 sprintf(s, "%s:%d", diskname, curr_diskstat->BlocksAvailable);
1179 if (scout_attn_disk_mode == SCOUT_DISKM_PCUSED) {
1181 (curr_diskstat->TotalBlocks -
1182 curr_diskstat->BlocksAvailable) /
1183 (float)(curr_diskstat->TotalBlocks) >
1184 scout_attn_disk_pcused)
1190 (curr_diskstat->BlocksAvailable <
1191 scout_attn_disk_minfree) ? 1 : 0;
1192 sc_disk = (a_srvline->disks) + found_idx;
1193 sc_disk->active = 1;
1195 (struct gator_lightobj *)(sc_disk->disk_lp->o_data);
1197 fprintf(scout_debugfd,
1198 "[%s] Justifying %s for disk idx %d (prev value: '%s')\n",
1199 rn, s, found_idx, diskdata->label);
1200 fflush(scout_debugfd);
1202 code = mini_justify(s, /*Src buffer */
1203 diskdata->label, /*Dest buffer */
1204 scout_col_width[COL_DISK], /*Dest's width */
1205 SCOUT_LEFT_JUSTIFY, /*Left-justify */
1206 SCOUT_LEFT_TRUNC, /*Left-truncate */
1207 SCOUT_IS_LDISK); /*Labeled disk */
1209 code = gator_light_set(sc_disk->disk_lp, pastthreshold);
1211 } /*Found disk record */
1214 /*Found AFS disk name */
1216 * Advance to the next disk statistics record.
1219 } /*For each statistics record */
1222 * We've now pulled out all the disk statistics from the probe.
1223 * See if any used disks that were there from the last time are
1224 * now gone. If so, we remove them.
1227 fprintf(scout_debugfd,
1228 "[%s] Scanning used disk records for inactive entries\n", rn);
1229 fflush(scout_debugfd);
1231 used_disk_idx = a_srvline->used_head;
1232 while (used_disk_idx != SCOUT_NIL) {
1234 fprintf(scout_debugfd, "[%s] Examining entry at index %d\n", rn,
1236 fflush(scout_debugfd);
1238 sc_disk = (a_srvline->disks) + used_disk_idx;
1239 next_used_idx = sc_disk->next;
1240 if (!(sc_disk->active)) {
1241 scout_RemoveInactiveDisk(a_srvline, /*Server record */
1242 used_disk_idx); /*Disk index to nuke */
1245 used_disk_idx = next_used_idx;
1247 } /*Remove inactive used disks */
1250 * If we've had to add or remove disks to/from the used list,
1251 * or if the frame width has changed, we recompute the light
1252 * locations before returning.
1254 if (fix_light_locs || a_width_changed)
1255 scout_RecomputeLightLocs(a_srvline);
1258 * Return the (possibly new) size of the current server record.
1260 return (a_srvline->num_lines);
1262 } /*mini_PrintDiskStats */
1264 /*------------------------------------------------------------------------
1268 * Handler routine passed to the fsprobe module. This handler is
1269 * called immediately after a poll of all the FileServers has taken
1270 * place. Its job is to write out selected data to the scout
1281 * All it needs to know is exported by the fsprobe module, namely
1282 * the data structure where the probe results are stored.
1285 * Recomputes disk light locations in response to reshaping the
1286 * scout window or from adding/deleting disk lights to/from
1287 * individual servers.
1288 *------------------------------------------------------------------------*/
1294 static char rn[] = "FS_Handler"; /*Routine name */
1295 int code; /*Return code */
1296 struct ProbeViceStatistics *curr_stats; /*Ptr to current stats */
1297 int *curr_probeOK; /*Ptr to current probeOK field */
1298 int curr_srvidx; /*Current server index */
1299 char s[128]; /*String buffer */
1300 static char sblank[] = " "; /*Blank string buffer */
1301 char *sp; /*Ptr to string buffer */
1302 struct mini_line *curr_line; /*Current mini-line */
1303 int curr_line_num; /*Current line number */
1304 struct gator_lightobj *lightdata; /*Private light data */
1305 int setting; /*Light setting (on or off) */
1306 int old_width; /*Keep the old width value */
1307 int width_changed; /*Has the frame width changed? */
1308 int fix_line_num; /*Line number needs fixing */
1309 int delta_line_num; /*Change in line number */
1312 * See if the size of the scout frame has changed since the last
1315 old_width = scout_frameDims.maxx;
1317 fprintf(scout_debugfd, "[%s] Calling wop_getdimensions\n", rn);
1318 fflush(scout_debugfd);
1320 WOP_GETDIMENSIONS(scout_frame->window, &scout_frameDims);
1321 width_changed = (old_width == scout_frameDims.maxx) ? 0 : 1;
1323 fprintf(scout_debugfd,
1324 "[%s] Frame dimensions are %d rows, %d columns\n", rn,
1325 scout_frameDims.maxy, scout_frameDims.maxx);
1327 fprintf(scout_debugfd, "[%s] Width has changed from %d columns\n",
1329 fflush(scout_debugfd);
1333 * Print out the selected fields for each server. We actually change
1334 * the light's label to the new data.
1336 curr_line = scout_screen.line;
1337 curr_stats = fsprobe_Results.stats;
1338 curr_probeOK = fsprobe_Results.probeOK;
1339 curr_line_num = curr_line->base_line;
1342 for (curr_srvidx = 0; curr_srvidx < scout_screen.numServers;
1345 * If the current server record is set up on the wrong line, fix
1346 * the non-disk light objects directly, and remember to fix the
1347 * disk light objects later on.
1349 if (curr_line->base_line != curr_line_num) {
1351 delta_line_num = curr_line_num - curr_line->base_line;
1352 curr_line->base_line = curr_line_num;
1353 scout_SetNonDiskLightLine(curr_line, curr_line_num);
1360 (struct gator_lightobj *)(curr_line->currConns_lp->o_data);
1361 if (*curr_probeOK == 0) {
1363 sprintf(sp, "%d", curr_stats->CurrentConnections);
1366 code = mini_justify(sp, /*Src buffer */
1367 lightdata->label, /*Dest buffer */
1368 scout_col_width[COL_CONN], /*Dest's width */
1369 SCOUT_RIGHT_JUSTIFY, /*Right-justify */
1370 SCOUT_LEFT_TRUNC, /*Left-truncate */
1371 SCOUT_ISNT_LDISK); /*Not a labeled disk */
1372 if (scout_attn_conn != SCOUT_ATTN_NOTUSED
1373 && curr_stats->CurrentConnections >= scout_attn_conn)
1377 code = gator_light_set(curr_line->currConns_lp, setting);
1379 lightdata = (struct gator_lightobj *)(curr_line->fetches_lp->o_data);
1380 if (*curr_probeOK == 0) {
1382 sprintf(sp, "%d", curr_stats->TotalFetchs);
1385 code = mini_justify(sp, /*Src buffer */
1386 lightdata->label, /*Dest buffer */
1387 scout_col_width[COL_FETCH], /*Dest's width */
1388 SCOUT_RIGHT_JUSTIFY, /*Right-justify */
1389 SCOUT_LEFT_TRUNC, /*Left-truncate */
1390 SCOUT_ISNT_LDISK); /*Not a labeled disk */
1391 if (scout_attn_fetch != SCOUT_ATTN_NOTUSED
1392 && curr_stats->TotalFetchs >= scout_attn_fetch)
1396 code = gator_light_set(curr_line->fetches_lp, setting);
1398 lightdata = (struct gator_lightobj *)(curr_line->stores_lp->o_data);
1399 if (*curr_probeOK == 0) {
1401 sprintf(sp, "%d", curr_stats->TotalStores);
1404 code = mini_justify(sp, /*Src buffer */
1405 lightdata->label, /*Dest buffer */
1406 scout_col_width[COL_STORE], /*Dest's width */
1407 SCOUT_RIGHT_JUSTIFY, /*Right-justify */
1408 SCOUT_LEFT_TRUNC, /*Left-truncate */
1409 SCOUT_ISNT_LDISK); /*Not a labeled disk */
1410 if (scout_attn_store != SCOUT_ATTN_NOTUSED
1411 && curr_stats->TotalStores >= scout_attn_store)
1415 code = gator_light_set(curr_line->stores_lp, setting);
1418 (struct gator_lightobj *)(curr_line->workstations_lp->o_data);
1419 if (*curr_probeOK == 0) {
1421 sprintf(sp, "%d", curr_stats->WorkStations);
1424 code = mini_justify(sp, /*Src buffer */
1425 lightdata->label, /*Dest buffer */
1426 scout_col_width[COL_WK], /*Dest's width */
1427 SCOUT_RIGHT_JUSTIFY, /*Right-justify */
1428 SCOUT_LEFT_TRUNC, /*Left-truncate */
1429 SCOUT_ISNT_LDISK); /*Not a labeled disk */
1430 if (scout_attn_workstations != SCOUT_ATTN_NOTUSED
1431 && curr_stats->WorkStations >= scout_attn_workstations)
1435 code = gator_light_set(curr_line->workstations_lp, setting);
1438 * We turn the server light on if there was an error in the
1439 * current probe (e.g., if the curr_probeOK field is non-zero.
1440 * (Don't forget to fix the light's line if it needs it).
1442 setting = (*curr_probeOK) ? 1 : 0;
1443 code = gator_light_set(curr_line->srvName_lp, setting);
1446 * Print out the disk statistics. The value returned is the
1447 * number of lines taken up by the server record (or 0 if
1448 * something went wrong).
1450 code = mini_PrintDiskStats(curr_line, /*Ptr to server line */
1451 curr_stats, /*Fresh disk stats */
1452 *curr_probeOK, /*Was probe OK? */
1453 width_changed, /*Has the width changed? */
1454 fix_line_num, /*Fix the line number? */
1455 delta_line_num); /*Change in line number */
1457 fprintf(stderr, "[%s] Error in printing out disk statistics\n",
1461 curr_line_num += code;
1464 * Advance the current mini_line, stats source, and probe success
1471 } /*for each server probed */
1474 * Display the scout frame.
1476 sprintf(s, "Probe %d results", fsprobe_Results.probeNum);
1477 gtxframe_DisplayString(scout_frame, s);
1478 WOP_DISPLAY(scout_gwin);
1481 * Return the happy news.
1487 /*------------------------------------------------------------------------
1491 * Initialize each line in the mini_screen.
1494 * struct sockaddr_in *a_skt : Ptr to server socket info.
1495 * int a_lineNum; : Line number being created.
1496 * struct mini_line *a_line : Ptr to mini_line to set up.
1497 * char *a_srvname : Printable server name.
1501 * Error value otherwise.
1504 * Nothing interesting.
1508 *------------------------------------------------------------------------*/
1511 init_mini_line(struct sockaddr_in *a_skt, int a_lineNum,
1512 struct mini_line *a_line, char *a_srvname)
1513 { /*init_mini_line */
1515 static char rn[] = "init_mini_line"; /*Routine name */
1516 int curr_x; /*Current X position */
1517 int curr_y; /*Current Y position */
1518 char s[128]; /*Scratch buffer */
1519 int code; /*Return code */
1520 struct gator_lightobj *lightdata; /*Private light data */
1523 fprintf(scout_debugfd, "[%s] Called for base line %d\n", rn,
1525 fflush(scout_debugfd);
1529 * Fill in the top fields (except the disk fields, which will be
1530 * done elsewhere), then create the light onodes.
1532 memcpy((char *)&(a_line->skt), (char *)a_skt, sizeof(struct sockaddr_in));
1533 a_line->numDisks = 0;
1534 a_line->base_line = a_lineNum + scout_screen.base_line_num;
1535 a_line->num_lines = 1;
1538 curr_y = a_line->base_line;
1539 if ((a_line->currConns_lp =
1540 mini_initLightObject("Conns", curr_x, curr_y, scout_col_width[COL_CONN],
1543 fprintf(stderr, "[%s:%s] Can't create currConns light object\n", pn,
1547 curr_x += scout_col_width[COL_CONN] + 1;
1549 if ((a_line->fetches_lp =
1550 mini_initLightObject("Fetches", curr_x, curr_y, scout_col_width[COL_FETCH],
1551 scout_frame->window))
1553 fprintf(stderr, "[%s:%s] Can't create fetches light object\n", pn,
1557 curr_x += scout_col_width[COL_FETCH] + 1;
1559 if ((a_line->stores_lp =
1560 mini_initLightObject("Stores", curr_x, curr_y, scout_col_width[COL_STORE],
1561 scout_frame->window))
1563 fprintf(stderr, "[%s:%s] Can't create stores light object\n", pn, rn);
1566 curr_x += scout_col_width[COL_STORE] + 1;
1568 if ((a_line->workstations_lp =
1569 mini_initLightObject("WrkStn", curr_x, curr_y, scout_col_width[COL_WK],
1570 scout_frame->window))
1572 fprintf(stderr, "[%s:%s] Can't create workstations light object\n",
1576 curr_x += scout_col_width[COL_WK] + 1;
1578 if ((a_line->srvName_lp =
1579 mini_initLightObject(a_srvname, curr_x, curr_y,
1580 scout_col_width[COL_SRVNAME], scout_frame->window))
1582 fprintf(stderr, "[%s:%s] Can't create server name light object\n", pn,
1586 sprintf(s, "%s", a_srvname);
1587 lightdata = (struct gator_lightobj *)(a_line->srvName_lp->o_data);
1588 code = mini_justify(s, /*Src buffer */
1589 lightdata->label, /*Dest buffer */
1590 scout_col_width[COL_SRVNAME], /*Dest's width */
1591 SCOUT_CENTER, /*Centered */
1592 SCOUT_RIGHT_TRUNC, /*Right-truncate */
1593 SCOUT_ISNT_LDISK); /*Not a labeled disk */
1596 "[%s] Can't center server name inside of light object\n", rn);
1599 curr_x += scout_col_width[COL_SRVNAME] + 1;
1601 if (scout_initDiskLightObjects(a_line, scout_frame->window)) {
1602 fprintf(stderr, "[%s:%s] Can't create disk light objects\n", pn, rn);
1607 * Finally, return the happy news.
1611 } /*init_mini_line */
1613 /*------------------------------------------------------------------------
1617 * Workhorse routine that starts up the FileServer probe.
1620 * int a_numservers : Length of above list.
1621 * struct cmd_item *a_srvname : List of FileServer machines to
1623 * int a_pkg : Window package to use.
1627 * Error value otherwise.
1630 * Nothing interesting.
1634 *------------------------------------------------------------------------*/
1637 execute_scout(int a_numservers, struct cmd_item *a_srvname, int a_pkg)
1638 { /*execute_scout */
1640 static char rn[] = "execute_scout"; /*Routine name */
1641 static char fullsrvname[128]; /*Full server name */
1642 int code; /*Return code */
1643 struct sockaddr_in *FSSktArray; /*Server socket array */
1644 int sktbytes; /*Num bytes in above */
1645 struct sockaddr_in *curr_skt; /*Ptr to current socket */
1646 struct cmd_item *curr_item; /*Ptr to current cmd item */
1647 struct hostent *he; /*Host entry */
1648 struct mini_line *mini_lines; /*Ptr to all mini-lines */
1649 struct mini_line *curr_line; /*Ptr to current line */
1650 int i; /*Generic loop variable */
1651 int mini_line_bytes; /*Num bytes in mini_lines */
1652 struct timeval tv; /*Time structure */
1653 int linenum; /*Current mini-line number */
1655 PROCESS pid; /*Main LWP process ID */
1656 PROCESS gxlistener_ID; /*Input Server LWP process ID */
1658 struct gator_lightobj *lightdata; /*Private light data */
1661 fprintf(scout_debugfd, "[%s] Called\n", rn);
1662 fflush(scout_debugfd);
1666 * We have to initialize LWP support before we start up any of
1670 code = LWP_InitializeProcessSupport(LWP_NORMAL_PRIORITY, &pid);
1672 fprintf(stderr, "[%s:%s] Can't initialize LWP\n", pn, rn);
1673 scout_CleanExit(code);
1678 * Initialize the gtx package.
1681 fprintf(stderr, "[%s:%s] Starting up gtx package\n", pn, rn);
1683 scout_gwin = gtx_Init(0, /*Don't start up InputServer yet */
1684 -1); /*Type of window package */
1685 if (scout_gwin == NULL) {
1686 fprintf(stderr, "[%s:%s] Call to gtx_Init() failed!\n", pn, rn);
1691 * Remember we've set up gtx so we can exit cleanly from now on.
1693 scout_gtx_initialized = 1;
1696 * Create the frame everything will go into, set it up as our only
1697 * frame for this window.
1699 scout_frame = gtxframe_Create();
1700 if (scout_frame == (struct gtx_frame *)0) {
1701 fprintf(stderr, "[%s:%s] Call to gtxframe_Create() failed!\n", pn,
1705 gtxframe_SetFrame(scout_gwin, scout_frame);
1706 WOP_GETDIMENSIONS(scout_frame->window, &scout_frameDims);
1709 * Allocate an array of sockets to describe each FileServer we'll be
1712 sktbytes = a_numservers * sizeof(struct sockaddr_in);
1713 FSSktArray = (struct sockaddr_in *)malloc(sktbytes);
1714 if (FSSktArray == (struct sockaddr_in *)0) {
1716 "[%s] Can't malloc() %d sockaddrs (%d bytes) for the given servers\n",
1717 rn, a_numservers, sktbytes);
1718 scout_CleanExit(-1);
1720 memset(FSSktArray, 0, sktbytes);
1723 * Sweep through the server names provided, filling in the socket
1724 * info for each. Take into account the fact that we may have a
1725 * base name associated for each.
1727 curr_item = a_srvname;
1728 curr_skt = FSSktArray;
1730 if (*scout_basename == '\0')
1731 sprintf(fullsrvname, "%s", curr_item->data);
1733 sprintf(fullsrvname, "%s.%s", curr_item->data, scout_basename);
1734 he = hostutil_GetHostByName(fullsrvname);
1736 fprintf(stderr, "[%s] Can't get host info for '%s'\n", rn,
1740 memcpy(&(curr_skt->sin_addr.s_addr), he->h_addr, 4);
1741 #if defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
1742 curr_skt->sin_family = AF_INET; /*Internet family */
1744 curr_skt->sin_family = htons(AF_INET); /*Internet family */
1746 curr_skt->sin_port = htons(7000); /*FileServer port */
1749 * Bump our pointers.
1751 curr_item = curr_item->next;
1754 } /*Build socket entry for each server */
1757 * Create the set of mini-lines, one per server.
1759 mini_line_bytes = a_numservers * sizeof(struct mini_line);
1760 mini_lines = (struct mini_line *)malloc(mini_line_bytes);
1761 if (mini_lines == (struct mini_line *)0) {
1762 fprintf(stderr, "[%s] Can't malloc() %d bytes for %d screen lines\n",
1763 rn, mini_line_bytes, a_numservers);
1766 memset(mini_lines, 0, mini_line_bytes);
1769 * Set up each line in the mini_lines, creating and initializing
1770 * its light objects.
1772 scout_screen.base_line_num = 4;
1773 curr_line = mini_lines;
1774 curr_skt = FSSktArray;
1776 curr_item = a_srvname;
1777 gtxframe_ClearList(scout_frame);
1780 * Create the light objects that server as banner lines. Remember
1781 * to take into account the server basename, if any, and the name
1782 * of the host that scout if running on, if that's wanted.
1784 if (scout_showhostname) {
1785 if (*scout_basename == '\0')
1786 sprintf(scout_Banner, "[%s] %s", scout_hostname, "Scout");
1788 sprintf(scout_Banner, "[%s] Scout for %s", scout_hostname,
1791 if (*scout_basename == '\0')
1792 sprintf(scout_Banner, "%s", " Scout");
1794 sprintf(scout_Banner, " Scout for %s", scout_basename);
1796 scout_banner0_lp = mini_initLightObject("Banner 0", /*Light name */
1797 0, /*X*/ 0, /*Y*/ scout_frameDims.maxx, /*Width */
1798 scout_gwin); /*Window */
1799 if (scout_banner0_lp != NULL) {
1800 lightdata = (struct gator_lightobj *)(scout_banner0_lp->o_data);
1802 mini_justify(scout_Banner, lightdata->label, scout_frameDims.maxx,
1803 SCOUT_CENTER, SCOUT_RIGHT_TRUNC, SCOUT_ISNT_LDISK);
1804 code = gator_light_set(scout_banner0_lp, 1);
1805 code = gtxframe_AddToList(scout_frame, scout_banner0_lp);
1809 fprintf(scout_debugfd, "[%s] Scout label is '%s', %" AFS_SIZET_FMT " chars\n", rn,
1810 lightdata->label, strlen(lightdata->label));
1813 scout_banner1_lp = mini_initLightObject("Banner 1", /*Light name */
1814 0, /*X*/ 2, /*Y*/ scout_frameDims.maxx, /*Width */
1815 scout_gwin); /*Window */
1816 if (scout_banner1_lp != NULL) {
1817 char attn_label[256];
1818 if (scout_attn_disk_mode == SCOUT_DISKM_PCUSED) {
1819 snprintf(attn_label, sizeof(attn_label), "%s: > %s%% used",
1820 scout_label[5], scout_attn_disk_pcusedstr);
1822 snprintf(attn_label, sizeof(attn_label), "%s: < %d blocks free",
1823 scout_label[5], scout_attn_disk_minfree);
1825 snprintf(scout_Banner, sizeof(scout_Banner),
1826 "%*s %*s %*s %*s %*s %s",
1827 scout_col_width[0], scout_label[0],
1828 scout_col_width[1], scout_label[1],
1829 scout_col_width[2], scout_label[2],
1830 scout_col_width[3], scout_label[3],
1831 scout_col_width[4], scout_label[4],
1834 lightdata = (struct gator_lightobj *)(scout_banner1_lp->o_data);
1836 mini_justify(scout_Banner, lightdata->label, scout_frameDims.maxx,
1837 SCOUT_LEFT_JUSTIFY, SCOUT_RIGHT_TRUNC,
1840 code = gtxframe_AddToList(scout_frame, scout_banner1_lp);
1843 scout_banner2_lp = mini_initLightObject("Banner 2", /*Light name */
1844 0, /*X*/ 3, /*Y*/ scout_frameDims.maxx, /*Width */
1845 scout_gwin); /*Window */
1846 if (scout_banner2_lp != NULL) {
1847 snprintf(scout_Banner, sizeof(scout_Banner),
1848 "%*s %*s %*s %*s %*s %s",
1849 scout_col_width[0], scout_underline[0],
1850 scout_col_width[1], scout_underline[1],
1851 scout_col_width[2], scout_underline[2],
1852 scout_col_width[3], scout_underline[3],
1853 scout_col_width[4], scout_underline[4],
1854 scout_underline[5]);
1856 lightdata = (struct gator_lightobj *)(scout_banner2_lp->o_data);
1858 mini_justify(scout_Banner, lightdata->label,
1859 scout_frameDims.maxx, SCOUT_LEFT_JUSTIFY,
1860 SCOUT_RIGHT_TRUNC, SCOUT_ISNT_LDISK);
1861 code = gtxframe_AddToList(scout_frame, scout_banner2_lp);
1864 for (i = 0; i < a_numservers; i++) {
1865 code = init_mini_line(curr_skt, linenum, curr_line, curr_item->data);
1867 fprintf(stderr, "[%s] Can't initialize line for server %d\n", rn,
1874 curr_item = curr_item->next;
1878 * Now that all lines have been set up, we feed in the light items
1879 * created. Note: the disk lights are entered at a later time,
1880 * as they enter the used disk list for each server.
1882 curr_line = mini_lines;
1883 for (i = 0; i < a_numservers; i++) {
1884 code = gtxframe_AddToList(scout_frame, curr_line->currConns_lp);
1887 "[%s] Can't add client connections light to display list\n",
1892 code = gtxframe_AddToList(scout_frame, curr_line->fetches_lp);
1895 "[%s] Can't add fetches light to frame display list\n",
1900 code = gtxframe_AddToList(scout_frame, curr_line->stores_lp);
1903 "[%s] Can't add stores light to frame display list\n",
1908 code = gtxframe_AddToList(scout_frame, curr_line->workstations_lp);
1911 "[%s] Can't add workstation light to display list\n", rn);
1915 code = gtxframe_AddToList(scout_frame, curr_line->srvName_lp);
1918 "[%s] Can't add server name light to display list\n", rn);
1923 * Move down to the next server record.
1927 } /*Add lights in server records to display list */
1931 * Set up the minimal keymap.
1933 code = keymap_BindToString(scout_frame->keymap, /*Ptr to keymap */
1934 "e", /*Key to bind */
1935 ExitCmd, /*Cmd to execute */
1937 NULL); /*Ptr to rock */
1939 fprintf(stderr, "[%s] Can't bind key `e', code is %d\n", rn, code);
1945 * Finish setting up the overall mini_screen structure.
1947 scout_screen.numServers = a_numservers;
1948 scout_screen.line = mini_lines;
1949 WOP_GETDIMENSIONS(scout_frame->window, &scout_frameDims);
1952 * Start up the fsprobe package, which will gather FileServer
1953 * statistics for us on a regular basis.
1955 gtxframe_DisplayString(scout_frame,
1956 "Establishing File Server connection(s)...");
1957 code = fsprobe_Init(a_numservers, /*Num FileServers to probe */
1958 FSSktArray, /*FileServer socket array */
1959 scout_probefreq, /*Probe frequency */
1960 FS_Handler, /*Handler routine */
1961 0); /*Turn debugging output off */
1963 scout_debug); /*Turn debugging output off */
1966 fprintf(stderr, "[%s] Error returned by fsprobe_Init: %d\n", rn,
1973 * Start up the input server LWP for our window.
1976 code = LWP_CreateProcess(gtx_InputServer, /*Fcn to start up */
1977 8192, /*Stack size in bytes */
1978 LWP_NORMAL_PRIORITY, /*Priority */
1979 (void *)scout_gwin, /*Params: Ptr to window */
1980 "gx-listener", /*Name to use */
1981 &gxlistener_ID); /*Returned LWP process ID */
1984 code = (int)(intptr_t)gtx_InputServer(scout_gwin);
1987 "[%s] Error exit from gtx_InputServer(), error is %d\n", rn,
1989 scout_CleanExit(code);
1993 * We fall into a loop, sleeping forever.
1996 tv.tv_sec = 60 * 60; /*Sleep for an hour at a time */
1998 code = select(0, /*Num fds */
1999 0, /*Descriptors ready for reading */
2000 0, /*Descriptors ready for writing */
2001 0, /*Descriptors with exceptional conditions */
2002 &tv); /*Timeout structure */
2003 } /*Sleep forever */
2007 * How did we get here? Oh, well, clean up our windows and
2008 * return sweetness and light anyway.
2010 WOP_CLEANUP(&scout_gwin);
2014 } /*execute_scout */
2016 /*------------------------------------------------------------------------
2020 * Given a pointer to the list of servers we'll be polling,
2021 * compute the length of the list.
2024 * struct cmd_item *a_firstItem : Ptr to first item in list.
2027 * Length of the above list.
2030 * Nothing interesting.
2034 *------------------------------------------------------------------------*/
2036 static int countServers(struct cmd_item *a_firstItem)
2039 int list_len; /*List length */
2040 struct cmd_item *curr_item; /*Ptr to current item */
2043 curr_item = a_firstItem;
2050 curr_item = curr_item->next;
2060 /*------------------------------------------------------------------------
2061 * scout_AdoptThresholds
2064 * Parse and adopt one or more threshold values, as read off the
2068 * struct cmd_item *a_thresh_item : Ptr to item on command-line
2072 * Nothing (but may exit the entire program on error!)
2075 * Valid keywords are:
2076 * conn, disk, fetch, store, ws
2077 * The disk value, if it has a % sign, signifies that attention
2078 * will be triggered when the disk is more than that percentage
2079 * full; otherwise, it will specify the minimum number of free
2084 *------------------------------------------------------------------------*/
2086 static void scout_AdoptThresholds(struct cmd_item *a_thresh_item)
2087 { /*scout_AdoptThresholds */
2089 static char rn[] = "scout_AdoptThresholds"; /*Routine name */
2090 struct cmd_item *curr_item; /*Current item */
2091 char *curr_name; /*Current name half of pair */
2092 char *curr_value; /*Current value half of pair */
2093 int diskval_len; /*Length of disk attn value */
2095 curr_item = a_thresh_item;
2098 * If there isn't a corresponding value for the current
2099 * attention field, bitch & die.
2101 if (curr_item->next == (struct cmd_item *)0) {
2102 printf("[%s] No threshold value given for '%s'\n", rn,
2104 scout_CleanExit(-1);
2107 curr_name = curr_item->data;
2108 curr_value = curr_item->next->data;
2110 if (strcmp(curr_name, "conn") == 0) {
2112 fprintf(scout_debugfd,
2113 "[%s] Setting conn attn value to %d (default %d)\n",
2114 rn, atoi(curr_value), scout_attn_conn);
2115 fflush(scout_debugfd);
2117 scout_attn_conn = atoi(curr_value);
2118 } else if (strcmp(curr_name, "disk") == 0) {
2120 * If there's a '%' as the last character in the value,
2121 * we use percentage mode.
2123 diskval_len = strlen(curr_value);
2124 if (curr_value[diskval_len - 1] == '%') {
2125 curr_value[diskval_len - 1] = '\0';
2127 fprintf(scout_debugfd,
2128 "[%s] New disk attn value: 0.%s used (default %f)\n",
2129 rn, curr_value, scout_attn_disk_pcused);
2130 fflush(scout_debugfd);
2132 sprintf(scout_attn_disk_pcusedstr, "%s", curr_value);
2133 scout_attn_disk_pcused =
2134 ((float)(atoi(curr_value))) / ((float)(100));
2135 } /*Percentage mode */
2138 fprintf(scout_debugfd,
2139 "[%s] New disk attn value: %s min free (default %f)\n",
2140 rn, curr_value, scout_attn_disk_pcused);
2141 fflush(scout_debugfd);
2143 scout_attn_disk_mode = SCOUT_DISKM_MINFREE;
2144 scout_attn_disk_minfree = atoi(curr_value);
2145 } /*Min free blocks mode */
2146 } else if (strcmp(curr_name, "fetch") == 0) {
2148 fprintf(scout_debugfd,
2149 "[%s] Setting fetch attn value to %d (default %d)\n",
2150 rn, atoi(curr_value), scout_attn_fetch);
2151 fflush(scout_debugfd);
2153 scout_attn_fetch = atoi(curr_value);
2154 } else if (strcmp(curr_name, "store") == 0) {
2156 fprintf(scout_debugfd,
2157 "[%s] Setting store attn value to %d (default %d)\n",
2158 rn, atoi(curr_value), scout_attn_store);
2159 fflush(scout_debugfd);
2161 scout_attn_store = atoi(curr_value);
2162 } else if (strcmp(curr_name, "ws") == 0) {
2164 fprintf(scout_debugfd,
2165 "[%s] Setting workstation attn value to %d (default %d)\n",
2166 rn, atoi(curr_value), scout_attn_workstations);
2167 fflush(scout_debugfd);
2169 scout_attn_workstations = atoi(curr_value);
2171 printf("[%s] Unknown attention item: '%s'\n", rn,
2173 scout_CleanExit(-1);
2177 * Advance past the just-processed pair.
2179 curr_item = curr_item->next->next;
2181 } /*Interpret each name-value pair */
2183 } /*scout_AdoptThresholds */
2186 * Setup the user specified column widths.
2188 * The column widths specifies the number of digits which
2189 * will be displayed without truncation. The column widths
2190 * are given in the same order in which they are displayed,
2191 * from left to right. Not all columns need to be specified
2192 * on the command line. The default column widths for those
2193 * columns not specified. Column widths can not be set smaller
2194 * than the heading underline.
2196 * @param[in] a_width_item command line width item list
2199 scout_SetColumnWidths(struct cmd_item *a_width_item)
2203 int num_cols = sizeof(scout_col_width) / sizeof(*scout_col_width);
2205 for (i = 0; a_width_item && i < num_cols; i++) {
2206 width = atoi(a_width_item->data);
2208 int min_width = strlen(scout_underline[i]);
2210 width = max(width, min_width);
2212 scout_col_width[i] = width + 1;
2214 a_width_item = a_width_item->next;
2217 fprintf(stderr, "Too many values given for -columnwidths\n");
2222 /*------------------------------------------------------------------------
2226 * Routine called when Scout is invoked, responsible for basic
2227 * initialization, command line parsing, and calling the
2228 * routine that does all the work.
2231 * as : Command syntax descriptor.
2232 * arock : Associated rock (not used here).
2235 * Zero (but may exit the entire program on error!)
2238 * Nothing interesting.
2241 * Initializes this program.
2242 *------------------------------------------------------------------------*/
2244 static int scoutInit(struct cmd_syndesc *as, void *arock)
2247 static char rn[] = "scoutInit"; /*Routine name */
2248 int code; /*Return code */
2249 int wpkg_to_use; /*Window package to use */
2250 int server_count; /*Number of servers to watch */
2251 char *debug_filename; /*Name of debugging output file */
2254 fprintf(scout_debugfd, "[%s] Called\n", rn);
2255 fflush(scout_debugfd);
2258 if (as->parms[P_DEBUG].items != 0) {
2260 debug_filename = as->parms[P_DEBUG].items->data;
2261 scout_debugfd = fopen(debug_filename, "w");
2262 if (scout_debugfd == (FILE *) 0) {
2263 printf("[%s] Can't open debugging file '%s'!\n", rn,
2265 scout_CleanExit(-1);
2267 fprintf(scout_debugfd, "[%s] Writing to Scout debugging file '%s'\n",
2268 rn, debug_filename);
2271 wpkg_to_use = atoi(as->parms[P_PACKAGE].items->data);
2273 wpkg_to_use = 2; /*Always use curses for now */
2275 fprintf(stderr, "[%s:%s] Using graphics package %d: ", pn, rn,
2277 switch (wpkg_to_use) {
2278 case GATOR_WIN_CURSES:
2279 fprintf(stderr, "curses\n");
2281 case GATOR_WIN_DUMB:
2282 fprintf(stderr, "dumb terminal\n");
2285 fprintf(stderr, "X11\n");
2288 fprintf(stderr, "Illegal graphics package: %d\n", wpkg_to_use);
2289 scout_CleanExit(-1);
2290 } /*end switch (wpkg_to_use) */
2293 if (as->parms[P_FREQ].items != 0)
2294 scout_probefreq = atoi(as->parms[P_FREQ].items->data);
2296 scout_probefreq = 60;
2299 * See if we've been fed a base server name.
2301 if (as->parms[P_BASE].items != 0)
2302 sprintf(scout_basename, "%s", as->parms[P_BASE].items->data);
2304 *scout_basename = '\0';
2307 * Count the number of servers we've been asked to monitor.
2309 server_count = countServers(as->parms[P_SERVER].items);
2312 * Create a line of blanks, a generally-useful thing.
2314 sprintf(scout_blankline, "%255s", " ");
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.
2320 if (as->parms[P_HOST].items != 0) {
2321 scout_showhostname = 1;
2322 *scout_hostname = '\0';
2323 code = gethostname(scout_hostname, 128);
2325 sprintf(scout_hostname, "%s", "*No Hostname*");
2329 * Pull in any and all attention/highlighting thresholds.
2331 if (as->parms[P_ATTENTION].items != 0)
2332 scout_AdoptThresholds(as->parms[P_ATTENTION].items);
2334 if (as->parms[P_WIDTHS].items != 0) {
2335 scout_SetColumnWidths(as->parms[P_WIDTHS].items);
2339 * Now, drive the sucker.
2341 code = execute_scout(server_count, /*Num servers */
2342 as->parms[P_SERVER].items, /*Ptr to srv names */
2343 wpkg_to_use); /*Graphics pkg */
2345 fprintf(stderr, "[%s] Error executing scout: %d\n", rn, code);
2346 scout_CleanExit(-1);
2350 * We initialized (and ran) correctly, so return the good news.
2356 #include "AFS_component_version_number.c"
2359 main(int argc, char **argv)
2362 afs_int32 code; /*Return code */
2363 struct cmd_syndesc *ts; /*Ptr to cmd line syntax descriptor */
2365 #ifdef AFS_AIX32_ENV
2367 * The following signal action for AIX is necessary so that in case of a
2368 * crash (i.e. core is generated) we can include the user's data section
2369 * in the core dump. Unfortunately, by default, only a partial core is
2370 * generated which, in many cases, isn't too useful.
2372 struct sigaction nsa;
2374 sigemptyset(&nsa.sa_mask);
2375 nsa.sa_handler = SIG_DFL;
2376 nsa.sa_flags = SA_FULLDUMP;
2377 sigaction(SIGSEGV, &nsa, NULL);
2380 * Set up the commands we understand.
2382 ts = cmd_CreateSyntax("initcmd", scoutInit, NULL, "initialize the program");
2383 cmd_AddParm(ts, "-server", CMD_LIST, CMD_REQUIRED,
2384 "FileServer name(s) to monitor");
2385 cmd_AddParm(ts, "-basename", CMD_SINGLE, CMD_OPTIONAL,
2386 "base server name");
2388 cmd_AddParm(ts, "-package", CMD_SINGLE, CMD_REQUIRED,
2389 "Graphics package to use");
2391 cmd_AddParm(ts, "-frequency", CMD_SINGLE, CMD_OPTIONAL,
2392 "poll frequency, in seconds");
2393 cmd_AddParm(ts, "-host", CMD_FLAG, CMD_OPTIONAL,
2394 "show name of host you're running on");
2395 cmd_AddParm(ts, "-attention", CMD_LIST, CMD_OPTIONAL,
2396 "specify attention (highlighting) level");
2397 cmd_AddParm(ts, "-debug", CMD_SINGLE, CMD_OPTIONAL,
2398 "turn debugging output on to the named file");
2399 cmd_AddParm(ts, "-columnwidths", CMD_LIST, CMD_OPTIONAL,
2400 "specify column widths");
2403 * Parse command-line switches & execute the test, then get the heck
2406 code = cmd_Dispatch(argc, argv);
2409 fprintf(stderr, "[%s:%s] Call to cmd_Dispatch() failed; code is %d\n",
2416 return 0; /* not reachable */