static char rcsid[] = "$Header: pstat.c,v 800.2 86/03/06 18:17:19 root Exp $";
static char sccsid[]="%W% %Y% %Q% %G%";
/*
 * pstat -- Display system related information upon stdout.
 *
 *	History
 *	-------
 *	831215	Original is probably 4.1c, adapted by Jamie Markevitz.
 *	850606	jht -- Adapted for Valid's 4.2bsd
 */

#if	0
#define	USE_FIXED_POINT		/* For p_pctcpu within proc-structure */
#define	QUOTA			/* For u_quota & u_qflags in user-structure */
#endif

#define mask(x) (x&0377)
#define	clear(x) ((int)x&0x7fffffff)

#include "../../h/types.h"
#include "../../h/param.h"
#include "../../h/dir.h"
#include "../../h/proc.h"
#include "../../h/text.h"
#include "../../h/inode.h"
#include "../../h/buf.h"

#define	KERNEL
#include "../../h/file.h"
#undef	KERNEL
#define	f_inode	f_data		/* Compatibility with 4.2bsd */

#include "../../h/map.h"
#include "../../h/ioctl.h"
#include "../../h/tty.h"
#include "../../h/user.h"
#include "../../h/conf.h"
#include "../../h/vm.h"
#ifdef s32
#include "../../usr.include/a.out.h"
#else s32
#include "../../usr.include/nlist.h"
#endif s32

#include "../../machine/pte.h"
#ifndef	bsd42
#include <sys/descript.h>
#endif	bsd42



char	*fcore	= "/dev/kmem";	/* Default RAM image to scan		*/
char	*fnlist	= "/vmunix";	/* Default bucket of symbols to scan	*/

int	fc;			/* Holds file descriptor for fcore	*/

/*
 * "What to get" table for nlist-ing
 * stuff from the kernel RAM.
 */
struct nlist nl[] = {
#define	SINODE	0
	{ "inode" },

#define	STEXT	1
	{ "text" },		/* Describes executing or sticky runnables */

#define	SPROC	2
	{ "proc" },		/* Process table */

#define	SKL	3
	{ "cons" },

#define	SFIL	4		/* Table of open files within the system */
	{ "file" },

#define	USRPTMA	5
	{ "Usrptmap" },		/* Process-slot to page-table-entry map */

#define	USRPT	6
	{ "usrpt" },

#define	SNSWAP	7
	{ "nswap" },		/* Capacity of the aggregate swap areas */

#define	SWAPMAP	8
	{ "swapmap" },

#define	SNPROC	9
	{ "nproc" },		/* Max # of processes the kernel will support */

#define	SNTEXT	10
	{ "ntext" },		/* # buckets for executable files */

#define	SNFILE	11
	{ "nfile" },

#define	SNINODE	12
	{ "ninode" },		/* Max # of inode in kernel RAM cache	*/

#define	SNSWAPMAP 13
	{ "nswapmap" },

#define	SPTY	14
	{ "pt_tty" },

#define	X_DMMIN		15
	{ "dmmin" },

#define	X_DMMAX		16
	{ "dmmax" },

#define	SBUF		17
	{ "buf" },

#define	SNBUF		18
	{ "nbuf" },

#ifdef	s32
#define	SOCT	19
	{ "oct_tty" },

#define	SSC	20
	{ "sc_tty" },

#else	s32
/*
 * Stuff that strictly relates to UNIBUS,
 * which only the VAX-11/7?0 posses for 4.2
 */
#define	SDZ	19
	{ "dz_tty" },

#define	SNDZ	20
	{ "dz_cnt" },

#define	SDH	21
	{ "dh11" },

#define	SNDH	22
	{ "ndh11" },
#endif	s32

	NULL,
};

/*
 * Flags that drive the algorithms.
 * Non-zero implies assertion.
 */
int	allflg;		/* Display EVERYTHING!			*/

int	filf;		/* Display FILE		information	*/

int	inof;		/* Display INODE	information	*/

int	kflg;		/* Specifies file from which to obtain MEM-FILE	*/

int	prcf;		/* Display PROCESS	information	*/

int	swpf;		/* Display SWAP		information	*/

int	totflg;		/* Display various TOTALS 		*/

int	ttyf;		/* Display TTY		information	*/

int	txtf;		/* Display TEXT		information	*/

int	usrf;		/* Display USER		information	*/

int	buff;		/* Display BUFFER	information	*/


long	ubase;
#if 0
char	partab[1];
#endif
/*
 * Routing table for the device drivers
 */
