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