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>
32 #include <gtxwindows.h> /*Generic window package */
33 #include <gtxobjects.h> /*Object definitions */
34 #include <gtxtextobj.h> /*Text object interface */
35 #include <gtxlightobj.h> /*Light object interface */
36 #include <gtxcurseswin.h> /*Curses window package */
37 #include <gtxdumbwin.h> /*Dumb terminal window package */
38 #include <gtxX11win.h> /*X11 window package */
39 #include <gtxframe.h> /*Frame package */
40 #include <stdio.h> /*Standard I/O stuff */
41 #include <cmd.h> /*Command interpretation library */
42 #include <fsprobe.h> /*Interface for fsprobe module */
46 extern struct hostent *hostutil_GetHostByName();
47 extern int gtx_InputServer();
48 extern int gethostname();
51 * Command line parameter indicies.
64 * Define the width in chars for each light object on the mini-line.
66 #define LIGHTOBJ_CONN_WIDTH 5
67 #define LIGHTOBJ_FETCH_WIDTH 10
68 #define LIGHTOBJ_STORE_WIDTH 10
69 #define LIGHTOBJ_WK_WIDTH 5
70 #define LIGHTOBJ_SRVNAME_WIDTH 13
71 #define LIGHTOBJ_DISK_WIDTH 12
74 * Define the types of justification we can perform.
76 #define SCOUT_RIGHT_JUSTIFY 0
77 #define SCOUT_LEFT_JUSTIFY 1
78 #define SCOUT_CENTER 2
81 * Define the types of truncation we can perform.
83 #define SCOUT_LEFT_TRUNC 0
84 #define SCOUT_RIGHT_TRUNC 1
87 * Define whether the value passed is a labeled disk quantity.
89 #define SCOUT_ISNT_LDISK 0
90 #define SCOUT_IS_LDISK 1
93 * We sometimes use index-base pointers, so we need a distinguished
96 #define SCOUT_NIL (-1)
99 * Structure describing everything you want to know about a FileServer
103 int prev; /*Index of previous list entry */
104 int next; /*Index of next list entry */
105 int active; /*Is this disk known to exist? */
106 char *name; /*Single-letter disk name */
107 struct onode *disk_lp; /*Ptr to disk light object */
111 * Structure defining all the objects in the Scout line (or lines)
112 * for each server being watched. Note that scout_disk linked list
113 * for used disks is ordered alphabetically.
117 * Information on server location & configuration.
119 struct sockaddr_in skt; /*Server's socket info */
120 int numDisks; /*Number of disks used */
122 * Screen location info.
124 int base_line; /*Line number on the screen */
125 int num_lines; /*Number of lines of info */
127 * Associated light objects.
129 struct onode *currConns_lp; /*Number of current connections */
130 struct onode *fetches_lp; /*Number of data fetches */
131 struct onode *stores_lp; /*Number of data stores */
132 struct onode *workstations_lp; /*Workstation info */
133 struct onode *srvName_lp; /*Server name */
134 struct scout_disk disks[VOLMAXPARTS]; /*Info on all the disks */
135 int used_head; /*Index of first used disk struct */
136 int used_tail; /*Index of last used disk struct */
137 int free_head; /*Index of first free disk struct */
138 int free_tail; /*Index of last free disk struct */
142 * Structure defining the contents of the Scout screen.
145 int numServers; /*Number of servers being watched */
146 int base_line_num; /*Base mini-line number */
147 struct mini_line *line; /*Array of screen lines */
150 static char pn[] = "scout"; /*Program name */
151 static int scout_debug = 0; /*Is debugging turned on? */
152 static FILE *scout_debugfd; /*Debugging file descriptor */
153 static int scout_gtx_initialized = 0; /*Has gtx been initialized? */
154 static struct mini_screen scout_screen; /*Mini-screen itself */
155 static int scout_probefreq; /*Probe frequency in seconds */
156 static char scout_basename[64]; /*Base server name */
157 static char scout_hostname[128]; /*Name of machine we're running on */
158 static int scout_showhostname = 0; /*Show name of machine we're on? */
159 static char scout_blankline[256]; /*Blank line */
160 static struct gwin *scout_gwin; /*Window to use */
161 static struct gtx_frame *scout_frame; /*Frame to use */
162 static struct onode *scout_banner0_lp; /*Banner light, line 0 */
163 static struct onode *scout_banner1_lp; /*Banner light, line 1 */
164 static struct onode *scout_banner2_lp; /*Banner light, line 2 */
165 static int scout_DiskLightLeftCol = 0; /*Column for leftmost disk light */
166 static struct gwin_sizeparams scout_frameDims; /*Frame dimensions */
169 * Attention thresholds & modes.
171 #define SCOUT_ATTN_NOTUSED (-1)
172 #define SCOUT_DISKM_PCUSED 0
173 #define SCOUT_DISKM_MINFREE 1
175 static int scout_attn_conn = SCOUT_ATTN_NOTUSED;
176 static int scout_attn_fetch = SCOUT_ATTN_NOTUSED;
177 static int scout_attn_store = SCOUT_ATTN_NOTUSED;
178 static int scout_attn_workstations = SCOUT_ATTN_NOTUSED;
179 static int scout_attn_disk_mode = SCOUT_DISKM_PCUSED;
180 static int scout_attn_disk_minfree = 1000;
181 static float scout_attn_disk_pcused = 0.95;
182 static char scout_attn_disk_pcusedstr[8] = "95";
185 * Some strings we'll be using over and over again.
187 static char scout_Banner[256];
188 static char scout_LightLabels[] =
189 "Conn Fetch Store Ws Disk attn:";
190 static char scout_LightLabelUnd[] =
191 "---- -------- -------- ----- ----------";
194 /*------------------------------------------------------------------------
198 * Exits cleanly from the Scout. If gtx has not yet been initialized,
199 * then we simply call exit() with the value provided. Otherwise,
200 * we call the appropriate gtx routine to exit cleanly from gtx, which
201 * must reset the terminal or window. We also close the debugging
202 * file descriptor, if one has been opened.
205 * int a_exitval : Value with which to exit the program.
211 * Actions depend on scout_gtx_initialized.
214 * This routine will always exit Scout.
215 *------------------------------------------------------------------------*/
218 scout_CleanExit(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((char *)(>xframe_exitValue));
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(a_name, a_x, a_y, a_width, a_win)
271 { /*mini_initLightObject */
273 static char rn[] = "mini_initLightObject"; /*Routine name */
274 struct onode *newlightp; /*Ptr to new light onode */
275 /*We only support curses right now */
276 struct gator_light_crparams light_crparams; /*Light creation params */
277 char *truncname; /*Truncated name, if needed */
278 int name_len; /*True length of name */
281 fprintf(scout_debugfd,
282 "[%s] Called for name '%s', [%d, %d], %d-char field\n", rn,
283 a_name, a_x, a_y, a_width);
284 fflush(scout_debugfd);
289 * Set up the creation parameters according to the information we've
292 light_crparams.onode_params.cr_type = GATOR_OBJ_LIGHT;
293 name_len = strlen(a_name);
295 fprintf(scout_debugfd, "[%s] Name '%s' has %d chars\n", rn, a_name,
297 if (name_len <= a_width)
298 sprintf(light_crparams.onode_params.cr_name, "%s", a_name);
301 * We need to truncate the given name, leaving a `*' at the end to
302 * show us it's been truncated.
304 truncname = light_crparams.onode_params.cr_name;
305 strncpy(truncname, a_name, a_width - 1);
306 truncname[a_width - 1] = '*';
307 truncname[a_width] = 0;
309 light_crparams.onode_params.cr_x = a_x;
310 light_crparams.onode_params.cr_y = a_y;
311 light_crparams.onode_params.cr_width = a_width;
312 light_crparams.onode_params.cr_height = 1;
313 light_crparams.onode_params.cr_window = a_win;
314 light_crparams.onode_params.cr_home_obj = NULL;
315 light_crparams.onode_params.cr_prev_obj = NULL;
316 light_crparams.onode_params.cr_parent_obj = NULL;
317 light_crparams.onode_params.cr_helpstring = NULL;
319 light_crparams.appearance = 0;
320 light_crparams.flashfreq = 0;
321 sprintf(light_crparams.label, "%s", a_name);
322 light_crparams.label_x = 0;
323 light_crparams.label_y = 0;
326 gator_objects_create((struct onode_createparams *)(&light_crparams));
329 * Return the news, happy or not.
333 } /*mini_initLightObject */
335 /*------------------------------------------------------------------------
336 * scout_initDiskLightObjects
339 * Create and initialize all Scout light objects for a server's
343 * struct scout_disk *a_line : Ptr to the server object line.
344 * struct gwin *a_win : Ptr to window structure.
355 *------------------------------------------------------------------------*/
358 scout_initDiskLightObjects(a_line, a_win)
359 struct mini_line *a_line;
362 { /*scout_initDiskLightObjects */
364 static char rn[] = "scout_initDiskLightObjects"; /*Routine name */
365 struct scout_disk *curr_disk; /*Ptr to current disk being set up */
366 int i; /*Loop variable */
369 fprintf(scout_debugfd, "[%s] Called\n", rn);
370 fflush(scout_debugfd);
374 * Set up the base linked list fields.
376 a_line->used_head = SCOUT_NIL;
377 a_line->used_tail = SCOUT_NIL;
378 a_line->free_head = 0;
379 a_line->free_tail = VOLMAXPARTS - 1;
382 * Sweep through the disk structures, creating the light objects and
383 * marking them all as free.
385 curr_disk = a_line->disks;
386 for (i = 0; i < VOLMAXPARTS; i++) {
388 * Create the disk light object.
390 if ((curr_disk->disk_lp = mini_initLightObject("Disk", /*Object name */
393 LIGHTOBJ_DISK_WIDTH, /*Width */
396 fprintf(stderr, "[%s:%s] Can't create disk %d light object\n", pn,
402 * Set the other fields in the disk records; Note that in the
403 * fencepost cases, the prev and next pointers will have to be
406 curr_disk->prev = i - 1;
407 curr_disk->next = i + 1;
408 curr_disk->active = 0;
409 curr_disk->name = '\0';
412 * Bump up to the next disk structure.
416 } /*for each disk structure */
419 * We made it all the way through. Fix the fencepost pointers, set
420 * the overall pointers, then return success.
422 a_line->disks[0].prev = SCOUT_NIL;
423 a_line->disks[VOLMAXPARTS - 1].next = SCOUT_NIL;
427 } /*scout_initDiskLightObjects */
430 /*------------------------------------------------------------------------
434 * Place the chars in the source buffer into the target buffer
435 * with the desired justification, either centered, left-justified
436 * or right-justified. Also, support inidication of truncation
437 * with a star (*), either on the left or right of the string,
438 * and whether we're justifying a labeled disk quantity.
441 * char *a_srcbuff : Ptr to source char buffer.
442 * char *a_dstbuff : Ptr to dest char buffer.
443 * int a_dstwidth : Width of dest buffer in chars.
444 * int a_justification : Kind of justification.
445 * int a_rightTrunc : If non-zero, place the truncation char
446 * on the right of the string. Otherwise,
447 * place it on the left.
448 * int a_isLabeledDisk : Is this a labeled disk quantity?
455 * All it needs to know is exported by the fsprobe module, namely
456 * the data structure where the probe results are stored.
460 *------------------------------------------------------------------------*/
463 mini_justify(a_srcbuff, a_dstbuff, a_dstwidth, a_justification, a_rightTrunc,
474 static char rn[] = "mini_justify"; /*Routine name */
475 int leftpad_chars; /*# of chars for left-padding */
476 int num_src_chars; /*# of chars in source */
477 int true_num_src_chars; /*# src chars before truncation */
478 int trunc_needed; /*Is truncation needed? */
479 char diskChar; /*Disk name prefix */
482 fprintf(scout_debugfd, "[%s] Called with '%s', dest width=%d\n", rn,
483 a_srcbuff, a_dstwidth);
484 fflush(scout_debugfd);
488 * Remember the disk label, if we've been passed such a thing.
491 diskChar = *a_srcbuff;
494 * If the destination width will overrun the gtx string storage,
495 * we automatically shorten up.
497 if (a_dstwidth > GATOR_LABEL_CHARS) {
499 fprintf(scout_debugfd,
500 "[%s] Dest width (%d) > gtx buflen (%d), shrinking dest width\n",
501 rn, a_dstwidth, GATOR_LABEL_CHARS);
502 fflush(scout_debugfd);
504 a_dstwidth = GATOR_LABEL_CHARS;
508 * If our source string is too long, prepare for truncation.
510 true_num_src_chars = strlen(a_srcbuff);
511 if (true_num_src_chars >= a_dstwidth) {
513 num_src_chars = a_dstwidth - 1;
516 a_srcbuff += (true_num_src_chars - num_src_chars);
519 num_src_chars = true_num_src_chars;
522 * Compute the necessary left-padding.
524 switch (a_justification) {
526 case SCOUT_RIGHT_JUSTIFY:
527 leftpad_chars = (a_dstwidth - 1) - num_src_chars;
530 case SCOUT_LEFT_JUSTIFY:
532 * This is the really easy one.
538 leftpad_chars = ((a_dstwidth - 1) - num_src_chars) / 2;
542 fprintf(stderr, "[%s] Illegal justification command: %d", rn,
545 } /*Switch on justification type */
549 * Clear out the dest buffer, then place the source string at the
550 * appropriate padding location. Remember to place a string
551 * terminator at the end of the dest buffer, plus whatever truncation
552 * may be needed. If we're left-truncating, we've already shifted
553 * the src buffer appropriately.
555 strncpy(a_dstbuff, scout_blankline, a_dstwidth);
556 strncpy(a_dstbuff + leftpad_chars, a_srcbuff, num_src_chars);
557 *(a_dstbuff + a_dstwidth - 1) = '\0';
560 *(a_dstbuff + a_dstwidth - 2) = '*'; /*Truncate on the right */
562 if (a_isLabeledDisk) {
563 *a_dstbuff = diskChar;
564 *(a_dstbuff + 1) = ':';
565 *(a_dstbuff + 2) = '*'; /*Truncate on the left, disk */
567 *a_dstbuff = '*'; /*Truncate on the left, non-disk */
571 /*Handle truncations */
573 * Return the good news.
579 /*------------------------------------------------------------------------
580 * scout_SetNonDiskLightLine
583 * Given a mini-line and a line number, place all non-disk lights
587 * struct mini_line *a_srvline : Ptr to server descriptor.
588 * int a_linenum : Line number to move to.
594 * The light's location is stored not only in the onode, but in
595 * the light's rock, so we have to change both sets of value.
599 *------------------------------------------------------------------------*/
602 scout_SetNonDiskLightLine(a_srvline, a_linenum)
603 struct mini_line *a_srvline;
606 { /*scout_SetNonDiskLightLine */
608 static char rn[] = "scout_SetNonDiskLightLine"; /*Routine name */
609 struct gator_lightobj *nondisk_lightdata; /*Non-disk light data field */
610 struct gwin_strparams *nondisk_strparams; /*Associated string params */
613 * Do the exact same operation for each non-disk light in the record.
615 a_srvline->currConns_lp->o_y = a_linenum;
617 (struct gator_lightobj *)(a_srvline->currConns_lp->o_data);
618 nondisk_strparams = (struct gwin_strparams *)(nondisk_lightdata->llrock);
619 nondisk_strparams->y = a_linenum;
621 a_srvline->fetches_lp->o_y = a_linenum;
623 (struct gator_lightobj *)(a_srvline->fetches_lp->o_data);
624 nondisk_strparams = (struct gwin_strparams *)(nondisk_lightdata->llrock);
625 nondisk_strparams->y = a_linenum;
627 a_srvline->stores_lp->o_y = a_linenum;
629 (struct gator_lightobj *)(a_srvline->stores_lp->o_data);
630 nondisk_strparams = (struct gwin_strparams *)(nondisk_lightdata->llrock);
631 nondisk_strparams->y = a_linenum;
633 a_srvline->workstations_lp->o_y = a_linenum;
635 (struct gator_lightobj *)(a_srvline->workstations_lp->o_data);
636 nondisk_strparams = (struct gwin_strparams *)(nondisk_lightdata->llrock);
637 nondisk_strparams->y = a_linenum;
639 a_srvline->srvName_lp->o_y = a_linenum;
641 (struct gator_lightobj *)(a_srvline->srvName_lp->o_data);
642 nondisk_strparams = (struct gwin_strparams *)(nondisk_lightdata->llrock);
643 nondisk_strparams->y = a_linenum;
645 } /*scout_SetNonDiskLightLine */
647 /*------------------------------------------------------------------------
648 * scout_RecomputeLightLocs
651 * Given a pointer to a server record, recompute its disk light
652 * locations (and keep proper track of the number of screen lines
653 * required for the server record).
656 * struct mini_line *a_srvline : Ptr to server descriptor.
659 * 0 if anything went wrong,
660 * else the number of lines used by this server record.
663 * One or more records have joined or left the used light list
664 * for this server. We're not sure which ones, so we recompute
665 * them all. We may also have had a width change in the gtx
666 * frame. The base_line field in the server record is guaranteed
667 * to be correct at this point.
671 *------------------------------------------------------------------------*/
674 scout_RecomputeLightLocs(a_srvline)
675 struct mini_line *a_srvline;
677 { /*scout_RecomputeLightLocs */
679 static char rn[] = "scout_RecomputeLightLocs"; /*Routine name */
680 int lights_per_line; /*# lights/line */
681 int lights_this_line; /*# lights on cur line */
682 int curr_idx; /*Current disk light idx */
683 struct scout_disk *sc_disk; /*Ptr to disk record array */
684 int lines_for_server; /*Num lines in server record */
685 int curr_line; /*Current line being filled */
686 int curr_x; /*Current x value for light */
687 struct gator_lightobj *disk_lightdata; /*Disk light data field */
688 struct gwin_strparams *disk_strparams; /*String params for disk light */
691 fprintf(scout_debugfd, "[%s] Called\n", rn);
692 fflush(scout_debugfd);
696 * If we haven't yet computed the column for the leftmost disk light,
699 if (scout_DiskLightLeftCol == 0)
700 scout_DiskLightLeftCol =
701 LIGHTOBJ_CONN_WIDTH + LIGHTOBJ_FETCH_WIDTH +
702 LIGHTOBJ_STORE_WIDTH + LIGHTOBJ_WK_WIDTH +
703 LIGHTOBJ_SRVNAME_WIDTH + 5;
706 * Calculate how many disk light objects can fit in one line.
709 (scout_frameDims.maxx -
710 scout_DiskLightLeftCol) / (LIGHTOBJ_DISK_WIDTH + 1);
712 fprintf(scout_debugfd, "[%s] %d lights per line\n", rn,
714 fflush(scout_debugfd);
718 * Sweep through the used disk light list, computing the location
721 lights_this_line = 0;
722 curr_idx = a_srvline->used_head;
723 lines_for_server = 1;
724 curr_line = a_srvline->base_line;
725 curr_x = scout_DiskLightLeftCol;
727 while (curr_idx != SCOUT_NIL) {
729 * Bump the number of lines for the server if we've already
730 * filled up the current line.
732 if (lights_this_line >= lights_per_line) {
733 lights_this_line = 0;
736 curr_x = scout_DiskLightLeftCol;
739 /*Current line filled up */
741 * Set the current disk light's location.
743 sc_disk = a_srvline->disks;
744 sc_disk[curr_idx].disk_lp->o_x = curr_x;
745 sc_disk[curr_idx].disk_lp->o_y = curr_line;
747 (struct gator_lightobj *)(sc_disk[curr_idx].disk_lp->o_data);
748 disk_strparams = (struct gwin_strparams *)(disk_lightdata->llrock);
749 disk_strparams->x = curr_x;
750 disk_strparams->y = curr_line;
752 fprintf(scout_debugfd,
753 "[%s] Disk light at index %d located at [%d, %d]\n", rn,
754 curr_idx, curr_x, curr_line);
755 fflush(scout_debugfd);
759 * Record the inclusion of the light and move on to the next
763 curr_x += LIGHTOBJ_DISK_WIDTH + 1;
764 curr_idx = sc_disk[curr_idx].next;
766 } /*Update each used disk light */
769 * Remember to record the (possibly new) number of lines in the
770 * server record before returning the value of that field.
772 if (a_srvline->num_lines != lines_for_server) {
774 fprintf(scout_debugfd,
775 "[%s] Server previously had %d screen lines; now changed\n",
776 rn, a_srvline->num_lines);
777 fflush(scout_debugfd);
779 a_srvline->num_lines = lines_for_server;
783 fprintf(scout_debugfd, "[%s] Server has %d screen lines\n", rn,
784 a_srvline->num_lines);
785 fflush(scout_debugfd);
787 return (a_srvline->num_lines);
789 } /*scout_RecomputeLightLocs */
791 /*------------------------------------------------------------------------
795 * Given a single-letter disk name and a pointer to the current server
796 * record, look for a used disk record with that name within the server.
797 * If we can't find one, we create and incorporate one, and return that
798 * fact to our caller.
801 * char a_diskname : Single-char disk name.
802 * struct mini_line *a_srvline : Ptr to server descriptor.
803 * int *a_record_added : Was a new record added?
806 * Index of matching used disk record,
807 * SCOUT_NIL otherwise.
809 * Return via parameter:
810 * a_record_added set to 1 iff record was added to the used disk list.
813 * Used disk records are kept in alphabetical order by the single-char
814 * disk name. Should a matching used disk record not be found, one is
815 * pulled from the free pool.
818 * An entry may be pulled off the free list and inserted into the
819 * used list. This entry is placed in the update list for the
820 * current gtx frame (at least not by this routine).
821 *------------------------------------------------------------------------*/
824 scout_FindUsedDisk(a_diskname, a_srvline, a_record_added)
826 struct mini_line *a_srvline;
829 { /*scout_FindUsedDisk */
831 static char rn[] = "scout_FindUsedDisk"; /*Routine name */
832 int curr_idx; /*Disk record index */
833 int append_idx; /*Index to append after */
834 int new_idx; /*Index of new used record */
835 struct scout_disk *sc_disk; /*Ptr to disk record */
836 int code; /*Function return value */
839 fprintf(scout_debugfd, "[%s] Called\n", rn);
840 fflush(scout_debugfd);
844 * Sweep through the used disk records, looking for a match.
846 curr_idx = a_srvline->used_head;
847 append_idx = SCOUT_NIL;
848 sc_disk = a_srvline->disks;
850 fprintf(scout_debugfd,
851 "[%s] Scanning existing used disk entries for disk '%s'\n",
853 fflush(scout_debugfd);
855 while (curr_idx != SCOUT_NIL) {
857 fprintf(scout_debugfd, "[%s] Disk %d is named '%s'\n", rn,
858 curr_idx, sc_disk[curr_idx].name);
859 fflush(scout_debugfd);
861 if (strcmp(sc_disk[curr_idx].name, a_diskname) == 0) {
863 * We found it! Bug out.
866 fprintf(scout_debugfd, "[%s] Match found\n", rn);
867 fflush(scout_debugfd);
873 * If we are alphabetically past the given disk name, we
874 * know that we won't find it in the used disk list; we
875 * also have the append index set correctly.
877 if (strcmp(a_diskname, sc_disk[curr_idx].name) < 0) {
879 fprintf(scout_debugfd, "[%s] Disk '%s' can't be here\n", rn,
881 fflush(scout_debugfd);
887 * There's still hope we'll find it. Move on to the next used
888 * disk record, keeping this index as the best candidate so far
889 * for appending a missing entry.
891 append_idx = curr_idx;
892 curr_idx = sc_disk[curr_idx].next;
893 } /*Look for match */
896 * We didn't find the record we wanted, which means we'll pull a
897 * record out of the free pool for it. If we didn't find a place
898 * to append it, we then insert it at the beginning of the queue.
900 if (a_srvline->free_head == SCOUT_NIL)
903 new_idx = a_srvline->free_head;
905 fprintf(scout_debugfd, "[%s] Choosing free index %d for new entry\n",
907 fflush(scout_debugfd);
909 a_srvline->free_head = sc_disk[new_idx].next;
910 if (a_srvline->free_head == SCOUT_NIL)
911 a_srvline->free_tail = SCOUT_NIL;
914 * Fill in the new record.
916 sc_disk[new_idx].active = 0;
917 sc_disk[new_idx].name = a_diskname;
920 * Insert the new record where it belongs on the used disk list.
922 if (append_idx == SCOUT_NIL) {
924 * It belongs at the beginning of the list.
927 fprintf(scout_debugfd, "[%s] Inserted at used disk head\n", rn);
928 fflush(scout_debugfd);
930 sc_disk[new_idx].next = a_srvline->used_head;
931 sc_disk[new_idx].prev = SCOUT_NIL;
932 a_srvline->used_head = new_idx;
933 if (a_srvline->used_tail == SCOUT_NIL)
934 a_srvline->used_tail = new_idx;
937 fprintf(scout_debugfd, "[%s] Entry appended after index %d\n", rn,
939 fflush(scout_debugfd);
941 sc_disk[new_idx].prev = append_idx;
942 sc_disk[new_idx].next = sc_disk[append_idx].next;
943 sc_disk[append_idx].next = new_idx;
944 if (sc_disk[new_idx].next == SCOUT_NIL)
945 a_srvline->used_tail = new_idx;
947 sc_disk[sc_disk[new_idx].next].prev = new_idx;
951 * Add the new used disk light object to the display list for
955 fprintf(scout_debugfd,
956 "[%s] Adding disk light at index %d to display list\n", rn,
958 fflush(scout_debugfd);
960 code = gtxframe_AddToList(scout_frame, sc_disk[new_idx].disk_lp);
963 fprintf(scout_debugfd,
964 "[%s] Can't add to display list, code is %d\n", rn, code);
965 fflush(scout_debugfd);
970 } /*scout_FindUsedDisk */
972 /*------------------------------------------------------------------------
973 * scout_RemoveInactiveDisk
976 * Given a server record and a used disk index, remove the disk
977 * record from the used list, put it on the free list, and remove
978 * it from the gtx frame update list.
981 * struct mini_line *a_srvline : Ptr to server descriptor.
982 * int a_used_idx : Index of used disk record.
988 * Formerly-used disk records are returned to the free pool.
991 * Free and used disk record lists are modified for this server.
992 * The disk record in question is pulled off the gtx update list
994 *------------------------------------------------------------------------*/
997 scout_RemoveInactiveDisk(a_srvline, a_used_idx)
998 struct mini_line *a_srvline;
1001 { /*scout_RemoveInactiveDisk */
1003 static char rn[] = "scout_RemoveInactiveDisk"; /*Routine name */
1006 fprintf(scout_debugfd, "[%s] Called\n", rn);
1007 fflush(scout_debugfd);
1010 /*code = gtxframe_RemoveFromList(scout_frame->window, lightobj); */
1012 } /*scout_RemoveInactiveDisk */
1014 /*------------------------------------------------------------------------
1015 * mini_PrintDiskStats
1018 * Given server indexing and light object information, a pointer
1019 * to a set of statistics, and whether the probe that produced these
1020 * stats succeeded or not, print out the stats in a nice way.
1023 * struct mini_line *a_srvline : Ptr to server descriptor.
1024 * struct ProbeViceStatistics *a_stats : Ptr to current stats.
1025 * int a_probeOK : Was the probe OK?
1026 * int a_width_changed : Has the frame width changed?
1027 * int a_fix_line_num : Is the line number wrong?
1028 * int a_delta_line_num : Change in line number.
1031 * 0 if something went wrong,
1032 * else the number of lines taken up by this server record.
1035 * Nothing interesting.
1039 *------------------------------------------------------------------------*/
1042 mini_PrintDiskStats(a_srvline, a_stats, a_probeOK, a_width_changed,
1043 a_fix_line_num, a_delta_line_num)
1044 struct mini_line *a_srvline;
1045 struct ProbeViceStatistics *a_stats;
1048 int a_delta_line_num;
1050 { /*mini_PrintDiskStats */
1052 static char rn[] = "mini_PrintDiskStats"; /*Routine name */
1053 int code; /*Return code */
1054 char s[128]; /*String buffer */
1055 struct onode *curr_disklight; /*Ptr to current disk light */
1056 struct onode *srvname_light; /*Ptr to server name light */
1057 ViceDisk *curr_diskstat; /*Ptr to current disk stat */
1058 int curr_disk; /*Current disk stat number */
1059 int used_disk_idx; /*Used disk index */
1060 int next_used_idx; /*Ditto */
1061 int pastthreshold; /*Was disk past threshold? */
1062 struct gator_lightobj *diskdata; /*Private light data */
1063 struct gwin_strparams *disk_strparams; /*String params for disk light */
1064 char *diskname = 0; /*Name of disk */
1065 int found_idx; /*Idx of matching disk */
1066 char *srv_name; /*Server name */
1067 struct scout_disk *sc_disk; /*Ptr to scout disk desc */
1068 int fix_light_locs; /*Recompute disk light locs? */
1071 fprintf(scout_debugfd, "[%s] Called\n", rn);
1072 fflush(scout_debugfd);
1076 * Remember the current server's print name, don't recompute light
1079 srvname_light = a_srvline->srvName_lp;
1080 srv_name = ((struct gator_lightobj *)(srvname_light->o_data))->label;
1083 fprintf(scout_debugfd, "[%s] Value of a_delta_line_num is %d\n", rn,
1085 fflush(scout_debugfd);
1089 * If the probe failed, we simply blank out all the used disk
1090 * objects. Note: a NON-ZERO value of a_probeOK implies failure.
1093 used_disk_idx = a_srvline->used_head;
1094 while (used_disk_idx != SCOUT_NIL) {
1096 * Point to the current used disk's light, blank out its
1097 * contents, and make sure highlighting is turned off. We
1098 * also take this opportunity to fix the line numbers if
1101 curr_disklight = a_srvline->disks[used_disk_idx].disk_lp;
1102 diskdata = (struct gator_lightobj *)(curr_disklight->o_data);
1104 fprintf(scout_debugfd,
1105 "[%s] Prev value of disk light %d: '%s'\n", rn,
1106 used_disk_idx, diskdata->label);
1107 fflush(scout_debugfd);
1109 code = mini_justify(" ", /*Src buffer */
1110 diskdata->label, /*Dest buffer */
1111 LIGHTOBJ_DISK_WIDTH, /*Dest's width */
1112 SCOUT_RIGHT_JUSTIFY, /*Right-justify */
1113 SCOUT_LEFT_TRUNC, /*Left-truncate */
1114 SCOUT_ISNT_LDISK); /*Not a labeled disk */
1115 code = gator_light_set(curr_disklight, 0);
1116 if (a_fix_line_num) {
1117 curr_disklight->o_y += a_delta_line_num;
1118 disk_strparams = (struct gwin_strparams *)(diskdata->llrock);
1119 disk_strparams->y += a_delta_line_num;
1123 * Advance to next used disk, if any.
1125 used_disk_idx = a_srvline->disks[used_disk_idx].next;
1127 } /*Blank out disk name field */
1130 * If the frame width has changed, we have to recompute all disk
1131 * light locations. After that, the number of lines in the server
1132 * record will be accurate, and we return them.
1134 if (a_width_changed)
1135 scout_RecomputeLightLocs(a_srvline);
1137 return (a_srvline->num_lines);
1141 /*Probe failed for the server */
1143 * Probe was successful. Sweep through the statistics records,
1144 * and put up all values having to do with AFS partitions. First,
1145 * mark all used disk objects for this server as inactive and fix
1146 * their line numbers if needed.
1148 sc_disk = a_srvline->disks;
1149 used_disk_idx = a_srvline->used_head;
1150 while (used_disk_idx != SCOUT_NIL) {
1152 fprintf(scout_debugfd, "[%s] Marking used disk %d inactive\n", rn,
1154 fflush(scout_debugfd);
1156 sc_disk = (a_srvline->disks) + used_disk_idx;
1157 sc_disk->active = 0;
1158 used_disk_idx = sc_disk->next;
1159 if (a_fix_line_num) {
1160 sc_disk->disk_lp->o_y += a_delta_line_num;
1161 diskdata = (struct gator_lightobj *)(sc_disk->disk_lp->o_data);
1162 disk_strparams = (struct gwin_strparams *)(diskdata->llrock);
1163 disk_strparams->y += a_delta_line_num;
1165 } /*Mark used disks inactive */
1167 curr_diskstat = (ViceDisk *) a_stats->Disk;
1168 for (curr_disk = 0; curr_disk < VOLMAXPARTS; curr_disk++) {
1170 * An AFS partition name must be prefixed by `/vicep`.
1173 fprintf(scout_debugfd, "[%s] Disk stats at 0x%x for disk '%s'\n",
1174 rn, curr_diskstat, curr_diskstat->Name);
1175 fflush(scout_debugfd);
1177 if (strncmp("/vice", curr_diskstat->Name, 5) == 0) {
1179 * Pull out the single-letter name (actually, abbreviation)
1180 * of the disk and look for such an entry in the used disks.
1182 diskname = &curr_diskstat->Name[6];
1183 found_idx = scout_FindUsedDisk(diskname, /*1-char name */
1184 a_srvline, /*Server record */
1185 &fix_light_locs); /*Recompute? */
1186 if (found_idx == SCOUT_NIL) {
1188 "[%s] Can't display /vicep%s on server '%s'\n", rn,
1189 diskname, srv_name);
1192 * Found (or created) record for this disk. Fill in the single-
1193 * letter name of the disk followed by the number of free blocks.
1194 * Turn the disk light on if the number of free blocks exceeds
1195 * the threshold the user set, either % used or min free blocks.
1197 sprintf(s, "%s:%d", diskname, curr_diskstat->BlocksAvailable);
1198 if (scout_attn_disk_mode == SCOUT_DISKM_PCUSED) {
1200 (curr_diskstat->TotalBlocks -
1201 curr_diskstat->BlocksAvailable) /
1202 (float)(curr_diskstat->TotalBlocks) >
1203 scout_attn_disk_pcused)
1209 (curr_diskstat->BlocksAvailable <
1210 scout_attn_disk_minfree) ? 1 : 0;
1211 sc_disk = (a_srvline->disks) + found_idx;
1212 sc_disk->active = 1;
1214 (struct gator_lightobj *)(sc_disk->disk_lp->o_data);
1216 fprintf(scout_debugfd,
1217 "[%s] Justifying %s for disk idx %d (prev value: '%s')\n",
1218 rn, s, found_idx, diskdata->label);
1219 fflush(scout_debugfd);
1221 code = mini_justify(s, /*Src buffer */
1222 diskdata->label, /*Dest buffer */
1223 LIGHTOBJ_DISK_WIDTH, /*Dest's width */
1224 SCOUT_LEFT_JUSTIFY, /*Left-justify */
1225 SCOUT_LEFT_TRUNC, /*Left-truncate */
1226 SCOUT_IS_LDISK); /*Labeled disk */
1228 code = gator_light_set(sc_disk->disk_lp, pastthreshold);
1230 } /*Found disk record */
1233 /*Found AFS disk name */
1235 * Advance to the next disk statistics record.
1238 } /*For each statistics record */
1241 * We've now pulled out all the disk statistics from the probe.
1242 * See if any used disks that were there from the last time are
1243 * now gone. If so, we remove them.
1246 fprintf(scout_debugfd,
1247 "[%s] Scanning used disk records for inactive entries\n", rn);
1248 fflush(scout_debugfd);
1250 used_disk_idx = a_srvline->used_head;
1251 while (used_disk_idx != SCOUT_NIL) {
1253 fprintf(scout_debugfd, "[%s] Examining entry at index %d\n", rn,
1255 fflush(scout_debugfd);
1257 sc_disk = (a_srvline->disks) + used_disk_idx;
1258 next_used_idx = sc_disk->next;
1259 if (!(sc_disk->active)) {
1260 scout_RemoveInactiveDisk(a_srvline, /*Server record */
1261 used_disk_idx); /*Disk index to nuke */
1264 used_disk_idx = next_used_idx;
1266 } /*Remove inactive used disks */
1269 * If we've had to add or remove disks to/from the used list,
1270 * or if the frame width has changed, we recompute the light
1271 * locations before returning.
1273 if (fix_light_locs || a_width_changed)
1274 scout_RecomputeLightLocs(a_srvline);
1277 * Return the (possibly new) size of the current server record.
1279 return (a_srvline->num_lines);
1281 } /*mini_PrintDiskStats */
1283 /*------------------------------------------------------------------------
1287 * Handler routine passed to the fsprobe module. This handler is
1288 * called immediately after a poll of all the FileServers has taken
1289 * place. Its job is to write out selected data to the scout
1300 * All it needs to know is exported by the fsprobe module, namely
1301 * the data structure where the probe results are stored.
1304 * Recomputes disk light locations in response to reshaping the
1305 * scout window or from adding/deleting disk lights to/from
1306 * individual servers.
1307 *------------------------------------------------------------------------*/
1313 static char rn[] = "FS_Handler"; /*Routine name */
1314 int code; /*Return code */
1315 struct ProbeViceStatistics *curr_stats; /*Ptr to current stats */
1316 int *curr_probeOK; /*Ptr to current probeOK field */
1317 int curr_srvidx; /*Current server index */
1318 char s[128]; /*String buffer */
1319 static char sblank[] = " "; /*Blank string buffer */
1320 char *sp; /*Ptr to string buffer */
1321 struct mini_line *curr_line; /*Current mini-line */
1322 int curr_line_num; /*Current line number */
1323 struct gator_lightobj *lightdata; /*Private light data */
1324 int setting; /*Light setting (on or off) */
1325 int old_width; /*Keep the old width value */
1326 int width_changed; /*Has the frame width changed? */
1327 int fix_line_num; /*Line number needs fixing */
1328 int delta_line_num; /*Change in line number */
1331 * See if the size of the scout frame has changed since the last
1334 old_width = scout_frameDims.maxx;
1336 fprintf(scout_debugfd, "[%s] Calling wop_getdimensions\n", rn);
1337 fflush(scout_debugfd);
1339 WOP_GETDIMENSIONS(scout_frame->window, &scout_frameDims);
1340 width_changed = (old_width == scout_frameDims.maxx) ? 0 : 1;
1342 fprintf(scout_debugfd,
1343 "[%s] Frame dimensions are %d rows, %d columns\n", rn,
1344 scout_frameDims.maxy, scout_frameDims.maxx);
1346 fprintf(scout_debugfd, "[%s] Width has changed from %d columns\n",
1348 fflush(scout_debugfd);
1352 * Print out the selected fields for each server. We actually change
1353 * the light's label to the new data.
1355 curr_line = scout_screen.line;
1356 curr_stats = fsprobe_Results.stats;
1357 curr_probeOK = fsprobe_Results.probeOK;
1358 curr_line_num = curr_line->base_line;
1361 for (curr_srvidx = 0; curr_srvidx < scout_screen.numServers;
1364 * If the current server record is set up on the wrong line, fix
1365 * the non-disk light objects directly, and remember to fix the
1366 * disk light objects later on.
1368 if (curr_line->base_line != curr_line_num) {
1370 delta_line_num = curr_line_num - curr_line->base_line;
1371 curr_line->base_line = curr_line_num;
1372 scout_SetNonDiskLightLine(curr_line, curr_line_num);
1379 (struct gator_lightobj *)(curr_line->currConns_lp->o_data);
1380 if (*curr_probeOK == 0) {
1382 sprintf(sp, "%d", curr_stats->CurrentConnections);
1385 code = mini_justify(sp, /*Src buffer */
1386 lightdata->label, /*Dest buffer */
1387 LIGHTOBJ_CONN_WIDTH, /*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_conn != SCOUT_ATTN_NOTUSED
1392 && curr_stats->CurrentConnections >= scout_attn_conn)
1396 code = gator_light_set(curr_line->currConns_lp, setting);
1398 lightdata = (struct gator_lightobj *)(curr_line->fetches_lp->o_data);
1399 if (*curr_probeOK == 0) {
1401 sprintf(sp, "%d", curr_stats->TotalFetchs);
1404 code = mini_justify(sp, /*Src buffer */
1405 lightdata->label, /*Dest buffer */
1406 LIGHTOBJ_FETCH_WIDTH, /*Dest's width */
1407 SCOUT_RIGHT_JUSTIFY, /*Right-justify */
1408 SCOUT_LEFT_TRUNC, /*Left-truncate */
1409 SCOUT_ISNT_LDISK); /*Not a labeled disk */
1410 if (scout_attn_fetch != SCOUT_ATTN_NOTUSED
1411 && curr_stats->TotalFetchs >= scout_attn_fetch)
1415 code = gator_light_set(curr_line->fetches_lp, setting);
1417 lightdata = (struct gator_lightobj *)(curr_line->stores_lp->o_data);
1418 if (*curr_probeOK == 0) {
1420 sprintf(sp, "%d", curr_stats->TotalStores);
1423 code = mini_justify(sp, /*Src buffer */
1424 lightdata->label, /*Dest buffer */
1425 LIGHTOBJ_STORE_WIDTH, /*Dest's width */
1426 SCOUT_RIGHT_JUSTIFY, /*Right-justify */
1427 SCOUT_LEFT_TRUNC, /*Left-truncate */
1428 SCOUT_ISNT_LDISK); /*Not a labeled disk */
1429 if (scout_attn_store != SCOUT_ATTN_NOTUSED
1430 && curr_stats->TotalStores >= scout_attn_store)
1434 code = gator_light_set(curr_line->stores_lp, setting);
1437 (struct gator_lightobj *)(curr_line->workstations_lp->o_data);
1438 if (*curr_probeOK == 0) {
1440 sprintf(sp, "%d", curr_stats->WorkStations);
1443 code = mini_justify(sp, /*Src buffer */
1444 lightdata->label, /*Dest buffer */
1445 LIGHTOBJ_WK_WIDTH, /*Dest's width */
1446 SCOUT_RIGHT_JUSTIFY, /*Right-justify */
1447 SCOUT_LEFT_TRUNC, /*Left-truncate */
1448 SCOUT_ISNT_LDISK); /*Not a labeled disk */
1449 if (scout_attn_workstations != SCOUT_ATTN_NOTUSED
1450 && curr_stats->WorkStations >= scout_attn_workstations)
1454 code = gator_light_set(curr_line->workstations_lp, setting);
1457 * We turn the server light on if there was an error in the
1458 * current probe (e.g., if the curr_probeOK field is non-zero.
1459 * (Don't forget to fix the light's line if it needs it).
1461 setting = (*curr_probeOK) ? 1 : 0;
1462 code = gator_light_set(curr_line->srvName_lp, setting);
1465 * Print out the disk statistics. The value returned is the
1466 * number of lines taken up by the server record (or 0 if
1467 * something went wrong).
1469 code = mini_PrintDiskStats(curr_line, /*Ptr to server line */
1470 curr_stats, /*Fresh disk stats */
1471 *curr_probeOK, /*Was probe OK? */
1472 width_changed, /*Has the width changed? */
1473 fix_line_num, /*Fix the line number? */
1474 delta_line_num); /*Change in line number */
1476 fprintf(stderr, "[%s] Error in printing out disk statistics\n",
1480 curr_line_num += code;
1483 * Advance the current mini_line, stats source, and probe success
1490 } /*for each server probed */
1493 * Display the scout frame.
1495 sprintf(s, "Probe %d results", fsprobe_Results.probeNum);
1496 gtxframe_DisplayString(scout_frame, s);
1497 WOP_DISPLAY(scout_gwin);
1500 * Return the happy news.
1506 /*------------------------------------------------------------------------
1510 * Initialize each line in the mini_screen.
1513 * struct sockaddr_in *a_skt : Ptr to server socket info.
1514 * int a_lineNum; : Line number being created.
1515 * struct mini_line *a_line : Ptr to mini_line to set up.
1516 * char *a_srvname : Printable server name.
1520 * Error value otherwise.
1523 * Nothing interesting.
1527 *------------------------------------------------------------------------*/
1530 init_mini_line(a_skt, a_lineNum, a_line, a_srvname)
1531 struct sockaddr_in *a_skt;
1533 struct mini_line *a_line;
1536 { /*init_mini_line */
1538 static char rn[] = "init_mini_line"; /*Routine name */
1539 int curr_x; /*Current X position */
1540 int curr_y; /*Current Y position */
1541 char s[128]; /*Scratch buffer */
1542 int code; /*Return code */
1543 struct gator_lightobj *lightdata; /*Private light data */
1546 fprintf(scout_debugfd, "[%s] Called for base line %d\n", rn,
1548 fflush(scout_debugfd);
1552 * Fill in the top fields (except the disk fields, which will be
1553 * done elsewhere), then create the light onodes.
1555 memcpy((char *)&(a_line->skt), (char *)a_skt, sizeof(struct sockaddr_in));
1556 a_line->numDisks = 0;
1557 a_line->base_line = a_lineNum + scout_screen.base_line_num;
1558 a_line->num_lines = 1;
1561 curr_y = a_line->base_line;
1562 if ((a_line->currConns_lp =
1563 mini_initLightObject("Conns", curr_x, curr_y, LIGHTOBJ_CONN_WIDTH,
1566 fprintf(stderr, "[%s:%s] Can't create currConns light object\n", pn,
1570 curr_x += LIGHTOBJ_CONN_WIDTH + 1;
1572 if ((a_line->fetches_lp =
1573 mini_initLightObject("Fetches", curr_x, curr_y, LIGHTOBJ_FETCH_WIDTH,
1574 scout_frame->window))
1576 fprintf(stderr, "[%s:%s] Can't create fetches light object\n", pn,
1580 curr_x += LIGHTOBJ_FETCH_WIDTH + 1;
1582 if ((a_line->stores_lp =
1583 mini_initLightObject("Stores", curr_x, curr_y, LIGHTOBJ_STORE_WIDTH,
1584 scout_frame->window))
1586 fprintf(stderr, "[%s:%s] Can't create stores light object\n", pn, rn);
1589 curr_x += LIGHTOBJ_STORE_WIDTH + 1;
1591 if ((a_line->workstations_lp =
1592 mini_initLightObject("WrkStn", curr_x, curr_y, LIGHTOBJ_WK_WIDTH,
1593 scout_frame->window))
1595 fprintf(stderr, "[%s:%s] Can't create workstations light object\n",
1599 curr_x += LIGHTOBJ_WK_WIDTH + 1;
1601 if ((a_line->srvName_lp =
1602 mini_initLightObject(a_srvname, curr_x, curr_y,
1603 LIGHTOBJ_SRVNAME_WIDTH, scout_frame->window))
1605 fprintf(stderr, "[%s:%s] Can't create server name light object\n", pn,
1609 sprintf(s, "%s", a_srvname);
1610 lightdata = (struct gator_lightobj *)(a_line->srvName_lp->o_data);
1611 code = mini_justify(s, /*Src buffer */
1612 lightdata->label, /*Dest buffer */
1613 LIGHTOBJ_SRVNAME_WIDTH, /*Dest's width */
1614 SCOUT_CENTER, /*Centered */
1615 SCOUT_RIGHT_TRUNC, /*Right-truncate */
1616 SCOUT_ISNT_LDISK); /*Not a labeled disk */
1619 "[%s] Can't center server name inside of light object\n", rn);
1622 curr_x += LIGHTOBJ_SRVNAME_WIDTH + 1;
1624 if (scout_initDiskLightObjects(a_line, scout_frame->window)) {
1625 fprintf(stderr, "[%s:%s] Can't create disk light objects\n", pn, rn);
1630 * Finally, return the happy news.
1634 } /*init_mini_line */
1636 /*------------------------------------------------------------------------
1640 * Workhorse routine that starts up the FileServer probe.
1643 * int a_numservers : Length of above list.
1644 * struct cmd_item *a_srvname : List of FileServer machines to
1646 * int a_pkg : Window package to use.
1650 * Error value otherwise.
1653 * Nothing interesting.
1657 *------------------------------------------------------------------------*/
1660 execute_scout(a_numservers, a_srvname, a_pkg)
1662 struct cmd_item *a_srvname;
1665 { /*execute_scout */
1667 static char rn[] = "execute_scout"; /*Routine name */
1668 static char fullsrvname[128]; /*Full server name */
1669 register int code; /*Return code */
1670 struct sockaddr_in *FSSktArray; /*Server socket array */
1671 int sktbytes; /*Num bytes in above */
1672 struct sockaddr_in *curr_skt; /*Ptr to current socket */
1673 struct cmd_item *curr_item; /*Ptr to current cmd item */
1674 struct hostent *he; /*Host entry */
1675 struct mini_line *mini_lines; /*Ptr to all mini-lines */
1676 struct mini_line *curr_line; /*Ptr to current line */
1677 int i; /*Generic loop variable */
1678 int mini_line_bytes; /*Num bytes in mini_lines */
1679 struct timeval tv; /*Time structure */
1680 int linenum; /*Current mini-line number */
1682 PROCESS pid; /*Main LWP process ID */
1683 PROCESS gxlistener_ID; /*Input Server LWP process ID */
1685 struct gator_lightobj *lightdata; /*Private light data */
1688 fprintf(scout_debugfd, "[%s] Called\n", rn);
1689 fflush(scout_debugfd);
1693 * We have to initialize LWP support before we start up any of
1697 code = LWP_InitializeProcessSupport(LWP_NORMAL_PRIORITY, &pid);
1699 fprintf(stderr, "[%s:%s] Can't initialize LWP\n", pn, rn);
1700 scout_CleanExit(code);
1705 * Initialize the gtx package.
1708 fprintf(stderr, "[%s:%s] Starting up gtx package\n", pn, rn);
1710 scout_gwin = gtx_Init(0, /*Don't start up InputServer yet */
1711 -1); /*Type of window package */
1712 if (scout_gwin == NULL) {
1713 fprintf(stderr, "[%s:%s] Call to gtx_Init() failed!\n", pn, rn);
1718 * Remember we've set up gtx so we can exit cleanly from now on.
1720 scout_gtx_initialized = 1;
1723 * Create the frame everything will go into, set it up as our only
1724 * frame for this window.
1726 scout_frame = gtxframe_Create();
1727 if (scout_frame == (struct gtx_frame *)0) {
1728 fprintf(stderr, "[%s:%s] Call to gtxframe_Create() failed!\n", pn,
1732 gtxframe_SetFrame(scout_gwin, scout_frame);
1733 WOP_GETDIMENSIONS(scout_frame->window, &scout_frameDims);
1736 * Allocate an array of sockets to describe each FileServer we'll be
1739 sktbytes = a_numservers * sizeof(struct sockaddr_in);
1740 FSSktArray = (struct sockaddr_in *)malloc(sktbytes);
1741 if (FSSktArray == (struct sockaddr_in *)0) {
1743 "[%s] Can't malloc() %d sockaddrs (%d bytes) for the given servers\n",
1744 rn, a_numservers, sktbytes);
1745 scout_CleanExit(-1);
1747 memset(FSSktArray, 0, sktbytes);
1750 * Sweep through the server names provided, filling in the socket
1751 * info for each. Take into account the fact that we may have a
1752 * base name associated for each.
1754 curr_item = a_srvname;
1755 curr_skt = FSSktArray;
1757 if (*scout_basename == '\0')
1758 sprintf(fullsrvname, "%s", curr_item->data);
1760 sprintf(fullsrvname, "%s.%s", curr_item->data, scout_basename);
1761 he = hostutil_GetHostByName(fullsrvname);
1763 fprintf(stderr, "[%s] Can't get host info for '%s'\n", rn,
1767 memcpy(&(curr_skt->sin_addr.s_addr), he->h_addr, 4);
1768 #if defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
1769 curr_skt->sin_family = AF_INET; /*Internet family */
1771 curr_skt->sin_family = htons(AF_INET); /*Internet family */
1773 curr_skt->sin_port = htons(7000); /*FileServer port */
1776 * Bump our pointers.
1778 curr_item = curr_item->next;
1781 } /*Build socket entry for each server */
1784 * Create the set of mini-lines, one per server.
1786 mini_line_bytes = a_numservers * sizeof(struct mini_line);
1787 mini_lines = (struct mini_line *)malloc(mini_line_bytes);
1788 if (mini_lines == (struct mini_line *)0) {
1789 fprintf(stderr, "[%s] Can't malloc() %d bytes for %d screen lines\n",
1790 rn, mini_line_bytes, a_numservers);
1793 memset(mini_lines, 0, mini_line_bytes);
1796 * Set up each line in the mini_lines, creating and initializing
1797 * its light objects.
1799 scout_screen.base_line_num = 4;
1800 curr_line = mini_lines;
1801 curr_skt = FSSktArray;
1803 curr_item = a_srvname;
1804 gtxframe_ClearList(scout_frame);
1807 * Create the light objects that server as banner lines. Remember
1808 * to take into account the server basename, if any, and the name
1809 * of the host that scout if running on, if that's wanted.
1811 if (scout_showhostname) {
1812 if (*scout_basename == '\0')
1813 sprintf(scout_Banner, "[%s] %s", scout_hostname, "Scout");
1815 sprintf(scout_Banner, "[%s] Scout for %s", scout_hostname,
1818 if (*scout_basename == '\0')
1819 sprintf(scout_Banner, "%s", " Scout");
1821 sprintf(scout_Banner, " Scout for %s", scout_basename);
1823 scout_banner0_lp = mini_initLightObject("Banner 0", /*Light name */
1824 0, /*X*/ 0, /*Y*/ scout_frameDims.maxx, /*Width */
1825 scout_gwin); /*Window */
1826 if (scout_banner0_lp != NULL) {
1827 lightdata = (struct gator_lightobj *)(scout_banner0_lp->o_data);
1829 mini_justify(scout_Banner, lightdata->label, scout_frameDims.maxx,
1830 SCOUT_CENTER, SCOUT_RIGHT_TRUNC, SCOUT_ISNT_LDISK);
1831 code = gator_light_set(scout_banner0_lp, 1);
1832 code = gtxframe_AddToList(scout_frame, scout_banner0_lp);
1836 fprintf(scout_debugfd, "[%s] Scout label is '%s', %d chars\n", rn,
1837 lightdata->label, strlen(lightdata->label));
1840 scout_banner1_lp = mini_initLightObject("Banner 1", /*Light name */
1841 0, /*X*/ 2, /*Y*/ scout_frameDims.maxx, /*Width */
1842 scout_gwin); /*Window */
1843 if (scout_banner1_lp != NULL) {
1844 if (scout_attn_disk_mode == SCOUT_DISKM_PCUSED) {
1845 sprintf(scout_Banner, "%s > %s%% used", scout_LightLabels,
1846 scout_attn_disk_pcusedstr);
1848 sprintf(scout_Banner, "%s < %d blocks free", scout_LightLabels,
1849 scout_attn_disk_minfree);
1851 lightdata = (struct gator_lightobj *)(scout_banner1_lp->o_data);
1853 mini_justify(scout_Banner, lightdata->label, scout_frameDims.maxx,
1854 SCOUT_LEFT_JUSTIFY, SCOUT_RIGHT_TRUNC,
1857 code = gtxframe_AddToList(scout_frame, scout_banner1_lp);
1860 scout_banner2_lp = mini_initLightObject("Banner 2", /*Light name */
1861 0, /*X*/ 3, /*Y*/ scout_frameDims.maxx, /*Width */
1862 scout_gwin); /*Window */
1863 if (scout_banner2_lp != NULL) {
1864 lightdata = (struct gator_lightobj *)(scout_banner2_lp->o_data);
1866 mini_justify(scout_LightLabelUnd, lightdata->label,
1867 scout_frameDims.maxx, SCOUT_LEFT_JUSTIFY,
1868 SCOUT_RIGHT_TRUNC, SCOUT_ISNT_LDISK);
1869 code = gtxframe_AddToList(scout_frame, scout_banner2_lp);
1872 for (i = 0; i < a_numservers; i++) {
1873 code = init_mini_line(curr_skt, linenum, curr_line, curr_item->data);
1875 fprintf(stderr, "[%s] Can't initialize line for server %d\n", rn,
1882 curr_item = curr_item->next;
1886 * Now that all lines have been set up, we feed in the light items
1887 * created. Note: the disk lights are entered at a later time,
1888 * as they enter the used disk list for each server.
1890 curr_line = mini_lines;
1891 for (i = 0; i < a_numservers; i++) {
1892 code = gtxframe_AddToList(scout_frame, curr_line->currConns_lp);
1895 "[%s] Can't add client connections light to display list\n",
1900 code = gtxframe_AddToList(scout_frame, curr_line->fetches_lp);
1903 "[%s] Can't add fetches light to frame display list\n",
1908 code = gtxframe_AddToList(scout_frame, curr_line->stores_lp);
1911 "[%s] Can't add stores light to frame display list\n",
1916 code = gtxframe_AddToList(scout_frame, curr_line->workstations_lp);
1919 "[%s] Can't add workstation light to display list\n", rn);
1923 code = gtxframe_AddToList(scout_frame, curr_line->srvName_lp);
1926 "[%s] Can't add server name light to display list\n", rn);
1931 * Move down to the next server record.
1935 } /*Add lights in server records to display list */
1939 * Set up the minimal keymap.
1941 code = keymap_BindToString(scout_frame->keymap, /*Ptr to keymap */
1942 "e", /*Key to bind */
1943 ExitCmd, /*Cmd to execute */
1945 NULL); /*Ptr to rock */
1947 fprintf(stderr, "[%s] Can't bind key `e', code is %d\n", rn, code);
1953 * Finish setting up the overall mini_screen structure.
1955 scout_screen.numServers = a_numservers;
1956 scout_screen.line = mini_lines;
1957 WOP_GETDIMENSIONS(scout_frame->window, &scout_frameDims);
1960 * Start up the fsprobe package, which will gather FileServer
1961 * statistics for us on a regular basis.
1963 gtxframe_DisplayString(scout_frame,
1964 "Establishing File Server connection(s)...");
1965 code = fsprobe_Init(a_numservers, /*Num FileServers to probe */
1966 FSSktArray, /*FileServer socket array */
1967 scout_probefreq, /*Probe frequency */
1968 FS_Handler, /*Handler routine */
1969 0); /*Turn debugging output off */
1971 scout_debug); /*Turn debugging output off */
1974 fprintf(stderr, "[%s] Error returned by fsprobe_Init: %d\n", rn,
1981 * Start up the input server LWP for our window.
1984 code = LWP_CreateProcess(gtx_InputServer, /*Fcn to start up */
1985 8192, /*Stack size in bytes */
1986 LWP_NORMAL_PRIORITY, /*Priority */
1987 (void *)scout_gwin, /*Params: Ptr to window */
1988 "gx-listener", /*Name to use */
1989 &gxlistener_ID); /*Returned LWP process ID */
1992 code = gtx_InputServer(scout_gwin);
1995 "[%s] Error exit from gtx_InputServer(), error is %d\n", rn,
1997 scout_CleanExit(code);
2001 * We fall into a loop, sleeping forever.
2004 tv.tv_sec = 60 * 60; /*Sleep for an hour at a time */
2006 code = select(0, /*Num fds */
2007 0, /*Descriptors ready for reading */
2008 0, /*Descriptors ready for writing */
2009 0, /*Descriptors with exceptional conditions */
2010 &tv); /*Timeout structure */
2011 } /*Sleep forever */
2015 * How did we get here? Oh, well, clean up our windows and
2016 * return sweetness and light anyway.
2018 WOP_CLEANUP(&scout_gwin);
2022 } /*execute_scout */
2024 /*------------------------------------------------------------------------
2028 * Given a pointer to the list of servers we'll be polling,
2029 * compute the length of the list.
2032 * struct cmd_item *a_firstItem : Ptr to first item in list.
2035 * Length of the above list.
2038 * Nothing interesting.
2042 *------------------------------------------------------------------------*/
2044 static int countServers(a_firstItem)
2045 struct cmd_item *a_firstItem;
2049 int list_len; /*List length */
2050 struct cmd_item *curr_item; /*Ptr to current item */
2053 curr_item = a_firstItem;
2060 curr_item = curr_item->next;
2070 /*------------------------------------------------------------------------
2071 * scout_AdoptThresholds
2074 * Parse and adopt one or more threshold values, as read off the
2078 * struct cmd_item *a_thresh_item : Ptr to item on command-line
2082 * Nothing (but may exit the entire program on error!)
2085 * Valid keywords are:
2086 * conn, disk, fetch, store, ws
2087 * The disk value, if it has a % sign, signifies that attention
2088 * will be triggered when the disk is more than that percentage
2089 * full; otherwise, it will specify the minimum number of free
2094 *------------------------------------------------------------------------*/
2096 static void scout_AdoptThresholds(a_thresh_item)
2097 struct cmd_item *a_thresh_item;
2099 { /*scout_AdoptThresholds */
2101 static char rn[] = "scout_AdoptThresholds"; /*Routine name */
2102 struct cmd_item *curr_item; /*Current item */
2103 char *curr_name; /*Current name half of pair */
2104 char *curr_value; /*Current value half of pair */
2105 int diskval_len; /*Length of disk attn value */
2107 curr_item = a_thresh_item;
2110 * If there isn't a corresponding value for the current
2111 * attention field, bitch & die.
2113 if (curr_item->next == (struct cmd_item *)0) {
2114 printf("[%s] No threshold value given for '%s'\n", rn,
2116 scout_CleanExit(-1);
2119 curr_name = curr_item->data;
2120 curr_value = curr_item->next->data;
2122 if (strcmp(curr_name, "conn") == 0) {
2124 fprintf(scout_debugfd,
2125 "[%s] Setting conn attn value to %d (default %d)\n",
2126 rn, curr_value, scout_attn_conn);
2127 fflush(scout_debugfd);
2129 scout_attn_conn = atoi(curr_value);
2130 } else if (strcmp(curr_name, "disk") == 0) {
2132 * If there's a '%' as the last character in the value,
2133 * we use percentage mode.
2135 diskval_len = strlen(curr_value);
2136 if (curr_value[diskval_len - 1] == '%') {
2137 curr_value[diskval_len - 1] = '\0';
2139 fprintf(scout_debugfd,
2140 "[%s] New disk attn value: 0.%s used (default %f)\n",
2141 rn, curr_value, scout_attn_disk_pcused);
2142 fflush(scout_debugfd);
2144 sprintf(scout_attn_disk_pcusedstr, "%s", curr_value);
2145 scout_attn_disk_pcused =
2146 ((float)(atoi(curr_value))) / ((float)(100));
2147 } /*Percentage mode */
2150 fprintf(scout_debugfd,
2151 "[%s] New disk attn value: %s min free (default %d)\n",
2152 rn, atoi(curr_value), scout_attn_disk_pcused);
2153 fflush(scout_debugfd);
2155 scout_attn_disk_mode = SCOUT_DISKM_MINFREE;
2156 scout_attn_disk_minfree = atoi(curr_value);
2157 } /*Min free blocks mode */
2158 } else if (strcmp(curr_name, "fetch") == 0) {
2160 fprintf(scout_debugfd,
2161 "[%s] Setting fetch attn value to %d (default %d)\n",
2162 rn, curr_value, scout_attn_fetch);
2163 fflush(scout_debugfd);
2165 scout_attn_fetch = atoi(curr_value);
2166 } else if (strcmp(curr_name, "store") == 0) {
2168 fprintf(scout_debugfd,
2169 "[%s] Setting store attn value to %d (default %d)\n",
2170 rn, curr_value, scout_attn_store);
2171 fflush(scout_debugfd);
2173 scout_attn_store = atoi(curr_value);
2174 } else if (strcmp(curr_name, "ws") == 0) {
2176 fprintf(scout_debugfd,
2177 "[%s] Setting workstation attn value to %d (default %d)\n",
2178 rn, curr_value, scout_attn_workstations);
2179 fflush(scout_debugfd);
2181 scout_attn_workstations = atoi(curr_value);
2183 printf("[%s] Unknown attention item: '%s'\n", rn,
2185 scout_CleanExit(-1);
2189 * Advance past the just-processed pair.
2191 curr_item = curr_item->next->next;
2193 } /*Interpret each name-value pair */
2195 } /*scout_AdoptThresholds */
2197 /*------------------------------------------------------------------------
2201 * Routine called when Scout is invoked, responsible for basic
2202 * initialization, command line parsing, and calling the
2203 * routine that does all the work.
2206 * as : Command syntax descriptor.
2207 * arock : Associated rock (not used here).
2210 * Zero (but may exit the entire program on error!)
2213 * Nothing interesting.
2216 * Initializes this program.
2217 *------------------------------------------------------------------------*/
2219 static int scoutInit(as, arock)
2220 struct cmd_syndesc *as;
2225 static char rn[] = "scoutInit"; /*Routine name */
2226 int code; /*Return code */
2227 int wpkg_to_use; /*Window package to use */
2228 int server_count; /*Number of servers to watch */
2229 char *debug_filename; /*Name of debugging output file */
2232 fprintf(scout_debugfd, "[%s] Called\n", rn);
2233 fflush(scout_debugfd);
2236 if (as->parms[P_DEBUG].items != 0) {
2238 debug_filename = as->parms[P_DEBUG].items->data;
2239 scout_debugfd = fopen(debug_filename, "w");
2240 if (scout_debugfd == (FILE *) 0) {
2241 printf("[%s] Can't open debugging file '%s'!\n", rn,
2243 scout_CleanExit(-1);
2245 fprintf(scout_debugfd, "[%s] Writing to Scout debugging file '%s'\n",
2246 rn, debug_filename);
2249 wpkg_to_use = atoi(as->parms[P_PACKAGE].items->data);
2251 wpkg_to_use = 2; /*Always use curses for now */
2253 fprintf(stderr, "[%s:%s] Using graphics package %d: ", pn, rn,
2255 switch (wpkg_to_use) {
2256 case GATOR_WIN_CURSES:
2257 fprintf(stderr, "curses\n");
2259 case GATOR_WIN_DUMB:
2260 fprintf(stderr, "dumb terminal\n");
2263 fprintf(stderr, "X11\n");
2266 fprintf(stderr, "Illegal graphics package: %d\n", wpkg_to_use);
2267 scout_CleanExit(-1);
2268 } /*end switch (wpkg_to_use) */
2271 if (as->parms[P_FREQ].items != 0)
2272 scout_probefreq = atoi(as->parms[P_FREQ].items->data);
2274 scout_probefreq = 60;
2277 * See if we've been fed a base server name.
2279 if (as->parms[P_BASE].items != 0)
2280 sprintf(scout_basename, "%s", as->parms[P_BASE].items->data);
2282 *scout_basename = '\0';
2285 * Count the number of servers we've been asked to monitor.
2287 server_count = countServers(as->parms[P_SERVER].items);
2290 * Create a line of blanks, a generally-useful thing.
2292 sprintf(scout_blankline, "%255s", " ");
2295 * Pull in the name of the host we're executing on if we've been
2296 * asked to. If we can't get the name, we provide a default.
2298 if (as->parms[P_HOST].items != 0) {
2299 scout_showhostname = 1;
2300 *scout_hostname = '\0';
2301 code = gethostname(scout_hostname, 128);
2303 sprintf(scout_hostname, "%s", "*No Hostname*");
2307 * Pull in any and all attention/highlighting thresholds.
2309 if (as->parms[P_ATTENTION].items != 0)
2310 scout_AdoptThresholds(as->parms[P_ATTENTION].items);
2313 * Now, drive the sucker.
2315 code = execute_scout(server_count, /*Num servers */
2316 as->parms[P_SERVER].items, /*Ptr to srv names */
2317 wpkg_to_use); /*Graphics pkg */
2319 fprintf(stderr, "[%s] Error executing scout: %d\n", rn, code);
2320 scout_CleanExit(-1);
2324 * We initialized (and ran) correctly, so return the good news.
2330 #include "AFS_component_version_number.c"
2338 register afs_int32 code; /*Return code */
2339 register struct cmd_syndesc *ts; /*Ptr to cmd line syntax descriptor */
2341 #ifdef AFS_AIX32_ENV
2343 * The following signal action for AIX is necessary so that in case of a
2344 * crash (i.e. core is generated) we can include the user's data section
2345 * in the core dump. Unfortunately, by default, only a partial core is
2346 * generated which, in many cases, isn't too useful.
2348 struct sigaction nsa;
2350 sigemptyset(&nsa.sa_mask);
2351 nsa.sa_handler = SIG_DFL;
2352 nsa.sa_flags = SA_FULLDUMP;
2353 sigaction(SIGSEGV, &nsa, NULL);
2356 * Set up the commands we understand.
2358 ts = cmd_CreateSyntax("initcmd", scoutInit, 0, "initialize the program");
2359 cmd_AddParm(ts, "-server", CMD_LIST, CMD_REQUIRED,
2360 "FileServer name(s) to monitor");
2361 cmd_AddParm(ts, "-basename", CMD_SINGLE, CMD_OPTIONAL,
2362 "base server name");
2364 cmd_AddParm(ts, "-package", CMD_SINGLE, CMD_REQUIRED,
2365 "Graphics package to use");
2367 cmd_AddParm(ts, "-frequency", CMD_SINGLE, CMD_OPTIONAL,
2368 "poll frequency, in seconds");
2369 cmd_AddParm(ts, "-host", CMD_FLAG, CMD_OPTIONAL,
2370 "show name of host you're running on");
2371 cmd_AddParm(ts, "-attention", CMD_LIST, CMD_OPTIONAL,
2372 "specify attention (highlighting) level");
2373 cmd_AddParm(ts, "-debug", CMD_SINGLE, CMD_OPTIONAL,
2374 "turn debugging output on to the named file");
2377 * Parse command-line switches & execute the test, then get the heck
2380 code = cmd_Dispatch(argc, argv);
2383 fprintf(stderr, "[%s:%s] Call to cmd_Dispatch() failed; code is %d\n",