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