home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / compsrcs / misc / volume07 / si < prev    next >
Encoding:
Internet Message Format  |  1991-08-27  |  17.8 KB

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