~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

src/xmeter-1.15/xmeter.c

: ~

  1 /*
  2  * xmeter.c - Display histogram of rstat(3) output for multiple hosts.
  3  *
  4  * Copyright (c) 1991, Bob Schwartzkopf
  5  *
  6  * Permission to use, copy, modify and distribute this software and its
  7  * documentation for any purpose is hereby granted without fee, provided
  8  * that the above copyright notice appear in all copies and that both the
  9  * copyright notice and this permission notice appear in supporting
 10  * documentation, and that the name of the RAND Corporation not be used
 11  * in advertising or publicity pertaining to distribution of the software
 12  * without specific, written prior permission.  The RAND Corporation
 13  * makes no representations about the suitability of this software for
 14  * any purpose.  It is provided "as is" without express or implied
 15  * warranty.
 16  *
 17  * The X Consortium, and any party obtaining a copy of these files from
 18  * the X Consortium, directly or indirectly, is granted, free of charge, a
 19  * full and unrestricted irrevocable, world-wide, paid up, royalty-free,
 20  * nonexclusive right and license to deal in this software and
 21  * documentation files (the "Software"), including without limitation the
 22  * rights to use, copy, modify, merge, publish, distribute, sublicense,
 23  * and/or sell copies of the Software, and to permit persons who receive
 24  * copies from any such party to do so.  This license includes without
 25  * limitation a license to do the foregoing actions under any patents of
 26  * the party supplying this software to the X Consortium.
 27  *
 28  * Author: Bob Schwartzkopf, The RAND Corporation
 29  *
 30  * Suggestions for improvements and bug fixes can be sent to "bobs@rand.org".
 31  * As my schedule permits I'll try to incorporate them.
 32  */
 33 
 34 #ifndef lint
 35 static char     *RCSid="$Header: /net/src/rand/bin/xmeter/RCS/xmeter.c,v 1.19 1994/05/25 01:01:08 bobs Exp $";
 36 #endif lint
 37 
 38 /*
 39  * $Log: xmeter.c,v $
 40  * Revision 1.19  1994/05/25  01:01:08  bobs
 41  * Add X copyright.
 42  *
 43  * Revision 1.18  1994/02/12  02:46:40  bobs
 44  * Port to solaris 2.
 45  *
 46  * Revision 1.17  1994/02/10  20:54:17  bobs
 47  * Fixed bug in quit() that caused core dumps.
 48  * Removed bcopy() call in newshmeter().
 49  *
 50  * Revision 1.16  1993/12/09  20:10:26  bobs
 51  * Patches 12 and 13 (see README for details).
 52  *
 53  * Revision 1.15  1993/08/18  01:42:33  bobs
 54  * Fixed bug in fdisks(), dk_xfer dimensioned is 4.
 55  * Include <X11/Xos.h>, remove some other includes and external declarations.
 56  * Changed vfork to vork.
 57  * Don't destroy popup widget in popdownscale if it's null.
 58  * Include <sys/dk.h> under hpux.
 59  *
 60  * Revision 1.14  1993/05/25  00:06:27  bobs
 61  * Use sigset(3) under SVR4.
 62  *
 63  * Revision 1.13  1993/01/25  22:32:18  bobs
 64  * Redo previous 2 edits.
 65  *
 66  * Revision 1.12  1993/01/19  00:24:22  bobs
 67  * Have child processes exit if parent has gone away.
 68  *
 69  * Revision 1.11  1993/01/19  00:12:33  bobs
 70  * Kill children on INT signal too.
 71  *
 72  * Revision 1.10  1993/01/19  00:08:56  bobs
 73  * Kill child processes on TERM signal.
 74  *
 75  * Revision 1.9  1992/05/21  00:11:17  bobs
 76  * Add option to display current value in label.
 77  * Add quit option to stat menu.
 78  * Redo application resource handling in more portable way.
 79  * Use complete hostname for comparisons when shortnames has been specified.
 80  * Redo child process cleanup code in a hopefully more portable way.
 81  * Add stat name as fourth arg to alert programs.
 82  * Fix divide by zero problem in functions that return stat values.
 83  *
 84  * Revision 1.8  1991/09/16  21:01:04  bobs
 85  * Fix bugs handling down hosts.
 86  * Add composite stats swap, disks, page and pkts.
 87  * Add popup window with version number, scale and downtime (if applicable).
 88  *
 89  * Revision 1.7  1991/06/03  22:21:43  root
 90  * Add -v option to print xmeter version number.
 91  * Add defstat option.
 92  * Add code to clear stripchart when watched stat is changed.
 93  * When host is down fork process to wait for it to come up instead of
 94  * having toplevel process wait for timeouts.
 95  *
 96  * Revision 1.6  90/09/28  20:32:34  root
 97  * Add explicit closes of sockets back in, apparently some versions of
 98  * clnt_destroy() don't do it automatically.
 99  * 
100  * Revision 1.5  90/09/18  20:47:03  root
101  * Allow user specification of foreground colors.
102  * 
103  * Revision 1.4  90/08/20  14:18:01  root
104  * Added menus, column and row options, background bitmaps, and user
105  * specifiable programs to be invoked when graphs change state.
106  * 
107  * Revision 1.3  90/06/07  16:17:06  bobs
108  * Removed "retries".
109  * Changed name of paned widgets to host name displayed in that widget.
110  * Used actual time between rstat calls instead of "update" interval in
111  * computing rates in functions that return values to stripchart widgets.
112  * Removed "ost" variable, rewrote functions that return values to
113  * stripcharts.
114  * Fixed bug in fsys, fcpu and fuser that could cause divide by 0 errors.
115  * Fixed rpc timeout handling in getmeter and getport.
116  * Use RSTATVERS_TIME instead of RSTATVERS, which isn't defined in SunOS 4.1.
117  * 
118  * Revision 1.2  90/05/04  12:31:52  bobs
119  * Fix memory leak in getport().  Wasn't freeing resources allocated by
120  * clntudp_create when clnt_call failed.  Also removed explicit calls
121  * to close sockets since clnt_destroy() does this.
122  * 
123  * Revision 1.1  90/04/30  14:33:59  bobs
124  * Initial revision
125  * 
126  */
127 
128 #include <stdio.h>
129 #include <sys/time.h>
130 #include <sys/param.h>
131 #include <sys/socket.h>
132 #include <sys/wait.h>
133 #include <signal.h>
134 #include <netdb.h>
135 #define PORTMAP         /* Get right function declarations on Solaris 2 */
136 #include <rpc/rpc.h>
137 #include <rpc/pmap_prot.h>
138 #include <rpcsvc/rstat.h>
139 /*
140  * We need the definitions of CP_USER, CP_NICE and CP_SYS.  Some systems
141  * declare them in <sys/dk.h>, which may or may not be included by
142  * <rpcsvc/rstat.h>, others define them in <rpcsvc/rstat.h>, and others 
143  * don't seem to define them anywhere.  To simplify things I'm just
144  * going to define them here if I didn't get them from <rpcsvc/rstat.h>.
145  * If they ever change this is going to break.
146  */
147 #ifndef CP_USER
148 #define CP_USER         0
149 #define CP_NICE         1
150 #define CP_SYS          2
151 #endif
152 #ifndef CPUSTATES
153 #ifdef RSTAT_CPUSTATES
154 #define CPUSTATES       RSTAT_CPUSTATES
155 #else
156 #define CPUSTATES       4
157 #endif
158 #endif
159 #include <X11/Xos.h>
160 #include <X11/Xlib.h>
161 #include <X11/Intrinsic.h>
162 #include <X11/StringDefs.h>
163 #include <X11/Xatom.h>
164 #include <X11/Shell.h>
165 #include <X11/Xaw/Cardinals.h>
166 #include <X11/Xaw/Form.h>
167 #include <X11/Xaw/StripChart.h>
168 #include <X11/Xaw/SimpleMenu.h>
169 #include <X11/Xaw/MenuButton.h>
170 #include <X11/Xaw/SmeBSB.h>
171 #include <X11/Xaw/Paned.h>
172 #include <X11/Xmu/Xmu.h>
173 #include "patchlevel.h"
174 
175 #define MAJORVERSION    1
176 #define DMSG            "down"
177 #define OK              0
178 #define WARN            1
179 #define ERROR           2
180 #define FATAL           3
181 #define MAXBACKS        (FATAL+1)
182 #define STATMENU        "statmenu"
183 #ifndef FSCALE
184 #define FSCALE          (1 << 8)
185 #endif
186 
187 /*
188  * There is one METER structure per strip chart.  If multiple stats
189  * on a single host are being watched we save rstatd calls by sharing
190  * part of this structure (SHMETER) between the different meters watching
191  * the same host.
192  */
193 typedef struct _shmeter {
194     char                *name;  /* Host name                            */
195     char                *label; /* Displayed host name                  */
196     struct sockaddr_in  addr;
197     CLIENT              *clnt;
198     int                 s;      /* Socket                               */
199     struct statstime    st[2];  /* Keep last 2 stats to compute diffs   */
200     int                 idx;    /* Index into st array                  */
201     int                 refcnt; /* Meters sharing this structure        */
202     int                 curcnt; /* Meters who've displayed current data */
203     int                 first;  /* TRUE when only 1 rstat has been done */
204     int                 pid;    /* Pid of proc waiting for host         */
205     time_t              when;   /* Time we first notice host down       */
206     struct _shmeter     *nxt;   /* Link these together                  */
207 } SHMETER;
208 
209 typedef struct _meter {
210     char                *label;
211     int                 stat;           /* Which stat to watch          */
212     Widget              pdwidget;       /* Paned widget                 */
213     Widget              mbwidget;       /* MenuButton widget            */
214     Widget              scwidget;       /* StripChart widget            */
215     int                 oldstate;       /* Save state so know when to   */
216                                         /* change backgrounds           */
217     SHMETER             *sh;            /* Shared info                  */
218     Pixmap              pm;             /* Current background pixmap    */
219     int                 oldjumpscroll;  /* Old jumpscroll value         */
220     struct _meter       *nxt;
221 } METER;
222 
223 /*
224  * There is a STATDATA structure for each statistic that can be monitored.
225  */
226 typedef struct {
227     int         (*val)();       /* Function that computes this stat     */
228     char        *name;          /* Name of stat for menu widget         */
229 } STATDATA;
230 
231 #if defined(SVR4) || defined(sgi)
232 #define SIGTYPE void
233 #else
234 #define SIGTYPE int
235 #endif
236 
237 int             getstatus();
238 int             changestat();
239 int             selecthost();
240 SIGTYPE         freechild();
241 METER           *initmeter();
242 SHMETER         *newshmeter();
243 int             fcoll(), fcpu(), fierr(), fintr(), fipkt(), fload();
244 int             foerr(), fopkt(), fpage(), fpgpgin(), fpgpgout();
245 int             fpswpin(), fpswpout(), fswt(), fsys(), fuser();
246 int             fpkts(), fdisks(), fswap(), ferr();
247 void            popupscale();
248 void            popdownscale();
249 void            quit();
250 char            *mystrdup();
251 
252 static STATDATA         sd[] = {
253 #define S_COLL          0
254   {fcoll, "coll"},
255 #define S_CPU           S_COLL+1
256   {fcpu, "cpu"},
257 #define S_DISKS         S_CPU+1
258   {fdisks, "disks"},
259 #define S_ERR           S_DISKS+1
260   {ferr, "err"},
261 #define S_IERR          S_ERR+1
262   {fierr, "ierr"},
263 #define S_INTR          S_IERR+1
264   {fintr, "intr"},
265 #define S_IPKT          S_INTR+1
266   {fipkt, "ipkt"},
267 #define S_LOAD          S_IPKT+1
268   {fload, "load"},
269 #define S_OERR          S_LOAD+1
270   {foerr, "oerr"},
271 #define S_OPKT          S_OERR+1
272   {fopkt, "opkt"},
273 #define S_PAGE          S_OPKT+1
274   {fpage, "page"},
275 #define S_PGPGIN        S_PAGE+1
276   {fpgpgin, "pgpgin"},
277 #define S_PGPGOUT       S_PGPGIN+1
278   {fpgpgout, "pgpgout"},
279 #define S_PKTS          S_PGPGOUT+1
280   {fpkts, "pkts"},
281 #define S_PSWPIN        S_PKTS+1
282   {fpswpin, "pswpin"},
283 #define S_PSWPOUT       S_PSWPIN+1
284   {fpswpout, "pswpout"},
285 #define S_SWAP          S_PSWPOUT+1
286   {fswap, "swap"},
287 #define S_SWT           S_SWAP+1
288   {fswt, "swt"},
289 #define S_SYS           S_SWT+1
290   {fsys, "sys"},
291 #define S_USER          S_SYS+1
292   {fuser, "user"},
293 };
294 #define DEFSTATNAME     "load"
295 #define MAXSTAT         (sizeof(sd) / sizeof(STATDATA))
296 #define MAXSTATNAME     10              /* Max length of stat name      */
297 #define MAXSTATVALUE    10              /* Max length of stat value     */
298 
299 /*
300  * xmeter supports 4 background colors and pixmaps that it will switch
301  * between as a meter changes state, called OK, WARN, ERROR and FATAL.
302  * The background bitmaps are stored in BITMAP structures.
303  */
304 typedef struct {
305   int           w;                              /* Width of bitmap      */
306   int           h;                              /* Height of bitmap     */
307   Pixmap        bm;                             /* Bitmap               */
308 } BITMAP;
309 
310 /*
311  * Application specific resources are stored in an APPRESOURCES structure.
312  **/
313 typedef struct {
314   Pixel                 back[MAXBACKS];         /* Meter backgrounds    */
315   Pixel                 bd[MAXBACKS];           /* Meter borders        */
316   BITMAP                bitmap[MAXBACKS];       /* Stripchart bg pixmaps*/
317   int                   columns;                /* Columns to display   */
318   String                defStat;                /* Default stat         */
319   Boolean               displayValue;           /* Show value in label  */
320   int                   errorLevel;             /* Error level          */
321   Pixel                 fore[MAXBACKS];         /* Meter foregrounds    */
322   Pixel                 hl[MAXBACKS];           /* Meter highlights     */
323   Pixel                 ibd[MAXBACKS];          /* Meter internal bds   */
324   Pixel                 lback[MAXBACKS];        /* Label backgrounds    */
325   Pixel                 lfore[MAXBACKS];        /* Label foregrounds    */
326   String                prog[MAXBACKS];         /* Alert programs       */
327   int                   retries;                /* RPC retries          */
328   int                   rows;                   /* Rows to display      */
329   int                   scales[MAXSTAT];        /* Scale for each stat  */
330   Boolean               shortName;              /* Short hostname flag  */
331   int                   timeout;                /* RPC timeout          */
332   int                   warnLevel;              /* Warning level        */
333 } APPRESOURCES;
334 
335 /*
336  * Global variables.
337  */
338 static char             *progname;
339 static Pixmap           bitmapdef = XtUnspecifiedPixmap;
340 static struct timeval   ptto = {0, 0};          /* RPC timeout interval */
341 static struct timeval   tto = {0, 0};           /* Total timeout        */
342 static SHMETER          *shmeters = NULL;       /* List of SHMETERs     */
343 static METER            *selected;              /* Current meter        */
344 static METER            *meterlist = NULL;      /* List of METERs       */
345 static int              loadscaledef = FSCALE;  /* Scale for load ave.  */
346 static Widget           popup;          /* Used by pop[up|down]scale    */
347 static APPRESOURCES     ar;             /* App specific resources       */
348 
349 #define offset(f)       XtOffsetOf(APPRESOURCES, f)
350 static XtResource       resources[] = {
351     {"columns", "Columns", XtRInt, sizeof(int),
352         offset(columns), XtRString, ""},
353     {"defStat", "DefStat", XtRString, sizeof(char *),
354         offset(defStat), XtRString, DEFSTATNAME},
355     {"displayValue", "DisplayValue", XtRBoolean, sizeof(Boolean),
356         offset(displayValue), XtRString, "False"},
357     {"errorBack", XtCBackground, XtRPixel, sizeof(Pixel),
358         offset(back[ERROR]), XtRString, XtDefaultBackground},
359     {"errorBd", XtCForeground, XtRPixel, sizeof(Pixel),
360         offset(bd[ERROR]), XtRString, XtDefaultForeground},
361     {"errorBitmap", XtCBitmap, XtRBitmap, sizeof(Pixmap),
362         offset(bitmap[ERROR].bm), XtRBitmap,(caddr_t) &bitmapdef},
363     {"errorFore", XtCForeground, XtRPixel, sizeof(Pixel),
364         offset(fore[ERROR]), XtRString, XtDefaultForeground},
365     {"errorHl", XtCForeground, XtRPixel, sizeof(Pixel),
366         offset(hl[ERROR]), XtRString, XtDefaultForeground},
367     {"errorIbd", XtCForeground, XtRPixel, sizeof(Pixel),
368         offset(ibd[ERROR]), XtRString, XtDefaultForeground},
369     {"errorLevel", "ErrorLevel", XtRInt, sizeof(int),
370         offset(errorLevel), XtRString, "6"},
371     {"errorProg", "Program", XtRString, sizeof(char *),
372         offset(prog[ERROR]), XtRString, NULL},
373     {"fatalBack", XtCBackground, XtRPixel, sizeof(Pixel),
374         offset(back[FATAL]), XtRString, XtDefaultBackground},
375     {"fatalBd", XtCForeground, XtRPixel, sizeof(Pixel),
376         offset(bd[FATAL]), XtRString, XtDefaultForeground},
377     {"fatalBitmap", XtCBitmap, XtRBitmap, sizeof(Pixmap),
378         offset(bitmap[FATAL].bm), XtRBitmap,(caddr_t) &bitmapdef},
379     {"fatalFore", XtCForeground, XtRPixel, sizeof(Pixel),
380         offset(fore[FATAL]), XtRString, XtDefaultForeground},
381     {"fatalHl", XtCForeground, XtRPixel, sizeof(Pixel),
382         offset(hl[FATAL]), XtRString, XtDefaultForeground},
383     {"fatalIbd", XtCForeground, XtRPixel, sizeof(Pixel),
384         offset(ibd[FATAL]), XtRString, XtDefaultForeground},
385     {"fatalProg", "Program", XtRString, sizeof(char *),
386         offset(prog[FATAL]), XtRString, NULL},
387     {"lErrorBack", XtCBackground, XtRPixel, sizeof(Pixel),
388         offset(lback[ERROR]), XtRString, XtDefaultBackground},
389     {"lErrorFore", XtCForeground, XtRPixel, sizeof(Pixel),
390         offset(lfore[ERROR]), XtRString, XtDefaultForeground},
391     {"lFatalBack", XtCBackground, XtRPixel, sizeof(Pixel),
392         offset(lback[FATAL]), XtRString, XtDefaultBackground},
393     {"lFatalFore", XtCForeground, XtRPixel, sizeof(Pixel),
394         offset(lfore[FATAL]), XtRString, XtDefaultForeground},
395     {"lOkBack", XtCBackground, XtRPixel, sizeof(Pixel),
396         offset(lback[OK]), XtRString, XtDefaultBackground},
397     {"lOkFore", XtCForeground, XtRPixel, sizeof(Pixel),
398         offset(lfore[OK]), XtRString, XtDefaultForeground},
399     {"lWarnBack", XtCBackground, XtRPixel, sizeof(Pixel),
400         offset(lback[WARN]), XtRString, XtDefaultBackground},
401     {"lWarnFore", XtCForeground, XtRPixel, sizeof(Pixel),
402         offset(lfore[WARN]), XtRString, XtDefaultForeground},
403     {"okBack", XtCBackground, XtRPixel, sizeof(Pixel),
404         offset(back[OK]), XtRString, XtDefaultBackground},
405     {"okBd", XtCForeground, XtRPixel, sizeof(Pixel),
406         offset(bd[OK]), XtRString, XtDefaultForeground},
407     {"okBitmap", XtCBitmap, XtRBitmap, sizeof(Pixmap),
408         offset(bitmap[OK].bm), XtRBitmap, (caddr_t) &bitmapdef},
409     {"okFore", XtCForeground, XtRPixel, sizeof(Pixel),
410         offset(fore[OK]), XtRString, XtDefaultForeground},
411     {"okHl", XtCForeground, XtRPixel, sizeof(Pixel),
412         offset(hl[OK]), XtRString, XtDefaultForeground},
413     {"okIbd", XtCForeground, XtRPixel, sizeof(Pixel),
414         offset(ibd[OK]), XtRString, XtDefaultForeground},
415     {"okProg", "Program", XtRString, sizeof(char *),
416         offset(prog[OK]), XtRString, NULL},
417     {"retries", "Retries", XtRInt, sizeof(int),
418         offset(retries), XtRString, "2"},
419     {"rows", "Rows", XtRInt, sizeof(int),
420         offset(rows), XtRString, ""},
421     {"scaleColl", "ScaleColl", XtRInt, sizeof(int),
422         offset(scales[S_COLL]), XtRString, "1"},
423     {"scaleCpu", "ScaleCpu", XtRInt, sizeof(int),
424         offset(scales[S_CPU]), XtRString, "20"},
425     {"scaleDisks", "ScaleDisks", XtRInt, sizeof(int),
426         offset(scales[S_DISKS]), XtRString, "40"},
427     {"scaleErr", "ScaleErr", XtRInt, sizeof(int),
428         offset(scales[S_ERR]), XtRString, "1"},
429     {"scaleIerr", "ScaleIerr", XtRInt, sizeof(int),
430         offset(scales[S_IERR]), XtRString, "1"},
431     {"scaleIntr", "ScaleIntr", XtRInt, sizeof(int),
432         offset(scales[S_INTR]), XtRString, "50"},
433     {"scaleIpkt", "ScaleIpkt", XtRInt, sizeof(int),
434         offset(scales[S_IPKT]), XtRString, "20"},
435     {"scaleLoad", "ScaleLoad", XtRInt, sizeof(int),
436         offset(scales[S_LOAD]), XtRInt, (caddr_t) &loadscaledef},
437     {"scaleOerr", "ScaleOerr", XtRInt, sizeof(int),
438         offset(scales[S_OERR]), XtRString, "1"},
439     {"scaleOpkt", "ScaleOpkt", XtRInt, sizeof(int),
440         offset(scales[S_OPKT]), XtRString, "20"},
441     {"scalePage", "ScalePage", XtRInt, sizeof(int),
442         offset(scales[S_PAGE]), XtRString, "10"},
443     {"scalePgpgin", "ScalePgpgin", XtRInt, sizeof(int),
444         offset(scales[S_PGPGIN]), XtRString, "10"},
445     {"scalePgpgout", "ScalePgpgout", XtRInt, sizeof(int),
446         offset(scales[S_PGPGOUT]), XtRString, "10"},
447     {"scalePkts", "ScalePkts", XtRInt, sizeof(int),
448         offset(scales[S_PKTS]), XtRString, "40"},
449     {"scalePswpin", "ScalePswpin", XtRInt, sizeof(int),
450         offset(scales[S_PSWPIN]), XtRString, "5"},
451     {"scalePswpout", "ScalePswpout", XtRInt, sizeof(int),
452         offset(scales[S_PSWPOUT]), XtRString, "5"},
453     {"scaleSwap", "ScaleSwap", XtRInt, sizeof(int),
454         offset(scales[S_SWAP]), XtRString, "5"},
455     {"scaleSwt", "ScaleSwt", XtRInt, sizeof(int),
456         offset(scales[S_SWT]), XtRString, "30"},
457     {"scaleSys", "ScaleSys", XtRInt, sizeof(int),
458         offset(scales[S_SYS]), XtRString, "20"},
459     {"scaleUser", "ScaleUser", XtRInt, sizeof(int),
460         offset(scales[S_USER]), XtRString, "20"},
461     {"shortName", "Shortname", XtRBoolean, sizeof(Boolean),
462         offset(shortName), XtRString, "False"},
463     {"timeout", "Timeout", XtRInt, sizeof(int),
464         offset(timeout), XtRString, "5"},
465     {"warnBack", XtCBackground, XtRPixel, sizeof(Pixel),
466         offset(back[WARN]), XtRString, XtDefaultBackground},
467     {"warnBd", XtCForeground, XtRPixel, sizeof(Pixel),
468         offset(bd[WARN]), XtRString, XtDefaultForeground},
469     {"warnBitmap", XtCBitmap, XtRBitmap, sizeof(Pixmap),
470         offset(bitmap[WARN].bm), XtRBitmap, (caddr_t) &bitmapdef},
471     {"warnFore", XtCForeground, XtRPixel, sizeof(Pixel),
472         offset(fore[WARN]), XtRString, XtDefaultForeground},
473     {"warnHl", XtCForeground, XtRPixel, sizeof(Pixel),
474         offset(hl[WARN]), XtRString, XtDefaultForeground},
475     {"warnIbd", XtCForeground, XtRPixel, sizeof(Pixel),
476         offset(ibd[WARN]), XtRString, XtDefaultForeground},
477     {"warnLevel", "WarnLevel", XtRInt, sizeof(int),
478         offset(warnLevel), XtRString, "3"},
479     {"warnProg", "Program", XtRString, sizeof(char *),
480         offset(prog[WARN]), XtRString, NULL},
481 };
482 static XrmOptionDescRec options[] = {
483     {"-cols",           "columns",              XrmoptionSepArg, NULL},
484     {"-dv",             "displayValue",         XrmoptionNoArg, "True"},
485     {"-ebd",            "errorBd",              XrmoptionSepArg, NULL},
486     {"-ebg",            "errorBack",            XrmoptionSepArg, NULL},
487     {"-efg",            "errorFore",            XrmoptionSepArg, NULL},
488     {"-ehl",            "errorHl",              XrmoptionSepArg, NULL},
489     {"-eibd",           "errorIbd",             XrmoptionSepArg, NULL},
490     {"-elevel",         "errorLevel",           XrmoptionSepArg, NULL},
491     {"-ep",             "errorProg",            XrmoptionSepArg, NULL},
492     {"-fbd",            "fatalBd",              XrmoptionSepArg, NULL},
493     {"-fbg",            "fatalBack",            XrmoptionSepArg, NULL},
494     {"-ffg",            "fatalFore",            XrmoptionSepArg, NULL},
495     {"-fhl",            "fatalHl",              XrmoptionSepArg, NULL},
496     {"-fibd",           "fatalIbd",             XrmoptionSepArg, NULL},
497     {"-fp",             "fatalProg",            XrmoptionSepArg, NULL},
498     {"-h",              "*Paned.height",        XrmoptionSepArg, NULL},
499     {"-lebg",           "lErrorBack",           XrmoptionSepArg, NULL},
500     {"-lefg",           "lErrorFore",           XrmoptionSepArg, NULL},
501     {"-lfbg",           "lFatalBack",           XrmoptionSepArg, NULL},
502     {"-lffg",           "lFatalFore",           XrmoptionSepArg, NULL},
503     {"-lobg",           "lOkBack",              XrmoptionSepArg, NULL},
504     {"-lofg",           "lOkFore",              XrmoptionSepArg, NULL},
505     {"-lwbg",           "lWarnBack",            XrmoptionSepArg, NULL},
506     {"-lwfg",           "lWarnFore",            XrmoptionSepArg, NULL},
507     {"-obd",            "okBd",                 XrmoptionSepArg, NULL},
508     {"-obg",            "okBack",               XrmoptionSepArg, NULL},
509     {"-ofg",            "okFore",               XrmoptionSepArg, NULL},
510     {"-ohl",            "okHl",                 XrmoptionSepArg, NULL},
511     {"-oibd",           "okIbd",                XrmoptionSepArg, NULL},
512     {"-op",             "okProg",               XrmoptionSepArg, NULL},
513     {"-rows",           "rows",                 XrmoptionSepArg, NULL},
514     {"-rt",             "retries",              XrmoptionSepArg, NULL},
515     {"-scoll",          "scaleColl",            XrmoptionSepArg, NULL},
516     {"-scpu",           "scaleCpu",             XrmoptionSepArg, NULL},
517     {"-sdisks",         "scaleDisks",           XrmoptionSepArg, NULL},
518     {"-serr",           "scaleErr",             XrmoptionSepArg, NULL},
519     {"-sierr",          "scaleIerr",            XrmoptionSepArg, NULL},
520     {"-sintr",          "scaleIntr",            XrmoptionSepArg, NULL},
521     {"-sipkt",          "scaleIpkt",            XrmoptionSepArg, NULL},
522     {"-sload",          "scaleLoad",            XrmoptionSepArg, NULL},
523     {"-sn",             "shortName",            XrmoptionNoArg, "True"},
524     {"-soerr",          "scaleOerr",            XrmoptionSepArg, NULL},
525     {"-sopkt",          "scaleOpkt",            XrmoptionSepArg, NULL},
526     {"-spage",          "scalePage",            XrmoptionSepArg, NULL},
527     {"-spgpgin",        "scalePgpgin",          XrmoptionSepArg, NULL},
528     {"-spgpgout",       "scalePgpgout",         XrmoptionSepArg, NULL},
529     {"-spkts",          "scalePkts",            XrmoptionSepArg, NULL},
530     {"-spswpin",        "scalePswpin",          XrmoptionSepArg, NULL},
531     {"-spswpout",       "scalePswpout",         XrmoptionSepArg, NULL},
532     {"-sswap",          "scaleSwap",            XrmoptionSepArg, NULL},
533     {"-sswt",           "scaleSwt",             XrmoptionSepArg, NULL},
534     {"-ssys",           "scaleSys",             XrmoptionSepArg, NULL},
535     {"-suser",          "scaleUser",            XrmoptionSepArg, NULL},
536     {"-to",             "timeout",              XrmoptionSepArg, NULL},
537     {"-update",         "*StripChart.update",   XrmoptionSepArg, NULL},
538     {"-w",              "*Paned.width",         XrmoptionSepArg, NULL},
539     {"-wbd",            "warnBd",               XrmoptionSepArg, NULL},
540     {"-wbg",            "warnBack",             XrmoptionSepArg, NULL},
541     {"-wfg",            "warnFore",             XrmoptionSepArg, NULL},
542     {"-whl",            "warnHl",               XrmoptionSepArg, NULL},
543     {"-wibd",           "warnIbd",              XrmoptionSepArg, NULL},
544     {"-wlevel",         "warnLevel",            XrmoptionSepArg, NULL},
545     {"-wp",             "warnProg",             XrmoptionSepArg, NULL},
546 };
547 
548 static XtActionsRec     scact[] = {
549     {"popupscale", popupscale},
550     {"popdownscale", popdownscale}
551 };
552 #define NUMSCACT        (sizeof(scact) / sizeof(XtActionsRec))
553 
554 static XtActionsRec     actions[] = {
555     {"quit", quit},
556 };
557 Atom                    wm_delete_window;
558 
559 main(argc, argv)
560 
561 int     argc;
562 char    **argv;
563 
564 {
565   Widget                toplevel;
566   Widget                form;
567   Widget                pane = NULL;
568   int                   i;
569   int                   n;
570   Arg                   args[10];
571   XtAppContext          appcon;
572   String                mbtrans =
573       "<EnterWindow>:   highlight()\n\
574        <LeaveWindow>:   reset()\n\
575        <BtnDown>:       set() notify() PopupMenu()";
576   XtTranslations        mbtt;
577   String                sctrans =
578       "<BtnDown>:       popupscale()\n\
579        <BtnUp>:         popdownscale()";
580   XtTranslations        scacttt;
581   Widget                *lw;    /* Last column or row of widgets        */
582   int                   numwgt;
583 
584   progname = argv[0];
585   toplevel = XtAppInitialize(&appcon, "XMeter", options,
586                 XtNumber(options), &argc, argv, NULL, NULL, ZERO);
587   if (argc < 2)
588       usage();
589   XtGetApplicationResources(toplevel, (XtPointer) &ar,
590                             resources, XtNumber(resources), NULL, ZERO);
591   form = XtCreateManagedWidget("form", formWidgetClass, toplevel, NULL, ZERO);
592         /* Handle f.delete      */
593   XtAppAddActions(XtWidgetToApplicationContext(toplevel), actions,
594                   XtNumber(actions));
595   XtOverrideTranslations(toplevel,
596         XtParseTranslationTable("<Message>WM_PROTOCOLS: quit()"));
597   if (strcmp("-v", argv[1]) == 0)
598        printversion();
599   init(toplevel, &lw);
600   createmenus(form);
601   mbtt = XtParseTranslationTable(mbtrans);
602   scacttt = XtParseTranslationTable(sctrans);
603   XtAppAddActions(appcon, scact, NUMSCACT);
604   /*
605    * Each meter consists of a paned widget, each paned widget has two
606    * children, which are a menubutton widget and stripchart widget.
607    * The following loop creates and initializes the appropriate widgets.
608    */
609   for (i = 1, numwgt = 0; i < argc; i++, numwgt++) {
610       meterlist = initmeter(meterlist, &i, argc, argv);
611         /*
612          * Create paned widget.
613          */
614       n = 0;
615       if (ar.columns > 0) {             /* Locate pane in form ...      */
616           XtSetArg(args[n], XtNfromVert, lw[numwgt % ar.columns]); n++;
617           if (numwgt % ar.columns != 0) {
618               XtSetArg(args[n], XtNfromHoriz, pane); n++;
619           }
620       } else {
621           XtSetArg(args[n], XtNfromHoriz, lw[numwgt % ar.rows]); n++;
622           if (numwgt % ar.rows != 0) {
623               XtSetArg(args[n], XtNfromVert, pane); n++;
624           }
625       }
626       XtSetArg(args[n], XtNborder, ar.bd[OK]); n++;
627       XtSetArg(args[n], XtNinternalBorderColor, ar.ibd[OK]); n++;
628       pane = XtCreateManagedWidget(meterlist->sh->label, panedWidgetClass,
629                                    form, args, n);
630       lw[numwgt % (ar.columns > 0 ? ar.columns : ar.rows)] = pane;
631       meterlist->pdwidget = pane;
632         /*
633          * Create menubutton widget.
634          */
635       n = 0;
636       XtSetArg(args[n], XtNshowGrip, XtEno); n++;
637       XtSetArg(args[n], XtNlabel, meterlist->label); n++;
638       XtSetArg(args[n], XtNbackground, ar.lback[OK]); n++;
639       XtSetArg(args[n], XtNforeground, ar.lfore[OK]); n++;
640       XtSetArg(args[n], XtNmenuName, STATMENU); n++;
641       XtSetArg(args[n], XtNtranslations, mbtt); n++;
642       meterlist->mbwidget = XtCreateManagedWidget("menu",
643                                 menuButtonWidgetClass, pane, args, n);
644       XtRemoveAllCallbacks(meterlist->mbwidget, XtNcallback);
645       XtAddCallback(meterlist->mbwidget, XtNcallback,
646                     (XtCallbackProc) selecthost, (XtPointer) meterlist);
647         /*
648          * Create stripchart widget.
649          */
650       n = 0;
651       XtSetArg(args[n], XtNfromVert, meterlist->mbwidget); n++;
652       XtSetArg(args[n], XtNresizable, TRUE); n++;
653       XtSetArg(args[n], XtNbackground, ar.back[OK]); n++;
654       XtSetArg(args[n], XtNforeground, ar.fore[OK]); n++;
655       XtSetArg(args[n], XtNhighlight, ar.hl[OK]); n++;
656       XtSetArg(args[n], XtNtranslations, scacttt); n++;
657       meterlist->scwidget = XtCreateManagedWidget("load",
658                                 stripChartWidgetClass, pane, args, n);
659       XtRemoveAllCallbacks(meterlist->scwidget, XtNgetValue);
660       XtAddCallback(meterlist->scwidget, XtNgetValue,
661                     (XtCallbackProc) getstatus, (XtPointer) meterlist);
662   }
663   free(lw);
664 #ifdef SVR4
665   sigset(SIGCHLD, freechild);
666 #else
667   signal(SIGCHLD, freechild);           /* Clean up after our children  */
668 #endif
669   XtRealizeWidget(toplevel);
670   wm_delete_window = XInternAtom(XtDisplay(toplevel), "WM_DELETE_WINDOW",
671                                  False);
672   XSetWMProtocols(XtDisplay(toplevel), XtWindow(toplevel),
673                   &wm_delete_window, 1);
674   setokbackgrounds(XtDisplay(toplevel), XtScreen(toplevel));
675   XtAppMainLoop(appcon);
676   return(0);
677 }
678 
679 usage()
680 
681 {
682   int   i;
683 
684   fprintf(stderr, "Usage: %s [toolkit options] [options] [stat] host ...\n",
685            progname);
686   fprintf(stderr, "  Options are:");
687   for (i = 0; i < XtNumber(options); i++) {
688       if (i % 8 == 0)
689           fprintf(stderr, "\n    ");
690       else
691           fprintf(stderr, ", ");
692       fprintf(stderr, "%s", options[i].option);
693   }
694   fprintf(stderr, ", -v\n  Stats to watch are:");
695   for (i = 0; i < MAXSTAT; i++) {
696       if (i % 8 == 0)
697           fprintf(stderr, "\n    ");
698       else
699           fprintf(stderr, ", ");
700       fprintf(stderr, "-%s", sd[i].name);
701   }
702   fprintf(stderr, "\n");
703   exit(1);
704 }
705 
706 /*
707  * printversion - Print version number and exit.
708  */
709 printversion()
710 
711 {
712   printf("XMeter version %d.%d\n", MAJORVERSION, PATCHLEVEL);
713   exit(0);
714 }
715 
716 /*
717  * init - Initialze various globals.
718  */
719 init(toplevel, lw)
720 
721 Widget  toplevel;
722 Widget  **lw;
723 
724 {
725   int           i;
726   Window        rw;
727   int           x;
728   int           y;
729   int           bwidth;
730   int           depth;
731 
732   ptto.tv_sec = ar.timeout;
733   tto.tv_sec = ar.timeout * ar.retries;
734   if (ar.columns <= 0 && ar.rows <= 0)
735       ar.columns = 1;
736   if (ar.columns > 0) {
737       if ((*lw = (Widget *) calloc(ar.columns, sizeof(Widget))) == NULL)
738           fatal("lw");  
739   } else
740       if ((*lw = (Widget *) calloc(ar.rows, sizeof(Widget))) == NULL)
741           fatal("lw");
742   for (i = 0; i < MAXBACKS; i++)
743       if (ar.bitmap[i].bm != bitmapdef) /* Get bitmap dimensions        */
744           XGetGeometry(XtDisplay(toplevel), ar.bitmap[i].bm, &rw, &x, &y,
745                 (unsigned int *) &ar.bitmap[i].w,
746                 (unsigned int *) &ar.bitmap[i].h,
747                 (unsigned int *) &bwidth, (unsigned int *) &depth);
748 }
749 
750 /*
751  * createmenus - Create menus used by each meter.  Currently there's just
752  *   one which consists of the stats that can be monitored, and a quit
753  *   command.
754  */
755 createmenus(parent)
756 
757 Widget  parent;
758 
759 {
760   int           i;
761   int           n;
762   Widget        menu;
763   Widget        me;
764   Arg           args[10];
765 
766   menu = XtCreatePopupShell(STATMENU, simpleMenuWidgetClass, parent,
767                             NULL, ZERO);
768   for (i = 0; i < MAXSTAT; i++) {
769       n = 0;
770       XtSetArg(args[n], XtNlabel, sd[i].name); n++;
771       me = XtCreateManagedWidget(sd[i].name, smeBSBObjectClass, menu,
772                                  args, n);
773       XtRemoveAllCallbacks(me, XtNcallback);
774       XtAddCallback(me, XtNcallback,
775                     (XtCallbackProc) changestat, (XtPointer) i);
776   }
777   n = 0;
778   XtSetArg(args[n], XtNlabel, "quit"); n++;
779   me = XtCreateManagedWidget("quit", smeBSBObjectClass, menu, args, n);
780   XtRemoveAllCallbacks(me, XtNcallback);
781   XtAddCallback(me, XtNcallback, (XtCallbackProc) quit, (XtPointer) NULL);
782 }
783 
784 void
785 popupscale(w, event, params, num)
786 
787 Widget          w;
788 XEvent          *event;
789 String          *params;
790 Cardinal        num;
791 
792 {
793   int           n;
794   Arg           args[10];
795   Position      x;
796   Position      y;
797   static char   buf[100];
798   METER         *h;
799   time_t        tdown;
800 
801   for (h = meterlist; h; h = h->nxt)
802       if (h->scwidget == w)
803           break;
804   if (!h) {
805       fprintf(stderr, "popupscale: Bad stripchart widget\n");
806       exit(1);
807   }
808   XtTranslateCoords(w, (Position) 0, (Position) 0, &x, &y);
809   n = 0;
810   XtSetArg(args[n], XtNx, x); n++;
811   XtSetArg(args[n], XtNy, y); n++;
812   popup = XtCreatePopupShell("popup", transientShellWidgetClass, w, args, n);
813   if (h->sh->pid != -1) {
814       tdown = time(0) - h->sh->when;
815       sprintf(buf, "%s\nversion %d.%d\nscale %d\ndown %02d:%02d:%02d",
816               h->sh->name,
817               MAJORVERSION, PATCHLEVEL,
818               h->stat == S_LOAD ? ar.scales[h->stat] / FSCALE :
819                                   ar.scales[h->stat],
820               tdown / (60*60), (tdown / 60) % 60, tdown % 60);
821   } else
822       sprintf(buf, "%s\nversion %d.%d\nscale %d",
823               h->sh->name,
824               MAJORVERSION, PATCHLEVEL,
825               h->stat == S_LOAD ? ar.scales[h->stat] / FSCALE :
826                                   ar.scales[h->stat]);
827   n = 0;
828   XtSetArg(args[n], XtNlabel, buf); n++;
829   XtCreateManagedWidget("label", labelWidgetClass, popup, args, n);
830   XtPopup(popup, XtGrabNone);
831 }
832 
833 void
834 popdownscale(w, event, params, num)
835 
836 Widget          w;
837 XEvent          *event;
838 String          *params;
839 Cardinal        num;
840 
841 {
842   if (popup)                    /* Can be NULL in some cases apparently */
843       XtDestroyWidget(popup);
844 }
845 
846 /*
847  * setokbackgrounds - Set initial background pixmaps.  Can't do this
848  *   when the stripchart widgets are created as they have to be
849  *   realized before the pixmaps can be created.
850  */
851 setokbackgrounds(d, s)
852 
853 Display *d;
854 Screen  *s;
855 
856 {
857   METER         *h;
858   int           n;
859   Arg           args[10];
860 
861   if (ar.bitmap[OK].bm != bitmapdef) {
862       for (h = meterlist; h; h = h->nxt) {
863           h->pm = XmuCreatePixmapFromBitmap(d, XtWindow(h->scwidget),
864                                             ar.bitmap[OK].bm,
865                                             ar.bitmap[OK].w, ar.bitmap[OK].h,
866                                             DefaultDepthOfScreen(s),
867                                             ar.fore[OK],
868                                             ar.back[OK]);
869           n = 0;
870           XtSetArg(args[n], XtNbackgroundPixmap, h->pm); n++;
871           XtSetValues(h->scwidget, args, n);
872       }
873   }
874 }
875 
876 /*
877  * freechild - Clean up child processes.
878  */
879 SIGTYPE
880 freechild(sig)
881 
882 int     sig;
883 
884 {
885   int   pid;
886   METER *h;
887 
888   pid = wait(NULL);
889 #ifdef SYSV
890 #ifdef SVR4
891   sigset(SIGCHLD, freechild);
892 #else !SVR4
893   signal(SIGCHLD, freechild);
894 #endif SVR4
895 #endif SYSV
896   if (pid <= 0)
897       return;
898   for (h = meterlist; h; h = h->nxt)
899       if (h->sh->pid == pid) {          /* Start updating host again    */
900           h->sh->pid = -1;
901           break;
902       }
903 }
904 
905 /*
906  * getstatus - Get status from remote host, update meter appropriately,
907  *   including changing colors, background pixmap and label if necessary.
908  */
909 getstatus(w, h, data)
910 
911 Widget  w;
912 METER   *h;
913 char    *data;
914 
915 {
916   int                   l;
917   int                   n;
918   int                   s;
919   register SHMETER      *sh;
920   Arg                   args[10];
921 
922   sh = h->sh;
923   if (h->oldstate == FATAL && sh->pid != -1) {  /* Ignore dead hosts    */
924       *(double *) data = 0.0;
925       return;
926   }
927   if (h->oldjumpscroll) {               /* Restore old jumpscroll value */
928       n = 0;
929       XtSetArg(args[n], XtNjumpScroll, h->oldjumpscroll); n++;
930       XtSetValues(h->scwidget, args, n);
931       h->oldjumpscroll = 0;
932   }
933   s = state(l = getmeter(h), h);
934   if (ar.displayValue) {
935       n = 0;                            /* Update menubutton            */
936       XtSetArg(args[n], XtNbackground, ar.lback[s]); n++;
937       XtSetArg(args[n], XtNforeground, ar.lfore[s]); n++;
938       sprintf(h->label, "%s %s %.2f", sh->label,
939               s == FATAL ? DMSG : sd[h->stat].name,
940               s == FATAL ? 0.0 : (float) l / ar.scales[h->stat]);
941       XtSetArg(args[n], XtNlabel, h->label); n++;
942       XtSetValues(h->mbwidget, args, n);
943   }
944   *(double *) data = (s == FATAL) ? 0.0 : (double) l / ar.scales[h->stat];
945   if (s != h->oldstate) {
946       sh->when = time(0);
947       if (ar.bitmap[h->oldstate].bm != bitmapdef)
948           XFreePixmap(XtDisplay(w), h->pm);
949       n = 0;                            /* Update stripchart widget     */
950       XtSetArg(args[n], XtNbackground, ar.back[s]); n++;
951       XtSetArg(args[n], XtNforeground, ar.fore[s]); n++;
952       XtSetArg(args[n], XtNhighlight, ar.hl[s]); n++;
953       if (ar.bitmap[s].bm != bitmapdef) {
954           h->pm = XmuCreatePixmapFromBitmap(XtDisplay(w),
955                                             XtWindow(w),
956                                             ar.bitmap[s].bm,
957                                             ar.bitmap[s].w, ar.bitmap[s].h,
958                                             DefaultDepthOfScreen(XtScreen(w)),
959                                             ar.fore[s],
960                                             ar.back[s]);
961           XtSetArg(args[n], XtNbackgroundPixmap, h->pm); n++;
962       } else if (ar.bitmap[h->oldstate].bm != bitmapdef) {
963           XtSetArg(args[n], XtNbackgroundPixmap, XtUnspecifiedPixmap); n++;
964       }
965       XtSetValues(w, args, n);
966       n = 0;                            /* Update menubutton widget     */
967       XtSetArg(args[n], XtNbackground, ar.lback[s]); n++;
968       XtSetArg(args[n], XtNforeground, ar.lfore[s]); n++;
969       if (ar.displayValue) {
970           sprintf(h->label, "%s %s %.2f", sh->label,
971                   s == FATAL ? DMSG : sd[h->stat].name,
972                   s == FATAL ? 0.0 : (float) l / ar.scales[h->stat]);
973           XtSetArg(args[n], XtNlabel, h->label); n++;
974       } else if (s == FATAL || h->oldstate == FATAL) {
975           sprintf(h->label, "%s %s", sh->label,
976                    s == FATAL ? DMSG : sd[h->stat].name);
977           XtSetArg(args[n], XtNlabel, h->label); n++;
978       }
979       XtSetValues(h->mbwidget, args, n);
980       n = 0;                            /* Update paned widget          */
981       XtSetArg(args[n], XtNborder, ar.bd[s]); n++;
982       XtSetArg(args[n], XtNinternalBorderColor, ar.ibd[s]); n++;
983       XtSetValues(h->pdwidget, args, n);
984       if (ar.prog[s])
985           runprog(h, s);
986       if (s == FATAL)
987           sh->pid = waitforhost(h);
988   }
989   h->oldstate = s;
990 }
991 
992 /*
993  * waitforhost - Fork process which will wait for host to come back up.
994  *   Child exits if parent is init (pid 1), to handle case where parent
995  *   has gone away.
996  */
997 int
998 waitforhost(h)
999 
1000 METER   *h;
1001 
1002 {
1003   int   pid;
1004 
1005   if (pid = fork())
1006       return(pid);
1007 #ifdef SVR4
1008   sigset(SIGTERM, SIG_DFL);
1009 #else !SVR4
1010   signal(SIGTERM, SIG_DFL);
1011 #endif !SVR4
1012   while (1) {
1013       sleep(10);
1014       if (getport(h) > 0 || getppid() < 2)
1015           exit(0);
1016   }
1017 }
1018 
1019 /*
1020  * runprog - Run user specified alert program.
1021  */
1022 runprog(h, s)
1023 
1024 METER   *h;
1025 int     s;
1026 
1027 {
1028   char  oldstate[4];
1029   char  state[4];
1030 
1031   sprintf(oldstate, "%d", h->oldstate);
1032   sprintf(state, "%d", s);
1033   if (vfork())
1034       return;                   /* Parent just returns          */
1035   execlp(ar.prog[s], ar.prog[s], oldstate, state,
1036          h->sh->label, sd[h->stat].name, 0);
1037   fatal(ar.prog[s]);
1038 }
1039 
1040 /*
1041  * selecthost - Select host for next changestat().
1042  */
1043 selecthost(w, h, data)
1044 
1045 Widget  w;
1046 METER   *h;
1047 char    *data;
1048 
1049 {
1050   selected = h;
1051 }
1052 
1053 /*
1054  * changestat - Change statistic we're looking at.  To clear the stripchart
1055  *   it's necessary to poke the "interval" field in the StripChartWidget
1056  *   structure, and then set "jumpScroll" to the width of the stripchart.
1057  *   jumpScroll is saved here and restored in getstatus().
1058  */
1059 #include <X11/IntrinsicP.h>
1060 #include <X11/Xaw/StripCharP.h>
1061 changestat(w, statidx, data)
1062 
1063 Widget  w;
1064 int     statidx;
1065 char    *data;
1066 
1067 {
1068   int   n;
1069   Arg   args[10];
1070   int   width;
1071 
1072   selected->stat = statidx;
1073   sprintf(selected->label, "%s %s", selected->sh->label, sd[statidx].name);
1074   n = 0;
1075   XtSetArg(args[n], XtNlabel, selected->label); n++;
1076   XtSetValues(selected->mbwidget, args, n);
1077   n = 0;
1078   XtSetArg(args[n], XtNwidth, &width); n++;
1079   XtSetArg(args[n], XtNjumpScroll, &selected->oldjumpscroll); n++;
1080   XtGetValues(selected->scwidget, args, n);
1081   n = 0;
1082   XtSetArg(args[n], XtNjumpScroll, width); n++;
1083   XtSetValues(selected->scwidget, args, n);
1084   ((StripChartWidget) selected->scwidget)->strip_chart.interval = width;
1085 }
1086 
1087 /*
1088  * state - Return state of current stat.
1089  */
1090 int
1091 state(l, h)
1092 
1093 int     l;
1094 METER   *h;
1095 
1096 {
1097   if (l < 0)
1098       return(FATAL);
1099   else if (l < ar.warnLevel * ar.scales[h->stat])
1100       return(OK);
1101   else if (l < ar.errorLevel * ar.scales[h->stat])
1102       return(WARN);
1103   else
1104       return(ERROR);
1105 }
1106 
1107 /*
1108  * The following functions return the value of the specified stat, which
1109  * is normally computed by taking the difference between the current
1110  * value and the previous value, and dividing by the update interval in
1111  * order to get the current rate.
1112  */
1113 #define DIF(m,fld)      (m->sh->st[m->sh->idx].fld - \
1114                          m->sh->st[m->sh->idx ^ 1].fld)
1115 #define INT(m)          (DIF(m,curtime.tv_sec) <= 0 ? 1 : \
1116                                                       DIF(m,curtime.tv_sec))
1117 
1118 int
1119 fcoll(h)
1120 
1121 METER   *h;
1122 
1123 {
1124   return(DIF (h, if_collisions) / INT(h));
1125 }
1126 
1127 int
1128 fcpu(h)
1129 
1130 METER   *h;
1131 
1132 {
1133   int   i;
1134   int   t;
1135   int   d[CPUSTATES];
1136 
1137   for (t = 0, i= 0; i < CPUSTATES; i++)
1138       t += (d[i] = DIF (h, cp_time[i]));
1139   return(t ? (100 * (d[CP_USER]+d[CP_NICE]+d[CP_SYS])) / t : 0);
1140 }
1141 
1142 int
1143 fdisks(h)
1144 
1145 METER   *h;
1146 
1147 {
1148   int   i;
1149   int   t;
1150 
1151   for (t = 0, i= 0; i < 4; i++)
1152       t += (DIF (h, dk_xfer[i]));
1153   return(t / INT(h));
1154 }
1155 
1156 int
1157 ferr(h)
1158 
1159 METER   *h;
1160 
1161 {
1162   return(fierr(h) + foerr(h));
1163 }
1164 
1165 int
1166 fierr(h)
1167 
1168 METER   *h;
1169 
1170 {
1171   return(DIF (h, if_ierrors) / INT(h));
1172 }
1173 
1174 int
1175 fintr(h)
1176 
1177 METER   *h;
1178 
1179 {
1180   return(DIF (h, v_intr) / INT(h));
1181 }
1182 
1183 int
1184 fipkt(h)
1185 
1186 METER   *h;
1187 
1188 {
1189   return(DIF (h, if_ipackets) / INT(h));
1190 }
1191 
1192 int
1193 fload(h)
1194 
1195 METER   *h;
1196 
1197 {
1198   return(h->sh->st[h->sh->idx].avenrun[0]);
1199 }
1200 
1201 int
1202 foerr(h)
1203 
1204 METER   *h;
1205 
1206 {
1207   return(DIF (h, if_oerrors) / INT(h));
1208 }
1209 
1210 int
1211 fopkt(h)
1212 
1213 METER   *h;
1214 
1215 {
1216   return(DIF (h, if_opackets) / INT(h));
1217 }
1218 
1219 int
1220 fpage(h)
1221 
1222 METER   *h;
1223 
1224 {
1225   return((DIF (h, v_pgpgin) + DIF (h, v_pgpgout)) / INT(h));
1226 }
1227 
1228 int
1229 fpgpgin(h)
1230 
1231 METER   *h;
1232 
1233 {
1234   return(DIF (h, v_pgpgin) / INT(h));
1235 }
1236 
1237 int
1238 fpkts(h)
1239 
1240 METER   *h;
1241 
1242 {
1243   return(fipkt(h) + fopkt(h));
1244 }
1245 
1246 int
1247 fpgpgout(h)
1248 
1249 METER   *h;
1250 
1251 {
1252   return(DIF (h, v_pgpgout) / INT(h));
1253 }
1254 
1255 int
1256  fswap(h)
1257 
1258 METER   *h;
1259 
1260 {
1261   return(fpswpin(h) + fpswpout(h));
1262 }
1263 
1264 int
1265  fpswpin(h)
1266 
1267 METER   *h;
1268 
1269 {
1270   return(DIF (h, v_pswpin) / INT(h));
1271 }
1272 
1273 int
1274 fpswpout(h)
1275 
1276 METER   *h;
1277 
1278 {
1279   return(DIF (h, v_pswpout) / INT(h));
1280 }
1281 
1282 int
1283 fswt(h)
1284 
1285 METER   *h;
1286 
1287 {
1288   return(DIF (h, v_swtch) / INT(h));
1289 }
1290 
1291 int
1292 fsys(h)
1293 
1294 METER   *h;
1295 
1296 {
1297   int   i;
1298   int   t;
1299   int   d[CPUSTATES];
1300 
1301   for (t = 0, i= 0; i < CPUSTATES; i++)
1302       t += (d[i] = DIF (h, cp_time[i]));
1303   return(t ? (100 * d[CP_SYS]) / t : 0);
1304 }
1305 
1306 int
1307 fuser(h)
1308 
1309 METER   *h;
1310 
1311 {
1312   int   i;
1313   int   t;
1314   int   d[CPUSTATES];
1315 
1316   for (t = 0, i= 0; i < CPUSTATES; i++)
1317       t += (d[i] = DIF (h, cp_time[i]));
1318   return(t ? (100 * (d[CP_USER] + d[CP_NICE])) / t : 0);
1319 }
1320 
1321 /*
1322  * getmeter - Executes rstat(3) call to read statistics for specified host.
1323  *   I do all the rpc junk myself so that I have better control over timeouts
1324  *   than rstat(3) gives me.  If we're watching multiple stats
1325  *   on the same host I only do one rstat(3) call (refcnt and curcnt are
1326  *   used for this).
1327  */
1328 int
1329 getmeter(h)
1330 
1331 register METER  *h;
1332 
1333 {
1334   enum clnt_stat        cs;
1335   register SHMETER      *sh;
1336   int                   p;
1337 
1338   sh = h->sh;
1339   if (sh->curcnt >= sh->refcnt)
1340       sh->curcnt = 0;
1341   if (!sh->curcnt++) {
1342       if (sh->clnt == NULL) {
1343           if ((p = getport(h)) <= 0)
1344               return(-1);
1345           sh->addr.sin_port = htons(p);
1346           sh->s = RPC_ANYSOCK;
1347           if (!(sh->clnt = clntudp_create(&sh->addr, RSTATPROG, RSTATVERS_TIME,
1348                                           ptto, &sh->s)))
1349               return(-1);
1350           sh->first = 1;
1351           sh->idx = 0;
1352       } else {
1353           sh->first = 0;
1354           sh->idx ^= 1;
1355       }
1356       cs = clnt_call(sh->clnt, RSTATPROC_STATS, xdr_void, 0, xdr_statstime,
1357                      (caddr_t) &sh->st[sh->idx], tto);
1358       if (cs != RPC_SUCCESS) {
1359           clnt_destroy(sh->clnt);
1360           close(sh->s); /* Some clnt_destroy's don't do this    */
1361           sh->clnt = NULL;
1362           return(-1);
1363       }
1364   }
1365   return(sh->first ? 0 : sh->clnt == NULL ? -1 : (sd[h->stat].val)(h));
1366 }
1367 
1368 /*
1369  * getport - Get port rstatd is listening on.
1370  */
1371 int
1372 getport(h)
1373 
1374 METER   *h;
1375 
1376 {
1377   CLIENT                *c;
1378   enum clnt_stat        cs;
1379   static struct pmap    pm = {RSTATPROG, RSTATVERS_TIME, IPPROTO_UDP, 0};
1380   unsigned short        p;
1381   register SHMETER      *sh;
1382 
1383   sh = h->sh;
1384   sh->s = RPC_ANYSOCK;
1385   sh->addr.sin_port = htons(PMAPPORT);
1386   if (!(c = clntudp_create(&sh->addr, PMAPPROG, PMAPVERS, ptto, &sh->s)))
1387       return(-1);
1388   cs = clnt_call(c, PMAPPROC_GETPORT, xdr_pmap, (caddr_t) &pm,
1389                  xdr_u_short, (caddr_t) &p, tto);
1390   clnt_destroy(c);
1391   close(sh->s);         /* Some clnt_destroys don't do this     */
1392   return(cs == RPC_SUCCESS ? p : -1);
1393 }
1394 
1395 /*
1396  * initmeter - Fill in METER and SHMETER structures for this stat.
1397  */
1398 METER
1399 *initmeter(meterlist, idx, argc, argv)
1400 
1401 METER   *meterlist;
1402 int     *idx;
1403 int     argc;
1404 char    **argv;
1405 
1406 {
1407   register METER        *h;
1408   struct hostent        *he;
1409   int                   i;
1410   char                  *cp;
1411 
1412   /*
1413    * Create and fill in METER struct.
1414    */
1415   if (!(h = (METER *) malloc(sizeof(METER))))
1416       fatal("METER");
1417   h->nxt = meterlist;
1418   cp = (argv[*idx][0] == '-') ? &argv[*idx][1] : ar.defStat;
1419   for (i = 0; i < MAXSTAT; i++)
1420       if (strcmp(cp, sd[i].name) == 0) {
1421           h->stat = i;
1422           break;
1423       }
1424   if ((cp != ar.defStat) && (++(*idx) == argc || i >= MAXSTAT))
1425       usage();
1426   if ((he = gethostbyname(argv[*idx])) == NULL)
1427        fatal(argv[*idx]);
1428   h->oldstate = OK;
1429   h->oldjumpscroll = 0;
1430   h->sh = newshmeter(he);
1431   if (!(h->label = (char *) malloc(strlen(h->sh->label) + 2 + MAXSTATNAME +
1432                                    MAXSTATVALUE + 6)))
1433       fatal("label");
1434   sprintf(h->label, "%s %s", h->sh->label, sd[h->stat].name);
1435   return(h);
1436 }
1437 
1438 /*
1439  * newshmeter - Return SHMETER structure for host.  Keeps
1440  *   reference count for each SHMETER.  If an SHMETER for this host
1441  *   doesn't already exist then one is created and saved on the shmeter
1442  *   linked list.  Note that he->h_name gets stepped on by this routine
1443  *   after it is saved in sh->name.
1444  *   
1445  */
1446 SHMETER
1447 *newshmeter(he)
1448 
1449 struct hostent  *he;
1450 
1451 {
1452   SHMETER       *sh;
1453   char          *cp;
1454 
1455   /*
1456    * If we're already looking at this host then just return existing
1457    * structure.
1458    */
1459   for (sh = shmeters; sh; sh = sh->nxt)
1460       if (strcmp(sh->name, he->h_name) == 0) {
1461           sh->refcnt++;         /* Count how many references            */
1462           return(sh);
1463       }
1464   /*
1465    * Not looking at this host yet, create and fill in SHMETER struct.
1466    */
1467   if (!(sh = (SHMETER *) malloc(sizeof(SHMETER))))
1468       fatal("SHMETER");
1469   sh->nxt = shmeters;           /* Save this struct in linked list      */
1470   shmeters = sh;
1471   if (!(sh->name = mystrdup(he->h_name)))
1472       fatal("newshmeter");
1473   if (ar.shortName && (cp = strchr(he->h_name, '.'))) {
1474       *cp = '\0';
1475       if (!(sh->label = mystrdup(he->h_name)))
1476           fatal("initmeter");
1477   } else
1478       sh->label = sh->name;
1479   sh->addr.sin_family = AF_INET;
1480   sh->addr.sin_addr.s_addr = *(int *) he->h_addr;
1481   sh->clnt = NULL;
1482   sh->refcnt = 1;
1483   sh->curcnt = 0;
1484   sh->pid = -1;
1485   return(sh);
1486 }
1487 
1488 /*
1489  * mystrdup - Not everyone has strdup() in their C library, so provide
1490  *   our own.
1491  */
1492 char *
1493 mystrdup(s)
1494 
1495 char    *s;
1496 
1497 {
1498   char  *t;
1499 
1500   if (t = (char *) malloc(strlen(s) + 1))
1501       return(strcpy(t, s));
1502   else
1503       return(NULL);
1504 }
1505 
1506 void
1507 quit(w)
1508 
1509 Widget  w;
1510 
1511 {
1512   XtDestroyApplicationContext(XtWidgetToApplicationContext(w));
1513   exit(0);
1514 }
1515 
1516 fatal(m)
1517 
1518 char    *m;
1519 
1520 {
1521   perror(m);
1522   exit(1);
1523 }
1524 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.