home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / misc / volume1 / 8708 / 1 next >
Encoding:
Internet Message Format  |  1990-07-13  |  38.6 KB

  1. From: allbery@ncoast.UUCP (Brandon S. Allbery)
  2. Newsgroups: comp.sources.misc
  3. Subject: Load average, "w", and status line for USG systems
  4. Message-ID: <3733@ncoast.UUCP>
  5. Date: 2 Aug 87 19:12:50 GMT
  6. Sender: allbery@ncoast.UUCP
  7. Organization: Cleveland Public Access UN*X, Cleveland, Oh
  8. Lines: 1447
  9. Approved: allbery@ncoast.UUCP
  10. X-Archive: comp.sources.misc/8708/1
  11.  
  12. Herein are some programs I use under System V.  They are:
  13.  
  14. avenrun -- a daemon which calculates an approximate load average from the
  15.     "runque" and "runocc" parameters in the kernel "sysinfo" structure.
  16.     Thanks to Phil Budne for the original, which forged "rwho" packets
  17.     for USG systems on BSD networks; this one puts its load average into
  18.     an array of 3 (double)'s in a shm segment identified by ftok("/unix",
  19.     'a').
  20.  
  21. w -- The BSD "w" program, large as life.  It works as expected, except that
  22.     the "JCPU" is a kludge; USG doesn't keep per-session CPU time.
  23.  
  24. csl -- A status line program.  It displays things in "panels" which "rotate"
  25.     every 5 seconds.  The information displayed is:
  26.     
  27.         - sender and subject of mail in your mailbox,
  28.           one message per panel
  29.         - current program (if possible), login name,
  30.           # of messages in mailbox, current date/time
  31.         - full name and terminal (useful!), # non-daemons
  32.           running
  33.         - list of system users, similar to "who -q"
  34.         - lines from $HOME/.messages, one per panel
  35.  
  36. I've been using these for a few months without problems.  Enjoy!
  37. ++Brandon
  38.  
  39. #--------------------------------CUT HERE-------------------------------------
  40. #! /bin/sh
  41. #
  42. # This is a shell archive.  Save this into a file, edit it
  43. # and delete all lines above this comment.  Then give this
  44. # file to sh by executing the command "sh file".  The files
  45. # will be extracted into the current directory owned by
  46. # you with default permissions.
  47. #
  48. # The files contained herein are:
  49. #
  50. # -rw-r--r--   1 allbery  System      1579 May  7 22:09 README.w
  51. # -rw-r--r--   1 allbery  System      8210 May  7 21:52 avenrun.c
  52. # -rw-r--r--   1 allbery  System      8313 May  7 21:52 csl.c
  53. # -rw-r--r--   1 allbery  System      7909 May  7 21:28 w.c
  54. # -rw-r--r--   1 allbery  System      1023 May  7 22:51 avenrun.1m
  55. # -rw-r--r--   1 allbery  System      3217 May  7 22:39 csl.1l
  56. # -rw-r--r--   1 allbery  System      3056 May  7 23:12 w.1l
  57. #
  58. echo 'x - README.w'
  59. if test -f README.w; then echo 'shar: not overwriting README.w'; else
  60. sed 's/^X//' << '________This_Is_The_END________' > README.w
  61. XThe following are some programs which give you some familiar BSD utilities
  62. Xin a System V environment.  The programs are:
  63. X
  64. X    w    - Yes, "w", as big as life!  Requires...
  65. X    avenrun    - A program to be invoked in /etc/rc which computes
  66. X          a "load average" from information in the "sysinfo"
  67. X          structure of the kernel.  Based on a program by
  68. X          Phil Budne which forges "rwhod" packets for mixed
  69. X          networks; #define RWHOD for the original program.
  70. X    csl    - I have no idea what the BSD "sysline" does, but this
  71. X          is my idea of a status line.  The name stands for
  72. X          "cyclic status line"; it doesn't even attempt to
  73. X          fit everything into one line, instead it cycles
  74. X          through a set of "panels".  See the man page.
  75. X          This also wants "avenrun" to be running.
  76. X
  77. XNote that "w" (and ONLY "w") can be compiled for System III or Xenix 3.0;
  78. Xthis is in fact the default, use -DSYS5 to get the full version.
  79. X
  80. XNo Makefile; the compile commands are trivial:
  81. X
  82. X    cc -O -o w w.c -DSYS5        # omit the -DSYS5 for System III
  83. X    cc -O -o avenrun avenrun.c    # add -DRWHOD for rwhod forgery
  84. X    cc -O -o csl csl.c
  85. X
  86. X"w" requires read permission on /dev/kmem, /dev/mem, and /dev/swap.  "avenrun"
  87. Xrequires read permission on /dev/kmem (to read the sysinfo structure).  "csl"
  88. Xcan run as a normal user program.  On tdi2 we keep /dev/*mem and /dev/swap
  89. X-r--r----- root/sys and have "avenrun" and "w" setgid sys.
  90. X
  91. XIf someone wants to tell me what "sysline" under BSD does, I'd be interested
  92. Xin writing a real one.  But "csl" is everything in one small package, so I
  93. Xwill probably continue to use it.
  94. X
  95. XEnjoy!
  96. X
  97. X++Brando
  98. ________This_Is_The_END________
  99. if test `wc -l < README.w` -ne 37; then
  100.     echo 'shar: README.w was damaged during transit (should have been 37 bytes)'
  101. fi
  102. fi        ; : end of overwriting check
  103. echo 'x - avenrun.c'
  104. if test -f avenrun.c; then echo 'shar: not overwriting avenrun.c'; else
  105. sed 's/^X//' << '________This_Is_The_END________' > avenrun.c
  106. X/*
  107. X *    ldavg.c -- compute load averages for System V
  108. X *    Phil Budne @ Boston U / DSG
  109. X *
  110. X *    Forges BSD 4.2 rwhod packets containing system load averages
  111. X *    (#ifdef RWHOD for this, else a shm segment is used, ftok("/unix", 'a'))
  112. X */
  113. X
  114. X# include <sys/types.h>            /* system types */
  115. X# include <sys/sysinfo.h>        /* sysinfo structure */
  116. X# include <sys/utsname.h>        /* for uname(2) */
  117. X# include <sys/stat.h>            /* for stat(2) */
  118. X# include <sys/param.h>            /* for HZ */
  119. X# include <stdio.h>
  120. X# include <nlist.h>
  121. X# include <time.h>
  122. X# include <math.h>
  123. X# include <utmp.h>
  124. X# include <fcntl.h>
  125. X#ifdef RWHOD
  126. X# include "rwhod.h"            /* (from BSD) */
  127. X#else  SHM
  128. X# include <sys/ipc.h>
  129. X# include <sys/shm.h>
  130. X#endif RWHOD
  131. X
  132. X/* # define DEBUG /**/
  133. X#ifdef RWHOD
  134. X# define UDP 1
  135. X# define DSK 1
  136. X# define PMUL 100
  137. X
  138. X# if UDP
  139. X# include "netdb.h"
  140. Xunsigned short port = 513;
  141. Xunsigned long ipaddr;
  142. X# endif
  143. X#endif RWHOD
  144. X
  145. Xextern struct utmp *getutent();
  146. X
  147. X# define SYSTEM "/unix"
  148. X# define KMEM "/dev/kmem"
  149. X
  150. Xstruct nlist nl[] = {
  151. X# define NL_SYSINFO 0
  152. X        { "_sysinfo" },            /* 0 */
  153. X# define NL_LBOLT 1
  154. X    { "_lbolt" },            /* 1 */
  155. X        { 0 }
  156. X};
  157. X
  158. X#ifdef RWHOD
  159. Xstruct whod proto;
  160. Xstruct utsname utsn;
  161. Xchar whopacket[100];
  162. X#else  SHM
  163. Xkey_t aven_key;
  164. Xint aven_shm;
  165. Xdouble *aven_seg;
  166. X#endif RWHOD
  167. Xint fd, memfd;
  168. X
  169. Xchar *system = SYSTEM;
  170. Xchar *kmem = KMEM;
  171. Xchar *argv0;
  172. X
  173. Xmain(argc, argv)
  174. Xint  argc;
  175. Xchar *argv[];
  176. X{
  177. X    switch (fork()) {
  178. X    case -1:
  179. X        perror("fork");
  180. X        exit(1);
  181. X    case 0:
  182. X        break;
  183. X    default:
  184. X        exit(0);
  185. X    }
  186. X    argv0 = argv[0];
  187. X#ifdef RWHOD
  188. X    uname(&utsn);            /* get system names */
  189. X#endif RWHOD
  190. X    setpgrp();            /* create own pgrp */
  191. X    init_nlist();            /* get name values, open kmem */
  192. X    init_packet();            /* initialize packet prototype */
  193. X    doit();                /* never returns */
  194. X} /* main */
  195. X
  196. Xinit_nlist() {
  197. X    nlist(system, nl);        /* get system values */
  198. X
  199. X        if(nl[NL_SYSINFO].n_value == 0) {
  200. X                fprintf(stderr, "%s: can't find sysinf structure\n", argv0);
  201. X                exit(1);
  202. X        } /* no value */
  203. X
  204. X    if ((memfd = open(kmem, O_RDONLY)) < 0) {
  205. X        fprintf(stderr, "%s: no mem\n", argv0);
  206. X        exit(1);
  207. X    } /* could not open kmem */
  208. X
  209. X} /* init_nlist */
  210. X
  211. X# define PERIOD 5            /* sample period (in seconds) */
  212. X# define INTERVAL1 60            /* average interval 1 (in seconds) */
  213. X# define INTERVAL2 (5*60)        /* average interval 2 (in seconds) */
  214. X# define INTERVAL3 (15*60)        /* average interval 3 (in seconds) */
  215. X# define PACKINTERVAL 30        /* interval for make_packet */
  216. X
  217. Xdoit() {
  218. X    struct sysinfo sinf;
  219. X    int packt = 0;
  220. X    long occ, que, nocc, nque, n, c;
  221. X    double avg1, avg2, avg3, new;
  222. X    double exp1, exp2, exp3;
  223. X
  224. X    exp1 = exp( - ((double) PERIOD) / INTERVAL1 );
  225. X    exp2 = exp( - ((double) PERIOD) / INTERVAL2 );
  226. X    exp3 = exp( - ((double) PERIOD) / INTERVAL3 );
  227. X
  228. X    getsysinf(&sinf);        /* prime the pump */
  229. X    occ = sinf.runocc;        /* number of samples */
  230. X    que = sinf.runque;        /* run queue summation */
  231. X
  232. X    avg1 = avg2 = avg3 = ((double) que) / occ;
  233. X
  234. X    for( ; ; ) {
  235. X        if( --packt < 0 ) {
  236. X#ifdef RWHOD
  237. X            make_packet((int) (avg1 * PMUL),
  238. X                    (int) (avg2 * PMUL),
  239. X                    (int) (avg3 * PMUL));
  240. X#else  SHM
  241. X            make_packet(avg1, avg2, avg3);
  242. X#endif RWHOD
  243. X            packt = PACKINTERVAL / PERIOD;
  244. X        } /* packet time */
  245. X
  246. X/*        printf("runque: %ld  runocc: %ld\n", que, occ ); /**/
  247. X
  248. X        sleep(PERIOD);
  249. X        getsysinf(&sinf);    /* get new info */
  250. X        nocc = sinf.runocc;
  251. X        nque = sinf.runque;
  252. X
  253. X        n = nocc - occ;        /* get number of times updated */
  254. X        if( n <= 0 ) continue;
  255. X        c = nque - que - n;    /* get number of runners w/o us */
  256. X        if( c < 0 ) c = 0;    /* mumble! */
  257. X
  258. X        new = ((double) c ) / n; /* new instantaneous avg */
  259. X
  260. X        /************************************************/
  261. X        /*   The following formula is used to achieve   */
  262. X        /*   exponential decay of old measurements:    */
  263. X        /*    avgN = avgN * expN  +  new * (1 - expN)    */
  264. X        /*                        */
  265. X        /*   However, the factorized forms below    */
  266. X        /*   require fewer floating point operations.    */
  267. X        /************************************************/
  268. X
  269. X        avg1 = ((avg1 - new) * exp1) + new;
  270. X        avg2 = ((avg2 - new) * exp2) + new;
  271. X        avg3 = ((avg3 - new) * exp3) + new;
  272. X
  273. X        occ = nocc;
  274. X        que = nque;
  275. X
  276. X    } /* for ever */
  277. X} /* doit */
  278. X
  279. Xgetsysinf(s)
  280. Xstruct sysinfo *s;
  281. X{
  282. X    l_lseek(memfd, (long)nl[NL_SYSINFO].n_value, 0);
  283. X    r_read(memfd, (char *)s, sizeof(struct sysinfo));
  284. X}
  285. X
  286. X/* lseek with error checking */
  287. Xl_lseek(fd, offset, whence)
  288. Xint fd, whence;
  289. Xlong    offset;
  290. X{
  291. X    if (lseek(fd, offset, whence) == -1) {
  292. X        fprintf(stderr, "%s: error on lseek\n", argv0);
  293. X        exit(1);
  294. X    }
  295. X}
  296. X
  297. X/* read with error checking */
  298. Xr_read (fd, buf, nbytes)
  299. Xint    fd, nbytes;
  300. Xchar    *buf;
  301. X{
  302. X    if (read(fd, buf, nbytes) != nbytes) {
  303. X        fprintf(stderr, "%s: error on read\n", argv0);
  304. X        exit(1);
  305. X    }
  306. X}
  307. X
  308. Xinit_packet() {
  309. X#ifdef RWHOD
  310. X    time_t boothz;
  311. X# if UDP
  312. X    struct hostent *he;
  313. X
  314. X    he = gethostbyname( "localnet" );
  315. X    if( he == NULL || he->h_addr == 0 ) {
  316. X        fprintf(stderr, "no address: localnet\n");
  317. X        exit( 1 );
  318. X    }
  319. X    ipaddr = he->h_addr;
  320. X# endif
  321. X# if DSK
  322. X    sprintf(whopacket, "/usr/spool/rwho/whod.%s", utsn.nodename);
  323. X# endif
  324. X    memset(&proto, '\0', sizeof proto);    /* clear proto packet */
  325. X
  326. X    strncat(proto.wd_hostname, utsn.nodename, 9); /* at most 9, add null */
  327. X    proto.wd_vers = WHODVERSION;
  328. X    proto.wd_type = WHODTYPE_STATUS;
  329. X
  330. X    l_lseek(memfd, (long)nl[NL_LBOLT].n_value, 0);
  331. X    r_read(memfd, (char *)&boothz, sizeof( boothz ) );
  332. X    proto.wd_boottime = time(0) - (boothz / HZ);
  333. X#else  SHM
  334. X    if ((aven_key = ftok(SYSTEM, 'a')) == (key_t) -1) {
  335. X        perror(SYSTEM);
  336. X        exit(1);
  337. X    }
  338. X    if ((aven_shm = shmget(aven_key, 3 * sizeof (double), IPC_CREAT|IPC_EXCL|0644)) < 0) {
  339. X        perror("shmget");
  340. X        exit(1);
  341. X    }
  342. X    if ((int) (aven_seg = (double *) shmat(aven_shm, (char *) 0, 0)) == -1) {
  343. X        perror("shmat");
  344. X        if (shmdt((char *) aven_seg) == -1)
  345. X            perror("shmdt");
  346. X        if (shmctl(aven_shm, IPC_RMID, (struct shmid_ds *) 0) < 0)
  347. X            perror("shmctl(IPC_RMID)");
  348. X        exit(1);
  349. X    }
  350. X#endif RWHOD
  351. X    
  352. X} /* init_packet */
  353. X
  354. Xmake_packet(iavg1, iavg2, iavg3)
  355. X#ifdef RWHOD
  356. Xlong iavg1, iavg2, iavg3;
  357. X#else  SHM
  358. Xdouble iavg1, iavg2, iavg3;
  359. X#endif RWHOD
  360. X{
  361. X#ifdef RWHOD
  362. X    static struct whod packet;    /* local packet copy */
  363. X    register struct whoent *wep;    /* pointer to packet whoent */
  364. X    register struct utmp *utp;    /* return from getutent */
  365. X    int whof, cc;            /* output file, char count */
  366. X
  367. X    packet = proto;            /* copy proto packet */
  368. X    time(&packet.wd_sendtime);
  369. X    time(&packet.wd_recvtime);    /* forge this !! */
  370. X    packet.wd_loadav[0] = iavg1;
  371. X    packet.wd_loadav[1] = iavg2;
  372. X    packet.wd_loadav[2] = iavg3;
  373. X
  374. X    setutent();            /* open utmp file */
  375. X    wep = &packet.wd_we[0];        /* get pointer to first user in pkt */
  376. X
  377. X    while( (utp = getutent()) != NULL ) {
  378. X        if( (utp->ut_type == USER_PROCESS) && utp->ut_user[0]) {
  379. X        strncpy(wep->we_utmp.out_line, utp->ut_id, 4);
  380. X        wep->we_utmp.out_line[4] = '\0';
  381. X
  382. X        strncpy(wep->we_utmp.out_name, utp->ut_user, 8);
  383. X
  384. X        wep->we_utmp.out_time = utp->ut_time;
  385. X
  386. X        wep->we_idle = idletime(utp);
  387. X        wep++;            /* bump packet pointer */
  388. X        } /* user process */
  389. X    } /* while */
  390. X    endutent();
  391. X
  392. X# if DSK
  393. X    whof = creat(whopacket, 0644);    /* open packt file */
  394. X    if( whof >= 0 ) {
  395. X        cc = (char *)wep - (char *)&packet;
  396. X        if( write(whof, (char *)&packet, cc) != cc )
  397. X            perror("write failed");
  398. X        close(whof);
  399. X    } /* file opened */
  400. X    else perror(whopacket);
  401. X# endif
  402. X# if UDP
  403. X    cc = (char *)wep - (char *)&packet;
  404. X    udpsend( (char *)&packet, cc, ipaddr, port, port, 1);
  405. X# endif
  406. X# ifdef DEBUG
  407. X    fprintf(stderr, "wrote packet (%d)\n", cc);
  408. X    fflush(stderr);
  409. X# endif
  410. X#else  SHM
  411. X    aven_seg[0] = iavg1;
  412. X    aven_seg[1] = iavg2;
  413. X    aven_seg[2] = iavg3;
  414. X#endif RWHOD
  415. X} /* make_packet */
  416. X
  417. X#ifdef RWHOD
  418. Xidletime(up)
  419. Xstruct utmp *up;
  420. X{
  421. X    register int i;
  422. X    register char *cp, *dp;
  423. X    char ttyname[10];
  424. X    struct stat buf;
  425. X    time_t now;
  426. X
  427. X    cp = "/dev/";
  428. X    dp = ttyname;
  429. X    
  430. X    while( *cp != '\0' )        /* copy "/dev/" */
  431. X        *dp++ = *cp++;
  432. X
  433. X    cp = up->ut_line;            /* get line name */
  434. X    if( *cp == 's' )            /* starts with an 's'? (sxtnnn) */
  435. X        *dp++ = 'v';            /* insert a 'v' */
  436. X
  437. X    for( i = 0; i < 8; i++ )        /* copy line name */
  438. X        if( (*dp++ = *cp++) == '\0' ) break;    /* or until null */
  439. X
  440. X    if( stat(ttyname, &buf) != 0 )    /* get file status */
  441. X        return( 0 );
  442. X
  443. X    time(&now);                /* get current time */
  444. X    i = now - buf.st_atime;        /* get differnce from last acces */
  445. X    return( i );            /* return idle time */
  446. X} /* idletime */
  447. X#endif RWHOD
  448. ________This_Is_The_END________
  449. if test `wc -l < avenrun.c` -ne 342; then
  450.     echo 'shar: avenrun.c was damaged during transit (should have been 342 bytes)'
  451. fi
  452. fi        ; : end of overwriting check
  453. echo 'x - csl.c'
  454. if test -f csl.c; then echo 'shar: not overwriting csl.c'; else
  455. sed 's/^X//' << '________This_Is_The_END________' > csl.c
  456. X#include <curses.h>
  457. X#include <a.out.h>
  458. X#include <term.h>
  459. X#include <time.h>
  460. X#include <fcntl.h>
  461. X#include <varargs.h>
  462. X#include <pwd.h>
  463. X#include <signal.h>
  464. X#include <sys/types.h>
  465. X#include <sys/ipc.h>
  466. X#include <sys/shm.h>
  467. X#include <sys/param.h>
  468. X#include <sys/dir.h>
  469. X#include <sys/proc.h>
  470. X#include <sys/user.h>
  471. X#include <sys/var.h>
  472. X#include <sys/inode.h>
  473. X#include <sys/file.h>
  474. X#include <sys/stat.h>
  475. X#include <sys/sysmacros.h>
  476. X#include <utmp.h>
  477. X
  478. X#define DISPLAY        5    /* seconds between panels */
  479. X
  480. Xchar SObuf[BUFSIZ], lock[1024], messages[1024], fullname[64], logname[64];
  481. Xdouble *avenrun;
  482. Xint kmem, nproc, mem, swap, mail;
  483. Xdaddr_t swplo;
  484. X
  485. Xextern char *getenv(), *curcmd(), *ttyname(), *strrchr(), *itoa(), *fname(), *strchr();
  486. Xextern int cleanup();
  487. Xextern void setpwent();
  488. Xextern struct passwd *getpwnam();
  489. Xextern long time();
  490. Xextern void setutent();
  491. Xextern struct utmp *getutent();
  492. X
  493. Xstruct nlist k[] = {
  494. X    {"_proc"},
  495. X    {"_v"},
  496. X    {"_swplo"},    
  497. X    {0},
  498. X};
  499. X
  500. Xchar *weekday[] = {
  501. X    "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat",
  502. X};
  503. X
  504. Xmain() {
  505. X    int cnt, nmsg, avend_id, aprogs, panel;
  506. X    char *cp, *cmd;
  507. X    key_t avend_k;
  508. X    struct tm *now;
  509. X    long instant;
  510. X    char msg[1024], subj[1024], from[128], mailf[128];
  511. X    char *fp, *bp, *logtty;
  512. X    struct utmp *user;
  513. X    
  514. X    setupterm((char *) 0, fileno(stdout), (int *) 0);
  515. X    if (!has_status_line) {
  516. X        fprintf(stderr, "csl: terminal doesn't have a status line\n");
  517. X        exit(1);
  518. X    }
  519. X    switch (fork()) {
  520. X    case 0:
  521. X        break;
  522. X    case -1:
  523. X        perror("csl");
  524. X        exit(1);
  525. X    default:
  526. X        exit(0);
  527. X    }
  528. X    signal(SIGINT, SIG_IGN);
  529. X    signal(SIGQUIT, SIG_IGN);
  530. X    signal(SIGHUP, cleanup);
  531. X    freopen("/dev/null", "r", stdin);
  532. X    if (nlist("/unix", k) != 0) {
  533. X        perror("/unix");
  534. X        exit(2);
  535. X    }
  536. X    if ((kmem = open("/dev/kmem", O_RDONLY)) == -1) {
  537. X        perror("/dev/kmem");
  538. X        exit(1);
  539. X    }
  540. X    if ((mem = open("/dev/mem", O_RDONLY)) == -1) {
  541. X        perror("/dev/mem");
  542. X        exit(1);
  543. X    }
  544. X    if ((swap = open("/dev/swap", O_RDONLY)) == -1) {
  545. X        perror("/dev/swap");
  546. X        exit(1);
  547. X    }
  548. X    if ((cp = getenv("LOGNAME")) == (char *) 0)
  549. X        strcpy(logname, "daemon");
  550. X    else
  551. X        strcpy(logname, cp);
  552. X    fname(fullname);
  553. X    getnproc();
  554. X    if ((cp = getenv("HOME")) == (char *) 0) {
  555. X         strcpy(lock, "./.syslinelock");
  556. X        strcpy(messages, "./.messages");
  557. X    }
  558. X    else {
  559. X        sprintf(lock, "%s/.syslinelock", cp);
  560. X        sprintf(messages, "%s/.messages", cp);
  561. X    }
  562. X    setbuf(stdout, SObuf);
  563. X    if ((avend_k = ftok("/unix", 'a')) == (key_t) -1) {
  564. X        perror("/unix");
  565. X        exit(1);
  566. X    }
  567. X    if ((avend_id = shmget(avend_k, 3 * sizeof (double), 0644)) < 0)
  568. X        avenrun = (double *) 0;
  569. X    else if ((int) (avenrun = (double *) shmat(avend_id, (char *) 0, SHM_RDONLY)) == -1) {
  570. X        perror("shmat");
  571. X        exit(1);
  572. X    }
  573. X    lseek(kmem, k[3].n_value, 0);
  574. X    read(kmem, &swplo, sizeof swplo);
  575. X    logtty = strrchr(ttyname(fileno(stdout)), '/') + 1;
  576. X    sprintf(mailf, "/usr/mail/%s", logname);
  577. X    for (;;) {
  578. X        if (access(lock, 0) == 0) {
  579. X            putp(dis_status_line);
  580. X            fflush(stdout);
  581. X            while (access(lock, 0) == 0)
  582. X                sleep(30);
  583. X        }
  584. X        panel = 1;
  585. X        from[0] = '\0';
  586. X        subj[0] = '\0';
  587. X        if ((mail = open(mailf, O_RDONLY)) == -1)
  588. X            nmsg = 0;
  589. X        else {
  590. X            cnt = 0;
  591. X            while (rgets(mail, msg, sizeof msg) != -1) {
  592. X                if (strncmp(msg, "From ", 5) == 0) {
  593. X                    int mcnt;
  594. X
  595. X                    if (from[0] != '\0')
  596. X                        showpanel(panel++, "New mail from %s: %s", from, (subj[0]? subj: "[No subject]"));
  597. X                    subj[0] = '\0';
  598. X                    cnt++;
  599. X                    for (mcnt = 5; msg[mcnt] != '\0'; mcnt++)
  600. X                        if (msg[mcnt] == ' ')
  601. X                            break;
  602. X                    msg[mcnt++] = '\0';
  603. X                    if ((fp = strrchr(msg + 5, '!')) == (char *) 0)
  604. X                        strcpy(from, msg + 5);
  605. X                    else {
  606. X                        *fp = '\0';
  607. X                        if ((bp = strrchr(msg + 5, '!')) == (char *) 0)
  608. X                        bp = msg + 5;
  609. X                        *fp = '!';
  610. X                        strcpy(from, bp);
  611. X                    }
  612. X                    subj[0] = '\0';
  613. X                }
  614. X                else if (strncmp(msg, "Subject: ", 9) == 0)
  615. X                    strcpy(subj, msg + 9);
  616. X            }
  617. X            close(mail);
  618. X            if (from[0] != '\0')
  619. X                showpanel(panel++, "New mail from %s: %s", from, (subj[0]? subj: "[No subject]"));
  620. X            nmsg = cnt;
  621. X        }
  622. X        cmd = curcmd(&aprogs);
  623. X        time(&instant);
  624. X        now = localtime(&instant);
  625. X        if (avenrun != (double *) 0)
  626. X            showpanel(panel++, " %s // %s // %4.2f %4.2f %4.2f // %s msgs // %3s %02d/%02d %02d:%02d ", cmd, logname, avenrun[0], avenrun[1], avenrun[2], (nmsg == 0? "No": itoa(nmsg)), weekday[now->tm_wday], now->tm_mon + 1, now->tm_mday, now->tm_hour, now->tm_min);
  627. X        else
  628. X            showpanel(panel++, " %s // %s // %s msgs // %3s %02d/%02d %02d:%02d //", cmd, logname, (nmsg == 0? "No": itoa(nmsg)), weekday[now->tm_wday], now->tm_mon + 1, now->tm_mday, now->tm_hour, now->tm_min);
  629. X        showpanel(panel++, " ``%s'' on %s // %d active programs", fullname, logtty, aprogs);
  630. X        if ((mail = open(messages, O_RDONLY)) != -1) {
  631. X            while (rgets(mail, msg, sizeof msg) != -1)
  632. X                showpanel(panel++, "%s", msg);
  633. X            close(mail);
  634. X        }
  635. X        setutent();
  636. X        cnt = 0;
  637. X        msg[0] = '\0';
  638. X        while ((user = getutent()) != (struct utmp *) 0) {
  639. X            if (user->ut_type != USER_PROCESS)
  640. X                continue;
  641. X            sprintf(subj, "%.8s", user->ut_user);
  642. X            if (msg[0] != '\0')
  643. X                strcat(msg, ", ");
  644. X            strcat(msg, subj);
  645. X            cnt++;
  646. X        }
  647. X        showpanel(panel++, " %d users: %s", cnt, msg);
  648. X    }
  649. X}
  650. X
  651. Xcleanup() {
  652. X    if (avenrun != (double *) 0 && shmdt(avenrun) < 0) {
  653. X        perror("shmdt");
  654. X        exit(1);
  655. X    }
  656. X    reset_shell_mode();
  657. X    exit(0);
  658. X}
  659. X
  660. Xgetnproc() {
  661. X    struct var v;
  662. X
  663. X    lseek(kmem, k[1].n_value, 0);
  664. X    read(kmem, &v, sizeof v);
  665. X    nproc = v.v_proc;
  666. X}
  667. X
  668. Xchar *curcmd(progp)
  669. Xint *progp; {
  670. X    struct proc p;
  671. X    struct user cmd;
  672. X    struct file f;
  673. X    struct inode i;
  674. X    static struct stat idev;
  675. X    static int pgrp, mypid;
  676. X    static char cmdname[DIRSIZ + 1];
  677. X    long stime;
  678. X    int cnt;
  679. X    static int didit = 0;
  680. X    
  681. X    if (didit == 0) {
  682. X        stat("/dev/null", &idev);
  683. X        pgrp = getpgrp();
  684. X        mypid = getpid();
  685. X        didit = 1;
  686. X    }
  687. X    *progp = 0;
  688. X    stime = 0L;
  689. X    strcpy(cmdname, "???");
  690. X    lseek(kmem, k[0].n_value, 0);
  691. X    for (cnt = 0; cnt < nproc; cnt++) {
  692. X        read(kmem, &p, sizeof p);
  693. X        if (p.p_stat != SRUN && p.p_stat != SSLEEP)
  694. X            continue;
  695. X        if (p.p_pid == mypid)
  696. X            continue;
  697. X        if (p.p_pgrp != pgrp)
  698. X            continue;
  699. X        if (p.p_stat == SSLEEP && (long) p.p_wchan >= k[0].n_value && (long) p.p_wchan < k[0].n_value + nproc * sizeof p)
  700. X            continue;    /* sleeping on a child */
  701. X        (*progp)++;
  702. X        if (p.p_flag & SLOAD) {
  703. X            lseek(mem, (long) (NBPC * p.p_addr), 0);
  704. X            read(mem, &cmd, sizeof cmd);
  705. X        }
  706. X        else {
  707. X            lseek(swap, (swplo + p.p_swaddr + ctod(p.p_swsize) - ctod(USIZE)) << 9, 0);
  708. X            read(swap, &cmd, sizeof cmd);
  709. X        }
  710. X        if (cmd.u_ttyp == 0)
  711. X            continue;
  712. X/* AAUGH!  USG VAR csh'es close stdin!!!  That's absolutely insane!!!
  713. X *        if (p.p_pid != p.p_ppid && cmd.u_ofile[0] == 0)
  714. X *            continue;
  715. X */
  716. X        if (cmd.u_ofile[0] != 0) {
  717. X            lseek(kmem, cmd.u_ofile[0], 0);
  718. X            read(kmem, &f, sizeof f);
  719. X            lseek(kmem, f.f_inode, 0);
  720. X            read(kmem, &i, sizeof i);
  721. X            lseek(kmem, k[0].n_value + cnt * sizeof p, 0);
  722. X            if (i.i_dev == idev.st_dev && i.i_number == idev.st_ino && cmd.u_signal[SIGINT] == (long) SIG_IGN)
  723. X                continue;    /* ignore background processes */
  724. X        }
  725. X        if (cmd.u_start < stime)
  726. X            continue;
  727. X        stime = cmd.u_start;
  728. X        strncpy(cmdname, cmd.u_comm, DIRSIZ);
  729. X    }
  730. X    return cmdname;
  731. X}
  732. X
  733. Xrgets(fd, buf, maxlen)
  734. Xchar *buf;
  735. Xunsigned maxlen; {
  736. X    unsigned cnt;
  737. X    
  738. X    *buf = '\0';
  739. X    for (cnt = 0; cnt < maxlen - 1 && read(fd, buf, 1) > 0 && *buf != '\n'; cnt++, buf++)
  740. X        ;
  741. X    if (cnt == 0 && *buf != '\n')
  742. X        return -1;
  743. X    *buf = '\0';
  744. X    return cnt;
  745. X}
  746. X
  747. Xchar *itoa(n) {
  748. X    static char ibuf[20];
  749. X    
  750. X    sprintf(ibuf, "%d", n);
  751. X    return ibuf;
  752. X}
  753. X
  754. X/* Does the lint declaration below actually *do* anything? */
  755. X/*VARARGS PRINTFLIKE2*/
  756. Xshowpanel(va_alist)
  757. Xva_dcl {
  758. X    va_list args;
  759. X    int panel, cnt;
  760. X    static char buf[5120];
  761. X    register char *cp;
  762. X
  763. X    va_start(args);
  764. X    panel = va_arg(args, int);
  765. X    cp = va_arg(args, char *);
  766. X    sprintf(buf, "%2.2d>", panel);
  767. X    vsprintf(buf + 3, cp, args);
  768. X    putp(tparm(to_status_line, 0));
  769. X    for (cp = buf, cnt = 0; cnt < width_status_line && *cp != '\0'; cp++, cnt++)
  770. X        putchar(*cp);
  771. X    while (cnt++ < width_status_line)
  772. X        putchar(' ');
  773. X    putp(from_status_line);
  774. X    fflush(stdout);
  775. X    sleep(DISPLAY);
  776. X}
  777. X
  778. X/*
  779. X * If you use RJE fullnames :0000-Foo Z. Bar(0000):, change this.
  780. X * If you aren't running RJE, why bother with it?
  781. X */
  782. X
  783. Xchar *fname(buf)
  784. Xchar *buf; {
  785. X    static char fbuf[128];
  786. X    struct passwd *me;
  787. X    char *cp;
  788. X
  789. X    setpwent();
  790. X    me = getpwnam(logname);
  791. X    endpwent();
  792. X    if (me == (struct passwd *) 0)
  793. X        strcpy(fbuf, logname);
  794. X    else {
  795. X        strcpy(fbuf, me->pw_gecos);
  796. X        if ((cp = strchr(fbuf, ',')) != (char *) 0)
  797. X            *cp = '\0';
  798. X    }
  799. X    if (buf == (char *) 0)
  800. X        return fbuf;
  801. X    strcpy(buf, fbuf);
  802. X    return buf;
  803. X}
  804. ________This_Is_The_END________
  805. if test `wc -l < csl.c` -ne 348; then
  806.     echo 'shar: csl.c was damaged during transit (should have been 348 bytes)'
  807. fi
  808. fi        ; : end of overwriting check
  809. echo 'x - w.c'
  810. if test -f w.c; then echo 'shar: not overwriting w.c'; else
  811. sed 's/^X//' << '________This_Is_The_END________' > w.c
  812. X/*
  813. X * %W% %E% %U% ncoast!bsa %Z%
  814. X * %Z% Copyright (C) 1985 by Brandon S. Allbery, All Rights Reserved %Z%
  815. X */
  816. X
  817. X#ifndef lint
  818. Xstatic char _SccsId[] = "%W% %E% %U% ncoast!bsa %Z%";
  819. Xstatic char _CopyRt[] = "%Z% Copyright (C) 1985 by Brandon S. Allbery %Z%";
  820. X#endif  lint
  821. X
  822. X#include <stdio.h>
  823. X#include <time.h>
  824. X#include <signal.h>
  825. X#include <a.out.h>
  826. X#ifdef SYS5
  827. X#include <sys/types.h>
  828. X#endif
  829. X#include <sys/param.h>
  830. X#include <sys/var.h>
  831. X#include <sys/proc.h>
  832. X#include <sys/dir.h>
  833. X#include <sys/user.h>
  834. X#include <sys/stat.h>
  835. X#ifdef SYS5
  836. X#include <sys/ipc.h>
  837. X#include <sys/shm.h>
  838. X#include <sys/sysmacros.h>
  839. X#endif
  840. X#include <utmp.h>
  841. X
  842. X#define UTMP        "/etc/utmp"
  843. X#ifndef KERNEL
  844. X#define KERNEL        "/unix"
  845. X#endif
  846. X#define KMEM        "/dev/kmem"
  847. X#define PMEM        "/dev/mem"
  848. X#define SMEM        "/dev/swap"
  849. X
  850. X#define MIN        (60)
  851. X#define HOUR        (MIN * 60)
  852. X#define DAY        (HOUR * 24)
  853. X#define WEEK        (DAY * 7)
  854. X#define MONTH        (DAY * 30)
  855. X
  856. XFILE *kfd;
  857. XFILE *mfd;
  858. XFILE *sfd;
  859. XFILE *utmp;
  860. Xlong nproc;
  861. Xchar _SObuf[BUFSIZ];
  862. Xdaddr_t swplo;
  863. Xshort mypid;
  864. X
  865. Xstruct nlist kernel[] = {
  866. X    {"_v"},
  867. X    {"_proc"},
  868. X    {"_swplo"},
  869. X    {NULL},
  870. X};
  871. X
  872. Xchar *months[] = {
  873. X    "Jan", "Feb", "Mar", "Apr", "May", "Jun",
  874. X    "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
  875. X};
  876. X
  877. Xstruct tm *localtime();
  878. Xchar *vtime();
  879. Xchar *uptime();
  880. Xchar *itoa();
  881. X
  882. Xmain() {
  883. X    struct utmp user;
  884. X    short ucnt;
  885. X    long now;
  886. X    struct var vars;
  887. X#ifdef SYS5
  888. X    int shm_id;
  889. X    key_t shm_k;
  890. X    double *avenrun;
  891. X#endif
  892. X    
  893. X    setbuf(stdout, _SObuf);
  894. X    mypid = getpid();
  895. X    time(&now);
  896. X    if (nlist(KERNEL, kernel) == -1) {
  897. X        perror(KERNEL);
  898. X        exit(2);
  899. X    }
  900. X    if ((utmp = fopen(UTMP, "r")) == NULL) {
  901. X        perror(UTMP);
  902. X        exit(1);
  903. X    }
  904. X    ucnt = 0;
  905. X    while (fread(&user, sizeof user, 1, utmp) > 0) {
  906. X#ifdef SYS5
  907. X        if (user.ut_type != USER_PROCESS)
  908. X#else
  909. X        if (user.ut_name[0] == '\0')
  910. X#endif
  911. X            continue;
  912. X        ucnt++;
  913. X    }
  914. X    if (kfd == NULL) {
  915. X        if ((kfd = fopen(KMEM, "r")) == NULL) {
  916. X            perror(KMEM);
  917. X            exit(3);
  918. X        }
  919. X    }
  920. X    fseek(kfd, kernel[0].n_value, 0);
  921. X    fread(&vars, sizeof vars, 1, kfd);
  922. X    nproc = vars.v_proc;
  923. X    fseek(kfd, kernel[2].n_value, 0);
  924. X    fread(&swplo, sizeof swplo, 1, kfd);
  925. X    if (mfd == NULL) {
  926. X        if ((mfd = fopen(PMEM, "r")) == NULL) {
  927. X            perror(PMEM);
  928. X            exit(4);
  929. X        }
  930. X    }
  931. X    if (sfd == NULL) {
  932. X        if ((sfd = fopen(SMEM, "r")) == NULL) {
  933. X            perror(SMEM);
  934. X            exit(5);
  935. X        }
  936. X    }
  937. X#ifdef SYS5
  938. X    if ((shm_k = ftok(KERNEL, 'a')) == (key_t) -1) {
  939. X        perror(KERNEL);
  940. X        exit(2);
  941. X    }
  942. X    if ((shm_id = shmget(shm_k, 3 * sizeof *avenrun, 0644)) < 0) {
  943. X        perror("shmget()");
  944. X        exit(2);
  945. X    }
  946. X    if ((int) (avenrun = (double *) shmat(shm_id, (char *) 0, SHM_RDONLY)) == -1) {
  947. X        perror("shmat()");
  948. X        exit(2);
  949. X    }
  950. X    printf(" %s  up%s,  %d users,  load average: %.1f, %.1f, %.1f\nUser     tty       login@  idle   JCPU   PCPU what\n", vtime(&now), uptime(), ucnt, avenrun[0], avenrun[1], avenrun[2]);
  951. X    if (shmdt((char *) avenrun) == -1) {
  952. X        perror("shmdt()");
  953. X        exit(2);
  954. X    }
  955. X#else
  956. X    printf(" %s  up%s,  %d users,  load average: not available under sys3\nUser     tty       login@  idle   JCPU   PCPU what\n", vtime(&now), uptime(), ucnt);
  957. X#endif
  958. X    rewind(utmp);
  959. X    while (fread(&user, sizeof user, 1, utmp) > 0) {
  960. X#ifdef SYS5
  961. X        if (user.ut_type != USER_PROCESS)
  962. X#else
  963. X        if (user.ut_name[0] == '\0')
  964. X#endif
  965. X            continue;
  966. X        show(&user);
  967. X    }
  968. X    fclose(utmp);
  969. X    exit(0);
  970. X}
  971. X
  972. Xchar *uptime() {
  973. X    static char timebuf[128];
  974. X#ifdef SYS5
  975. X    struct utmp bootdata;
  976. X#else
  977. X    struct proc swapper;
  978. X    struct user bootproc;
  979. X#endif
  980. X    long oldpos, now;
  981. X    short cnt, ocnt;
  982. X    
  983. X#ifdef SYS5
  984. X    oldpos = fseek(utmp, 0L, 0);
  985. X    do {
  986. X        fread(&bootdata, sizeof bootdata, 1, utmp);
  987. X    } while (bootdata.ut_type != BOOT_TIME);
  988. X    fseek(utmp, oldpos, 0);
  989. X#else
  990. X    oldpos = fseek(kfd, 0L, 1);
  991. X    fseek(kfd, kernel[1].n_value, 0);
  992. X    fread(&swapper, sizeof swapper, 1, kfd);
  993. X    fseek(kfd, oldpos, 0);
  994. X    oldpos = fseek(mfd, 0L, 1);
  995. X    fseek(mfd, ctob(swapper.p_addr), 0);
  996. X    fread(&bootproc, sizeof bootproc, 1, mfd);
  997. X    fseek(mfd, 0L, 1);
  998. X#endif
  999. X    time(&now);
  1000. X#ifdef SYS5
  1001. X    now -= bootdata.ut_time;
  1002. X#else
  1003. X    now -= bootproc.u_start;
  1004. X#endif
  1005. X    if (now < 0L)
  1006. X        return " with strange clock time";
  1007. X    timebuf[0] = '\0';
  1008. X    ocnt = 0;
  1009. X    cnt = 0;
  1010. X    while (now >= MONTH) {
  1011. X        cnt++;
  1012. X        now -= MONTH;
  1013. X    }
  1014. X    if (cnt > 0) {
  1015. X        strcat(timebuf, itoa(cnt));
  1016. X        strcat(timebuf, " mon");
  1017. X        if (cnt > 1)
  1018. X            strcat(timebuf, "s");
  1019. X        if (++ocnt == 2)
  1020. X            return timebuf;
  1021. X    }
  1022. X    cnt = 0;
  1023. X    while (now >= WEEK) {
  1024. X        cnt++;
  1025. X        now -= WEEK;
  1026. X    }
  1027. X    if (cnt > 0) {
  1028. X        strcat(timebuf, itoa(cnt));
  1029. X        strcat(timebuf, " wk");
  1030. X        if (cnt > 1)
  1031. X            strcat(timebuf, "s");
  1032. X        if (++ocnt == 2)
  1033. X            return timebuf;
  1034. X    }
  1035. X    cnt = 0;
  1036. X    while (now >= DAY) {
  1037. X        cnt++;
  1038. X        now -= DAY;
  1039. X    }
  1040. X    if (cnt > 0) {
  1041. X        strcat(timebuf, itoa(cnt));
  1042. X        strcat(timebuf, " day");
  1043. X        if (cnt > 1)
  1044. X            strcat(timebuf, "s");
  1045. X        if (++ocnt == 2)
  1046. X            return timebuf;
  1047. X    }
  1048. X    cnt = 0;
  1049. X    while (now >= HOUR) {
  1050. X        cnt++;
  1051. X        now -= HOUR;
  1052. X    }
  1053. X    if (cnt > 0) {
  1054. X        strcat(timebuf, itoa(cnt));
  1055. X        strcat(timebuf, " hr");
  1056. X        if (cnt > 1)
  1057. X            strcat(timebuf, "s");
  1058. X    }
  1059. X    return timebuf;
  1060. X}
  1061. X
  1062. Xchar *itoa(n)
  1063. Xint n; {
  1064. X    static char buf[20];
  1065. X    
  1066. X    sprintf(buf, " %d", n);
  1067. X    return buf;
  1068. X}
  1069. X
  1070. Xshow(uinfo)
  1071. Xstruct utmp *uinfo; {
  1072. X    struct stat sbuf;
  1073. X    struct proc proc;
  1074. X    struct user prog;
  1075. X    char ttydev[16];
  1076. X    long now, cnt, offset, jcpu;
  1077. X    short mpid, isswap;
  1078. X    FILE *ufd;
  1079. X    
  1080. X    strcpy(ttydev, "/dev/");
  1081. X    strncpy(&ttydev[5], uinfo->ut_line, 8);
  1082. X    ttydev[13] = '\0';
  1083. X    if (stat(ttydev, &sbuf) != 0) {
  1084. X        perror(ttydev);
  1085. X        return;
  1086. X    }
  1087. X    time(&now);
  1088. X    now -= sbuf.st_atime;
  1089. X    printf("%-8.8s %-8.8s %7s ", uinfo->ut_name, uinfo->ut_line, vtime(&uinfo->ut_time));
  1090. X    if (now > DAY)
  1091. X        printf("%4dd", now / DAY);
  1092. X    else if (now > HOUR)
  1093. X        printf("%2d:%02d", now / HOUR, (now % HOUR) / 60);
  1094. X    else if (now > MIN)
  1095. X        printf("%5d", now / MIN);
  1096. X    else
  1097. X        printf("     ");
  1098. X    putchar(' ');
  1099. X    fseek(kfd, kernel[1].n_value, 0);
  1100. X    mpid = -1;
  1101. X    jcpu = 0;
  1102. X    for (cnt = 0; cnt < nproc; cnt++) {
  1103. X        fread(&proc, sizeof proc, 1, kfd);
  1104. X        if (proc.p_stat == 0 || proc.p_stat == SZOMB || proc.p_stat == SWAIT)
  1105. X            continue;
  1106. X        if (proc.p_flag & SLOAD) {
  1107. X            fseek(mfd, ctob(proc.p_addr), 0);
  1108. X            fread(&prog, sizeof prog, 1, mfd);
  1109. X            isswap = 0;
  1110. X        }
  1111. X        else {
  1112. X#ifdef SYS5
  1113. X            fseek(sfd, (swplo + proc.p_swaddr + ctod(proc.p_swsize) - ctod(USIZE)) << 9, 0);
  1114. X#else
  1115. X            fseek(sfd, (long) (swplo + proc.p_addr) << 9, 0);
  1116. X#endif
  1117. X            fread(&prog, sizeof prog, 1, sfd);
  1118. X            isswap = 1;
  1119. X        }
  1120. X        if (prog.u_ttyp == NULL)
  1121. X            continue;
  1122. X        if (sbuf.st_rdev != prog.u_ttyd)
  1123. X            continue;
  1124. X        jcpu += prog.u_utime + prog.u_stime;
  1125. X        if (proc.p_pid == mypid)
  1126. X            continue;
  1127. X        if (proc.p_pid > mpid)
  1128. X            mpid = proc.p_pid;
  1129. X    }
  1130. X    if (mpid == -1)
  1131. X        printf("[can't stat]");
  1132. X    else {
  1133. X        fseek(kfd, kernel[1].n_value, 0);
  1134. X        for (cnt = 0; cnt < nproc; cnt++) {
  1135. X            fread(&proc, sizeof proc, 1, kfd);
  1136. X            if (proc.p_pid == mpid)
  1137. X                break;
  1138. X        }
  1139. X        if (proc.p_pid != mpid)
  1140. X            printf("[interstice]");
  1141. X        else {
  1142. X            if (proc.p_flag & SLOAD) {
  1143. X                fseek(mfd, ctob(proc.p_addr), 0);
  1144. X                fread(&prog, sizeof prog, 1, mfd);
  1145. X            }
  1146. X            else {
  1147. X#ifdef SYS5
  1148. X                fseek(sfd, (swplo + proc.p_swaddr + ctod(proc.p_swsize) - ctod(USIZE)) << 9, 0);
  1149. X#else
  1150. X                fseek(sfd, (long) (swplo + proc.p_addr) << 9, 0);
  1151. X#endif
  1152. X                fread(&prog, sizeof prog, 1, sfd);
  1153. X            }
  1154. X            printf("%3d:%02d %3d:%02d ", jcpu / MIN, jcpu % MIN, (prog.u_utime + prog.u_stime) / MIN, (prog.u_utime + prog.u_stime) % MIN);
  1155. X            prog.u_procp = &proc;
  1156. X            pcmd(&prog);
  1157. X        }
  1158. X    }
  1159. X    putchar('\n');
  1160. X}
  1161. X
  1162. Xchar *vtime(when)
  1163. Xlong *when; {
  1164. X    struct tm then, now;
  1165. X    static char buf[20];
  1166. X    short hour, min, ampm;
  1167. X    long clock;
  1168. X
  1169. X    time(&clock);
  1170. X    now = *localtime(&clock);
  1171. X    then = *localtime(when);
  1172. X    if (then.tm_mon != now.tm_mon || then.tm_mday != now.tm_mday) {
  1173. X        sprintf(buf, "%s %2d", months[then.tm_mon], then.tm_mday);
  1174. X        return buf;
  1175. X    }
  1176. X    min = then.tm_min;
  1177. X    if (then.tm_hour == 0) {
  1178. X        ampm = 'a';
  1179. X        hour = 12;
  1180. X    }
  1181. X    else if (then.tm_hour > 0 && then.tm_hour < 12) {
  1182. X        ampm = 'a';
  1183. X        hour = then.tm_hour;
  1184. X    }
  1185. X    else if (then.tm_hour == 12) {
  1186. X        ampm = 'p';
  1187. X        hour = 12;
  1188. X    }
  1189. X    else {
  1190. X        ampm = 'p';
  1191. X        hour = then.tm_hour - 12;
  1192. X    }
  1193. X    sprintf(buf, "%d:%02d%cm", hour, min, ampm);
  1194. X    return buf;
  1195. X}
  1196. X
  1197. Xpcmd(uinfo)
  1198. Xstruct user *uinfo; {
  1199. X    /* someday look up the user's command line */
  1200. X    printf("%-.14s", uinfo->u_comm);
  1201. X}
  1202. ________This_Is_The_END________
  1203. if test `wc -l < w.c` -ne 390; then
  1204.     echo 'shar: w.c was damaged during transit (should have been 390 bytes)'
  1205. fi
  1206. fi        ; : end of overwriting check
  1207. echo 'x - avenrun.1m'
  1208. if test -f avenrun.1m; then echo 'shar: not overwriting avenrun.1m'; else
  1209. sed 's/^X//' << '________This_Is_The_END________' > avenrun.1m
  1210. X.TH AVENRUN 1M
  1211. X.SH NAME
  1212. Xavenrun \- compute load averages
  1213. X.SH SYNOPSIS
  1214. X.B avenrun
  1215. X.SH DESCRIPTION
  1216. X.B
  1217. XAvenrun
  1218. Xis a program to generate load average numbers on systems running AT&T's
  1219. Xversion of UNIX(R).  (UNIX is a registered trademark of AT&T.)  It does
  1220. Xits job by creating a shared memory segment whose key is the value of
  1221. X.I ftok(\"/unix\", 'a')
  1222. Xwhich contains three (double)'s.  It then updates this structure with the
  1223. X1-minute, 5-minute, and 15-minute load averages, as calculated from the
  1224. Xsysinfo structure of the kernel (the "runque" and "runocc" entries).
  1225. X.P
  1226. XThe load average is only an approximation of the actual number, which is
  1227. Xthe average number of processes on the run queue.  It is about as close as
  1228. Xyou can get without actually computing the load average in the kernel as
  1229. Xprocesses are placed on the run queue.
  1230. X.SH FILES
  1231. X.ta \w'/dev/kmem    'u
  1232. X/unix    system namelist
  1233. X.br
  1234. X/dev/kmem    kernel memory, for the sysinfo structure
  1235. X.DT
  1236. X.SH SEE ALSO
  1237. Xstdipc(3), shmop(2), sa(4).
  1238. X.SH BUGS
  1239. XIt really should be in the kernel.
  1240. ________This_Is_The_END________
  1241. if test `wc -l < avenrun.1m` -ne 30; then
  1242.     echo 'shar: avenrun.1m was damaged during transit (should have been 30 bytes)'
  1243. fi
  1244. fi        ; : end of overwriting check
  1245. echo 'x - csl.1l'
  1246. if test -f csl.1l; then echo 'shar: not overwriting csl.1l'; else
  1247. sed 's/^X//' << '________This_Is_The_END________' > csl.1l
  1248. X.TH CSL local
  1249. X.SH NAME
  1250. Xcsl \- cyclic status line
  1251. X.SH SYNOPSIS
  1252. X.B csl
  1253. X.SH DESCRIPTION
  1254. X.B Csl
  1255. Xis a program for displaying interesting information on the status line
  1256. Xof a terminal which possesses one.  The information is shown in "panels"
  1257. Xwhich are displayed for five seconds before going to the next panel.
  1258. XAfter the last panel is displayed, the first panel will be redisplayed.
  1259. X.PP
  1260. XThe panels display information in the following order:
  1261. X.IP
  1262. X- mail messages, one per panel; sender and subject
  1263. X.IP
  1264. X- current program, login name, load average, current time
  1265. X.IP
  1266. X- full name, terminal, number of active programs
  1267. X.IP
  1268. X- lines from $HOME/.messages, one per panel
  1269. X.IP
  1270. X- current users on the system
  1271. X.PP
  1272. XAn example of some successive panels:
  1273. X.nf
  1274. X
  1275. X    01>From bobw: Re: x10.bas
  1276. X    02>From root: [No subject]
  1277. X    03> jove // brandon // 0.76 1.02 0.95 // Thu 05/08 16:56
  1278. X    04> "Brandon Allbery" on tty2 // 3 active programs
  1279. X    05>START THE MONTHLY REPORTS!!!
  1280. X
  1281. X.fi
  1282. X.PP
  1283. X.B Csl
  1284. Xlooks for terminfo definitions "hsl", "tsl", "fsl", "wsl", and "dsl".
  1285. XIt does not make use of the parameterization feature except to position
  1286. Xto the first column of the status line, so non-addressable status lines
  1287. X(such as on the Wyse 50 and Wyse 75) can be used.
  1288. X.P
  1289. XIf the file
  1290. X.I $HOME/.syslinelock
  1291. Xis found to exist at the beginning of a cycle,
  1292. X.B csl
  1293. Xwaits until the file disappears before performing any more displays.
  1294. XThis is useful when 
  1295. X.B csl
  1296. Xupsets the display from a particular program, or on terminals which
  1297. Xdo not accept keyboard commands while the status line is being loaded
  1298. X(e.g. the Wyse 75) when rapid keyboard input is required.
  1299. X.SH FILES
  1300. X.ta \w'$HOME/.syslinelock    'u
  1301. X$HOME/.syslinelock    Disables status line
  1302. X.br
  1303. X$HOME/.messages    Scanned for messages to display
  1304. X.br
  1305. X/usr/mail/$LOGNAME    Scanned for new mail
  1306. X.br
  1307. X/etc/passwd    The user's full name is stored here
  1308. X.br
  1309. X/etc/utmp    Current users, and the current user's terminal
  1310. X.DT
  1311. X.SH NOTES
  1312. X.B Csl
  1313. Xwill refuse to run on a terminal whose terminfo description does not
  1314. Xinclude the boolean attribute "hsl".  See terminfo(4) for information
  1315. Xabout the status line attributes of terminfo.
  1316. X.PP
  1317. XThe full name of a user is expected to be the (only) entry in the pw_gecos
  1318. Xfield of /etc/passwd for that user (see
  1319. X.B getpwent(3) .
  1320. XRJE format (of the form
  1321. X"0000-user(0000)") is not understood.
  1322. X.SH SEE ALSO
  1323. Xterminfo(4), avenrun(1m).
  1324. X.SH BUGS
  1325. X.B Csl
  1326. Xshould scan for $HOME/.syslinelock after each panel, rather than at
  1327. Xthe beginning of a cycle.
  1328. X.PP
  1329. XThings can change while
  1330. X.I csl
  1331. Xis displaying a panel; in general, changes are not seen until the next
  1332. Xcycle.
  1333. X.PP
  1334. XFull names are not always easy to figure out under System V.  Some sites
  1335. Xuse the RJE format, others use the BSD format.
  1336. X.B Csl
  1337. Xuses BSD because it's straightforward, the full name is the pw_gecos field
  1338. Xup to a comma.
  1339. X.PP
  1340. XBecause VAR versions of
  1341. X.B csh(1)
  1342. Xinsist on closing their fd 0,
  1343. X.B csl
  1344. Xmust admit such programs as being running in the foreground.  This causes
  1345. Xvarious lies about the name of the current process.
  1346. X.PP
  1347. XOn systems running MH, the mail checking routines will fail; they
  1348. Xexpect "normal" UUCP mailboxes, not MMDF maildrops.  Perhaps the
  1349. Xbest fix for this is to run
  1350. X.B ims(local)
  1351. Xinstead.
  1352. X.PP
  1353. XIt isn't
  1354. X.B statline(1) .
  1355. X(This may be a feature.)
  1356. ________This_Is_The_END________
  1357. if test `wc -l < csl.1l` -ne 108; then
  1358.     echo 'shar: csl.1l was damaged during transit (should have been 108 bytes)'
  1359. fi
  1360. fi        ; : end of overwriting check
  1361. echo 'x - w.1l'
  1362. if test -f w.1l; then echo 'shar: not overwriting w.1l'; else
  1363. sed 's/^X//' << '________This_Is_The_END________' > w.1l
  1364. X.TH W 1 local
  1365. X.SH NAME
  1366. Xw \- display users and processes
  1367. X.SH SYNOPSIS
  1368. X.B w
  1369. X.SH DESCRIPTION
  1370. X.B W
  1371. Xis a program which displays an "intelligent" listing of the current users,
  1372. Xwhat they're doing, and how active they are.  There are two basic kinds
  1373. Xof information displayed:  system information and per-user information.
  1374. XAn example is shown below.
  1375. X.nf
  1376. X
  1377. X 10:55pm  up 2 wks 2 days,  4 users,  load average: 1.2, 1.0, 0.8
  1378. XUser     tty       login@  idle   JCPU   PCPU what
  1379. Xrhg      tty6     10:36pm        12:20  12:20 csh
  1380. Xrobertd  tty7     10:21pm         9:21   9:21 csh
  1381. Xbobw     tty13    10:26pm       160:35 149:43 rn
  1382. Xallbery  tty15     9:47pm        50:22   0:18 sh
  1383. X
  1384. X.fi
  1385. XThe first line displays the current time, how long the system has been up,
  1386. Xthe number of users, and the load average (if available; not under System
  1387. XIII).  The other lines display for each user, the user's login name, the
  1388. Xterminal the user is on, the time the user logged in, how long the user has
  1389. Xbeen idle, the CPU time used by the current program and total CPU for the
  1390. Xlogin session, and the current program.
  1391. X.SH FILES
  1392. X.ta \w'/dev/kmem    'u
  1393. X/dev/kmem    System memory (the process table)
  1394. X.br
  1395. X/dev/mem    In-core program images
  1396. X.br
  1397. X/dev/swap    Swapped program images
  1398. X.br
  1399. X/dev    Searches for terminals
  1400. X.br
  1401. X/etc/utmp    Current system users and boot time
  1402. X.DT
  1403. X.SH NOTES
  1404. X.B W
  1405. Xdisplays the process name as shown by
  1406. X.B ps(1)
  1407. Xwithout the -f argument.
  1408. X.SH SEE ALSO
  1409. Xavenrun(1m), ps(1), who(1).
  1410. X.SH BUGS
  1411. XJCPU and current process are both kludges.  The former is really only the
  1412. XCPU of running programs in the terminal session, as System V does not retain
  1413. Xuser and system times for all programs in a sessionl; the latter attempts to
  1414. Xdisregard background processes, but it is nearly impossible to successfully
  1415. Xdetermine if a program is in the background or not.  This is exacerbated by
  1416. Xthe fact that VAR csh(1)'s, when available, look suspiciously like
  1417. Xbackground processes because they close their standard input.
  1418. X.PP
  1419. XIf the user block is demand paged, 
  1420. X.B w
  1421. Xwon't find it; I don't have access to a demand-paged system.
  1422. X.PP
  1423. X.B who -u
  1424. Xand
  1425. X.B w
  1426. Xhave different ideas on what constitutes idle time; one uses time of last
  1427. Xinput, the other the time of last output.
  1428. X.PP
  1429. XThe boot time isn't guaranteed to be correct if you don't have a real time
  1430. Xclock with battery backup.  There is also a kludge which will not affect
  1431. Xnormal systems, but which deals with a tendency for Plexus systems to
  1432. Xforward-date the system clock by one month.
  1433. X.PP
  1434. XIt is possible that reading the summarized child's system and user times
  1435. Xwould produce a better approximation of JCPU.  This is only likely, however,
  1436. Xif the times are updated recursively.
  1437. X.PP
  1438. XThings can change while 
  1439. X.B w
  1440. Xis running; this occasionally causes the current program to be printed as
  1441. X"[can't stat]" or as "[interstice]".
  1442. X.PP
  1443. XIf you want "w" to work correctly, get 4.2BSD.
  1444. X.PP
  1445. XIt should really take options for the system namelist, memory, and
  1446. Xswap files, as well as the key of the shared memory partition; it should
  1447. Xalso recover gracefully if avenrun(1m) isn't running.
  1448. ________This_Is_The_END________
  1449. if test `wc -l < w.1l` -ne 84; then
  1450.     echo 'shar: w.1l was damaged during transit (should have been 84 bytes)'
  1451. fi
  1452. fi        ; : end of overwriting check
  1453. exit 0
  1454. -- 
  1455.  Brandon S. Allbery, moderator of comp.sources.misc and comp.binaries.ibm.pc
  1456.   {{harvard,mit-eddie}!necntc,well!hoptoad,sun!cwruecmp!hal}!ncoast!allbery
  1457. ARPA: necntc!ncoast!allbery@harvard.harvard.edu  Fido: 157/502  MCI: BALLBERY
  1458.    <<ncoast Public Access UNIX: +1 216 781 6201 24hrs. 300/1200/2400 baud>>
  1459.