v13i056: xmeter, Patch6, Part01/01

Rober Schwartzkopf bobs at rand.org
Tue Jun 18 16:42:17 AEST 1991


Submitted-by: Rober Schwartzkopf <bobs at rand.org>
Posting-number: Volume 13, Issue 56
Archive-name: xmeter/patch6
Patch-To: xmeter: Volume 9, Issue 59 (9/28/90)

This is xmeter patchlevel 6.  Changes since the previous release
include new option (-v) to print xmeter version, defstat option to
change the default statistic to be watched, clearing of stripchart
widgets when watched stat is changed, and better handling of dead
hosts, as well as a couple of minor bug fixes.

Bob Schwartzkopf (bobs at rand.org)

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of shell archive."
# Contents:  patchlevel.h README Imakefile xmeter.c xmeter.man
#   XMeter.ad
# Wrapped by root at boris on Mon Jun  3 15:27:22 1991
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'patchlevel.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'patchlevel.h'\"
else
echo shar: Extracting \"'patchlevel.h'\" \(21 characters\)
sed "s/^X//" >'patchlevel.h' <<'END_OF_FILE'
X#define PATCHLEVEL 6
END_OF_FILE
if test 21 -ne `wc -c <'patchlevel.h'`; then
    echo shar: \"'patchlevel.h'\" unpacked with wrong size!
fi
# end of 'patchlevel.h'
fi
if test -f 'README' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'README'\"
else
echo shar: Extracting \"'README'\" \(1879 characters\)
sed "s/^X//" >'README' <<'END_OF_FILE'
Xxmeter displays a histogram of data returned by rstat(3).  It can be
Xtold to monitor multiple hosts, or to monitor multiple statistics on the
Xsame host.
X
XAuthor: Bob Schwartzkopf (bobs at rand.org)
X	The RAND Corporation
X	1700 Main Street
X	Santa Monica, CA 90406-2138
X
XEdit history
X
XPatchlevel 6
X	- Clear stripcharts when monitored statistic is changed.
X	- Allow setting of monitored stat in .Xdefaults.
X	- Added -v option to display version number.
X	- Fork new process to wait for dead host to come back up.
X
XPatchlevel 5
X	- Put explict closes of sockets back in after clnt_destroy().
X	  Apparently some versions of clnt_destroy don't close the
X	  socket.
X	- Minor changes to XMeter.ad.
X
XPatchlevel 4
X	- Allow user to specify foreground, border, internal border and
X	  highlight color for each level.
X	- Fixed bug in determining width/height of form widget.
X	- Allow user to specify label foreground and background colors
X	  independently of stripcharts.
X	- Made all colors either class Foreground or Background, should
X	  simplify .Xdefaults files.
X
XPatchlevel 3
X	- Added "cols" and "rows" options, allows rectangular
X	  layout of graphs.  Removed "orientation" option.
X	- Backgrounds of stripcharts can now be set to user specified
X	  bitmaps with "*Bitmap" resources.
X	- Added op, wp, ep and fp options, which takes a program name as an
X	  argument.  When a graph enters state OK, WARN, ERROR or FATAL, the
X	  specified program is invoked.
X	- Added menus which allow the monitored statistic to be changed
X	  on the fly.
X
XPatchlevel 2
X	- Changed resource name of paned widgets to host name.
X	- Used actual time between rstat(3) calls instead of "update"
X	  interval for computing graph values.
X	- Rewrote functions that return graph values.
X	- Fixed divide by 0 errors in fcpu(), fsys() and fuser().
X	- Use RSTATVERS_TIME instead of RSTATVERS.
X
XPatchlevel 1
X	- Fixed memory leak.
END_OF_FILE
if test 1879 -ne `wc -c <'README'`; then
    echo shar: \"'README'\" unpacked with wrong size!
fi
# end of 'README'
fi
if test -f 'Imakefile' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'Imakefile'\"
else
echo shar: Extracting \"'Imakefile'\" \(369 characters\)
sed "s/^X//" >'Imakefile' <<'END_OF_FILE'
X       INCLUDES = -I$(TOP) -I$(TOP)/X11
X        DEPLIBS = XawClientDepLibs
XLOCAL_LIBRARIES = XawClientLibs
X  SYS_LIBRARIES = -lrpcsvc
X           SRCS = xmeter.c
X           OBJS = xmeter.o
X	  SHARS = patchlevel.h README Imakefile xmeter.c xmeter.man XMeter.ad
X
XComplexProgramTarget(xmeter)
XInstallAppDefaults(XMeter)
X
Xxmeter.shar:	$(SHARS)
X	shar -o xmeter.shar $(SHARS)
END_OF_FILE
if test 369 -ne `wc -c <'Imakefile'`; then
    echo shar: \"'Imakefile'\" unpacked with wrong size!
