static char SCCS_ID [] = "@(#)ps.c    	3.2	 16:14:57 - 81/12/17 ";
/*
 *	ps - process status
 *	examine and print certain things about processes
 */

#include <stdio.h>
#include <a.out.h>
#include <core.h>
#include <sys/local.h>
#include <sys/param.h>
#include <sys/proc.h>
#include <sys/tty.h>
#include <sys/dir.h>
#include <sys/user.h>

struct nlist nl[] = {
	{ "proc" },
#define	X_PROC		0
	{ "swapdev" },
#define	X_SWAPDEV	1
	{ "swplo" },
#define	X_SWPLO		2
	{ "nproc" },
#define X_NPROC         3
	{ "" },
};

struct	proc mproc;
struct  proc *kproc;    /* pointer to the proc table in the kernel */
int nproc;              /* size of proc table in the kernel */

struct	user u;
int	chkpid;
int	retcode=1;
int	lflg;
int	vflg;
int	kflg;
int	xflg;
char	*tptr;
long	lseek();
char	*gettty();
char	*getptr();
char	*strncmp();
int	aflg;
int	mem;
int	swmem;
int	swap;
daddr_t swplo = 6999;

int	ndev;
struct devl {
	char	dname[DIRSIZ];
	dev_t	dev;
} devl[256];

char	*coref;

main(argc, argv)
char **argv;
{
	int i;
	char *ap;
	int uid, puid;

	if (argc>1) {
		ap = argv[1];
		while (*ap) switch (*ap++) {

		case 'v':
			vflg++;
			break;

		case 'a':
			aflg++;
			break;

		case 't':
			if(*ap)
				tptr = ap;
			aflg++;
			if (*tptr == '?')
				xflg++;
			goto bbreak;

		case 'x':
			xflg++;
			break;

		case '-':
			break;

		case 'l':
			lflg++;
			break;

		case 'k':
			kflg++;
			break;

		default:
			chkpid = atoi(ap-1);
			goto bbreak;
			break;
		}
	}

bbreak:
	if(chdir("/dev") < 0) {
		fprintf(stderr, "Can't change to /dev\n");
		exit(1);
	}
	nlist(argc>2? argv[2]:"/unix", nl);
	if (nl[X_PROC].n_type==0) {
		fprintf(stderr, "No namelist\n");
		exit(1);
	}
	if (nl[X_NPROC].n_type==0) {
		fprintf(stderr, "Namelist has no nproc entry\n");
		exit(1);
	}
	coref = "/dev/mem";
	if(kflg)
		coref = "/usr/sys/core";
	if ((mem = open(coref, 0)) < 0) {
		fprintf(stderr, "No mem\n");
		exit(1);
	}
	swmem = open(coref, 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));
	/*
	 * Find base of swap
	 */
	lseek(mem, (long)nl[X_SWPLO].n_value, 0);
	read(mem, (char *)&swplo, sizeof(swplo));
	/*
	 * Find out how big the proc table is
	 */
	lseek(mem, (long)nl[X_NPROC].n_value, 0);
	read(mem, (char *)&nproc, sizeof(nproc));
	/*
	 * Locate proc table
	 */
	lseek(mem, (long)nl[X_PROC].n_value, 0);
	read(mem, (char *)&kproc, sizeof(kproc));
	lseek(mem, (long)kproc, 0);
	getdev();
	uid = getuid();
	if (lflg)
/***/	printf(" F S UID   PID  PPID CPU PRI  NICE  ADDR  SZ  WCHAN TTY  TIME CMD\n"); else
/***/		if (chkpid==0) printf("   PID TTY  TIME CMD\n");
	for (i=0; i<nproc; i++) {
		read(mem, (char *)&mproc, sizeof mproc);
		if (mproc.p_stat==0)
			continue;
		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;
		}
	}
	exit(retcode);
}

