home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume7 / si < prev    next >
Encoding:
Text File  |  1989-08-06  |  17.5 KB  |  733 lines

  1. Newsgroups: comp.sources.misc
  2. subject: v07i122: si -- display user process trees (Xenix 386)
  3. From: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc)
  4. Reply-To: allbery@hal.CWRU.Edu@nc386.UUCP
  5.  
  6. Posting-number: Volume 7, Issue 122
  7. Submitted-by: allbery@hal.CWRU.Edu@nc386.UUCP
  8. Archive-name: si
  9.  
  10. As one of the folks in charge of NCoast.ORG, I often find it useful to keep
  11. an eye on what people are doing on the system.  This program makes it easy
  12. by displaying genealogical process trees.
  13.  
  14. ++Brandon
  15. #--------------------------------CUT HERE-------------------------------------
  16. #! /bin/sh
  17. #
  18. # This is a shell archive.  Save this into a file, edit it
  19. # and delete all lines above this comment.  Then give this
  20. # file to sh by executing the command "sh file".  The files
  21. # will be extracted into the current directory owned by
  22. # you with default permissions.
  23. #
  24. # The files contained herein are:
  25. #
  26. # -rw-r--r--   1 allbery  20           780 Aug  6 14:53 README
  27. # -rw-r--r--   1 allbery  20         11187 Aug  6 14:06 si.c
  28. # -rw-r--r--   1 allbery  20          2860 Aug  6 14:45 si.man
  29. #
  30. echo 'x - README'
  31. if test -f README; then echo 'shar: not overwriting README'; else
  32. sed 's/^X//' << '________This_Is_The_END________' > README
  33. XThis program displays process trees for processes other than the kernel
  34. Xand init.  The name is historical; the first version did considerably
  35. Xmore than this one does, but subsequent versions were under System III
  36. Xand much of the information was unavailable or inaccessible.
  37. X
  38. XTo compile:  cc -o si si.c -ltinfo -lx
  39. X         chown sysinfo si
  40. X         chmod 4711 si
  41. X(you need root permissions to chown and chgrp the program)
  42. X
  43. XTo run:  si [ -m ]
  44. X
  45. XUse -m to get idle time calculations like SCO's version of w; the default is
  46. Xthe idle time calculation used by who and finger.  (I wish more programs
  47. Xallowed the user to choose!)
  48. X
  49. XThe current version only works under SCO Xenix 386, but should be portable to
  50. XSystem III, System V R2/R3, and Xenix 3/5 systems with a little tweaking.
  51. X
  52. X++Brandon
  53. ________This_Is_The_END________
  54. if test `wc -c < README` -ne 780; then
  55.     echo 'shar: README was damaged during transit (should have been 780 bytes)'
  56. fi
  57. fi        ; : end of overwriting check
  58. echo 'x - si.c'
  59. if test -f si.c; then echo 'shar: not overwriting si.c'; else
  60. sed 's/^X//' << '________This_Is_The_END________' > si.c
  61. X/*
  62. X * System process and user information
  63. X *
  64. X * Slurp the entire process table into memory (discarding system processes)
  65. X * and sort it by process tree and tty.  Then present the information after
  66. X * the fashion of the old "si", using modified strings to represent NLI ttys
  67. X * and null ttys.
  68. X *
  69. X * This version is for SCO Xenix 386.  The original ran under Plexus System III
  70. X * on a Plexus P/35 (68000 Unix).
  71. X */
  72. X
  73. X#define M_TERMINFO        /* d*mn SCO, anyway */
  74. X
  75. X#include <curses.h>
  76. X#include <term.h>
  77. X#include <sys/types.h>
  78. X#include <sys/param.h>
  79. X#include <sys/sysmacros.h>
  80. X#include <sys/seg.h>
  81. X#include <sys/page.h>
  82. X#include <sys/proc.h>
  83. X#include <utmp.h>
  84. X#include <sys/stat.h>
  85. X#include <a.out.h>
  86. X#include <time.h>
  87. X#include <signal.h>
  88. X#include <sys/var.h>
  89. X#include <sys/dir.h>
  90. X#include <sys/user.h>
  91. X#include <sys/tty.h>
  92. X#include <pwd.h>
  93. X#include <grp.h>
  94. X
  95. X#define UTMP        "/etc/utmp"
  96. X#define DEV        "/dev/"
  97. X#define KERNEL        "/xenix"
  98. X#define KMEM        "/dev/kmem"
  99. X#define PMEM        "/dev/mem"
  100. X#define SMEM        "/dev/swap"
  101. X
  102. Xint kfd;
  103. Xint mfd;
  104. Xint sfd;
  105. Xint utmp;
  106. Xint dfd;
  107. Xint idlef;
  108. Xlong nproc;
  109. Xdaddr_t swplo;
  110. X
  111. Xstruct nlist kernel[] =
  112. X{
  113. X    {"_v"},
  114. X    {"_proc"},
  115. X    {"_swplo"},
  116. X    {NULL},
  117. X};
  118. X
  119. Xstruct tm *localtime();
  120. Xstruct passwd *getpwuid(), *getpwnam();
  121. Xstruct group *getgrgid();
  122. Xchar *strrchr(), *malloc();
  123. X
  124. X#define DAY        (60L*60L*24)
  125. X#define HOUR        (60L*60L)
  126. X#define MIN        (60L)
  127. X
  128. X#define static
  129. X
  130. Xstatic void endw(), pcmd();
  131. Xstatic int die(), paint(), grandparent(), pgsort(), rgetc(), showtty();
  132. Xstatic struct proc *ppid();
  133. X
  134. Xstatic
  135. Xvoid
  136. Xendw()
  137. X{
  138. X    move(LINES - 1, 0);
  139. X    clrtoeol();
  140. X    refresh();
  141. X    endwin();
  142. X}
  143. X
  144. Xint dying = 0;
  145. Xint repaint = 0;
  146. X
  147. Xstatic
  148. Xint
  149. Xdie(s)
  150. X{
  151. X    signal(s, die);
  152. X    dying = 1;
  153. X}
  154. X
  155. Xstatic
  156. Xint
  157. Xpaint(s)
  158. X{
  159. X    signal(s, paint);
  160. X    repaint = 1;
  161. X}
  162. X
  163. Xstruct proc *proctab;
  164. Xint numproc;
  165. X
  166. X/*
  167. X * find the ultimate parent of a tree of processes
  168. X */
  169. X
  170. Xstatic
  171. Xstruct proc *
  172. Xppid(p)
  173. X    register struct proc *p;
  174. X{
  175. X    register struct proc *pp;
  176. X
  177. X    if (p->p_ppid == 1)
  178. X    return p;
  179. X    for (;;) {
  180. X    for (pp = proctab; pp < &proctab[numproc]; pp++)
  181. X        if (pp->p_pid == p->p_ppid)
  182. X        break;
  183. X    if (pp == &proctab[numproc])
  184. X        return 0;
  185. X    if (pp->p_ppid == 1)
  186. X        return pp;
  187. X    p = pp;
  188. X    }
  189. X}
  190. X
  191. X/*
  192. X * similar to ppid(), but stop when a parent process is the other specified
  193. X * process; return 1 if it's found, 0 if not
  194. X */
  195. X
  196. Xstatic
  197. Xint
  198. Xgrandparent(p, gp)
  199. X    register struct proc *p, *gp;
  200. X{
  201. X    register struct proc *pp;
  202. X
  203. X    if (p->p_ppid < 2)
  204. X    return 0;
  205. X    for (;;) {
  206. X    for (pp = proctab; pp < &proctab[numproc]; pp++)
  207. X        if (pp->p_pid == p->p_ppid)
  208. X        break;
  209. X    if (pp == &proctab[numproc])
  210. X        return 0;
  211. X    if (pp == gp)
  212. X        return 1;
  213. X    if (pp->p_ppid < 2)
  214. X        return 0;
  215. X    p = pp;
  216. X    }
  217. X}
  218. X
  219. X/*
  220. X * sort function for qsort() of process table
  221. X * order by process group, then parent of "tree" of processes within group,
  222. X * then relative hierarchy within "tree".
  223. X * if tree parent's pid is same as pgrp, always sorts before other parents
  224. X */
  225. X
  226. Xstatic
  227. Xint
  228. Xpgsort(p1, p2)
  229. X    register struct proc *p1, *p2;
  230. X{
  231. X    register struct proc *p1p, *p2p;
  232. X
  233. X    /* sort by process group first... */
  234. X    if (p1->p_pgrp != p2->p_pgrp)
  235. X    return p1->p_pgrp - p2->p_pgrp;
  236. X    /* sort by great^n-grandparent */
  237. X    if ((p1p = ppid(p1)) != (p2p = ppid(p2))) {
  238. X    if (p1p->p_pgrp == p1p->p_pid)
  239. X        return -1;
  240. X    if (p2p->p_pgrp == p2p->p_pid)
  241. X        return 1;
  242. X    return p1p->p_pid - p2p->p_pid;
  243. X    }
  244. X    /* great^n-grandparent comes first, always */
  245. X    if (p1->p_ppid < 2)
  246. X    return -1;
  247. X    if (p2->p_ppid < 2)
  248. X    return 1;
  249. X    /* follow hierarchy up searching for common ancestry */
  250. X    if (grandparent(p1, p2))
  251. X    return 1;
  252. X    if (grandparent(p2, p1))
  253. X    return -1;
  254. X    /* this shouldn't happen... */
  255. X    return 0;
  256. X}
  257. X
  258. Xint
  259. Xmain(argc, argv)
  260. X    char **argv;
  261. X{
  262. X    struct var vars;
  263. X    register struct proc *scanp, *insp;
  264. X    int depth, ptr, pgrp, ruid, rgid;
  265. X    int stack[20];
  266. X    struct user *u;
  267. X    struct passwd *pw;
  268. X    struct group *gr;
  269. X
  270. X    if (argc == 2)
  271. X    idlef = (strcmp(argv[1], "-m") == 0);
  272. X    signal(SIGHUP, die);
  273. X    signal(SIGQUIT, die);
  274. X    signal(SIGINT, paint);
  275. X    signal(SIGTERM, die);
  276. X    initscr();
  277. X    cbreak();
  278. X    noecho();
  279. X    nl();
  280. X    if (!cursor_address || !*cursor_address)
  281. X    {
  282. X    endw();
  283. X    fprintf(stderr, "I can't use your terminal.\n");
  284. X    exit(1);
  285. X    }
  286. X    if (nlist(KERNEL, kernel) == -1)
  287. X    {
  288. X    endw();
  289. X    perror(KERNEL);
  290. X    exit(2);
  291. X    }
  292. X    if ((utmp = open(UTMP, 0)) == -1)
  293. X    {
  294. X    endw();
  295. X    perror(UTMP);
  296. X    exit(1);
  297. X    }
  298. X    if ((kfd = open(KMEM, 0)) == -1)
  299. X    {
  300. X    endw();
  301. X    perror(KMEM);
  302. X    exit(3);
  303. X    }
  304. X    lseek(kfd, kernel[0].n_value, 0);
  305. X    read(kfd, &vars, sizeof vars);
  306. X    nproc = vars.v_proc;
  307. X    lseek(kfd, kernel[2].n_value, 0);
  308. X    read(kfd, &swplo, sizeof swplo);
  309. X    if ((mfd = open(PMEM, 0)) == -1)
  310. X    {
  311. X    endw();
  312. X    perror(PMEM);
  313. X    exit(4);
  314. X    }
  315. X    if ((sfd = open(SMEM, 0)) == -1)
  316. X    {
  317. X    endw();
  318. X    perror(SMEM);
  319. X    exit(5);
  320. X    }
  321. X    if ((dfd = open(DEV, 0)) == -1)
  322. X    {
  323. X    endw();
  324. X    perror(DEV);
  325. X    exit(6);
  326. X    }
  327. X    if ((proctab = (struct proc *) malloc(nproc * sizeof *proctab)) == 0)
  328. X    {
  329. X    endw();
  330. X    fprintf(stderr, "Out of memory\n");
  331. X    exit(6);
  332. X    }
  333. X    for (;;)
  334. X    {
  335. X    /* handle pending signals */
  336. X    if (dying)
  337. X    {
  338. X        endw();
  339. X        exit(0);
  340. X    }
  341. X    if (repaint)
  342. X    {
  343. X        repaint = 0;
  344. X        clear();
  345. X    }
  346. X    /* prepare for output */
  347. X    erase();
  348. X    /* gobble proc */
  349. X    lseek(kfd, (long) kernel[1].n_value, 0);
  350. X    read(kfd, proctab, nproc * sizeof *proctab);
  351. X    numproc = nproc;
  352. X    /* zero out swapper and init */
  353. X    memset(proctab, 0, 2 * sizeof *proctab);
  354. X    insp = proctab;
  355. X    /* prune proctab[] (and add user structures) */
  356. X    for (scanp = proctab; scanp < &proctab[nproc]; scanp++)
  357. X    {
  358. X        switch (scanp->p_stat)
  359. X        {
  360. X        case 0:
  361. X        case SWAIT:
  362. X        case SIDL:
  363. X        case SZOMB:
  364. X        scanp->p_stat = 0;
  365. X        numproc--;
  366. X        continue;
  367. X        default:
  368. X        while (insp->p_stat != 0 && insp != scanp)
  369. X            insp++;
  370. X        if (insp != scanp)
  371. X        {
  372. X            memcpy(insp, scanp, sizeof *scanp);
  373. X            scanp->p_stat = 0;
  374. X        }
  375. X        if (!(insp->p_wchan = malloc(sizeof (struct user))))
  376. X        {
  377. X            endw();
  378. X            fprintf(stderr, "Out of memory\n");
  379. X            exit(8);
  380. X        }
  381. X        if (insp->p_flag & SLOAD)
  382. X        {
  383. X            lseek(mfd, insp->p_addr[0].te_frameno * NBPC, 0);
  384. X            read(mfd, insp->p_wchan, sizeof (struct user));
  385. X        }
  386. X        else
  387. X        {
  388. X            lseek(sfd, insp->p_addr[0].te_frameno * NBPC, 0);
  389. X            read(sfd, insp->p_wchan, sizeof (struct user));
  390. X        }
  391. X        /* zap gettys, we could care less */
  392. X        if (isgetty(insp))
  393. X        {
  394. X            insp->p_stat = 0;
  395. X            free(insp->p_wchan);
  396. X            scanp->p_stat = 0;
  397. X            numproc--;
  398. X        }
  399. X        }
  400. X    }
  401. X    /* sort proctab[] by process group */
  402. X    qsort(proctab, numproc, sizeof *proctab, pgsort);
  403. X    /* print proctab[] */
  404. X    pgrp = -1;
  405. X    for (scanp = proctab; scanp < &proctab[numproc]; scanp++)
  406. X    {
  407. X        u = (struct user *) scanp->p_wchan;
  408. X        ((struct user *) scanp->p_wchan)->u_procp = scanp;
  409. X        if (scanp->p_pgrp != pgrp)
  410. X        {
  411. X        if (pgrp != -1)
  412. X            addch('\n');
  413. X        pgrp = scanp->p_pgrp;
  414. X        if (!u->u_ttyp)
  415. X        {
  416. X            addstr("(no tty)");
  417. X            move(stdscr->_cury, 40);
  418. X            addstr("Process group detached from terminal\n");
  419. X            ruid = u->u_ruid;
  420. X            rgid = u->u_rgid;
  421. X        }
  422. X        else if (!showtty(scanp, u, &ruid, &rgid))
  423. X        {
  424. X            ruid = u->u_ruid;
  425. X            rgid = u->u_rgid;
  426. X            move(stdscr->_cury, 40);
  427. X            addstr("Process group orphaned\n");
  428. X        }
  429. X        depth = -1;
  430. X        }
  431. X        for (ptr = depth; ptr >= 0; ptr--)
  432. X        if (scanp->p_ppid == stack[ptr])
  433. X            break;
  434. X        stack[depth = ++ptr] = scanp->p_pid;
  435. X        printw("  %5d ", scanp->p_pid);
  436. X        if (u->u_uid == ruid)
  437. X        addstr("         ");
  438. X        else
  439. X        {
  440. X        setpwent();
  441. X        if (pw = getpwuid(u->u_uid))
  442. X            printw("%-8.8s ", pw->pw_name);
  443. X        else
  444. X            printw("%-8d ", u->u_uid);
  445. X        }
  446. X        if (u->u_gid == rgid)
  447. X        addstr("         ");
  448. X        else
  449. X        {
  450. X        setgrent();
  451. X        if (gr = getgrgid(u->u_gid))
  452. X            printw("%-8.8s ", gr->gr_name);
  453. X        else
  454. X            printw("%-8d ", u->u_gid);
  455. X        }
  456. X        printw("%*s ", depth * 2, "");
  457. X        pcmd(u);
  458. X        addch('\n');
  459. X        free(u);
  460. X    }
  461. X    refresh();
  462. X    sleep(5);
  463. X    }
  464. X}
  465. X
  466. X/*
  467. X * print the command name and arguments (if possible) of a process
  468. X * for xenix, this prints u.u_psargs instead of groveling in core
  469. X */
  470. X
  471. Xstatic
  472. Xvoid
  473. Xpcmd(uinfo)
  474. X    struct user *uinfo;
  475. X{
  476. X    int c, d;
  477. X
  478. X    for (c = PSARGSZ; c-- && uinfo->u_psargs[c] != '\0'; )
  479. X    ;
  480. X    if (!c)
  481. X    printw("(%.*s)", DIRSIZ, uinfo->u_comm);
  482. X    else
  483. X    {
  484. X    if (c > COLS - stdscr->_curx - 1)
  485. X        c = COLS - stdscr->_curx - 1;
  486. X    printw("%.*s", c, uinfo->u_psargs);
  487. X    for (d = 0; d < c && uinfo->u_psargs[d] != ' '; d++)
  488. X        ;
  489. X    uinfo->u_psargs[d] = '\0';
  490. X    for (; d >= 0 && uinfo->u_psargs[d] != '/'; d--)
  491. X        ;
  492. X    if (strncmp(uinfo->u_psargs + d + 1, uinfo->u_comm, DIRSIZ) != 0)
  493. X        printw(" (%.*s)", DIRSIZ, uinfo->u_comm);
  494. X    }
  495. X}
  496. X
  497. X/*
  498. X * print tty information for process; if process owner (pgrp) isn't logged in,
  499. X * return FALSE, else set *ruidp and *rgidp and return TRUE
  500. X */
  501. X
  502. Xstatic
  503. Xint
  504. Xshowtty(p, u, ruidp, rgidp)
  505. X    struct proc *p;
  506. X    struct user *u;
  507. X    int *ruidp, *rgidp;
  508. X{
  509. X    int isut;
  510. X    struct tty t;
  511. X    struct direct dev;
  512. X    char *cp;
  513. X    char ttyp[32], login[16];
  514. X    struct stat sb;
  515. X    struct utmp ut;
  516. X    struct tm *tp;
  517. X    struct passwd *pw;
  518. X    long now;
  519. X
  520. X    lseek(kfd, (long) u->u_ttyp, 0);
  521. X    read(kfd, &t, sizeof t);
  522. X    sb.st_rdev = -1;
  523. X    lseek(dfd, 0L, 0);
  524. X    while (read(dfd, &dev, sizeof dev) == sizeof dev)
  525. X    {
  526. X    strcpy(ttyp, DEV);
  527. X    strncat(ttyp, dev.d_name, DIRSIZ);
  528. X    ttyp[DIRSIZ + sizeof DEV] = '\0';
  529. X    if (stat(ttyp, &sb) == -1 || (sb.st_mode & S_IFMT) != S_IFCHR)
  530. X        continue;
  531. X    if (sb.st_rdev == u->u_ttyd)
  532. X        break;
  533. X    }
  534. X    if (sb.st_rdev != u->u_ttyd)
  535. X    {
  536. X    printw("(cdev %d/%d not found)", major(u->u_ttyd), minor(u->u_ttyd));
  537. X    return 0;
  538. X    }
  539. X    if (t.t_pgrp != p->p_pgrp)
  540. X    {
  541. X    printw("          %-8.8s          old", dev.d_name);
  542. X    return 0;
  543. X    }
  544. X    lseek(utmp, 0L, 0);
  545. X    while (isut = (read(utmp, &ut, sizeof ut) == sizeof ut))
  546. X    if (ut.ut_type != USER_PROCESS)
  547. X        continue;
  548. X    else if (strncmp(ut.ut_line, dev.d_name, sizeof ut.ut_line) == 0)
  549. X        break;
  550. X    if (!isut || ut.ut_name[0] == '\0')
  551. X    {
  552. X    printw("          %-8.8s          old", dev.d_name);
  553. X    return 0;
  554. X    }
  555. X    printw("%-8.8s  %-8.8s  ", ut.ut_name, dev.d_name);
  556. X    tp = localtime(&ut.ut_time);
  557. X    time(&now);
  558. X    if (now - ut.ut_time >= 86400)
  559. X    printw("  %02d/%02d", tp->tm_mon + 1, tp->tm_mday);
  560. X    else
  561. X    printw("  %2d:%02d", tp->tm_hour, tp->tm_min);
  562. X    if ((now -= (idlef? sb.st_mtime: sb.st_atime)) >= 86400)
  563. X    printw("  %3dd", now / 86400);
  564. X    else if (now >= 3600)
  565. X    printw("  %2d:%02d", now / 3600, (now % 3600) / 60);
  566. X    else if (now >= 60)
  567. X    printw("  %3d", now / 60);
  568. X    strncpy(login, ut.ut_name, sizeof ut.ut_name);
  569. X    login[sizeof ut.ut_name] = '\0';
  570. X    move(stdscr->_cury, 40);
  571. X    setpwent();
  572. X    if (!(pw = getpwnam(login)))
  573. X    {
  574. X    *ruidp = u->u_ruid;
  575. X    *rgidp = u->u_rgid;
  576. X    addstr("(user not in passwd file)\n");
  577. X    }
  578. X    else
  579. X    {
  580. X    *ruidp = pw->pw_uid;
  581. X    *rgidp = pw->pw_gid;
  582. X    for (cp = pw->pw_gecos; *cp && *cp != ','; cp++)
  583. X        ;
  584. X    *cp = '\0';
  585. X    addstr(pw->pw_gecos);
  586. X    addch('\n');
  587. X    }
  588. X    return 1;
  589. X}
  590. X
  591. X/*
  592. X * determine "getty-ness" of a process
  593. X */
  594. X
  595. Xisgetty(u)
  596. X    struct proc *u;
  597. X{
  598. X    struct utmp ut;
  599. X
  600. X    lseek(utmp, 0L, 0);
  601. X    while (read(utmp, &ut, sizeof ut) == sizeof ut)
  602. X    if (ut.ut_pid == u->p_pid)
  603. X        return ut.ut_type == LOGIN_PROCESS;
  604. X    return 0;
  605. X}
  606. ________This_Is_The_END________
  607. if test `wc -c < si.c` -ne 11187; then
  608.     echo 'shar: si.c was damaged during transit (should have been 11187 bytes)'
  609. fi
  610. fi        ; : end of overwriting check
  611. echo 'x - si.man'
  612. if test -f si.man; then echo 'shar: not overwriting si.man'; else
  613. sed 's/^X//' << '________This_Is_The_END________' > si.man
  614. X.TH SI 1 "6 August 1989"
  615. X.SH NAME
  616. Xsi \- show system and user process trees
  617. X.SH SYNOPSIS
  618. X.B si
  619. X[
  620. X.B -m
  621. X]
  622. X.SH DESCRIPTION
  623. X.I Si
  624. Xdisplays indented process trees for processes other than the kernel,
  625. X.IR init ,
  626. Xand
  627. X.IR getty .
  628. XThe information displayed is the terminal name or
  629. X.BR "(no tty)" ,
  630. Xthe logged-in user,
  631. Xlogin time,
  632. Xidle time and user name,
  633. Xand for each process the process ID,
  634. Xeffective user and group IDs if different from the logged-in user's IDs,
  635. Xand the process name and arguments (if available).
  636. XIf the process name is not available or differs from the exec name,
  637. Xthe exec name is displayed in parentheses.
  638. XProcesses are displayed in order by process group,
  639. Xand within each process group by parent/child relationship.
  640. XThe only option is
  641. X.BR "-m" ,
  642. Xwhich causes
  643. X.I si
  644. Xto compute the idle time based on the tty's modification time
  645. Xrather than access time.
  646. XThis allows the user to select between the idle time displayed by
  647. X.I who
  648. Xor by
  649. X.IR w .
  650. X.PP
  651. XThe program is full-screen,
  652. Xusing
  653. X.I curses
  654. X(with
  655. X.IR M_TERMINFO )
  656. Xto control screen updates.
  657. XIt has two interactive commands:
  658. Xpress
  659. X.B quit
  660. X(usually
  661. X.BR Control-\\ )
  662. Xto exit,
  663. Xand
  664. X.B intr
  665. X(usually
  666. X.B DEL
  667. Xor
  668. X.BR Control-C )
  669. Xto force the screen to be redrawn after line noise or an
  670. Xunexpected screen message.
  671. X.SH FILES
  672. X.nf
  673. X.ta 2i
  674. X/dev/kmem    system tables
  675. X/dev/mem    processes in core
  676. X/dev/swap    processes on swap
  677. X.fi
  678. X.SH SEE ALSO
  679. Xwho(1), w(1), finger(1)
  680. X.SH AUTHOR
  681. X.nf
  682. XBrandon S. Allbery
  683. Xtdi2!brandon (first version)
  684. Xncoast!allbery (second version)
  685. Xallbery@NCoast.ORG (third version)
  686. Xnc386!allbery (fourth version)
  687. X.fi
  688. X.SH HISTORY
  689. XFirst written at Tridelta Industries (tdi2), for System V Release 2.2.
  690. XThis version displayed quite a bit more information than the current one;
  691. Xit may be resurrected in the future.
  692. X.PP
  693. XA vastly simplified version was implemented on ncoast (nc68k);
  694. Xmuch of the information in the original was not available under
  695. XSystem III,
  696. Xso the program was restricted to process trees of logged-in users.
  697. X.PP
  698. XA third version was implemented much later,
  699. Xalso under System III.
  700. XIt displayed process trees for detached processes as well,
  701. Xand did a much better job of sorting processes.
  702. X.PP
  703. XThe fourth version was written for Xenix V/386,
  704. Xand amounted to a port of the third version to that environment.
  705. X.SH BUGS
  706. XThe program truncates lines that will not fit across the screen;
  707. Xon an 80-column screen under Xenix 386, this rarely causes problems.
  708. XIt also omits lines which will not fit,
  709. Xwhich is somewhat more serious on busy systems.
  710. X.PP
  711. XOccasionally,
  712. Xa race condition will cause
  713. X.I si
  714. Xto hang instead of exiting or redrawing the screen.
  715. XThis is a side effect of the old V7 signal mechanism;
  716. Xif SCO UNIX 386 implements SVR3 (more) reliable signals,
  717. Xthis will go away.
  718. XEnter the command again to retain control of the program.
  719. X(This may cause
  720. X.I si
  721. Xto exit without restoring the terminal state.)
  722. ________This_Is_The_END________
  723. if test `wc -c < si.man` -ne 2860; then
  724.     echo 'shar: si.man was damaged during transit (should have been 2860 bytes)'
  725. fi
  726. fi        ; : end of overwriting check
  727. exit 0
  728. --
  729. Brandon S. Allbery, moderator of comp.sources.misc    allbery@uunet.uu.net
  730. Please send comp.sources.misc submissions to comp-sources-misc@<backbone>,
  731. related mail to comp-sources-misc-request@<backbone>, and personal mail ONLY
  732. to allbery@NCoast.ORG.  You have only yourself to blame if you don't.
  733.