fi
# end of 'Imakefile'
fi
if test -f 'xmeter.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'xmeter.c'\"
else
echo shar: Extracting \"'xmeter.c'\" \(33499 characters\)
sed "s/^X//" >'xmeter.c' <<'END_OF_FILE'
X/*
X * xmeter.c - Display histogram of rstat(3) output for multiple hosts.
X *
X * Author: Bob Schwartzkopf, The RAND Corporation
X *
X * Suggestions for improvements and bug fixes can be sent to "bobs at rand.org".
X * As my schedule permits I'll try to incorporate them.
X */
X
X#ifndef lint
Xstatic char	*RCSid="$Header: /usr/rand/src/bin/xmeter/RCS/xmeter.c,v 1.7 1991/06/03 22:21:43 root Exp $";
X#endif lint
X
X/*
X * $Log: xmeter.c,v $
X * Revision 1.7  1991/06/03  22:21:43  root
X * Add -v option to print xmeter version number.
X * Add defstat option.
X * Add code to clear stripchart when watched stat is changed.
X * When host is down fork process to wait for it to come up instead of
X * having toplevel process wait for timeouts.
X *
X * Revision 1.6  90/09/28  20:32:34  root
X * Add explicit closes of sockets back in, apparently some versions of
X * clnt_destroy() don't do it automatically.
X * 
X * Revision 1.5  90/09/18  20:47:03  root
X * Allow user specification of foreground colors.
X * 
X * Revision 1.4  90/08/20  14:18:01  root
X * Added menus, column and row options, background bitmaps, and user
X * specifiable programs to be invoked when graphs change state.
X * 
X * Revision 1.3  90/06/07  16:17:06  bobs
X * Removed "retries".
X * Changed name of paned widgets to host name displayed in that widget.
X * Used actual time between rstat calls instead of "update" interval in
X * computing rates in functions that return values to stripchart widgets.
X * Removed "ost" variable, rewrote functions that return values to
X * stripcharts.
X * Fixed bug in fsys, fcpu and fuser that could cause divide by 0 errors.
X * Fixed rpc timeout handling in getmeter and getport.
X * Use RSTATVERS_TIME instead of RSTATVERS, which isn't defined in SunOS 4.1.
X * 
X * Revision 1.2  90/05/04  12:31:52  bobs
X * Fix memory leak in getport().  Wasn't freeing resources allocated by
X * clntudp_create when clnt_call failed.  Also removed explicit calls
X * to close sockets since clnt_destroy() does this.
X * 
X * Revision 1.1  90/04/30  14:33:59  bobs
X * Initial revision
X * 
X */
X
X#include <stdio.h>
X#include <sys/time.h>
X#include <sys/param.h>
X#include <sys/socket.h>
X#include <sys/dk.h>
X#include <signal.h>
X#include <netdb.h>
X#include <rpc/rpc.h>
X#include <rpc/pmap_prot.h>
X#include <rpcsvc/rstat.h>
X#include <X11/Xlib.h>
X#include <X11/Intrinsic.h>
X#include <X11/StringDefs.h>
X#include <X11/Xatom.h>
X#include <X11/Shell.h>
X#include <X11/Xaw/Cardinals.h>
X#include <X11/Xaw/Form.h>
X#include <X11/Xaw/StripChart.h>
X#include <X11/Xaw/SimpleMenu.h>
X#include <X11/Xaw/MenuButton.h>
X#include <X11/Xaw/SmeBSB.h>
X#include <X11/Xaw/Paned.h>
X#include <X11/Xmu/Xmu.h>
X#include "patchlevel.h"
X
X#define MAJORVERSION	1
X#define DMSG		"down"
X#define OK		0
X#define WARN		1
X#define ERROR		2
X#define FATAL		3
X#define MAXBACKS	(FATAL+1)
X#define STATMENU	"statmenu"
X#ifndef FSCALE
X#define FSCALE		(1 << 8)
X#endif
X
X/*
X * There is one METER structure per strip chart.  If multiple stats
X * on a single host are being watched we save rstatd calls by sharing
X * part of this structure (SHMETER) between the different meters watching
X * the same host.
X */
Xtypedef struct _shmeter {
X    char		*name;	/* Host name				*/
X    struct sockaddr_in	addr;
X    CLIENT		*clnt;
X    int			s;	/* Socket				*/
X    struct statstime	st[2];	/* Keep last 2 stats to compute diffs	*/
X    int			idx;	/* Index into st array			*/
X    int			refcnt;	/* Meters sharing this structure	*/
X    int			curcnt;	/* Meters who've displayed current data	*/
X    int			first;	/* TRUE when only 1 rstat has been done	*/
X    int			pid;	/* Pid of proc waiting for host		*/
X    struct _shmeter	*nxt;	/* Link these together			*/
X} SHMETER;
X
Xtypedef struct _meter {
X    char		*label;
X    int			stat;		/* Which stat to watch		*/
X    Widget		pdwidget;	/* Paned widget			*/
X    Widget		mbwidget;	/* MenuButton widget		*/
X    Widget		scwidget;	/* StripChart widget		*/
X    int			oldstate;	/* Save state so know when to	*/
X					/* change backgrounds		*/
X    SHMETER		*sh;		/* Shared info			*/
X    Pixmap		pm;		/* Current background pixmap	*/
X    int			oldjumpscroll;	/* Old jumpscroll value		*/
X    struct _meter	*nxt;
X} METER;
X
X/*
X * There is a STATDATA structure for each statistic that can be monitored.
X */
Xtypedef struct {
X    int		scale;		/* Each stat is scaled			*/
X    int		(*val)();	/* Function that computes this stat	*/
X    char	*name;		/* Name of stat for menu widget		*/
X} STATDATA;
X
X/*
X * xmeter supports 4 background colors and pixmaps that it will switch
X * between as a meter changes state, called OK, WARN, ERROR and FATAL.
X * The background bitmaps are stored in BITMAP structures.
X */
Xtypedef struct {
X  int		w;				/* Width of bitmap	*/
X  int		h;				/* Height of bitmap	*/
X  Pixmap	bm;				/* Bitmap		*/
X} BITMAP;
X
X/*
X * Functions
X */
Xextern char	*malloc ();
Xextern char	*index ();
Xint		getstatus ();
Xint		changestat ();
Xint		selecthost ();
Xint		freechild ();
XMETER		*initmeter ();
Xint		fcoll (), fcpu (), fierr (), fintr (), fipkt (), fload ();
Xint		foerr (), fopkt (), fpage (), fpgpgin (), fpgpgout ();
Xint		fpswpin (), fpswpout (), fswt (), fsys (), fuser ();
X
XSTATDATA		sd[] = {
X#define S_COLL		0
X  {1, fcoll, "coll"},
X#define S_CPU		S_COLL+1
X  {1, fcpu, "cpu"},
X#define S_IERR		S_CPU+1
X  {1, fierr, "ierr"},
X#define S_INTR		S_IERR+1
X  {1, fintr, "intr"},
X#define S_IPKT		S_INTR+1
X  {1, fipkt, "ipkt"},
X#define S_LOAD		S_IPKT+1
X  {1, fload, "load"},
X#define S_OERR		S_LOAD+1
X  {1, foerr, "oerr"},
X#define S_OPKT		S_OERR+1
X  {1, fopkt, "opkt"},
X#define S_PAGE		S_OPKT+1
X  {1, fpage, "page"},
X#define S_PGPGIN	S_PAGE+1
X  {1, fpgpgin, "pgpgin"},
X#define S_PGPGOUT	S_PGPGIN+1
X  {1, fpgpgout, "pgpgout"},
X#define S_PSWPIN	S_PGPGOUT+1
X  {1, fpswpin, "pswpin"},
X#define S_PSWPOUT	S_PSWPIN+1
X  {1, fpswpout, "pswpout"},
X#define S_SWT		S_PSWPOUT+1
X  {1, fswt, "swt"},
X#define S_SYS		S_SWT+1
X  {1, fsys, "sys"},
X#define S_USER		S_SYS+1
X  {1, fuser, "user"},
X};
X#define DEFSTATNAME	"load"
X#define MAXSTAT		(sizeof (sd) / sizeof (STATDATA))
X#define MAXSTATNAME	10		/* Max length of stat name	*/
X
Xstatic char		*progname;
XPixel			back[MAXBACKS];		/* Meter backgrounds	*/
XPixel			fore[MAXBACKS];		/* Meter foregrounds	*/
XPixel			hl[MAXBACKS];		/* Meter highlights	*/
XPixel			bd[MAXBACKS];		/* Meter borders	*/
XPixel			ibd[MAXBACKS];		/* Meter internal bds	*/
XPixel			lback[MAXBACKS];	/* Label backgrounds	*/
XPixel			lfore[MAXBACKS];	/* Label foregrounds	*/
XBITMAP			bitmap[MAXBACKS];	/* Stripchart bg pixmaps*/
XPixmap			bitmapdef = XtUnspecifiedPixmap;
Xint			warnLevel;		/* Warning level	*/
Xint			errorLevel;		/* Error level		*/
Xstatic struct timeval	ptto = {0, 0};		/* RPC timeout interval	*/
Xstatic struct timeval	tto = {0, 0};		/* Total timeout	*/
Xstatic SHMETER		*shmeters = NULL;	/* List of SHMETERs	*/
Xstatic METER		*selected;		/* Current meter	*/
Xstatic METER		*meterlist = NULL;	/* List of METERs	*/
Xint			columns;		/* Columns to display	*/
Xint			rows;			/* Rows	to display	*/
Xint			timeout;		/* RPC timeout		*/
Xint			retries;		/* RPC retries		*/
Xint			loadscaledef = FSCALE;	/* Scale for load ave.	*/
XBoolean			shortname;		/* Short hostname flag	*/
XString			prog[MAXBACKS];		/* Alert programs	*/
XString			defstat;		/* Default stat		*/
Xstatic XtResource	application_resources[] = {
X    {"columns", "Columns", XtRInt, sizeof (int),
X	(Cardinal) &columns, XtRString, "0"},
X    {"defStat", "DefStat", XtRString, sizeof (char *),
X	(Cardinal) &defstat, XtRString, DEFSTATNAME},
X    {"errorBack", XtCBackground, XtRPixel, sizeof (Pixel),
X	(Cardinal) &back[ERROR], XtRString, XtDefaultBackground},
X    {"errorBd", XtCForeground, XtRPixel, sizeof (Pixel),
X	(Cardinal) &bd[ERROR], XtRString, XtDefaultForeground},
X    {"errorBitmap", XtCBitmap, XtRBitmap, sizeof (Pixmap),
X	(Cardinal) &bitmap[ERROR].bm, XtRBitmap, (caddr_t) &bitmapdef},
X    {"errorFore", XtCForeground, XtRPixel, sizeof (Pixel),
X	(Cardinal) &fore[ERROR], XtRString, XtDefaultForeground},
X    {"errorHl", XtCForeground, XtRPixel, sizeof (Pixel),
X	(Cardinal) &hl[ERROR], XtRString, XtDefaultForeground},
X    {"errorIbd", XtCForeground, XtRPixel, sizeof (Pixel),
X	(Cardinal) &ibd[ERROR], XtRString, XtDefaultForeground},
X    {"errorLevel", "ErrorLevel", XtRInt, sizeof (int),
X	(Cardinal) &errorLevel, XtRString, "6"},
X    {"errorProg", "Program", XtRString, sizeof (char *),
X	(Cardinal) &prog[ERROR], XtRString, NULL},
X    {"fatalBack", XtCBackground, XtRPixel, sizeof (Pixel),
X	(Cardinal) &back[FATAL], XtRString, XtDefaultBackground},
X    {"fatalBd", XtCForeground, XtRPixel, sizeof (Pixel),
X	(Cardinal) &bd[FATAL], XtRString, XtDefaultForeground},
X    {"fatalBitmap", XtCBitmap, XtRBitmap, sizeof (Pixmap),
X	(Cardinal) &bitmap[FATAL].bm, XtRBitmap, (caddr_t) &bitmapdef},
X    {"fatalFore", XtCForeground, XtRPixel, sizeof (Pixel),
X	(Cardinal) &fore[FATAL], XtRString, XtDefaultForeground},
X    {"fatalHl", XtCForeground, XtRPixel, sizeof (Pixel),
X	(Cardinal) &hl[FATAL], XtRString, XtDefaultForeground},
X    {"fatalIbd", XtCForeground, XtRPixel, sizeof (Pixel),
X	(Cardinal) &ibd[FATAL], XtRString, XtDefaultForeground},
X    {"fatalProg", "Program", XtRString, sizeof (char *),
X	(Cardinal) &prog[FATAL], XtRString, NULL},
X    {"lErrorBack", XtCBackground, XtRPixel, sizeof (Pixel),
X	(Cardinal) &lback[ERROR], XtRString, XtDefaultBackground},
X    {"lErrorFore", XtCForeground, XtRPixel, sizeof (Pixel),
X	(Cardinal) &lfore[ERROR], XtRString, XtDefaultForeground},
X    {"lFatalBack", XtCBackground, XtRPixel, sizeof (Pixel),
X	(Cardinal) &lback[FATAL], XtRString, XtDefaultBackground},
X    {"lFatalFore", XtCForeground, XtRPixel, sizeof (Pixel),
X	(Cardinal) &lfore[FATAL], XtRString, XtDefaultForeground},
X    {"lOkBack", XtCBackground, XtRPixel, sizeof (Pixel),
X	(Cardinal) &lback[OK], XtRString, XtDefaultBackground},
X    {"lOkFore", XtCForeground, XtRPixel, sizeof (Pixel),
X	(Cardinal) &lfore[OK], XtRString, XtDefaultForeground},
X    {"lWarnBack", XtCBackground, XtRPixel, sizeof (Pixel),
X	(Cardinal) &lback[WARN], XtRString, XtDefaultBackground},
X    {"lWarnFore", XtCForeground, XtRPixel, sizeof (Pixel),
X	(Cardinal) &lfore[WARN], XtRString, XtDefaultForeground},
X    {"okBack", XtCBackground, XtRPixel, sizeof (Pixel),
X	(Cardinal) &back[OK], XtRString, XtDefaultBackground},
X    {"okBd", XtCForeground, XtRPixel, sizeof (Pixel),
X	(Cardinal) &bd[OK], XtRString, XtDefaultForeground},
X    {"okBitmap", XtCBitmap, XtRBitmap, sizeof (Pixmap),
X	(Cardinal) &bitmap[OK].bm, XtRBitmap, (caddr_t) &bitmapdef},
X    {"okFore", XtCForeground, XtRPixel, sizeof (Pixel),
X	(Cardinal) &fore[OK], XtRString, XtDefaultForeground},
X    {"okHl", XtCForeground, XtRPixel, sizeof (Pixel),
X	(Cardinal) &hl[OK], XtRString, XtDefaultForeground},
X    {"okIbd", XtCForeground, XtRPixel, sizeof (Pixel),
X	(Cardinal) &ibd[OK], XtRString, XtDefaultForeground},
X    {"okProg", "Program", XtRString, sizeof (char *),
X	(Cardinal) &prog[OK], XtRString, NULL},
X    {"retries", "Retries", XtRInt, sizeof (int),
X	(Cardinal) &retries, XtRString, "2"},
X    {"rows", "Rows", XtRInt, sizeof (int),
X	(Cardinal) &rows, XtRString, "0"},
X    {"scaleColl", "ScaleColl", XtRInt, sizeof (int),
X	(Cardinal) &sd[S_COLL].scale, XtRString, "1"},
X    {"scaleCpu", "ScaleCpu", XtRInt, sizeof (int),
X	(Cardinal) &sd[S_CPU].scale, XtRString, "20"},
X    {"scaleIerr", "ScaleIerr", XtRInt, sizeof (int),
X	(Cardinal) &sd[S_IERR].scale, XtRString, "1"},
X    {"scaleIntr", "ScaleIntr", XtRInt, sizeof (int),
X	(Cardinal) &sd[S_INTR].scale, XtRString, "50"},
X    {"scaleIpkt", "ScaleIpkt", XtRInt, sizeof (int),
X	(Cardinal) &sd[S_IPKT].scale, XtRString, "20"},
X    {"scaleLoad", "ScaleLoad", XtRInt, sizeof (int),
X	(Cardinal) &sd[S_LOAD].scale, XtRInt, (caddr_t) &loadscaledef},
X    {"scaleOerr", "ScaleOerr", XtRInt, sizeof (int),
X	(Cardinal) &sd[S_OERR].scale, XtRString, "1"},
X    {"scaleOpkt", "ScaleOpkt", XtRInt, sizeof (int),
X	(Cardinal) &sd[S_OPKT].scale, XtRString, "20"},
X    {"scalePage", "ScalePage", XtRInt, sizeof (int),
X	(Cardinal) &sd[S_PAGE].scale, XtRString, "10"},
X    {"scalePgpgin", "ScalePgpgin", XtRInt, sizeof (int),
X	(Cardinal) &sd[S_PGPGIN].scale, XtRString, "10"},
X    {"scalePgpgout", "ScalePgpgout", XtRInt, sizeof (int),
X	(Cardinal) &sd[S_PGPGOUT].scale, XtRString, "10"},
X    {"scalePswpin", "ScalePswpin", XtRInt, sizeof (int),
X	(Cardinal) &sd[S_PSWPIN].scale, XtRString, "1"},
X    {"scalePswpout", "ScalePswpout", XtRInt, sizeof (int),
X	(Cardinal) &sd[S_PSWPOUT].scale, XtRString, "1"},
X    {"scaleSwt", "ScaleSwt", XtRInt, sizeof (int),
X	(Cardinal) &sd[S_SWT].scale, XtRString, "30"},
X    {"scaleSys", "ScaleSys", XtRInt, sizeof (int),
X	(Cardinal) &sd[S_SYS].scale, XtRString, "20"},
X    {"scaleUser", "ScaleUser", XtRInt, sizeof (int),
X	(Cardinal) &sd[S_USER].scale, XtRString, "20"},
X    {"shortName", "Shortname", XtRBoolean, sizeof (Boolean),
X	(Cardinal) &shortname, XtRString, "False"},
X    {"timeout", "Timeout", XtRInt, sizeof (int),
X	(Cardinal) &timeout, XtRString, "5"},
X    {"warnBack", XtCBackground, XtRPixel, sizeof (Pixel),
X	(Cardinal) &back[WARN], XtRString, XtDefaultBackground},
X    {"warnBd", XtCForeground, XtRPixel, sizeof (Pixel),
X	(Cardinal) &bd[WARN], XtRString, XtDefaultForeground},
X    {"warnBitmap", XtCBitmap, XtRBitmap, sizeof (Pixmap),
X	(Cardinal) &bitmap[WARN].bm, XtRBitmap, (caddr_t) &bitmapdef},
X    {"warnFore", XtCForeground, XtRPixel, sizeof (Pixel),
X	(Cardinal) &fore[WARN], XtRString, XtDefaultForeground},
X    {"warnHl", XtCForeground, XtRPixel, sizeof (Pixel),
X	(Cardinal) &hl[WARN], XtRString, XtDefaultForeground},
X    {"warnIbd", XtCForeground, XtRPixel, sizeof (Pixel),
X	(Cardinal) &ibd[WARN], XtRString, XtDefaultForeground},
X    {"warnLevel", "WarnLevel", XtRInt, sizeof (int),
X	(Cardinal) &warnLevel, XtRString, "3"},
X    {"warnProg", "Program", XtRString, sizeof (char *),
X	(Cardinal) &prog[WARN], XtRString, NULL},
X};
Xstatic XrmOptionDescRec	options[] = {
X    {"-cols",		"columns",		XrmoptionSepArg,	NULL},
X    {"-ebd",		"errorBd",		XrmoptionSepArg,	NULL},
X    {"-ebg",		"errorBack",		XrmoptionSepArg,	NULL},
X    {"-efg",		"errorFore",		XrmoptionSepArg,	NULL},
X    {"-ehl",		"errorHl",		XrmoptionSepArg,	NULL},
X    {"-eibd",		"errorIbd",		XrmoptionSepArg,	NULL},
X    {"-elevel",		"errorLevel",		XrmoptionSepArg,	NULL},
X    {"-ep",		"errorProg",		XrmoptionSepArg,	NULL},
X    {"-fbd",		"fatalBd",		XrmoptionSepArg,	NULL},
X    {"-fbg",		"fatalBack",		XrmoptionSepArg,	NULL},
X    {"-ffg",		"fatalFore",		XrmoptionSepArg,	NULL},
X    {"-fhl",		"fatalHl",		XrmoptionSepArg,	NULL},
X    {"-fibd",		"fatalIbd",		XrmoptionSepArg,	NULL},
X    {"-fp",		"fatalProg",		XrmoptionSepArg,	NULL},
X    {"-h",		"*Paned.height",	XrmoptionSepArg,	NULL},
X    {"-lebg",		"lErrorBack",		XrmoptionSepArg,	NULL},
X    {"-lefg",		"lErrorFore",		XrmoptionSepArg,	NULL},
X    {"-lfbg",		"lFatalBack",		XrmoptionSepArg,	NULL},
X    {"-lffg",		"lFatalFore",		XrmoptionSepArg,	NULL},
X    {"-lobg",		"lOkBack",		XrmoptionSepArg,	NULL},
X    {"-lofg",		"lOkFore",		XrmoptionSepArg,	NULL},
X    {"-lwbg",		"lWarnBack",		XrmoptionSepArg,	NULL},
X    {"-lwfg",		"lWarnFore",		XrmoptionSepArg,	NULL},
X    {"-obd",		"okBd",			XrmoptionSepArg,	NULL},
X    {"-obg",		"okBack",		XrmoptionSepArg,	NULL},
X    {"-ofg",		"okFore",		XrmoptionSepArg,	NULL},
X    {"-ohl",		"okHl",			XrmoptionSepArg,	NULL},
X    {"-oibd",		"okIbd",		XrmoptionSepArg,	NULL},
X    {"-op",		"okProg",		XrmoptionSepArg,	NULL},
X    {"-rows",		"rows",			XrmoptionSepArg,	NULL},
X    {"-rt",		"retries",		XrmoptionSepArg,	NULL},
X    {"-scoll",		"scaleColl",		XrmoptionSepArg,	NULL},
X    {"-scpu",		"scaleCpu",		XrmoptionSepArg,	NULL},
X    {"-sierr",		"scaleIerr",		XrmoptionSepArg,	NULL},
X    {"-sintr",		"scaleIntr",		XrmoptionSepArg,	NULL},
X    {"-sipkt",		"scaleIpkt",		XrmoptionSepArg,	NULL},
X    {"-sload",		"scaleLoad",		XrmoptionSepArg,	NULL},
X    {"-sn",		"shortName",		XrmoptionNoArg,		"on"},
X    {"-soerr",		"scaleOerr",		XrmoptionSepArg,	NULL},
X    {"-sopkt",		"scaleOpkt",		XrmoptionSepArg,	NULL},
X    {"-spage",		"scalePage",		XrmoptionSepArg,	NULL},
X    {"-spgpgin",	"scalePgpgin",		XrmoptionSepArg,	NULL},
X    {"-spgpgout",	"scalePgpgout",		XrmoptionSepArg,	NULL},
X    {"-spswpin",	"scalePswpin",		XrmoptionSepArg,	NULL},
X    {"-spswpout",	"scalePswpout",		XrmoptionSepArg,	NULL},
X    {"-sswt",		"scaleSwt",		XrmoptionSepArg,	NULL},
X    {"-ssys",		"scaleSys",		XrmoptionSepArg,	NULL},
X    {"-suser",		"scaleUser",		XrmoptionSepArg,	NULL},
X    {"-to",		"timeout",		XrmoptionSepArg,	NULL},
X    {"-update",		"*StripChart.update",	XrmoptionSepArg,	NULL},
X    {"-w",		"*Paned.width",		XrmoptionSepArg,	NULL},
X    {"-wbd",		"warnBd",		XrmoptionSepArg,	NULL},
X    {"-wbg",		"warnBack",		XrmoptionSepArg,	NULL},
X    {"-wfg",		"warnFore",		XrmoptionSepArg,	NULL},
X    {"-whl",		"warnHl",		XrmoptionSepArg,	NULL},
X    {"-wibd",		"warnIbd",		XrmoptionSepArg,	NULL},
X    {"-wlevel",		"warnLevel",		XrmoptionSepArg,	NULL},
X    {"-wp",		"warnProg",		XrmoptionSepArg,	NULL},
X};
Xstatic Arg		formargs[] = {
X    {XtNdefaultDistance,	1},		/* Spacing		*/
X    {XtNresizable,		TRUE },		/* Resizable		*/
X};
X
Xmain (argc, argv)
X
Xint	argc;
Xchar	**argv;
X
X{
X  Widget		toplevel;
X  Widget		form;
X  Widget		pane = NULL;
X  int			i;
X  int			n;
X  Arg			args[10];
X  XtAppContext		appcon;
X  String		mbtrans =
X      "<EnterWindow>:	highlight()\n\
X       <LeaveWindow>:	reset()\n\
X       <BtnDown>:	set() notify() PopupMenu()";
X  XtTranslations	mbtt;
X  Widget		*lw;	/* Last column or row of widgets	*/
X  int			numwgt;
X
X  progname = argv[0];
X  toplevel = XtAppInitialize (&appcon, "XMeter", options,
X		XtNumber (options), &argc, argv, NULL, NULL, ZERO);
X  XtGetApplicationResources (toplevel, NULL, application_resources,
X			     XtNumber (application_resources), NULL, 0);
X  form = XtCreateManagedWidget ("form", formWidgetClass, toplevel,
X			        formargs, XtNumber (formargs));
X  if (argc < 2)
X      usage ();
X  if (strcmp ("-v", argv[1]) == 0)
X       printversion ();
X  init (toplevel, &lw);
X  createmenus (form);
X  mbtt = XtParseTranslationTable (mbtrans);
X  /*
X   * Each meter consists of a paned widget, each paned widget has two
X   * children, which are a menubutton widget and stripchart widget.
X   * The following loop creates and initializes the appropriate widgets.
X   */
X  for (i = 1, numwgt = 0; i < argc; i++, numwgt++) {
X      meterlist = initmeter (meterlist, &i, argc, argv);
X	/*
X	 * Create paned widget.
X	 */
X      n = 0;
X      if (columns > 0) {		/* Locate pane in form ...	*/
X	  XtSetArg (args[n], XtNfromVert, lw[numwgt % columns]); n++;
X	  if (numwgt % columns != 0) {
X	      XtSetArg (args[n], XtNfromHoriz, pane); n++;
X	  }
X      } else {
X	  XtSetArg (args[n], XtNfromHoriz, lw[numwgt % rows]); n++;
X	  if (numwgt % rows != 0) {
X	      XtSetArg (args[n], XtNfromVert, pane); n++;
X	  }
X      }
X      XtSetArg (args[n], XtNborder, bd[OK]); n++;
X      XtSetArg (args[n], XtNinternalBorderColor, ibd[OK]); n++;
X      pane = XtCreateManagedWidget (meterlist->sh->name, panedWidgetClass,
X				    form, args, n);
X      lw[numwgt % (columns > 0 ? columns : rows)] = pane;
X      meterlist->pdwidget = pane;
X	/*
X	 * Create menubutton widget.
X	 */
X      n = 0;
X      XtSetArg (args[n], XtNshowGrip, XtEno); n++;
X      XtSetArg (args[n], XtNlabel, meterlist->label); n++;
X      XtSetArg (args[n], XtNbackground, lback[OK]); n++;
X      XtSetArg (args[n], XtNforeground, lfore[OK]); n++;
X      XtSetArg (args[n], XtNmenuName, STATMENU); n++;
X      XtSetArg (args[n], XtNtranslations, mbtt); n++;
X      meterlist->mbwidget = XtCreateManagedWidget ("menu",
X				menuButtonWidgetClass, pane, args, n);
X      XtRemoveAllCallbacks (meterlist->mbwidget, XtNcallback);
X      XtAddCallback (meterlist->mbwidget, XtNcallback, selecthost, meterlist);
X	/*
X	 * Create stripchart widget.
X	 */
X      n = 0;
X      XtSetArg (args[n], XtNfromVert, meterlist->mbwidget); n++;
X      XtSetArg (args[n], XtNresizable, TRUE); n++;
X      XtSetArg (args[n], XtNbackground, back[OK]); n++;
X      XtSetArg (args[n], XtNforeground, fore[OK]); n++;
X      XtSetArg (args[n], XtNhighlight, hl[OK]); n++;
X      meterlist->scwidget = XtCreateManagedWidget ("load",
X				stripChartWidgetClass, pane, args, n);
X      XtRemoveAllCallbacks (meterlist->scwidget, XtNgetValue);
X      XtAddCallback (meterlist->scwidget, XtNgetValue, getstatus, meterlist);
X  }
X  free (lw);
X  signal (SIGCHLD, freechild);		/* Clean up after our children	*/
X  XtRealizeWidget (toplevel);
X  setokbackgrounds (XtDisplay (toplevel), XtScreen (toplevel));
X  XtAppMainLoop (appcon);
X}
X
Xusage ()
X
X{
X  int	i;
X
X  fprintf (stderr, "Usage: %s [toolkit options] [options] [stat] host ...\n",
X	   progname);
X  fprintf (stderr, "  Options are:");
X  for (i = 0; i < XtNumber (options); i++) {
X      if (i % 8 == 0)
X          fprintf (stderr, "\n    ");
X      else
X	  fprintf (stderr, ", ");
X      fprintf (stderr, "%s", options[i].option);
X  }
X  fprintf (stderr, ", -v\n  Stats to watch are:");
X  for (i = 0; i < MAXSTAT; i++) {
X      if (i % 8 == 0)
X          fprintf (stderr, "\n    ");
X      else
X	  fprintf (stderr, ", ");
X      fprintf (stderr, "-%s", sd[i].name);
X  }
X  fprintf (stderr, "\n");
X  exit (1);
X}
X
X/*
X * printversion - Print version number and exit.
X */
Xprintversion ()
X
X{
X  printf ("XMeter version %d.%d\n", MAJORVERSION, PATCHLEVEL);
X  exit (0);
X}
X
X/*
X * init - Initialze various globals.
X */
Xinit (toplevel, lw)
X
XWidget	toplevel;
XWidget	**lw;
X
X{
X  int		i;
X  Window	rw;
X  int		x;
X  int		y;
X  int		bwidth;
X  int		depth;
X
X  ptto.tv_sec = timeout;
X  tto.tv_sec = timeout * retries;
X  if (columns <= 0 && rows <= 0)
X      columns = 1;
X  if (columns > 0) {
X      if ((*lw = (Widget *) calloc (columns, sizeof (Widget))) == NULL)	
X	  fatal ("lw");	
X  } else
X      if ((*lw = (Widget *) calloc (rows, sizeof (Widget))) == NULL)
X	  fatal ("lw");
X  for (i = 0; i < MAXBACKS; i++)
X      if (bitmap[i].bm != bitmapdef)	/* Get bitmap dimensions	*/
X	  XGetGeometry (XtDisplay (toplevel), bitmap[i].bm, &rw, &x, &y,
X			&bitmap[i].w, &bitmap[i].h, &bwidth, &depth);
X}
X
X/*
X * createmenus - Create menus used by each meter.  Currently there's just
X *   one which consists of the stats that can be monitored.
X */
Xcreatemenus (parent)
X
XWidget	parent;
X
X{
X  int		i;
X  int		n;
X  Widget	menu;
X  Widget	me;
X  Arg		args[10];
X
X  menu = XtCreatePopupShell (STATMENU, simpleMenuWidgetClass, parent,
X			     NULL, ZERO);
X  for (i = 0; i < MAXSTAT; i++) {
X      n = 0;
X      XtSetArg (args[n], XtNlabel, sd[i].name); n++;
X      me = XtCreateManagedWidget (sd[i].name, smeBSBObjectClass, menu,
X				  args, n);
X      XtRemoveAllCallbacks (me, XtNcallback);
X      XtAddCallback (me, XtNcallback, changestat, i);
X  }
X}
X
X/*
X * setokbackgrounds - Set initial background pixmaps.  Can't do this
X *   when the stripchart widgets are created as they have to be
X *   realized apparently before the pixmaps can be created.
X */
Xsetokbackgrounds (d, s)
X
XDisplay	*d;
XScreen	*s;
X
X{
X  METER		*h;
X  int		n;
X  Arg		args[10];
X
X  if (bitmap[OK].bm != bitmapdef) {
X      for (h = meterlist; h; h = h->nxt) {
X	  h->pm = XmuCreatePixmapFromBitmap (d, XtWindow (h->scwidget),
X					     bitmap[OK].bm,
X					     bitmap[OK].w, bitmap[OK].h,
X					     DefaultDepthOfScreen (s),
X					     fore[OK],
X					     back[OK]);
X	  n = 0;
X	  XtSetArg (args[n], XtNbackgroundPixmap, h->pm); n++;
X	  XtSetValues (h->scwidget, args, n);
X      }
X  }
X}
X
X/*
X * freechild - Clean up child processes.
X */
Xfreechild ()
X
X{
X  int	status;
X  int	pid;
X  METER	*h;
X
X  pid = wait (&status);
X  for (h = meterlist; h; h = h->nxt)
X      if (h->sh->pid == pid) {	/* Start updating host again	*/
X	  h->sh->pid = -1;
X	  break;
X      }
X}
X
X/*
X * getstatus - Get status from remote host, update meter appropriately,
X *   including changing colors, background pixmap and label if necessary.
X */
Xgetstatus (w, h, data)
X
XWidget	w;
XMETER	*h;
Xchar	*data;
X
X{
X  int			l;
X  int			n;
X  int			s;
X  register SHMETER	*sh;
X  Arg			args[10];
X
X  sh = h->sh;
X  if (h->oldstate == FATAL && sh->pid != -1)	/* Ignore dead hosts	*/
X      return;
X  if (h->oldjumpscroll) {		/* Restore old jumpscroll value	*/
X      n = 0;
X      XtSetArg (args[n], XtNjumpScroll, h->oldjumpscroll); n++;
X      XtSetValues (h->scwidget, args, n);
X      h->oldjumpscroll = 0;
X  }
X  s = state (l = getmeter (h), h);
X  *(double *) data = s == FATAL ? 0.0 : (double) l / sd[h->stat].scale;
X  if (s != h->oldstate) {
X      if (bitmap[h->oldstate].bm != bitmapdef)
X	  XFreePixmap (XtDisplay (w), h->pm);
X      n = 0;				/* Update stripchart widget	*/
X      XtSetArg (args[n], XtNbackground, back[s]); n++;
X      XtSetArg (args[n], XtNforeground, fore[s]); n++;
X      XtSetArg (args[n], XtNhighlight, hl[s]); n++;
X      if (bitmap[s].bm != bitmapdef) {
X	  h->pm = XmuCreatePixmapFromBitmap (XtDisplay (w),
X					     XtWindow (w),
X					     bitmap[s].bm,
X					     bitmap[s].w, bitmap[s].h,
X					     DefaultDepthOfScreen(XtScreen(w)),
X					     fore[s],
X					     back[s]);
X	  XtSetArg (args[n], XtNbackgroundPixmap, h->pm); n++;
X      } else if (bitmap[h->oldstate].bm != bitmapdef) {
X	  XtSetArg (args[n], XtNbackgroundPixmap, XtUnspecifiedPixmap); n++;
X      }
X      XtSetValues (w, args, n);
X      n = 0;				/* Update menubutton widget	*/
X      XtSetArg (args[n], XtNbackground, lback[s]); n++;
X      XtSetArg (args[n], XtNforeground, lfore[s]); n++;
X      if (s == FATAL || h->oldstate == FATAL) {
X	  sprintf (h->label, "%s %s", sh->name,
X		   s == FATAL ? DMSG : sd[h->stat].name);
X	  XtSetArg (args[n], XtNlabel, h->label); n++;
X      }
X      XtSetValues (h->mbwidget, args, n);
X      n = 0;				/* Update paned widget		*/
X      XtSetArg (args[n], XtNborder, bd[s]); n++;
X      XtSetArg (args[n], XtNinternalBorderColor, ibd[s]); n++;
X      XtSetValues (h->pdwidget, args, n);
X      if (prog[s])
X	  runprog (h, s);
X      if (s == FATAL)
X	  sh->pid = waitforhost (h);
X  }
X  h->oldstate = s;
X}
X
X/*
X * waitforhost - Fork process which will wait for host to come back up.
X */
Xint waitforhost (h)
X
XMETER	*h;
X
X{
X  int	pid;
X
X  if (pid = fork ())
X      return (pid);
X  while (1) {
X      sleep (10);
X      if (getport (h) >= 0)
X	  exit (0);
X  }
X}
X
X/*
X * runprog - Run user specified alert program.
X */
Xrunprog (h, s)
X
XMETER	*h;
Xint	s;
X
X{
X  char	oldstate[4];
X  char	state[4];
X
X  sprintf (oldstate, "%d", h->oldstate);
X  sprintf (state, "%d", s);
X  if (vfork ())
X      return;			/* Parent just returns		*/
X  execlp (prog[s], prog[s], oldstate, state, h->sh->name, NULL);
X  fatal (prog[s]);
X}
X
X/*
X * selecthost - Select host for next changestat().
X */
Xselecthost (w, h, data)
X
XWidget	w;
XMETER	*h;
Xchar	*data;
X
X{
X  selected = h;
X}
X
X/*
X * changestat - Change statistic we're looking at.  To clear the stripchart
X *   it's necessary to poke the "interval" field in the StripChartWidget
X *   structure, and then set "jumpScroll" to the width of the stripchart.
X *   jumpScroll is saved here and restored in getstatus().
X */
X#include <X11/IntrinsicP.h>
X#include <X11/Xaw/StripCharP.h>
Xchangestat (w, statidx, data)
X
XWidget	w;
Xint	statidx;
Xchar	*data;
X
X{
X  int	n;
X  Arg	args[10];
X  int	width;
X
X  selected->stat = statidx;
X  sprintf (selected->label, "%s %s", selected->sh->name,
X	   sd[statidx].name);
X  n = 0;
X  XtSetArg (args[n], XtNlabel, selected->label); n++;
X  XtSetValues (selected->mbwidget, args, n);
X  n = 0;
X  XtSetArg (args[n], XtNwidth, &width); n++;
X  XtSetArg (args[n], XtNjumpScroll, &selected->oldjumpscroll); n++;
X  XtGetValues (selected->scwidget, args, n);
X  n = 0;
X  XtSetArg (args[n], XtNjumpScroll, width); n++;
X  XtSetValues (selected->scwidget, args, n);
X  ((StripChartWidget) selected->scwidget)->strip_chart.interval = width;
X}
X
X/*
X * state - Return state of current stat.
X */
Xint state (l, h)
X
Xint	l;
XMETER	*h;
X
X{
X  if (l < 0)
X      return (FATAL);
X  else if (l < warnLevel * sd[h->stat].scale)
X      return (OK);
X  else if (l < errorLevel * sd[h->stat].scale)
X      return (WARN);
X  else
X      return (ERROR);
X}
X
X/*
X * The following functions return the value of the specified stat, which
X * is normally computed by taking the difference between the current
X * value and the previous value, and dividing by the update interval in
X * order to get the current rate.
X */
X#define DIF(m,fld)	(m->sh->st[m->sh->idx].fld - \
X			 m->sh->st[m->sh->idx ^ 1].fld)
X
Xint fcoll (h)
X
XMETER	*h;
X
X{
X  return (DIF (h, if_collisions) / DIF (h, curtime.tv_sec));
X}
X
Xint fcpu (h)
X
XMETER	*h;
X
X{
X  int	i;
X  int	t;
X  int	d[CPUSTATES];
X
X  for (t = 0, i= 0; i < CPUSTATES; i++)
X      t += (d[i] = DIF (h, cp_time[i]));
X  return (t ? (100 * (d[CP_USER]+d[CP_NICE]+d[CP_SYS])) / t : 0);
X}
X
Xint fierr (h)
X
XMETER	*h;
X
X{
X  return (DIF (h, if_ierrors) / DIF (h, curtime.tv_sec));
X}
X
Xint fintr (h)
X
XMETER	*h;
X
X{
X  return (DIF (h, v_intr) / DIF (h, curtime.tv_sec));
X}
X
Xint fipkt (h)
X
XMETER	*h;
X
X{
X  return (DIF (h, if_ipackets) / DIF (h, curtime.tv_sec));
X}
X
Xint fload (h)
X
XMETER	*h;
X
X{
X  return (h->sh->st[h->sh->idx].avenrun[0]);
X}
X
Xint foerr (h)
X
XMETER	*h;
X
X{
X  return (DIF (h, if_oerrors) / DIF (h, curtime.tv_sec));
X}
X
Xint fopkt (h)
X
XMETER	*h;
X
X{
X  return (DIF (h, if_opackets) / DIF (h, curtime.tv_sec));
X}
X
Xint fpage (h)
X
XMETER	*h;
X
X{
X  return ((DIF (h, v_pgpgin) + DIF (h, v_pgpgout)) / DIF (h, curtime.tv_sec));
X}
X
Xint fpgpgin (h)
X
XMETER	*h;
X
X{
X  return (DIF (h, v_pgpgin) / DIF (h, curtime.tv_sec));
X}
X
Xint fpgpgout (h)
X
XMETER	*h;
X
X{
X  return (DIF (h, v_pgpgout) / DIF (h, curtime.tv_sec));
X}
X
Xint  fpswpin (h)
X
XMETER	*h;
X
X{
X  return (DIF (h, v_pswpin) / DIF (h, curtime.tv_sec));
X}
X
Xint fpswpout (h)
X
XMETER	*h;
X
X{
X  return (DIF (h, v_pswpout) / DIF (h, curtime.tv_sec));
X}
X
Xint fswt (h)
X
XMETER	*h;
X
X{
X  return (DIF (h, v_swtch) / DIF (h, curtime.tv_sec));
X}
X
Xint fsys (h)
X
XMETER	*h;
X
X{
X  int	i;
X  int	t;
X  int	d[CPUSTATES];
X
X  for (t = 0, i= 0; i < CPUSTATES; i++)
X      t += (d[i] = DIF (h, cp_time[i]));
X  return (t ? (100 * d[CP_SYS]) / t : 0);
X}
X
Xint fuser (h)
X
XMETER	*h;
X
X{
X  int	i;
X  int	t;
X  int	d[CPUSTATES];
X
X  for (t = 0, i= 0; i < CPUSTATES; i++)
X      t += (d[i] = DIF (h, cp_time[i]));
X  return (t ? (100 * (d[CP_USER] + d[CP_NICE])) / t : 0);
X}
X
X/*
X * getmeter - Executes rstat(3) call to read statistics for specified host.
X *   I do all the rpc junk myself so that I have better control over timeouts
X *   than rstat(3) gives me.  If we're watching multiple stats
X *   on the same host I only do one rstat(3) call (refcnt and curcnt are
X *   used for this).
X */
Xint getmeter (h)
X
Xregister METER	*h;
X
X{
X  enum clnt_stat	cs;
X  register SHMETER	*sh;
X  int			p;
X
X  sh = h->sh;
X  if (sh->curcnt >= sh->refcnt)
X      sh->curcnt = 0;
X  if (!sh->curcnt++) {
X      if (sh->clnt == NULL) {
X          if ((p = getport (h)) < 0)
X	      return (-1);
X	  sh->addr.sin_port = htons (p);
X          sh->s = RPC_ANYSOCK;
X          if (!(sh->clnt = clntudp_create(&sh->addr, RSTATPROG, RSTATVERS_TIME,
X					  ptto, &sh->s)))
X	      return (-1);
X	  sh->first = 1;
X          sh->idx = 0;
X      } else {
X	  sh->first = 0;
X	  sh->idx ^= 1;
X      }
X      cs = clnt_call (sh->clnt, RSTATPROC_STATS, xdr_void, 0, xdr_statstime,
X		      &sh->st[sh->idx], tto);
X      if (cs != RPC_SUCCESS) {
X          clnt_destroy (sh->clnt);
X	  close (sh->s);	/* Some clnt_destroy's don't do this	*/
X          sh->clnt = NULL;
X          return (-1);
X      }
X  }
X  return (sh->first ? 0 :
X		      sh->clnt == NULL ? -1 : (sd[h->stat].val) (h));
X}
X
X/*
X * getport - Get port rstatd is listening on.
X */
Xint getport (h)
X
XMETER	*h;
X
X{
X  CLIENT		*c;
X  enum clnt_stat	cs;
X  static struct pmap	pm = {RSTATPROG, RSTATVERS_TIME, IPPROTO_UDP, 0};
X  short 		p;
X  register SHMETER	*sh;
X
X  sh = h->sh;
X  sh->s = RPC_ANYSOCK;
X  sh->addr.sin_port = htons (PMAPPORT);
X  if (!(c = clntudp_create (&sh->addr, PMAPPROG, PMAPVERS, ptto, &sh->s)))
X      return (-1);
X  cs = clnt_call (c, PMAPPROC_GETPORT, xdr_pmap, &pm, xdr_u_short, &p, tto);
X  clnt_destroy (c);
X  close (sh->s);		/* Some clnt_destroy's don't do this	*/
X  return (cs == RPC_SUCCESS ? p : -1);
X}
X
X/*
X * initmeter - Fill in METER and SHMETER structures for this stat.
X */
XMETER *initmeter (meterlist, idx, argc, argv)
X
XMETER	*meterlist;
Xint	*idx;
Xint	argc;
Xchar	**argv;
X
X{
X  register METER	*h;
X  register SHMETER	*sh;
X  struct hostent	*he;
X  int			i;
X  char			*cp;
X
X  /*
X   * Create and fill in METER struct.
X   */
X  if (!(h = (METER *) malloc (sizeof (METER))))
X      fatal ("METER");
X  h->nxt = meterlist;
X  cp = (argv[*idx][0] == '-') ? &argv[*idx][1] : defstat;
X  for (i = 0; i < MAXSTAT; i++)
X      if (strcmp (cp, sd[i].name) == 0) {
X	  h->stat = i;
X	  break;
X      }
X  if ((cp != defstat) && (++(*idx) == argc || i >= MAXSTAT))
X      usage ();
X  if ((he = gethostbyname (argv[*idx])) == NULL)
X       fatal (argv[*idx]);
X  if (shortname)
X      if (cp = index (he->h_name, '.'))
X          *cp = '\0';
X  if (!(h->label = malloc (strlen (he->h_name) + 2 + MAXSTATNAME)))
X      fatal ("label");
X  sprintf (h->label, "%s %s", he->h_name, sd[h->stat].name);
X  h->oldstate = OK;
X  h->oldjumpscroll = 0;
X  /*
X   * If we're already looking at this host then just point h->sh at
X   * existing structure and we're done.
X   */
X  for (sh = shmeters; sh; sh = sh->nxt)
X      if (strcmp (sh->name, he->h_name) == 0) {
X	  h->sh = sh;
X	  sh->refcnt++;		/* Count how many references	*/
X	  return (h);
X      }
X  /*
X   * Not looking at this host yet, create and fill in SHMETER struct.
X   */
X  if (!(sh = (SHMETER *) malloc (sizeof (SHMETER))))
X      fatal ("SHMETER");
X  sh->nxt = shmeters;	/* Save this struct in linked list	*/
X  shmeters = sh;
X  h->sh = sh;
X  if (!(sh->name = malloc (strlen (he->h_name) + 1)))
X      fatal ("name");
X  strcpy (sh->name, he->h_name);
X  bcopy (he->h_addr, &sh->addr.sin_addr, he->h_length);
X  sh->addr.sin_family = AF_INET;
X  sh->clnt = NULL;
X  sh->refcnt = 1;
X  sh->curcnt = 0;
X  sh->pid = -1;
X  return (h);
X}
X
Xfatal (m)
X
Xchar	*m;
X
X{
X  perror (m);
X  exit (1);
X}
END_OF_FILE
if test 33499 -ne `wc -c <'xmeter.c'`; then
    echo shar: \"'xmeter.c'\" unpacked with wrong size!
