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>
18 #include <opr/softsig.h>
21 #include <afs/gtxwindows.h> /*Generic window package */
22 #include <afs/gtxobjects.h> /*Object definitions */
23 #include <afs/gtxtextobj.h> /*Text object interface */
24 #include <afs/gtxlightobj.h> /*Light object interface */
25 #include <afs/gtxcurseswin.h> /*Curses window package */
26 #include <afs/gtxdumbwin.h> /*Dumb terminal window package */
27 #include <afs/gtxX11win.h> /*X11 window package */
28 #include <afs/gtxframe.h> /*Frame package */
29 #include <afs/gtxinput.h>
30 #include <afs/cmd.h> /*Command interpretation library */
31 #include <afs/fsprobe.h> /*Interface for fsprobe module */
32 #include <afs/afsutil.h>
37 * Command line parameter indicies.
48 * Define the default width in chars for each light object on the mini-line.
50 #define LIGHTOBJ_CONN_WIDTH 5
51 #define LIGHTOBJ_FETCH_WIDTH 10
52 #define LIGHTOBJ_STORE_WIDTH 10
53 #define LIGHTOBJ_WK_WIDTH 5
54 #define LIGHTOBJ_SRVNAME_WIDTH 13
55 #define LIGHTOBJ_DISK_WIDTH 12
58 * Define column width indices.
68 * Define the types of justification we can perform.
70 #define SCOUT_RIGHT_JUSTIFY 0
71 #define SCOUT_LEFT_JUSTIFY 1
72 #define SCOUT_CENTER 2
75 * Define the types of truncation we can perform.
77 #define SCOUT_LEFT_TRUNC 0
78 #define SCOUT_RIGHT_TRUNC 1
81 * Define whether the value passed is a labeled disk quantity.
83 #define SCOUT_ISNT_LDISK 0
84 #define SCOUT_IS_LDISK 1
87 * We sometimes use index-base pointers, so we need a distinguished
90 #define SCOUT_NIL (-1)
93 * Structure describing everything you want to know about a FileServer
97 int prev; /*Index of previous list entry */
98 int next; /*Index of next list entry */
99 int active; /*Is this disk known to exist? */
100 char *name; /*Single-letter disk name */
101 struct onode *disk_lp; /*Ptr to disk light object */
105 * Structure defining all the objects in the Scout line (or lines)
106 * for each server being watched. Note that scout_disk linked list
107 * for used disks is ordered alphabetically.
111 * Information on server location & configuration.
113 struct sockaddr_in skt; /*Server's socket info */
114 int numDisks; /*Number of disks used */
116 * Screen location info.
118 int base_line; /*Line number on the screen */
119 int num_lines; /*Number of lines of info */
121 * Associated light objects.
123 struct onode *currConns_lp; /*Number of current connections */
124 struct onode *fetches_lp; /*Number of data fetches */
125 struct onode *stores_lp; /*Number of data stores */
126 struct onode *workstations_lp; /*Workstation info */
127 struct onode *srvName_lp; /*Server name */
128 struct scout_disk disks[VOLMAXPARTS]; /*Info on all the disks */
129 int used_head; /*Index of first used disk struct */
130 int used_tail; /*Index of last used disk struct */
131 int free_head; /*Index of first free disk struct */
132 int free_tail; /*Index of last free disk struct */
136 * Structure defining the contents of the Scout screen.
139 int numServers; /*Number of servers being watched */
140 int base_line_num; /*Base mini-line number */
141 struct mini_line *line; /*Array of screen lines */
144 static char pn[] = "scout"; /*Program name */
145 static int scout_debug = 0; /*Is debugging turned on? */
146 static FILE *scout_debugfd; /*Debugging file descriptor */
147 static int scout_gtx_initialized = 0; /*Has gtx been initialized? */
148 static struct mini_screen scout_screen; /*Mini-screen itself */
149 static int scout_probefreq; /*Probe frequency in seconds */
150 static char scout_basename[64]; /*Base server name */
151 static char scout_hostname[128]; /*Name of machine we're running on */
152 static int scout_showhostname = 0; /*Show name of machine we're on? */
153 static char scout_blankline[256]; /*Blank line */
154 static struct gwin *scout_gwin; /*Window to use */
155 static struct gtx_frame *scout_frame; /*Frame to use */
156 static struct onode *scout_banner0_lp; /*Banner light, line 0 */
157 static struct onode *scout_banner1_lp; /*Banner light, line 1 */
158 static struct onode *scout_banner2_lp; /*Banner light, line 2 */
159 static int scout_DiskLightLeftCol = 0; /*Column for leftmost disk light */
160 static struct gwin_sizeparams scout_frameDims; /*Frame dimensions */
162 static int scout_col_width[] = { LIGHTOBJ_CONN_WIDTH,
163 LIGHTOBJ_FETCH_WIDTH,
164 LIGHTOBJ_STORE_WIDTH,
166 LIGHTOBJ_SRVNAME_WIDTH,
171 * Attention thresholds & modes.
173 #define SCOUT_ATTN_NOTUSED (-1)
174 #define SCOUT_DISKM_PCUSED 0
175 #define SCOUT_DISKM_MINFREE 1
177 static int scout_attn_conn = SCOUT_ATTN_NOTUSED;
178 static int scout_attn_fetch = SCOUT_ATTN_NOTUSED;
179 static int scout_attn_store = SCOUT_ATTN_NOTUSED;
180 static int scout_attn_workstations = SCOUT_ATTN_NOTUSED;
181 static int scout_attn_disk_mode = SCOUT_DISKM_PCUSED;
182 static int scout_attn_disk_minfree = 1000;
183 static float scout_attn_disk_pcused = 0.95;
184 static char scout_attn_disk_pcusedstr[8] = "95";
187 * Some strings we'll be using over and over again.
189 static char scout_Banner[256];
190 static const char *scout_label[] =
191 { "Conn", "Fetch", "Store", "Ws", "", "Disk attn" };
192 static const char *scout_underline[] =
193 { "----", "--------", "--------", "-----", "", "----------" };
196 /*------------------------------------------------------------------------
200 * Exits cleanly from the Scout. If gtx has not yet been initialized,
201 * then we simply call exit() with the value provided. Otherwise,
202 * we call the appropriate gtx routine to exit cleanly from gtx, which
203 * must reset the terminal or window. We also close the debugging
204 * file descriptor, if one has been opened.
207 * int a_exitval : Value with which to exit the program.
213 * Actions depend on scout_gtx_initialized.
216 * This routine will always exit Scout.
217 *------------------------------------------------------------------------*/
220 scout_CleanExit(int a_exitval)
221 { /*scout_CleanExit */
223 static char rn[] = "scout_CleanExit"; /*Routine name */
225 if (scout_debugfd != (FILE *) 0) {
226 fprintf(scout_debugfd, "[%s] Closing debugging file\n", rn);
227 fclose(scout_debugfd);
230 if (scout_gtx_initialized) {
231 gtxframe_exitValue = a_exitval;
232 gtxframe_ExitCmd((void *)(>xframe_exitValue), NULL);
236 } /*scout_CleanExit */
238 /*------------------------------------------------------------------------
239 * mini_initLightObject
242 * Create and initialize a light onode according to the given
246 * char *a_name : Ptr to the light's string name.
247 * int a_x : X offset.
248 * int a_y : Y offset.
249 * int a_width : Width in chars.
250 * struct gwin *a_win : Ptr to window structure.
253 * Ptr to new light onode on success,
254 * A null pointer otherwise.
261 *------------------------------------------------------------------------*/
263 static struct onode *
264 mini_initLightObject(char *a_name, int a_x, int a_y, int a_width, struct gwin *a_win)
265 { /*mini_initLightObject */
267 static char rn[] = "mini_initLightObject"; /*Routine name */
268 struct onode *newlightp; /*Ptr to new light onode */
269 /*We only support curses right now */
270 struct gator_light_crparams light_crparams; /*Light creation params */
271 int name_len; /*True length of name */
274 fprintf(scout_debugfd,
275 "[%s] Called for name '%s', [%d, %d], %d-char field\n", rn,
276 a_name, a_x, a_y, a_width);
277 fflush(scout_debugfd);
282 * Set up the creation parameters according to the information we've
285 light_crparams.onode_params.cr_type = GATOR_OBJ_LIGHT;
286 name_len = strlen(a_name);
288 fprintf(scout_debugfd, "[%s] Name '%s' has %d chars\n", rn, a_name,
291 if (a_width >= sizeof(light_crparams.onode_params.cr_name))
292 a_width = sizeof(light_crparams.onode_params.cr_name) - 1;
294 if (strlcpy(light_crparams.onode_params.cr_name, a_name, a_width + 1) >= a_width + 1)
295 /* The name is truncated, put a '*' at the end to note */
296 light_crparams.onode_params.cr_name[a_width - 1] = '*';
298 light_crparams.onode_params.cr_x = a_x;
299 light_crparams.onode_params.cr_y = a_y;
300 light_crparams.onode_params.cr_width = a_width;
301 light_crparams.onode_params.cr_height = 1;
302 light_crparams.onode_params.cr_window = a_win;
303 light_crparams.onode_params.cr_home_obj = NULL;
304 light_crparams.onode_params.cr_prev_obj = NULL;
305 light_crparams.onode_params.cr_parent_obj = NULL;
306 light_crparams.onode_params.cr_helpstring = NULL;
308 light_crparams.appearance = 0;
309 light_crparams.flashfreq = 0;
310 sprintf(light_crparams.label, "%s", a_name);
311 light_crparams.label_x = 0;
312 light_crparams.label_y = 0;
315 gator_objects_create((struct onode_createparams *)(&light_crparams));
318 * Return the news, happy or not.
322 } /*mini_initLightObject */
324 /*------------------------------------------------------------------------
325 * scout_initDiskLightObjects
328 * Create and initialize all Scout light objects for a server's
332 * struct scout_disk *a_line : Ptr to the server object line.
333 * struct gwin *a_win : Ptr to window structure.
344 *------------------------------------------------------------------------*/
347 scout_initDiskLightObjects(struct mini_line *a_line, struct gwin *a_win)
348 { /*scout_initDiskLightObjects */
350 static char rn[] = "scout_initDiskLightObjects"; /*Routine name */
351 struct scout_disk *curr_disk; /*Ptr to current disk being set up */
352 int i; /*Loop variable */
355 fprintf(scout_debugfd, "[%s] Called\n", rn);
356 fflush(scout_debugfd);
360 * Set up the base linked list fields.
362 a_line->used_head = SCOUT_NIL;
363 a_line->used_tail = SCOUT_NIL;
364 a_line->free_head = 0;
365 a_line->free_tail = VOLMAXPARTS - 1;
368 * Sweep through the disk structures, creating the light objects and
369 * marking them all as free.
371 curr_disk = a_line->disks;
372 for (i = 0; i < VOLMAXPARTS; i++) {
374 * Create the disk light object.
376 if ((curr_disk->disk_lp = mini_initLightObject("Disk", /*Object name */
379 scout_col_width[COL_DISK], /*Width */
382 fprintf(stderr, "[%s:%s] Can't create disk %d light object\n", pn,
388 * Set the other fields in the disk records; Note that in the
389 * fencepost cases, the prev and next pointers will have to be
392 curr_disk->prev = i - 1;
393 curr_disk->next = i + 1;
394 curr_disk->active = 0;
395 curr_disk->name = "";
398 * Bump up to the next disk structure.
402 } /*for each disk structure */
405 * We made it all the way through. Fix the fencepost pointers, set
406 * the overall pointers, then return success.
408 a_line->disks[0].prev = SCOUT_NIL;
409 a_line->disks[VOLMAXPARTS - 1].next = SCOUT_NIL;
413 } /*scout_initDiskLightObjects */
416 /*------------------------------------------------------------------------
420 * Place the chars in the source buffer into the target buffer
421 * with the desired justification, either centered, left-justified
422 * or right-justified. Also, support inidication of truncation
423 * with a star (*), either on the left or right of the string,
424 * and whether we're justifying a labeled disk quantity.
427 * char *a_srcbuff : Ptr to source char buffer.
428 * char *a_dstbuff : Ptr to dest char buffer.
429 * int a_dstwidth : Width of dest buffer in chars.
430 * int a_justification : Kind of justification.
431 * int a_rightTrunc : If non-zero, place the truncation char
432 * on the right of the string. Otherwise,
433 * place it on the left.
434 * int a_isLabeledDisk : Is this a labeled disk quantity?
441 * All it needs to know is exported by the fsprobe module, namely
442 * the data structure where the probe results are stored.
446 *------------------------------------------------------------------------*/
449 mini_justify(char *a_srcbuff, char *a_dstbuff, int a_dstwidth,
450 int a_justification, int a_rightTrunc,
454 static char rn[] = "mini_justify"; /*Routine name */
455 int leftpad_chars; /*# of chars for left-padding */
456 int num_src_chars; /*# of chars in source */
457 int true_num_src_chars; /*# src chars before truncation */
458 int trunc_needed; /*Is truncation needed? */
459 char diskChar = 0; /*Disk name prefix */
462 fprintf(scout_debugfd, "[%s] Called with '%s', dest width=%d\n", rn,
463 a_srcbuff, a_dstwidth);
464 fflush(scout_debugfd);
468 * Remember the disk label, if we've been passed such a thing.
471 diskChar = *a_srcbuff;
474 * If the destination width will overrun the gtx string storage,
475 * we automatically shorten up.
477 if (a_dstwidth > GATOR_LABEL_CHARS) {
479 fprintf(scout_debugfd,
480 "[%s] Dest width (%d) > gtx buflen (%d), shrinking dest width\n",
481 rn, a_dstwidth, GATOR_LABEL_CHARS);
482 fflush(scout_debugfd);
484 a_dstwidth = GATOR_LABEL_CHARS;
488 * If our source string is too long, prepare for truncation.
490 true_num_src_chars = strlen(a_srcbuff);
491 if (true_num_src_chars >= a_dstwidth) {
493 num_src_chars = a_dstwidth - 1;
496 a_srcbuff += (true_num_src_chars - num_src_chars);
499 num_src_chars = true_num_src_chars;
502 * Compute the necessary left-padding.
504 switch (a_justification) {
506 case SCOUT_RIGHT_JUSTIFY:
507 leftpad_chars = (a_dstwidth - 1) - num_src_chars;
510 case SCOUT_LEFT_JUSTIFY:
512 * This is the really easy one.
518 leftpad_chars = ((a_dstwidth - 1) - num_src_chars) / 2;
522 fprintf(stderr, "[%s] Illegal justification command: %d", rn,
525 } /*Switch on justification type */
529 * Clear out the dest buffer, then place the source string at the
530 * appropriate padding location. Remember to place a string
531 * terminator at the end of the dest buffer, plus whatever truncation
532 * may be needed. If we're left-truncating, we've already shifted
533 * the src buffer appropriately.
535 strncpy(a_dstbuff, scout_blankline, a_dstwidth);
536 strncpy(a_dstbuff + leftpad_chars, a_srcbuff, num_src_chars);
537 *(a_dstbuff + a_dstwidth - 1) = '\0';
540 *(a_dstbuff + a_dstwidth - 2) = '*'; /*Truncate on the right */
542 if (a_isLabeledDisk) {
543 *a_dstbuff = diskChar;
544 *(a_dstbuff + 1) = ':';
545 *(a_dstbuff + 2) = '*'; /*Truncate on the left, disk */
547 *a_dstbuff = '*'; /*Truncate on the left, non-disk */
551 /*Handle truncations */
553 * Return the good news.
559 /*------------------------------------------------------------------------
560 * scout_SetNonDiskLightLine
563 * Given a mini-line and a line number, place all non-disk lights
567 * struct mini_line *a_srvline : Ptr to server descriptor.
568 * int a_linenum : Line number to move to.
574 * The light's location is stored not only in the onode, but in
575 * the light's rock, so we have to change both sets of value.
579 *------------------------------------------------------------------------*/
582 scout_SetNonDiskLightLine(struct mini_line *a_srvline, int a_linenum)
583 { /*scout_SetNonDiskLightLine */
585 struct gator_lightobj *nondisk_lightdata; /*Non-disk light data field */
586 struct gwin_strparams *nondisk_strparams; /*Associated string params */
589 * Do the exact same operation for each non-disk light in the record.
591 a_srvline->currConns_lp->o_y = a_linenum;
593 (struct gator_lightobj *)(a_srvline->currConns_lp->o_data);
594 nondisk_strparams = (struct gwin_strparams *)(nondisk_lightdata->llrock);
595 nondisk_strparams->y = a_linenum;
597 a_srvline->fetches_lp->o_y = a_linenum;
599 (struct gator_lightobj *)(a_srvline->fetches_lp->o_data);
600 nondisk_strparams = (struct gwin_strparams *)(nondisk_lightdata->llrock);
601 nondisk_strparams->y = a_linenum;
603 a_srvline->stores_lp->o_y = a_linenum;
605 (struct gator_lightobj *)(a_srvline->stores_lp->o_data);
606 nondisk_strparams = (struct gwin_strparams *)(nondisk_lightdata->llrock);
607 nondisk_strparams->y = a_linenum;
609 a_srvline->workstations_lp->o_y = a_linenum;
611 (struct gator_lightobj *)(a_srvline->workstations_lp->o_data);
612 nondisk_strparams = (struct gwin_strparams *)(nondisk_lightdata->llrock);
613 nondisk_strparams->y = a_linenum;
615 a_srvline->srvName_lp->o_y = a_linenum;
617 (struct gator_lightobj *)(a_srvline->srvName_lp->o_data);
618 nondisk_strparams = (struct gwin_strparams *)(nondisk_lightdata->llrock);
619 nondisk_strparams->y = a_linenum;
621 } /*scout_SetNonDiskLightLine */
623 /*------------------------------------------------------------------------
624 * scout_RecomputeLightLocs
627 * Given a pointer to a server record, recompute its disk light
628 * locations (and keep proper track of the number of screen lines
629 * required for the server record).
632 * struct mini_line *a_srvline : Ptr to server descriptor.
635 * 0 if anything went wrong,
636 * else the number of lines used by this server record.
639 * One or more records have joined or left the used light list
640 * for this server. We're not sure which ones, so we recompute
641 * them all. We may also have had a width change in the gtx
642 * frame. The base_line field in the server record is guaranteed
643 * to be correct at this point.
647 *------------------------------------------------------------------------*/
650 scout_RecomputeLightLocs(struct mini_line *a_srvline)
651 { /*scout_RecomputeLightLocs */
653 static char rn[] = "scout_RecomputeLightLocs"; /*Routine name */
654 int lights_per_line; /*# lights/line */
655 int lights_this_line; /*# lights on cur line */
656 int curr_idx; /*Current disk light idx */
657 struct scout_disk *sc_disk; /*Ptr to disk record array */
658 int lines_for_server; /*Num lines in server record */
659 int curr_line; /*Current line being filled */
660 int curr_x; /*Current x value for light */
661 struct gator_lightobj *disk_lightdata; /*Disk light data field */
662 struct gwin_strparams *disk_strparams; /*String params for disk light */
665 fprintf(scout_debugfd, "[%s] Called\n", rn);
666 fflush(scout_debugfd);
670 * If we haven't yet computed the column for the leftmost disk light,
673 if (scout_DiskLightLeftCol == 0) {
675 int num_cols = sizeof(scout_col_width) / sizeof(*scout_col_width);
676 scout_DiskLightLeftCol = 0;
677 for (i = 0; i < (num_cols - 1); i++) {
678 scout_DiskLightLeftCol += scout_col_width[i] + 1;
683 * Calculate how many disk light objects can fit in one line.
686 (scout_frameDims.maxx -
687 scout_DiskLightLeftCol) / (scout_col_width[COL_DISK] + 1);
689 fprintf(scout_debugfd, "[%s] %d lights per line\n", rn,
691 fflush(scout_debugfd);
695 * Sweep through the used disk light list, computing the location
698 lights_this_line = 0;
699 curr_idx = a_srvline->used_head;
700 lines_for_server = 1;
701 curr_line = a_srvline->base_line;
702 curr_x = scout_DiskLightLeftCol;
704 while (curr_idx != SCOUT_NIL) {
706 * Bump the number of lines for the server if we've already
707 * filled up the current line.
709 if (lights_this_line >= lights_per_line) {
710 lights_this_line = 0;
713 curr_x = scout_DiskLightLeftCol;
716 /*Current line filled up */
718 * Set the current disk light's location.
720 sc_disk = a_srvline->disks;
721 sc_disk[curr_idx].disk_lp->o_x = curr_x;
722 sc_disk[curr_idx].disk_lp->o_y = curr_line;
724 (struct gator_lightobj *)(sc_disk[curr_idx].disk_lp->o_data);
725 disk_strparams = (struct gwin_strparams *)(disk_lightdata->llrock);
726 disk_strparams->x = curr_x;
727 disk_strparams->y = curr_line;
729 fprintf(scout_debugfd,
730 "[%s] Disk light at index %d located at [%d, %d]\n", rn,
731 curr_idx, curr_x, curr_line);
732 fflush(scout_debugfd);
736 * Record the inclusion of the light and move on to the next
740 curr_x += scout_col_width[COL_DISK] + 1;
741 curr_idx = sc_disk[curr_idx].next;
743 } /*Update each used disk light */
746 * Remember to record the (possibly new) number of lines in the
747 * server record before returning the value of that field.
749 if (a_srvline->num_lines != lines_for_server) {
751 fprintf(scout_debugfd,
752 "[%s] Server previously had %d screen lines; now changed\n",
753 rn, a_srvline->num_lines);
754 fflush(scout_debugfd);
756 a_srvline->num_lines = lines_for_server;
760 fprintf(scout_debugfd, "[%s] Server has %d screen lines\n", rn,
761 a_srvline->num_lines);
762 fflush(scout_debugfd);
764 return (a_srvline->num_lines);
766 } /*scout_RecomputeLightLocs */
768 /*------------------------------------------------------------------------
772 * Given a single-letter disk name and a pointer to the current server
773 * record, look for a used disk record with that name within the server.
774 * If we can't find one, we create and incorporate one, and return that
775 * fact to our caller.
778 * char a_diskname : Single-char disk name.
779 * struct mini_line *a_srvline : Ptr to server descriptor.
780 * int *a_record_added : Was a new record added?
783 * Index of matching used disk record,
784 * SCOUT_NIL otherwise.
786 * Return via parameter:
787 * a_record_added set to 1 iff record was added to the used disk list.
790 * Used disk records are kept in alphabetical order by the single-char
791 * disk name. Should a matching used disk record not be found, one is
792 * pulled from the free pool.
795 * An entry may be pulled off the free list and inserted into the
796 * used list. This entry is placed in the update list for the
797 * current gtx frame (at least not by this routine).
798 *------------------------------------------------------------------------*/
801 scout_FindUsedDisk(char *a_diskname, struct mini_line *a_srvline, int *a_record_added)
802 { /*scout_FindUsedDisk */
804 static char rn[] = "scout_FindUsedDisk"; /*Routine name */
805 int curr_idx; /*Disk record index */
806 int append_idx; /*Index to append after */
807 int new_idx; /*Index of new used record */
808 struct scout_disk *sc_disk; /*Ptr to disk record */
809 int code; /*Function return value */
812 fprintf(scout_debugfd, "[%s] Called\n", rn);
813 fflush(scout_debugfd);
817 * Sweep through the used disk records, looking for a match.
819 curr_idx = a_srvline->used_head;
820 append_idx = SCOUT_NIL;
821 sc_disk = a_srvline->disks;
823 fprintf(scout_debugfd,
824 "[%s] Scanning existing used disk entries for disk '%s'\n",
826 fflush(scout_debugfd);
828 while (curr_idx != SCOUT_NIL) {
830 fprintf(scout_debugfd, "[%s] Disk %d is named '%s'\n", rn,
831 curr_idx, sc_disk[curr_idx].name);
832 fflush(scout_debugfd);
834 if (strcmp(sc_disk[curr_idx].name, a_diskname) == 0) {
836 * We found it! Bug out.
839 fprintf(scout_debugfd, "[%s] Match found\n", rn);
840 fflush(scout_debugfd);
846 * If we are alphabetically past the given disk name, we
847 * know that we won't find it in the used disk list; we
848 * also have the append index set correctly.
850 if (strcmp(a_diskname, sc_disk[curr_idx].name) < 0) {
852 fprintf(scout_debugfd, "[%s] Disk '%s' can't be here\n", rn,
854 fflush(scout_debugfd);
860 * There's still hope we'll find it. Move on to the next used
861 * disk record, keeping this index as the best candidate so far
862 * for appending a missing entry.
864 append_idx = curr_idx;
865 curr_idx = sc_disk[curr_idx].next;
866 } /*Look for match */
869 * We didn't find the record we wanted, which means we'll pull a
870 * record out of the free pool for it. If we didn't find a place
871 * to append it, we then insert it at the beginning of the queue.
873 if (a_srvline->free_head == SCOUT_NIL)
876 new_idx = a_srvline->free_head;
878 fprintf(scout_debugfd, "[%s] Choosing free index %d for new entry\n",
880 fflush(scout_debugfd);
882 a_srvline->free_head = sc_disk[new_idx].next;
883 if (a_srvline->free_head == SCOUT_NIL)
884 a_srvline->free_tail = SCOUT_NIL;
887 * Fill in the new record.
889 sc_disk[new_idx].active = 0;
890 sc_disk[new_idx].name = a_diskname;
893 * Insert the new record where it belongs on the used disk list.
895 if (append_idx == SCOUT_NIL) {
897 * It belongs at the beginning of the list.
900 fprintf(scout_debugfd, "[%s] Inserted at used disk head\n", rn);
901 fflush(scout_debugfd);
903 sc_disk[new_idx].next = a_srvline->used_head;
904 sc_disk[new_idx].prev = SCOUT_NIL;
905 a_srvline->used_head = new_idx;
906 if (a_srvline->used_tail == SCOUT_NIL)
907 a_srvline->used_tail = new_idx;
910 fprintf(scout_debugfd, "[%s] Entry appended after index %d\n", rn,
912 fflush(scout_debugfd);
914 sc_disk[new_idx].prev = append_idx;
915 sc_disk[new_idx].next = sc_disk[append_idx].next;
916 sc_disk[append_idx].next = new_idx;
917 if (sc_disk[new_idx].next == SCOUT_NIL)
918 a_srvline->used_tail = new_idx;
920 sc_disk[sc_disk[new_idx].next].prev = new_idx;
924 * Add the new used disk light object to the display list for
928 fprintf(scout_debugfd,
929 "[%s] Adding disk light at index %d to display list\n", rn,
931 fflush(scout_debugfd);
933 code = gtxframe_AddToList(scout_frame, sc_disk[new_idx].disk_lp);
936 fprintf(scout_debugfd,
937 "[%s] Can't add to display list, code is %d\n", rn, code);
938 fflush(scout_debugfd);
943 } /*scout_FindUsedDisk */
945 /*------------------------------------------------------------------------
946 * scout_RemoveInactiveDisk
949 * Given a server record and a used disk index, remove the disk
950 * record from the used list, put it on the free list, and remove
951 * it from the gtx frame update list.
954 * struct mini_line *a_srvline : Ptr to server descriptor.
955 * int a_used_idx : Index of used disk record.
961 * Formerly-used disk records are returned to the free pool.
964 * Free and used disk record lists are modified for this server.
965 * The disk record in question is pulled off the gtx update list
967 *------------------------------------------------------------------------*/
970 scout_RemoveInactiveDisk(struct mini_line *a_srvline, int a_used_idx)
971 { /*scout_RemoveInactiveDisk */
973 static char rn[] = "scout_RemoveInactiveDisk"; /*Routine name */
976 fprintf(scout_debugfd, "[%s] Called\n", rn);
977 fflush(scout_debugfd);
980 /*code = gtxframe_RemoveFromList(scout_frame->window, lightobj); */
982 } /*scout_RemoveInactiveDisk */
984 /*------------------------------------------------------------------------
985 * mini_PrintDiskStats
988 * Given server indexing and light object information, a pointer
989 * to a set of statistics, and whether the probe that produced these
990 * stats succeeded or not, print out the stats in a nice way.
993 * struct mini_line *a_srvline : Ptr to server descriptor.
994 * struct ProbeViceStatistics *a_stats : Ptr to current stats.
995 * int a_probeOK : Was the probe OK?
996 * int a_width_changed : Has the frame width changed?
997 * int a_fix_line_num : Is the line number wrong?
998 * int a_delta_line_num : Change in line number.
1001 * 0 if something went wrong,
1002 * else the number of lines taken up by this server record.
1005 * Nothing interesting.
1009 *------------------------------------------------------------------------*/
1012 mini_PrintDiskStats(struct mini_line *a_srvline,
1013 struct ProbeViceStatistics *a_stats,
1014 int a_probeOK, int a_width_changed,
1015 int a_fix_line_num, int a_delta_line_num)
1016 { /*mini_PrintDiskStats */
1018 static char rn[] = "mini_PrintDiskStats"; /*Routine name */
1019 char s[128]; /*String buffer */
1020 struct onode *curr_disklight; /*Ptr to current disk light */
1021 struct onode *srvname_light; /*Ptr to server name light */
1022 ViceDisk *curr_diskstat; /*Ptr to current disk stat */
1023 int curr_disk; /*Current disk stat number */
1024 int used_disk_idx; /*Used disk index */
1025 int next_used_idx; /*Ditto */
1026 int pastthreshold; /*Was disk past threshold? */
1027 struct gator_lightobj *diskdata; /*Private light data */
1028 struct gwin_strparams *disk_strparams; /*String params for disk light */
1029 char *diskname = 0; /*Name of disk */
1030 int found_idx; /*Idx of matching disk */
1031 char *srv_name; /*Server name */
1032 struct scout_disk *sc_disk; /*Ptr to scout disk desc */
1033 int fix_light_locs; /*Recompute disk light locs? */
1036 fprintf(scout_debugfd, "[%s] Called\n", rn);
1037 fflush(scout_debugfd);
1041 * Remember the current server's print name, don't recompute light
1044 srvname_light = a_srvline->srvName_lp;
1045 srv_name = ((struct gator_lightobj *)(srvname_light->o_data))->label;
1048 fprintf(scout_debugfd, "[%s] Value of a_delta_line_num is %d\n", rn,
1050 fflush(scout_debugfd);
1054 * If the probe failed, we simply blank out all the used disk
1055 * objects. Note: a NON-ZERO value of a_probeOK implies failure.
1058 used_disk_idx = a_srvline->used_head;
1059 while (used_disk_idx != SCOUT_NIL) {
1061 * Point to the current used disk's light, blank out its
1062 * contents, and make sure highlighting is turned off. We
1063 * also take this opportunity to fix the line numbers if
1066 curr_disklight = a_srvline->disks[used_disk_idx].disk_lp;
1067 diskdata = (struct gator_lightobj *)(curr_disklight->o_data);
1069 fprintf(scout_debugfd,
1070 "[%s] Prev value of disk light %d: '%s'\n", rn,
1071 used_disk_idx, diskdata->label);
1072 fflush(scout_debugfd);
1074 mini_justify(" ", /*Src buffer */
1075 diskdata->label, /*Dest buffer */
1076 scout_col_width[COL_DISK], /*Dest's width */
1077 SCOUT_RIGHT_JUSTIFY, /*Right-justify */
1078 SCOUT_LEFT_TRUNC, /*Left-truncate */
1079 SCOUT_ISNT_LDISK); /*Not a labeled disk */
1080 gator_light_set(curr_disklight, 0);
1081 if (a_fix_line_num) {
1082 curr_disklight->o_y += a_delta_line_num;
1083 disk_strparams = (struct gwin_strparams *)(diskdata->llrock);
1084 disk_strparams->y += a_delta_line_num;
1088 * Advance to next used disk, if any.
1090 used_disk_idx = a_srvline->disks[used_disk_idx].next;
1092 } /*Blank out disk name field */
1095 * If the frame width has changed, we have to recompute all disk
1096 * light locations. After that, the number of lines in the server
1097 * record will be accurate, and we return them.
1099 if (a_width_changed)
1100 scout_RecomputeLightLocs(a_srvline);
1102 return (a_srvline->num_lines);
1106 /*Probe failed for the server */
1108 * Probe was successful. Sweep through the statistics records,
1109 * and put up all values having to do with AFS partitions. First,
1110 * mark all used disk objects for this server as inactive and fix
1111 * their line numbers if needed.
1113 used_disk_idx = a_srvline->used_head;
1114 while (used_disk_idx != SCOUT_NIL) {
1116 fprintf(scout_debugfd, "[%s] Marking used disk %d inactive\n", rn,
1118 fflush(scout_debugfd);
1120 sc_disk = (a_srvline->disks) + used_disk_idx;
1121 sc_disk->active = 0;
1122 used_disk_idx = sc_disk->next;
1123 if (a_fix_line_num) {
1124 sc_disk->disk_lp->o_y += a_delta_line_num;
1125 diskdata = (struct gator_lightobj *)(sc_disk->disk_lp->o_data);
1126 disk_strparams = (struct gwin_strparams *)(diskdata->llrock);
1127 disk_strparams->y += a_delta_line_num;
1129 } /*Mark used disks inactive */
1131 curr_diskstat = (ViceDisk *) a_stats->Disk;
1132 for (curr_disk = 0; curr_disk < VOLMAXPARTS; curr_disk++) {
1134 * An AFS partition name must be prefixed by `/vicep`.
1137 fprintf(scout_debugfd, "[%s] Disk stats at %p for disk '%s'\n",
1138 rn, curr_diskstat, curr_diskstat->Name);
1139 fflush(scout_debugfd);
1141 if (strncmp("/vice", curr_diskstat->Name, 5) == 0) {
1143 * Pull out the single-letter name (actually, abbreviation)
1144 * of the disk and look for such an entry in the used disks.
1146 diskname = &curr_diskstat->Name[6];
1147 found_idx = scout_FindUsedDisk(diskname, /*1-char name */
1148 a_srvline, /*Server record */
1149 &fix_light_locs); /*Recompute? */
1150 if (found_idx == SCOUT_NIL) {
1152 "[%s] Can't display /vicep%s on server '%s'\n", rn,
1153 diskname, srv_name);
1156 * Found (or created) record for this disk. Fill in the single-
1157 * letter name of the disk followed by the number of free blocks.
1158 * Turn the disk light on if the number of free blocks exceeds
1159 * the threshold the user set, either % used or min free blocks.
1161 sprintf(s, "%s:%d", diskname, curr_diskstat->BlocksAvailable);
1162 if (scout_attn_disk_mode == SCOUT_DISKM_PCUSED) {
1164 (curr_diskstat->TotalBlocks -
1165 curr_diskstat->BlocksAvailable) /
1166 (float)(curr_diskstat->TotalBlocks) >
1167 scout_attn_disk_pcused)
1173 (curr_diskstat->BlocksAvailable <
1174 scout_attn_disk_minfree) ? 1 : 0;
1175 sc_disk = (a_srvline->disks) + found_idx;
1176 sc_disk->active = 1;
1178 (struct gator_lightobj *)(sc_disk->disk_lp->o_data);
1180 fprintf(scout_debugfd,
1181 "[%s] Justifying %s for disk idx %d (prev value: '%s')\n",
1182 rn, s, found_idx, diskdata->label);
1183 fflush(scout_debugfd);
1185 mini_justify(s, /*Src buffer */
1186 diskdata->label, /*Dest buffer */
1187 scout_col_width[COL_DISK], /*Dest's width */
1188 SCOUT_LEFT_JUSTIFY, /*Left-justify */
1189 SCOUT_LEFT_TRUNC, /*Left-truncate */
1190 SCOUT_IS_LDISK); /*Labeled disk */
1192 gator_light_set(sc_disk->disk_lp, pastthreshold);
1194 } /*Found disk record */
1197 /*Found AFS disk name */
1199 * Advance to the next disk statistics record.
1202 } /*For each statistics record */
1205 * We've now pulled out all the disk statistics from the probe.
1206 * See if any used disks that were there from the last time are
1207 * now gone. If so, we remove them.
1210 fprintf(scout_debugfd,
1211 "[%s] Scanning used disk records for inactive entries\n", rn);
1212 fflush(scout_debugfd);
1214 used_disk_idx = a_srvline->used_head;
1215 while (used_disk_idx != SCOUT_NIL) {
1217 fprintf(scout_debugfd, "[%s] Examining entry at index %d\n", rn,
1219 fflush(scout_debugfd);
1221 sc_disk = (a_srvline->disks) + used_disk_idx;
1222 next_used_idx = sc_disk->next;
1223 if (!(sc_disk->active)) {
1224 scout_RemoveInactiveDisk(a_srvline, /*Server record */
1225 used_disk_idx); /*Disk index to nuke */
1228 used_disk_idx = next_used_idx;
1230 } /*Remove inactive used disks */
1233 * If we've had to add or remove disks to/from the used list,
1234 * or if the frame width has changed, we recompute the light
1235 * locations before returning.
1237 if (fix_light_locs || a_width_changed)
1238 scout_RecomputeLightLocs(a_srvline);
1241 * Return the (possibly new) size of the current server record.
1243 return (a_srvline->num_lines);
1245 } /*mini_PrintDiskStats */
1247 /*------------------------------------------------------------------------
1251 * Handler routine passed to the fsprobe module. This handler is
1252 * called immediately after a poll of all the FileServers has taken
1253 * place. Its job is to write out selected data to the scout
1264 * All it needs to know is exported by the fsprobe module, namely
1265 * the data structure where the probe results are stored.
1268 * Recomputes disk light locations in response to reshaping the
1269 * scout window or from adding/deleting disk lights to/from
1270 * individual servers.
1271 *------------------------------------------------------------------------*/
1277 static char rn[] = "FS_Handler"; /*Routine name */
1278 int code; /*Return code */
1279 struct ProbeViceStatistics *curr_stats; /*Ptr to current stats */
1280 int *curr_probeOK; /*Ptr to current probeOK field */
1281 int curr_srvidx; /*Current server index */
1282 char s[128]; /*String buffer */
1283 static char sblank[] = " "; /*Blank string buffer */
1284 char *sp; /*Ptr to string buffer */
1285 struct mini_line *curr_line; /*Current mini-line */
1286 int curr_line_num; /*Current line number */
1287 struct gator_lightobj *lightdata; /*Private light data */
1288 int setting; /*Light setting (on or off) */
1289 int old_width; /*Keep the old width value */
1290 int width_changed; /*Has the frame width changed? */
1291 int fix_line_num; /*Line number needs fixing */
1292 int delta_line_num; /*Change in line number */
1295 * See if the size of the scout frame has changed since the last
1298 old_width = scout_frameDims.maxx;
1300 fprintf(scout_debugfd, "[%s] Calling wop_getdimensions\n", rn);
1301 fflush(scout_debugfd);
1303 WOP_GETDIMENSIONS(scout_frame->window, &scout_frameDims);
1304 width_changed = (old_width == scout_frameDims.maxx) ? 0 : 1;
1306 fprintf(scout_debugfd,
1307 "[%s] Frame dimensions are %d rows, %d columns\n", rn,
1308 scout_frameDims.maxy, scout_frameDims.maxx);
1310 fprintf(scout_debugfd, "[%s] Width has changed from %d columns\n",
1312 fflush(scout_debugfd);
1316 * Print out the selected fields for each server. We actually change
1317 * the light's label to the new data.
1319 curr_line = scout_screen.line;
1320 curr_stats = fsprobe_Results.stats;
1321 curr_probeOK = fsprobe_Results.probeOK;
1322 curr_line_num = curr_line->base_line;
1324 for (curr_srvidx = 0; curr_srvidx < scout_screen.numServers;
1327 * If the current server record is set up on the wrong line, fix
1328 * the non-disk light objects directly, and remember to fix the
1329 * disk light objects later on.
1331 if (curr_line->base_line != curr_line_num) {
1333 delta_line_num = curr_line_num - curr_line->base_line;
1334 curr_line->base_line = curr_line_num;
1335 scout_SetNonDiskLightLine(curr_line, curr_line_num);
1342 (struct gator_lightobj *)(curr_line->currConns_lp->o_data);
1343 if (*curr_probeOK == 0) {
1345 sprintf(sp, "%d", curr_stats->CurrentConnections);
1348 mini_justify(sp, /*Src buffer */
1349 lightdata->label, /*Dest buffer */
1350 scout_col_width[COL_CONN], /*Dest's width */
1351 SCOUT_RIGHT_JUSTIFY, /*Right-justify */
1352 SCOUT_LEFT_TRUNC, /*Left-truncate */
1353 SCOUT_ISNT_LDISK); /*Not a labeled disk */
1354 if (scout_attn_conn != SCOUT_ATTN_NOTUSED
1355 && curr_stats->CurrentConnections >= scout_attn_conn)
1359 gator_light_set(curr_line->currConns_lp, setting);
1361 lightdata = (struct gator_lightobj *)(curr_line->fetches_lp->o_data);
1362 if (*curr_probeOK == 0) {
1364 sprintf(sp, "%u", curr_stats->TotalFetchs);
1367 mini_justify(sp, /*Src buffer */
1368 lightdata->label, /*Dest buffer */
1369 scout_col_width[COL_FETCH], /*Dest's width */
1370 SCOUT_RIGHT_JUSTIFY, /*Right-justify */
1371 SCOUT_LEFT_TRUNC, /*Left-truncate */
1372 SCOUT_ISNT_LDISK); /*Not a labeled disk */
1373 if (scout_attn_fetch != SCOUT_ATTN_NOTUSED
1374 && curr_stats->TotalFetchs >= scout_attn_fetch)
1378 gator_light_set(curr_line->fetches_lp, setting);
1380 lightdata = (struct gator_lightobj *)(curr_line->stores_lp->o_data);
1381 if (*curr_probeOK == 0) {
1383 sprintf(sp, "%u", curr_stats->TotalStores);
1386 mini_justify(sp, /*Src buffer */
1387 lightdata->label, /*Dest buffer */
1388 scout_col_width[COL_STORE], /*Dest's width */
1389 SCOUT_RIGHT_JUSTIFY, /*Right-justify */
1390 SCOUT_LEFT_TRUNC, /*Left-truncate */
1391 SCOUT_ISNT_LDISK); /*Not a labeled disk */
1392 if (scout_attn_store != SCOUT_ATTN_NOTUSED
1393 && curr_stats->TotalStores >= scout_attn_store)
1397 gator_light_set(curr_line->stores_lp, setting);
1400 (struct gator_lightobj *)(curr_line->workstations_lp->o_data);
1401 if (*curr_probeOK == 0) {
1403 sprintf(sp, "%d", curr_stats->WorkStations);
1406 mini_justify(sp, /*Src buffer */
1407 lightdata->label, /*Dest buffer */
1408 scout_col_width[COL_WK], /*Dest's width */
1409 SCOUT_RIGHT_JUSTIFY, /*Right-justify */
1410 SCOUT_LEFT_TRUNC, /*Left-truncate */
1411 SCOUT_ISNT_LDISK); /*Not a labeled disk */
1412 if (scout_attn_workstations != SCOUT_ATTN_NOTUSED
1413 && curr_stats->WorkStations >= scout_attn_workstations)
1417 gator_light_set(curr_line->workstations_lp, setting);
1420 * We turn the server light on if there was an error in the
1421 * current probe (e.g., if the curr_probeOK field is non-zero.
1422 * (Don't forget to fix the light's line if it needs it).
1424 setting = (*curr_probeOK) ? 1 : 0;
1425 gator_light_set(curr_line->srvName_lp, setting);
1428 * Print out the disk statistics. The value returned is the
1429 * number of lines taken up by the server record (or 0 if
1430 * something went wrong).
1432 code = mini_PrintDiskStats(curr_line, /*Ptr to server line */
1433 curr_stats, /*Fresh disk stats */
1434 *curr_probeOK, /*Was probe OK? */
1435 width_changed, /*Has the width changed? */
1436 fix_line_num, /*Fix the line number? */
1437 delta_line_num); /*Change in line number */
1439 fprintf(stderr, "[%s] Error in printing out disk statistics\n",
1443 curr_line_num += code;
1446 * Advance the current mini_line, stats source, and probe success
1453 } /*for each server probed */
1456 * Display the scout frame.
1458 sprintf(s, "Probe %d results", fsprobe_Results.probeNum);
1459 gtxframe_DisplayString(scout_frame, s);
1460 WOP_DISPLAY(scout_gwin);
1463 * Return the happy news.
1469 /*------------------------------------------------------------------------
1473 * Initialize each line in the mini_screen.
1476 * struct sockaddr_in *a_skt : Ptr to server socket info.
1477 * int a_lineNum; : Line number being created.
1478 * struct mini_line *a_line : Ptr to mini_line to set up.
1479 * char *a_srvname : Printable server name.
1483 * Error value otherwise.
1486 * Nothing interesting.
1490 *------------------------------------------------------------------------*/
1493 init_mini_line(struct sockaddr_in *a_skt, int a_lineNum,
1494 struct mini_line *a_line, char *a_srvname)
1495 { /*init_mini_line */
1497 static char rn[] = "init_mini_line"; /*Routine name */
1498 int curr_x; /*Current X position */
1499 int curr_y; /*Current Y position */
1500 char s[128]; /*Scratch buffer */
1501 int code; /*Return code */
1502 struct gator_lightobj *lightdata; /*Private light data */
1505 fprintf(scout_debugfd, "[%s] Called for base line %d\n", rn,
1507 fflush(scout_debugfd);
1511 * Fill in the top fields (except the disk fields, which will be
1512 * done elsewhere), then create the light onodes.
1514 memcpy((char *)&(a_line->skt), (char *)a_skt, sizeof(struct sockaddr_in));
1515 a_line->numDisks = 0;
1516 a_line->base_line = a_lineNum + scout_screen.base_line_num;
1517 a_line->num_lines = 1;
1520 curr_y = a_line->base_line;
1521 if ((a_line->currConns_lp =
1522 mini_initLightObject("Conns", curr_x, curr_y, scout_col_width[COL_CONN],
1525 fprintf(stderr, "[%s:%s] Can't create currConns light object\n", pn,
1529 curr_x += scout_col_width[COL_CONN] + 1;
1531 if ((a_line->fetches_lp =
1532 mini_initLightObject("Fetches", curr_x, curr_y, scout_col_width[COL_FETCH],
1533 scout_frame->window))
1535 fprintf(stderr, "[%s:%s] Can't create fetches light object\n", pn,
1539 curr_x += scout_col_width[COL_FETCH] + 1;
1541 if ((a_line->stores_lp =
1542 mini_initLightObject("Stores", curr_x, curr_y, scout_col_width[COL_STORE],
1543 scout_frame->window))
1545 fprintf(stderr, "[%s:%s] Can't create stores light object\n", pn, rn);
1548 curr_x += scout_col_width[COL_STORE] + 1;
1550 if ((a_line->workstations_lp =
1551 mini_initLightObject("WrkStn", curr_x, curr_y, scout_col_width[COL_WK],
1552 scout_frame->window))
1554 fprintf(stderr, "[%s:%s] Can't create workstations light object\n",
1558 curr_x += scout_col_width[COL_WK] + 1;
1560 if ((a_line->srvName_lp =
1561 mini_initLightObject(a_srvname, curr_x, curr_y,
1562 scout_col_width[COL_SRVNAME], scout_frame->window))
1564 fprintf(stderr, "[%s:%s] Can't create server name light object\n", pn,
1568 sprintf(s, "%s", a_srvname);
1569 lightdata = (struct gator_lightobj *)(a_line->srvName_lp->o_data);
1570 code = mini_justify(s, /*Src buffer */
1571 lightdata->label, /*Dest buffer */
1572 scout_col_width[COL_SRVNAME], /*Dest's width */
1573 SCOUT_CENTER, /*Centered */
1574 SCOUT_RIGHT_TRUNC, /*Right-truncate */
1575 SCOUT_ISNT_LDISK); /*Not a labeled disk */
1578 "[%s] Can't center server name inside of light object\n", rn);
1582 if (scout_initDiskLightObjects(a_line, scout_frame->window)) {
1583 fprintf(stderr, "[%s:%s] Can't create disk light objects\n", pn, rn);
1588 * Finally, return the happy news.
1592 } /*init_mini_line */
1594 /*------------------------------------------------------------------------
1598 * Workhorse routine that starts up the FileServer probe.
1601 * int a_numservers : Length of above list.
1602 * struct cmd_item *a_srvname : List of FileServer machines to
1604 * int a_pkg : Window package to use.
1608 * Error value otherwise.
1611 * Nothing interesting.
1615 *------------------------------------------------------------------------*/
1618 execute_scout(int a_numservers, struct cmd_item *a_srvname, int a_pkg)
1619 { /*execute_scout */
1621 static char rn[] = "execute_scout"; /*Routine name */
1622 static char fullsrvname[128]; /*Full server name */
1623 int code; /*Return code */
1624 struct sockaddr_in *FSSktArray; /*Server socket array */
1625 int sktbytes; /*Num bytes in above */
1626 struct sockaddr_in *curr_skt; /*Ptr to current socket */
1627 struct cmd_item *curr_item; /*Ptr to current cmd item */
1628 struct hostent *he; /*Host entry */
1629 struct mini_line *mini_lines; /*Ptr to all mini-lines */
1630 struct mini_line *curr_line; /*Ptr to current line */
1631 int i; /*Generic loop variable */
1632 int mini_line_bytes; /*Num bytes in mini_lines */
1633 int linenum; /*Current mini-line number */
1634 struct gator_lightobj *lightdata; /*Private light data */
1637 fprintf(scout_debugfd, "[%s] Called\n", rn);
1638 fflush(scout_debugfd);
1642 * We have to initialize thread support before we start up any of
1648 * Initialize the gtx package.
1650 scout_gwin = gtx_Init(0, /*Don't start up InputServer yet */
1651 -1); /*Type of window package */
1652 if (scout_gwin == NULL) {
1653 fprintf(stderr, "[%s:%s] Call to gtx_Init() failed!\n", pn, rn);
1658 * Remember we've set up gtx so we can exit cleanly from now on.
1660 scout_gtx_initialized = 1;
1663 * Create the frame everything will go into, set it up as our only
1664 * frame for this window.
1666 scout_frame = gtxframe_Create();
1667 if (scout_frame == (struct gtx_frame *)0) {
1668 fprintf(stderr, "[%s:%s] Call to gtxframe_Create() failed!\n", pn,
1672 gtxframe_SetFrame(scout_gwin, scout_frame);
1673 WOP_GETDIMENSIONS(scout_frame->window, &scout_frameDims);
1676 * Allocate an array of sockets to describe each FileServer we'll be
1679 sktbytes = a_numservers * sizeof(struct sockaddr_in);
1680 FSSktArray = calloc(1, sktbytes);
1681 if (FSSktArray == (struct sockaddr_in *)0) {
1683 "[%s] Can't malloc() %d sockaddrs (%d bytes) for the given servers\n",
1684 rn, a_numservers, sktbytes);
1685 scout_CleanExit(-1);
1689 * Sweep through the server names provided, filling in the socket
1690 * info for each. Take into account the fact that we may have a
1691 * base name associated for each.
1693 curr_item = a_srvname;
1694 curr_skt = FSSktArray;
1696 if (*scout_basename == '\0')
1697 sprintf(fullsrvname, "%s", curr_item->data);
1699 sprintf(fullsrvname, "%s.%s", curr_item->data, scout_basename);
1700 he = hostutil_GetHostByName(fullsrvname);
1702 fprintf(stderr, "[%s] Can't get host info for '%s'\n", rn,
1706 memcpy(&(curr_skt->sin_addr.s_addr), he->h_addr, 4);
1707 curr_skt->sin_family = AF_INET;
1708 curr_skt->sin_port = htons(7000); /* FileServer port */
1711 * Bump our pointers.
1713 curr_item = curr_item->next;
1716 } /*Build socket entry for each server */
1719 * Create the set of mini-lines, one per server.
1721 mini_line_bytes = a_numservers * sizeof(struct mini_line);
1722 mini_lines = calloc(1, mini_line_bytes);
1723 if (mini_lines == (struct mini_line *)0) {
1724 fprintf(stderr, "[%s] Can't malloc() %d bytes for %d screen lines\n",
1725 rn, mini_line_bytes, a_numservers);
1730 * Set up each line in the mini_lines, creating and initializing
1731 * its light objects.
1733 scout_screen.base_line_num = 4;
1734 curr_line = mini_lines;
1735 curr_skt = FSSktArray;
1737 curr_item = a_srvname;
1738 gtxframe_ClearList(scout_frame);
1741 * Create the light objects that server as banner lines. Remember
1742 * to take into account the server basename, if any, and the name
1743 * of the host that scout if running on, if that's wanted.
1745 if (scout_showhostname) {
1746 if (*scout_basename == '\0')
1747 sprintf(scout_Banner, "[%s] %s", scout_hostname, "Scout");
1749 sprintf(scout_Banner, "[%s] Scout for %s", scout_hostname,
1752 if (*scout_basename == '\0')
1753 sprintf(scout_Banner, "%s", " Scout");
1755 sprintf(scout_Banner, " Scout for %s", scout_basename);
1757 scout_banner0_lp = mini_initLightObject("Banner 0", /*Light name */
1758 0, /*X*/ 0, /*Y*/ scout_frameDims.maxx, /*Width */
1759 scout_gwin); /*Window */
1760 if (scout_banner0_lp != NULL) {
1761 lightdata = (struct gator_lightobj *)(scout_banner0_lp->o_data);
1762 mini_justify(scout_Banner, lightdata->label, scout_frameDims.maxx,
1763 SCOUT_CENTER, SCOUT_RIGHT_TRUNC, SCOUT_ISNT_LDISK);
1764 gator_light_set(scout_banner0_lp, 1);
1765 gtxframe_AddToList(scout_frame, scout_banner0_lp);
1769 fprintf(scout_debugfd, "[%s] Scout label is '%s', %" AFS_SIZET_FMT " chars\n", rn,
1770 lightdata->label, strlen(lightdata->label));
1773 scout_banner1_lp = mini_initLightObject("Banner 1", /*Light name */
1774 0, /*X*/ 2, /*Y*/ scout_frameDims.maxx, /*Width */
1775 scout_gwin); /*Window */
1776 if (scout_banner1_lp != NULL) {
1777 char attn_label[256];
1778 if (scout_attn_disk_mode == SCOUT_DISKM_PCUSED) {
1779 snprintf(attn_label, sizeof(attn_label), "%s: > %s%% used",
1780 scout_label[5], scout_attn_disk_pcusedstr);
1782 snprintf(attn_label, sizeof(attn_label), "%s: < %d blocks free",
1783 scout_label[5], scout_attn_disk_minfree);
1785 code = snprintf(scout_Banner, sizeof(scout_Banner),
1786 "%*s %*s %*s %*s %*s %s",
1787 scout_col_width[0], scout_label[0],
1788 scout_col_width[1], scout_label[1],
1789 scout_col_width[2], scout_label[2],
1790 scout_col_width[3], scout_label[3],
1791 scout_col_width[4], scout_label[4],
1793 if (code < 0 || code >= sizeof(scout_Banner)) {
1794 fprintf(stderr, "[%s] Truncation while generating banner\n", rn);
1798 lightdata = (struct gator_lightobj *)(scout_banner1_lp->o_data);
1799 mini_justify(scout_Banner, lightdata->label, scout_frameDims.maxx,
1800 SCOUT_LEFT_JUSTIFY, SCOUT_RIGHT_TRUNC,
1803 gtxframe_AddToList(scout_frame, scout_banner1_lp);
1806 scout_banner2_lp = mini_initLightObject("Banner 2", /*Light name */
1807 0, /*X*/ 3, /*Y*/ scout_frameDims.maxx, /*Width */
1808 scout_gwin); /*Window */
1809 if (scout_banner2_lp != NULL) {
1810 snprintf(scout_Banner, sizeof(scout_Banner),
1811 "%*s %*s %*s %*s %*s %s",
1812 scout_col_width[0], scout_underline[0],
1813 scout_col_width[1], scout_underline[1],
1814 scout_col_width[2], scout_underline[2],
1815 scout_col_width[3], scout_underline[3],
1816 scout_col_width[4], scout_underline[4],
1817 scout_underline[5]);
1819 lightdata = (struct gator_lightobj *)(scout_banner2_lp->o_data);
1820 mini_justify(scout_Banner, lightdata->label,
1821 scout_frameDims.maxx, SCOUT_LEFT_JUSTIFY,
1822 SCOUT_RIGHT_TRUNC, SCOUT_ISNT_LDISK);
1823 gtxframe_AddToList(scout_frame, scout_banner2_lp);
1826 for (i = 0; i < a_numservers; i++) {
1827 code = init_mini_line(curr_skt, linenum, curr_line, curr_item->data);
1829 fprintf(stderr, "[%s] Can't initialize line for server %d\n", rn,
1836 curr_item = curr_item->next;
1840 * Now that all lines have been set up, we feed in the light items
1841 * created. Note: the disk lights are entered at a later time,
1842 * as they enter the used disk list for each server.
1844 curr_line = mini_lines;
1845 for (i = 0; i < a_numservers; i++) {
1846 code = gtxframe_AddToList(scout_frame, curr_line->currConns_lp);
1849 "[%s] Can't add client connections light to display list\n",
1854 code = gtxframe_AddToList(scout_frame, curr_line->fetches_lp);
1857 "[%s] Can't add fetches light to frame display list\n",
1862 code = gtxframe_AddToList(scout_frame, curr_line->stores_lp);
1865 "[%s] Can't add stores light to frame display list\n",
1870 code = gtxframe_AddToList(scout_frame, curr_line->workstations_lp);
1873 "[%s] Can't add workstation light to display list\n", rn);
1877 code = gtxframe_AddToList(scout_frame, curr_line->srvName_lp);
1880 "[%s] Can't add server name light to display list\n", rn);
1885 * Move down to the next server record.
1889 } /*Add lights in server records to display list */
1892 * Finish setting up the overall mini_screen structure.
1894 scout_screen.numServers = a_numservers;
1895 scout_screen.line = mini_lines;
1896 WOP_GETDIMENSIONS(scout_frame->window, &scout_frameDims);
1899 * Start up the fsprobe package, which will gather FileServer
1900 * statistics for us on a regular basis.
1902 gtxframe_DisplayString(scout_frame,
1903 "Establishing File Server connection(s)...");
1904 code = fsprobe_Init(a_numservers, /*Num FileServers to probe */
1905 FSSktArray, /*FileServer socket array */
1906 scout_probefreq, /*Probe frequency */
1907 FS_Handler, /*Handler routine */
1908 0); /*Turn debugging output off */
1910 fprintf(stderr, "[%s] Error returned by fsprobe_Init: %d\n", rn,
1915 code = (int)(intptr_t)gtx_InputServer(scout_gwin);
1918 "[%s] Error exit from gtx_InputServer(), error is %d\n", rn,
1920 scout_CleanExit(code);
1923 fsprobe_Wait(0); /* sleep forever */
1925 } /*execute_scout */
1927 /*------------------------------------------------------------------------
1931 * Given a pointer to the list of servers we'll be polling,
1932 * compute the length of the list.
1935 * struct cmd_item *a_firstItem : Ptr to first item in list.
1938 * Length of the above list.
1941 * Nothing interesting.
1945 *------------------------------------------------------------------------*/
1947 static int countServers(struct cmd_item *a_firstItem)
1950 int list_len; /*List length */
1951 struct cmd_item *curr_item; /*Ptr to current item */
1954 curr_item = a_firstItem;
1961 curr_item = curr_item->next;
1971 /*------------------------------------------------------------------------
1972 * scout_AdoptThresholds
1975 * Parse and adopt one or more threshold values, as read off the
1979 * struct cmd_item *a_thresh_item : Ptr to item on command-line
1983 * Nothing (but may exit the entire program on error!)
1986 * Valid keywords are:
1987 * conn, disk, fetch, store, ws
1988 * The disk value, if it has a % sign, signifies that attention
1989 * will be triggered when the disk is more than that percentage
1990 * full; otherwise, it will specify the minimum number of free
1995 *------------------------------------------------------------------------*/
1997 static void scout_AdoptThresholds(struct cmd_item *a_thresh_item)
1998 { /*scout_AdoptThresholds */
2000 static char rn[] = "scout_AdoptThresholds"; /*Routine name */
2001 struct cmd_item *curr_item; /*Current item */
2002 char *curr_name; /*Current name half of pair */
2003 char *curr_value; /*Current value half of pair */
2004 int diskval_len; /*Length of disk attn value */
2006 curr_item = a_thresh_item;
2009 * If there isn't a corresponding value for the current
2010 * attention field, bitch & die.
2012 if (curr_item->next == (struct cmd_item *)0) {
2013 printf("[%s] No threshold value given for '%s'\n", rn,
2015 scout_CleanExit(-1);
2018 curr_name = curr_item->data;
2019 curr_value = curr_item->next->data;
2021 if (strcmp(curr_name, "conn") == 0) {
2023 fprintf(scout_debugfd,
2024 "[%s] Setting conn attn value to %d (default %d)\n",
2025 rn, atoi(curr_value), scout_attn_conn);
2026 fflush(scout_debugfd);
2028 scout_attn_conn = atoi(curr_value);
2029 } else if (strcmp(curr_name, "disk") == 0) {
2031 * If there's a '%' as the last character in the value,
2032 * we use percentage mode.
2034 diskval_len = strlen(curr_value);
2035 if (curr_value[diskval_len - 1] == '%') {
2036 curr_value[diskval_len - 1] = '\0';
2038 fprintf(scout_debugfd,
2039 "[%s] New disk attn value: 0.%s used (default %f)\n",
2040 rn, curr_value, scout_attn_disk_pcused);
2041 fflush(scout_debugfd);
2043 sprintf(scout_attn_disk_pcusedstr, "%s", curr_value);
2044 scout_attn_disk_pcused =
2045 ((float)(atoi(curr_value))) / ((float)(100));
2046 } /*Percentage mode */
2049 fprintf(scout_debugfd,
2050 "[%s] New disk attn value: %s min free (default %f)\n",
2051 rn, curr_value, scout_attn_disk_pcused);
2052 fflush(scout_debugfd);
2054 scout_attn_disk_mode = SCOUT_DISKM_MINFREE;
2055 scout_attn_disk_minfree = atoi(curr_value);
2056 } /*Min free blocks mode */
2057 } else if (strcmp(curr_name, "fetch") == 0) {
2059 fprintf(scout_debugfd,
2060 "[%s] Setting fetch attn value to %d (default %d)\n",
2061 rn, atoi(curr_value), scout_attn_fetch);
2062 fflush(scout_debugfd);
2064 scout_attn_fetch = atoi(curr_value);
2065 } else if (strcmp(curr_name, "store") == 0) {
2067 fprintf(scout_debugfd,
2068 "[%s] Setting store attn value to %d (default %d)\n",
2069 rn, atoi(curr_value), scout_attn_store);
2070 fflush(scout_debugfd);
2072 scout_attn_store = atoi(curr_value);
2073 } else if (strcmp(curr_name, "ws") == 0) {
2075 fprintf(scout_debugfd,
2076 "[%s] Setting workstation attn value to %d (default %d)\n",
2077 rn, atoi(curr_value), scout_attn_workstations);
2078 fflush(scout_debugfd);
2080 scout_attn_workstations = atoi(curr_value);
2082 printf("[%s] Unknown attention item: '%s'\n", rn,
2084 scout_CleanExit(-1);
2088 * Advance past the just-processed pair.
2090 curr_item = curr_item->next->next;
2092 } /*Interpret each name-value pair */
2094 } /*scout_AdoptThresholds */
2097 * Setup the user specified column widths.
2099 * The column widths specifies the number of digits which
2100 * will be displayed without truncation. The column widths
2101 * are given in the same order in which they are displayed,
2102 * from left to right. Not all columns need to be specified
2103 * on the command line. The default column widths for those
2104 * columns not specified. Column widths can not be set smaller
2105 * than the heading underline.
2107 * @param[in] a_width_item command line width item list
2110 scout_SetColumnWidths(struct cmd_item *a_width_item)
2114 int num_cols = sizeof(scout_col_width) / sizeof(*scout_col_width);
2116 for (i = 0; a_width_item && i < num_cols; i++) {
2117 width = atoi(a_width_item->data);
2119 int min_width = strlen(scout_underline[i]);
2121 width = max(width, min_width);
2123 scout_col_width[i] = width + 1;
2125 a_width_item = a_width_item->next;
2128 fprintf(stderr, "Too many values given for -columnwidths\n");
2133 /*------------------------------------------------------------------------
2137 * Routine called when Scout is invoked, responsible for basic
2138 * initialization, command line parsing, and calling the
2139 * routine that does all the work.
2142 * as : Command syntax descriptor.
2143 * arock : Associated rock (not used here).
2146 * Zero (but may exit the entire program on error!)
2149 * Nothing interesting.
2152 * Initializes this program.
2153 *------------------------------------------------------------------------*/
2155 static int scoutInit(struct cmd_syndesc *as, void *arock)
2158 static char rn[] = "scoutInit"; /*Routine name */
2159 int code; /*Return code */
2160 int wpkg_to_use; /*Window package to use */
2161 int server_count; /*Number of servers to watch */
2162 char *debug_filename; /*Name of debugging output file */
2165 fprintf(scout_debugfd, "[%s] Called\n", rn);
2166 fflush(scout_debugfd);
2169 if (as->parms[P_DEBUG].items != 0) {
2171 debug_filename = as->parms[P_DEBUG].items->data;
2172 scout_debugfd = fopen(debug_filename, "w");
2173 if (scout_debugfd == (FILE *) 0) {
2174 printf("[%s] Can't open debugging file '%s'!\n", rn,
2176 scout_CleanExit(-1);
2178 fprintf(scout_debugfd, "[%s] Writing to Scout debugging file '%s'\n",
2179 rn, debug_filename);
2181 wpkg_to_use = 2; /*Always use curses for now */
2182 if (as->parms[P_FREQ].items != 0)
2183 scout_probefreq = atoi(as->parms[P_FREQ].items->data);
2185 scout_probefreq = 60;
2188 * See if we've been fed a base server name.
2190 if (as->parms[P_BASE].items != 0)
2191 sprintf(scout_basename, "%s", as->parms[P_BASE].items->data);
2193 *scout_basename = '\0';
2196 * Count the number of servers we've been asked to monitor.
2198 server_count = countServers(as->parms[P_SERVER].items);
2201 * Create a line of blanks, a generally-useful thing.
2203 sprintf(scout_blankline, "%255s", " ");
2206 * Pull in the name of the host we're executing on if we've been
2207 * asked to. If we can't get the name, we provide a default.
2209 if (as->parms[P_HOST].items != 0) {
2210 scout_showhostname = 1;
2211 *scout_hostname = '\0';
2212 code = gethostname(scout_hostname, 128);
2214 sprintf(scout_hostname, "%s", "*No Hostname*");
2218 * Pull in any and all attention/highlighting thresholds.
2220 if (as->parms[P_ATTENTION].items != 0)
2221 scout_AdoptThresholds(as->parms[P_ATTENTION].items);
2223 if (as->parms[P_WIDTHS].items != 0) {
2224 scout_SetColumnWidths(as->parms[P_WIDTHS].items);
2228 * Now, drive the sucker.
2230 code = execute_scout(server_count, /*Num servers */
2231 as->parms[P_SERVER].items, /*Ptr to srv names */
2232 wpkg_to_use); /*Graphics pkg */
2234 fprintf(stderr, "[%s] Error executing scout: %d\n", rn, code);
2235 scout_CleanExit(-1);
2239 * We initialized (and ran) correctly, so return the good news.
2245 #include "AFS_component_version_number.c"
2248 main(int argc, char **argv)
2251 afs_int32 code; /*Return code */
2252 struct cmd_syndesc *ts; /*Ptr to cmd line syntax descriptor */
2254 #ifdef AFS_AIX32_ENV
2256 * The following signal action for AIX is necessary so that in case of a
2257 * crash (i.e. core is generated) we can include the user's data section
2258 * in the core dump. Unfortunately, by default, only a partial core is
2259 * generated which, in many cases, isn't too useful.
2261 struct sigaction nsa;
2263 sigemptyset(&nsa.sa_mask);
2264 nsa.sa_handler = SIG_DFL;
2265 nsa.sa_flags = SA_FULLDUMP;
2266 sigaction(SIGSEGV, &nsa, NULL);
2269 * Set up the commands we understand.
2271 ts = cmd_CreateSyntax("initcmd", scoutInit, NULL, 0, "initialize the program");
2272 cmd_AddParm(ts, "-server", CMD_LIST, CMD_REQUIRED,
2273 "FileServer name(s) to monitor");
2274 cmd_AddParm(ts, "-basename", CMD_SINGLE, CMD_OPTIONAL,
2275 "base server name");
2276 cmd_AddParm(ts, "-frequency", CMD_SINGLE, CMD_OPTIONAL,
2277 "poll frequency, in seconds");
2278 cmd_AddParm(ts, "-host", CMD_FLAG, CMD_OPTIONAL,
2279 "show name of host you're running on");
2280 cmd_AddParm(ts, "-attention", CMD_LIST, CMD_OPTIONAL,
2281 "specify attention (highlighting) level");
2282 cmd_AddParm(ts, "-debug", CMD_SINGLE, CMD_OPTIONAL,
2283 "turn debugging output on to the named file");
2284 cmd_AddParm(ts, "-columnwidths", CMD_LIST, CMD_OPTIONAL,
2285 "specify column widths");
2288 * Parse command-line switches & execute the test, then get the heck
2291 code = cmd_Dispatch(argc, argv);
2297 return 0; /* not reachable */