struct	cdevsw	cdevsw[1];
struct	bdevsw	bdevsw[1];

/*
 * Pointers to page-table-entry aggregates.
 */
struct	pte	*Usrptma;
struct	pte	*usrpt;

char	**ourName;	/* Our name from command line	*/
int	dmmin,	dmmax;	/* Swapspace related extrema	*/

/*
 * Entry point
 */
main(argc, argv, envv)
	int	argc;
	char	**argv;
	char	**envv;		/* The vector of environment information */
{
	register char	*argp;
	int		 allflags;

	/*
	 * Grunge through the argument list
	 */
	argc--, ourName = argv++;
	while (argc > 0 && **argv == '-') {
		argp = *argv++;
		argp++;
		argc--;
		while (*argp++)
		switch (argp[-1]) {

		case 'T':	/* Display info	about totals */
			totflg++;
			break;

		case 'a':	/* Display ALL info	*/
			allflg++;
			break;

		case 'i':	/* Display inode info	*/
			inof++;
			break;

		case 'k':	/* Specify alternate RAM image */
			kflg++;
			fcore = "/vmcore";
			break;

		case 'x':	/* Display text info	*/
			txtf++;
			break;

		case 'p':	/* Display process info	*/
			prcf++;
			break;

		case 't':	/* Display tty info	*/
			ttyf++;
			break;

		case 'u':	/* Specify the address the or the upage(s) */
			if (argc == 0)
				break;
			argc--;
			usrf++;
			sscanf( *argv++, "%x", &ubase);
			break;

		case 'f':	/* Display file info	*/
			filf++;
			break;

		case 's':	/* Display swap info	*/
			swpf++;
			break;

		case 'b':	/* Display buffer info	*/
			buff++;
			break;

		default:
			usage();
			exit(1);
		}
	}
	if (argc>1)
		fcore = argv[1];
	if ((fc = open(fcore, 0)) < 0) {
		printf("Can't find %s\n", fcore);
		exit(1);
	}
	if (argc>0)
		fnlist = argv[0];
	nlist(fnlist, nl);
#ifndef s32
	usrpt = (struct pte *)nl[USRPT].n_value;
#endif s32
	Usrptma = (struct pte *)nl[USRPTMA].n_value;
	if (nl[0].n_type == 0) {
		printf("no namelist\n");
		exit(1);
	}
#ifdef s32
	lseek(fc, (long)nl[USRPT].n_value, 0);
	if (read(fc, (char *)&usrpt, sizeof (usrpt)) != sizeof (usrpt)) {
		printf("pstat: cannot read usrpt\n");
		exit(1);
	}
#endif s32
	allflags = filf | totflg | inof | prcf | txtf | ttyf | usrf | swpf | buff;
	if (allflags == 0) {
		printf("pstat: one or more of -[aixptfsub] is required\n");
		exit(1);
	}
	/*
	 * Produce the reports requested in the arg-list:
	 */
	if (filf||totflg)	dofile();
	if (inof||totflg)	doinode();
	if (prcf||totflg)	doproc();
	if (txtf||totflg)	dotext();
	if (ttyf)		dotty();
	if (usrf)		dousr();
	if (swpf||totflg)	doswap();
	if (buff||totflg)	dobuffer();
}

/*
 * Display usage information
 */
usage()
{
	printf("usage: %s -[aixptfsb] [-u [ubase]] [system] [core]\n", ourName);
}

/*
 * Display inode related information
 */
