xload.c revision fd0c672f
1/* $XConsortium: xload.c,v 1.37 94/04/17 20:43:44 converse Exp $ */
2/* $XFree86: xc/programs/xload/xload.c,v 1.6tsi Exp $ */
3/*
4
5Copyright (c) 1989  X Consortium
6
7Permission is hereby granted, free of charge, to any person obtaining
8a copy of this software and associated documentation files (the
9"Software"), to deal in the Software without restriction, including
10without limitation the rights to use, copy, modify, merge, publish,
11distribute, sublicense, and/or sell copies of the Software, and to
12permit persons to whom the Software is furnished to do so, subject to
13the following conditions:
14
15The above copyright notice and this permission notice shall be included
16in all copies or substantial portions of the Software.
17
18THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
21IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR
22OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
23ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
24OTHER DEALINGS IN THE SOFTWARE.
25
26Except as contained in this notice, the name of the X Consortium shall
27not be used in advertising or otherwise to promote the sale, use or
28other dealings in this Software without prior written authorization
29from the X Consortium.
30
31*/
32
33/*
34 * xload - display system load average in a window
35 */
36
37#include <errno.h>
38#include <stdio.h>
39#include <stdlib.h>
40#include <unistd.h>
41#include <X11/Intrinsic.h>
42#include <X11/Xatom.h>
43#include <X11/StringDefs.h>
44#include <X11/Shell.h>
45
46#include <X11/Xaw/Cardinals.h>
47#include <X11/Xaw/Label.h>
48#include <X11/Xaw/Paned.h>
49#include <X11/Xaw/StripChart.h>
50#include <X11/Xmu/SysUtil.h>
51#include "xload.h"
52
53#include "xload.bit"
54
55char *ProgramName;
56
57static void quit(Widget w, XEvent *event, String *params, Cardinal *num_params);
58static void ClearLights(Display *dpy);
59static void SetLights(XtPointer data, XtIntervalId *timer);
60
61/*
62 * Definition of the Application resources structure.
63 */
64
65typedef struct _XLoadResources {
66  Boolean show_label;
67  Boolean use_lights;
68  String remote;
69} XLoadResources;
70
71/*
72 * Command line options table.  Only resources are entered here...there is a
73 * pass over the remaining options after XtParseCommand is let loose.
74 */
75
76static XrmOptionDescRec options[] = {
77 {"-scale",		"*load.minScale",	XrmoptionSepArg,	NULL},
78 {"-update",		"*load.update",		XrmoptionSepArg,	NULL},
79 {"-hl",		"*load.highlight",	XrmoptionSepArg,	NULL},
80 {"-highlight",		"*load.highlight",	XrmoptionSepArg,	NULL},
81 {"-label",		"*label.label",		XrmoptionSepArg,	NULL},
82 {"-nolabel",		"*showLabel",	        XrmoptionNoArg,       "False"},
83 {"-lights",		"*useLights",		XrmoptionNoArg,	      "True"},
84 {"-jumpscroll",	"*load.jumpScroll",	XrmoptionSepArg,	NULL},
85 {"-remote",            "*remote",              XrmoptionSepArg,        NULL},
86};
87
88/*
89 * The structure containing the resource information for the
90 * Xload application resources.
91 */
92
93#define Offset(field) (XtOffsetOf(XLoadResources, field))
94
95static XtResource my_resources[] = {
96  {"showLabel", XtCBoolean, XtRBoolean, sizeof(Boolean),
97     Offset(show_label), XtRImmediate, (XtPointer) TRUE},
98  {"useLights", XtCBoolean, XtRBoolean, sizeof(Boolean),
99    Offset(use_lights), XtRImmediate, (XtPointer) FALSE},
100  {"remote", XtCString, XtRString, sizeof(XtRString),
101    Offset(remote), XtRImmediate, (XtPointer) FALSE},
102
103};
104
105#undef Offset
106
107XLoadResources resources;
108
109static XtActionsRec xload_actions[] = {
110    { "quit",	quit },
111};
112static Atom wm_delete_window;
113static int light_update = 10 * 1000;
114
115/*
116 * Exit with message describing command line format.
117 */
118
119static void usage(void)
120{
121    fprintf (stderr, "usage:  %s [-options ...]\n\n", ProgramName);
122    fprintf (stderr, "where options include:\n");
123    fprintf (stderr,
124      "    -display dpy            X server on which to display\n");
125    fprintf (stderr,
126      "    -geometry geom          size and location of window\n");
127    fprintf (stderr,
128      "    -fn font                font to use in label\n");
129    fprintf (stderr,
130      "    -scale number           minimum number of scale lines\n");
131    fprintf (stderr,
132      "    -update seconds         interval between updates\n");
133    fprintf (stderr,
134      "    -label string           annotation text\n");
135    fprintf (stderr,
136      "    -bg color               background color\n");
137    fprintf (stderr,
138      "    -fg color               graph color\n");
139    fprintf (stderr,
140      "    -hl color               scale and text color\n");
141    fprintf (stderr,
142      "    -nolabel                removes the label from above the chart.\n");
143    fprintf (stderr,
144      "    -jumpscroll value       number of pixels to scroll on overflow\n");
145    fprintf (stderr,
146      "    -remote host            remote host to monitor\n");
147    fprintf (stderr, "\n");
148    exit(1);
149}
150
151int
152main(int argc, char **argv)
153{
154    XtAppContext app_con;
155    Widget toplevel, load, pane, label_wid, load_parent;
156    Arg args[1];
157    Pixmap icon_pixmap = None;
158    char *label, host[256];
159
160    ProgramName = argv[0];
161
162    /* For security reasons, we reset our uid/gid after doing the necessary
163       system initialization and before calling any X routines. */
164    InitLoadPoint();
165    /* reset gid first while still (maybe) root */
166    if (setgid(getgid()) == -1) {
167	    fprintf(stderr, "%s: setgid failed: %s\n",
168		ProgramName, strerror(errno));
169	    exit(1);
170    }
171    if (setuid(getuid()) == -1) {
172	    fprintf(stderr, "%s: setuid failed: %s\n",
173		ProgramName, strerror(errno));
174	    exit(1);
175    }
176
177    XtSetLanguageProc(NULL, (XtLanguageProc) NULL, NULL);
178
179    toplevel = XtAppInitialize(&app_con, "XLoad", options, XtNumber(options),
180			       &argc, argv, NULL, NULL, (Cardinal) 0);
181    if (argc != 1) usage();
182
183    XtGetApplicationResources( toplevel, (XtPointer) &resources,
184			      my_resources, XtNumber(my_resources),
185			      NULL, (Cardinal) 0);
186
187    if (resources.use_lights)
188    {
189	char	    name[1024];
190	XrmString   type;
191	XrmValue    db_value;
192	XrmValue    int_value;
193	Bool	    found = False;
194
195	(void) sprintf (name, "%s.paned.load.update", XtName(toplevel));
196	found = XrmGetResource (XtScreenDatabase(XtScreen(toplevel)),
197				name, "XLoad.Paned.StripChart.Interval",
198				&type, &db_value);
199	if (found) {
200	    int_value.size = sizeof(int);
201	    int_value.addr = (XPointer) &light_update;
202	    found = XtConvertAndStore(toplevel, type, &db_value, XtRInt,
203				      &int_value);
204	    if (found) light_update *= 1000;
205	}
206	ClearLights (XtDisplay (toplevel));
207	SetLights ((XtPointer) toplevel, (XtIntervalId *) 0);
208    }
209    else
210    {
211    	/*
212     	 * This is a hack so that f.delete will do something useful in this
213     	 * single-window application.
214     	 */
215    	XtAppAddActions (app_con, xload_actions, XtNumber(xload_actions));
216    	XtOverrideTranslations(toplevel,
217		    	XtParseTranslationTable ("<Message>WM_PROTOCOLS: quit()"));
218
219    	XtSetArg (args[0], XtNiconPixmap, &icon_pixmap);
220    	XtGetValues(toplevel, args, ONE);
221    	if (icon_pixmap == None) {
222	    XtSetArg(args[0], XtNiconPixmap,
223		     XCreateBitmapFromData(XtDisplay(toplevel),
224				       	   XtScreen(toplevel)->root,
225				       	   (char *)xload_bits,
226				       	   xload_width, xload_height));
227	    XtSetValues (toplevel, args, ONE);
228    	}
229
230    	if (resources.show_label) {
231      	  pane = XtCreateManagedWidget ("paned", panedWidgetClass,
232				    	toplevel, NULL, ZERO);
233
234      	  label_wid = XtCreateManagedWidget ("label", labelWidgetClass,
235					     pane, NULL, ZERO);
236
237      	  XtSetArg (args[0], XtNlabel, &label);
238      	  XtGetValues(label_wid, args, ONE);
239
240      	  if ( strcmp("label", label) == 0 ) {
241	    (void) XmuGetHostname (host, 255);
242	    XtSetArg (args[0], XtNlabel, host);
243	    XtSetValues (label_wid, args, ONE);
244      	  }
245
246      	  load_parent = pane;
247    	}
248    	else
249      	  load_parent = toplevel;
250
251    	load = XtCreateManagedWidget ("load", stripChartWidgetClass,
252				      load_parent, NULL, ZERO);
253
254    	if (resources.remote)
255	  XtAddCallback(load, XtNgetValue, GetRLoadPoint, NULL);
256	else
257	  XtAddCallback(load, XtNgetValue, GetLoadPoint, NULL);
258
259    	XtRealizeWidget (toplevel);
260    	wm_delete_window = XInternAtom (XtDisplay(toplevel), "WM_DELETE_WINDOW",
261				    	False);
262    	(void) XSetWMProtocols (XtDisplay(toplevel), XtWindow(toplevel),
263			    	&wm_delete_window, 1);
264    }
265    XtAppMainLoop(app_con);
266
267    return 0;
268}
269
270static unsigned long	current_leds;
271
272static void
273ClearLights (dpy)
274    Display *dpy;
275{
276    XKeyboardControl	cntrl;
277
278    cntrl.led_mode = LedModeOff;
279    XChangeKeyboardControl (dpy, KBLedMode, &cntrl);
280    current_leds = 0;
281}
282
283static void
284SetLights (data, timer)
285    XtPointer	    data;
286    XtIntervalId    *timer;
287{
288    Widget		toplevel;
289    Display		*dpy;
290    double		value;
291    unsigned long	new_leds, change, bit;
292    int			i;
293    XKeyboardControl	cntrl;
294
295    toplevel = (Widget) data;
296    dpy = XtDisplay (toplevel);
297    if (resources.remote)
298      GetRLoadPoint (toplevel, (XtPointer) 0, (XtPointer) &value);
299    else
300      GetLoadPoint (toplevel, (XtPointer) 0, (XtPointer) &value);
301    new_leds = (1 << (int) (value + 0.1)) - 1;
302    change = new_leds ^ current_leds;
303    i = 1;
304    bit = 1;
305    while (current_leds != new_leds)
306    {
307	if (change & bit)
308	{
309	    cntrl.led = i;
310	    cntrl.led_mode = new_leds & bit ? LedModeOn : LedModeOff;
311	    XChangeKeyboardControl (dpy, KBLed|KBLedMode, &cntrl);
312	    current_leds ^= bit;
313	}
314	i++;
315	bit <<= 1;
316    }
317    XtAppAddTimeOut(XtWidgetToApplicationContext(toplevel), light_update,
318		    SetLights, data);
319}
320
321static void quit (w, event, params, num_params)
322    Widget w;
323    XEvent *event;
324    String *params;
325    Cardinal *num_params;
326{
327    if (event->type == ClientMessage &&
328        event->xclient.data.l[0] != wm_delete_window) {
329        XBell (XtDisplay(w), 0);
330        return;
331    }
332    if (resources.use_lights)
333	ClearLights (XtDisplay (w));
334    XtDestroyApplicationContext(XtWidgetToApplicationContext(w));
335    exit (0);
336}
337
338
339
340
341
342
343