xload.c revision 953c684b
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    /* reset gid first while still (maybe) root */
182    if (setgid(getgid()) == -1) {
183	    fprintf(stderr, gettext("%s: setgid failed: %s\n"),
184		ProgramName, strerror(errno));
185	    exit(1);
186    }
187    if (setuid(getuid()) == -1) {
188	    fprintf(stderr, gettext("%s: setuid failed: %s\n"),
189		ProgramName, strerror(errno));
190	    exit(1);
191    }
192
193    XtSetLanguageProc(NULL, (XtLanguageProc) NULL, NULL);
194
195    toplevel = XtAppInitialize(&app_con, "XLoad", options, XtNumber(options),
196			       &argc, argv, NULL, NULL, (Cardinal) 0);
197
198#ifdef USE_GETTEXT
199    textdomain("xload");
200
201    if ((domaindir = getenv ( "TEXTDOMAINDIR" )) == NULL) {
202	domaindir = LOCALEDIR;
203    }
204    bindtextdomain("xload", domaindir);
205#endif
206
207    if (argc != 1) usage();
208
209    XtGetApplicationResources( toplevel, (XtPointer) &resources,
210			      my_resources, XtNumber(my_resources),
211			      NULL, (Cardinal) 0);
212
213    if (resources.use_lights)
214    {
215	char	    name[1024];
216	XrmString   type;
217	XrmValue    db_value;
218	XrmValue    int_value;
219	Bool	    found = False;
220
221	snprintf (name, sizeof(name), "%s.paned.load.update", XtName(toplevel));
222	found = XrmGetResource (XtScreenDatabase(XtScreen(toplevel)),
223				name, "XLoad.Paned.StripChart.Interval",
224				&type, &db_value);
225	if (found) {
226	    int_value.size = sizeof(int);
227	    int_value.addr = (XPointer) &light_update;
228	    found = XtConvertAndStore(toplevel, type, &db_value, XtRInt,
229				      &int_value);
230	    if (found) light_update *= 1000;
231	}
232	ClearLights (XtDisplay (toplevel));
233	SetLights ((XtPointer) toplevel, (XtIntervalId *) 0);
234    }
235    else
236    {
237    	/*
238     	 * This is a hack so that f.delete will do something useful in this
239     	 * single-window application.
240     	 */
241    	XtAppAddActions (app_con, xload_actions, XtNumber(xload_actions));
242    	XtOverrideTranslations(toplevel,
243		    	XtParseTranslationTable ("<Message>WM_PROTOCOLS: quit()"));
244
245    	XtSetArg (args[0], XtNiconPixmap, &icon_pixmap);
246    	XtGetValues(toplevel, args, ONE);
247    	if (icon_pixmap == None) {
248	    XtSetArg(args[0], XtNiconPixmap,
249		     XCreateBitmapFromData(XtDisplay(toplevel),
250				       	   XtScreen(toplevel)->root,
251				       	   (char *)xload_bits,
252				       	   xload_width, xload_height));
253	    XtSetValues (toplevel, args, ONE);
254    	}
255
256    	if (resources.show_label) {
257      	  pane = XtCreateManagedWidget ("paned", panedWidgetClass,
258				    	toplevel, NULL, ZERO);
259
260      	  label_wid = XtCreateManagedWidget ("label", labelWidgetClass,
261					     pane, NULL, ZERO);
262
263      	  XtSetArg (args[0], XtNlabel, &label);
264      	  XtGetValues(label_wid, args, ONE);
265
266      	  if ( strcmp("label", label) == 0 ) {
267	    (void) XmuGetHostname (host, 255);
268	    XtSetArg (args[0], XtNlabel, host);
269	    XtSetValues (label_wid, args, ONE);
270      	  }
271
272      	  load_parent = pane;
273    	}
274    	else
275      	  load_parent = toplevel;
276
277    	load = XtCreateManagedWidget ("load", stripChartWidgetClass,
278				      load_parent, NULL, ZERO);
279
280    	if (resources.remote)
281	  XtAddCallback(load, XtNgetValue, GetRLoadPoint, NULL);
282	else
283	  XtAddCallback(load, XtNgetValue, GetLoadPoint, NULL);
284
285    	XtRealizeWidget (toplevel);
286    	wm_delete_window = XInternAtom (XtDisplay(toplevel), "WM_DELETE_WINDOW",
287				    	False);
288    	(void) XSetWMProtocols (XtDisplay(toplevel), XtWindow(toplevel),
289			    	&wm_delete_window, 1);
290    }
291    XtAppMainLoop(app_con);
292
293    return 0;
294}
295
296static unsigned long	current_leds;
297
298static void
299ClearLights (Display *dpy)
300{
301    XKeyboardControl	cntrl = {
302	.led_mode = LedModeOff
303    };
304    XChangeKeyboardControl (dpy, KBLedMode, &cntrl);
305    current_leds = 0;
306}
307
308static void
309SetLights (XtPointer data, XtIntervalId *timer)
310{
311    Widget		toplevel;
312    Display		*dpy;
313    double		value;
314    unsigned long	new_leds, change, bit;
315    int			i;
316
317    toplevel = (Widget) data;
318    dpy = XtDisplay (toplevel);
319    if (resources.remote)
320      GetRLoadPoint (toplevel, (XtPointer) 0, (XtPointer) &value);
321    else
322      GetLoadPoint (toplevel, (XtPointer) 0, (XtPointer) &value);
323    new_leds = (1 << (int) (value + 0.1)) - 1;
324    change = new_leds ^ current_leds;
325    i = 1;
326    bit = 1;
327    while (current_leds != new_leds)
328    {
329	if (change & bit)
330	{
331	    XKeyboardControl	cntrl = {
332		.led = i,
333		.led_mode = new_leds & bit ? LedModeOn : LedModeOff
334	    };
335	    XChangeKeyboardControl (dpy, KBLed|KBLedMode, &cntrl);
336	    current_leds ^= bit;
337	}
338	i++;
339	bit <<= 1;
340    }
341    XtAppAddTimeOut(XtWidgetToApplicationContext(toplevel), light_update,
342		    SetLights, data);
343}
344
345static void quit (Widget w, XEvent *event, String *params, Cardinal *num_params)
346{
347    if (event->type == ClientMessage &&
348        event->xclient.data.l[0] != wm_delete_window) {
349        XBell (XtDisplay(w), 0);
350        return;
351    }
352    if (resources.use_lights)
353	ClearLights (XtDisplay (w));
354    XtDestroyApplicationContext(XtWidgetToApplicationContext(w));
355    exit (0);
356}
357
358
359
360
361
362
363