doinode()
{
	register struct inode *ip;
	struct inode *xinode, *ainode;
	register int nin;
	int ninode;

	nin = 0;
	ninode = getw(nl[SNINODE].n_value);
	xinode = (struct inode *)calloc(ninode, sizeof (struct inode));
	lseek(fc, (int)(ainode = (struct inode *)getw(nl[SINODE].n_value)), 0);
	read(fc, xinode, ninode * sizeof(struct inode));
	for (ip = xinode; ip < &xinode[ninode]; ip++)
		if (ip->i_count)
			nin++;
	if (totflg) {
		printf("%3d/%3d inodes\n", nin, ninode);
		return;
	}
	printf("%d/%d active inodes\n", nin, ninode);
printf("   LOC      FLAGS    CNT DEVICE  RDC WRC  INO  MODE  NLK  UID   SIZE/DEV\n");
	for (ip = xinode; ip < &xinode[ninode]; ip++) {
		if (ip->i_count == 0)
			continue;
		printf("%8.1x ", ainode + (ip - xinode));
		putf(ip->i_flag&ILOCKED, 'L');
		putf(ip->i_flag&IUPD, 'U');
		putf(ip->i_flag&IACC, 'A');
		putf(ip->i_flag&IMOUNT, 'M');
		putf(ip->i_flag&IWANT, 'W');
		putf(ip->i_flag&ITEXT, 'T');
		putf(ip->i_flag&ICHG, 'C');
		putf(ip->i_flag&ISHLOCK, 'S');
		putf(ip->i_flag&IEXLOCK, 'E');
		putf(ip->i_flag&ILWAIT, 'Z');
		printf("%4d", ip->i_count&0377);
		printf("%4d,%3d", major(ip->i_dev), minor(ip->i_dev));
		printf("%4d", ip->i_shlockc&0377);
		printf("%4d", ip->i_exlockc&0377);
		printf("%6d", ip->i_number);
		printf("%6x", ip->i_mode & 0xffff);
		printf("%4d", ip->i_nlink);
		printf("%5d", ip->i_uid);
		if ((ip->i_mode&IFMT)==IFBLK || (ip->i_mode&IFMT)==IFCHR)
			printf("%6d,%3d", major(ip->i_rdev), minor(ip->i_rdev));
		else
			printf("%10ld", ip->i_size);
		printf("\n");
	}
	free(xinode);
}

getw(loc)
	off_t loc;
{
	int word;

	if (kflg)
		loc &= 0x7fffffff;
	lseek(fc, loc, 0);
	read(fc, &word, sizeof (word));
	if (kflg)
		word &= 0x7fffffff;
	return (word);
}

putf(v, n)
{
	if (v)
		printf("%c", n);
	else
		printf(" ");
}

/*
 * Display information about (runnable) texts.
 */
dotext()
{
	register struct text *xp;
	int ntext;
	struct text *xtext, *atext;
	int ntx;

	ntx = 0;
	ntext = getw(nl[SNTEXT].n_value);
	xtext = (struct text *)calloc(ntext, sizeof (struct text));
	lseek(fc, (int)(atext = (struct text *)getw(nl[STEXT].n_value)), 0);
	read(fc, xtext, ntext * sizeof (struct text));
	for (xp = xtext; xp < &xtext[ntext]; xp++)
		if (xp->x_iptr!=NULL)
			ntx++;
	if (totflg) {
		printf("%3d/%3d texts\n", ntx, ntext);
		return;
	}
	printf("%d/%d active texts\n", ntx, ntext);
	printf("   LOC   FLAGS DADDR      CADDR  RSS SIZE      IPTR  CNT CCNT\n");
	for (xp = xtext; xp < &xtext[ntext]; xp++) {
		if (xp->x_iptr == NULL)
			continue;
		printf("%8.1x", atext + (xp - xtext));
		printf(" ");
		putf(xp->x_flag&XPAGI, 'P');
		putf(xp->x_flag&XTRC, 'T');
		putf(xp->x_flag&XWRIT, 'W');
		putf(xp->x_flag&XLOAD, 'L');
		putf(xp->x_flag&XLOCK, 'K');
		putf(xp->x_flag&XWANT, 'w');
		printf("%5x", xp->x_daddr[0]);
		printf("%11x", xp->x_caddr);
		printf("%5d", xp->x_rssize);
		printf("%5d", xp->x_size);
		printf("%10.1x", xp->x_iptr);
		printf("%5d", xp->x_count&0377);
		printf("%5d", xp->x_ccount);
		printf("\n");
	}
	free(xtext);
}

/*
 * Display information about processes in the system
 */