fi
# end of 'xmeter.c'
fi
if test -f 'xmeter.man' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'xmeter.man'\"
else
echo shar: Extracting \"'xmeter.man'\" \(14019 characters\)
sed "s/^X//" >'xmeter.man' <<'END_OF_FILE'
X.TH XMETER 1 "14 August 1989" "X Version 11"
X.SH NAME
Xxmeter - rstat display for X
X.SH SYNOPSIS
X.B xmeter
X[-\fItoolkitoption\fP ...] [-\fIoption\fP ...] [-\fIstat\fP] hosts ...
X.SH DESCRIPTION
X.I Xmeter 
Xdisplays a periodically updating histogram of the system statistics
Xgathered by rstat(3) for the specified hosts.  Meters can be
Xdisplayed in a vertical, horizontal or rectangular arrangement.  As
Xstatistics range between 4 user defineable levels (OK, WARN, ERROR
Xor FATAL), the background, foreground, highlight, border and internal
Xborder  colors and the background bitmap of each meter can be changed.
X.LP
X.I Xmeter
Xuses the StripChart widget of the Athena Widget Set to graph each
Xstatistic.  StripCharts automatically scale the graph as the value
Xvaries, by drawing a number of horizontal lines across the StripChart.
XEach line represents an increment of a user settable value.  For
Xexample, if the statistic being graphed is number of pages paged in
Xper second, and the scale is set to 10, then each horizontal line
Xwould represent 10 pages per second.  Each time a graph is updated,
X.I xmeter
Xwill examine the current value of the statistic and the current scale,
Xas the number of scale lines increases above
X.I wlevel
Xand
X.I elevel
Xthe background colors and bitmaps of each graph are modified as specified.
X.LP
XThe statistic being graphed may be modified while
X.I xmeter
Xis running by moving the mouse cursor into the label part of a graph,
Xclicking any mouse button, and sliding down to the desired stat.
X.SH OPTIONS
X.PP
X.I Xmeter
Xaccepts all of the standard X Toolkit command line options along with the 
Xfollowing additional options:
X.PP
X.TP 8
X.B \-cols \fIcols\fP
XThis option specifies the number of columns the meters should be
Xdisplayed in.  If both
X.I cols
Xand
X.I rows
Xare specified,
X.I cols
Xtakes precedence.  The default is 1 column.
X.PP
X.TP 8
X.B \-ebd \fIcolor\fP
XSet error level border color.
X.PP
X.TP 8
X.B \-ebg \fIcolor\fP
XSet error level background color.
X.PP
X.TP 8
X.B \-efg \fIcolor\fP
XSet error level foreground color.
X.PP
X.TP 8
X.B \-ehl \fIcolor\fP
XSet error level highlight color.
X.PP
X.TP 8
X.B \-eibd \fIcolor\fP
XSet error level internal border color.
X.PP
X.TP 8
X.B \-elevel \fIinteger\fP
XThis option specifies the level at which the background color is changed
Xto ebg.  The default is 6.
X.PP
X.TP 8
X.B \-ep \fIprogram\fP
X.I program
Xshould be the name of a program to be invoked when the meter enters the
Xerror state.
X.I program
Xwill be passed 3 arguments, oldstate, newstate and the hostname being
Xmonitored.  Oldstate and newstate will be integers ranging from 0 to
X3, corresponding to levels OK, WARN, ERROR and FATAL.
X.PP
X.TP 8
X.B \-fbd \fIcolor\fP
XSet fatal level border color.
X.PP
X.TP 8
X.B \-fbg \fIcolor\fP
XSet fatal level background color.
X.PP
X.TP 8
X.B \-ffg \fIcolor\fP
XSet fatal level foreground color.
X.PP
X.TP 8
X.B \-fhl \fIcolor\fP
XSet fatal level highlight color.
X.PP
X.TP 8
X.B \-fibd \fIcolor\fP
XSet fatal level internal border color.
X.PP
X.TP 8
X.B \-fp \fIprogram\fP
X.I program
Xshould be the name of a program to be invoked when the monitored host is
Xdown.
X.I program
Xwill be passed 3 arguments, oldstate, newstate and the hostname being
Xmonitored.  Oldstate and newstate will be integers ranging from 0 to
X3, corresponding to levels OK, WARN, ERROR and FATAL.
X.PP
X.TP 8
X.B \-h \fIpixels\fP
XThis option specifies the height of each chart
X.I xmeter
Xwill display.  The default is 80.
X.PP
X.TP 8
X.B \-lebg \fIcolor\fP
XSet error level background color in menubutton.
X.PP
X.TP 8
X.B \-lefg \fIcolor\fP
XSet error level foreground color in menubutton.
X.PP
X.TP 8
X.B \-lfbg \fIcolor\fP
XSet fatal level background color in menubutton.
X.PP
X.TP 8
X.B \-lffg \fIcolor\fP
XSet fatal level foreground color in menubutton.
X.PP
X.TP 8
X.B \-lobg \fIcolor\fP
XSet ok level background color in menubutton.
X.PP
X.TP 8
X.B \-lofg \fIcolor\fP
XSet ok level foreground color in menubutton.
X.PP
X.TP 8
X.B \-lwbg \fIcolor\fP
XSet warn level background color in menubutton.
X.PP
X.TP 8
X.B \-lwfg \fIcolor\fP
XSet warn level foreground color in menubutton.
X.PP
X.TP 8
X.B \-obd \fIcolor\fP
XSet ok level border color.
X.PP
X.TP 8
X.B \-obg \fIcolor\fP
XSet ok level background color.
X.PP
X.TP 8
X.B \-ofg \fIcolor\fP
XSet ok level foreground color.
X.PP
X.TP 8
X.B \-ohl \fIcolor\fP
XSet ok level highlight color.
X.PP
X.TP 8
X.B \-oibd \fIcolor\fP
XSet ok level internal border color.
X.PP
X.TP 8
X.B \-op \fIprogram\fP
X.I program
Xshould be the name of a program to be invoked when the meter enters WARN
Xstate.
X.I program
Xwill be passed 3 arguments, oldstate, newstate and the hostname being
Xmonitored.  Oldstate and newstate will be integers ranging from 0 to
X3, corresponding to levels OK, WARN, ERROR and FATAL.
X.PP
X.TP 8
X.B \-rows \fIrows\fP
XThis option specifies the number of rows the meters should be
Xdisplayed in.  If both
X.I cols
Xand
X.I rows
Xare specified,
X.I cols
Xtakes precedence.  The default is 1 column.
X.PP
X.TP 8
X.B \-rt \fIretries\fP
XThis option specifies the number of times to retry failed RPC calls.
XThe default is 2.
X.PP
X.TP 8
X.B \-scoll \fIinteger\fP
XSet scale for collisions.  The default is 1.
X.PP
X.TP 8
X.B \-scpu \fIinteger\fP
XSet scale for cpu time.  The default is 20.
X.PP
X.TP 8
X.B \-sierr \fIinteger\fP
XSet scale for input errors.  The default is 1.
X.PP
X.TP 8
X.B \-sintr \fIinteger\fP
XSet scale for interrupts.  The default is 50.
X.PP
X.TP 8
X.B \-sipkt \fIinteger\fP
XSet scale for input packets.  The default is 20.
X.PP
X.TP 8
X.B \-sload \fIinteger\fP
XSet scale for load average.  The default is FSCALE (see param.h).
X.PP
X.TP 8
X.B \-sn
XIf specified strips off domain part of host name in menubuttons.
X.PP
X.TP 8
X.B \-soerr \fIinteger\fP
XSet scale for output errors.  The default is 1.
X.PP
X.TP 8
X.B \-sopkt \fIinteger\fP
XSet scale for output packets.  The default is 20.
X.PP
X.TP 8
X.B \-spage \fIinteger\fP
XSet scale for pages paged in and out.  The default is 10.
X.PP
X.TP 8
X.B \-spgpgin \fIinteger\fP
XSet scale for pages paged in.  The default is 10.
X.PP
X.TP 8
X.B \-spgpgout \fIinteger\fP
XSet scale for pages paged out.  The default is 10.
X.PP
X.TP 8
X.B \-spswpin \fIinteger\fP
XSet scale for pages swapped in.  The default is 1.
X.PP
X.TP 8
X.B \-spswpout \fIinteger\fP
XSet scale for pages swapped out.  The default is 1.
X.PP
X.TP 8
X.B \-sswt \fIinteger\fP
XSet scale for context switches.  The default is 30.
X.PP
X.TP 8
X.B \-ssys \fIinteger\fP
XSet scale for sys time.  The default is 20.
X.PP
X.TP 8
X.B \-suser \fIinteger\fP
XSet scale for user time.  The default is 20.
X.PP
X.TP 8
X.B \-to \fIseconds\fP
XThis option specifies the timeout for RPC calls.  The default is 5 seconds.
X.PP
X.TP 8
X.B \-update \fIseconds\fP
XThis option specifies the frequency in seconds at which
X.I xmeter
Xupdates its display.  The minimum amount of time allowed between updates
Xis 5 seconds.  The default is 60 seconds.
X.PP
X.TP 8
X.B \-v
XPrint version number and exit.
X.PP
X.TP 8
X.B \-w \fIpixels\fP
XThis option specifies the width of each chart
X.I xmeter
Xwill display.  The default is 80.
X.PP
X.TP 8
X.B \-wbd \fIcolor\fP
XSet warn level border color.
X.PP
X.TP 8
X.B \-wbg \fIcolor\fP
XSet warn level background color.
X.PP
X.TP 8
X.B \-wfg \fIcolor\fP
XSet warn level foreground color.
X.PP
X.TP 8
X.B \-whl \fIcolor\fP
XSet warn level highlight color.
X.PP
X.TP 8
X.B \-wibd \fIcolor\fP
XSet warn level internal border color.
X.PP
X.TP 8
X.B \-wlevel \fIinteger\fP
XThis option specifies the level at which the background color is changed
Xto wbg.  The default is 3.
X.PP
X.TP 8
X.B \-wp \fIprogram\fP
X.I program
Xshould be the name of a program to be invoked when the meter enters
XWARN state.
X.I program
Xwill be passed 3 arguments, oldstate, newstate and the hostname being
Xmonitored.  Oldstate and newstate will be integers ranging from 0 to
X3, corresponding to levels OK, WARN, ERROR and FATAL.
X.SH STATISTICS
X.PP
X.TP 8
X.B \-coll
XGraph number of collisions per second.
X.PP
X.TP 8
X.B \-cpu
XGraph percentage of non idle time for the specified host.
X.PP
X.TP 8
X.B \-ierr
XGraph number of input errors per second.
X.PP
X.TP 8
X.B \-intr
XGraph number of interrupts per second.
X.PP
X.TP 8
X.B \-ipkt
XGraph number of input packets per second.
X.PP
X.TP 8
X.B \-load
XGraph 1 minute load average.
X.PP
X.TP 8
X.B \-oerr
XGraph number of output errors per second.
X.PP
X.TP 8
X.B \-opkt
XGraph number of output packets per second.
X.PP
X.TP 8
X.B \-page
XSum of pgpgin and pgpgout values.
X.PP
X.TP 8
X.B \-pgpgin
XGraph number of pages paged in per second.
X.PP
X.TP 8
X.B \-pgpgout
XGraph number of pages paged out per second.
X.PP
X.TP 8
X.B \-pswpin
XGraph number of swapins per second.
X.PP
X.TP 8
X.B \-pswpout
XGraph number of swapouts per second.
X.PP
X.TP 8
X.B \-swt
XGraph number of context switches per second.
X.PP
X.TP 8
X.B \-sys
XGraph percentage of system time for the specified host.
X.PP
X.TP 8
X.B \-user
XGraph percentage of user time for the specified host.
X.SH "WIDGET HIERARCHY"
XThe widget hierarchy for
X.I xmeter
Xis given below.  Class names are given first, followed by instance
Xnames.
X.sp
X.nf
XXMeter xmeter
X	Form form
X		SimpleMenu statmenu
X			SmeBSB <stat>
X		Paned <hostname>
X			MenuButton menu
X			StripChart load
X.SH "RESOURCES"
XThe following resources are defined.  Resource instance names
Xare specified first, followed by class name.
X.PP
X.TP 8
X.B columns Columns
XSet number of columns of display.
X.PP
X.TP 8
X.B defStat DefStat
XDefault statistic to graph, the default is \fBload\fP.
X.PP
X.TP 8
X.B errorBack Background
XError level background color.
X.PP
X.TP 8
X.B errorBd Foreground
XError level border color.
X.PP
X.TP 8
X.B errorBitmap Bitmap
XError level background bitmap.
X.PP
X.TP 8
X.B errorFore Foreground
XError level foreground color.
X.PP
X.TP 8
X.B errorHl Foreground
XError level highlight color.
X.PP
X.TP 8
X.B errorIbd Foreground
XError level internal border color.
X.PP
X.TP 8
X.B errorLevel ErrorLevel
XWhen a statistic is above this value colors and bitmaps are
Xset to the appropriate error level value.
X.PP
X.TP 8
X.B errorProg Program
XProgram to be invoked when a meter enters error state.
X.PP
X.TP 8
X.B fatalBack Background
XBackground color of dead hosts.
X.PP
X.TP 8
X.B fatalBd Foreground
XBorder color of dead hosts.
X.PP
X.TP 8
X.B fatalBitmap Bitmap
XBackground bitmap of dead hosts.
X.PP
X.TP 8
X.B fatalFore Foreground
XForeground color of dead hosts.
X.PP
X.TP 8
X.B fatalHl Foreground
XHighlight color of dead hosts.
X.PP
X.TP 8
X.B fatalIbd Foreground
XInternal border color of dead hosts.
X.PP
X.TP 8
X.B fatalProg Program
XProgram to be invoked when a meter enters fatal state.
X.PP
X.TP 8
X.B lErrorBack Background
XError level background color of menubutton widget.
X.PP
X.TP 8
X.B lErrorFore Foreground
XError level foreground color of menubutton widget.
X.PP
X.TP 8
X.B lFatalBack Background
XFatal level background color of menubutton widget.
X.PP
X.TP 8
X.B lFatalFore Foreground
XFatal level foreground color of menubutton widget.
X.PP
X.TP 8
X.B lOkBack Background
XOk level background color of menubutton widget.
X.PP
X.TP 8
X.B lOkFore Foreground
XOk level foreground color of menubutton widget.
X.PP
X.TP 8
X.B lWarnBack Background
XWarn level background color of menubutton widget.
X.PP
X.TP 8
X.B lWarnFore Foreground
XWarn level foreground color of menubutton widget.
X.PP
X.TP 8
X.B okBack Background
XOk level background color.
X.PP
X.TP 8
X.B okBd Foreground
XOk level border color.
X.PP
X.TP 8
X.B okBitmap Bitmap
XOk level background bitmap.
X.PP
X.TP 8
X.B okFore Foreground
XOk level foreground color.
X.PP
X.TP 8
X.B okHl Foreground
XOk level highlight color.
X.PP
X.TP 8
X.B okIbd Foreground
XOk level internal border color.
X.PP
X.TP 8
X.B okProg Program
XProgram to be invoked when a meter enters ok state.
X.PP
X.TP 8
X.B retries Retries
XNumber of retries for RPC calls.
X.PP
X.TP 8
X.B rows Rows
XNumber of rows to display.
X.PP
X.TP 8
X.B scaleColl ScaleColl
XScale for interface collisions.
X.PP
X.TP 8
X.B scaleCpu ScaleCpu
XScale for percentage cpu usage.
X.PP
X.TP 8
X.B scaleIerr ScaleIerr
XScale for interface input errors.
X.PP
X.TP 8
X.B scaleIerr ScaleIntr
XScale for interface interrupts.
X.PP
X.TP 8
X.B scaleIpkt ScaleIpkt
XScale for interface input packets.
X.PP
X.TP 8
X.B scaleLoad ScaleLoad
XScale for load average.
X.PP
X.TP 8
X.B scaleOerr ScaleOerr
XScale for interface output errors.
X.PP
X.TP 8
X.B scaleOpkt ScaleOpkt
XScale for interface output packets.
X.PP
X.TP 8
X.B scalePage ScalePage
XScale for paging (sum of pageins and pageouts).
X.PP
X.TP 8
X.B scalePgpgin ScalePgpgin
XScale for pages paged in.
X.PP
X.TP 8
X.B scalePgpgout ScalePgpgout
XScale for pages paged out.
X.PP
X.TP 8
X.B scalePswpin ScalePswpin
XScale for swap ins.
X.PP
X.TP 8
X.B scalePswpout ScalePswpout
XScale for swap outs.
X.PP
X.TP 8
X.B scaleSwt ScaleSwt
XScale for context switches.
X.PP
X.TP 8
X.B scaleSys ScaleSys
XScale for percentage system time.
X.PP
X.TP 8
X.B scaleUser ScaleUser
XScale for percentage user time.
X.PP
X.TP 8
X.B shortName ShortName
XTrim domains off host names.
X.PP
X.TP 8
X.B timeout Timeout
XTimeout for RPC calls.
X.PP
X.TP 8
X.B update Interval
XInterval between updates.
X.PP
X.TP 8
X.B warnBack Background
XWarn level background color.
X.PP
X.TP 8
X.B warnBd Foreground
XWarn level border color.
X.PP
X.TP 8
X.B warnBitmap Bitmap
XWarn level Background bitmap.
Xbelow ErrorLevel.
X.PP
X.TP 8
X.B warnFore Foreground
XWarn level foreground color.
X.PP
X.TP 8
X.B warnHl Foreground
XWarn level highlight color.
X.PP
X.TP 8
X.B warnIbd Foreground
XWarn level internal border.
X.PP
X.TP 8
X.B warnLevel WarnLevel
XWhen statistic is above this level and below ErrorLevel background colors
Xand bitmaps are set to WarnBack and WarnBitmap.
X.PP
X.TP 8
X.B warnProg Program
XProgram to be invoked when a meter enters warn state.
X.SH BUGS
XWhen a host doesn't respond it can sometimes take awhile for the labels
Xin the menubuttons to update.
X.LP
XIf a height for the meters is specified but not a width, the error
X"Widget has zero width and/or height" is printed by the X toolkit.
XThe converse is not true.  I suspect the problem is in the Paned
Xwidget but xmeter could be doing something wrong.  The supplied
Xapplication defaults file initializes both width and height, as long
Xas this is installed there shouldn't be a problem unless the user
Xexplicitly sets width to 0.
X.SH AUTHOR
XBob Schwartzkopf, The RAND Corporation.  Based on xload from MIT.
END_OF_FILE
if test 14019 -ne `wc -c <'xmeter.man'`; then
    echo shar: \"'xmeter.man'\" unpacked with wrong size!
fi
# end of 'xmeter.man'
fi
if test -f 'XMeter.ad' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'XMeter.ad'\"
else
echo shar: Extracting \"'XMeter.ad'\" \(80 characters\)
sed "s/^X//" >'XMeter.ad' <<'END_OF_FILE'
XXMeter*Paned.Width:		80
XXMeter*Paned.Height:		80
XXMeter*StripChart.Interval:	60
END_OF_FILE
if test 80 -ne `wc -c <'XMeter.ad'`; then
    echo shar: \"'XMeter.ad'\" unpacked with wrong size!
fi
# end of 'XMeter.ad'
fi
echo shar: End of shell archive.
exit 0


--
Dan Heller
O'Reilly && Associates       Z-Code Software    Comp-sources-x:
Senior Writer                President          comp-sources-x at uunet.uu.net
argv at ora.com                 argv at zipcode.com



More information about the Comp.sources.x mailing list