home *** CD-ROM | disk | FTP | other *** search
- From decwrl!ucbvax!tut.cis.ohio-state.edu!cs.utexas.edu!uunet!allbery Sun Aug 6 16:31:24 PDT 1989
- Article 1023 of comp.sources.misc:
- Path: decwrl!ucbvax!tut.cis.ohio-state.edu!cs.utexas.edu!uunet!allbery
- From: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc)
- Newsgroups: comp.sources.misc
- Subject: v07i122: si -- display user process trees (Xenix 386)
- Message-ID: <62808@uunet.UU.NET>
- Date: 6 Aug 89 22:31:47 GMT
- Sender: allbery@uunet.UU.NET
- Reply-To: allbery@hal.CWRU.Edu@nc386.UUCP
- Lines: 727
- Approved: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc)
-
- Posting-number: Volume 7, Issue 122
- Submitted-by: allbery@hal.CWRU.Edu@nc386.UUCP
- Archive-name: si
-
- As one of the folks in charge of NCoast.ORG, I often find it useful to keep
- an eye on what people are doing on the system. This program makes it easy
- by displaying genealogical process trees.
-
- ++Brandon
- #--------------------------------CUT HERE-------------------------------------
- #! /bin/sh
- #
- # This is a shell archive. Save this into a file, edit it
- # and delete all lines above this comment. Then give this
- # file to sh by executing the command "sh file". The files
- # will be extracted into the current directory owned by
- # you with default permissions.
- #
- # The files contained herein are:
- #
- # -rw-r--r-- 1 allbery 20 780 Aug 6 14:53 README
- # -rw-r--r-- 1 allbery 20 11187 Aug 6 14:06 si.c
- # -rw-r--r-- 1 allbery 20 2860 Aug 6 14:45 si.man
- #
- echo 'x - README'
- if test -f README; then echo 'shar: not overwriting README'; else
- sed 's/^X//' << '________This_Is_The_END________' > README
- XThis program displays process trees for processes other than the kernel
- Xand init. The name is historical; the first version did considerably
- Xmore than this one does, but subsequent versions were under System III
- Xand much of the information was unavailable or inaccessible.
- X
- XTo compile: cc -o si si.c -ltinfo -lx
- X chown sysinfo si
- X chmod 4711 si
- X(you need root permissions to chown and chgrp the program)
- X
- XTo run: si [ -m ]
- X
- XUse -m to get idle time calculations like SCO's version of w; the default is
- Xthe idle time calculation used by who and finger. (I wish more programs
- Xallowed the user to choose!)
- X
- XThe current version only works under SCO Xenix 386, but should be portable to
- XSystem III, System V R2/R3, and Xenix 3/5 systems with a little tweaking.
- X
- X++Brandon
- ________This_Is_The_END________
- if test `wc -c < README` -ne 780; then
- echo 'shar: README was damaged during transit (should have been 780 bytes)'
- fi
- fi ; : end of overwriting check
- echo 'x - si.c'
- if test -f si.c; then echo 'shar: not overwriting si.c'; else
- sed 's/^X//' << '________This_Is_The_END________' > si.c
- X/*
- X * System process and user information
- X *
- X * Slurp the entire process table into memory (discarding system processes)
- X * and sort it by process tree and tty. Then present the information after
- X * the fashion of the old "si", using modified strings to represent NLI ttys
- X * and null ttys.
- X *
- X * This version is for SCO Xenix 386. The original ran under Plexus System III
- X * on a Plexus P/35 (68000 Unix).
- X */
- X
- X#define M_TERMINFO /* d*mn SCO, anyway */
- X
- X#include <curses.h>
- X#include <term.h>
- X#include <sys/types.h>
- X#include <sys/param.h>
- X#include <sys/sysmacros.h>
- X#include <sys/seg.h>
- X#include <sys/page.h>
- X#include <sys/proc.h>
- X#include <utmp.h>
- X#include <sys/stat.h>
- X#include <a.out.h>
- X#include <time.h>
- X#include <signal.h>
- X#include <sys/var.h>
- X#include <sys/dir.h>
- X#include <sys/user.h>
- X#include <sys/tty.h>
- X#include <pwd.h>
- X#include <grp.h>
- X
- X#define UTMP "/etc/utmp"
- X#define DEV "/dev/"
- X#define KERNEL "/xenix"
- X#define KMEM "/dev/kmem"
- X#define PMEM "/dev/mem"
- X#define SMEM "/dev/swap"
- X
- Xint kfd;
- Xint mfd;
- Xint sfd;
- Xint utmp;
- Xint dfd;
- Xint idlef;
- Xlong nproc;
- Xdaddr_t swplo;
- X
- Xstruct nlist kernel[] =
- X{
- X {"_v"},
- X {"_proc"},
- X {"_swplo"},
- X {NULL},
- X};
- X
- Xstruct tm *localtime();
- Xstruct passwd *getpwuid(), *getpwnam();
- Xstruct group *getgrgid();
- Xchar *strrchr(), *malloc();
- X
- X#define DAY (60L*60L*24)
- X#define HOUR (60L*60L)
- X#define MIN (60L)
- X
- X#define static
- X
- Xstatic void endw(), pcmd();
- Xstatic int die(), paint(), grandparent(), pgsort(), rgetc(), showtty();
- Xstatic struct proc *ppid();
- X
- Xstatic
- Xvoid
- Xendw()
- X{
- X move(LINES - 1, 0);
- X clrtoeol();
- X refresh();
- X endwin();
- X}
- X
- Xint dying = 0;
- Xint repaint = 0;
- X
- Xstatic
- Xint
- Xdie(s)
- X{
- X signal(s, die);
- X dying = 1;
- X}
- X
- Xstatic
- Xint
- Xpaint(s)
- X{
- X signal(s, paint);
- X repaint = 1;
- X}
- X
- Xstruct proc *proctab;
- Xint numproc;
- X
- X/*
- X * find the ultimate parent of a tree of processes
- X */
- X
- Xstatic
- Xstruct proc *
- Xppid(p)
- X register struct proc *p;
- X{
- X register struct proc *pp;
- X
- X if (p->p_ppid == 1)
- X return p;
- X for (;;) {
- X for (pp = proctab; pp < &proctab[numproc]; pp++)
- X if (pp->p_pid == p->p_ppid)
- X break;
- X if (pp == &proctab[numproc])
- X return 0;
- X if (pp->p_ppid == 1)
- X return pp;
- X p = pp;
- X }
- X}
- X
- X/*
- X * similar to ppid(), but stop when a parent process is the other specified
- X * process; return 1 if it's found, 0 if not
- X */
- X
- Xstatic
- Xint
- Xgrandparent(p, gp)
- X register struct proc *p, *gp;
- X{
- X register struct proc *pp;
- X
- X if (p->p_ppid < 2)
- X return 0;
- X for (;;) {
- X for (pp = proctab; pp < &proctab[numproc]; pp++)
- X if (pp->p_pid == p->p_ppid)
- X break;
- X if (pp == &proctab[numproc])
- X return 0;
- X if (pp == gp)
- X return 1;
- X if (pp->p_ppid < 2)
- X return 0;
- X p = pp;
- X }
- X}
- X
- X/*
- X * sort function for qsort() of process table
- X * order by process group, then parent of "tree" of processes within group,
- X * then relative hierarchy within "tree".
- X * if tree parent's pid is same as pgrp, always sorts before other parents
- X */
- X
- Xstatic
- Xint
- Xpgsort(p1, p2)
- X register struct proc *p1, *p2;
- X{
- X register struct proc *p1p, *p2p;
- X
- X /* sort by process group first... */
- X if (p1->p_pgrp != p2->p_pgrp)
- X return p1->p_pgrp - p2->p_pgrp;
- X /* sort by great^n-grandparent */
- X if ((p1p = ppid(p1)) != (p2p = ppid(p2))) {
- X if (p1p->p_pgrp == p1p->p_pid)
- X return -1;
- X if (p2p->p_pgrp == p2p->p_pid)
- X return 1;
- X return p1p->p_pid - p2p->p_pid;
- X }
- X /* great^n-grandparent comes first, always */
- X if (p1->p_ppid < 2)
- X return -1;
- X if (p2->p_ppid < 2)
- X return 1;
- X /* follow hierarchy up searching for common ancestry */
- X if (grandparent(p1, p2))
- X return 1;
- X if (grandparent(p2, p1))
- X return -1;
- X /* this shouldn't happen... */
- X return 0;
- X}
- X
- Xint
- Xmain(argc, argv)
- X char **argv;
- X{
- X struct var vars;
- X register struct proc *scanp, *insp;
- X int depth, ptr, pgrp, ruid, rgid;
- X int stack[20];
- X struct user *u;
- X struct passwd *pw;
- X struct group *gr;
- X
- X if (argc == 2)
- X idlef = (strcmp(argv[1], "-m") == 0);
- X signal(SIGHUP, die);
- X signal(SIGQUIT, die);
- X signal(SIGINT, paint);
- X signal(SIGTERM, die);
- X initscr();
- X cbreak();
- X noecho();
- X nl();
- X if (!cursor_address || !*cursor_address)
- X {
- X endw();
- X fprintf(stderr, "I can't use your terminal.\n");
- X exit(1);
- X }
- X if (nlist(KERNEL, kernel) == -1)
- X {
- X endw();
- X perror(KERNEL);
- X exit(2);
- X }
- X if ((utmp = open(UTMP, 0)) == -1)
- X {
- X endw();
- X perror(UTMP);
- X exit(1);
- X }
- X if ((kfd = open(KMEM, 0)) == -1)
- X {
- X endw();
- X perror(KMEM);
- X exit(3);
- X }
- X lseek(kfd, kernel[0].n_value, 0);
- X read(kfd, &vars, sizeof vars);
- X nproc = vars.v_proc;
- X lseek(kfd, kernel[2].n_value, 0);
- X read(kfd, &swplo, sizeof swplo);
- X if ((mfd = open(PMEM, 0)) == -1)
- X {
- X endw();
- X perror(PMEM);
- X exit(4);
- X }
- X if ((sfd = open(SMEM, 0)) == -1)
- X {
- X endw();
- X perror(SMEM);
- X exit(5);
- X }
- X if ((dfd = open(DEV, 0)) == -1)
- X {
- X endw();
- X perror(DEV);
- X exit(6);
- X }
- X if ((proctab = (struct proc *) malloc(nproc * sizeof *proctab)) == 0)
- X {
- X endw();
- X fprintf(stderr, "Out of memory\n");
- X exit(6);
- X }
- X for (;;)
- X {
- X /* handle pending signals */
- X if (dying)
- X {
- X endw();
- X exit(0);
- X }
- X if (repaint)
- X {
- X repaint = 0;
- X clear();
- X }
- X /* prepare for output */
- X erase();
- X /* gobble proc */
- X lseek(kfd, (long) kernel[1].n_value, 0);
- X read(kfd, proctab, nproc * sizeof *proctab);
- X numproc = nproc;
- X /* zero out swapper and init */
- X memset(proctab, 0, 2 * sizeof *proctab);
- X insp = proctab;
- X /* prune proctab[] (and add user structures) */
- X for (scanp = proctab; scanp < &proctab[nproc]; scanp++)
- X {
- X switch (scanp->p_stat)
- X {
- X case 0:
- X case SWAIT:
- X case SIDL:
- X case SZOMB:
- X scanp->p_stat = 0;
- X numproc--;
- X continue;
- X default:
- X while (insp->p_stat != 0 && insp != scanp)
- X insp++;
- X if (insp != scanp)
- X {
- X memcpy(insp, scanp, sizeof *scanp);
- X scanp->p_stat = 0;
- X }
- X if (!(insp->p_wchan = malloc(sizeof (struct user))))
- X {
- X endw();
- X fprintf(stderr, "Out of memory\n");
- X exit(8);
- X }
- X if (insp->p_flag & SLOAD)
- X {
- X lseek(mfd, insp->p_addr[0].te_frameno * NBPC, 0);
- X read(mfd, insp->p_wchan, sizeof (struct user));
- X }
- X else
- X {
- X lseek(sfd, insp->p_addr[0].te_frameno * NBPC, 0);
- X read(sfd, insp->p_wchan, sizeof (struct user));
- X }
- X /* zap gettys, we could care less */
- X if (isgetty(insp))
- X {
- X insp->p_stat = 0;
- X free(insp->p_wchan);
- X scanp->p_stat = 0;
- X numproc--;
- X }
- X }
- X }
- X /* sort proctab[] by process group */
- X qsort(proctab, numproc, sizeof *proctab, pgsort);
- X /* print proctab[] */
- X pgrp = -1;
- X for (scanp = proctab; scanp < &proctab[numproc]; scanp++)
- X {
- X u = (struct user *) scanp->p_wchan;
- X ((struct user *) scanp->p_wchan)->u_procp = scanp;
- X if (scanp->p_pgrp != pgrp)
- X {
- X if (pgrp != -1)
- X addch('\n');
- X pgrp = scanp->p_pgrp;
- X if (!u->u_ttyp)
- X {
- X addstr("(no tty)");
- X move(stdscr->_cury, 40);
- X addstr("Process group detached from terminal\n");
- X ruid = u->u_ruid;
- X rgid = u->u_rgid;
- X }
- X else if (!showtty(scanp, u, &ruid, &rgid))
- X {
- X ruid = u->u_ruid;
- X rgid = u->u_rgid;
- X move(stdscr->_cury, 40);
- X addstr("Process group orphaned\n");
- X }
- X depth = -1;
- X }
- X for (ptr = depth; ptr >= 0; ptr--)
- X if (scanp->p_ppid == stack[ptr])
- X break;
- X stack[depth = ++ptr] = scanp->p_pid;
- X printw(" %5d ", scanp->p_pid);
- X if (u->u_uid == ruid)
- X addstr(" ");
- X else
- X {
- X setpwent();
- X if (pw = getpwuid(u->u_uid))
- X printw("%-8.8s ", pw->pw_name);
- X else
- X printw("%-8d ", u->u_uid);
- X }
- X if (u->u_gid == rgid)
- X addstr(" ");
- X else
- X {
- X setgrent();
- X if (gr = getgrgid(u->u_gid))
- X printw("%-8.8s ", gr->gr_name);
- X else
- X printw("%-8d ", u->u_gid);
- X }
- X printw("%*s ", depth * 2, "");
- X pcmd(u);
- X addch('\n');
- X free(u);
- X }
- X refresh();
- X sleep(5);
- X }
- X}
- X
- X/*
- X * print the command name and arguments (if possible) of a process
- X * for xenix, this prints u.u_psargs instead of groveling in core
- X */
- X
- Xstatic
- Xvoid
- Xpcmd(uinfo)
- X struct user *uinfo;
- X{
- X int c, d;
- X
- X for (c = PSARGSZ; c-- && uinfo->u_psargs[c] != '\0'; )
- X ;
- X if (!c)
- X printw("(%.*s)", DIRSIZ, uinfo->u_comm);
- X else
- X {
- X if (c > COLS - stdscr->_curx - 1)
- X c = COLS - stdscr->_curx - 1;
- X printw("%.*s", c, uinfo->u_psargs);
- X for (d = 0; d < c && uinfo->u_psargs[d] != ' '; d++)
- X ;
- X uinfo->u_psargs[d] = '\0';
- X for (; d >= 0 && uinfo->u_psargs[d] != '/'; d--)
- X ;
- X if (strncmp(uinfo->u_psargs + d + 1, uinfo->u_comm, DIRSIZ) != 0)
- X printw(" (%.*s)", DIRSIZ, uinfo->u_comm);
- X }
- X}
- X
- X/*
- X * print tty information for process; if process owner (pgrp) isn't logged in,
- X * return FALSE, else set *ruidp and *rgidp and return TRUE
- X */
- X
- Xstatic
- Xint
- Xshowtty(p, u, ruidp, rgidp)
- X struct proc *p;
- X struct user *u;
- X int *ruidp, *rgidp;
- X{
- X int isut;
- X struct tty t;
- X struct direct dev;
- X char *cp;
- X char ttyp[32], login[16];
- X struct stat sb;
- X struct utmp ut;
- X struct tm *tp;
- X struct passwd *pw;
- X long now;
- X
- X lseek(kfd, (long) u->u_ttyp, 0);
- X read(kfd, &t, sizeof t);
- X sb.st_rdev = -1;
- X lseek(dfd, 0L, 0);
- X while (read(dfd, &dev, sizeof dev) == sizeof dev)
- X {
- X strcpy(ttyp, DEV);
- X strncat(ttyp, dev.d_name, DIRSIZ);
- X ttyp[DIRSIZ + sizeof DEV] = '\0';
- X if (stat(ttyp, &sb) == -1 || (sb.st_mode & S_IFMT) != S_IFCHR)
- X continue;
- X if (sb.st_rdev == u->u_ttyd)
- X break;
- X }
- X if (sb.st_rdev != u->u_ttyd)
- X {
- X printw("(cdev %d/%d not found)", major(u->u_ttyd), minor(u->u_ttyd));
- X return 0;
- X }
- X if (t.t_pgrp != p->p_pgrp)
- X {
- X printw(" %-8.8s old", dev.d_name);
- X return 0;
- X }
- X lseek(utmp, 0L, 0);
- X while (isut = (read(utmp, &ut, sizeof ut) == sizeof ut))
- X if (ut.ut_type != USER_PROCESS)
- X continue;
- X else if (strncmp(ut.ut_line, dev.d_name, sizeof ut.ut_line) == 0)
- X break;
- X if (!isut || ut.ut_name[0] == '\0')
- X {
- X printw(" %-8.8s old", dev.d_name);
- X return 0;
- X }
- X printw("%-8.8s %-8.8s ", ut.ut_name, dev.d_name);
- X tp = localtime(&ut.ut_time);
- X time(&now);
- X if (now - ut.ut_time >= 86400)
- X printw(" %02d/%02d", tp->tm_mon + 1, tp->tm_mday);
- X else
- X printw(" %2d:%02d", tp->tm_hour, tp->tm_min);
- X if ((now -= (idlef? sb.st_mtime: sb.st_atime)) >= 86400)
- X printw(" %3dd", now / 86400);
- X else if (now >= 3600)
- X printw(" %2d:%02d", now / 3600, (now % 3600) / 60);
- X else if (now >= 60)
- X printw(" %3d", now / 60);
- X strncpy(login, ut.ut_name, sizeof ut.ut_name);
- X login[sizeof ut.ut_name] = '\0';
- X move(stdscr->_cury, 40);
- X setpwent();
- X if (!(pw = getpwnam(login)))
- X {
- X *ruidp = u->u_ruid;
- X *rgidp = u->u_rgid;
- X addstr("(user not in passwd file)\n");
- X }
- X else
- X {
- X *ruidp = pw->pw_uid;
- X *rgidp = pw->pw_gid;
- X for (cp = pw->pw_gecos; *cp && *cp != ','; cp++)
- X ;
- X *cp = '\0';
- X addstr(pw->pw_gecos);
- X addch('\n');
- X }
- X return 1;
- X}
- X
- X/*
- X * determine "getty-ness" of a process
- X */
- X
- Xisgetty(u)
- X struct proc *u;
- X{
- X struct utmp ut;
- X
- X lseek(utmp, 0L, 0);
- X while (read(utmp, &ut, sizeof ut) == sizeof ut)
- X if (ut.ut_pid == u->p_pid)
- X return ut.ut_type == LOGIN_PROCESS;
- X return 0;
- X}
- ________This_Is_The_END________
- if test `wc -c < si.c` -ne 11187; then
- echo 'shar: si.c was damaged during transit (should have been 11187 bytes)'
- fi
- fi ; : end of overwriting check
- echo 'x - si.man'
- if test -f si.man; then echo 'shar: not overwriting si.man'; else
- sed 's/^X//' << '________This_Is_The_END________' > si.man
- X.TH SI 1 "6 August 1989"
- X.SH NAME
- Xsi \- show system and user process trees
- X.SH SYNOPSIS
- X.B si
- X[
- X.B -m
- X]
- X.SH DESCRIPTION
- X.I Si
- Xdisplays indented process trees for processes other than the kernel,
- X.IR init ,
- Xand
- X.IR getty .
- XThe information displayed is the terminal name or
- X.BR "(no tty)" ,
- Xthe logged-in user,
- Xlogin time,
- Xidle time and user name,
- Xand for each process the process ID,
- Xeffective user and group IDs if different from the logged-in user's IDs,
- Xand the process name and arguments (if available).
- XIf the process name is not available or differs from the exec name,
- Xthe exec name is displayed in parentheses.
- XProcesses are displayed in order by process group,
- Xand within each process group by parent/child relationship.
- XThe only option is
- X.BR "-m" ,
- Xwhich causes
- X.I si
- Xto compute the idle time based on the tty's modification time
- Xrather than access time.
- XThis allows the user to select between the idle time displayed by
- X.I who
- Xor by
- X.IR w .
- X.PP
- XThe program is full-screen,
- Xusing
- X.I curses
- X(with
- X.IR M_TERMINFO )
- Xto control screen updates.
- XIt has two interactive commands:
- Xpress
- X.B quit
- X(usually
- X.BR Control-\\ )
- Xto exit,
- Xand
- X.B intr
- X(usually
- X.B DEL
- Xor
- X.BR Control-C )
- Xto force the screen to be redrawn after line noise or an
- Xunexpected screen message.
- X.SH FILES
- X.nf
- X.ta 2i
- X/dev/kmem system tables
- X/dev/mem processes in core
- X/dev/swap processes on swap
- X.fi
- X.SH SEE ALSO
- Xwho(1), w(1), finger(1)
- X.SH AUTHOR
- X.nf
- XBrandon S. Allbery
- Xtdi2!brandon (first version)
- Xncoast!allbery (second version)
- Xallbery@NCoast.ORG (third version)
- Xnc386!allbery (fourth version)
- X.fi
- X.SH HISTORY
- XFirst written at Tridelta Industries (tdi2), for System V Release 2.2.
- XThis version displayed quite a bit more information than the current one;
- Xit may be resurrected in the future.
- X.PP
- XA vastly simplified version was implemented on ncoast (nc68k);
- Xmuch of the information in the original was not available under
- XSystem III,
- Xso the program was restricted to process trees of logged-in users.
- X.PP
- XA third version was implemented much later,
- Xalso under System III.
- XIt displayed process trees for detached processes as well,
- Xand did a much better job of sorting processes.
- X.PP
- XThe fourth version was written for Xenix V/386,
- Xand amounted to a port of the third version to that environment.
- X.SH BUGS
- XThe program truncates lines that will not fit across the screen;
- Xon an 80-column screen under Xenix 386, this rarely causes problems.
- XIt also omits lines which will not fit,
- Xwhich is somewhat more serious on busy systems.
- X.PP
- XOccasionally,
- Xa race condition will cause
- X.I si
- Xto hang instead of exiting or redrawing the screen.
- XThis is a side effect of the old V7 signal mechanism;
- Xif SCO UNIX 386 implements SVR3 (more) reliable signals,
- Xthis will go away.
- XEnter the command again to retain control of the program.
- X(This may cause
- X.I si
- Xto exit without restoring the terminal state.)
- ________This_Is_The_END________
- if test `wc -c < si.man` -ne 2860; then
- echo 'shar: si.man was damaged during transit (should have been 2860 bytes)'
- fi
- fi ; : end of overwriting check
- exit 0
- --
- Brandon S. Allbery, moderator of comp.sources.misc allbery@uunet.uu.net
- Please send comp.sources.misc submissions to comp-sources-misc@<backbone>,
- related mail to comp-sources-misc-request@<backbone>, and personal mail ONLY
- to allbery@NCoast.ORG. You have only yourself to blame if you don't.
-
-
-