doproc()
{
	struct proc *xproc, *aproc;
	int nproc;
	register struct proc *pp;
	register loc, np;
	struct pte apte;

	nproc = getw(nl[SNPROC].n_value);
	xproc = (struct proc *)calloc(nproc, sizeof (struct proc));
	lseek(fc, (int)(aproc = (struct proc *)getw(nl[SPROC].n_value)), 0);
	read(fc, xproc, nproc * sizeof (struct proc));
	np = 0;
	for (pp=xproc; pp < &xproc[nproc]; pp++)
		if (pp->p_stat)
			np++;
	if (totflg) {
		printf("%3d/%3d processes\n", np, nproc);
		return;
	}
	printf("%d/%d processes\n", np, nproc);
	printf("   LOC    S    F POIP PRI      SIG   UID SLP TIM  CPU  NI   PGRP    PID   PPID    ADDR   RSS SRSS SIZE    WCHAN    LINK   TEXTP CLKT\n");
	for (pp=xproc; pp<&xproc[nproc]; pp++) {
		if (pp->p_stat==0 && allflg==0)
			continue;
		printf("%8x", aproc + (pp - xproc));
		printf(" %2d", pp->p_stat);
		printf(" %4x", pp->p_flag & 0xffff);
		printf(" %4d", pp->p_poip);
		printf(" %3d", pp->p_pri);
		printf(" %8x", pp->p_sig);
		printf(" %5d", pp->p_uid);
		printf(" %3d", pp->p_slptime);
		printf(" %3d", pp->p_time);
		printf(" %4d", pp->p_cpu&0377);
		printf(" %3d", pp->p_nice);
		printf(" %6d", pp->p_pgrp);
		printf(" %6d", pp->p_pid);
		printf(" %6d", pp->p_ppid);
		if (kflg)
			pp->p_addr = (struct pte *)clear((int)pp->p_addr);
		lseek(fc, (long)(Usrptma+btokmx(pp->p_addr)), 0);
		read(fc, &apte, sizeof(apte));
		printf(" %8x", ctob(apte.pg_pfnum+1) - sizeof(struct pte) * UPAGES);
		printf(" %4x", pp->p_rssize);
		printf(" %4x", pp->p_swrss);
		printf(" %5x", pp->p_dsize+pp->p_ssize);
		printf(" %7x", clear(pp->p_wchan));
		printf(" %7x", clear(pp->p_link));
		printf(" %7x", clear(pp->p_textp));
		printf("\n");
	}
}

/*
 * Display information about the ttys.
 */
dotty()
{
#ifdef	s32
	struct tty oct_tty[128];
	int noct = 8, nsc = 2;
#else	s32
	struct tty dz_tty[128];
	int ndz;
#endif	s32
	register struct tty *tp;
	register char *mesg;

#ifdef	s32
	mesg = " # RAW CAN OUT   MODE    ADDR   DEL COL  STATE   PGRP DISC\n";
	printf(mesg);
	printf("1 cons\n");
	if (kflg)
		nl[SKL].n_value = clear(nl[SKL].n_value);
	lseek(fc, (long)nl[SKL].n_value, 0);
	read(fc, oct_tty, sizeof(oct_tty[0]));
	ttyprt(&oct_tty[0], 0);
	if (kflg) {
		nl[SSC].n_value = clear(nl[SSC].n_value);
	}
	printf("%d sc lines\n", nsc);
	lseek(fc, (long)nl[SSC].n_value, 0);
	read(fc, oct_tty, nsc * sizeof (struct tty));
	for (tp = oct_tty; tp < &oct_tty[nsc]; tp++)
		ttyprt(tp, tp - oct_tty);

	if (kflg) {
		nl[SOCT].n_value = clear(nl[SOCT].n_value);
	}
	printf("%d oct lines\n", noct);
	lseek(fc, (long)nl[SOCT].n_value, 0);
	read(fc, oct_tty, noct * sizeof (struct tty));
	for (tp = oct_tty; tp < &oct_tty[noct]; tp++)
		ttyprt(tp, tp - oct_tty);
pty:
	if (nl[SPTY].n_type == 0)
		goto pty;
	if (kflg) {
		nl[SPTY].n_value = clear(nl[SPTY].n_value);
	}
	printf("32 pty lines\n");
	lseek(fc, (long)nl[SPTY].n_value, 0);
	read(fc, oct_tty, 32*sizeof(struct tty));
	for (tp = oct_tty; tp < &oct_tty[32]; tp++)
		ttyprt(tp, tp - oct_tty);
#else	s32
	/*
	 * 4.2bsd stuff that strictly relate to UNIBUS devices,
	 * which only the VAX-11/7xx's posses.
	 */
	printf("1 cons\n");
	if (kflg)
		nl[SKL].n_value = clear(nl[SKL].n_value);
	lseek(fc, (long)nl[SKL].n_value, 0);
	read(fc, dz_tty, sizeof(dz_tty[0]));
	mesg = " # RAW CAN OUT   MODE    ADDR   DEL COL  STATE   PGRP DISC\n";
	printf(mesg);
	ttyprt(&dz_tty[0], 0);
	if (nl[SNDZ].n_type == 0)
		goto dh;
	if (kflg) {
		nl[SNDZ].n_value = clear(nl[SNDZ].n_value);
		nl[SDZ].n_value = clear(nl[SDZ].n_value);
	}
	lseek(fc, (long)nl[SNDZ].n_value, 0);
	read(fc, &ndz, sizeof(ndz));
	printf("%d dz lines\n", ndz);
	lseek(fc, (long)nl[SDZ].n_value, 0);
	read(fc, dz_tty, ndz * sizeof (struct tty));
	for (tp = dz_tty; tp < &dz_tty[ndz]; tp++)
		ttyprt(tp, tp - dz_tty);
dh:
	if (nl[SNDH].n_type == 0)
		goto pty;
	if (kflg) {
		nl[SNDH].n_value = clear(nl[SNDH].n_value);
		nl[SDH].n_value = clear(nl[SDH].n_value);
	}
	lseek(fc, (long)nl[SNDH].n_value, 0);
	read(fc, &ndz, sizeof(ndz));
	printf("%d dh lines\n", ndz);
	lseek(fc, (long)nl[SDH].n_value, 0);
	read(fc, dz_tty, ndz * sizeof(struct tty));
	for (tp = dz_tty; tp < &dz_tty[ndz]; tp++)
		ttyprt(tp, tp - dz_tty);
pty:
	if (nl[SPTY].n_type == 0)
		goto pty;
	if (kflg) {
		nl[SPTY].n_value = clear(nl[SPTY].n_value);
	}
	printf("32 pty lines\n");
	lseek(fc, (long)nl[SPTY].n_value, 0);
	read(fc, dz_tty, 32*sizeof(struct tty));
	for (tp = dz_tty; tp < &dz_tty[32]; tp++)
		ttyprt(tp, tp - dz_tty);
#endif	!s32
}

