|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1980 Regents of the University of California. ! 3: * All rights reserved. The Berkeley software License Agreement ! 4: * specifies the terms and conditions for redistribution. ! 5: */ ! 6: ! 7: #ifndef lint ! 8: char copyright[] = ! 9: "@(#) Copyright (c) 1980 Regents of the University of California.\n\ ! 10: All rights reserved.\n"; ! 11: #endif not lint ! 12: ! 13: #ifndef lint ! 14: static char sccsid[] = "@(#)sysline.c 5.6 (Berkeley) 1/9/86"; ! 15: #endif not lint ! 16: ! 17: /* ! 18: * sysline - system status display on 25th line of terminal ! 19: * j.k.foderaro ! 20: * ! 21: * Prints a variety of information on the special status line of terminals ! 22: * that have a status display capability. Cursor motions, status commands, ! 23: * etc. are gleamed from /etc/termcap. ! 24: * By default, all information is printed, and flags are given on the command ! 25: * line to disable the printing of information. The information and ! 26: * disabling flags are: ! 27: * ! 28: * flag what ! 29: * ----- ---- ! 30: * time of day ! 31: * load average and change in load average in the last 5 mins ! 32: * number of user logged on ! 33: * -p # of processes the users owns which are runnable and the ! 34: * number which are suspended. Processes whose parent is 1 ! 35: * are not counted. ! 36: * -l users who've logged on and off. ! 37: * -m summarize new mail which has arrived ! 38: * ! 39: * <other flags> ! 40: * -r use non reverse video ! 41: * -c turn off 25th line for 5 seconds before redisplaying. ! 42: * -b beep once one the half hour, twice on the hour ! 43: * +N refresh display every N seconds. ! 44: * -i print pid first thing ! 45: * -e do simple print designed for an emacs buffer line ! 46: * -w do the right things for a window ! 47: * -h print hostname between time and load average ! 48: * -D print day/date before time of day ! 49: * -d debug mode - print status line data in human readable format ! 50: * -q quiet mode - don't output diagnostic messages ! 51: * -s print Short (left-justified) line if escapes not allowed ! 52: * -j Print left Justified line regardless ! 53: */ ! 54: ! 55: #define BSD4_2 /* for 4.2 BSD */ ! 56: #define WHO /* turn this on always */ ! 57: #define HOSTNAME /* 4.1a or greater, with hostname() */ ! 58: #define RWHO /* 4.1a or greater, with rwho */ ! 59: #define VMUNIX /* turn this on if you are running on vmunix */ ! 60: #define NEW_BOOTTIME /* 4.1c or greater */ ! 61: ! 62: #define NETPREFIX "ucb" ! 63: #define DEFDELAY 60 /* update status once per minute */ ! 64: #define MAILDIR "/usr/spool/mail" ! 65: /* ! 66: * if MAXLOAD is defined, then if the load average exceeded MAXLOAD ! 67: * then the process table will not be scanned and the log in/out data ! 68: * will not be checked. The purpose of this is to reduced the load ! 69: * on the system when it is loaded. ! 70: */ ! 71: #define MAXLOAD 6.0 ! 72: ! 73: #include <stdio.h> ! 74: #include <sys/param.h> ! 75: #include <sys/signal.h> ! 76: #include <utmp.h> ! 77: #include <ctype.h> ! 78: #ifndef BSD4_2 ! 79: #include <unctrl.h> ! 80: #endif ! 81: #include <sys/time.h> ! 82: #include <sys/stat.h> ! 83: #ifdef VMUNIX ! 84: #include <nlist.h> ! 85: #include <sys/vtimes.h> ! 86: #include <sys/proc.h> ! 87: #endif ! 88: #ifdef pdp11 ! 89: #include <a.out.h> ! 90: #include <sys/proc.h> ! 91: #endif ! 92: #include <curses.h> ! 93: #undef nl ! 94: #ifdef TERMINFO ! 95: #include <term.h> ! 96: #endif TERMINFO ! 97: ! 98: #ifdef RWHO ! 99: #include <protocols/rwhod.h> ! 100: ! 101: #define DOWN_THRESHOLD (11 * 60) ! 102: #define RWHOLEADER "/usr/spool/rwho/whod." ! 103: ! 104: struct remotehost { ! 105: char *rh_host; ! 106: int rh_file; ! 107: } remotehost[10]; ! 108: int nremotes = 0; ! 109: #endif RWHO ! 110: ! 111: struct nlist nl[] = { ! 112: #ifdef NEW_BOOTTIME ! 113: { "_boottime" }, /* After 4.1a the label changed to "boottime" */ ! 114: #else ! 115: { "_bootime" }, /* Under 4.1a and earlier it is "bootime" */ ! 116: #endif ! 117: #define NL_BOOT 0 ! 118: { "_proc" }, ! 119: #define NL_PROC 1 ! 120: { "_avenrun" }, ! 121: #define NL_AVEN 2 ! 122: #ifdef VMUNIX ! 123: { "_nproc" }, ! 124: #define NL_NPROC 3 ! 125: #endif ! 126: 0 ! 127: }; ! 128: ! 129: /* stuff for the kernel */ ! 130: int kmem; /* file descriptor for /dev/kmem */ ! 131: struct proc *proc, *procNPROC; ! 132: int nproc; ! 133: int procadr; ! 134: double avenrun[3]; /* used for storing load averages */ ! 135: ! 136: /* ! 137: * In order to determine how many people are logged on and who has ! 138: * logged in or out, we read in the /etc/utmp file. We also keep track of ! 139: * the previous utmp file. ! 140: */ ! 141: int ut = -1; /* the file descriptor */ ! 142: struct utmp *new, *old; ! 143: char *status; /* per tty status bits, see below */ ! 144: int nentries; /* number of utmp entries */ ! 145: /* string lengths for printing */ ! 146: #define LINESIZE (sizeof old->ut_line) ! 147: #define NAMESIZE (sizeof old->ut_name) ! 148: /* ! 149: * Status codes to say what has happened to a particular entry in utmp. ! 150: * NOCH means no change, ON means new person logged on, ! 151: * OFF means person logged off. ! 152: */ ! 153: #define NOCH 0 ! 154: #define ON 0x1 ! 155: #define OFF 0x2 ! 156: ! 157: #ifdef WHO ! 158: char whofilename[100]; ! 159: char whofilename2[100]; ! 160: #endif ! 161: ! 162: #ifdef HOSTNAME ! 163: char hostname[MAXHOSTNAMELEN+1]; /* one more for null termination */ ! 164: #endif ! 165: ! 166: char lockfilename[100]; /* if exists, will prevent us from running */ ! 167: ! 168: /* flags which determine which info is printed */ ! 169: int mailcheck = 1; /* m - do biff like checking of mail */ ! 170: int proccheck = 1; /* p - give information on processes */ ! 171: int logcheck = 1; /* l - tell who logs in and out */ ! 172: int hostprint = 0; /* h - print out hostname */ ! 173: int dateprint = 0; /* h - print out day/date */ ! 174: int quiet = 0; /* q - hush diagnostic messages */ ! 175: ! 176: /* flags which determine how things are printed */ ! 177: int clr_bet_ref = 0; /* c - clear line between refeshes */ ! 178: int reverse = 1; /* r - use reverse video */ ! 179: int shortline = 0; /* s - short (left-justified) if escapes not allowed */ ! 180: int leftline = 0; /* j - left-justified even if escapes allowed */ ! 181: ! 182: /* flags which have terminal do random things */ ! 183: int beep = 0; /* b - beep every half hour and twice every hour */ ! 184: int printid = 0; /* i - print pid of this process at startup */ ! 185: int synch = 1; /* synchronize with clock */ ! 186: ! 187: /* select output device (status display or straight output) */ ! 188: int emacs = 0; /* e - assume status display */ ! 189: int window = 0; /* w - window mode */ ! 190: int dbug = 0; /* d - debug */ ! 191: ! 192: /* ! 193: * used to turn off reverse video every REVOFF times ! 194: * in an attempt to not wear out the phospher. ! 195: */ ! 196: #define REVOFF 5 ! 197: int revtime = 1; ! 198: ! 199: /* used by mail checker */ ! 200: off_t mailsize = 0; ! 201: off_t linebeg = 0; /* place where we last left off reading */ ! 202: ! 203: /* things used by the string routines */ ! 204: int chars; /* number of printable characters */ ! 205: char *sp; ! 206: char strarr[512]; /* big enough now? */ ! 207: /* flags to stringdump() */ ! 208: char sawmail; /* remember mail was seen to print bells */ ! 209: char mustclear; /* status line messed up */ ! 210: ! 211: /* strings which control status line display */ ! 212: #ifdef TERMINFO ! 213: char *rev_out, *rev_end, *arrows; ! 214: char *tparm(); ! 215: #else ! 216: char to_status_line[64]; ! 217: char from_status_line[64]; ! 218: char dis_status_line[64]; ! 219: char clr_eol[64]; ! 220: char rev_out[20], rev_end[20]; ! 221: char *arrows, *bell = "\007"; ! 222: int eslok; /* escapes on status line okay (reverse, cursor addressing) */ ! 223: int columns; ! 224: #define tparm(cap, parm) tgoto((cap), 0, (parm)) ! 225: char *tgoto(); ! 226: #endif ! 227: ! 228: /* to deal with window size changes */ ! 229: #ifdef SIGWINCH ! 230: int sigwinch(); ! 231: char winchanged; /* window size has changed since last update */ ! 232: #endif ! 233: ! 234: /* random globals */ ! 235: char *username; ! 236: char *ourtty; /* keep track of what tty we're on */ ! 237: struct stat stbuf, mstbuf; /* mstbuf for mail check only */ ! 238: unsigned delay = DEFDELAY; ! 239: short uid; ! 240: double loadavg = 0.0; /* current load average */ ! 241: int users = 0; ! 242: ! 243: char *getenv(); ! 244: char *ttyname(); ! 245: char *strcpy1(); ! 246: char *sysrup(); ! 247: char *calloc(); ! 248: char *malloc(); ! 249: int outc(); ! 250: int erroutc(); ! 251: ! 252: main(argc,argv) ! 253: register char **argv; ! 254: { ! 255: int clearbotl(); ! 256: register char *cp; ! 257: char *home; ! 258: extern char _sobuf[]; ! 259: extern char *index(); ! 260: ! 261: setbuf(stdout, _sobuf); ! 262: ! 263: #ifdef HOSTNAME ! 264: gethostname(hostname, sizeof hostname - 1); ! 265: if ((cp = index(hostname, '.')) != NULL) ! 266: *cp = '\0'; ! 267: #endif ! 268: ! 269: for (argv++; *argv != 0; argv++) ! 270: switch (**argv) { ! 271: case '-': ! 272: for (cp = *argv + 1; *cp; cp++) { ! 273: switch(*cp) { ! 274: case 'r' : /* turn off reverse video */ ! 275: reverse = 0; ! 276: break; ! 277: case 'c': ! 278: clr_bet_ref = 1; ! 279: break; ! 280: case 'h': ! 281: hostprint = 1; ! 282: break; ! 283: case 'D': ! 284: dateprint = 1; ! 285: break; ! 286: #ifdef RWHO ! 287: case 'H': ! 288: if (argv[1] == 0) ! 289: break; ! 290: argv++; ! 291: if (strcmp(hostname, *argv) && ! 292: strcmp(&hostname[sizeof NETPREFIX - 1], *argv)) ! 293: remotehost[nremotes++].rh_host = *argv; ! 294: break; ! 295: #endif RWHO ! 296: case 'm': ! 297: mailcheck = 0; ! 298: break; ! 299: case 'p': ! 300: proccheck = 0; ! 301: break; ! 302: case 'l': ! 303: logcheck = 0; ! 304: break; ! 305: case 'b': ! 306: beep = 1; ! 307: break; ! 308: case 'i': ! 309: printid = 1; ! 310: break; ! 311: case 'w': ! 312: window = 1; ! 313: break; ! 314: case 'e': ! 315: emacs = 1; ! 316: break; ! 317: case 'd': ! 318: dbug = 1; ! 319: break; ! 320: case 'q': ! 321: quiet = 1; ! 322: break; ! 323: case 's': ! 324: shortline = 1; ! 325: break; ! 326: case 'j': ! 327: leftline = 1; ! 328: break; ! 329: default: ! 330: fprintf(stderr, ! 331: "sysline: bad flag: %c\n", *cp); ! 332: } ! 333: } ! 334: break; ! 335: case '+': ! 336: delay = atoi(*argv + 1); ! 337: if (delay < 10) ! 338: delay = 10; ! 339: else if (delay > 500) ! 340: delay = 500; ! 341: synch = 0; /* no more sync */ ! 342: break; ! 343: default: ! 344: fprintf(stderr, "sysline: illegal argument %s\n", ! 345: argv[0]); ! 346: } ! 347: if (emacs) { ! 348: reverse = 0; ! 349: columns = 79; ! 350: } else /* if not to emacs window, initialize terminal dependent info */ ! 351: initterm(); ! 352: #ifdef SIGWINCH ! 353: /* ! 354: * When the window size changes and we are the foreground ! 355: * process (true if -w), we get this signal. ! 356: */ ! 357: signal(SIGWINCH, sigwinch); ! 358: #endif ! 359: getwinsize(); /* get window size from ioctl */ ! 360: ! 361: /* immediately fork and let the parent die if not emacs mode */ ! 362: if (!emacs && !window && !dbug) { ! 363: if (fork()) ! 364: exit(0); ! 365: /* pgrp should take care of things, but ignore them anyway */ ! 366: signal(SIGINT, SIG_IGN); ! 367: signal(SIGQUIT, SIG_IGN); ! 368: #ifdef VMUNIX ! 369: signal(SIGTTOU, SIG_IGN); ! 370: #endif ! 371: } ! 372: /* ! 373: * When we logoff, init will do a "vhangup()" on this ! 374: * tty which turns off I/O access and sends a SIGHUP ! 375: * signal. We catch this and thereby clear the status ! 376: * display. Note that a bug in 4.1bsd caused the SIGHUP ! 377: * signal to be sent to the wrong process, so you had to ! 378: * `kill -HUP' yourself in your .logout file. ! 379: * Do the same thing for SIGTERM, which is the default kill ! 380: * signal. ! 381: */ ! 382: signal(SIGHUP, clearbotl); ! 383: signal(SIGTERM, clearbotl); ! 384: /* ! 385: * This is so kill -ALRM to force update won't screw us up.. ! 386: */ ! 387: signal(SIGALRM, SIG_IGN); ! 388: ! 389: uid = getuid(); ! 390: ourtty = ttyname(2); /* remember what tty we are on */ ! 391: if (printid) { ! 392: printf("%d\n", getpid()); ! 393: fflush(stdout); ! 394: } ! 395: dup2(2, 1); ! 396: ! 397: if ((home = getenv("HOME")) == 0) ! 398: home = ""; ! 399: strcpy1(strcpy1(whofilename, home), "/.who"); ! 400: strcpy1(strcpy1(whofilename2, home), "/.sysline"); ! 401: strcpy1(strcpy1(lockfilename, home), "/.syslinelock"); ! 402: ! 403: if ((kmem = open("/dev/kmem",0)) < 0) { ! 404: fprintf(stderr, "Can't open kmem.\n"); ! 405: exit(1); ! 406: } ! 407: readnamelist(); ! 408: if (proccheck) ! 409: initprocread(); ! 410: if (mailcheck) ! 411: if ((username = getenv("USER")) == 0) ! 412: mailcheck = 0; ! 413: else { ! 414: chdir(MAILDIR); ! 415: if (stat(username, &mstbuf) >= 0) ! 416: mailsize = mstbuf.st_size; ! 417: else ! 418: mailsize = 0; ! 419: } ! 420: ! 421: while (emacs || window || isloggedin()) ! 422: if (access(lockfilename, 0) >= 0) ! 423: sleep(60); ! 424: else { ! 425: prtinfo(); ! 426: sleep(delay); ! 427: if (clr_bet_ref) { ! 428: tputs(dis_status_line, 1, outc); ! 429: fflush(stdout); ! 430: sleep(5); ! 431: } ! 432: revtime = (1 + revtime) % REVOFF; ! 433: } ! 434: clearbotl(); ! 435: /*NOTREACHED*/ ! 436: } ! 437: ! 438: isloggedin() ! 439: { ! 440: /* ! 441: * you can tell if a person has logged out if the owner of ! 442: * the tty has changed ! 443: */ ! 444: struct stat statbuf; ! 445: ! 446: return fstat(2, &statbuf) == 0 && statbuf.st_uid == uid; ! 447: } ! 448: ! 449: readnamelist() ! 450: { ! 451: time_t bootime, clock, nintv, time(); ! 452: ! 453: #ifdef pdp11 ! 454: nlist("/unix", nl); ! 455: #else ! 456: nlist("/vmunix", nl); ! 457: #endif ! 458: if (nl[0].n_value == 0) { ! 459: if (!quiet) ! 460: fprintf(stderr, "No namelist\n"); ! 461: return; ! 462: } ! 463: lseek(kmem, (long)nl[NL_BOOT].n_value, 0); ! 464: read(kmem, &bootime, sizeof(bootime)); ! 465: (void) time(&clock); ! 466: nintv = clock - bootime; ! 467: if (nintv <= 0L || nintv > 60L*60L*24L*365L) { ! 468: if (!quiet) ! 469: fprintf(stderr, ! 470: "Time makes no sense... namelist must be wrong\n"); ! 471: nl[NL_PROC].n_value = nl[NL_AVEN].n_value = 0; ! 472: } ! 473: } ! 474: ! 475: readutmp(nflag) ! 476: char nflag; ! 477: { ! 478: static time_t lastmod; /* initially zero */ ! 479: static off_t utmpsize; /* ditto */ ! 480: struct stat st; ! 481: ! 482: if (ut < 0 && (ut = open("/etc/utmp", 0)) < 0) { ! 483: fprintf(stderr, "sysline: Can't open utmp.\n"); ! 484: exit(1); ! 485: } ! 486: if (fstat(ut, &st) < 0 || st.st_mtime == lastmod) ! 487: return 0; ! 488: lastmod = st.st_mtime; ! 489: if (utmpsize != st.st_size) { ! 490: utmpsize = st.st_size; ! 491: nentries = utmpsize / sizeof (struct utmp); ! 492: if (old == 0) { ! 493: old = (struct utmp *)calloc(utmpsize, 1); ! 494: new = (struct utmp *)calloc(utmpsize, 1); ! 495: } else { ! 496: old = (struct utmp *)realloc((char *)old, utmpsize); ! 497: new = (struct utmp *)realloc((char *)new, utmpsize); ! 498: free(status); ! 499: } ! 500: status = malloc(nentries * sizeof *status); ! 501: if (old == 0 || new == 0 || status == 0) { ! 502: fprintf(stderr, "sysline: Out of memory.\n"); ! 503: exit(1); ! 504: } ! 505: } ! 506: lseek(ut, 0L, 0); ! 507: (void) read(ut, (char *) (nflag ? new : old), utmpsize); ! 508: return 1; ! 509: } ! 510: ! 511: /* ! 512: * read in the process table locations and sizes, and allocate space ! 513: * for storing the process table. This is done only once. ! 514: */ ! 515: initprocread() ! 516: { ! 517: ! 518: if (nl[NL_PROC].n_value == 0) ! 519: return; ! 520: #ifdef VMUNIX ! 521: lseek(kmem, (long)nl[NL_PROC].n_value, 0); ! 522: read(kmem, &procadr, sizeof procadr); ! 523: lseek(kmem, (long)nl[NL_NPROC].n_value, 0); ! 524: read(kmem, &nproc, sizeof nproc); ! 525: #endif ! 526: #ifdef pdp11 ! 527: procadr = nl[NL_PROC].n_value; ! 528: nproc = NPROC; /* from param.h */ ! 529: #endif ! 530: if ((proc = (struct proc *) calloc(nproc, sizeof (struct proc))) == 0) { ! 531: fprintf(stderr, "Out of memory.\n"); ! 532: exit(1); ! 533: } ! 534: procNPROC = proc + nproc; ! 535: } ! 536: ! 537: /* ! 538: * read in the process table. This assumes that initprocread has alread been ! 539: * called to set up storage. ! 540: */ ! 541: readproctab() ! 542: { ! 543: ! 544: if (nl[NL_PROC].n_value == 0) ! 545: return (0); ! 546: lseek(kmem, (long)procadr, 0); ! 547: read(kmem, (char *)proc, nproc * sizeof (struct proc)); ! 548: return (1); ! 549: } ! 550: ! 551: prtinfo() ! 552: { ! 553: int on, off; ! 554: register i; ! 555: char fullprocess; ! 556: ! 557: stringinit(); ! 558: #ifdef SIGWINCH ! 559: if (winchanged) { ! 560: winchanged = 0; ! 561: getwinsize(); ! 562: mustclear = 1; ! 563: } ! 564: #endif ! 565: #ifdef WHO ! 566: /* check for file named .who in the home directory */ ! 567: whocheck(); ! 568: #endif ! 569: timeprint(); ! 570: /* ! 571: * if mail is seen, don't print rest of info, just the mail ! 572: * reverse new and old so that next time we run, we won't lose log ! 573: * in and out information ! 574: */ ! 575: if (mailcheck && (sawmail = mailseen())) ! 576: goto bottom; ! 577: #ifdef HOSTNAME ! 578: #ifdef RWHO ! 579: for (i = 0; i < nremotes; i++) { ! 580: char *tmp; ! 581: ! 582: stringspace(); ! 583: tmp = sysrup(remotehost + i); ! 584: stringcat(tmp, strlen(tmp)); ! 585: } ! 586: #endif ! 587: /* ! 588: * print hostname info if requested ! 589: */ ! 590: if (hostprint) { ! 591: stringspace(); ! 592: stringcat(hostname, -1); ! 593: } ! 594: #endif ! 595: /* ! 596: * print load average and difference between current load average ! 597: * and the load average 5 minutes ago ! 598: */ ! 599: if (nl[NL_AVEN].n_value != 0) { ! 600: double diff; ! 601: ! 602: stringspace(); ! 603: #ifdef VMUNIX ! 604: lseek(kmem, (long)nl[NL_AVEN].n_value, 0); ! 605: read(kmem, avenrun, sizeof avenrun); ! 606: #endif ! 607: #ifdef pdp11 ! 608: loadav(avenrun); ! 609: #endif ! 610: if ((diff = avenrun[0] - avenrun[1]) < 0.0) ! 611: stringprt("%.1f %.1f", avenrun[0], diff); ! 612: else ! 613: stringprt("%.1f +%.1f", avenrun[0], diff); ! 614: loadavg = avenrun[0]; /* remember load average */ ! 615: } ! 616: /* ! 617: * print log on and off information ! 618: */ ! 619: stringspace(); ! 620: fullprocess = 1; ! 621: #ifdef MAXLOAD ! 622: if (loadavg > MAXLOAD) ! 623: fullprocess = 0; /* too loaded to run */ ! 624: #endif ! 625: /* ! 626: * Read utmp file (logged in data) only if we are doing a full ! 627: * process, or if this is the first time and we are calculating ! 628: * the number of users. ! 629: */ ! 630: on = off = 0; ! 631: if (users == 0) { /* first time */ ! 632: if (readutmp(0)) ! 633: for (i = 0; i < nentries; i++) ! 634: if (old[i].ut_name[0]) ! 635: users++; ! 636: } else if (fullprocess && readutmp(1)) { ! 637: struct utmp *tmp; ! 638: ! 639: users = 0; ! 640: for (i = 0; i < nentries; i++) { ! 641: if (strncmp(old[i].ut_name, ! 642: new[i].ut_name, NAMESIZE) == 0) ! 643: status[i] = NOCH; ! 644: else if (old[i].ut_name[0] == '\0') { ! 645: status[i] = ON; ! 646: on++; ! 647: } else if (new[i].ut_name[0] == '\0') { ! 648: status[i] = OFF; ! 649: off++; ! 650: } else { ! 651: status[i] = ON | OFF; ! 652: on++; ! 653: off++; ! 654: } ! 655: if (new[i].ut_name[0]) ! 656: users++; ! 657: } ! 658: tmp = new; ! 659: new = old; ! 660: old = tmp; ! 661: } ! 662: /* ! 663: * Print: ! 664: * 1. number of users ! 665: * 2. a * for unread mail ! 666: * 3. a - if load is too high ! 667: * 4. number of processes running and stopped ! 668: */ ! 669: stringprt("%du", users); ! 670: if (mailsize > 0 && mstbuf.st_mtime >= mstbuf.st_atime) ! 671: stringcat("*", -1); ! 672: if (!fullprocess && (proccheck || logcheck)) ! 673: stringcat("-", -1); ! 674: if (fullprocess && proccheck && readproctab()) { ! 675: register struct proc *p; ! 676: int procrun, procstop; ! 677: ! 678: /* ! 679: * We are only interested in processes which have the same ! 680: * uid as us, and whose parent process id is not 1. ! 681: */ ! 682: procrun = procstop = 0; ! 683: for (p = proc; p < procNPROC; p++) { ! 684: if (p->p_stat == 0 || p->p_pgrp == 0 || ! 685: p->p_uid != uid || p->p_ppid == 1) ! 686: continue; ! 687: switch (p->p_stat) { ! 688: case SSTOP: ! 689: procstop++; ! 690: break; ! 691: case SSLEEP: ! 692: /* ! 693: * Sleep can mean waiting for a signal or just ! 694: * in a disk or page wait queue ready to run. ! 695: * We can tell if it is the later by the pri ! 696: * being negative. ! 697: */ ! 698: if (p->p_pri < PZERO) ! 699: procrun++; ! 700: break; ! 701: case SWAIT: ! 702: case SRUN: ! 703: case SIDL: ! 704: procrun++; ! 705: } ! 706: } ! 707: if (procrun > 0 || procstop > 0) { ! 708: stringspace(); ! 709: if (procrun > 0 && procstop > 0) ! 710: stringprt("%dr %ds", procrun, procstop); ! 711: else if (procrun > 0) ! 712: stringprt("%dr", procrun); ! 713: else ! 714: stringprt("%ds", procstop); ! 715: } ! 716: } ! 717: /* ! 718: * If anyone has logged on or off, and we are interested in it, ! 719: * print it out. ! 720: */ ! 721: if (logcheck) { ! 722: /* old and new have already been swapped */ ! 723: if (on) { ! 724: stringspace(); ! 725: stringcat("on:", -1); ! 726: for (i = 0; i < nentries; i++) ! 727: if (status[i] & ON) { ! 728: stringprt(" %.8s", old[i].ut_name); ! 729: ttyprint(old[i].ut_line); ! 730: } ! 731: } ! 732: if (off) { ! 733: stringspace(); ! 734: stringcat("off:", -1); ! 735: for (i = 0; i < nentries; i++) ! 736: if (status[i] & OFF) { ! 737: stringprt(" %.8s", new[i].ut_name); ! 738: ttyprint(new[i].ut_line); ! 739: } ! 740: } ! 741: } ! 742: bottom: ! 743: /* dump out what we know */ ! 744: stringdump(); ! 745: } ! 746: ! 747: timeprint() ! 748: { ! 749: long curtime; ! 750: struct tm *tp, *localtime(); ! 751: static int beepable = 1; ! 752: ! 753: /* always print time */ ! 754: time(&curtime); ! 755: tp = localtime(&curtime); ! 756: if (dateprint) ! 757: stringprt("%.11s", ctime(&curtime)); ! 758: stringprt("%d:%02d", tp->tm_hour > 12 ? tp->tm_hour - 12 : ! 759: (tp->tm_hour == 0 ? 12 : tp->tm_hour), tp->tm_min); ! 760: if (synch) /* sync with clock */ ! 761: delay = 60 - tp->tm_sec; ! 762: /* ! 763: * Beepable is used to insure that we get at most one set of beeps ! 764: * every half hour. ! 765: */ ! 766: if (beep) ! 767: if (beepable) { ! 768: if (tp->tm_min == 30) { ! 769: tputs(bell, 1, outc); ! 770: fflush(stdout); ! 771: beepable = 0; ! 772: } else if (tp->tm_min == 0) { ! 773: tputs(bell, 1, outc); ! 774: fflush(stdout); ! 775: sleep(2); ! 776: tputs(bell, 1, outc); ! 777: fflush(stdout); ! 778: beepable = 0; ! 779: } ! 780: } else ! 781: if (tp->tm_min != 0 && tp->tm_min != 30) ! 782: beepable = 1; ! 783: } ! 784: ! 785: /* ! 786: * whocheck -- check for file named .who and print it on the who line first ! 787: */ ! 788: whocheck() ! 789: { ! 790: int chss; ! 791: register char *p; ! 792: char buff[81]; ! 793: int whofile; ! 794: ! 795: if ((whofile = open(whofilename, 0)) < 0 && ! 796: (whofile = open(whofilename2, 0)) < 0) ! 797: return; ! 798: chss = read(whofile, buff, sizeof buff - 1); ! 799: close(whofile); ! 800: if (chss <= 0) ! 801: return; ! 802: buff[chss] = '\0'; ! 803: /* ! 804: * Remove all line feeds, and replace by spaces if they are within ! 805: * the message, else replace them by nulls. ! 806: */ ! 807: for (p = buff; *p;) ! 808: if (*p == '\n') ! 809: if (p[1]) ! 810: *p++ = ' '; ! 811: else ! 812: *p = '\0'; ! 813: else ! 814: p++; ! 815: stringcat(buff, p - buff); ! 816: stringspace(); ! 817: } ! 818: ! 819: /* ! 820: * ttyprint -- given the name of a tty, print in the string buffer its ! 821: * short name surrounded by parenthesis. ! 822: * ttyxx is printed as (xx) ! 823: * console is printed as (cty) ! 824: */ ! 825: ttyprint(name) ! 826: char *name; ! 827: { ! 828: char buff[11]; ! 829: ! 830: if (strncmp(name, "tty", 3) == 0) ! 831: stringprt("(%.*s)", LINESIZE - 3, name + 3); ! 832: else if (strcmp(name, "console") == 0) ! 833: stringcat("(cty)", -1); ! 834: else ! 835: stringprt("(%.*s)", LINESIZE, name); ! 836: } ! 837: ! 838: /* ! 839: * mail checking function ! 840: * returns 0 if no mail seen ! 841: */ ! 842: mailseen() ! 843: { ! 844: FILE *mfd; ! 845: register n; ! 846: register char *cp; ! 847: char lbuf[100], sendbuf[100], *bufend; ! 848: char seenspace; ! 849: int retval = 0; ! 850: ! 851: if (stat(username, &mstbuf) < 0) { ! 852: mailsize = 0; ! 853: return 0; ! 854: } ! 855: if (mstbuf.st_size <= mailsize || (mfd = fopen(username,"r")) == NULL) { ! 856: mailsize = mstbuf.st_size; ! 857: return 0; ! 858: } ! 859: fseek(mfd, mailsize, 0); ! 860: while ((n = readline(mfd, lbuf, sizeof lbuf)) >= 0 && ! 861: strncmp(lbuf, "From ", 5) != 0) ! 862: ; ! 863: if (n < 0) { ! 864: stringcat("Mail has just arrived", 0); ! 865: goto out; ! 866: } ! 867: retval = 1; ! 868: /* ! 869: * Found a From line, get second word, which is the sender, ! 870: * and print it. ! 871: */ ! 872: for (cp = lbuf + 5; *cp && *cp != ' '; cp++) /* skip to blank */ ! 873: ; ! 874: *cp = '\0'; /* terminate name */ ! 875: stringspace(); ! 876: stringprt("Mail from %s ", lbuf + 5); ! 877: /* ! 878: * Print subject, and skip over header. ! 879: */ ! 880: while ((n = readline(mfd, lbuf, sizeof lbuf)) > 0) ! 881: if (strncmp(lbuf, "Subject:", 8) == 0) ! 882: stringprt("on %s ", lbuf + 9); ! 883: if (!emacs) ! 884: stringcat(arrows, 2); ! 885: else ! 886: stringcat(": ", 2); ! 887: if (n < 0) /* already at eof */ ! 888: goto out; ! 889: /* ! 890: * Print as much of the letter as we can. ! 891: */ ! 892: cp = sendbuf; ! 893: if ((n = columns - chars) > sizeof sendbuf - 1) ! 894: n = sizeof sendbuf - 1; ! 895: bufend = cp + n; ! 896: seenspace = 0; ! 897: while ((n = readline(mfd, lbuf, sizeof lbuf)) >= 0) { ! 898: register char *rp; ! 899: ! 900: if (strncmp(lbuf, "From ", 5) == 0) ! 901: break; ! 902: if (cp >= bufend) ! 903: continue; ! 904: if (!seenspace) { ! 905: *cp++ = ' '; /* space before lines */ ! 906: seenspace = 1; ! 907: } ! 908: rp = lbuf; ! 909: while (*rp && cp < bufend) ! 910: if (isspace(*rp)) { ! 911: if (!seenspace) { ! 912: *cp++ = ' '; ! 913: seenspace = 1; ! 914: } ! 915: rp++; ! 916: } else { ! 917: *cp++ = *rp++; ! 918: seenspace = 0; ! 919: } ! 920: } ! 921: *cp = 0; ! 922: stringcat(sendbuf, -1); ! 923: /* ! 924: * Want to update write time so a star will ! 925: * appear after the number of users until the ! 926: * user reads his mail. ! 927: */ ! 928: out: ! 929: mailsize = linebeg; ! 930: fclose(mfd); ! 931: touch(username); ! 932: return retval; ! 933: } ! 934: ! 935: /* ! 936: * readline -- read a line from fp and store it in buf. ! 937: * return the number of characters read. ! 938: */ ! 939: readline(fp, buf, n) ! 940: register FILE *fp; ! 941: char *buf; ! 942: register n; ! 943: { ! 944: register c; ! 945: register char *cp = buf; ! 946: ! 947: linebeg = ftell(fp); /* remember loc where line begins */ ! 948: cp = buf; ! 949: while (--n > 0 && (c = getc(fp)) != EOF && c != '\n') ! 950: *cp++ = c; ! 951: *cp = 0; ! 952: if (c == EOF && cp - buf == 0) ! 953: return -1; ! 954: return cp - buf; ! 955: } ! 956: ! 957: ! 958: /* ! 959: * string hacking functions ! 960: */ ! 961: ! 962: stringinit() ! 963: { ! 964: sp = strarr; ! 965: chars = 0; ! 966: } ! 967: ! 968: /*VARARGS1*/ ! 969: stringprt(format, a, b, c) ! 970: char *format; ! 971: { ! 972: char tempbuf[150]; ! 973: ! 974: stringcat(sprintf(tempbuf, format, a, b, c), -1); ! 975: } ! 976: ! 977: stringdump() ! 978: { ! 979: char bigbuf[sizeof strarr + 200]; ! 980: register char *bp = bigbuf; ! 981: register int i; ! 982: ! 983: if (!emacs) { ! 984: if (sawmail) ! 985: bp = strcpy1(bp, bell); ! 986: if (eslok) ! 987: bp = strcpy1(bp, tparm(to_status_line, ! 988: leftline ? 0 : columns - chars)); ! 989: else { ! 990: bp = strcpy1(bp, to_status_line); ! 991: if (!shortline && !leftline) ! 992: for (i = columns - chars; --i >= 0;) ! 993: *bp++ = ' '; ! 994: } ! 995: if (reverse && revtime != 0) ! 996: bp = strcpy1(bp, rev_out); ! 997: } ! 998: *sp = 0; ! 999: bp = strcpy1(bp, strarr); ! 1000: if (!emacs) { ! 1001: if (reverse) ! 1002: bp = strcpy1(bp, rev_end); ! 1003: bp = strcpy1(bp, from_status_line); ! 1004: if (sawmail) ! 1005: bp = strcpy1(strcpy1(bp, bell), bell); ! 1006: *bp = 0; ! 1007: tputs(bigbuf, 1, outc); ! 1008: if (mustclear) { ! 1009: mustclear = 0; ! 1010: tputs(clr_eol, 1, outc); ! 1011: } ! 1012: if (dbug) ! 1013: putchar('\n'); ! 1014: fflush(stdout); ! 1015: } else ! 1016: write(2, bigbuf, bp - bigbuf); ! 1017: } ! 1018: ! 1019: stringspace() ! 1020: { ! 1021: if (reverse && revtime != 0) { ! 1022: #ifdef TERMINFO ! 1023: stringcat(rev_end, ! 1024: magic_cookie_glitch <= 0 ? 0 : magic_cookie_glitch); ! 1025: stringcat(" ", 1); ! 1026: stringcat(rev_out, ! 1027: magic_cookie_glitch <= 0 ? 0 : magic_cookie_glitch); ! 1028: #else ! 1029: stringcat(rev_end, 0); ! 1030: stringcat(" ", 1); ! 1031: stringcat(rev_out, 0); ! 1032: #endif TERMINFO ! 1033: } else ! 1034: stringcat(" ", 1); ! 1035: } ! 1036: ! 1037: /* ! 1038: * stringcat :: concatenate the characters in string str to the list we are ! 1039: * building to send out. ! 1040: * str - the string to print. may contain funny (terminal control) chars. ! 1041: * n - the number of printable characters in the string ! 1042: * or if -1 then str is all printable so we can truncate it, ! 1043: * otherwise don't print only half a string. ! 1044: */ ! 1045: stringcat(str, n) ! 1046: register char *str; ! 1047: register n; ! 1048: { ! 1049: register char *p = sp; ! 1050: ! 1051: if (n < 0) { /* truncate */ ! 1052: n = columns - chars; ! 1053: while ((*p++ = *str++) && --n >= 0) ! 1054: ; ! 1055: p--; ! 1056: chars += p - sp; ! 1057: sp = p; ! 1058: } else if (chars + n <= columns) { /* don't truncate */ ! 1059: while (*p++ = *str++) ! 1060: ; ! 1061: chars += n; ! 1062: sp = p - 1; ! 1063: } ! 1064: } ! 1065: ! 1066: /* ! 1067: * touch :: update the modify time of a file. ! 1068: */ ! 1069: touch(name) ! 1070: char *name; /* name of file */ ! 1071: { ! 1072: register fd; ! 1073: char buf; ! 1074: ! 1075: if ((fd = open(name, 2)) >= 0) { ! 1076: read(fd, &buf, 1); /* get first byte */ ! 1077: lseek(fd, 0L, 0); /* go to beginning */ ! 1078: write(fd, &buf, 1); /* and rewrite first byte */ ! 1079: close(fd); ! 1080: } ! 1081: } ! 1082: ! 1083: ! 1084: /* ! 1085: * clearbotl :: clear bottom line. ! 1086: * called when process quits or is killed. ! 1087: * it clears the bottom line of the terminal. ! 1088: */ ! 1089: clearbotl() ! 1090: { ! 1091: register int fd; ! 1092: int exit(); ! 1093: ! 1094: signal(SIGALRM, exit); ! 1095: alarm(30); /* if can't open in 30 secs, just die */ ! 1096: if (!emacs && (fd = open(ourtty, 1)) >= 0) { ! 1097: write(fd, dis_status_line, strlen(dis_status_line)); ! 1098: close(fd); ! 1099: } ! 1100: #ifdef PROF ! 1101: if (chdir("/usr/src/ucb/sysline") < 0) ! 1102: (void) chdir("/tmp"); ! 1103: #endif ! 1104: exit(0); ! 1105: } ! 1106: ! 1107: #ifdef TERMINFO ! 1108: initterm() ! 1109: { ! 1110: static char standbuf[40]; ! 1111: ! 1112: setupterm(0, 1, 0); ! 1113: if (!window && !has_status_line) { ! 1114: /* not an appropriate terminal */ ! 1115: if (!quiet) ! 1116: fprintf(stderr, "sysline: no status capability for %s\n", ! 1117: getenv("TERM")); ! 1118: exit(1); ! 1119: } ! 1120: if (window || status_line_esc_ok) { ! 1121: if (set_attributes) { ! 1122: /* reverse video mode */ ! 1123: strcpy(standbuf, ! 1124: tparm(set_attributes,0,0,1,0,0,0,0,0,0)); ! 1125: rev_out = standbuf; ! 1126: rev_end = exit_attribute_mode; ! 1127: } else if (enter_standout_mode && exit_standout_mode) { ! 1128: rev_out = enter_standout_mode; ! 1129: rev_end = exit_standout_mode; ! 1130: } else ! 1131: rev_out = rev_end = ""; ! 1132: } else ! 1133: rev_out = rev_end = ""; ! 1134: columns--; /* avoid cursor wraparound */ ! 1135: } ! 1136: ! 1137: #else /* TERMCAP */ ! 1138: ! 1139: initterm() ! 1140: { ! 1141: char *term, *cp; ! 1142: static char tbuf[1024]; ! 1143: char is2[40]; ! 1144: extern char *UP; ! 1145: ! 1146: if ((term = getenv("TERM")) == NULL) { ! 1147: if (!quiet) ! 1148: fprintf(stderr, ! 1149: "sysline: No TERM variable in enviroment\n"); ! 1150: exit(1); ! 1151: } ! 1152: if (tgetent(tbuf, term) <= 0) { ! 1153: if (!quiet) ! 1154: fprintf(stderr, ! 1155: "sysline: Unknown terminal type: %s\n", term); ! 1156: exit(1); ! 1157: } ! 1158: if (!window && tgetflag("hs") <= 0) { ! 1159: if (!strncmp(term, "h19", 3)) { ! 1160: /* for upward compatability with h19sys */ ! 1161: strcpy(to_status_line, ! 1162: "\033j\033x5\033x1\033Y8%+ \033o"); ! 1163: strcpy(from_status_line, "\033k\033y5"); ! 1164: strcpy(dis_status_line, "\033y1"); ! 1165: strcpy(rev_out, "\033p"); ! 1166: strcpy(rev_end, "\033q"); ! 1167: arrows = "\033Fhh\033G"; ! 1168: columns = 80; ! 1169: UP = "\b"; ! 1170: return; ! 1171: } ! 1172: if (!quiet) ! 1173: fprintf(stderr, ! 1174: "sysline: No status capability for %s\n", term); ! 1175: exit(1); ! 1176: } ! 1177: cp = is2; ! 1178: if (tgetstr("i2", &cp) != NULL) { ! 1179: /* someday tset will do this */ ! 1180: tputs(is2, 1, erroutc); ! 1181: fflush(stdout); ! 1182: } ! 1183: ! 1184: /* the "-1" below is to avoid cursor wraparound problems */ ! 1185: columns = tgetnum("co") - 1; ! 1186: if (window) { ! 1187: strcpy(to_status_line, "\r"); ! 1188: cp = dis_status_line; /* use the clear line sequence */ ! 1189: *cp++ = '\r'; ! 1190: tgetstr("ce", &cp); ! 1191: if (leftline) ! 1192: strcpy(from_status_line, dis_status_line + 1); ! 1193: else ! 1194: strcpy(from_status_line, ""); ! 1195: } else { ! 1196: cp = to_status_line; ! 1197: tgetstr("ts", &cp); ! 1198: cp = from_status_line; ! 1199: tgetstr("fs", &cp); ! 1200: cp = dis_status_line; ! 1201: tgetstr("ds", &cp); ! 1202: eslok = tgetflag("es"); ! 1203: } ! 1204: if (eslok || window) { ! 1205: cp = rev_out; ! 1206: tgetstr("so", &cp); ! 1207: cp = rev_end; ! 1208: tgetstr("se", &cp); ! 1209: cp = clr_eol; ! 1210: tgetstr("ce", &cp); ! 1211: } else ! 1212: reverse = 0; /* turn off reverse video */ ! 1213: UP = "\b"; ! 1214: if (!strncmp(term, "h19", 3)) ! 1215: arrows = "\033Fhh\033G"; /* "two tiny graphic arrows" */ ! 1216: else ! 1217: arrows = "->"; ! 1218: } ! 1219: #endif TERMINFO ! 1220: ! 1221: #ifdef pdp11 ! 1222: loadav(ap) ! 1223: double ap[]; ! 1224: { ! 1225: register int i; ! 1226: short s_avenrun[3]; ! 1227: ! 1228: lseek(kmem, (long)nl[NL_AVEN].n_value, 0); ! 1229: read(kmem, s_avenrun, sizeof(s_avenrun)); ! 1230: for (i=0; i < (sizeof(s_avenrun)/sizeof(s_avenrun[0])); i++) ! 1231: ap[i] = s_avenrun[i] / 256.0; ! 1232: } ! 1233: #endif ! 1234: ! 1235: #ifdef RWHO ! 1236: char * ! 1237: sysrup(hp) ! 1238: register struct remotehost *hp; ! 1239: { ! 1240: char filename[100]; ! 1241: struct whod wd; ! 1242: #define WHOD_HDR_SIZE (sizeof (wd) - sizeof (wd.wd_we)) ! 1243: static char buffer[50]; ! 1244: time_t now; ! 1245: ! 1246: /* ! 1247: * rh_file is initially 0. ! 1248: * This is ok since standard input is assumed to exist. ! 1249: */ ! 1250: if (hp->rh_file == 0) { ! 1251: /* ! 1252: * Try rwho hostname file, and if that fails try ucbhostname. ! 1253: */ ! 1254: (void) strcpy1(strcpy1(filename, RWHOLEADER), hp->rh_host); ! 1255: if ((hp->rh_file = open(filename, 0)) < 0) { ! 1256: (void) strcpy1(strcpy1(strcpy1(filename, RWHOLEADER), ! 1257: NETPREFIX), hp->rh_host); ! 1258: hp->rh_file = open(filename, 0); ! 1259: } ! 1260: } ! 1261: if (hp->rh_file < 0) ! 1262: return sprintf(buffer, "%s?", hp->rh_host); ! 1263: (void) lseek(hp->rh_file, (off_t)0, 0); ! 1264: if (read(hp->rh_file, (char *)&wd, WHOD_HDR_SIZE) != WHOD_HDR_SIZE) ! 1265: return sprintf(buffer, "%s ?", hp->rh_host); ! 1266: (void) time(&now); ! 1267: if (now - wd.wd_recvtime > DOWN_THRESHOLD) { ! 1268: long interval; ! 1269: long days, hours, minutes; ! 1270: ! 1271: interval = now - wd.wd_recvtime; ! 1272: minutes = (interval + 59) / 60; /* round to minutes */ ! 1273: hours = minutes / 60; /* extract hours from minutes */ ! 1274: minutes %= 60; /* remove hours from minutes */ ! 1275: days = hours / 24; /* extract days from hours */ ! 1276: hours %= 24; /* remove days from hours */ ! 1277: if (days > 7 || days < 0) ! 1278: (void) sprintf(buffer, "%s down", hp->rh_host); ! 1279: else if (days > 0) ! 1280: (void) sprintf(buffer, "%s %d+%d:%02d", ! 1281: hp->rh_host, days, hours, minutes); ! 1282: else ! 1283: (void) sprintf(buffer, "%s %d:%02d", ! 1284: hp->rh_host, hours, minutes); ! 1285: } else ! 1286: (void) sprintf(buffer, "%s %.1f", ! 1287: hp->rh_host, wd.wd_loadav[0]/100.0); ! 1288: return buffer; ! 1289: } ! 1290: #endif RWHO ! 1291: ! 1292: getwinsize() ! 1293: { ! 1294: #ifdef TIOCGWINSZ ! 1295: struct winsize winsize; ! 1296: ! 1297: /* the "-1" below is to avoid cursor wraparound problems */ ! 1298: if (ioctl(2, TIOCGWINSZ, (char *)&winsize) >= 0 && winsize.ws_col != 0) ! 1299: columns = winsize.ws_col - 1; ! 1300: #endif ! 1301: } ! 1302: ! 1303: #ifdef SIGWINCH ! 1304: sigwinch() ! 1305: { ! 1306: winchanged++; ! 1307: } ! 1308: #endif ! 1309: ! 1310: char * ! 1311: strcpy1(p, q) ! 1312: register char *p, *q; ! 1313: { ! 1314: ! 1315: while (*p++ = *q++) ! 1316: ; ! 1317: return p - 1; ! 1318: } ! 1319: ! 1320: outc(c) ! 1321: char c; ! 1322: { ! 1323: if (dbug) ! 1324: printf("%s", unctrl(c)); ! 1325: else ! 1326: putchar(c); ! 1327: } ! 1328: ! 1329: erroutc(c) ! 1330: char c; ! 1331: { ! 1332: if (dbug) ! 1333: fprintf(stderr, "%s", unctrl(c)); ! 1334: else ! 1335: putc(c, stderr); ! 1336: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.