|
|
1.1 root 1: #include <X/mit-copyright.h>
2:
3: /* Copyright 1985, by the Massachusetts Institute of Technology */
4: /* xload -- graph load average on X window system display.
5: * K. Shane Hartman and Stuart A. Malone with ripoffs from xclock.
6: * Host name feature added by Jim Gettys.
7: * Scale feature added by Bob Scheifler.
8: * Rescale feature added by Stuart A. Malone.
9: */
10: #ifndef lint
11: static char *rcsid_xload_c = "$Header: xload.c,v 10.13 86/11/30 14:59:08 jg Rel $";
12: #endif lint
13:
14: #include <stdio.h>
15: #include <strings.h>
16: #include <nlist.h>
17: #include <sys/time.h>
18: #include <sys/file.h>
19: #include <sys/param.h>
20: #include <X/Xlib.h>
21:
22: typedef enum _bool {FALSE, TRUE} Bool;
23:
24: #define KMEM_FILE "/dev/kmem"
25: #define KMEM_ERROR "cannot open /dev/kmem"
26:
27: #define DEFAULT_BORDER_WIDTH 3
28: #define DEFAULT_UPDATE 5 /* Any smaller leads to lossage */
29: #define DEFAULT_FONT "6x10"
30: #define DEFAULT_POSITION "=360x120-0+0" /* upper right hand corner */
31: #define DEFAULT_SCALE 1
32:
33: struct nlist namelist[] = { /* namelist for vmunix grubbing */
34: #define LOADAV 0
35: {"_avenrun"},
36: {0}
37: };
38:
39: extern char *getenv();
40:
41: /* GLOBAL */
42:
43: Window win; /* load average window */
44: double data[2048]; /* accumulated load average data */
45: int background; /* color of background */
46: int foreground; /* color of graph */
47: int highlight; /* color of text, scale */
48: Font font; /* font for printing hostname */
49: char *fn = DEFAULT_FONT; /* font for hostname */
50: FontInfo font_info;
51: char host[256]; /* the host name */
52: double scale = DEFAULT_SCALE; /* n divisions for graph */
53: double min_scale = DEFAULT_SCALE; /* minimum value for scale */
54: double max_loadavg = 0.0; /* maximum loadavg on the graph */
55: int mapped = 1; /* should really display? */
56:
57: /* Diagnostic printer - Print message and exit */
58:
59: void xload_error(message)
60: char *message;
61: {
62: fprintf(stderr, "xload: %s\n", message);
63: perror("xload");
64: exit(1);
65: }
66:
67: /* Blts data according to current size, then redraws the load average window.
68: * Next represents the number of valid points in data. Returns the (possibly)
69: * adjusted value of next. If next is 0, this routine draws an empty window
70: * (scale - 1 lines for graph). If next is less than the current window width,
71: * the returned value is identical to the initial value of next and data is
72: * unchanged. Otherwise keeps half a window's worth of data. If data is
73: * changed, then max_loadavg is updated to reflect the largest data point.
74: */
75:
76: int repaint_window(width, height, next)
77: register int width, height, next;
78: {
79: register int i, j;
80:
81: if (mapped)
82: XClear(win);
83: if (next >= width) {
84: j = width >> 1;
85: bcopy((char *)(data + next - j),(char *)data, j * sizeof(double));
86: next = j;
87: /* Since we just lost some data, recompute the max_loadavg. */
88: max_loadavg = 0.0;
89: for (i = 0; i < next; i++) {
90: if (data[i] > max_loadavg) max_loadavg = data[i];
91: }
92: }
93:
94: /* Compute the minimum scale required to graph the data, but don't go
95: lower than min_scale. */
96: if (max_loadavg > min_scale) scale = ((int)max_loadavg) + 1;
97: else scale = min_scale;
98:
99: if (!mapped) return(next);
100:
101: /* Print hostname */
102: XTextMask(win, 2, 2, host, strlen(host), font, highlight);
103:
104: /* Draw graph reference lines */
105: for (i = 1; i < scale; i++) {
106: j = (i * height) / scale;
107: XLine(win, 0, j, width, j, 1, 1, highlight, GXcopy, AllPlanes);
108: }
109:
110: /* Draw data point lines. */
111: for (i = 0; i < next; i++)
112: XLine(win, i, height, i, (int)(height - (data[i] * height) / scale),
113: 1, 1, foreground, GXcopy, AllPlanes);
114: return(next);
115: }
116:
117: /* Exit with message describing command line format */
118:
119: void usage()
120: {
121: fprintf(stderr,
122: "usage: xload [-fn {font}] [-update {seconds}] [-scale {integer}] [-rv]\n"
123: );
124: fprintf(stderr,
125: " [=[{width}][x{height}][{+-}{xoff}[{+-}{yoff}]]] [[{host}]:[{vs}]]\n"
126: );
127: fprintf(stderr,
128: " [-fg {color}] [-bg {color}] [-hl {color}] [-bd {color}] [-bw {pixels}]\n");
129: exit(1);
130: }
131:
132: /* Returns pointer to first char in search which is also in what, else NULL. */
133:
134: char *strscan(search, what)
135: register char *search;
136: register char *what;
137: {
138: register int i;
139: register len = strlen(what);
140: register char c;
141: while (c = *(search++))
142: for (i = 0; i < len; i++)
143: if (c == what[i]) return (--search);
144: return (NULL);
145: }
146:
147:
148: void main(argc, argv)
149: int argc;
150: char **argv;
151: {
152: char *arg;
153:
154: register int i;
155:
156: register int kmem; /* kmem pointer */
157: register double loadavg; /* load average value */
158: long loadavg_seek; /* offset to load average in kmem */
159:
160: char display[256]; /* will contain vs host */
161: int vsnum; /* will contain vs number */
162:
163: int reverse = 0;
164: char *border_color;
165: char *fore_color;
166: char *back_color;
167: char *high_color;
168: int border_pixmap;
169: int border_width = DEFAULT_BORDER_WIDTH;
170: int update = DEFAULT_UPDATE;
171: Color cdef;
172: OpaqueFrame window; /* frame for the window */
173: char *geometry = NULL;
174: char *def = DEFAULT_POSITION; /* default position */
175: char *option;
176:
177: XEvent event;
178:
179: int maxfds; /* for select call */
180: int readfds;
181: int fdmask;
182: struct timeval timeout; /* will contain update interval */
183:
184: /* Get name list. Then open kmem so we can seek for load average. */
185:
186: nlist("/vmunix", namelist);
187: if (namelist[LOADAV].n_type == 0) xload_error("cannot get name list");
188: loadavg_seek = namelist[LOADAV].n_value;
189: kmem = open(KMEM_FILE, O_RDONLY);
190: if (kmem < 0) xload_error(KMEM_ERROR);
191:
192: gethostname(host, sizeof(host)); /* Who are we? */
193: display[0] = '\0';
194:
195: if ((option = XGetDefault(argv[0],"ReverseVideo")) != NULL )
196: if (strcmp (option, "on") == 0)
197: reverse = 1;
198: if ((option = XGetDefault(argv[0],"BorderWidth")) != NULL)
199: border_width = atoi(option);
200: if ((option = XGetDefault(argv[0],"BodyFont")) != NULL)
201: fn = option;
202: if ((border_color = XGetDefault(argv[0],"Border")) == NULL)
203: border_color = XGetDefault(argv[0],"BorderColor");
204: back_color = XGetDefault(argv[0],"Background");
205: fore_color = XGetDefault(argv[0],"Foreground");
206: high_color = XGetDefault(argv[0],"Highlight");
207: if ((option = XGetDefault(argv[0],"Update")) != NULL)
208: update = atoi(option);
209: if ((option = XGetDefault(argv[0],"Scale")) != NULL)
210: min_scale = atoi(option);
211: if ((option = XGetDefault(argv[0], "Geometry")) != NULL)
212: geometry = option;
213:
214: for (i = 1; i < argc; i++) { /* Parse line */
215: if (argv[i][0] == '=') {
216: geometry = argv[i];
217: continue;
218: }
219: if (index(argv[i], ':') != NULL) { /* host:display */
220: strncpy(display, argv[i], sizeof(display));
221: continue;
222: }
223: if (strcmp(argv[i], "-rv") == 0 ||
224: strcmp(argv[i], "-reverse") == 0) { /* black on white */
225: reverse = 1;
226: continue;
227: }
228: if (strcmp(argv[i], "-fw") == 0 ||
229: strcmp(argv[i], "-forward") == 0) { /* white on black */
230: reverse = 0;
231: continue;
232: }
233: if (strcmp(argv[i], "-bw") == 0 ||
234: strcmp(argv[i], "-border") == 0) { /* border width */
235: if (++i >= argc) usage();
236: border_width = atoi(argv[i]);
237: continue;
238: }
239: if (strcmp(argv[i], "-fn") == 0 ||
240: strcmp(argv[i], "-font") == 0) { /* host name font */
241: if (++i >= argc) usage();
242: fn = argv[i];
243: continue;
244: }
245: if (strcmp(argv[i], "-bd") == 0 ||
246: strcmp(argv[i], "-color") == 0) { /* border color */
247: if (++i >= argc) usage();
248: border_color = argv[i];
249: continue;
250: }
251: if (strcmp(argv[i], "-fg") == 0 ||
252: strcmp(argv[i], "-foreground") == 0) { /* foreground color */
253: if (++i >= argc) usage();
254: fore_color = argv[i];
255: continue;
256: }
257: if (strcmp(argv[i], "-bg") == 0 ||
258: strcmp(argv[i], "-background") == 0) { /* background color */
259: if (++i >= argc) usage();
260: back_color = argv[i];
261: continue;
262: }
263: if (strcmp(argv[i], "-hl") == 0 ||
264: strcmp(argv[i], "-highlight") == 0) { /* highlight color */
265: if (++i >= argc) usage();
266: high_color = argv[i];
267: continue;
268: }
269: if (strcmp(argv[i], "-u") == 0 ||
270: strcmp(argv[i], "-update") == 0) { /* update interval */
271: if (++i >= argc) usage();
272: update = atoi(argv[i]);
273: continue;
274: }
275: if (strcmp(argv[i], "-s") == 0 ||
276: strcmp(argv[i], "-scale") == 0) { /* load scale */
277: if (++i >= argc) usage();
278: min_scale = atoi(argv[i]);
279: continue;
280: }
281: usage();
282: }
283:
284: if (border_width < 0) border_width = DEFAULT_BORDER_WIDTH;
285: if (update < DEFAULT_UPDATE) update = DEFAULT_UPDATE;
286: if (min_scale <= 0) min_scale = DEFAULT_SCALE;
287: scale = min_scale;
288:
289: /* Open display */
290: if (!XOpenDisplay(display)) {
291: fprintf(stderr, "%s: Can't open display '%s'\n",
292: argv[0], XDisplayName(display));
293: exit(1);
294: }
295:
296: /* Need a font to print hostname in */
297: font = XGetFont(fn);
298: if (!font)
299: xload_error("cannot open font");
300: XQueryFont(font, &font_info);
301:
302: if (border_color && DisplayCells() > 2 &&
303: XParseColor(border_color, &cdef) && XGetHardwareColor(&cdef))
304: border_pixmap = XMakeTile(cdef.pixel);
305: else if (reverse) border_pixmap = WhitePixmap;
306: else border_pixmap = BlackPixmap;
307:
308: if (back_color && DisplayCells() > 2 &&
309: XParseColor(back_color, &cdef) && XGetHardwareColor(&cdef))
310: background = cdef.pixel;
311: else if (reverse) background = BlackPixel;
312: else background = WhitePixel;
313:
314: if (fore_color && DisplayCells() > 2 &&
315: XParseColor(fore_color, &cdef) && XGetHardwareColor(&cdef))
316: foreground = cdef.pixel;
317: else if (reverse) foreground = WhitePixel;
318: else foreground = BlackPixel;
319:
320: if (high_color && DisplayCells() > 2 &&
321: XParseColor(high_color, &cdef) && XGetHardwareColor(&cdef))
322: highlight = cdef.pixel;
323: else highlight = foreground;
324:
325: window.bdrwidth = border_width;
326: window.border = border_pixmap;
327: window.background = XMakeTile(background);
328: win = XCreate ("Load Average", argv[0], geometry, def, &window,
329: font_info.width * strlen(host) + 4, font_info.height + 4);
330: XSelectInput(win, ExposeWindow|UnmapWindow);
331: XMapWindow(win); /* Map window to screen */
332: timeout.tv_sec = update; /* Set up timeout for select */
333: timeout.tv_usec = 0;
334: maxfds = dpyno() + 1; /* Set up select arguments */
335: fdmask = 1 << dpyno();
336: i = 0; /* Window is initially empty */
337:
338: while (1) { /* Main loop */
339: if (XPending()) {
340: XNextEvent(&event);
341: switch (event.type) {
342: case ExposeWindow:
343: mapped = 1;
344: window.width = ((XExposeEvent *) &event)->width;
345: window.height = ((XExposeEvent *) &event)->height;
346: i = repaint_window(window.width, window.height, i);
347: break;
348: case UnmapWindow:
349: mapped = 0;
350: break;
351: default:
352: xload_error("unexpected X event");
353: }
354: }
355: else if (i >= window.width) i = repaint_window(window.width, window.height, i);
356: /* Get the load average, stash the point and draw corresponding line. */
357: lseek(kmem, loadavg_seek, 0);
358: #ifdef sun
359: {
360: long temp;
361: read(kmem, (char *)&temp, sizeof(long));
362: loadavg = (double)temp/FSCALE;
363: }
364: #else
365: read(kmem, (char *)&loadavg, sizeof(double));
366: #endif
367:
368: /* Keep max_loadavg up to date, and if this data point is off the
369: graph, change the scale to make it fit. */
370: if (loadavg > max_loadavg) {
371: max_loadavg = loadavg;
372: if (max_loadavg > scale) {
373: scale = ((int)max_loadavg) + 1;
374: i = repaint_window(window.width, window.height, i);
375: }
376: }
377:
378: data[i] = loadavg;
379: if (mapped) {
380: XLine(win, i, window.height, i,
381: (int)(window.height - (window.height * loadavg) / scale),
382: 1, 1, foreground, GXcopy, AllPlanes);
383: XFlush(); /* Flush output buffers */
384: }
385: i++; /* Next point */
386: readfds = fdmask; /* Initialize select mask */
387: /* and select on display fd */
388: if (select(maxfds, &readfds, NULL, NULL, &timeout) == -1)
389: xload_error("select error on display file descriptor");
390: } /* while */
391: } /* main */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.