|
|
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.9 86/02/01 16:00:54 tony 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: short gray_bits[16] = {
58: 0xaaaa, 0x5555, 0xaaaa, 0x5555,
59: 0xaaaa, 0x5555, 0xaaaa, 0x5555,
60: 0xaaaa, 0x5555, 0xaaaa, 0x5555,
61: 0xaaaa, 0x5555, 0xaaaa, 0x5555};
62:
63: /* Diagnostic printer - Print message and exit */
64:
65: void xload_error(message)
66: char *message;
67: {
68: fprintf(stderr, "xload: %s\n", message);
69: perror("xload");
70: exit(1);
71: }
72:
73: /* Blts data according to current size, then redraws the load average window.
74: * Next represents the number of valid points in data. Returns the (possibly)
75: * adjusted value of next. If next is 0, this routine draws an empty window
76: * (scale - 1 lines for graph). If next is less than the current window width,
77: * the returned value is identical to the initial value of next and data is
78: * unchanged. Otherwise keeps half a window's worth of data. If data is
79: * changed, then max_loadavg is updated to reflect the largest data point.
80: */
81:
82: int repaint_window(width, height, next)
83: register int width, height, next;
84: {
85: register int i, j;
86:
87: if (mapped)
88: XClear(win);
89: if (next >= width) {
90: j = width >> 1;
91: bcopy((char *)(data + next - j),(char *)data, j * sizeof(double));
92: next = j;
93: /* Since we just lost some data, recompute the max_loadavg. */
94: max_loadavg = 0.0;
95: for (i = 0; i < next; i++) {
96: if (data[i] > max_loadavg) max_loadavg = data[i];
97: }
98: }
99:
100: /* Compute the minimum scale required to graph the data, but don't go
101: lower than min_scale. */
102: if (max_loadavg > min_scale) scale = ((int)max_loadavg) + 1;
103: else scale = min_scale;
104:
105: if (!mapped) return(next);
106:
107: /* Print hostname */
108: XTextMask(win, 2, 2, host, strlen(host), font, highlight);
109:
110: /* Draw graph reference lines */
111: for (i = 1; i < scale; i++) {
112: j = (i * height) / scale;
113: XLine(win, 0, j, width, j, 1, 1, highlight, GXcopy, AllPlanes);
114: }
115:
116: /* Draw data point lines. */
117: for (i = 0; i < next; i++)
118: XLine(win, i, height, i, (int)(height - (data[i] * height) / scale),
119: 1, 1, foreground, GXcopy, AllPlanes);
120: return(next);
121: }
122:
123: /* Exit with message describing command line format */
124:
125: void usage()
126: {
127: fprintf(stderr,
128: "usage: xload [-fn {font}] [-update {seconds}] [-scale {integer}] [-rv]\n"
129: );
130: fprintf(stderr,
131: " [=[{width}][x{height}][{+-}{xoff}[{+-}{yoff}]]] [[{host}]:[{vs}]]\n"
132: );
133: fprintf(stderr,
134: " [-fg {color}] [-bg {color}] [-hl {color}] [-bd {color}] [-bw {pixels}]\n");
135: exit(1);
136: }
137:
138: /* Returns pointer to first char in search which is also in what, else NULL. */
139:
140: char *strscan(search, what)
141: register char *search;
142: register char *what;
143: {
144: register int i;
145: register len = strlen(what);
146: register char c;
147: while (c = *(search++))
148: for (i = 0; i < len; i++)
149: if (c == what[i]) return (--search);
150: return (NULL);
151: }
152:
153:
154: void main(argc, argv)
155: int argc;
156: char **argv;
157: {
158: char *arg;
159:
160: register int i;
161:
162: register int kmem; /* kmem pointer */
163: register double loadavg; /* load average value */
164: long loadavg_seek; /* offset to load average in kmem */
165:
166: char display[256]; /* will contain vs host */
167: int vsnum; /* will contain vs number */
168:
169: int reverse = 0;
170: char *border_color;
171: char *fore_color;
172: char *back_color;
173: char *high_color;
174: int border_pixmap;
175: int border_width = DEFAULT_BORDER_WIDTH;
176: int update = DEFAULT_UPDATE;
177: Color cdef;
178: OpaqueFrame window; /* frame for the window */
179: char *geometry = NULL;
180: char *def = DEFAULT_POSITION; /* default position */
181: char *option;
182:
183: XEvent event;
184:
185: int maxfds; /* for select call */
186: int readfds;
187: int fdmask;
188: struct timeval timeout; /* will contain update interval */
189:
190: /* Get name list. Then open kmem so we can seek for load average. */
191:
192: nlist("/vmunix", namelist);
193: if (namelist[LOADAV].n_type == 0) xload_error("cannot get name list");
194: loadavg_seek = namelist[LOADAV].n_value;
195: kmem = open(KMEM_FILE, O_RDONLY);
196: if (kmem < 0) xload_error(KMEM_ERROR);
197:
198: gethostname(host, sizeof(host)); /* Who are we? */
199: display[0] = '\0';
200:
201: if ((option = XGetDefault(argv[0],"ReverseVideo")) != NULL )
202: if (strcmp (option, "on") == 0)
203: reverse = 1;
204: if ((option = XGetDefault(argv[0],"BorderWidth")) != NULL)
205: border_width = atoi(option);
206: if ((option = XGetDefault(argv[0],"BodyFont")) != NULL)
207: fn = option;
208: if ((border_color = XGetDefault(argv[0],"Border")) == NULL)
209: border_color = XGetDefault(argv[0],"BorderColor");
210: back_color = XGetDefault(argv[0],"Background");
211: fore_color = XGetDefault(argv[0],"Foreground");
212: high_color = XGetDefault(argv[0],"Highlight");
213: if ((option = XGetDefault(argv[0],"Update")) != NULL)
214: update = atoi(option);
215: if ((option = XGetDefault(argv[0],"Scale")) != NULL)
216: min_scale = atoi(option);
217:
218: for (i = 1; i < argc; i++) { /* Parse line */
219: if (argv[i][0] == '=') {
220: geometry = argv[i];
221: continue;
222: }
223: if (index(argv[i], ':') != NULL) { /* host:display */
224: strncpy(display, argv[i], sizeof(display));
225: continue;
226: }
227: if (strcmp(argv[i], "-rv") == 0 ||
228: strcmp(argv[i], "-reverse") == 0) { /* black on white */
229: reverse = 1;
230: continue;
231: }
232: if (strcmp(argv[i], "-fw") == 0 ||
233: strcmp(argv[i], "-forward") == 0) { /* white on black */
234: reverse = 0;
235: continue;
236: }
237: if (strcmp(argv[i], "-bw") == 0 ||
238: strcmp(argv[i], "-border") == 0) { /* border width */
239: if (++i >= argc) usage();
240: border_width = atoi(argv[i]);
241: continue;
242: }
243: if (strcmp(argv[i], "-fn") == 0 ||
244: strcmp(argv[i], "-font") == 0) { /* host name font */
245: if (++i >= argc) usage();
246: fn = argv[i];
247: continue;
248: }
249: if (strcmp(argv[i], "-bd") == 0 ||
250: strcmp(argv[i], "-color") == 0) { /* border color */
251: if (++i >= argc) usage();
252: border_color = argv[i];
253: continue;
254: }
255: if (strcmp(argv[i], "-fg") == 0 ||
256: strcmp(argv[i], "-foreground") == 0) { /* foreground color */
257: if (++i >= argc) usage();
258: fore_color = argv[i];
259: continue;
260: }
261: if (strcmp(argv[i], "-bg") == 0 ||
262: strcmp(argv[i], "-background") == 0) { /* background color */
263: if (++i >= argc) usage();
264: back_color = argv[i];
265: continue;
266: }
267: if (strcmp(argv[i], "-hl") == 0 ||
268: strcmp(argv[i], "-highlight") == 0) { /* highlight color */
269: if (++i >= argc) usage();
270: high_color = argv[i];
271: continue;
272: }
273: if (strcmp(argv[i], "-u") == 0 ||
274: strcmp(argv[i], "-update") == 0) { /* update interval */
275: if (++i >= argc) usage();
276: update = atoi(argv[i]);
277: continue;
278: }
279: if (strcmp(argv[i], "-s") == 0 ||
280: strcmp(argv[i], "-scale") == 0) { /* load scale */
281: if (++i >= argc) usage();
282: min_scale = atoi(argv[i]);
283: continue;
284: }
285: usage();
286: }
287:
288: if (border_width < 0) border_width = DEFAULT_BORDER_WIDTH;
289: if (update < DEFAULT_UPDATE) update = DEFAULT_UPDATE;
290: if (min_scale <= 0) min_scale = DEFAULT_SCALE;
291: scale = min_scale;
292:
293: /* Open display */
294: if (!XOpenDisplay(display))
295: xload_error("cannot open display");
296:
297: /* Need a font to print hostname in */
298: font = XGetFont(fn);
299: if (!font)
300: xload_error("cannot open font");
301: XQueryFont(font, &font_info);
302:
303: if (border_color && DisplayCells() > 2 &&
304: XParseColor(border_color, &cdef) && XGetHardwareColor(&cdef))
305: border_pixmap = XMakeTile(cdef.pixel);
306: else if (border_color && strcmp(border_color, "black") == 0)
307: border_pixmap = BlackPixmap;
308: else if (border_color && strcmp(border_color, "white") == 0)
309: border_pixmap = WhitePixmap;
310: else
311: border_pixmap = XMakePixmap ((Bitmap) XStoreBitmap (16, 16, gray_bits),
312: BlackPixel, WhitePixel);
313:
314: if (back_color && DisplayCells() > 2 &&
315: XParseColor(back_color, &cdef) && XGetHardwareColor(&cdef)) {
316: background = cdef.pixel;
317: } else if (back_color && strcmp(back_color, "white") == 0) {
318: background = WhitePixel;
319: reverse = 0;
320: } else if (back_color && strcmp(back_color, "black") == 0) {
321: background = BlackPixel;
322: reverse = 0;
323: } else
324: background = BlackPixel;
325:
326: if (fore_color && DisplayCells() > 2 &&
327: XParseColor(fore_color, &cdef) && XGetHardwareColor(&cdef)) {
328: foreground = cdef.pixel;
329: } else if (fore_color && strcmp(fore_color, "black") == 0) {
330: foreground = BlackPixel;
331: reverse = 0;
332: } else if (fore_color && strcmp(fore_color, "white") == 0) {
333: foreground = WhitePixel;
334: reverse = 0;
335: } else
336: foreground = WhitePixel;
337:
338: if (high_color && DisplayCells() > 2 &&
339: XParseColor(high_color, &cdef) && XGetHardwareColor(&cdef))
340: highlight = cdef.pixel;
341: else if (reverse)
342: highlight = background;
343: else
344: highlight = foreground;
345:
346: if (reverse) {
347: background = foreground;
348: foreground = highlight;
349: }
350:
351: window.bdrwidth = border_width;
352: window.border = border_pixmap;
353: window.background = XMakeTile(background);
354: win = XCreate ("Load Average", argv[0], geometry, def, &window,
355: font_info.width * strlen(host) + 4, font_info.height + 4);
356: XSelectInput(win, ExposeWindow|UnmapWindow);
357: XMapWindow(win); /* Map window to screen */
358: timeout.tv_sec = update; /* Set up timeout for select */
359: timeout.tv_usec = 0;
360: maxfds = dpyno() + 1; /* Set up select arguments */
361: fdmask = 1 << dpyno();
362: i = 0; /* Window is initially empty */
363:
364: while (1) { /* Main loop */
365: if (XPending()) {
366: XNextEvent(&event);
367: switch (event.type) {
368: case ExposeWindow:
369: mapped = 1;
370: window.width = ((XExposeEvent *) &event)->width;
371: window.height = ((XExposeEvent *) &event)->height;
372: i = repaint_window(window.width, window.height, i);
373: break;
374: case UnmapWindow:
375: mapped = 0;
376: break;
377: default:
378: xload_error("unexpected X event");
379: }
380: }
381: else if (i >= window.width) i = repaint_window(window.width, window.height, i);
382: /* Get the load average, stash the point and draw corresponding line. */
383: lseek(kmem, loadavg_seek, 0);
384: #ifdef sun
385: {
386: long temp;
387: read(kmem, (char *)&temp, sizeof(long));
388: loadavg = (double)temp/FSCALE;
389: }
390: #else
391: read(kmem, (char *)&loadavg, sizeof(double));
392: #endif
393:
394: /* Keep max_loadavg up to date, and if this data point is off the
395: graph, change the scale to make it fit. */
396: if (loadavg > max_loadavg) {
397: max_loadavg = loadavg;
398: if (max_loadavg > scale) {
399: scale = ((int)max_loadavg) + 1;
400: i = repaint_window(window.width, window.height, i);
401: }
402: }
403:
404: data[i] = loadavg;
405: if (mapped) {
406: XLine(win, i, window.height, i,
407: (int)(window.height - (window.height * loadavg) / scale),
408: 1, 1, foreground, GXcopy, AllPlanes);
409: XFlush(); /* Flush output buffers */
410: }
411: i++; /* Next point */
412: readfds = fdmask; /* Initialize select mask */
413: /* and select on display fd */
414: if (select(maxfds, &readfds, NULL, NULL, &timeout) == -1)
415: xload_error("select error on display file descriptor");
416: } /* while */
417: } /* main */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.