+#
+/*
+ ps - show process status - iiasa version (jek)
+ originally from harvard and/or CULC
+
+ flags are single letters
+ multiple flags can occur in one argument
+ dashes are optional but are needed to delimit lists of things
+ multiple lists are present(???)
+ flags that imply other arguments read the following arguments
+ until the end of the list or until an argument starts with dash
+ certain flags read exactly one argument
+ initialization (i flag) should be done for:
+ new users,
+ new kernel
+ parameters here must change to indicate:
+ new tty devices, max tty lines, tty letter changes
+ max users
+ new things to wait for
+ this program should be changed if:
+ proc structure makes this obsolete
+ etc
+ recompilation should occur if:
+ kernel structures and or paramters (nproc etc.) change
+ any above changes of course
+
+ flags are:
+ a - show all processes that have pgrps except shells
+ b - show background (not detached)
+ c - show child times instead of process times
+ d - show detached processes inherited by init
+ e - show the environment with the args
+ f - show foreground jobs, connected to tty
+ g - show processes in given pgrps
+ h - unused
+ i - perform initialization (implies 'n')
+ j,k - unused
+ l - print long format. includes most good stuff
+ m - specify different memory file (file is next arg)
+ n - show no processes
+ o - unused
+ p - show only processes whose id's are in list (following args)
+ q - unused
+ r - repeat indefinitely (number of r's = seconds or r#)
+ s - show stopped processes
+ t - show only processes associated with ttys in list (following)
+ u - show only processes (or ancestors of) for users in list
+ v - be verbose - show the most information
+ w - wide format, show entire argument list (up to 512 chars)
+ x - show unattached processes - no pgrp. a+x gives shells also
+ y - unused
+ z - show zombies
+ A - show ALL information possible
+ B - show busy processes
+ F - go fast, avoid swap space.
+ G - print pgrp
+ U - use different UNIX file (next arg)
+ S - show size
+ T - show tty information
+ W - print wait channels in hex
+*/
+
+#include <signal.h>
+#include <h/param.h>
+#include <h/dir.h>
+#include <h/user.h>
+#include <h/proc.h>
+#include <h/pte.h>
+#include <h/vm.h>
+#include <h/inode.h>
+#include <h/file.h>
+#include <h/buf.h>
+#include <h/text.h>
+#include <h/tty.h>
+#include <h/conf.h>
+#include <nlist.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <pwd.h>
+
+
+#define TRUE 1
+#define FALSE 0
+#define INTPPG (NBPG/sizeof(int))
+#define MAXARGPG 5
+
+#define Usrptmap ((struct pte *)info.kaddr[ausrptmap])
+#define usrpt ((struct pte *)info.kaddr[ausrpt])
+#define cswitch ((struct cdevsw *)info.kaddr[acdevsw])
+struct proc *proc, *kproc;
+struct text *text, *ktext;
+struct buf *buf, *swbuf;
+struct inode *inode;
+int nproc, ntext, hz, nbuf, ninode, nfile, nswbuf;
+union {
+ struct user user;
+ char upages[UPAGES][NBPG];
+} user;
+int pad1; /* supposedly to aviod hardware problem reading /dev/mem */
+struct pte pagetable[UPAGES + MAXARGPG]; /* for users page table */
+int pad2; /* supposedly to aviod hardware problem reading /dev/mem */
+
+#define u user.user
+#define MSPID 2 /* max system pid, not to considered BUSY */
+
+#define MAXUSERS 256 /* total different users */
+#define UNAMELENGTH 8 /* length of a user name */
+#define NSPEC 15 /* number of specified things (proc, user, tty */
+#define MAXTTYS 100
+
+/* definitions to reuse uninteresting proc table entries for linked lists */
+
+struct procinfo { /* structure to use for */
+ char *pi_cmd; /* attaching a time */
+ struct ttyline *pi_tty;
+ long pi_time; /* and an arg string to a proc */
+};
+
+#define p_next p_link /* pointer to next proc in global list */
+#define p_bro p_rlink /* next process with same parent */
+#define p_son p_xlink /* first child of this process */
+#define pinfo(p) (*((struct procinfo **)&p->p_sig))
+#define procsize(p) ((p)->p_tsize + (p)->p_dsize + (p)->p_ssize)
+ /* size of process */
+#define ABS(x) ((int)(x) & ~0x80000000) /* clear top bit - type int */
+#define K 1024
+#define KSHIFT 10
+
+#define msize(x) (x >> (KSHIFT-PGSHIFT))
+
+#define USERPAGE 0 /* flag for pread - read user page */
+#define TOPMEM 1 /* flag for pread - read top of mem */
+
+struct proc *plist;
+int mypid; /* pid of this process */
+
+char Aflag, aflag, Bflag, bflag, cflag, dflag, eflag, fflag, Fflag;
+char Gflag, iflag, lflag, mflag, nflag, rflag, Sflag, sflag, Tflag;
+char Uflag, uflag, vflag, wflag, xflag, nxflag, Wflag, zflag;
+int select; /* flag indicating process selection */
+
+int ntotal, nbusy, nloaded, nswapped;
+int ktotal, kbusy, kloaded, kswapped;
+
+/* specified users, ttys, pids, pgrps */
+union numptr {
+ int nm_int;
+ char *nm_ptr;
+};
+
+union ttyptr {
+ struct ttyline *ty_line;
+ char *ty_ptr;
+};
+
+union numptr pids[NSPEC], *ppids = pids; /* specified process ids */
+union numptr grps[NSPEC], *pgrps = grps; /* specified groups */
+union numptr uids[NSPEC], *puids = uids; /* specified user ids */
+union ttyptr ttys[NSPEC], *pttys = ttys; /* specified ttys */
+
+/* files needed by ps */
+
+char *memf = "/dev/mem"; /* default memory file */
+int mem; /* memory file descriptor */
+char *kmemf = "/dev/kmem"; /* virtual memory file */
+int kmem; /* virtual memory file descriptor */
+char *symf = "/vmunix"; /* default symbol file */
+char *swapf = "/dev/swap"; /* default swap file */
+int swap; /* swap area file descriptor */
+char *infof = "/etc/spsinfo"; /* default info save file */
+int infofd; /* info file descriptor */
+
+/* variables read from the kernel */
+
+struct nlist namelist[] = {
+#define aproc 0
+ {"_proc"},
+#define aswapdev 1
+ {"_swapdev"},
+#define aswplo 2
+ {"_swplo"},
+#define answbuf 3
+ {"_nswbuf"},
+#define atext 4
+ {"_text"},
+#define abuf 5
+ {"_buf"},
+#define abfreeli 6
+ {"_bfreelist"},
+#define akl11 7
+ {"_kl11"},
+#define adh11 8
+ {"_dh11"},
+#define alpdt 9
+ {"_lp_softc"},
+#define albolt 10
+ {"_lbolt"},
+#define atout 11
+ {"_tout"},
+#define arunin 12
+ {"_runin"},
+#define arunout 13
+ {"_runout"},
+#define aipc 14
+ {"_ipc"},
+#define afile 15
+ {"_file"},
+#define ainode 16
+ {"_inode"},
+#define amaplock 17
+ {"_maplock"},
+#define acoremap 18
+ {"_coremap"},
+#define aswapmap 19
+ {"_swapmap"},
+#define au 20
+ {"_u"},
+#define adz11 21
+ {"_dz_tty"},
+#define aetext 22
+ {"_etext"},
+#define ausrptmap 23
+ {"_Usrptmap"},
+#define ausrpt 24
+ {"_usrpt"},
+#define achtbuf 25
+ {"_chtbuf"},
+#define arhtbuf 26
+ {"_rhtbuf"},
+#define ahpbuf 27
+ {"_hpbuf"},
+#define aswbuf 28
+ {"_swbuf"},
+#define arswbuf 29
+ {"_rswbuf"},
+#define acons 30
+ {"_cons"},
+#define ark7 31
+ {"_rrk7buf"},
+#define achrfclist 32
+ {"_Chrfclist"},
+#define anproc 33
+ {"_nproc"},
+#define antext 34
+ {"_ntext"},
+#define anbuf 35
+ {"_nbuf"},
+#define ahz 36
+ {"_hz"},
+#define aninode 37
+ {"_ninode"},
+#define anfile 38
+ {"_nfile"},
+#define answap 39
+ {"_nswap"},
+#define acdevsw 40
+ {"_cdevsw"},
+#define aChconntab 41
+ {"_Chconntab"},
+#define MAXSYMBOLS 42
+ {"", 0, 0},
+};
+
+/* this structure is read from info file or initialized (iflag) */
+
+struct {
+ caddr_t kaddr[MAXSYMBOLS]; /* useful kernel addresses */
+ char unames[MAXUSERS][UNAMELENGTH]; /* user names */
+ struct ttyline {
+ struct tty *l_addr; /* address of ttystruct */
+ unsigned l_pgrp; /* process group */
+ char l_name[2]; /* name */
+ dev_t l_dev; /* device number */
+ } ttyline[MAXTTYS];
+
+} info;
+int swapdev; /* major, minor of swap device */
+int swplo; /* unix swap disk offset */
+int nswap; /* unix swap space size */
+
+struct ttyline notty = {0, 0, {"- "}};
+
+/* flags for once only activities (once per repeat) */
+
+int heading;
+int coreinit, core;
+char *topmem;
+int arglength;
+char *getcore(), *store(), *waitingfor(), *getcmd(), *strcat(), *brk();
+
+main(argc,argv)
+char *argv[];
+{
+ register char *cp, **ap;
+ register int i;
+ int myuid;
+ extern char _sobuf[];
+
+ if ((myuid = getuid()) == 0)
+ nice(-100);
+
+ setbuf(stdout, _sobuf);
+ select = 0;
+ for (ap = &argv[1]; --argc; ap++) {
+ for (cp = *ap; *cp;) {
+ switch (*cp++) {
+ case '-':
+ continue;
+ case 'A': /* EVERYTHING */
+ Aflag++;
+ continue;
+ case 'a': /* all procs attached to ttys */
+ bflag++; /* include background */
+ fflag++; /* include foreground */
+ dflag++; /* include detached */
+ aflag++; /* include shells */
+ select++;
+ continue;
+ case 'b': /* all background processes */
+ bflag++;
+ select++;
+ continue;
+ case 'B': /* all busy processes */
+ Bflag++;
+ select++;
+ lflag++;
+ continue;
+ case 'c':
+ cflag++;
+ lflag++;
+ continue;
+ case 'd': /* detached processes */
+ dflag++;
+ select++;
+ continue;
+ case 'e':
+ eflag++;
+ continue;
+ case 'f': /* foreground only */
+ fflag++;
+ select++;
+ continue;
+ case 'F': /* go fast, don't touch swap */
+ Fflag++;
+ continue;
+ case 'G': /* print pgrp */
+ Gflag++;
+ continue;
+ case 'g': /* specify process gourp */
+ select++;
+ while (argc > 1) {
+ if (**++ap == '-') {
+ ap--;
+ break;
+ }
+ --argc;
+ if (pgrps >= &grps[NSPEC])
+ prexit("%a: too many groups\n");
+ (pgrps++)->nm_int = atoi(*ap);
+ }
+ if (pgrps == grps)
+ (pgrps++)->nm_int = getpgrp();
+ continue;
+ case 'i': /* initialize info file */
+ if (myuid != 0) /* must be super user */
+ goto def;
+ iflag++;
+ nflag++;
+ Uflag++;
+ continue;
+ case 'l': /* long output */
+ lflag++;
+ continue;
+ case 'm': /* use designated memory file */
+ if (myuid != 0) /* must be super user */
+ goto def;
+ if (argc-- < 2 || **++ap == '-')
+ prexit("%a: missing memory file\n");
+ memf = *ap;
+ mflag++;
+ continue;
+ case 'n':
+ select++;
+ nflag++;
+ continue;
+ case 'p': /* only designated processes */
+ select++;
+ while (argc > 1) {
+ if (**++ap == '-') {
+ ap--;
+ break;
+ }
+ --argc;
+ if (ppids >= &pids[NSPEC])
+ prexit("%a: too many pids\n");
+ (ppids++)->nm_int = atoi(*ap);
+ }
+ continue;
+ case 'r': /* repeat every <number> seconds */
+ if (myuid != 0)
+ goto def;
+ rflag++;
+ for (i = 0; *cp >= '0' && *cp <= '9'; cp++)
+ i = i * 10 + *cp - '0';
+ if (i)
+ rflag = i;
+ continue;
+ case 'U': /* use designated symbol file */
+ if (myuid != 0)
+ goto def;
+ if (argc-- < 2 || **++ap == '-')
+ prexit("%a: missing symbol file\n");
+ symf = *ap;
+ Uflag++;
+ continue;
+ case 's':
+ sflag++;
+ select++;
+ continue;
+ case 'S':
+ Sflag++;
+ continue;
+ case 'T':
+ Tflag++;
+ continue;
+ case 't': /* on designated tty(s) */
+ select++;
+ while (argc > 1) {
+ if (**++ap == '-') {
+ ap--;
+ break;
+ }
+ --argc;
+ if (pttys >= &ttys[NSPEC])
+ prexit("%a: too many ttys\n");
+ (pttys++)->ty_ptr = *ap;
+ }
+ if (pttys == ttys) {
+ char *ttyname();
+
+ if ( (pttys->ty_ptr = ttyname(2)) == 0)
+ prexit("%a: unknown tty\n");
+ else if (strcmp("/dev/console", pttys->ty_ptr) == 0)
+ (pttys++)->ty_ptr = "co";
+ else
+ (pttys++)->ty_ptr +=
+ sizeof("/dev/tty") - 1;
+ }
+ continue;
+ case 'u': /* specific user name */
+ aflag++;
+ select++;
+ puids = &uids[0];
+ while (argc > 1) {
+ if (**++ap == '-') {
+ ap--;
+ break;
+ }
+ --argc;
+ if (puids >= &uids[NSPEC])
+ prexit("%a: too many users\n");
+ (puids++)->nm_ptr = *ap;
+ }
+ if (puids == &uids[0])
+ (puids++)->nm_int = myuid;
+ continue;
+ case 'v': /* most verbose output */
+ vflag++;
+ lflag++;
+ continue;
+ case 'W':
+ Wflag++;
+ continue;
+ case 'w': /* wide form (all arguments) */
+ wflag++;
+ continue;
+ case 'x': /* include un-owned procs */
+ xflag++;
+ select++;
+ continue;
+ case 'z': /* include only zombies */
+ zflag++;
+ select++;
+ continue;
+ def:
+ default:
+ prexit("%a: unknown switch: %c\n", *--cp);
+ }
+ break;
+ }
+ }
+
+/* these lengths are kludgely tuned to make things not exceed 79 columns */
+ arglength = 60;
+ if (lflag)
+ arglength -= 28;
+ if (vflag)
+ arglength -= 14;
+ if ((mem = open(memf, 0)) < 0)
+ prexit("%a: cannot read system memory: %s\n", memf);
+ if ((kmem = open(kmemf, 0)) < 0)
+ prexit("%a: cannot read system virtural memory: %s\n", kmemf);
+ if (!Fflag && (swap = open(swapf, 0)) <0)
+ prexit("%a: cannot read swap device: %s\n", swapf);
+
+ if (!iflag)
+ if ((i = open(infof, 0)) < 0)
+ prexit("%a: cannot open info file\n");
+ else if (read(i, &info, sizeof info) != sizeof info)
+ prexit("%a: cannot read info file\n");
+ else
+ close(i);
+ if (Uflag) {
+ struct nlist *np;
+ if ((i = open(symf, 0)) < 0)
+ prexit("%a: can't read symbol file\n");
+ close(i);
+ nlist(symf, namelist);
+ for (np = namelist; np < &namelist[MAXSYMBOLS]; np++)
+ if (np->n_value == 0)
+ fprintf(stderr, "%a: can't find symbol: %s\n",
+ np->n_name);
+ if (namelist[0].n_value == -1)
+ prexit("%a: cannot read symbol file: %s\n", symf);
+ for (i = 0; i < MAXSYMBOLS; i++)
+ info.kaddr[i] = (caddr_t)namelist[i].n_value;
+ info.kaddr[aetext] = (caddr_t)( ((unsigned)info.kaddr[aetext] + 63) & ~63);
+ }
+ if (iflag) {
+ readusers();
+ ttyinit();
+ if ((infofd = creat(infof, 0600)) < 0)
+ prexit("%a: cannot create info file\n");
+ if ((i = write(infofd, &info, sizeof info)) != sizeof info) {
+ if (i == -1)
+ perror(0);
+ prexit("%a: cannot write info file: %d\n", i);
+ }
+ close(infofd);
+ }
+ lseek(kmem, (long)info.kaddr[aswapdev], 0);
+ read(kmem, &swapdev, sizeof(swapdev) );
+ lseek(kmem, (long)info.kaddr[aswplo], 0);
+ read(kmem, &swplo, sizeof(swplo) );
+ lseek(kmem, (long)info.kaddr[answap], 0);
+ read(kmem, &nswap, sizeof(nswap) );
+ lseek(kmem, (long)info.kaddr[anproc], 0);
+ read(kmem, &nproc, sizeof(nproc) );
+ lseek(kmem, (long)info.kaddr[antext], 0);
+ read(kmem, &ntext, sizeof(ntext) );
+ lseek(kmem, (long)info.kaddr[anbuf], 0);
+ read(kmem, &nbuf, sizeof(nbuf) );
+ lseek(kmem, (long)info.kaddr[abuf], 0);
+ read(kmem, &buf, sizeof(buf) );
+ lseek(kmem, (long)info.kaddr[answbuf], 0);
+ read(kmem, &nswbuf, sizeof(nswbuf) );
+ lseek(kmem, (long)info.kaddr[aswbuf], 0);
+ read(kmem, &swbuf, sizeof(swbuf) );
+ lseek(kmem, (long)info.kaddr[aninode], 0);
+ read(kmem, &ninode, sizeof(ninode) );
+ lseek(kmem, (long)info.kaddr[ainode], 0);
+ read(kmem, &inode, sizeof(inode) );
+ lseek(kmem, (long)info.kaddr[ahz], 0);
+ read(kmem, &hz, sizeof(hz) );
+ lseek(kmem, (long)info.kaddr[aproc], 0);
+ read(kmem, &kproc, sizeof(kproc));
+ lseek(kmem, (long)info.kaddr[atext], 0);
+ read(kmem, &ktext, sizeof(ktext));
+ proc = (struct proc *)getcore(nproc * sizeof(struct proc));
+ text = (struct text *)getcore(ntext * sizeof(struct text));
+ if (puids != &uids[0] && uids[0].nm_int != myuid)
+ usersetup();
+ if (!select) {
+ mypid = getpid();
+ (puids++)->nm_int = myuid;
+ nxflag++;
+ select++;
+ }
+ ttysetup();
+ topmem = 0;
+ do {
+ heading = 0; /* reset heading flag (for repeat) */
+ core = coreinit = 0; /* reset core flag (for repeat) */
+ lseek(kmem, (long)kproc, 0);
+ read(kmem, proc, nproc * sizeof(struct proc));
+ lseek(kmem, (long)ktext, 0);
+ read(kmem, text, ntext * sizeof(struct text));
+ needed();
+ mktree();
+ action (plist, 0);
+ printf("%d processes (%dkb), %d busy (%dkb), %d loaded (%dkb)\n",
+ ntotal, (ctob(ktotal) + 1023) / 1024,
+ nbusy, (ctob(kbusy) + 1023) / 1024,
+ nloaded, (ctob(kloaded) + 1023) / 1024);
+ fflush(stdout);
+ } while (rflag && sleep(rflag) == 0);
+ exit(0);
+}
+
+/* read the passwd file and fill in the user name arrays */
+readusers()
+{
+ register struct passwd *pw;
+ struct passwd *getpwent();
+
+ while((pw = getpwent()) != 0) {
+ if(info.unames[pw->pw_uid][0] == '\0')
+ strcpyn(info.unames[pw->pw_uid], pw->pw_name, UNAMELENGTH);
+ }
+ endpwent();
+}
+
+/* check for specified user names */
+
+usersetup()
+{
+ register int i;
+ register union numptr *ip;
+
+ for (ip = uids; ip < puids; ip++) {
+ for (i = 0; i < MAXUSERS; i++)
+ if (equalu(ip->nm_ptr, info.unames[i]))
+ goto cont2;
+ prexit("%a: unknown user: %s\n", ip->nm_ptr);
+ cont2:
+ ip->nm_int = i;
+ }
+}
+
+/* compare a fixed length user name */
+
+equalu(u1, u2)
+register char *u1, *u2;
+{
+ register int i = 0;
+
+ while (*u1++ == *u2)
+ if (!*u2++ || ++i == UNAMELENGTH)
+ return 1;
+ return 0;
+}
+
+/*
+ * Initialize the tty part of the info structure
+ */
+ttyinit()
+{
+ struct direct dir;
+ struct stat sbuf;
+ int fd;
+ register struct ttyline *lp = info.ttyline;
+
+ if ((fd = open("/dev", 0)) < 0)
+ prexit("%a: can't open /dev\n");
+ chdir("/dev");
+ while (read(fd, (char *)&dir, sizeof(dir)) == sizeof(dir)) {
+ if (dir.d_ino == 0 ||
+ strncmp("tty", dir.d_name, 3) != 0 &&
+ strcmp("console", dir.d_name) != 0)
+ continue;
+ if (dir.d_name[sizeof("tty") - 1] == 'C')
+ continue;
+ if (lp >= &info.ttyline[MAXTTYS])
+ prexit("%a: too many ttys in /dev\n");
+ if (dir.d_name[0] == 'c') {
+ lp->l_name[0] = 'c';
+ lp->l_name[1] = 'o';
+ } else {
+ lp->l_name[0] = dir.d_name[3];
+ lp->l_name[1] = dir.d_name[4];
+ }
+ stat(dir.d_name, &sbuf);
+ lp->l_dev = sbuf.st_rdev;
+ lseek(kmem, (long)&cswitch[major(sbuf.st_rdev)].d_ttys, 0);
+ read(kmem, (char *)&lp->l_addr, sizeof(lp->l_addr));
+ lp->l_addr += minor(sbuf.st_rdev);
+ lp++;
+ }
+ close(fd);
+}
+ttysetup()
+{
+ register struct ttyline *lp;
+ register char *cp;
+ union ttyptr *tp;
+ struct tty tty;
+
+ for (lp = info.ttyline; lp->l_name[0]; lp++) {
+ lseek(kmem, (long)lp->l_addr, 0);
+ if (read(kmem, &tty, sizeof tty) != sizeof tty)
+ prexit("%a: read error in kmem\n");
+ lp->l_pgrp = tty.t_pgrp;
+ if (Tflag)
+ printf("tty%-.2s: dev:%2d,%2d addr:%6x, rawq:%4d, canq:%d, outq:%4d, pgrp:%5d\n",
+ lp->l_name, major(lp->l_dev), minor(lp->l_dev),
+ ABS(lp->l_addr), tty.t_rawq.c_cc,
+ tty.t_canq.c_cc, tty.t_outq.c_cc,
+ tty.t_pgrp);
+ }
+#ifdef CHAOS
+ mkchttys(lp);
+#endif
+ /* now fix up specified ttys */
+
+ for (tp = &ttys[0]; tp < pttys; tp++) {
+ for (lp = info.ttyline; lp->l_name[0]; lp++)
+ if (strcmpn(tp->ty_ptr, lp->l_name, 2) == 0) {
+ tp->ty_line = lp;
+ goto cont2;
+ }
+ prexit("%a: unknown tty name: %c\n", tp->ty_ptr);
+ cont2:;
+ }
+}
+
+/*
+ * Determine which procs are needed for the printout
+ * and add these to a list of needed processes (plist)
+ */
+needed()
+{
+ register struct proc *p, *pp;
+ register struct text *tp;
+ struct ttyline *lp;
+ int ok;
+
+ plist = 0;
+ nswapped = ntotal = nbusy = nloaded = 0;
+ kswapped = ktotal = kbusy = kloaded = 0;
+
+ for (tp = text; tp < text + ntext; tp++)
+ if (tp->x_count) {
+ ktotal += tp->x_size;
+ if (!(tp->x_ccount))
+ kswapped += tp->x_size;
+ }
+
+ for (p = proc; p < proc + nproc; p++) {
+ if (!p->p_stat)
+ continue;
+ if (p->p_textp)
+ p->p_textp = &text[p->p_textp - ktext];
+ if (p->p_pptr) {
+ p->p_pptr = &proc[p->p_pptr - kproc];
+ if (p->p_pptr < proc || p->p_pptr >= &proc[nproc]) {
+ fprintf(stderr, "proc %d bad pptr\n", p->p_pid);
+ p->p_pptr = proc;
+ }
+ } else
+ p->p_pptr = proc;
+ }
+ for (p = &proc[0]; p < &proc[nproc]; p++) {
+ if (!p->p_stat)
+ continue;
+ ntotal++;
+ ktotal += procsize(p);
+ if (p->p_flag != SZOMB)
+ if (p->p_flag & SLOAD) {
+ nloaded++;
+ kloaded += procsize(p);
+ if ((tp = p->p_textp) && tp->x_count) {
+ tp->x_count = 0;
+ kloaded += tp->x_size;
+ }
+ } else {
+ nswapped++;
+ kswapped += procsize(p);
+ }
+ ok = FALSE;
+ if (p->p_stat == SRUN ||
+ p->p_stat == SSLEEP && (p->p_pri < PZERO && p->p_pid > MSPID)) {
+ nbusy++;
+ kbusy += procsize(p);
+ if ((tp = p->p_textp) && tp->x_ccount) {
+ tp->x_ccount = 0;
+ kbusy += tp->x_size;
+ }
+ if (Bflag)
+ ok = TRUE;
+ }
+ if (nflag)
+ continue;
+ if (zflag && p->p_stat == SZOMB)
+ ok = TRUE;
+ if (sflag && p->p_stat == SSTOP)
+ ok = TRUE;
+ if (select == 0 && mypid && p->p_pid == mypid)
+ continue;
+ if (p->p_pgrp == 0)
+ if (xflag)
+ ok = TRUE;
+ else if (nxflag)
+ continue;
+ if (dflag && p->p_pgrp != 0 && (p->p_flag & SDETACH) != 0)
+ ok = TRUE;
+ if (aflag && xflag && p->p_pgrp != 0 && (p->p_flag & SDETACH) == 0 &&
+ p->p_pptr == &proc[1])
+ ok = TRUE;
+ if (puids != uids) {
+ register union numptr *ip;
+
+ for (pp = p; pp > &proc[1]; pp = pp->p_pptr)
+ for (ip = uids; ip < puids; ip++)
+ if ((pp->p_uid & 0377) == ip->nm_int){
+ ok = TRUE;
+ goto uidok;
+ }
+ }
+ uidok:
+ if (pgrps != grps) {
+ register union numptr *ip;
+
+ for (pp = p; pp > &proc[1]; pp = pp->p_pptr)
+ for (ip = grps; ip < pgrps; ip++)
+ if (pp->p_pgrp == ip->nm_int) {
+ ok = TRUE;
+ goto pgrpok;
+ }
+ }
+ pgrpok:
+ if (ppids != pids) {
+ register union numptr *ip;
+
+ for (ip = pids; ip < ppids; ip++)
+ if (ip->nm_int == p->p_pid) {
+ ok = TRUE;
+ goto procok;
+ }
+ }
+ procok:
+ if (select && pttys == ttys && !fflag && !bflag && !ok)
+ continue;
+ if (getu(p) == 0) {
+ static struct procinfo fakep = {"--no upage--", ¬ty, 0};
+
+ if (select && !ok)
+ continue;
+ pinfo(p) = &fakep;
+ goto putonlist;
+ }
+ if (pttys != ttys && p->p_pgrp != 0) {
+ union ttyptr *ip;
+
+ for (ip = ttys; ip < pttys; ip++)
+ if (p->p_pgrp && p->p_pgrp == ip->ty_line->l_pgrp ||
+ p->p_stat == SSLEEP &&
+ p->p_wchan >= (char *)ip->ty_line->l_addr &&
+ p->p_wchan < (char *)ip->ty_line->l_addr +
+ sizeof (struct tty) ||
+ u.u_ttyd == ip->ty_line->l_dev) {
+ ok = TRUE;
+ break;
+ }
+ }
+ if (p->p_pgrp == 0)
+ lp = ¬ty;
+ else {
+ for (lp = info.ttyline; lp->l_name[0] != 0; lp++)
+ if (lp->l_dev == u.u_ttyd)
+ break;
+ if (lp->l_name[0] == 0)
+ lp = ¬ty;
+ else if (p->p_pptr != &proc[1]) {
+ if (fflag && p->p_pgrp == lp->l_pgrp)
+ ok = TRUE;
+ if (bflag && p->p_pgrp != lp->l_pgrp &&
+ (p->p_flag & SDETACH) == 0 &&
+ p->p_stat != SSTOP)
+ ok = TRUE;
+ }
+ }
+ if (select && !ok)
+ continue;
+ pinfo(p) = (struct procinfo *)getcore(sizeof (struct procinfo));
+ pinfo(p)->pi_time = u.u_vm.vm_utime + u.u_vm.vm_stime;
+ pinfo(p)->pi_tty = lp;
+ pinfo(p)->pi_cmd = getcmd(p);
+ putonlist:
+ /* we have a needed proc! */
+
+ p->p_next = plist;
+ plist = p;
+ p->p_son = p->p_bro = 0;
+ }
+}
+/*
+ * mktree - sort the needed processes by subtree and at the top by user
+ */
+mktree()
+{
+ register struct proc *p, *pp, *lp;
+ struct proc *op;
+ struct proc proot;
+
+ proot.p_bro = 0;
+
+ for (p = plist; p; p = p->p_next) { /* for all needed processes */
+ if (p->p_pptr > &proc[1]) {
+ for (pp = plist; pp; pp = pp->p_next)
+ if (pp == p->p_pptr) { /* if my parent */
+ if (lp = pp->p_son) { /* if siblings */
+ for (op = 0; lp && lp->p_pid <
+ p->p_pid;
+ lp = (op = lp)->p_bro)
+ ;
+ if (op) {
+ p->p_bro = lp;
+ op->p_bro = p;
+ break;
+ }
+ }
+ p->p_bro = lp; /* here if first or only */
+ pp->p_son = p;
+ break;
+ }
+ if (pp) /* if we found the parent */
+ continue;
+ }
+
+ /* we have a top level process, sort into top level list */
+
+ for (pp = (lp = &proot)->p_bro; pp; pp = (lp = pp)->p_bro)
+ if ((p->p_uid & 0377) < (pp->p_uid & 0377) ||
+ (p->p_uid & 0377) == (pp->p_uid & 0377) &&
+ p->p_pid < pp->p_pid)
+ break;
+ p->p_bro = lp->p_bro;
+ lp->p_bro = p;
+ }
+ plist = proot.p_bro;
+}
+
+action(p, md)
+register struct proc *p;
+register int md;
+{
+
+ if (p) {
+ printp(p, md);
+ if (p->p_son)
+ action(p->p_son, md+1);
+ if (p->p_bro)
+ action(p->p_bro, md);
+ }
+}
+
+/*
+ * Pretty print the output according to the switches.
+ */
+printp(p, md)
+register struct proc *p;
+{
+ register char *cp, *cp1;
+ char stat[10];
+ static int lastuid;
+ static char *statnames[] = {"Unk ", "Wait", "Wait", "Run ",
+ "Init", "Exit", "Stop"};
+
+ if (!heading) {
+ heading++;
+ printf("Ty User ");
+ if (lflag) {
+ printf("Stat");
+ if (vflag) printf(" Flgs Nice Pri ");
+ else printf(" ");
+ printf("Memory-kb Time Wait? ");
+ }
+ if (Aflag)
+ printf("Address Proc. Clock Alarm ");
+ if (Sflag)
+ printf("Size ");
+ if (Gflag)
+ printf("Group ");
+ printf("Proc# Command\n");
+ }
+ printf("%.2s%c", pinfo(p)->pi_tty->l_name,
+ p->p_pgrp == 0 ? ' ' :
+ p->p_flag & SDETACH ? '_' :
+ p->p_pgrp == pinfo(p)->pi_tty->l_pgrp ? '.' :
+ ' ');
+
+ if (md == 0) {
+ lastuid = p->p_uid & 0377;
+ cp = info.unames[lastuid];
+ if (*cp)
+ printf("%-8.8s ", cp);
+ else
+ printf("user%-4.4d ", lastuid);
+ } else {
+ if (md > 8)
+ md = 8;
+ printf("%*s*", md, "");
+ if ((p->p_uid & 0377) != lastuid) { /* setuid process! */
+ lastuid = p->p_uid & 0377;
+ cp = info.unames[lastuid];
+ } else
+ cp = "";
+ md = 8 - md;
+ printf("%-*.*s", md, md, cp);
+ }
+ if (lflag) {
+ cp = statnames[p->p_stat];
+ if (p->p_flag&SLOAD) {
+ for (cp1 = stat; *cp1 = *cp; cp1++, cp++)
+ if (*cp >= 'a' && *cp <= 'z')
+ *cp1 -= 'a' - 'A';
+ cp = stat;
+ }
+ printf("%-4.4s ", cp);
+ if (vflag) {
+ cp = stat;
+ if (p->p_flag & SSYS) *cp++ = 'U';
+ if (p->p_flag&SLOCK) *cp++ = 'L';
+ if (p->p_flag&STRC) *cp++ = 'T';
+ if (p->p_flag&SWTED) *cp++ = 'W';
+ if (p->p_flag&SSWAP) *cp++ = 'S';
+ while(cp < &stat[5]) *cp++ = ' ';
+ *cp = 0;
+ printf("%-4.4s ",stat);
+ if (p->p_nice != NZERO)
+ printf("%4d", p->p_nice - NZERO);
+ else
+ printf(" ");
+ if (p->p_stat != SZOMB)
+ printf("%4d ", p->p_pri);
+ else
+ printf(" ");
+ }
+ if (p->p_stat != SZOMB) {
+ printf("%4d", msize(procsize(p)) );
+ if (p->p_textp)
+ printf("+%4d ", msize(p->p_textp->x_size));
+ else
+ printf(" ");
+ prcpu(pinfo(p)->pi_time);
+ } else
+ printf(" ");
+ if (p->p_stat != SZOMB && p->p_stat != SRUN && p->p_stat != SSTOP)
+ if (!Wflag && (cp = waitingfor(p)))
+ printf("%-6.6s ", cp);
+ else printf("%6x ", ABS((int)p->p_wchan));
+ else printf(" ");
+ }
+ if (Aflag)
+ printf("%6x %6x %6d%6d ", p->p_addr,
+ (p - proc) * sizeof (struct proc) + info.kaddr[aproc],
+ p->p_time, p->p_clktim);
+ if (Sflag)
+ printf("%5x ", procsize(p) );
+ if (Gflag)
+ printf("%5D ", p->p_pgrp);
+ printf("%5D ", p->p_pid);
+ if (wflag)
+ printf("%s\n", pinfo(p)->pi_cmd);
+ else
+ printf("%-.*s\n", arglength, pinfo(p)->pi_cmd);
+}
+
+/* print cpu time */
+
+prcpu(time)
+long time;
+{
+ register unsigned i;
+
+ if (time < 0)
+ printf(" ---- ");
+ else if (time < (long)hz * 60 * 10) /* less than 10 minutes */
+ printf("%3d.%1d ",
+ (int)(time / hz),
+ (int)(time % hz / (hz / 10)));
+ else if (time < (long)hz * 60 * 60 * 10)/* less than 10 hours */
+ printf("%3d M ",
+ (int)((time + (hz * 60) / 2) / (hz * 60)));
+ else {
+ i = (time + ((long)hz * 60 * 60) / 2) /
+ ((long)hz * 60 * 60);
+ if (i < 1000)
+ printf("%3d H ", i);
+ else
+ printf(" ---- ");
+ }
+}
+/* Determine what a process is waiting for and describe it. */
+
+char *
+waitingfor(p)
+register struct proc *p;
+{
+ register caddr_t w;
+ register struct ttyline *lp;
+ register char *cp;
+
+ w = p->p_wchan;
+ if (w == (caddr_t)0)
+ return "null";
+ if (w >= (char *)kproc && w < (char *)(kproc + nproc))
+ return "child";
+ if (w >= (char *)swbuf && w < (char *)(swbuf + nswbuf))
+ return "swap";
+ if (w == info.kaddr[arswbuf])
+ return "rswap";
+ if (w >= (char *)buf && w < (char *)(buf + nbuf))
+ return "diskio";
+ if (w >= info.kaddr[afile] && w < info.kaddr[afile] + sizeof(struct file) * nfile)
+ return "file";
+ if (w >= (char *)inode && w < (char *)(inode + ninode))
+ switch((w - (char *)inode) % sizeof(struct inode)) {
+ case 1:
+ return "wpipe";
+ case 2:
+ return "rpipe";
+ case 3:
+ return "mutex";
+ case (int)&((struct inode *)0)->i_un.i_group.g_datq:
+ return "rmux";
+ default:
+ return "inode";
+ }
+ if (w == info.kaddr[achtbuf])
+ return "tapecn";
+ if (w == info.kaddr[ahpbuf])
+ return "rpdisk";
+ if (w == info.kaddr[ark7])
+ return "rkdisk";
+ if (w == info.kaddr[arhtbuf])
+ return "tapeio";
+ if (w == info.kaddr[alpdt])
+ return "printr";
+ if (w == info.kaddr[albolt])
+ return "lbolt";
+ if (w == info.kaddr[arunin])
+ return "runin";
+ if (w == info.kaddr[arunout])
+ return "runout";
+ if (w == info.kaddr[atout])
+ return "sleep";
+ if (w == info.kaddr[aipc])
+ return "ptrace";
+ if (w == info.kaddr[abfreeli])
+ return "buffer";
+ if (w == info.kaddr[amaplock])
+ return "ubmap";
+ if (w == info.kaddr[au])
+ return "pause";
+ if (w == info.kaddr[achrfclist])
+ return "chrfc";
+ for (lp = info.ttyline; lp->l_name[0]; lp++)
+ if (w >= (char *)lp->l_addr && w < (char *)lp->l_addr + sizeof (struct tty)) {
+#define TTY0 ((struct tty *)0)
+ switch(w - (char *)lp->l_addr) {
+ case (int)&TTY0->t_rawq:
+ cp = "rtty??";
+ break;
+ case (int)&TTY0->t_outq:
+ cp = "wtty??";
+ break;
+ case (int)&TTY0->t_state:
+ cp = "otty??";
+ break;
+ default:
+ cp = "?tty??";
+ }
+ cp[4] = lp->l_name[0];
+ cp[5] = lp->l_name[1];
+ return cp;
+ }
+ return 0;
+}
+
+getu(mproc)
+register struct proc *mproc;
+{
+ struct pte *pteaddr, apte;
+ register int i;
+ int ncl, size;
+
+ size = Sflag ? ctob(UPAGES) : sizeof (struct user);
+ if ((mproc->p_flag & SLOAD) == 0) {
+ lseek(swap, (long)ctob(mproc->p_swaddr), 0);
+ if (read(swap, (char *)&user.user, size) != size) {
+ fprintf(stderr, "%a: cant read u for pid %d from %s\n",
+ mproc->p_pid, swapf);
+ return (0);
+ }
+ return (1);
+ }
+ pteaddr = &Usrptmap[btokmx(mproc->p_p0br) + mproc->p_szpt - 1];
+ lseek(kmem, (long)(mflag ? ABS(pteaddr) : (int)pteaddr), 0);
+ if (read(kmem, (char *)&apte, sizeof(apte)) != sizeof(apte)) {
+ printf("%a: cant read indir pte to get u for pid %d from %s\n",
+ mproc->p_pid, swapf);
+ return (0);
+ }
+ lseek(mem, (long)
+ (ctob(apte.pg_pfnum+1) - (UPAGES+MAXARGPG) * sizeof (struct pte)),
+ 0);
+ if (read(mem, (char *)pagetable, sizeof(pagetable)) != sizeof(pagetable)) {
+ printf("%a: cant read page table for u of pid %d from %s\n",
+ mproc->p_pid, swapf);
+ return (0);
+ }
+ ncl = (size + NBPG*CLSIZE - 1) / (NBPG*CLSIZE);
+ while (--ncl >= 0) {
+ i = ncl * CLSIZE;
+ lseek(mem, (long)ctob(pagetable[MAXARGPG+i].pg_pfnum), 0);
+ if (read(mem, user.upages[i], CLSIZE*NBPG) != CLSIZE*NBPG) {
+ printf("%a: cant read page %d of u of pid %d from %s\n",
+ pagetable[MAXARGPG+i].pg_pfnum, mproc->p_pid, memf);
+ return(0);
+ }
+ }
+ return (1);
+}
+char *
+getcmd(p)
+register struct proc *p;
+{
+ struct pte apte;
+ char argbuf[MAXARGPG * NBPG], *argptr;
+ register int *ip;
+ register char *cp, *cp1;
+ int cc, nbad, i;
+
+ if (p->p_stat == SZOMB)
+ return "--Defunct--";
+ if ((p->p_flag&SLOAD) == 0 && Fflag)
+ return "--Swapped--";
+ if (p->p_flag & SSYS)
+ return p->p_pid == 0 ? "UNIX Swapper" :
+ p->p_pid == 2 ? "UNIX Pager" : "UNIX";
+ for (i = 0; i < MAXARGPG; i++) {
+ argptr = &argbuf[(MAXARGPG - 1 - i) * NBPG];
+ apte = pagetable[MAXARGPG - 1 - i];
+ if ((p->p_flag & SLOAD) && apte.pg_fod == 0 && apte.pg_pfnum ) {
+ lseek(mem, (long)ctob(apte.pg_pfnum), 0);
+ if (read(mem, argptr, NBPG) != NBPG)
+ return "---Mem read error (args)---";
+ } else if (Fflag)
+ goto cheap;
+ else {
+ lseek(swap, (long)ctob(u.u_smap.dm_map[0] + DMMIN - 1 - i), 0);
+ if (read(swap, argptr, NBPG) != NBPG)
+ return "---Swap read error (args)---";
+ }
+ /* Here block of stack is at argptr */
+ ip = (int *)&argptr[NBPG];
+ if (i == 0) {
+ *--ip = 0;
+ ip--;
+ }
+ while (ip > (int *)argptr && *--ip != 0)
+ ;
+ if (ip > (int *)argptr || *ip == 0)
+ break;
+ }
+ if (i >= MAXARGPG) {
+cheap:
+ argbuf[0] = '(';
+ strncpy(&argbuf[1], u.u_comm, sizeof(u.u_comm));
+ strcat(argbuf, ")");
+ return store(argbuf);
+ }
+ cp = (char *)(ip + 1);
+ if (*cp == '\0')
+ cp++;
+ nbad = 0;
+ for (cp1 = cp; cp1 < &argbuf[MAXARGPG*NBPG]; cp1++) {
+ cc = *cp1 & 0177;
+ if (cc == 0)
+ *cp1 = ' ';
+ else if (cc < ' ' || cc == 0177) {
+ if (++nbad >= 5) {
+ *cp1++ = ' ';
+ break;
+ }
+ *cp1 = '?';
+ } else if (!eflag && cc == '=') {
+ *cp1 = 0;
+ while (cp1 > cp && *--cp1 != ' ')
+ *cp1 = 0;
+ break;
+ }
+ }
+ while (*--cp1 == ' ')
+ *cp1 = 0;
+ if (!wflag && &cp[arglength] < (char *)&argbuf[MAXARGPG*NBPG - 1])
+ cp[arglength] = 0;
+ return store(cp);
+}
+
+/*
+ * Store a string in core for later use.
+ */
+char *
+store(cp)
+char *cp;
+{
+ register char *src, *dst, *svdst;
+
+ src = cp;
+ while (*src++);
+ svdst = getcore(src - cp);
+ dst = svdst;
+ src = cp;
+ while (*dst++ = *src++);
+ return(svdst);
+}
+
+/*
+ * Allocate and return a pointer to the asked for amount of core
+ */
+char *
+getcore(cnt)
+register int cnt;
+{
+ static char *corep;
+ register char *ip;
+ register int incr;
+ char *sbrk();
+
+ if (cnt > core) {
+ if (coreinit == 0) {
+ coreinit++;
+ if (topmem)
+ brk(topmem); /* after repeat!! */
+ else
+ topmem = sbrk(0);
+ corep = topmem;
+ }
+ incr = cnt > 4096 ? cnt : 4096;
+ if (sbrk(incr) == 0)
+ prexit("%a: out of memory!\n");
+ core += incr;
+ }
+ ip = corep;
+ core -= cnt;
+ corep += cnt;
+ return(ip);
+}
+#ifdef CHAOS
+#include "chunix/chsys.h"
+#include <chaos/chaos.h>
+
+mkchttys(lp)
+register struct ttyline *lp;
+{
+ register struct connection **cnp;
+ register int i;
+ struct tty tty;
+ struct connection *Chconntab[CHNCONNS];
+ struct connection conn;
+
+ lseek(kmem, (long)info.kaddr[aChconntab], 0);
+ read(kmem, (char *)Chconntab, sizeof(Chconntab));
+ for (i = 0, cnp = Chconntab; cnp < &Chconntab[CHNCONNS]; i++, cnp++) {
+ if (!*cnp)
+ continue;
+ lseek(kmem, (long)*cnp, 0);
+ read(kmem, (char *)&conn, sizeof(conn));
+ if ((conn.cn_flags & CHTTY) == 0)
+ continue;
+ lseek(kmem, (long)conn.cn_ttyp, 0);
+ read(kmem, (char *)&tty, sizeof(tty));
+ if (lp >= &info.ttyline[MAXTTYS])
+ prexit("%a: too many ttys\n");
+ lp->l_addr = conn.cn_ttyp;
+ lp->l_pgrp = tty.t_pgrp;
+ lp->l_dev = tty.t_dev;
+ lp->l_name[0] = 'C';
+ lp->l_name[1] = i < 10 ? '0' + i :
+ i - 10 <= 'z' - 'a' ? i - 10 + 'a' :
+ i - 10 - ('z' - 'a') + 'A';
+ if (Tflag)
+ printf("tty%-.2s: dev:%2d,%2d addr:%6x, rawq:%4d, canq:%d, outq:%4d, pgrp:%5d\n",
+ lp->l_name, major(lp->l_dev), minor(lp->l_dev),
+ ABS(lp->l_addr), tty.t_rawq.c_cc,
+ tty.t_canq.c_cc, tty.t_outq.c_cc,
+ tty.t_pgrp);
+ lp++;
+ }
+}
+#endif