ttyprt(atp, line)
	struct	tty	*atp;
{
	register struct tty *tp;

	printf("%2d", line);
	tp = atp;
	switch (tp->t_line) {

/*
	case NETLDISC:
		if (tp->t_rec)
			printf("%4d%4d", 0, tp->t_inbuf);
		else
			printf("%4d%4d", tp->t_inbuf, 0);
		break;
*/

	default:
		printf("%4d", tp->t_rawq.c_cc);
		printf("%4d", tp->t_canq.c_cc);
	}
	printf("%4d", tp->t_outq.c_cc);
	printf("%8.1x", tp->t_flags);
	printf(" %8.1x", tp->t_addr);
	printf("%3d", tp->t_delct);
	printf("%4d ", tp->t_col);
	putf(tp->t_state&TS_TIMEOUT, 'T');
	putf(tp->t_state&TS_WOPEN, 'W');
	putf(tp->t_state&TS_ISOPEN, 'O');
	putf(tp->t_state&TS_CARR_ON, 'C');
	putf(tp->t_state&TS_BUSY, 'B');
	putf(tp->t_state&TS_ASLEEP, 'A');
	putf(tp->t_state&TS_XCLUDE, 'X');
	putf(tp->t_state&TS_HUPCLS, 'H');
	printf("%6d", tp->t_pgrp);
	switch (tp->t_line) {

	case NTTYDISC:
		printf(" ntty");
		break;

	case NETLDISC:
		printf(" net");
		break;
	}
	printf("\n");
}

/*
 * Display information from the upage.
 */
