2.9BSD/usr/contrib/sched/cmd/ps.c
/*
* ps - process status
* examine and print certain things about processes
*/
#define XSCHED 1 /* use .h defns for experimental scheduler version */
#include <stdio.h>
#include <a.out.h>
#include <core.h>
#include <sys/param.h>
#include <sys/proc.h>
#include <termio.h>
#include <sys/tty.h>
#include <sys/dir.h>
#include <sys/user.h>
#include <pwd.h>
#include <sys/file.h>
#include <sys/inode.h>
#include <sys/buf.h>
struct nlist nl[] = {
{ "_buf" }, /* must be first pair -- see wsyminit() !!! */
{ "_nbuf" },
{ "_proc" },
#define X_PROC 2
{ "_endproc" },
#define X_EPROC 3
{ "_file" },
{ "_endfile" },
{ "_inode" },
{ "_endinod" },
{ "_dztty" },
{ "_enddztt" },
{ "_dltty" },
{ "_enddltt" },
{ "_dhtty" },
{ "_enddhtt" },
{ "_qztty" },
{ "_endqztt" },
#define WSARRAY 8
/* end of WSARRAY, start of WSYMS */
{ "_runin" },
{ "_runout" },
{ "_bfreeli" },
{ "_swbuf1" },
{ "_swbuf2" },
#define WSYMS 5
/* end of special section of nlist */
{ "_swapdev" },
#define X_SWAPDEV (WSARRAY*2 + WSYMS)
{ "_swplo" },
#define X_SWPLO (X_SWAPDEV+1)
{ "" },
};
dev_t swapdev = NODEV;
struct proc mproc;
struct user u;
int chkpid;
int retcode=1;
int lflg;
int xflg;
char *tptr = 0;
char *kname = 0; /* name of "/dev/kmem" alternative */
char *uname = 0; /* name of "/unix" alternative */
long lseek();
char *gettty();
int nproc;
char *getptr();
char *strncmp();
int aflg;
int mem;
int swmem;
int swpflg = 1; /* try to read swap file?? -- don't if not /dev/kmem */
int swap;
daddr_t swplo;
char outbuf[BUFSIZ];
int ndev;
struct devl {
char dname[DIRSIZ];
dev_t dev;
} devl[256];
main(argc, argv)
int argc;
char *argv[];
{
register int i;
register char *ap;
int uid, puid;
extern char *_pgmname;
int nother = 0;
int nrun = 0;
int nsleep = 0;
int nwait = 0;
_pgmname = "ps";
setbuf(stdout, outbuf);
uid = getuid();
if (argc > 1) {
/* process flags */
argc--; argv++;
for(ap = *argv++,argc--; *ap; ap++)
switch(*ap){
case '-':
break;
case 'a':
aflg++;
break;
case 'x':
xflg++;
break;
case 't':
aflg++;
if(argc > 0){
argc--;
tptr = *argv++;
if(*tptr == '\0')
tptr = 0;
}
break;
case 'l':
lflg++;
break;
case 'k':
if(argc > 0){
kname = *argv++;
argc--;
if(*kname == '\0' || uid != 0)
kname = 0;
if(kname != 0)
swpflg = 0;
}
break;
case 'p':
if(argc > 0){
argc--;
chkpid = atoi(*argv++);
}
break;
case 'u':
if(argc > 0){
argc--;
uname = *argv++;
if(*uname == '\0' || uid != 0)
uname = 0;
}
break;
default:
panic("bad option character: '%c'",*ap);
}
}
if(uname == 0)
uname = "/unix";
nlist(uname, nl);
if (nl[X_PROC].n_type==0)
panic("No namelist: '%s'",uname);
if(kname == 0)
kname = "/dev/mem";
if ((mem = open(kname, 0)) < 0)
panic("%#Can't read '%s'",kname);
swmem = open(kname, 0);
/*
* read mem to find swap dev.
*/
lseek(mem, (long)nl[X_SWAPDEV].n_value, 0);
read(mem, (char *)&nl[X_SWAPDEV].n_value, sizeof(nl[X_SWAPDEV].n_value));
swapdev = nl[X_SWAPDEV].n_value;
/*
* Find base of swap
*/
lseek(mem, (long)nl[X_SWPLO].n_value, 0);
read(mem, (char *)&swplo, sizeof(swplo));
wsyminit(); /* set up wchan symbol table */
/*
* Locate proc table
*/
lseek(mem,(long)nl[X_EPROC].n_value,0);
read(mem,(char *) &nproc,sizeof(nproc));
nproc -= nl[X_PROC].n_value;
nproc /= sizeof(struct proc);
lseek(mem, (long)nl[X_PROC].n_value, 0);
getdev();
if (lflg)
printf("SIZE WAITING-FOR LEVEL USER PPID ");
printf(" TIME TTY PID COMMAND\n");
fflush(stdout);
for (i=0; i<nproc; i++) {
read(mem, (char *)&mproc, sizeof mproc);
switch(mproc.p_stat){
case SEMPTY:
continue;
case SRUN:
nrun++;
break;
case SSLEEP:
nsleep++;
break;
case SWAIT:
nwait++;
break;
default:
nother++;
}
if (mproc.p_pgrp==0 && xflg==0 && mproc.p_uid==0)
continue;
puid = mproc.p_uid;
if ((uid != puid && aflg==0) ||
(chkpid!=0 && chkpid!=mproc.p_pid))
continue;
if(prcom(puid)) {
printf("\n");
retcode=0;
}
}
if(lflg)
printf("\n%d active: %d running, %d sleeping, %d waiting, %d other\n",
nother+nrun+nsleep+nwait,nrun,nsleep,nwait,nother);
exit(retcode);
}
char devdir[] = "/dev/";
getdev()
{
#include <sys/stat.h>
register FILE *df;
struct stat sbuf;
struct direct dbuf;
char swapfile[sizeof(dbuf.d_name)+sizeof(devdir)];
char dnam[sizeof(dbuf.d_name)+sizeof(devdir)];
swapfile[0] = '\0';
if ((df = fopen("/dev", "r")) == NULL)
panic("%#Can't open /dev");
ndev = 0;
while (fread((char *)&dbuf, sizeof(dbuf), 1, df) == 1) {
if(dbuf.d_ino == 0)
continue;
strcpy(dnam,"/dev/");
strncat(dnam,dbuf.d_name,sizeof(dbuf.d_name));
dnam[sizeof(dnam)-1] = '\0';
if(stat(dnam, &sbuf) < 0)
continue;
if(swpflg && (sbuf.st_mode&S_IFMT) == S_IFBLK)
if(sbuf.st_rdev == swapdev){
strcpy(swapfile,dnam);
}
if ((sbuf.st_mode&S_IFMT) != S_IFCHR)
continue;
strncpy(devl[ndev].dname, dbuf.d_name, sizeof(devl[0].dname));
devl[ndev].dev = sbuf.st_rdev;
ndev++;
}
fclose(df);
if(swpflg){
if(swapfile[0] == '\0')
panic("can't find swapfile");
if((swap = open(swapfile, 0)) < 0)
panic("%#can't open '%s'",swapfile);
}
}
long
round(a, b)
long a, b;
{
long w = ((a+b-1)/b)*b;
return(w);
}
struct map {
long b1, e1; long f1;
long b2, e2; long f2;
};
struct map datmap;
int ffile;
prcom(puid)
{
char *user_name();
char abuf[512];
long addr;
register int *ip;
register char *cp, *cp1;
long tm;
int c, nbad;
register char *tp;
long txtsiz, datsiz, stksiz;
int septxt;
int lw=(lflg?25:50);
char **ap;
if(mproc.p_stat != SEMPTY && mproc.p_stat != SZOMB){
if (mproc.p_flag&SLOAD) {
addr = ctob((long)mproc.p_addr);
ffile = swmem;
} else{
addr = (mproc.p_addr+swplo)<<9;
ffile = swap;
}
if(ffile != swap || swpflg){
lseek(ffile, addr, 0);
if (read(ffile, (char *)&u, sizeof(u)) != sizeof(u))
return(0);
/* set up address maps for user pcs */
txtsiz = ctob(u.u_tsize);
datsiz = ctob(u.u_dsize);
stksiz = ctob(u.u_ssize);
septxt = u.u_sep;
datmap.b1 = (septxt ? 0 : round(txtsiz,TXTRNDSIZ));
datmap.e1 = datmap.b1+datsiz;
datmap.f1 = ctob(USIZE)+addr;
datmap.b2 = stackbas(stksiz);
datmap.e2 = stacktop(stksiz);
datmap.f2 = ctob(USIZE)+(datmap.e1-datmap.b1)+addr;
tp = gettty();
if (tptr && strncmp(tptr, tp, 2))
return(0);
}
if (lflg) {
printf("%3d %c",
(mproc.p_size + 15)>>4, /* K-bytes */
(mproc.p_flag & SLOAD)? '*':' ');
prwchan(mproc.p_wchan, mproc.p_stat);
printf(" %2d %2d %-7.7s %5u ",
mproc.p_level,
mproc.p_baslev,
user_name(puid),
mproc.p_ppid);
}
if(ffile != swap || swpflg){
tm = (u.u_utime + u.u_stime + 30)/60;
printf("%3D:%02D %-2.2s %5u ",
(tm / 60), (tm % 60),
tp,mproc.p_pid);
}
else {
printf(" %5u ",mproc.p_pid);
}
}
else { /* ZOMBIE or empty slot */
if (lflg) {
printf("%3d %c",
(mproc.p_size + 15)>>4, /* K-bytes */
(mproc.p_flag & SLOAD)? '*':' ');
prwchan(mproc.p_wchan, mproc.p_stat);
printf(" %2d %2d %-7.7s %5u ",
mproc.p_level,
mproc.p_baslev,
user_name(puid),
mproc.p_ppid);
}
printf(" %5u ",mproc.p_pid);
if(mproc.p_stat == SZOMB)
printf(" <PROCESS EXITING>");
else
printf(" <EMPTY>");
return(1);
}
if (mproc.p_pid == 0) {
printf(" swapper");
return(1);
}
if(ffile == swap && swpflg == 0){
printf(" <SWAPPED OUT>");
return(1);
}
addr += ctob((long)mproc.p_size) - 512;
/* look for command name and arguments and print them */
lseek(ffile, addr+512-sizeof(char **), 0);
if (read(ffile, (char *)&ap, sizeof(char *)) != sizeof(char *))
return(1);
if (ap) {
char b[52];
char *bp = b;
while((cp=getptr(ap++)) && cp && (bp<b+lw) ) {
nbad = 0;
while((c=getbyte(cp++)) && (bp<b+lw)) {
if (c<' ' || c>'~') {
if (nbad++>3)
break;
continue;
}
*bp++ = c;
}
*bp++ = ' ';
}
*bp++ = 0;
prcmd(b);
return(1);
}
lseek(ffile, addr, 0);
if (read(ffile, abuf, sizeof(abuf)) != sizeof(abuf))
return(1);
for (ip = (int *)&abuf[512]-2; ip > (int *)abuf; ) {
if (*--ip == -1 || *ip==0) {
cp = (char *)(ip+1);
if (*cp==0)
cp++;
nbad = 0;
for (cp1 = cp; cp1 < &abuf[512]; cp1++) {
c = *cp1&0177;
if (c==0)
*cp1 = ' ';
else if (c < ' ' || c > 0176) {
if (++nbad >= 5) {
*cp1++ = ' ';
break;
}
*cp1 = '?';
} else if (c=='=') {
*cp1 = 0;
while (cp1>cp && *--cp1!=' ')
*cp1 = 0;
break;
}
}
while (*--cp1==' ')
*cp1 = 0;
prcmd(cp);
return(1);
}
}
printf(" (%.*s)", DIRSIZ, u.u_comm);
return(1);
}
prcmd(s)
char *s;
{
register char *p;
int f = (lflg ? 25 : 50); /* field width */
int bad = 0;
int good = 0;
while (*s == ' ' || *s == '\t')
s++;
for (p = s; *p && *p != ' ' && *p != '\t'; p++) {
if (*p < ' ') /* non-printable */
bad++;
if ((*p >= 'a' && *p <= 'z') || (*p >= '0' && *p <= '9')
|| (*p >= 'A' && *p <= 'Z'))
good++;
if (p >= (s + f))
bad++;
}
if (bad || (!good))
printf(" (%.*s)", DIRSIZ, u.u_comm);
else
printf(" %.*s", f, s);
}
char *
gettty()
{
register i;
register char *p;
if (u.u_ttyp==0)
return("?");
for (i=0; i<ndev; i++) {
if (devl[i].dev == u.u_ttyd) {
p = devl[i].dname;
if (p[0]=='t' && p[1]=='t' && p[2]=='y')
p += 3;
return(p);
}
}
return("?");
}
char *
getptr(adr)
char **adr;
{
char *ptr;
register char *p, *pa;
register i;
ptr = 0;
pa = (char *)adr;
p = (char *)&ptr;
for (i=0; i<sizeof(ptr); i++)
*p++ = getbyte(pa++);
return(ptr);
}
getbyte(adr)
char *adr;
{
register struct map *amap = &datmap;
char b;
long saddr;
if(!within(adr, amap->b1, amap->e1)) {
if(within(adr, amap->b2, amap->e2)) {
saddr = (unsigned)adr + amap->f2 - amap->b2;
} else
return(0);
} else
saddr = (unsigned)adr + amap->f1 - amap->b1;
if(lseek(ffile, saddr, 0)==-1
|| read(ffile, &b, 1)<1) {
return(0);
}
return((unsigned)b);
}
within(adr,lbd,ubd)
char *adr;
long lbd, ubd;
{
return((unsigned)adr>=lbd && (unsigned)adr<ubd);
}
/*
* Maintain list of user names, and return them on demand.
*/
#define MAXUTAB 50
/******************************
char *
center(s)
register char *s;
{
register int n;
register char *p;
static char b[8];
n = 7 - strlen(s);
n /= 2;
for(p = &b[0]; n-- > 0;)
*p++ = ' ';
while(p < &b[7]){
if(*s != '\0')
*p++ = *s++;
else
*p++ = ' ';
}
*p = '\0';
return(&b[0]);
}
********************************/
char *
user_name(u)
int u;
{
static char nb[8];
register struct passwd *p;
struct utab {
short x_uid; /* user id number */
char x_name[8]; /* user name */
};
static struct utab utab[MAXUTAB];
register struct utab *up;
register char *s;
for(up = &utab[0]; up < &utab[MAXUTAB]; up++){
s = up->x_name;
if(*s == '\0' || up->x_uid == u)
break;
}
if(up >= &utab[MAXUTAB] || *s == '\0'){
p = getpwuid(u);
if(p != NULL && p->pw_name != NULL){
if(up < &utab[MAXUTAB]){
strncpy(s,p->pw_name,8);
s[7] = '\0';
up->x_uid = u;
}
s = p->pw_name;
}
else {
sprintf(nb,"%d",u);
s = nb;
}
}
return(s);
}
/*
* Print wchan value, symbolically interpreted.
*/
struct wsym {
char *w_string; /* label or name of the wchan */
unsigned w_size; /* number of bytes */
unsigned w_base; /* starting address */
unsigned w_end; /* first address AFTER it */
};
struct wsym wsyms[] = {
{ "runin", 1 },
{ "runout", 1 },
{ "bfreelist", sizeof(struct buf) },
{ "swbuf1", sizeof(struct buf) },
{ "swbuf2", sizeof(struct buf) },
{ "pause", 1, 0140000, 0140001 },
{0}
};
struct wsym warray[] = {
{ "buf", sizeof(struct buf) },
{ "proc", sizeof(struct proc) },
{ "file", sizeof(struct file) },
{ "inode", sizeof(struct inode) },
{ "dz", sizeof(struct tty) },
{ "dl", sizeof(struct tty) },
{ "dh", sizeof(struct tty) },
{ "qz", sizeof(struct tty) },
{ 0 }
};
prwchan(w, s)
register unsigned w; /* wchan address */
char s; /* process state */
{
register struct wsym *wp;
char b[20];
register char *x;
switch(s){
case SRUN:
x = "ready";
break;
case SSTOP:
x = "stopped";
break;
case SIDL:
x = "newborn";
break;
case SZOMB:
x = "zombie";
break;
case SEMPTY:
x = "empty";
break;
case SWAIT:
case SSLEEP:
x = 0;
break;
default:
x = "garbage";
break;
}
if (x) {
sprintf(b, "<%.8s>", x);
goto prt_it;
}
/* SSLEEP and SWAIT cases */
/* first check scalars */
for (wp = &wsyms[0]; wp->w_string; wp++) {
if ((w >= wp->w_base) && (w < wp->w_end)) {
sprintf(b, "%.10s", wp->w_string);
goto prt_it;
}
}
/* then check arrays */
for (wp = &warray[0]; wp->w_string; wp++) {
if ((w >= wp->w_base) && (w < wp->w_end)) {
w = (w - wp->w_base) / wp->w_size;
if(w > 999)
sprintf(b, "%.5s[???]", wp->w_string);
else
sprintf(b, "%.5s[%d]", wp->w_string, w);
goto prt_it;
}
}
/* sigh. No symbolic match */
printf(" %06o ", w);
return;
prt_it:
if (s == SSLEEP) {
for (x = &b[0]; *x; x++) {
if(*x >= 'a' && *x <= 'z')
*x += 'A' - 'a';
}
}
printf(" %-10.10s", b);
}
wsyminit()
{
register struct wsym *wp;
register struct nlist *np;
register int i;
long lseek();
int *e; /* read end address of table */
for (i = WSARRAY, wp = &warray[0], np = &nl[0]; i > 0; i--, wp++) {
if (np[0].n_type > 0 && np[1].n_type > 0) {
wp->w_base = np[0].n_value;
if (lseek(mem,(long)(np[1].n_value),0) != -1L &&
read(mem, &e, sizeof(e)) == sizeof(e))
wp->w_end = (unsigned) e;
else
wp->w_end = wp->w_base; /* invalid */
} else
wp->w_end = wp->w_base = 0;
np += 2;
}
/* unfortunately, buf[] is not delimited the same way, need to hack */
if(warray[0].w_base != warray[0].w_end) /* valid initialization */
warray[0].w_end = warray[0].w_end * warray[0].w_size +
warray[0].w_base;
for (i = WSYMS, wp = &wsyms[0]; i > 0; i--, wp++) {
if(np->n_type > 0) {
wp->w_base = np->n_value;
wp->w_end = wp->w_base + wp->w_size;
} else
wp->w_base = wp->w_end = 0;
np++;
}
}