# /* 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #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 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 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