dousr()
{
	struct user U;
	register i, j, *ip;

	/* This wins only if PAGSIZ > sizeof (struct user) */
	lseek(fc, ubase * NBPG, 0);
	read(fc, &U, sizeof(U));
	printf("pcb");
	ip = (int *)&U.u_pcb;
	while (ip < &U.u_arg[0]) {
		if ((ip - (int *)&U.u_pcb) % 4 == 0)
			printf("\t");
		printf("%x ", *ip++);
		if ((ip - (int *)&U.u_pcb) % 4 == 0)
			printf("\n");
	}
	if ((ip - (int *)&U.u_pcb) % 4 != 0)
		printf("\n");
	printf("arg\t");
	for (i=0; i<5; i++)
		printf(" %.1x", U.u_arg[i]);
	printf("\n");
	for (i=0; i<sizeof(label_t)/sizeof(int); i++) {
		if (i%5==0)
			printf("\t");
		printf("%9.1x", U.u_ssave.val[i]);
		if (i%5==4)
			printf("\n");
	}
	if (i%5)
		printf("\n");
	printf("segflg\t%d\nerror %d\n", U.u_segflg, U.u_error);
	printf("uids\t%d,%d,%d,%d\n", U.u_uid,U.u_gid,U.u_ruid,U.u_rgid);
	printf("procp\t%.1x\n", U.u_procp);
	printf("ap\t%.1x\n", U.u_ap);
	printf("r_val?\t%.1x %.1x\n", U.u_r.r_val1, U.u_r.r_val2);
	printf("base, count, offset %.1x %.1x %ld\n", U.u_base,
		U.u_count, U.u_offset);
	printf("cdir rdir %.1x %.1x\n", U.u_cdir, U.u_rdir);
	printf("dirp %.1x\n", U.u_dirp);
	printf("dent %d %.14s\n", U.u_dent.d_ino, U.u_dent.d_name);
	printf("pdir %.1o\n", U.u_pdir);
	printf("file\t");
	for (i=0; i<10; i++)
		printf("%9.1x", U.u_ofile[i]);
	printf("\n\t");
	for (i=10; i<NOFILE; i++)
		printf("%9.1x", U.u_ofile[i]);
	printf("\n");
	printf("pofile\t");
	for (i=0; i<10; i++)
		printf("%9.1x", U.u_pofile[i]);
	printf("\n\t");
	for (i=10; i<NOFILE; i++)
		printf("%9.1x", U.u_pofile[i]);
	printf("\n");
	printf("ssave");
	for (i=0; i<sizeof(label_t)/sizeof(int); i++) {
		if (i%5==0)
			printf("\t");
		printf("%9.1x", U.u_ssave.val[i]);
		if (i%5==4)
			printf("\n");
	}
	if (i%5)
		printf("\n");
	printf("sigs\t");
	for (i=0; i<NSIG; i++)
		printf("%.1x ", U.u_signal[i]);
	printf("\n");
	printf("code\t%.1x\n", U.u_code);
	printf("ar0\t%.1x\n", U.u_ar0);
	printf("prof\t%X %X %X %X\n", U.u_prof.pr_base, U.u_prof.pr_size,
	    U.u_prof.pr_off, U.u_prof.pr_scale);
	printf("\neosys\t%d\n", U.u_eosys);
	printf("ttyp\t%.1x\n", U.u_ttyp);
	printf("ttyd\t%d,%d\n", major(U.u_ttyd), minor(U.u_ttyd));
	printf("exdata\t");
	ip = (int *)&U.u_exdata;
	for (i = 0; i < 8; i++)
		printf("%.1ld ", *ip++);
	printf("\n");
	printf("comm %.14s\n", U.u_comm);
	printf("start\t%ld\n", U.u_start);
	printf("acflag\t%ld\n", U.u_acflag);
	printf("cmask\t%ld\n", U.u_cmask);
	printf("sizes\t%.1x %.1x %.1x\n", U.u_tsize, U.u_dsize, U.u_ssize);
	printf("ru\t");
	ip = (int *)&U.u_ru;
	for (i = 0; i < sizeof(U.u_ru)/sizeof(int); i++)
		printf("%ld ", ip[i]);
	printf("\n");
	ip = (int *)&U.u_cru;
	printf("cru\t");
	for (i = 0; i < sizeof(U.u_cru)/sizeof(int); i++)
		printf("%ld ", ip[i]);
	printf("\n");
/*
	i =  U.u_stack - &U;
	while (U[++i] == 0);
	i &= ~07;
	while (i < 512) {
		printf("%x ", 0140000+2*i);
		for (j=0; j<8; j++)
			printf("%9x", U[i++]);
		printf("\n");
	}
*/
}

oatoi(s)
char *s;
{
	register v;

	v = 0;
	while (*s)
		v = (v<<3) + *s++ - '0';
	return(v);
}

/*
 * Display information about open files.
 */
