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, 2023, Oracle and/or its affiliates.
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(int exitval)
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      "    -help                   print this message\n"
161      "    -version                print version info\n"
162                 ));
163    exit(exitval);
164}
165
166int
167main(int argc, char **argv)
168{
169    XtAppContext app_con;
170    Widget toplevel, load, pane, label_wid, load_parent;
171    Arg args[1];
172    Pixmap icon_pixmap = None;
173    char *label, host[256];
174    const char *domaindir;
175
176    XtSetLanguageProc ( NULL, NULL, NULL );
177
178    ProgramName = argv[0];
179
180    /* Handle args that don't require opening a display or load info source */
181    for (int n = 1; n < argc; n++) {
182	const char *argn = argv[n];
183	/* accept single or double dash for -help & -version */
184	if (argn[0] == '-' && argn[1] == '-') {
185	    argn++;
186	}
187	if (strcmp(argn, "-help") == 0) {
188	    usage(0);
189	}
190	if (strcmp(argn, "-version") == 0) {
191	    puts(PACKAGE_STRING);
192	    exit(0);
193	}
194    }
195
196    /* For security reasons, we reset our uid/gid after doing the necessary
197       system initialization and before calling any X routines. */
198    InitLoadPoint();
199
200#if !defined(_WIN32) || defined(__CYGWIN__)
201    /* reset gid first while still (maybe) root */
202    if (setgid(getgid()) == -1) {
203	    fprintf(stderr, gettext("%s: setgid failed: %s\n"),
204		ProgramName, strerror(errno));
205	    exit(1);
206    }
207    if (setuid(getuid()) == -1) {
208	    fprintf(stderr, gettext("%s: setuid failed: %s\n"),
209		ProgramName, strerror(errno));
210	    exit(1);
211    }
212#endif
213
214    XtSetLanguageProc(NULL, (XtLanguageProc) NULL, NULL);
215
216    toplevel = XtAppInitialize(&app_con, "XLoad", options, XtNumber(options),
217			       &argc, argv, NULL, NULL, (Cardinal) 0);
218
219#ifdef USE_GETTEXT
220    textdomain("xload");
221
222    if ((domaindir = getenv ( "TEXTDOMAINDIR" )) == NULL) {
223	domaindir = LOCALEDIR;
224    }
225    bindtextdomain("xload", domaindir);
226#endif
227
228    if (argc != 1) {
229	fputs(gettext("Unknown argument(s):"), stderr);
230	for (int n = 1; n < argc; n++) {
231	    fprintf(stderr, " %s", argv[n]);
232	}
233	fputs("\n\n", stderr);
234	usage(1);
235    }
236
237    XtGetApplicationResources( toplevel, (XtPointer) &resources,
238			      my_resources, XtNumber(my_resources),
239			      NULL, (Cardinal) 0);
240
241    if (resources.use_lights)
242    {
243	char	    name[1024];
244	XrmString   type;
245	XrmValue    db_value;
246	XrmValue    int_value;
247	Bool	    found = False;
248
249	snprintf (name, sizeof(name), "%s.paned.load.update", XtName(toplevel));
250	found = XrmGetResource (XtScreenDatabase(XtScreen(toplevel)),
251				name, "XLoad.Paned.StripChart.Interval",
252				&type, &db_value);
253	if (found) {
254	    int_value.size = sizeof(int);
255	    int_value.addr = (XPointer) &light_update;
256	    found = XtConvertAndStore(toplevel, type, &db_value, XtRInt,
257				      &int_value);
258	    if (found) light_update *= 1000;
259	}
260	ClearLights (XtDisplay (toplevel));
261	SetLights ((XtPointer) toplevel, (XtIntervalId *) 0);
262    }
263    else
264    {
265    	/*
266     	 * This is a hack so that f.delete will do something useful in this
267     	 * single-window application.
268     	 */
269    	XtAppAddActions (app_con, xload_actions, XtNumber(xload_actions));
270    	XtOverrideTranslations(toplevel,
271		    	XtParseTranslationTable ("<Message>WM_PROTOCOLS: quit()"));
272
273    	XtSetArg (args[0], XtNiconPixmap, &icon_pixmap);
274    	XtGetValues(toplevel, args, ONE);
275    	if (icon_pixmap == None) {
276	    XtSetArg(args[0], XtNiconPixmap,
277		     XCreateBitmapFromData(XtDisplay(toplevel),
278				       	   XtScreen(toplevel)->root,
279				       	   (char *)xload_bits,
280				       	   xload_width, xload_height));
281	    XtSetValues (toplevel, args, ONE);
282    	}
283
284    	if (resources.show_label) {
285      	  pane = XtCreateManagedWidget ("paned", panedWidgetClass,
286				    	toplevel, NULL, ZERO);
287
288      	  label_wid = XtCreateManagedWidget ("label", labelWidgetClass,
289					     pane, NULL, ZERO);
290
291      	  XtSetArg (args[0], XtNlabel, &label);
292      	  XtGetValues(label_wid, args, ONE);
293
294      	  if ( strcmp("label", label) == 0 ) {
295	    (void) XmuGetHostname (host, 255);
296	    XtSetArg (args[0], XtNlabel, host);
297	    XtSetValues (label_wid, args, ONE);
298      	  }
299
300      	  load_parent = pane;
301    	}
302    	else
303      	  load_parent = toplevel;
304
305    	load = XtCreateManagedWidget ("load", stripChartWidgetClass,
306				      load_parent, NULL, ZERO);
307
308    	if (resources.remote)
309	  XtAddCallback(load, XtNgetValue, GetRLoadPoint, NULL);
310	else
311	  XtAddCallback(load, XtNgetValue, GetLoadPoint, NULL);
312
313    	XtRealizeWidget (toplevel);
314    	wm_delete_window = XInternAtom (XtDisplay(toplevel), "WM_DELETE_WINDOW",
315				    	False);
316    	(void) XSetWMProtocols (XtDisplay(toplevel), XtWindow(toplevel),
317			    	&wm_delete_window, 1);
318    }
319    XtAppMainLoop(app_con);
320
321    return 0;
322}
323
324static unsigned long	current_leds;
325
326static void
327ClearLights (Display *dpy)
328{
329    XKeyboardControl	cntrl = {
330	.led_mode = LedModeOff
331    };
332    XChangeKeyboardControl (dpy, KBLedMode, &cntrl);
333    current_leds = 0;
334}
335
336static void
337SetLights (XtPointer data, XtIntervalId *timer)
338{
339    Widget		toplevel;
340    Display		*dpy;
341    double		value;
342    unsigned long	new_leds, change, bit;
343    int			i;
344
345    toplevel = (Widget) data;
346    dpy = XtDisplay (toplevel);
347    if (resources.remote)
348      GetRLoadPoint (toplevel, (XtPointer) 0, (XtPointer) &value);
349    else
350      GetLoadPoint (toplevel, (XtPointer) 0, (XtPointer) &value);
351    new_leds = (1 << (int) (value + 0.1)) - 1;
352    change = new_leds ^ current_leds;
353    i = 1;
354    bit = 1;
355    while (current_leds != new_leds)
356    {
357	if (change & bit)
358	{
359	    XKeyboardControl	cntrl = {
360		.led = i,
361		.led_mode = new_leds & bit ? LedModeOn : LedModeOff
362	    };
363	    XChangeKeyboardControl (dpy, KBLed|KBLedMode, &cntrl);
364	    current_leds ^= bit;
365	}
366	i++;
367	bit <<= 1;
368    }
369    XtAppAddTimeOut(XtWidgetToApplicationContext(toplevel), light_update,
370		    SetLights, data);
371}
372
373static void quit (Widget w, XEvent *event, String *params, Cardinal *num_params)
374{
375    if (event->type == ClientMessage &&
376        event->xclient.data.l[0] != wm_delete_window) {
377        XBell (XtDisplay(w), 0);
378        return;
379    }
380    if (resources.use_lights)
381	ClearLights (XtDisplay (w));
382    XtDestroyApplicationContext(XtWidgetToApplicationContext(w));
383    exit (0);
384}
385
386
387
388
389
390
391