2 * Copyright 2000, International Business Machines Corporation and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
11 * Scout: A quick and (semi-)dirty attempt at the old CMU vopcon.
12 *------------------------------------------------------------------------*/
14 #include <afsconfig.h>
15 #include <afs/param.h>
24 #include <gtxwindows.h> /*Generic window package*/
25 #include <gtxobjects.h> /*Object definitions*/
26 #include <gtxtextobj.h> /*Text object interface*/
27 #include <gtxlightobj.h> /*Light object interface*/
28 #include <gtxcurseswin.h> /*Curses window package*/
29 #include <gtxdumbwin.h> /*Dumb terminal window package*/
30 #include <gtxX11win.h> /*X11 window package*/
31 #include <gtxframe.h> /*Frame package*/
32 #include <stdio.h> /*Standard I/O stuff*/
33 #include <cmd.h> /*Command interpretation library*/
34 #include <fsprobe.h> /*Interface for fsprobe module*/
37 extern struct hostent *hostutil_GetHostByName();
38 extern int gtx_InputServer();
39 extern int gethostname();
42 * Command line parameter indicies.
55 * Define the width in chars for each light object on the mini-line.
57 #define LIGHTOBJ_CONN_WIDTH 5
58 #define LIGHTOBJ_FETCH_WIDTH 10
59 #define LIGHTOBJ_STORE_WIDTH 10
60 #define LIGHTOBJ_WK_WIDTH 5
61 #define LIGHTOBJ_SRVNAME_WIDTH 13
62 #define LIGHTOBJ_DISK_WIDTH 12
65 * Define the types of justification we can perform.
67 #define SCOUT_RIGHT_JUSTIFY 0
68 #define SCOUT_LEFT_JUSTIFY 1
69 #define SCOUT_CENTER 2
72 * Define the types of truncation we can perform.
74 #define SCOUT_LEFT_TRUNC 0
75 #define SCOUT_RIGHT_TRUNC 1
78 * Define whether the value passed is a labeled disk quantity.
80 #define SCOUT_ISNT_LDISK 0
81 #define SCOUT_IS_LDISK 1
84 * We sometimes use index-base pointers, so we need a distinguished
87 #define SCOUT_NIL (-1)
90 * Structure describing everything you want to know about a FileServer
94 int prev; /*Index of previous list entry*/
95 int next; /*Index of next list entry*/
96 int active; /*Is this disk known to exist?*/
97 char *name; /*Single-letter disk name*/
98 struct onode *disk_lp; /*Ptr to disk light object*/
102 * Structure defining all the objects in the Scout line (or lines)
103 * for each server being watched. Note that scout_disk linked list
104 * for used disks is ordered alphabetically.
108 * Information on server location & configuration.
110 struct sockaddr_in skt; /*Server's socket info*/
111 int numDisks; /*Number of disks used*/
113 * Screen location info.
115 int base_line; /*Line number on the screen*/
116 int num_lines; /*Number of lines of info*/
118 * Associated light objects.
120 struct onode *currConns_lp; /*Number of current connections*/
121 struct onode *fetches_lp; /*Number of data fetches*/
122 struct onode *stores_lp; /*Number of data stores*/
123 struct onode *workstations_lp; /*Workstation info*/
124 struct onode *srvName_lp; /*Server name*/
125 struct scout_disk disks[VOLMAXPARTS]; /*Info on all the disks*/
126 int used_head; /*Index of first used disk struct*/
127 int used_tail; /*Index of last used disk struct*/
128 int free_head; /*Index of first free disk struct*/
129 int free_tail; /*Index of last free disk struct*/
133 * Structure defining the contents of the Scout screen.
136 int numServers; /*Number of servers being watched*/
137 int base_line_num; /*Base mini-line number*/
138 struct mini_line *line; /*Array of screen lines*/
141 static char pn[] = "scout"; /*Program name*/
142 static int scout_debug = 0; /*Is debugging turned on?*/
143 static FILE *scout_debugfd; /*Debugging file descriptor*/
144 static int scout_gtx_initialized = 0; /*Has gtx been initialized?*/
145 static struct mini_screen scout_screen; /*Mini-screen itself*/
146 static int scout_probefreq; /*Probe frequency in seconds*/
147 static char scout_basename[64]; /*Base server name*/
148 static char scout_hostname[128]; /*Name of machine we're running on*/
149 static int scout_showhostname = 0; /*Show name of machine we're on?*/
150 static char scout_blankline[256]; /*Blank line*/
151 static struct gwin *scout_gwin; /*Window to use*/
152 static struct gtx_frame *scout_frame; /*Frame to use*/
153 static struct onode *scout_banner0_lp; /*Banner light, line 0*/
154 static struct onode *scout_banner1_lp; /*Banner light, line 1*/
155 static struct onode *scout_banner2_lp; /*Banner light, line 2*/
156 static int scout_DiskLightLeftCol = 0; /*Column for leftmost disk light*/
157 static struct gwin_sizeparams scout_frameDims; /*Frame dimensions*/
160 * Attention thresholds & modes.
162 #define SCOUT_ATTN_NOTUSED (-1)
163 #define SCOUT_DISKM_PCUSED 0
164 #define SCOUT_DISKM_MINFREE 1
166 static int scout_attn_conn = SCOUT_ATTN_NOTUSED;
167 static int scout_attn_fetch = SCOUT_ATTN_NOTUSED;
168 static int scout_attn_store = SCOUT_ATTN_NOTUSED;
169 static int scout_attn_workstations = SCOUT_ATTN_NOTUSED;
170 static int scout_attn_disk_mode = SCOUT_DISKM_PCUSED;
171 static int scout_attn_disk_minfree = 1000;
172 static float scout_attn_disk_pcused = 0.95;
173 static char scout_attn_disk_pcusedstr[8] = "95";
176 * Some strings we'll be using over and over again.
178 static char scout_Banner[256];
179 static char scout_LightLabels[] =
180 "Conn Fetch Store Ws Disk attn:";
181 static char scout_LightLabelUnd[] =
182 "---- -------- -------- ----- ----------";
185 /*------------------------------------------------------------------------
189 * Exits cleanly from the Scout. If gtx has not yet been initialized,
190 * then we simply call exit() with the value provided. Otherwise,
191 * we call the appropriate gtx routine to exit cleanly from gtx, which
192 * must reset the terminal or window. We also close the debugging
193 * file descriptor, if one has been opened.
196 * int a_exitval : Value with which to exit the program.
202 * Actions depend on scout_gtx_initialized.
205 * This routine will always exit Scout.
206 *------------------------------------------------------------------------*/
208 static void scout_CleanExit(a_exitval)
211 { /*scout_CleanExit*/
213 static char rn[] = "scout_CleanExit"; /*Routine name*/
215 if (scout_debugfd != (FILE *)0) {
216 fprintf(scout_debugfd, "[%s] Closing debugging file\n", rn);
217 fclose(scout_debugfd);
220 if (scout_gtx_initialized) {
221 gtxframe_exitValue = a_exitval;
222 gtxframe_ExitCmd((char *)(>xframe_exitValue));
227 } /*scout_CleanExit*/
229 /*------------------------------------------------------------------------
230 * mini_initLightObject
233 * Create and initialize a light onode according to the given
237 * char *a_name : Ptr to the light's string name.
238 * int a_x : X offset.
239 * int a_y : Y offset.
240 * int a_width : Width in chars.
241 * struct gwin *a_win : Ptr to window structure.
244 * Ptr to new light onode on success,
245 * A null pointer otherwise.
252 *------------------------------------------------------------------------*/
254 static struct onode *mini_initLightObject(a_name, a_x, a_y, a_width, a_win)
261 { /*mini_initLightObject*/
263 static char rn[] = "mini_initLightObject"; /*Routine name*/
264 struct onode *newlightp; /*Ptr to new light onode*/
265 /*We only support curses right now*/
266 struct gator_light_crparams light_crparams; /*Light creation params*/
267 char *truncname; /*Truncated name, if needed*/
268 int name_len; /*True length of name*/
271 fprintf(scout_debugfd,
272 "[%s] Called for name '%s', [%d, %d], %d-char field\n",
273 rn, a_name, a_x, a_y, a_width);
274 fflush(scout_debugfd);
276 newlightp = (struct onode *)0;
279 * Set up the creation parameters according to the information we've
282 light_crparams.onode_params.cr_type = GATOR_OBJ_LIGHT;
283 name_len = strlen(a_name);
285 fprintf(scout_debugfd, "[%s] Name '%s' has %d chars\n",
286 rn, a_name, name_len);
287 if (name_len <= a_width)
288 sprintf(light_crparams.onode_params.cr_name, "%s", a_name);
291 * We need to truncate the given name, leaving a `*' at the end to
292 * show us it's been truncated.
294 truncname = light_crparams.onode_params.cr_name;
295 strncpy(truncname, a_name, a_width-1);
296 truncname[a_width-1] = '*';
297 truncname[a_width] = 0;
299 light_crparams.onode_params.cr_x = a_x;
300 light_crparams.onode_params.cr_y = a_y;
301 light_crparams.onode_params.cr_width = a_width;
302 light_crparams.onode_params.cr_height = 1;
303 light_crparams.onode_params.cr_window = a_win;
304 light_crparams.onode_params.cr_home_obj = (struct onode *)0;
305 light_crparams.onode_params.cr_prev_obj = (struct onode *)0;
306 light_crparams.onode_params.cr_parent_obj = (struct onode *)0;
307 light_crparams.onode_params.cr_helpstring = (char *)0;
309 light_crparams.appearance = 0;
310 light_crparams.flashfreq = 0;
311 sprintf(light_crparams.label, "%s", a_name);
312 light_crparams.label_x = 0;
313 light_crparams.label_y = 0;
316 gator_objects_create((struct onode_createparams *)(&light_crparams));
319 * Return the news, happy or not.
323 } /*mini_initLightObject*/
325 /*------------------------------------------------------------------------
326 * scout_initDiskLightObjects
329 * Create and initialize all Scout light objects for a server's
333 * struct scout_disk *a_line : Ptr to the server object line.
334 * struct gwin *a_win : Ptr to window structure.
345 *------------------------------------------------------------------------*/
347 static int scout_initDiskLightObjects(a_line, a_win)
348 struct mini_line *a_line;
351 { /*scout_initDiskLightObjects*/
354 "scout_initDiskLightObjects"; /*Routine name*/
355 struct scout_disk *curr_disk; /*Ptr to current disk being set up*/
356 int i; /*Loop variable*/
359 fprintf(scout_debugfd, "[%s] Called\n", rn);
360 fflush(scout_debugfd);
364 * Set up the base linked list fields.
366 a_line->used_head = SCOUT_NIL;
367 a_line->used_tail = SCOUT_NIL;
368 a_line->free_head = 0;
369 a_line->free_tail = VOLMAXPARTS - 1;
372 * Sweep through the disk structures, creating the light objects and
373 * marking them all as free.
375 curr_disk = a_line->disks;
376 for (i=0; i < VOLMAXPARTS; i++) {
378 * Create the disk light object.
380 if ((curr_disk->disk_lp =
381 mini_initLightObject("Disk", /*Object name*/
384 LIGHTOBJ_DISK_WIDTH, /*Width*/
386 == (struct onode *)0) {
387 fprintf(stderr, "[%s:%s] Can't create disk %d light object\n",
393 * Set the other fields in the disk records; Note that in the
394 * fencepost cases, the prev and next pointers will have to be
397 curr_disk->prev = i-1;
398 curr_disk->next = i+1;
399 curr_disk->active = 0;
400 curr_disk->name = '\0';
403 * Bump up to the next disk structure.
407 } /*for each disk structure*/
410 * We made it all the way through. Fix the fencepost pointers, set
411 * the overall pointers, then return success.
413 a_line->disks[0].prev = SCOUT_NIL;
414 a_line->disks[VOLMAXPARTS-1].next = SCOUT_NIL;
418 } /*scout_initDiskLightObjects*/
421 /*------------------------------------------------------------------------
425 * Place the chars in the source buffer into the target buffer
426 * with the desired justification, either centered, left-justified
427 * or right-justified. Also, support inidication of truncation
428 * with a star (*), either on the left or right of the string,
429 * and whether we're justifying a labeled disk quantity.
432 * char *a_srcbuff : Ptr to source char buffer.
433 * char *a_dstbuff : Ptr to dest char buffer.
434 * int a_dstwidth : Width of dest buffer in chars.
435 * int a_justification : Kind of justification.
436 * int a_rightTrunc : If non-zero, place the truncation char
437 * on the right of the string. Otherwise,
438 * place it on the left.
439 * int a_isLabeledDisk : Is this a labeled disk quantity?
446 * All it needs to know is exported by the fsprobe module, namely
447 * the data structure where the probe results are stored.
451 *------------------------------------------------------------------------*/
453 int mini_justify(a_srcbuff, a_dstbuff, a_dstwidth, a_justification, a_rightTrunc, a_isLabeledDisk)
463 static char rn[] = "mini_justify"; /*Routine name*/
464 int leftpad_chars; /*# of chars for left-padding*/
465 int num_src_chars; /*# of chars in source*/
466 int true_num_src_chars; /*# src chars before truncation*/
467 int trunc_needed; /*Is truncation needed?*/
468 char diskChar; /*Disk name prefix*/
471 fprintf(scout_debugfd, "[%s] Called with '%s', dest width=%d\n",
472 rn, a_srcbuff, a_dstwidth);
473 fflush(scout_debugfd);
477 * Remember the disk label, if we've been passed such a thing.
480 diskChar = *a_srcbuff;
483 * If the destination width will overrun the gtx string storage,
484 * we automatically shorten up.
486 if (a_dstwidth > GATOR_LABEL_CHARS) {
488 fprintf(scout_debugfd,
489 "[%s] Dest width (%d) > gtx buflen (%d), shrinking dest width\n",
490 rn, a_dstwidth, GATOR_LABEL_CHARS);
491 fflush(scout_debugfd);
493 a_dstwidth = GATOR_LABEL_CHARS;
497 * If our source string is too long, prepare for truncation.
499 true_num_src_chars = strlen(a_srcbuff);
500 if (true_num_src_chars >= a_dstwidth) {
502 num_src_chars = a_dstwidth - 1;
505 a_srcbuff += (true_num_src_chars - num_src_chars);
509 num_src_chars = true_num_src_chars;
512 * Compute the necessary left-padding.
514 switch (a_justification) {
516 case SCOUT_RIGHT_JUSTIFY:
517 leftpad_chars = (a_dstwidth - 1) - num_src_chars;
520 case SCOUT_LEFT_JUSTIFY:
522 * This is the really easy one.
528 leftpad_chars = ((a_dstwidth - 1) - num_src_chars) / 2;
532 fprintf(stderr, "[%s] Illegal justification command: %d",
533 rn, a_justification);
535 } /*Switch on justification type*/
539 * Clear out the dest buffer, then place the source string at the
540 * appropriate padding location. Remember to place a string
541 * terminator at the end of the dest buffer, plus whatever truncation
542 * may be needed. If we're left-truncating, we've already shifted
543 * the src buffer appropriately.
545 strncpy(a_dstbuff, scout_blankline, a_dstwidth);
546 strncpy(a_dstbuff+leftpad_chars, a_srcbuff, num_src_chars);
547 *(a_dstbuff+a_dstwidth-1) = '\0';
550 *(a_dstbuff+a_dstwidth-2) = '*'; /*Truncate on the right*/
552 if (a_isLabeledDisk) {
553 *a_dstbuff = diskChar;
554 *(a_dstbuff+1) = ':';
555 *(a_dstbuff+2) = '*'; /*Truncate on the left, disk*/
558 *a_dstbuff = '*'; /*Truncate on the left, non-disk*/
560 } /*Handle truncations*/
563 * Return the good news.
569 /*------------------------------------------------------------------------
570 * scout_SetNonDiskLightLine
573 * Given a mini-line and a line number, place all non-disk lights
577 * struct mini_line *a_srvline : Ptr to server descriptor.
578 * int a_linenum : Line number to move to.
584 * The light's location is stored not only in the onode, but in
585 * the light's rock, so we have to change both sets of value.
589 *------------------------------------------------------------------------*/
591 static void scout_SetNonDiskLightLine(a_srvline, a_linenum)
592 struct mini_line *a_srvline;
595 { /*scout_SetNonDiskLightLine*/
598 "scout_SetNonDiskLightLine"; /*Routine name*/
599 struct gator_lightobj *nondisk_lightdata; /*Non-disk light data field*/
600 struct gwin_strparams *nondisk_strparams; /*Associated string params*/
603 * Do the exact same operation for each non-disk light in the record.
605 a_srvline->currConns_lp->o_y = a_linenum;
607 (struct gator_lightobj *)(a_srvline->currConns_lp->o_data);
609 (struct gwin_strparams *)(nondisk_lightdata->llrock);
610 nondisk_strparams->y = a_linenum;
612 a_srvline->fetches_lp->o_y = a_linenum;
614 (struct gator_lightobj *)(a_srvline->fetches_lp->o_data);
616 (struct gwin_strparams *)(nondisk_lightdata->llrock);
617 nondisk_strparams->y = a_linenum;
619 a_srvline->stores_lp->o_y = a_linenum;
621 (struct gator_lightobj *)(a_srvline->stores_lp->o_data);
623 (struct gwin_strparams *)(nondisk_lightdata->llrock);
624 nondisk_strparams->y = a_linenum;
626 a_srvline->workstations_lp->o_y = a_linenum;
628 (struct gator_lightobj *)(a_srvline->workstations_lp->o_data);
630 (struct gwin_strparams *)(nondisk_lightdata->llrock);
631 nondisk_strparams->y = a_linenum;
633 a_srvline->srvName_lp->o_y = a_linenum;
635 (struct gator_lightobj *)(a_srvline->srvName_lp->o_data);
637 (struct gwin_strparams *)(nondisk_lightdata->llrock);
638 nondisk_strparams->y = a_linenum;
640 } /*scout_SetNonDiskLightLine*/
642 /*------------------------------------------------------------------------
643 * scout_RecomputeLightLocs
646 * Given a pointer to a server record, recompute its disk light
647 * locations (and keep proper track of the number of screen lines
648 * required for the server record).
651 * struct mini_line *a_srvline : Ptr to server descriptor.
654 * 0 if anything went wrong,
655 * else the number of lines used by this server record.
658 * One or more records have joined or left the used light list
659 * for this server. We're not sure which ones, so we recompute
660 * them all. We may also have had a width change in the gtx
661 * frame. The base_line field in the server record is guaranteed
662 * to be correct at this point.
666 *------------------------------------------------------------------------*/
668 static int scout_RecomputeLightLocs(a_srvline)
669 struct mini_line *a_srvline;
671 { /*scout_RecomputeLightLocs*/
674 "scout_RecomputeLightLocs"; /*Routine name*/
675 int lights_per_line; /*# lights/line*/
676 int lights_this_line; /*# lights on cur line*/
677 int curr_idx; /*Current disk light idx*/
678 struct scout_disk *sc_disk; /*Ptr to disk record array*/
679 int lines_for_server; /*Num lines in server record*/
680 int curr_line; /*Current line being filled*/
681 int curr_x; /*Current x value for light*/
682 struct gator_lightobj *disk_lightdata; /*Disk light data field*/
683 struct gwin_strparams *disk_strparams; /*String params for disk light*/
686 fprintf(scout_debugfd, "[%s] Called\n", rn);
687 fflush(scout_debugfd);
691 * If we haven't yet computed the column for the leftmost disk light,
694 if (scout_DiskLightLeftCol == 0)
695 scout_DiskLightLeftCol =
696 LIGHTOBJ_CONN_WIDTH +
697 LIGHTOBJ_FETCH_WIDTH +
698 LIGHTOBJ_STORE_WIDTH +
700 LIGHTOBJ_SRVNAME_WIDTH + 5;
703 * Calculate how many disk light objects can fit in one line.
706 (scout_frameDims.maxx - scout_DiskLightLeftCol)/(LIGHTOBJ_DISK_WIDTH + 1);
708 fprintf(scout_debugfd, "[%s] %d lights per line\n",
709 rn, lights_per_line);
710 fflush(scout_debugfd);
714 * Sweep through the used disk light list, computing the location
717 lights_this_line = 0;
718 curr_idx = a_srvline->used_head;
719 lines_for_server = 1;
720 curr_line = a_srvline->base_line;
721 curr_x = scout_DiskLightLeftCol;
723 while (curr_idx != SCOUT_NIL) {
725 * Bump the number of lines for the server if we've already
726 * filled up the current line.
728 if (lights_this_line >= lights_per_line) {
729 lights_this_line = 0;
732 curr_x = scout_DiskLightLeftCol;
733 } /*Current line filled up*/
736 * Set the current disk light's location.
738 sc_disk = a_srvline->disks;
739 sc_disk[curr_idx].disk_lp->o_x = curr_x;
740 sc_disk[curr_idx].disk_lp->o_y = curr_line;
742 (struct gator_lightobj *)(sc_disk[curr_idx].disk_lp->o_data);
744 (struct gwin_strparams *)(disk_lightdata->llrock);
745 disk_strparams->x = curr_x;
746 disk_strparams->y = curr_line;
748 fprintf(scout_debugfd,
749 "[%s] Disk light at index %d located at [%d, %d]\n",
750 rn, curr_idx, curr_x, curr_line);
751 fflush(scout_debugfd);
755 * Record the inclusion of the light and move on to the next
759 curr_x += LIGHTOBJ_DISK_WIDTH + 1;
760 curr_idx = sc_disk[curr_idx].next;
762 } /*Update each used disk light*/
765 * Remember to record the (possibly new) number of lines in the
766 * server record before returning the value of that field.
768 if (a_srvline->num_lines != lines_for_server) {
770 fprintf(scout_debugfd,
771 "[%s] Server previously had %d screen lines; now changed\n",
772 rn, a_srvline->num_lines);
773 fflush(scout_debugfd);
775 a_srvline->num_lines = lines_for_server;
779 fprintf(scout_debugfd, "[%s] Server has %d screen lines\n",
780 rn, a_srvline->num_lines);
781 fflush(scout_debugfd);
783 return(a_srvline->num_lines);
785 } /*scout_RecomputeLightLocs*/
787 /*------------------------------------------------------------------------
791 * Given a single-letter disk name and a pointer to the current server
792 * record, look for a used disk record with that name within the server.
793 * If we can't find one, we create and incorporate one, and return that
794 * fact to our caller.
797 * char a_diskname : Single-char disk name.
798 * struct mini_line *a_srvline : Ptr to server descriptor.
799 * int *a_record_added : Was a new record added?
802 * Index of matching used disk record,
803 * SCOUT_NIL otherwise.
805 * Return via parameter:
806 * a_record_added set to 1 iff record was added to the used disk list.
809 * Used disk records are kept in alphabetical order by the single-char
810 * disk name. Should a matching used disk record not be found, one is
811 * pulled from the free pool.
814 * An entry may be pulled off the free list and inserted into the
815 * used list. This entry is placed in the update list for the
816 * current gtx frame (at least not by this routine).
817 *------------------------------------------------------------------------*/
819 static int scout_FindUsedDisk(a_diskname, a_srvline, a_record_added)
821 struct mini_line *a_srvline;
824 { /*scout_FindUsedDisk*/
826 static char rn[] = "scout_FindUsedDisk"; /*Routine name*/
827 int curr_idx; /*Disk record index*/
828 int append_idx; /*Index to append after*/
829 int new_idx; /*Index of new used record*/
830 struct scout_disk *sc_disk; /*Ptr to disk record*/
831 int code; /*Function return value*/
834 fprintf(scout_debugfd, "[%s] Called\n", rn);
835 fflush(scout_debugfd);
839 * Sweep through the used disk records, looking for a match.
841 curr_idx = a_srvline->used_head;
842 append_idx = SCOUT_NIL;
843 sc_disk = a_srvline->disks;
845 fprintf(scout_debugfd, "[%s] Scanning existing used disk entries for disk '%s'\n", rn, a_diskname);
846 fflush(scout_debugfd);
848 while (curr_idx != SCOUT_NIL) {
850 fprintf(scout_debugfd, "[%s] Disk %d is named '%s'\n",
851 rn, curr_idx, sc_disk[curr_idx].name);
852 fflush(scout_debugfd);
854 if (strcmp(sc_disk[curr_idx].name, a_diskname) == 0) {
856 * We found it! Bug out.
859 fprintf(scout_debugfd, "[%s] Match found\n", rn);
860 fflush(scout_debugfd);
866 * If we are alphabetically past the given disk name, we
867 * know that we won't find it in the used disk list; we
868 * also have the append index set correctly.
870 if (strcmp(a_diskname, sc_disk[curr_idx].name) < 0) {
872 fprintf(scout_debugfd, "[%s] Disk '%s' can't be here\n",
874 fflush(scout_debugfd);
880 * There's still hope we'll find it. Move on to the next used
881 * disk record, keeping this index as the best candidate so far
882 * for appending a missing entry.
884 append_idx = curr_idx;
885 curr_idx = sc_disk[curr_idx].next;
889 * We didn't find the record we wanted, which means we'll pull a
890 * record out of the free pool for it. If we didn't find a place
891 * to append it, we then insert it at the beginning of the queue.
893 if (a_srvline->free_head == SCOUT_NIL)
896 new_idx = a_srvline->free_head;
898 fprintf(scout_debugfd, "[%s] Choosing free index %d for new entry\n",
900 fflush(scout_debugfd);
902 a_srvline->free_head = sc_disk[new_idx].next;
903 if (a_srvline->free_head == SCOUT_NIL)
904 a_srvline->free_tail = SCOUT_NIL;
907 * Fill in the new record.
909 sc_disk[new_idx].active = 0;
910 sc_disk[new_idx].name = a_diskname;
913 * Insert the new record where it belongs on the used disk list.
915 if (append_idx == SCOUT_NIL) {
917 * It belongs at the beginning of the list.
920 fprintf(scout_debugfd, "[%s] Inserted at used disk head\n", rn);
921 fflush(scout_debugfd);
923 sc_disk[new_idx].next = a_srvline->used_head;
924 sc_disk[new_idx].prev = SCOUT_NIL;
925 a_srvline->used_head = new_idx;
926 if (a_srvline->used_tail == SCOUT_NIL)
927 a_srvline->used_tail = new_idx;
931 fprintf(scout_debugfd, "[%s] Entry appended after index %d\n",
933 fflush(scout_debugfd);
935 sc_disk[new_idx].prev = append_idx;
936 sc_disk[new_idx].next = sc_disk[append_idx].next;
937 sc_disk[append_idx].next = new_idx;
938 if (sc_disk[new_idx].next == SCOUT_NIL)
939 a_srvline->used_tail = new_idx;
941 sc_disk[sc_disk[new_idx].next].prev = new_idx;
945 * Add the new used disk light object to the display list for
949 fprintf(scout_debugfd, "[%s] Adding disk light at index %d to display list\n", rn, new_idx);
950 fflush(scout_debugfd);
952 code = gtxframe_AddToList(scout_frame, sc_disk[new_idx].disk_lp);
955 fprintf(scout_debugfd, "[%s] Can't add to display list, code is %d\n",
957 fflush(scout_debugfd);
962 } /*scout_FindUsedDisk*/
964 /*------------------------------------------------------------------------
965 * scout_RemoveInactiveDisk
968 * Given a server record and a used disk index, remove the disk
969 * record from the used list, put it on the free list, and remove
970 * it from the gtx frame update list.
973 * struct mini_line *a_srvline : Ptr to server descriptor.
974 * int a_used_idx : Index of used disk record.
980 * Formerly-used disk records are returned to the free pool.
983 * Free and used disk record lists are modified for this server.
984 * The disk record in question is pulled off the gtx update list
986 *------------------------------------------------------------------------*/
988 static void scout_RemoveInactiveDisk(a_srvline, a_used_idx)
989 struct mini_line *a_srvline;
992 { /*scout_RemoveInactiveDisk*/
994 static char rn[] = "scout_RemoveInactiveDisk"; /*Routine name*/
997 fprintf(scout_debugfd, "[%s] Called\n", rn);
998 fflush(scout_debugfd);
1001 /*code = gtxframe_RemoveFromList(scout_frame->window, lightobj);*/
1003 } /*scout_RemoveInactiveDisk*/
1005 /*------------------------------------------------------------------------
1006 * mini_PrintDiskStats
1009 * Given server indexing and light object information, a pointer
1010 * to a set of statistics, and whether the probe that produced these
1011 * stats succeeded or not, print out the stats in a nice way.
1014 * struct mini_line *a_srvline : Ptr to server descriptor.
1015 * struct ProbeViceStatistics *a_stats : Ptr to current stats.
1016 * int a_probeOK : Was the probe OK?
1017 * int a_width_changed : Has the frame width changed?
1018 * int a_fix_line_num : Is the line number wrong?
1019 * int a_delta_line_num : Change in line number.
1022 * 0 if something went wrong,
1023 * else the number of lines taken up by this server record.
1026 * Nothing interesting.
1030 *------------------------------------------------------------------------*/
1032 static int mini_PrintDiskStats(a_srvline, a_stats, a_probeOK, a_width_changed,
1033 a_fix_line_num, a_delta_line_num)
1034 struct mini_line *a_srvline;
1035 struct ProbeViceStatistics *a_stats;
1038 int a_delta_line_num;
1040 { /*mini_PrintDiskStats*/
1042 static char rn[] = "mini_PrintDiskStats"; /*Routine name*/
1043 int code; /*Return code*/
1044 char s[128]; /*String buffer*/
1045 struct onode *curr_disklight; /*Ptr to current disk light*/
1046 struct onode *srvname_light; /*Ptr to server name light*/
1047 ViceDisk *curr_diskstat; /*Ptr to current disk stat*/
1048 int curr_disk; /*Current disk stat number*/
1049 int used_disk_idx; /*Used disk index*/
1050 int next_used_idx; /*Ditto*/
1051 int pastthreshold; /*Was disk past threshold?*/
1052 struct gator_lightobj *diskdata; /*Private light data*/
1053 struct gwin_strparams *disk_strparams; /*String params for disk light*/
1054 char *diskname = 0; /*Name of disk*/
1055 int found_idx; /*Idx of matching disk*/
1056 char *srv_name; /*Server name*/
1057 struct scout_disk *sc_disk; /*Ptr to scout disk desc*/
1058 int fix_light_locs; /*Recompute disk light locs?*/
1061 fprintf(scout_debugfd, "[%s] Called\n", rn);
1062 fflush(scout_debugfd);
1066 * Remember the current server's print name, don't recompute light
1069 srvname_light = a_srvline->srvName_lp;
1070 srv_name = ((struct gator_lightobj *)(srvname_light->o_data))->label;
1073 fprintf(scout_debugfd, "[%s] Value of a_delta_line_num is %d\n",
1074 rn, a_delta_line_num);
1075 fflush(scout_debugfd);
1079 * If the probe failed, we simply blank out all the used disk
1080 * objects. Note: a NON-ZERO value of a_probeOK implies failure.
1083 used_disk_idx = a_srvline->used_head;
1084 while (used_disk_idx != SCOUT_NIL) {
1086 * Point to the current used disk's light, blank out its
1087 * contents, and make sure highlighting is turned off. We
1088 * also take this opportunity to fix the line numbers if
1091 curr_disklight = a_srvline->disks[used_disk_idx].disk_lp;
1092 diskdata = (struct gator_lightobj *)(curr_disklight->o_data);
1094 fprintf(scout_debugfd, "[%s] Prev value of disk light %d: '%s'\n",
1095 rn, used_disk_idx, diskdata->label);
1096 fflush(scout_debugfd);
1098 code = mini_justify(" ", /*Src buffer*/
1099 diskdata->label, /*Dest buffer*/
1100 LIGHTOBJ_DISK_WIDTH, /*Dest's width*/
1101 SCOUT_RIGHT_JUSTIFY, /*Right-justify*/
1102 SCOUT_LEFT_TRUNC, /*Left-truncate*/
1103 SCOUT_ISNT_LDISK); /*Not a labeled disk*/
1104 code = gator_light_set(curr_disklight, 0);
1105 if (a_fix_line_num) {
1106 curr_disklight->o_y += a_delta_line_num;
1108 (struct gwin_strparams *)(diskdata->llrock);
1109 disk_strparams->y += a_delta_line_num;
1113 * Advance to next used disk, if any.
1115 used_disk_idx = a_srvline->disks[used_disk_idx].next;
1117 } /*Blank out disk name field*/
1120 * If the frame width has changed, we have to recompute all disk
1121 * light locations. After that, the number of lines in the server
1122 * record will be accurate, and we return them.
1124 if (a_width_changed)
1125 scout_RecomputeLightLocs(a_srvline);
1127 return(a_srvline->num_lines);
1129 } /*Probe failed for the server*/
1132 * Probe was successful. Sweep through the statistics records,
1133 * and put up all values having to do with AFS partitions. First,
1134 * mark all used disk objects for this server as inactive and fix
1135 * their line numbers if needed.
1137 sc_disk = a_srvline->disks;
1138 used_disk_idx = a_srvline->used_head;
1139 while (used_disk_idx != SCOUT_NIL) {
1141 fprintf(scout_debugfd, "[%s] Marking used disk %d inactive\n",
1143 fflush(scout_debugfd);
1145 sc_disk = (a_srvline->disks) + used_disk_idx;
1146 sc_disk->active = 0;
1147 used_disk_idx = sc_disk->next;
1148 if (a_fix_line_num) {
1149 sc_disk->disk_lp->o_y += a_delta_line_num;
1151 (struct gator_lightobj *)(sc_disk->disk_lp->o_data);
1153 (struct gwin_strparams *)(diskdata->llrock);
1154 disk_strparams->y += a_delta_line_num;
1156 } /*Mark used disks inactive*/
1158 curr_diskstat = (ViceDisk *) a_stats->Disk;
1159 for (curr_disk = 0; curr_disk < VOLMAXPARTS; curr_disk++) {
1161 * An AFS partition name must be prefixed by `/vicep`.
1164 fprintf(scout_debugfd, "[%s] Disk stats at 0x%x for disk '%s'\n",
1165 rn, curr_diskstat, curr_diskstat->Name);
1166 fflush(scout_debugfd);
1168 if (strncmp("/vice", curr_diskstat->Name, 5) == 0) {
1170 * Pull out the single-letter name (actually, abbreviation)
1171 * of the disk and look for such an entry in the used disks.
1173 diskname = &curr_diskstat->Name[6];
1175 scout_FindUsedDisk(diskname, /*1-char name*/
1176 a_srvline, /*Server record*/
1177 &fix_light_locs); /*Recompute?*/
1178 if (found_idx == SCOUT_NIL) {
1180 "[%s] Can't display /vicep%s on server '%s'\n",
1181 rn, diskname, srv_name);
1185 * Found (or created) record for this disk. Fill in the single-
1186 * letter name of the disk followed by the number of free blocks.
1187 * Turn the disk light on if the number of free blocks exceeds
1188 * the threshold the user set, either % used or min free blocks.
1190 sprintf(s, "%s:%d", diskname, curr_diskstat->BlocksAvailable);
1191 if (scout_attn_disk_mode == SCOUT_DISKM_PCUSED) {
1192 if ((float)(curr_diskstat->TotalBlocks -
1193 curr_diskstat->BlocksAvailable) /
1194 (float)(curr_diskstat->TotalBlocks) > scout_attn_disk_pcused)
1201 (curr_diskstat->BlocksAvailable < scout_attn_disk_minfree) ?
1203 sc_disk = (a_srvline->disks) + found_idx;
1204 sc_disk->active = 1;
1205 diskdata = (struct gator_lightobj *)(sc_disk->disk_lp->o_data);
1207 fprintf(scout_debugfd,
1208 "[%s] Justifying %s for disk idx %d (prev value: '%s')\n",
1209 rn, s, found_idx, diskdata->label);
1210 fflush(scout_debugfd);
1212 code = mini_justify(s, /*Src buffer*/
1213 diskdata->label, /*Dest buffer*/
1214 LIGHTOBJ_DISK_WIDTH, /*Dest's width*/
1215 SCOUT_LEFT_JUSTIFY, /*Left-justify*/
1216 SCOUT_LEFT_TRUNC, /*Left-truncate*/
1217 SCOUT_IS_LDISK); /*Labeled disk*/
1219 code = gator_light_set(sc_disk->disk_lp, pastthreshold);
1221 } /*Found disk record*/
1222 } /*Found AFS disk name*/
1225 * Advance to the next disk statistics record.
1228 } /*For each statistics record*/
1231 * We've now pulled out all the disk statistics from the probe.
1232 * See if any used disks that were there from the last time are
1233 * now gone. If so, we remove them.
1236 fprintf(scout_debugfd, "[%s] Scanning used disk records for inactive entries\n", rn);
1237 fflush(scout_debugfd);
1239 used_disk_idx = a_srvline->used_head;
1240 while (used_disk_idx != SCOUT_NIL) {
1242 fprintf(scout_debugfd, "[%s] Examining entry at index %d\n",
1244 fflush(scout_debugfd);
1246 sc_disk = (a_srvline->disks) + used_disk_idx;
1247 next_used_idx = sc_disk->next;
1248 if (!(sc_disk->active)) {
1249 scout_RemoveInactiveDisk(a_srvline, /*Server record*/
1250 used_disk_idx); /*Disk index to nuke*/
1253 used_disk_idx = next_used_idx;
1255 } /*Remove inactive used disks*/
1258 * If we've had to add or remove disks to/from the used list,
1259 * or if the frame width has changed, we recompute the light
1260 * locations before returning.
1262 if (fix_light_locs || a_width_changed)
1263 scout_RecomputeLightLocs(a_srvline);
1266 * Return the (possibly new) size of the current server record.
1268 return(a_srvline->num_lines);
1270 } /*mini_PrintDiskStats*/
1272 /*------------------------------------------------------------------------
1276 * Handler routine passed to the fsprobe module. This handler is
1277 * called immediately after a poll of all the FileServers has taken
1278 * place. Its job is to write out selected data to the scout
1289 * All it needs to know is exported by the fsprobe module, namely
1290 * the data structure where the probe results are stored.
1293 * Recomputes disk light locations in response to reshaping the
1294 * scout window or from adding/deleting disk lights to/from
1295 * individual servers.
1296 *------------------------------------------------------------------------*/
1302 static char rn[] = "FS_Handler"; /*Routine name*/
1303 int code; /*Return code*/
1304 struct ProbeViceStatistics *curr_stats; /*Ptr to current stats*/
1305 int *curr_probeOK; /*Ptr to current probeOK field*/
1306 int curr_srvidx; /*Current server index*/
1307 char s[128]; /*String buffer*/
1308 static char sblank[] = " "; /*Blank string buffer*/
1309 char *sp; /*Ptr to string buffer*/
1310 struct mini_line *curr_line; /*Current mini-line*/
1311 int curr_line_num; /*Current line number*/
1312 struct gator_lightobj *lightdata; /*Private light data*/
1313 int setting; /*Light setting (on or off)*/
1314 int old_width; /*Keep the old width value*/
1315 int width_changed; /*Has the frame width changed?*/
1316 int fix_line_num; /*Line number needs fixing*/
1317 int delta_line_num; /*Change in line number*/
1320 * See if the size of the scout frame has changed since the last
1323 old_width = scout_frameDims.maxx;
1325 fprintf(scout_debugfd, "[%s] Calling wop_getdimensions\n", rn);
1326 fflush(scout_debugfd);
1328 WOP_GETDIMENSIONS(scout_frame->window, &scout_frameDims);
1329 width_changed = (old_width == scout_frameDims.maxx) ? 0 : 1;
1331 fprintf(scout_debugfd,
1332 "[%s] Frame dimensions are %d rows, %d columns\n",
1333 rn, scout_frameDims.maxy, scout_frameDims.maxx);
1335 fprintf(scout_debugfd,
1336 "[%s] Width has changed from %d columns\n", rn, old_width);
1337 fflush(scout_debugfd);
1341 * Print out the selected fields for each server. We actually change
1342 * the light's label to the new data.
1344 curr_line = scout_screen.line;
1345 curr_stats = fsprobe_Results.stats;
1346 curr_probeOK = fsprobe_Results.probeOK;
1347 curr_line_num = curr_line->base_line;
1350 for (curr_srvidx = 0;
1351 curr_srvidx < scout_screen.numServers;
1354 * If the current server record is set up on the wrong line, fix
1355 * the non-disk light objects directly, and remember to fix the
1356 * disk light objects later on.
1358 if (curr_line->base_line != curr_line_num) {
1360 delta_line_num = curr_line_num - curr_line->base_line;
1361 curr_line->base_line = curr_line_num;
1362 scout_SetNonDiskLightLine(curr_line, curr_line_num);
1369 lightdata = (struct gator_lightobj *)(curr_line->currConns_lp->o_data);
1370 if (*curr_probeOK == 0) {
1372 sprintf(sp, "%d", curr_stats->CurrentConnections);
1376 code = mini_justify(sp, /*Src buffer*/
1377 lightdata->label, /*Dest buffer*/
1378 LIGHTOBJ_CONN_WIDTH, /*Dest's width*/
1379 SCOUT_RIGHT_JUSTIFY, /*Right-justify*/
1380 SCOUT_LEFT_TRUNC, /*Left-truncate*/
1381 SCOUT_ISNT_LDISK); /*Not a labeled disk*/
1382 if (scout_attn_conn != SCOUT_ATTN_NOTUSED &&
1383 curr_stats->CurrentConnections >= scout_attn_conn)
1387 code = gator_light_set(curr_line->currConns_lp, setting);
1389 lightdata = (struct gator_lightobj *)(curr_line->fetches_lp->o_data);
1390 if (*curr_probeOK == 0) {
1392 sprintf(sp, "%d", curr_stats->TotalFetchs);
1396 code = mini_justify(sp, /*Src buffer*/
1397 lightdata->label, /*Dest buffer*/
1398 LIGHTOBJ_FETCH_WIDTH, /*Dest's width*/
1399 SCOUT_RIGHT_JUSTIFY, /*Right-justify*/
1400 SCOUT_LEFT_TRUNC, /*Left-truncate*/
1401 SCOUT_ISNT_LDISK); /*Not a labeled disk*/
1402 if (scout_attn_fetch != SCOUT_ATTN_NOTUSED &&
1403 curr_stats->TotalFetchs >= scout_attn_fetch)
1407 code = gator_light_set(curr_line->fetches_lp, setting);
1409 lightdata = (struct gator_lightobj *)(curr_line->stores_lp->o_data);
1410 if (*curr_probeOK == 0) {
1412 sprintf(sp, "%d", curr_stats->TotalStores);
1416 code = mini_justify(sp, /*Src buffer*/
1417 lightdata->label, /*Dest buffer*/
1418 LIGHTOBJ_STORE_WIDTH, /*Dest's width*/
1419 SCOUT_RIGHT_JUSTIFY, /*Right-justify*/
1420 SCOUT_LEFT_TRUNC, /*Left-truncate*/
1421 SCOUT_ISNT_LDISK); /*Not a labeled disk*/
1422 if (scout_attn_store != SCOUT_ATTN_NOTUSED &&
1423 curr_stats->TotalStores >= scout_attn_store)
1427 code = gator_light_set(curr_line->stores_lp, setting);
1429 lightdata = (struct gator_lightobj *)(curr_line->workstations_lp->o_data);
1430 if (*curr_probeOK == 0) {
1432 sprintf(sp, "%d", curr_stats->WorkStations);
1436 code = mini_justify(sp, /*Src buffer*/
1437 lightdata->label, /*Dest buffer*/
1438 LIGHTOBJ_WK_WIDTH, /*Dest's width*/
1439 SCOUT_RIGHT_JUSTIFY, /*Right-justify*/
1440 SCOUT_LEFT_TRUNC, /*Left-truncate*/
1441 SCOUT_ISNT_LDISK); /*Not a labeled disk*/
1442 if (scout_attn_workstations != SCOUT_ATTN_NOTUSED &&
1443 curr_stats->WorkStations >= scout_attn_workstations)
1447 code = gator_light_set(curr_line->workstations_lp, setting);
1450 * We turn the server light on if there was an error in the
1451 * current probe (e.g., if the curr_probeOK field is non-zero.
1452 * (Don't forget to fix the light's line if it needs it).
1454 setting = (*curr_probeOK) ? 1 : 0;
1455 code = gator_light_set(curr_line->srvName_lp, setting);
1458 * Print out the disk statistics. The value returned is the
1459 * number of lines taken up by the server record (or 0 if
1460 * something went wrong).
1463 mini_PrintDiskStats(curr_line, /*Ptr to server line*/
1464 curr_stats, /*Fresh disk stats*/
1465 *curr_probeOK, /*Was probe OK?*/
1466 width_changed, /*Has the width changed?*/
1467 fix_line_num, /*Fix the line number?*/
1468 delta_line_num);/*Change in line number*/
1470 fprintf(stderr, "[%s] Error in printing out disk statistics\n",
1475 curr_line_num += code;
1478 * Advance the current mini_line, stats source, and probe success
1485 } /*for each server probed*/
1488 * Display the scout frame.
1490 sprintf(s, "Probe %d results", fsprobe_Results.probeNum);
1491 gtxframe_DisplayString(scout_frame, s);
1492 WOP_DISPLAY(scout_gwin);
1495 * Return the happy news.
1501 /*------------------------------------------------------------------------
1505 * Initialize each line in the mini_screen.
1508 * struct sockaddr_in *a_skt : Ptr to server socket info.
1509 * int a_lineNum; : Line number being created.
1510 * struct mini_line *a_line : Ptr to mini_line to set up.
1511 * char *a_srvname : Printable server name.
1515 * Error value otherwise.
1518 * Nothing interesting.
1522 *------------------------------------------------------------------------*/
1524 static int init_mini_line(a_skt, a_lineNum, a_line, a_srvname)
1525 struct sockaddr_in *a_skt;
1527 struct mini_line *a_line;
1530 { /*init_mini_line*/
1532 static char rn[] = "init_mini_line"; /*Routine name*/
1533 int curr_x; /*Current X position*/
1534 int curr_y; /*Current Y position*/
1535 char s[128]; /*Scratch buffer*/
1536 int code; /*Return code*/
1537 struct gator_lightobj *lightdata; /*Private light data*/
1540 fprintf(scout_debugfd, "[%s] Called for base line %d\n",
1542 fflush(scout_debugfd);
1546 * Fill in the top fields (except the disk fields, which will be
1547 * done elsewhere), then create the light onodes.
1549 memcpy((char *)&(a_line->skt), (char *)a_skt, sizeof(struct sockaddr_in));
1550 a_line->numDisks = 0;
1551 a_line->base_line = a_lineNum + scout_screen.base_line_num;
1552 a_line->num_lines = 1;
1555 curr_y = a_line->base_line;
1556 if ((a_line->currConns_lp =
1557 mini_initLightObject("Conns",
1560 LIGHTOBJ_CONN_WIDTH,
1562 == (struct onode *)0) {
1563 fprintf(stderr, "[%s:%s] Can't create currConns light object\n",
1567 curr_x += LIGHTOBJ_CONN_WIDTH + 1;
1569 if ((a_line->fetches_lp =
1570 mini_initLightObject("Fetches",
1573 LIGHTOBJ_FETCH_WIDTH,
1574 scout_frame->window))
1575 == (struct onode *)0) {
1576 fprintf(stderr, "[%s:%s] Can't create fetches light object\n",
1580 curr_x += LIGHTOBJ_FETCH_WIDTH + 1;
1582 if ((a_line->stores_lp =
1583 mini_initLightObject("Stores",
1586 LIGHTOBJ_STORE_WIDTH,
1587 scout_frame->window))
1588 == (struct onode *)0) {
1589 fprintf(stderr, "[%s:%s] Can't create stores light object\n",
1593 curr_x += LIGHTOBJ_STORE_WIDTH + 1;
1595 if ((a_line->workstations_lp =
1596 mini_initLightObject("WrkStn",
1600 scout_frame->window))
1601 == (struct onode *)0) {
1602 fprintf(stderr, "[%s:%s] Can't create workstations light object\n",
1606 curr_x += LIGHTOBJ_WK_WIDTH + 1;
1608 if ((a_line->srvName_lp =
1609 mini_initLightObject(a_srvname,
1612 LIGHTOBJ_SRVNAME_WIDTH,
1613 scout_frame->window))
1614 == (struct onode *)0) {
1615 fprintf(stderr, "[%s:%s] Can't create server name light object\n",
1619 sprintf(s, "%s", a_srvname);
1620 lightdata = (struct gator_lightobj *)(a_line->srvName_lp->o_data);
1621 code = mini_justify(s, /*Src buffer*/
1622 lightdata->label, /*Dest buffer*/
1623 LIGHTOBJ_SRVNAME_WIDTH, /*Dest's width*/
1624 SCOUT_CENTER, /*Centered*/
1625 SCOUT_RIGHT_TRUNC, /*Right-truncate*/
1626 SCOUT_ISNT_LDISK); /*Not a labeled disk*/
1628 fprintf(stderr, "[%s] Can't center server name inside of light object\n", rn);
1631 curr_x += LIGHTOBJ_SRVNAME_WIDTH + 1;
1633 if (scout_initDiskLightObjects(a_line, scout_frame->window)) {
1634 fprintf(stderr, "[%s:%s] Can't create disk light objects\n",
1640 * Finally, return the happy news.
1644 } /*init_mini_line*/
1646 /*------------------------------------------------------------------------
1650 * Workhorse routine that starts up the FileServer probe.
1653 * int a_numservers : Length of above list.
1654 * struct cmd_item *a_srvname : List of FileServer machines to
1656 * int a_pkg : Window package to use.
1660 * Error value otherwise.
1663 * Nothing interesting.
1667 *------------------------------------------------------------------------*/
1669 static int execute_scout(a_numservers, a_srvname, a_pkg)
1671 struct cmd_item *a_srvname;
1676 static char rn[] = "execute_scout"; /*Routine name*/
1677 static char fullsrvname[128]; /*Full server name*/
1678 register int code; /*Return code*/
1679 struct sockaddr_in *FSSktArray; /*Server socket array*/
1680 int sktbytes; /*Num bytes in above*/
1681 struct sockaddr_in *curr_skt; /*Ptr to current socket*/
1682 struct cmd_item *curr_item; /*Ptr to current cmd item*/
1683 struct hostent *he; /*Host entry*/
1684 struct mini_line *mini_lines; /*Ptr to all mini-lines*/
1685 struct mini_line *curr_line; /*Ptr to current line*/
1686 int i; /*Generic loop variable*/
1687 int mini_line_bytes; /*Num bytes in mini_lines*/
1688 struct timeval tv; /*Time structure*/
1689 int linenum; /*Current mini-line number*/
1691 PROCESS pid; /*Main LWP process ID*/
1692 PROCESS gxlistener_ID; /*Input Server LWP process ID*/
1694 struct gator_lightobj *lightdata; /*Private light data*/
1697 fprintf(scout_debugfd, "[%s] Called\n", rn);
1698 fflush(scout_debugfd);
1702 * We have to initialize LWP support before we start up any of
1706 code = LWP_InitializeProcessSupport(LWP_NORMAL_PRIORITY, &pid);
1708 fprintf(stderr, "[%s:%s] Can't initialize LWP\n", pn, rn);
1709 scout_CleanExit(code);
1714 * Initialize the gtx package.
1717 fprintf(stderr, "[%s:%s] Starting up gtx package\n", pn, rn);
1719 scout_gwin = gtx_Init(0, /*Don't start up InputServer yet*/
1720 -1); /*Type of window package*/
1721 if (scout_gwin == (struct gwin *)0) {
1722 fprintf(stderr, "[%s:%s] Call to gtx_Init() failed!\n", pn, rn);
1727 * Remember we've set up gtx so we can exit cleanly from now on.
1729 scout_gtx_initialized = 1;
1732 * Create the frame everything will go into, set it up as our only
1733 * frame for this window.
1735 scout_frame = gtxframe_Create();
1736 if (scout_frame == (struct gtx_frame *)0) {
1737 fprintf(stderr, "[%s:%s] Call to gtxframe_Create() failed!\n", pn, rn);
1740 gtxframe_SetFrame(scout_gwin, scout_frame);
1741 WOP_GETDIMENSIONS(scout_frame->window, &scout_frameDims);
1744 * Allocate an array of sockets to describe each FileServer we'll be
1747 sktbytes = a_numservers * sizeof(struct sockaddr_in);
1748 FSSktArray = (struct sockaddr_in *) malloc(sktbytes);
1749 if (FSSktArray == (struct sockaddr_in *)0) {
1751 "[%s] Can't malloc() %d sockaddrs (%d bytes) for the given servers\n",
1752 rn, a_numservers, sktbytes);
1753 scout_CleanExit(-1);
1755 memset(FSSktArray, 0, sktbytes);
1758 * Sweep through the server names provided, filling in the socket
1759 * info for each. Take into account the fact that we may have a
1760 * base name associated for each.
1762 curr_item = a_srvname;
1763 curr_skt = FSSktArray;
1765 if (*scout_basename == '\0')
1766 sprintf(fullsrvname, "%s", curr_item->data);
1768 sprintf(fullsrvname, "%s.%s", curr_item->data, scout_basename);
1769 he = hostutil_GetHostByName(fullsrvname);
1770 if (he == (struct hostent *)0) {
1771 fprintf(stderr, "[%s] Can't get host info for '%s'\n",
1775 memcpy(&(curr_skt->sin_addr.s_addr), he->h_addr, 4);
1776 curr_skt->sin_family = htons(AF_INET); /*Internet family*/
1777 curr_skt->sin_port = htons(7000); /*FileServer port*/
1780 * Bump our pointers.
1782 curr_item = curr_item->next;
1785 } /*Build socket entry for each server*/
1788 * Create the set of mini-lines, one per server.
1790 mini_line_bytes = a_numservers * sizeof(struct mini_line);
1791 mini_lines = (struct mini_line *) malloc(mini_line_bytes);
1792 if (mini_lines == (struct mini_line *)0) {
1793 fprintf(stderr, "[%s] Can't malloc() %d bytes for %d screen lines\n",
1794 rn, mini_line_bytes, a_numservers);
1797 memset(mini_lines, 0, mini_line_bytes);
1800 * Set up each line in the mini_lines, creating and initializing
1801 * its light objects.
1803 scout_screen.base_line_num = 4;
1804 curr_line = mini_lines;
1805 curr_skt = FSSktArray;
1807 curr_item = a_srvname;
1808 gtxframe_ClearList(scout_frame);
1811 * Create the light objects that server as banner lines. Remember
1812 * to take into account the server basename, if any, and the name
1813 * of the host that scout if running on, if that's wanted.
1815 if (scout_showhostname) {
1816 if (*scout_basename == '\0')
1817 sprintf(scout_Banner, "[%s] %s", scout_hostname, "Scout");
1819 sprintf(scout_Banner, "[%s] Scout for %s",
1820 scout_hostname, scout_basename);
1823 if (*scout_basename == '\0')
1824 sprintf(scout_Banner, "%s", " Scout");
1826 sprintf(scout_Banner, " Scout for %s", scout_basename);
1829 mini_initLightObject("Banner 0", /*Light name*/
1832 scout_frameDims.maxx, /*Width*/
1833 scout_gwin); /*Window*/
1834 if (scout_banner0_lp != (struct onode *)0) {
1835 lightdata = (struct gator_lightobj *)(scout_banner0_lp->o_data);
1836 code = mini_justify(scout_Banner,
1838 scout_frameDims.maxx,
1842 code = gator_light_set(scout_banner0_lp, 1);
1843 code = gtxframe_AddToList(scout_frame, scout_banner0_lp);
1847 fprintf(scout_debugfd, "[%s] Scout label is '%s', %d chars\n",
1848 rn, lightdata->label, strlen(lightdata->label));
1852 mini_initLightObject("Banner 1", /*Light name*/
1855 scout_frameDims.maxx, /*Width*/
1856 scout_gwin); /*Window*/
1857 if (scout_banner1_lp != (struct onode *)0) {
1858 if (scout_attn_disk_mode == SCOUT_DISKM_PCUSED) {
1859 sprintf(scout_Banner, "%s > %s%% used",
1861 scout_attn_disk_pcusedstr);
1864 sprintf(scout_Banner, "%s < %d blocks free",
1865 scout_LightLabels, scout_attn_disk_minfree);
1867 lightdata = (struct gator_lightobj *)(scout_banner1_lp->o_data);
1868 code = mini_justify(scout_Banner,
1870 scout_frameDims.maxx,
1875 code = gtxframe_AddToList(scout_frame, scout_banner1_lp);
1879 mini_initLightObject("Banner 2", /*Light name*/
1882 scout_frameDims.maxx, /*Width*/
1883 scout_gwin); /*Window*/
1884 if (scout_banner2_lp != (struct onode *)0) {
1885 lightdata = (struct gator_lightobj *)(scout_banner2_lp->o_data);
1886 code = mini_justify(scout_LightLabelUnd,
1888 scout_frameDims.maxx,
1892 code = gtxframe_AddToList(scout_frame, scout_banner2_lp);
1895 for (i=0; i < a_numservers; i++) {
1896 code = init_mini_line(curr_skt, linenum, curr_line, curr_item->data);
1898 fprintf(stderr, "[%s] Can't initialize line for server %d\n", rn, i);
1904 curr_item = curr_item->next;
1908 * Now that all lines have been set up, we feed in the light items
1909 * created. Note: the disk lights are entered at a later time,
1910 * as they enter the used disk list for each server.
1912 curr_line = mini_lines;
1913 for (i = 0; i < a_numservers; i++) {
1914 code = gtxframe_AddToList(scout_frame, curr_line->currConns_lp);
1917 "[%s] Can't add client connections light to display list\n",
1922 code = gtxframe_AddToList(scout_frame, curr_line->fetches_lp);
1924 fprintf(stderr, "[%s] Can't add fetches light to frame display list\n",
1929 code = gtxframe_AddToList(scout_frame, curr_line->stores_lp);
1931 fprintf(stderr, "[%s] Can't add stores light to frame display list\n",
1936 code = gtxframe_AddToList(scout_frame, curr_line->workstations_lp);
1938 fprintf(stderr, "[%s] Can't add workstation light to display list\n",
1943 code = gtxframe_AddToList(scout_frame, curr_line->srvName_lp);
1945 fprintf(stderr, "[%s] Can't add server name light to display list\n",
1951 * Move down to the next server record.
1955 } /*Add lights in server records to display list*/
1959 * Set up the minimal keymap.
1962 keymap_BindToString(scout_frame->keymap, /*Ptr to keymap*/
1963 "e", /*Key to bind*/
1964 ExitCmd, /*Cmd to execute*/
1966 (char *)0); /*Ptr to rock*/
1968 fprintf(stderr, "[%s] Can't bind key `e', code is %d\n", rn, code);
1974 * Finish setting up the overall mini_screen structure.
1976 scout_screen.numServers = a_numservers;
1977 scout_screen.line = mini_lines;
1978 WOP_GETDIMENSIONS(scout_frame->window, &scout_frameDims);
1981 * Start up the fsprobe package, which will gather FileServer
1982 * statistics for us on a regular basis.
1984 gtxframe_DisplayString(scout_frame, "Establishing File Server connection(s)...");
1985 code = fsprobe_Init(a_numservers, /*Num FileServers to probe*/
1986 FSSktArray, /*FileServer socket array*/
1987 scout_probefreq, /*Probe frequency*/
1988 FS_Handler, /*Handler routine*/
1989 0); /*Turn debugging output off*/
1991 scout_debug); /*Turn debugging output off*/
1994 fprintf(stderr, "[%s] Error returned by fsprobe_Init: %d\n", rn, code);
2000 * Start up the input server LWP for our window.
2004 LWP_CreateProcess(gtx_InputServer, /*Fcn to start up*/
2005 8192, /*Stack size in bytes*/
2006 LWP_NORMAL_PRIORITY, /*Priority*/
2007 scout_gwin, /*Params: Ptr to window*/
2008 "gx-listener", /*Name to use*/
2009 &gxlistener_ID); /*Returned LWP process ID*/
2012 code = gtx_InputServer(scout_gwin);
2014 fprintf(stderr, "[%s] Error exit from gtx_InputServer(), error is %d\n",
2016 scout_CleanExit(code);
2020 * We fall into a loop, sleeping forever.
2023 tv.tv_sec = 60*60; /*Sleep for an hour at a time*/
2025 code = select(0, /*Num fds*/
2026 0, /*Descriptors ready for reading*/
2027 0, /*Descriptors ready for writing*/
2028 0, /*Descriptors with exceptional conditions*/
2029 &tv); /*Timeout structure*/
2034 * How did we get here? Oh, well, clean up our windows and
2035 * return sweetness and light anyway.
2037 WOP_CLEANUP(&scout_gwin);
2043 /*------------------------------------------------------------------------
2047 * Given a pointer to the list of servers we'll be polling,
2048 * compute the length of the list.
2051 * struct cmd_item *a_firstItem : Ptr to first item in list.
2054 * Length of the above list.
2057 * Nothing interesting.
2061 *------------------------------------------------------------------------*/
2063 static int countServers(a_firstItem)
2064 struct cmd_item *a_firstItem;
2068 int list_len; /*List length*/
2069 struct cmd_item *curr_item; /*Ptr to current item*/
2072 curr_item = a_firstItem;
2079 curr_item = curr_item->next;
2089 /*------------------------------------------------------------------------
2090 * scout_AdoptThresholds
2093 * Parse and adopt one or more threshold values, as read off the
2097 * struct cmd_item *a_thresh_item : Ptr to item on command-line
2101 * Nothing (but may exit the entire program on error!)
2104 * Valid keywords are:
2105 * conn, disk, fetch, store, ws
2106 * The disk value, if it has a % sign, signifies that attention
2107 * will be triggered when the disk is more than that percentage
2108 * full; otherwise, it will specify the minimum number of free
2113 *------------------------------------------------------------------------*/
2115 static void scout_AdoptThresholds(a_thresh_item)
2116 struct cmd_item *a_thresh_item;
2118 { /*scout_AdoptThresholds*/
2121 "scout_AdoptThresholds"; /*Routine name*/
2122 struct cmd_item *curr_item; /*Current item*/
2123 char *curr_name; /*Current name half of pair*/
2124 char *curr_value; /*Current value half of pair*/
2125 int diskval_len; /*Length of disk attn value*/
2127 curr_item = a_thresh_item;
2130 * If there isn't a corresponding value for the current
2131 * attention field, bitch & die.
2133 if (curr_item->next == (struct cmd_item *)0) {
2134 printf("[%s] No threshold value given for '%s'\n",
2135 rn, curr_item->data);
2136 scout_CleanExit(-1);
2139 curr_name = curr_item->data;
2140 curr_value = curr_item->next->data;
2142 if (strcmp(curr_name, "conn") == 0) {
2144 fprintf(scout_debugfd,
2145 "[%s] Setting conn attn value to %d (default %d)\n",
2146 rn, curr_value, scout_attn_conn);
2147 fflush(scout_debugfd);
2149 scout_attn_conn = atoi(curr_value);
2151 else if (strcmp(curr_name, "disk") == 0) {
2153 * If there's a '%' as the last character in the value,
2154 * we use percentage mode.
2156 diskval_len = strlen(curr_value);
2157 if (curr_value[diskval_len-1] == '%') {
2158 curr_value[diskval_len-1] = '\0';
2160 fprintf(scout_debugfd,
2161 "[%s] New disk attn value: 0.%s used (default %f)\n",
2162 rn, curr_value, scout_attn_disk_pcused);
2163 fflush(scout_debugfd);
2165 sprintf(scout_attn_disk_pcusedstr, "%s", curr_value);
2166 scout_attn_disk_pcused =
2167 ((float)(atoi(curr_value)))/((float)(100));
2168 } /*Percentage mode*/
2171 fprintf(scout_debugfd,
2172 "[%s] New disk attn value: %s min free (default %d)\n",
2173 rn, atoi(curr_value), scout_attn_disk_pcused);
2174 fflush(scout_debugfd);
2176 scout_attn_disk_mode = SCOUT_DISKM_MINFREE;
2177 scout_attn_disk_minfree = atoi(curr_value);
2178 } /*Min free blocks mode*/
2180 else if (strcmp(curr_name, "fetch") == 0) {
2182 fprintf(scout_debugfd,
2183 "[%s] Setting fetch attn value to %d (default %d)\n",
2184 rn, curr_value, scout_attn_fetch);
2185 fflush(scout_debugfd);
2187 scout_attn_fetch = atoi(curr_value);
2189 else if (strcmp(curr_name, "store") == 0) {
2191 fprintf(scout_debugfd,
2192 "[%s] Setting store attn value to %d (default %d)\n",
2193 rn, curr_value, scout_attn_store);
2194 fflush(scout_debugfd);
2196 scout_attn_store = atoi(curr_value);
2198 else if (strcmp(curr_name, "ws") == 0) {
2200 fprintf(scout_debugfd,
2201 "[%s] Setting workstation attn value to %d (default %d)\n",
2202 rn, curr_value, scout_attn_workstations);
2203 fflush(scout_debugfd);
2205 scout_attn_workstations = atoi(curr_value);
2208 printf("[%s] Unknown attention item: '%s'\n", rn, curr_item->data);
2209 scout_CleanExit(-1);
2213 * Advance past the just-processed pair.
2215 curr_item = curr_item->next->next;
2217 } /*Interpret each name-value pair*/
2219 } /*scout_AdoptThresholds*/
2221 /*------------------------------------------------------------------------
2225 * Routine called when Scout is invoked, responsible for basic
2226 * initialization, command line parsing, and calling the
2227 * routine that does all the work.
2230 * as : Command syntax descriptor.
2231 * arock : Associated rock (not used here).
2234 * Zero (but may exit the entire program on error!)
2237 * Nothing interesting.
2240 * Initializes this program.
2241 *------------------------------------------------------------------------*/
2243 static int scoutInit(as, arock)
2244 struct cmd_syndesc *as;
2249 static char rn[] = "scoutInit"; /*Routine name*/
2250 int code; /*Return code*/
2251 int wpkg_to_use; /*Window package to use*/
2252 int server_count; /*Number of servers to watch*/
2253 char *debug_filename; /*Name of debugging output file*/
2256 fprintf(scout_debugfd, "[%s] Called\n", rn);
2257 fflush(scout_debugfd);
2260 if (as->parms[P_DEBUG].items != 0) {
2262 debug_filename = as->parms[P_DEBUG].items->data;
2263 scout_debugfd = fopen(debug_filename, "w");
2264 if (scout_debugfd == (FILE *)0) {
2265 printf("[%s] Can't open debugging file '%s'!\n", rn, debug_filename);
2266 scout_CleanExit(-1);
2268 fprintf(scout_debugfd, "[%s] Writing to Scout debugging file '%s'\n",
2269 rn, debug_filename);
2272 wpkg_to_use = atoi(as->parms[P_PACKAGE].items->data);
2274 wpkg_to_use = 2; /*Always use curses for now*/
2276 fprintf(stderr, "[%s:%s] Using graphics package %d: ", pn, rn, wpkg_to_use);
2277 switch (wpkg_to_use) {
2278 case GATOR_WIN_CURSES:
2279 fprintf(stderr, "curses\n");
2281 case GATOR_WIN_DUMB:
2282 fprintf(stderr, "dumb terminal\n");
2285 fprintf(stderr, "X11\n");
2288 fprintf(stderr, "Illegal graphics package: %d\n", wpkg_to_use);
2289 scout_CleanExit(-1);
2290 } /*end switch (wpkg_to_use)*/
2293 if (as->parms[P_FREQ].items != 0)
2294 scout_probefreq = atoi(as->parms[P_FREQ].items->data);
2296 scout_probefreq = 60;
2299 * See if we've been fed a base server name.
2301 if (as->parms[P_BASE].items != 0)
2302 sprintf(scout_basename, "%s", as->parms[P_BASE].items->data);
2304 *scout_basename = '\0';
2307 * Count the number of servers we've been asked to monitor.
2309 server_count = countServers(as->parms[P_SERVER].items);
2312 * Create a line of blanks, a generally-useful thing.
2314 sprintf(scout_blankline, "%255s", " ");
2317 * Pull in the name of the host we're executing on if we've been
2318 * asked to. If we can't get the name, we provide a default.
2320 if (as->parms[P_HOST].items != 0) {
2321 scout_showhostname = 1;
2322 *scout_hostname = '\0';
2323 code = gethostname(scout_hostname, 128);
2325 sprintf(scout_hostname, "%s", "*No Hostname*");
2329 * Pull in any and all attention/highlighting thresholds.
2331 if (as->parms[P_ATTENTION].items != 0)
2332 scout_AdoptThresholds(as->parms[P_ATTENTION].items);
2335 * Now, drive the sucker.
2337 code = execute_scout(server_count, /*Num servers*/
2338 as->parms[P_SERVER].items, /*Ptr to srv names*/
2339 wpkg_to_use); /*Graphics pkg*/
2341 fprintf(stderr, "[%s] Error executing scout: %d\n", rn, code);
2342 scout_CleanExit(-1);
2346 * We initialized (and ran) correctly, so return the good news.
2352 #include "AFS_component_version_number.c"
2360 register afs_int32 code; /*Return code*/
2361 register struct cmd_syndesc *ts; /*Ptr to cmd line syntax descriptor*/
2363 #ifdef AFS_AIX32_ENV
2365 * The following signal action for AIX is necessary so that in case of a
2366 * crash (i.e. core is generated) we can include the user's data section
2367 * in the core dump. Unfortunately, by default, only a partial core is
2368 * generated which, in many cases, isn't too useful.
2370 struct sigaction nsa;
2372 sigemptyset(&nsa.sa_mask);
2373 nsa.sa_handler = SIG_DFL;
2374 nsa.sa_flags = SA_FULLDUMP;
2375 sigaction(SIGSEGV, &nsa, NULL);
2378 * Set up the commands we understand.
2380 ts = cmd_CreateSyntax("initcmd", scoutInit, 0,
2381 "initialize the program");
2382 cmd_AddParm(ts, "-server", CMD_LIST, CMD_REQUIRED,
2383 "FileServer name(s) to monitor");
2384 cmd_AddParm(ts, "-basename", CMD_SINGLE, CMD_OPTIONAL,
2385 "base server name");
2387 cmd_AddParm(ts, "-package", CMD_SINGLE, CMD_REQUIRED,
2388 "Graphics package to use");
2390 cmd_AddParm(ts, "-frequency", CMD_SINGLE, CMD_OPTIONAL,
2391 "poll frequency, in seconds");
2392 cmd_AddParm(ts, "-host", CMD_FLAG, CMD_OPTIONAL,
2393 "show name of host you're running on");
2394 cmd_AddParm(ts, "-attention", CMD_LIST, CMD_OPTIONAL,
2395 "specify attention (highlighting) level");
2396 cmd_AddParm(ts, "-debug", CMD_SINGLE, CMD_OPTIONAL,
2397 "turn debugging output on to the named file");
2400 * Parse command-line switches & execute the test, then get the heck
2403 code = cmd_Dispatch(argc, argv);
2406 fprintf(stderr, "[%s:%s] Call to cmd_Dispatch() failed; code is %d\n", pn, rn, code);