dofile()
{
	int nfile;
	struct file *xfile, *afile;
	register struct file *fp;
	register nf;
	int loc;
#ifdef	bsd42
	static char *dtypes[] = {
		"[0]",		/* Old 4.1c */
		"inode",
		"socket",
		"[3]",		/* Old 4.1c */
		"[4]",		/* Old 4.1c */
		"[5]",		/* Old 4.1c */
		"[6]",		/* Old 4.1c */
		"[7]",		/* Old 4.1c */
		"[9]",		/* Old 4.1c */
		"[10]",		/* Old 4.1c */
		"[11]"		/* Old 4.1c */
	};
#else	bsd42
	static char *dtypes[] = {
		"[0]",
		"kernel",	/*  1 */
		"fsys",		/*  2 */
		"file",		/*  3 */
		"dir",		/*  4 */
		"bdev",		/*  5 */
		"cdev",		/*  6 */
		"proc",		/*  7 */
		"socket",	/*  8 */
		"domain",	/*  9 */
		"tty"		/* 10 */
	};
#endif	bsd42

	nf = 0;
	nfile = getw(nl[SNFILE].n_value);
	xfile = (struct file *)calloc(nfile, sizeof (struct file));
	lseek(fc, (int)(afile = (struct file *)getw(nl[SFIL].n_value)), 0);
	read(fc, xfile, nfile * sizeof (struct file));
	for (fp=xfile; fp < &xfile[nfile]; fp++)
		if (fp->f_count)
			nf++;
	if (totflg) {
		printf("%3d/%3d files\n", nf, nfile);
		return;
	}
	printf("%d/%d open files\n", nf, nfile);
	printf("   LOC   TYPE    FLG  CNT   INO    OFFS|SOCK\n");
	for (fp=xfile,loc=(int)afile; fp < &xfile[nfile]; fp++,loc+=sizeof(xfile[0])) {
		if (fp->f_count==0)
			continue;
		printf("%8x ", loc);
#ifndef	bsd42
		if (fp->f_type <= DTYPE_TERMINAL)
			printf("%-8.8s", dtypes[fp->f_type]);
		else
			printf("8d", fp->f_type);
#else	bsd42
		printf("%-8.8s", dtypes[fp->f_type]);
#endif	bsd42
		putf(fp->f_flag&FREAD, 'R');
		putf(fp->f_flag&FWRITE, 'W');
		putf(fp->f_flag&FAPPEND, 'A');
		printf("%4d", mask(fp->f_count));
		printf("%9.1x", fp->f_inode);
#ifndef	s32
		if (fp->f_type == DTYPE_SOCKET)
			printf("  %x\n", fp->f_socket);
		else
			printf("  %ld\n", fp->f_offset);
#else
		printf("  %ld\n", fp->f_offset);
#endif
	}
}

/*
 * Display information about swapping.
 */
doswap()
{
	struct	proc	*proc;		/* Process table	*/
	int		 nproc;
	register struct	 proc	*pp;

	struct	text	*xtext;		/* Open or sticky texts	*/
	int		 ntext;
	register struct	 text	*xp;

	struct	map	*swapmap;	/* Swapping information	*/
	int		 nswapmap;
	int		 nswap, used, tused, free;

	register struct	mapent	*me;

	/* a DMMAX/2 block goes to argmap */
#ifdef	s32
	dmmin = getw(nl[X_DMMIN].n_value);
	dmmax = getw(nl[X_DMMAX].n_value);
#endif

	/*
	 * Get a copy of the entire process table
	 */
	nproc	= getw(nl[SNPROC].n_value);
	proc	= (struct proc *)calloc(nproc, sizeof (struct proc));
	lseek(fc, getw(nl[SPROC].n_value), 0);
	read(fc, proc, nproc * sizeof (struct proc));

	/*
	 * Get the entire swapmap
	 */
	nswapmap = getw(nl[SNSWAPMAP].n_value);
	swapmap	= (struct map *)calloc(nswapmap, sizeof (struct map));
	lseek(fc, getw(nl[SWAPMAP].n_value), 0);
	read(fc, swapmap, nswapmap * sizeof (struct map));

	nswap	= getw(nl[SNSWAP].n_value);
	/*
	 * Compute the amount of unused swap space
	 */
	free	= 0;
	for (me = (struct mapent *)(swapmap+1);
	    me < (struct mapent *)&swapmap[nswapmap]; me++)
		free += me->m_size;

	/*
	 * Get a copy of the entire text table
	 */
	ntext = getw(nl[SNTEXT].n_value);
	xtext = (struct text *)calloc(ntext, sizeof (struct text));
	lseek(fc, getw(nl[STEXT].n_value), 0);
	read(fc, xtext, ntext * sizeof (struct text));

	/*
	 * Walk the text table,
	 * tallying how much swapspace
	 * it indirectly consumes.
	 */
	tused = 0;
	for (xp = xtext; xp < &xtext[ntext]; xp++)
		if (xp->x_iptr!=NULL)
			tused += xdsize(xp);
	/*
	 * Now add in the data and stack space
	 * to the text space tally.
	 */
	used = tused;
	for (pp = proc; pp < &proc[nproc]; pp++) {
		if (pp->p_stat == 0 || pp->p_stat == SZOMB)
			continue;
		if (pp->p_flag & SSYS)
			continue;
		used += up(pp->p_dsize) + up(pp->p_ssize);
		if ((pp->p_flag&SLOAD) == 0)
			used += vusize(pp);
	}
	if (totflg) {
		printf("%3d/%3d 00k swap\n", used/2/100, (used+free)/2/100);
		return;
	}
	printf("%d used (%d text), %d free, %d missing\n",
#ifdef	s32
	    used/2, tused/2, free/2, (nswap - dmmax/2 - (used + free))/2);
#else
	    used/2, tused/2, free/2, (nswap - DMMAX/2 - (used + free))/2);
