|
|
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.