getdev()
{
#include <sys/stat.h>
	register FILE *df;
	struct stat sbuf;
	struct direct dbuf;

	if ((df = fopen("/dev", "r")) == NULL) {
		fprintf(stderr, "Can't open /dev\n");
		exit(1);
	}
	ndev = 0;
	while (fread((char *)&dbuf, sizeof(dbuf), 1, df) == 1) {
		if(dbuf.d_ino == 0)
			continue;
		if(stat(dbuf.d_name, &sbuf) < 0)
			continue;
		if ((sbuf.st_mode&S_IFMT) != S_IFCHR)
			continue;
		strcpy(devl[ndev].dname, dbuf.d_name);
		devl[ndev].dev = sbuf.st_rdev;
		ndev++;
	}
	fclose(df);
	if ((swap = open("/dev/swap", 0)) < 0) {
		fprintf(stderr, "Can't open /dev/swap\n");
		exit(1);
	}
}

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	file;
prcom(puid)
{
	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?35:80);
	char **ap;

	if (mproc.p_flag&SLOAD) {
		addr = ctob((long)mproc.p_addr);
		file = swmem;
	} else {
		addr = (mproc.p_addr+swplo)<<PGSHIFT;
		file = swap;
	}
	lseek(file, addr, 0);
	if (read(file, (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, 3))
		return(0);
	if (lflg) {
		printf("%2x %c%4d", mproc.p_flag,
			"0SWRIZT"[mproc.p_stat], puid);
	}
	printf("%6u", mproc.p_pid);
	if (lflg) {
		printf("%6u%4d%4d%5d%7x%4d", mproc.p_ppid, mproc.p_cpu&0377,
			mproc.p_pri,
			mproc.p_nice,
			mproc.p_addr, (mproc.p_size+7)>>3);
		if (mproc.p_wchan)
			printf("%7x", mproc.p_wchan);
		else
			printf("       ");
	}
/***/	printf(" %-3.3s", tp);
	if (mproc.p_stat==SZOMB) {
		printf("  <defunct>");
		return(1);
	}
/***/	tm = (u.u_utime + u.u_stime + HZ/2)/HZ;
	printf(" %2ld:", tm/60);
	tm %= 60;
	printf(tm<10?"0%ld":"%ld", tm);
	if (vflg && lflg==0) {	/* 0 == old tflg (print long times) */
/***/		tm = (u.u_cstime + HZ/2)/HZ;
		printf(" %2ld:", tm/60);
		tm %= 60;
		printf(tm<10?"0%ld":"%ld", tm);
/***/		tm = (u.u_cutime + HZ/2)/HZ;
		printf(" %2ld:", tm/60);
		tm %= 60;
		printf(tm<10?"0%ld":"%ld", tm);
	}
	if (mproc.p_pid == 0) {
		printf(" swapper");
		return(1);
	}
	addr += ctob((long)mproc.p_size) - 512;

	/* look for sh special */
	lseek(file, addr+512-sizeof(char **), 0);
	if (read(file, (char *)&ap, sizeof(char *)) != sizeof(char *))
		return(1);
	if (ap) {
		char b[82];
		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;
		printf(lflg?" %.30s":" %.60s", b);
		return(1);
	}

	if (pread(file, abuf, sizeof(abuf), addr) != 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;
			printf(lflg?" %.30s":" %.60s", cp);
			return(1);
		}
	}
	return(1);
}

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(file, saddr, 0)==-1
		   || read(file, &b, 1)<1) {
		return(0);
	}
	return((unsigned)b);
}


within(adr,lbd,ubd)
char *adr;
long lbd, ubd;
{
	return((unsigned)adr>=lbd && (unsigned)adr<ubd);
}

/*
 * pread is like read, but if it's /dev/mem we use the phys
 * system call for speed.  (On systems without phys we have
 * to use regular read.)
 */
pread(fd, ptr, nbytes, loc)
char *ptr;
long loc;
{
#ifdef  notdef
	/* doesn't work yet.  don't know why */
#define once(x) do {static int done; if (!done) {done = 1; (x);}} while (0)

	if (fd == swmem) {
		int rc;
#               define SEG 8
		once (printf ("doing phys\n"));
		rc=phys(SEG, nbytes/CLICK+1, (short)(loc/CLICK));
		if (rc>=0) {
			once (printf ("done phys\n"));
			memcpy(ptr, &((char *)(SEG * SEGMENT))[loc % CLICK],
			       nbytes);
			return nbytes;
		}
	}
#endif  notdef
	lseek(fd, loc, 0);
	return read(fd, ptr, nbytes);
}

memcpy(dest, src, nbytes)
register char *dest, *src;
register int nbytes;
{
	while (nbytes--)
		*dest++ = *src++;
}
