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