home *** CD-ROM | disk | FTP | other *** search
- Path: uunet!island!argv
- From: argv@island.uu.net (Dan Heller)
- Newsgroups: comp.sources.x
- Subject: v03i103: xnetload -- multiple host xload program, Part01/01
- Message-ID: <744@island.uu.net>
- Date: 8 May 89 06:22:03 GMT
- Sender: news@island.uu.net
- Organization: Island Graphics, Marin County, California
- Lines: 694
- Approved: island!argv@sun.com
-
- Submitted-by: Mike Berkley <jmberkley@watnext.waterloo.edu>
- Posting-number: Volume 3, Issue 103
- Archive-name: xnetload/part01
-
- [ I compiled, but didn't run this (we don't use rwhod here). Check the
- makefile before compiling or use the imakefile. The shar given makes
- its own directory. --argv ]
-
- What follows was written by the author:
-
- xnetload gives the system load for a list of remote machines by using
- rwhod statistics. The load for the local machine is also displayed,
- but is calculated using the standard Load widget routines, (this means
- that xnetload needs to be setgid kmem.)
-
- xnetload was written mostly as a tool to learning how to use the
- toolkit. I was amazed at what the toolkit can do in not very many
- lines of code.
-
- Don't forget to read the man page (there's a caveat about
- "*Load*update"). Send comments, bug reports, etc. to
- jmberkley@watnext.waterloo.edu.
-
- ---------------------------------------------------------------------------
- # This is a shell archive. Remove anything before this line,
- # then unpack it by saving it in a file and typing "sh file".
- #
- # Wrapped by watnext!jmberkley on Tue May 2 10:56:54 EDT 1989
- # Contents: xnetload/ xnetload/README xnetload/Imakefile xnetload/xnetload.c
- # xnetload/xnetload.1 xnetload/Makefile xnetload/AUTHOR
- # xnetload/patchlevel.h
-
- echo mkdir - xnetload
- mkdir xnetload
- chmod u=rwx,g=rx,o=rx xnetload
-
- echo x - xnetload/README
- sed 's/^@//' > "xnetload/README" <<'@//E*O*F xnetload/README//'
- README for xnetload
- Mike Berkley, April 1989
-
- xnetload gives the system load for a list of remote machines by using
- rwhod statistics. The load for the local machine is also displayed,
- but is calculated using the standard Load widget routines, (this means
- that xnetload needs to be setgid kmem.)
-
- There's an option to turn off the local load, -nolocal, which would
- allow you to run with xnetload non-setgid. Alternatively, you can
- compile xnetload with -DNOLOCAL (see the Imakefile and Makefile).
-
- xnetload was developed on a uVax running Ultrix. It also compiles and
- runs on Suns (both SunOS 3.5 and 4) and Sequents running Dynix. Of
- course, there are some little glitches: the Makefile needs to be
- altered and you may need to find a memcpy() somewhere.
-
- xnetload was written mostly as a tool to learning how to use the
- toolkit. I was amazed at what the toolkit can do in not very many
- lines of code.
-
- Since this was an experiment/learning tool, I'm sure that I did not
- follow all of the correct X guidelines.
-
- The getload() routine is just my own kludge to read rwhod stats. It
- works, but it is replaceable. Ideally, I would like to use some kind
- of system call like Sun 4's RPC versions of rwho and rup command, then
- there would not be any dependency on rwhod. If you are living on a
- system that does not use rwhod, or you would like a more efficient way
- of determining system load, then you can replace getload() without
- breaking the rest of the program.
-
- ** Note - if you define "*Load*update", but not **
- ** "xnetload*remote*update", then xnetload will **
- ** set both the remote and local update times to **
- ** the "*Load*update" value. If this time is **
- ** much less than the rwhod update period, then **
- ** the remote load displays will look more like **
- ** bar graphs. **
-
- Send comments, bug reports, etc. to jmberkley@watnext.waterloo.edu.
-
-
- ******************************************
- * Mike Berkley, University of Waterloo *
- * PAMI Lab *
- * jmberkley@watnext.waterloo.edu *
- * {utai,uunet}!watmath!watnext!jmberkley *
- ******************************************
- @//E*O*F xnetload/README//
- chmod u=rw,g=r,o=r xnetload/README
-
- echo x - xnetload/Imakefile
- sed 's/^@//' > "xnetload/Imakefile" <<'@//E*O*F xnetload/Imakefile//'
- #
- # Imakefile for xnetload
- #
- # Written by: Mike Berkley, jmberkley@watnext.waterloo.edu, 1989
- #
- # Permission to use, copy, modify and distribute (without charge) this
- # software and its documentation is granted, provided that this comment
- # is retained.
-
- #
- # Since xnetload finds the local machine's load using the standard Load
- # widget stuff, it needs to be able to read kmem, i.e. setgid kmem. If
- # you do not want this, then define NOLOCAL
- # DEFINES = -O -DNOLOCAL
-
- INCLUDES = -I$(TOP) -I$(TOP)/X11
-
- # Dynix doesn't have -L option on load, but I have left changing the
- # XLIB specification up to individual sites. Dynix and our Sun 3.5
- # don't come with a memcpy, so you'll have to add in whichever library
- # has memcpy.
- /* LOCAL_LIBRARIES = $(XAWLIB) $(XMULIB) $(XTOOLLIB) $(XLIB) */
- LOCAL_LIBRARIES = -L/usr/software/X11/lib -lXaw -lXmu -lXt -lX11
-
- SRCS = xnetload.c status.c
-
- INSTALLFLAGS = $(INSTKMEMFLAGS)
-
- all: xnetload
-
- SingleProgramTarget(xnetload,xnetload.o,,$(LOCAL_LIBRARIES))
- @//E*O*F xnetload/Imakefile//
- chmod u=rw,g=r,o=r xnetload/Imakefile
-
- echo x - xnetload/xnetload.c
- sed 's/^@//' > "xnetload/xnetload.c" <<'@//E*O*F xnetload/xnetload.c//'
- /*
- * xnetload.c: multiple xload, using rwho statistics
- *
- * Written by: Mike Berkley, jmberkley@watnext.waterloo.edu, 1989
- *
- * Permission to use, copy, modify and distribute (without charge) this
- * software and its documentation is granted, provided that this comment
- * is retained.
- *
- * The X Window system is a copyright of the Massachusetts
- * Institute of Technology
- *
- */
-
- /*
- * xnetload uses the Load widget load proc to get the local
- * machine load. This means that xnetload needs to be setgid
- * kmem. If you do not want this, then define NOLOCAL when compiling.
- */
-
- #include <stdio.h>
- #include <ctype.h>
- #include <netdb.h>
- #include <X11/Xos.h>
- #include <X11/Xlib.h>
- #include <X11/IntrinsicP.h>
- #include <X11/LoadP.h>
- #include <X11/StringDefs.h>
- #include <X11/Shell.h>
- #include <X11/Form.h>
- #include "patchlevel.h"
-
-
- extern void GetStatus(); /* gets rwho load */
- extern char *XtMalloc();
- extern time_t time();
- static Widget Toplevel, Formwin, Statuswin;
-
- #define DEFREMUPDATE 60 /* remote update defaults to 60 seconds */
- #define DOWNTIME (DEFREMUPDATE * 5)
- #define DOWNMSG " DOWN"
- #define RWHODHD "/usr/spool/rwho/whod"
-
- /* arguments to Form widget */
- static Arg Formargs[] = {
- { XtNfromVert, (XtArgVal) NULL }, /* Chain vert from value widget */
- { XtNdefaultDistance, (XtArgVal) 1 }, /* default spacing */
- { XtNresizable, (XtArgVal) TRUE }, /* allow resize */
- };
-
- /* Arguments to load windows */
- static Arg Statusargs[] = {
- { XtNfromVert, (XtArgVal) NULL }, /* Chain vert from .value wid */
- { XtNresizable, (XtArgVal) TRUE }, /* allow resize */
- { XtNlabel, (XtArgVal) NULL }, /* Load title */
- { XtNborderWidth, (XtArgVal) 0 }, /* width for each load wid */
- };
-
- /* Application specific resources - turn off local load display */
- static Boolean Localload;
- static XtResource app_resources[] = {
- { "localload", "LocalLoad", XtRBoolean, sizeof(Boolean),
- (Cardinal) &Localload, XtRString,
- /* if NOLOCAL is defined, then no local is displayed, by default */
- #ifdef NOLOCAL
- "off"
- #else
- "on"
- #endif
- },
- };
-
- /* command line options for local load display */
- /* If compiled NOLOCAL, then off is default, but on still allowed */
- static XrmOptionDescRec app_options[] = {
- #ifdef NOLOCAL
- { "-local", "localload", XrmoptionNoArg, "on" },
- #else
- { "-nolocal", "localload", XrmoptionNoArg, "off" },
- #endif
- };
-
- /* resources specific to the remote load displays */
- /*
- * You're wondering why I'm doing this, right? Well, the default update
- * for the Load widget is 5 seconds (I think), but if rwhod updates the
- * files every 60 seconds, then the load displays will look weird. So, I
- * don't force the user to have a 60 second update, but I at least make
- * this the default.
- */
- static int Remupdate = DEFREMUPDATE;
- static XtResource rem_resources[] = {
- { XtNupdate, XtCInterval, XtRInt, sizeof(int),
- (Cardinal) &Remupdate, XtRInt, (caddr_t) &Remupdate },
- };
-
- /* GetStatus() global vars */
- static char *Label;
- static Arg Labelarg;
-
- /* getload includes */
- /* Dynix doesn't have an rwhod.h file, so here's the struct for that system */
- #ifdef sequent
- struct outmp {
- char out_line[8]; /* tty name */
- char out_name[8]; /* user id */
- long out_time; /* time on */
- };
- struct whod {
- char wd_vers;
- char wd_type;
- char wd_fill[2];
- int wd_sendtime;
- int wd_recvtime;
- char wd_hostname[32];
- int wd_loadav[3];
- int wd_boottime;
- struct whoent {
- struct outmp we_utmp;
- int we_idle;
- } wd_we[1024 / sizeof (struct whoent)];
- };
- #else
- #include <protocols/rwhod.h>
- #endif
-
- main(argc,argv)
- int argc;
- char *argv[];
- {
- int currarg = 1; /* arg counter to walk through hosts */
- char
- *hostname, /* raw host name */
- *labelname; /* label, could be "machine DOWN" */
- struct hostent *host; /* for gethostbyname() */
-
- /* The toolkit tries to open your display if you use -help */
- /* so let's do it the other way */
- if((argc > 1) && !strncmp(argv[1],"-h",2)) {
- usage();
- exit(1);
- }
-
- /* Initialize the top level */
- Toplevel = XtInitialize(*argv[0], "XNetload",
- app_options, XtNumber(app_options), &argc, argv);
- /* Get local vs nolocal */
- XtGetApplicationResources( (Widget)Toplevel, (caddr_t)NULL,
- app_resources, XtNumber(app_resources),
- NULL, (Cardinal) 0);
-
- /* Create a Form widget to contain all of the Loads */
- Formwin =
- XtCreateManagedWidget("shell",
- formWidgetClass,
- Toplevel,
- Formargs,
- XtNumber(Formargs));
-
- /*
- * Load widget reads kmem for local load. Define NOLOCAL if you
- * don't want this.
- */
- if(Localload) {
- /* Get and set label name */
- labelname = XtMalloc(BUFSIZ*sizeof(char));
- gethostname(labelname,BUFSIZ);
- XtSetArg(Statusargs[XtNumber(Statusargs)-1],
- XtNlabel,(XtArgVal)labelname);
-
- /* Create the local load widget */
- Statuswin = XtCreateManagedWidget("local",
- loadWidgetClass,
- Formwin,
- Statusargs,
- XtNumber(Statusargs));
- }
-
- /* Remote Loads */
- /* currarg initialized above */
- for(;currarg < argc;currarg++) {
- /* translate command arg to a hostname */
- host = gethostbyname(argv[currarg]);
- /* if host == NULL, then hostname is junk for some reason */
- if(host) {
- /* allocate memory for hostname */
- if(!(hostname=XtMalloc((strlen(host->h_name)+1)*sizeof(char)))) {
- perror("xnetload: Ran out of memory for name");
- exit(1);
- }
- /* allocate memory for name and downmsg for label */
- if(!(labelname=XtMalloc((strlen(host->h_name)
- +strlen(DOWNMSG)+1)*sizeof(char))
- )) {
- perror("xnetload: Ran out of memory for labelname");
- exit(1);
- }
- /* set up chain to previous Load widget */
- XtSetArg(Statusargs[0],XtNfromVert, (XtArgVal)Statuswin);
-
- /* set label name */
- strcpy(labelname,host->h_name);
- XtSetArg(Statusargs[XtNumber(Statusargs)-1],
- XtNlabel,(XtArgVal)labelname);
-
- /* create the remote load widget, taking into account */
- /* modified label and vertical chaining */
- Statuswin = XtCreateManagedWidget("remote",
- loadWidgetClass,
- Formwin,
- Statusargs,
- XtNumber(Statusargs));
-
- /* This makes sure of 60 second default, without forcing! */
- XtGetApplicationResources( (Widget)Statuswin, (caddr_t)NULL,
- rem_resources, XtNumber(rem_resources),
- NULL, (Cardinal) 0);
-
- /* Set up hostname, and load callback (GetStatus()) */
- strcpy(hostname,host->h_name);
- XtRemoveAllCallbacks(Statuswin, XtNgetLoadProc);
- XtAddCallback(Statuswin,XtNgetLoadProc,
- GetStatus,(caddr_t)hostname);
- }
- }
-
- /* if there are no loads to display, then should stop */
- /* Note, Statuswin is static, guaranteed to start at 0, */
- /* so it's non-zero only if a load widget was created */
- if(!Statuswin) {
- fprintf(stderr,"xnetload: No machines to display\n");
- usage();
- exit(0);
- }
-
- /* draw the widgets, and look for new events */
- XtRealizeWidget(Toplevel);
- XtMainLoop();
- }
-
- /*
- * Load callback function
- *
- */
- void
- GetStatus(w,closure,call_data)
- Widget w; /* load widget */
- caddr_t closure; /* name of host, char* */
- caddr_t call_data; /* load, float* */
- {
- int load; /* current load for this machine */
- char fname[BUFSIZ]; /* name of rwhod file */
-
- /* get current label for widget */
- XtSetArg(Labelarg,XtNlabel,(XtArgVal)&Label);
- XtGetValues(w,&Labelarg,(Cardinal)1);
-
- sprintf(fname,"%s.%s",RWHODHD,(char *)closure);
-
- /* if load is less than zero, then machine is down or something */
- if((load = getload(fname)) < 0) {
- *(double *)call_data = 0.0;
- /* update label with DOWN message */
- if(!matchstr(Label,DOWNMSG))
- updatelabel(w,(char *)closure,DOWNMSG);
- }
- /* otherwise we found a good load, so use it */
- else {
- *(double *)call_data = (double)load/100.0;
- /* hate to do this everytime, but we have to check */
- if(matchstr(Label,DOWNMSG))
- updatelabel(w,(char *)closure,"");
- return;
- }
- }
-
- /*
- * look for pat in str - exact match, no wild cards here
- */
- static int
- matchstr(str,pat)
- register char *str, *pat;
- {
- while(str = index(str,*pat))
- if(! strcmp(str++,pat))
- return(TRUE);
- return(FALSE);
- }
-
- /*
- * replace label with str and msg
- */
- static int
- updatelabel(w,str,msg)
- Widget w;
- register char *str, *msg;
- {
- XEvent Sendevent;
-
- sprintf(Label,"%s%s",str,msg);
- XtSetArg(Labelarg,XtNlabel, (XtArgVal)Label);
- XtSetValues(w,&Labelarg, (Cardinal)1);
-
- /* Load widget doesn't redraw when label is changed. Force it! */
- Sendevent.xexpose.x = 0;
- Sendevent.xexpose.width = ((LoadWidget)w)->core.width;
- XClearWindow(XtDisplay(w),XtWindow(w));
- (*((LoadWidgetClass)&loadClassRec)->core_class.expose)
- (w, &Sendevent, (Region) NULL);
- }
-
- #define ISDOWN(now,wd) (((now) - (wd).wd_recvtime) > DOWNTIME)
- /*
- * actual function to get the load
- * reads rwhod stats to find the load average of a machine
- */
- static int
- getload(fname)
- char *fname;
- {
- int nbytes; /* number of bytes read */
- int fd; /* file descriptor */
- int counter; /* loop counter */
- time_t currtime; /* current time */
- struct whod wd;
- char buf[sizeof(struct whod)];
-
- (void) time(&currtime);
-
- /* Loop 3 times, looking for a non-zero load. */
- /* This keeps us from getting a zero load if rwhod is in */
- /* the process of doing something to the file. This is */
- /* important, since we'll get strange looking zero gaps */
- /* in the graph if we don't try our best to get a non-zero load. */
- for(counter=0;counter<=3;counter++) {
- /* open and read from the file */
- if((fd = open(fname, O_RDONLY, 0)) < 0)
- /* we can't open file, so it's down or something */
- return(-1);
-
- nbytes = read(fd, buf, sizeof(struct whod));
- close(fd);
- /* if we got enough bytes, then copy it to wd */
- if(nbytes >= (sizeof (wd) - sizeof(wd.wd_we))) {
-
- /* NOT everbody has memcpy, but can't use strncpy() */
- memcpy(&wd,buf,(sizeof (wd) - sizeof(wd.wd_we)));
-
- /* ISDOWN macro, if machine is really down or faking */
- if(ISDOWN(currtime,wd))
- return(-1);
- else if(wd.wd_loadav[0] > 0)
- return(wd.wd_loadav[0]);
- }
-
- /* If we got to here, then we need to loop again */
- sleep(1);
- }
- }
-
- static int
- usage()
- {
- fprintf(stderr,"usage:\n xnetload [-nolocal] [machine] ...\n");
- }
- @//E*O*F xnetload/xnetload.c//
- chmod u=rw,g=r,o=r xnetload/xnetload.c
-
- echo x - xnetload/xnetload.1
- sed 's/^@//' > "xnetload/xnetload.1" <<'@//E*O*F xnetload/xnetload.1//'
- @.TH XNETLOAD l "April 1989" "X Version 11"
- @.SH NAME
- xnetload - display load averages from local network machines
- @.SH SYNOPSIS
- @.B xnetload
- [-\fInolocal\fP] [\fImachine\fP] ...
- @.SH DESCRIPTION
- @.I xnetload
- uses the Athena Load widget and
- @.B rwhod
- statistics to display the
- load average of a number of machines on a local network.
- @.SH OPTIONS
- @.PP
- @.I xnetload
- accepts all of the standard X Toolkit command line options along with the
- following additional options:
- @.PP
- @.TP 8
- @.B \-nolocal
- By default, the load for the local machine is displayed and the
- load calculated using the
- Load widget's standard LoadProc. With this option,
- @.I xnetload
- will NOT display
- the local machine's load unless the hostname is listed
- on the command line. When
- @.B \-nolocal
- is used,
- @.I xnetload
- will not try to read
- @.I kmem.
- @.PP
- @.TP 8
- @.B \-local
- If
- @.I xnetload
- is compiled with
- @.B \-DNOLOCAL,
- then no local load will
- be displayed by default.
- @.B \-local
- will turn the local load back on, and make
- @.I xnetload
- read
- @.I kmem.
- @.PP
- @.TP 8
- @.B [machine] ...
- The load for each machine listed will be displayed.
- @.SH RESOURCES
- @.I xnetload
- uses the standard toolkit resources. These are some of the ones that
- I find useful:
- @.br
- @.sp
- !**** XLOAD ****
- @.br
- *Load*font: 6x10
- @.br
- *Load*height: 35
- @.br
- *Load*width: 90
- @.br
- !**** XMULTIMETER ****
- @.br
- xnetload.geometry: -0+0
- @.br
- ! Display the local machine load by reading kmem
- @.br
- xnetload.localload: on
- @.br
- ! number of seconds between updates for local machine
- @.br
- xnetload*local*update: 15
- @.br
- ! number of seconds between updates for remote machines
- @.br
- xnetload*remote*update: 40
- @.sp
- @.PP
- Note - if you define "*Load*update", but not "xnetload*remote*update",
- then
- @.I xnetload
- will set both the remote and local update times to the "*Load*update"
- value. If this time is much less than the
- @.B rwhod
- update period, then the remote load displays will look more like bar graphs.
- @.SH SEE ALSO
- X(1), xload(1), Athena Load widget
- @.SH BUGS
- @.I xnetload
- uses the Load widget's normal load function for the local
- system, therefore
- @.I xnetload
- should be setgid
- @.I kmem.
- If
- @.I xnetload
- cannot be setgid
- @.I kmem,
- then either compile with
- @.B \-DNOLOCAL
- or use the
- @.B \-nolocal
- option.
- @.PP
- @.I xnetload
- will also take a width and height on the application
- geometry specification, but sometimes the
- @.I Form
- widget will leave small gaps between the loads.
- @.PP
- A very wide
- @.I xnetload
- will often have wide margins. I think the
- @.I Form
- widget is doing this.
- @.SH AUTHOR
- J. Michael Berkley
- (jmberkley@watnext.waterloo.edu)
- @//E*O*F xnetload/xnetload.1//
- chmod u=rw,g=r,o=r xnetload/xnetload.1
-
- echo x - xnetload/Makefile
- sed 's/^@//' > "xnetload/Makefile" <<'@//E*O*F xnetload/Makefile//'
- #
- # Makefile for xnetload
- #
- # Written by: Mike Berkley, jmberkley@watnext.waterloo.edu, 1989
- #
- # Permission to use, copy, modify and distribute (without charge) this
- # software and its documentation is granted, provided that this comment
- # is retained.
- #
-
- # Since xnetload finds the local machine's load using the standard Load
- # widget stuff, it needs to be able to read kmem, i.e. setgid kmem. If
- # you do not want this, then define NOLOCAL
- # CFLAGS = -O -DNOLOCAL
- CFLAGS = -O
-
- XINC = /usr/software/X11/include
- XLIB = /usr/software/X11/lib
-
- # Dynix doesn't have -L option on load, but I have left changing the
- # XLIB specification up to individual sites. Dynix and our Sun 3.5
- # don't come with a memcpy, so you'll have to add in whichever library
- # has memcpy.
-
- INCLUDES = -I$(XINC)
- LIBS = -L$(XLIB) -lXaw -lXmu -lXt -lX11
-
- xnetload: xnetload.o
- $(CC) $(CFLAGS) -o xnetload xnetload.o $(LIBS)
-
- @.c.o:
- $(CC) $(CFLAGS) -c $(INCLUDES) $<
- @//E*O*F xnetload/Makefile//
- chmod u=rw,g=r,o=r xnetload/Makefile
-
- echo x - xnetload/AUTHOR
- sed 's/^@//' > "xnetload/AUTHOR" <<'@//E*O*F xnetload/AUTHOR//'
- xnetload was written by Mike Berkley, jmberkley@watnext.waterloo.edu
-
- Permission to use, copy, modify and distribute (without charge) this
- software and its documentation is granted, provided that this comment
- is retained.
- @//E*O*F xnetload/AUTHOR//
- chmod u=rw,g=r,o=r xnetload/AUTHOR
-
- echo x - xnetload/patchlevel.h
- sed 's/^@//' > "xnetload/patchlevel.h" <<'@//E*O*F xnetload/patchlevel.h//'
- #define PATCHLEVEL 0
- @//E*O*F xnetload/patchlevel.h//
- chmod u=rw,g=r,o=r xnetload/patchlevel.h
-
- echo Inspecting for damage in transit...
- temp=/tmp/shar$$; dtemp=/tmp/.shar$$
- trap "rm -f $temp $dtemp; exit" 0 1 2 3 15
- cat > $temp <<\!!!
- 49 345 2160 README
- 31 153 1023 Imakefile
- 365 1371 11622 xnetload.c
- 121 421 2644 xnetload.1
- 32 157 941 Makefile
- 5 29 222 AUTHOR
- 1 3 21 patchlevel.h
- 604 2479 18633 total
- !!!
- wc xnetload/README xnetload/Imakefile xnetload/xnetload.c xnetload/xnetload.1 xnetload/Makefile xnetload/AUTHOR xnetload/patchlevel.h | sed 's=[^ ]*/==' | diff -b $temp - >$dtemp
- if [ -s $dtemp ]
- then echo "Ouch [diff of wc output]:" ; cat $dtemp
- else echo "No problems found."
- fi
- exit 0
-