#endif
}

up(size)
	register int size;
{
	register int i, block;

	i = 0;

#ifdef	s32
	block = dmmin;
	while (i < size) {
		i += block;
		if (block < dmmax)
			block *= 2;
	}
#else
	block = DMMIN;
	while (i < size) {
		i += block;
		if (block < DMMAX)
			block *= 2;
	}
#endif
	return (i);
}

vusize(p)
	struct proc *p;
{
	register int tsz = p->p_tsize / NPTEPG;

	return (clrnd(UPAGES + clrnd(ctopt(p->p_tsize+p->p_dsize+p->p_ssize+UPAGES)) - tsz));
}

xdsize(xp)
	struct text *xp;
{

	if (xp->x_flag & XPAGI)
		return (clrnd(xp->x_size + ctopt(xp->x_size)));
	return (xp->x_size);
}

/*
 * Display buffer information
 */
dobuffer()
{
	register struct buf *bp;
	struct buf *xbuf, *abuf;
	register int nb, bf;
	int nbuffers;

	nb = 0;
	nbuffers = getw(nl[SNBUF].n_value);
	xbuf = (struct buf *)calloc(nbuffers, sizeof (struct buf));
	lseek(fc, (int)(abuf = (struct buf *)getw(nl[SBUF].n_value)), 0);
	read(fc, xbuf, nbuffers * sizeof(struct buf));
	for (bp = xbuf; bp < &xbuf[nbuffers]; bp++)
		if (bp->b_flags&B_BUSY)
			nb++;
	printf("\n");
	if (totflg) {
		printf("%3d/%3d busy buffers\n", nb, nbuffers);
		return;
	}
	printf("%d/%d busy buffers\n", nb, nbuffers);
	for (bp = xbuf; bp < &xbuf[nbuffers]; bp++) {
		bf = bp->b_flags;

		printf("\n");
		printf("%8.1x ", abuf + (bp - xbuf));
		printf("b_flags=0x%X ==> ", bf );

		printf("%s,%s,%s,%s %s,%s,%s,%s;  ",
							  "0",
			(bf & B_PARTIAL)? "PARTIAL"	: "",
			(bf & B_CALL)	? "CALL"	: "",
			(bf & B_BAD)	? "BAD"	: "",

							  "0",
			(bf & B_HEAD)	? "HEAD"	: "",
			(bf & B_LOCKED)	? "LOCKED"	: "",
			(bf & B_INVAL)	? "INVAL"	: "");
		
		printf("%s,%s,%s,%s %s,%s,%s,%s;  ",
			(bf & B_CACHE)	? "CACHE"	: "",
			(bf & B_PGIN)	? "PGIN"	: "",
			(bf & B_DIRTY)	? "DIRTY"	: "",
			(bf & B_PAGET)	? "PAGET"	: "",

			(bf & B_UAREA)	? "UAREA"	: "",
			(bf & B_TAPE)	? "TAPE"	: "",
			(bf & B_DELWRI)	? "DELWRI"	: "",
			(bf & B_ASYNC)	? "ASYNC"	: "");
	
		printf("%s,%s,%s,%s %s,%s,%s,%s;  ",
			(bf & B_AGE)	? "AGE"	: "",
			(bf & B_WANTED)	? "WANTED"	: "",
			(bf & B_XXX)	? "XXX"	: "",
			(bf & B_PHYS)	? "PHYS"	: "",

			(bf & B_BUSY)	? "BUSY"	: "",
			(bf & B_ERROR)	? "ERROR"	: "",
			(bf & B_DONE)	? "DONE"	: "",
			(bf & B_READ)	? "READ"	: "WRITE");


		printf("\nb_forw=0x%X b_back=0x%X   av_forw=0x%X av_back=0x%X\n",
			bp->b_forw,	bp->b_back,
			bp->av_forw,	bp->av_back);

		printf("b_count=0x%X=%d  b_bufsize=0x%x=%d  b_error=0x%x  b_dev=%02x/%02x\n",
			bp->b_bcount,	bp->b_bcount,
			bp->b_bufsize,	bp->b_bufsize,
			bp->b_error,
			major(bp->b_dev),
			minor(bp->b_dev));

		printf("b_un=0x%X=%d  b_blkno=0x%x=%d  b_resid=0x%x  b_proc=0x%X\n",
			bp->b_un,	bp->b_un,
			bp->b_blkno,	bp->b_blkno,
			bp->b_resid,
			bp->b_proc,	bp->b_iodone, bp->b_pfcent);
	
	}
	printf("\n");
	free(xbuf);
}
