[comp.sys.pyramid] Needed: ofiles source for Pyramid

mb@rex.cs.tulane.edu (Mark Benard) (02/28/91)

Has anyone modified ofiles to run on a Pyramid?

Mark

romain@pyramid.pyramid.com (Romain Kang) (02/28/91)

/etc/fuser should be sufficient for most applications where you'd want to
use ofiles, but...

This should run under OSx 5.0 or later.  4.4 needs a getuser() variant
more like stock BSD.

/*	ofiles.c
 *
 *	ofiles [-d ] [-k nlist core] [-n] [-p] args
 *
 *	Show owner of open file or network connection.
 *
 *	Reports owner, process ID, access type, command and inode number.
 *
 *	-d		select verbose debugging output
 *
 *	-k nlist core	specifies alternative name list and core files
 *			(DYNIX only)
 *
 *	-n		interpret names as network connection, hexadecimal
 *			Protocol Control Block (PCB) addresses
 *
 *	-p  		gives brief (pids only) report
 *
 *	names		file names, file system names or network connection
 *			PCB addresses
 *
 *	Stat each file or file system argument and scan the process table,
 *	looking for a match in the associated user structure's file lists.
 *
 *	Follow each PCB arg to the Internet Protocol Control Block (INPCB),
 *	thence to the socket; then scan the file table to find the file
 *	structure address associated with the socket; finally, scan the
 *	process table, looking for a nacth in the associated user structure's
 *	file lists.
 *
 *	Doesn't handlle remote NFS files.
 */

/*
 *	Authors:
 *
 *	The orignal author is:
 *
 *		C. Spencer
 *
 *	Contributors include:
 *
 *		Michael Ditto
 *		Tom Dunigan
 *		Alexander Dupuy
 *		Greg Nebbett
 *		Richard Tobin
 *
 *	From the Purdue University Computing Center:
 *
 *		Mike Spitzer 		converted to 4.3BSD, DYNIX 3.0.1[24]
 *		Ray Moody		SunOS 4.0 and ULTRIX 2.2
 *		Vik Lall
 *
 *		Vic Abell		added socket option and removed lint
 *				
 */

#ifndef lint
static char rcsid[]="$Header: ofiles.c,v 1.8.1.2 91/02/28 03:01:30 romain Exp $";
#endif /* lint */

#include <sys/param.h>
#include <sys/dir.h>
#include <sys/user.h>

#ifdef DYNIX
#define KERNEL
#include <sys/file.h>
#include <sys/vnode.h>
#include <sys/inode.h>
#undef KERNEL
#else
#define KERNEL
#include <sys/file.h>
#if !defined(sun) && !defined(pyr)
#include <sys/inode.h>
#endif
#undef KERNEL
#endif

#ifdef pyr
#else
#include <machine/pte.h>
#if !defined(ultrix) && !defined(sun)
#include <machine/machparam.h>
#endif
#endif
#include <sys/proc.h>
#include <nlist.h>
#include <sys/stat.h>
#include <pwd.h>
#include <fstab.h>
#include <sys/vmmac.h>
#include <stdio.h>

#ifdef sun
#include <kvm.h>
kvm_t	*kd;
#endif

#if defined(sun) || defined(pyr)
#include <sys/vnode.h>
#include <ufs/inode.h>
struct snode {
	struct snode *s_next;
	struct vnode s_vnode;
	struct vnode *s_realvp;
	struct vnode *s_bdevvp;
	u_short s_flag;
	dev_t s_dev;
};
#endif

#ifdef ultrix
#include <sys/gnode.h>
#include <sys/gnode_common.h>
#include <machine/param.h>
#endif

#include <sys/socket.h>
#include <sys/socketvar.h>
#include <net/route.h>
#include <netinet/in.h>
#include <netinet/in_pcb.h>
#include <netinet/tcp.h>
#include <netinet/tcp_fsm.h>
#include <netinet/tcp_timer.h>
#include <netinet/tcp_var.h>

#define CDIR	01
#define OFILE	02
#define RDIR	04
#define SHFILE	010
#define EXFILE	020
#define SOCKET  040

char *namelist;
char *corefile;
int k_opt = 0;
int n_opt = 0;

#ifdef	ultrix
#define	ls_t	long
#else
#define ls_t	off_t
#endif

#ifdef	sun
char	*sprintf();
#endif

ls_t lseek(), vtophys();

void eread(), eseek();
#ifdef	ultrix
void exit(), nlist(), perror();
#endif

int nproc;		/* number of entries in proc table 		*/
int mem;		/* fd for /dev/mem				*/
int kmem;
int swap;		/* fd for /dev/swap				*/
long procbase;
int ppid = -1;		/* previously display PID */

int dirinode;		/* directory (CDIR or RDIR) inode */
int opninode;		/* save inode of open file */
int pids_only = 0;	/* if non-zero, only output process ids	*/

char *progname;
struct nlist nl[] = {
#define	X_PROC		0
	{ "_proc" },
#define X_NPROC 	1
	{"_nproc"},
#define X_USRPTMA	2
    	{"_Usrptmap"},	
#define X_USRPT		3
	{"_usrpt"},
#define X_SYSMAP	4
	{"_Sysmap"},
#define	SFIL		5
	{ "_file" },
#define	SNFILE		6
	{ "_nfile" },
	{ "" },
};

#ifndef	DYNIX
struct pte *usrpt, *Usrptma;
#endif

int debug;

main(argc, argv)
	int 	argc;
	char	*argv[];
{

#ifdef ultrix
	struct gnode *i, *getinode();
#else
	struct inode *i, *getinode();
#endif
#ifdef	pyr
	int fdspace;
	struct file **fd_array;
#endif
	struct stat s;
	struct user *u, *getuser();
	struct proc p;
	register int filen, flags, procn;
	register char *filename, *fsname;
	struct fstab *fs, *getfsfile(), *getfsspec();
	char *getsockfp(), *rindex();
	struct file *fp;
	int ax, err, findf, nmct;
	char *ap;
	int exitval = 0;

#ifdef	lint
/*
 * The following code satisfies lint for KERNEL symbols.
 * This program is lint-free under 4.3BSD, DYNIX 3.0.1[24], SunOS 4.0
 * and ULTRIX 2.2, using the lint libraries of the systems at the
 * Purdue University Computing Center.
 */
#if	!defined(ultrix) && !defined(DYNIX) && !defined(sun)
	long lintlong;
#endif
#ifdef	ultrix
	struct nch *lintnch;
	float lintfloat;
#endif
#if	!defined(DYNIX)
	file = fileNFILE = NULL;
	fp = file;
	fp = fileNFILE;
	nfile = 0;
	filen = nfile;
#endif
#if	!defined(ultrix) && !defined(DYNIX) && !defined(sun)
	inode = inodeNINODE = rootdir = NULL;
	i = inode;
	i = inodeNINODE;
	i = rootdir;
	ninode = 0;
	nextinodeid = 0l;
	lintlong = nextinodeid;
	nextinodeid = lintlong;
	filen = ninode;
#endif
#ifdef	sun
	tcp_ttl = 0;
	filen  = tcp_ttl;
#endif
#ifdef	ultrix
	nch = NULL;
	lintnch = nch;
	nch = lintnch;
	nchsize = 0;
	filen = nchsize;
	tcp_alpha = tcp_beta = 0.0;
	lintfloat = tcp_alpha;
	lintfloat = tcp_beta;
	tcp_alpha = lintfloat;
#endif
#endif	/* lint */

	if ((progname = rindex(argv[0], '/')))
		progname++;
	else
		progname = argv[0];

	if (argc == 1) {

usage:

#ifdef	DYNIX
		(void) fprintf(stderr,
			"usage: %s [-d ] [-k nlist core] [-n] [-p] names\n",
			progname);
#else
		(void) fprintf(stderr,
			"usage: %s [-d ] [-n] [-p] names\n", progname);
#endif
		(void) fprintf(stderr, "\t-d    = select verbose debugging output\n");
#ifdef	DYNIX
		(void) fprintf(stderr,
			"\t-k    = use specified nlist and core files\n");
#endif
		(void) fprintf(stderr,
			"\t-n    = interpret names as network connection, hexadecimal,\n");
		(void) fprintf(stderr,
			"\t        Protocol Control Block (PCB) addresses, as supplied\n");
		(void) fprintf(stderr,
			"\t        by netstat's -A option\n");
		(void) fprintf(stderr, "\t-p    = print only process IDs\n");
		(void) fprintf(stderr,
			"\tnames = file names or PCB addresses\n");
		exit(exitval);
	}

	/* check for switches */
	for (err = 0, ax = 1; ax < argc; ax++) {
		ap = argv[ax];
		if (*ap++ != '-')
			break;
		while (*ap) {
			switch (*ap++) {

			case 'd':
				debug = 1;
				break;
#ifdef	DYNIX
			case 'k':
				if ((ax + 2) >= argc) {
					(void) fprintf(stderr,
						"%s: no nlist/core after -k\n",
						progname);
					err++;
				} else {
					namelist = argv[++ax];
					corefile = argv[++ax];
					k_opt = 1;
					continue;
				}
				break;
#endif
			case 'n':
				n_opt++;
				break;

			case 'p':
				pids_only = 1;
				break;

			default:
				(void) fprintf(stderr,
					"%s: unknown switch - %c\n",
					progname, *(ap - 1));
				err++;
			}
		}
	}
	if (ax >= argc) {
		(void) fprintf(stderr, "%s: no names specified\n", progname);
		err++;
	}
	if (err) {
		exitval = 1;
		goto usage;
	}

#ifdef sun
    	if ((kd = kvm_open (NULL, NULL, NULL, O_RDONLY)) == 0) {
		(void) fprintf(stderr, "%s: can't access memory: ",
			progname);
        	perror ("");
		exit(1);
	}
#endif
	if ((mem = open("/dev/mem", 0)) < 0) {
		(void) fprintf(stderr, "%s: /dev/mem: ", progname);
		perror("");
		exit(1);
	}
	if (k_opt) {
		if ((kmem = open(corefile, 0)) < 0) {
			(void) fprintf(stderr, "%s: %s: ",
				progname, corefile);
			perror("");
			exit(1);
		}
	} else {
		if ((kmem = open("/dev/kmem", 0)) < 0) {
			(void) fprintf(stderr, "%s: /dev/kmem: ", progname);
			perror("");
			exit(1);
		}
	}
	if (!k_opt) 
#ifndef pyr
		if ((swap = open("/dev/drum", 0)) < 0) {
			(void) fprintf(stderr, "%s: /dev/drum: ", progname);
			perror("");
			exit(1);
		}
#endif

	getsyms();

	for (err = 0, nmct = argc - ax; ax < argc; ax++) {
		/* if -n, then arg is a PCB */
		if (n_opt) {
			if ((filename = getsockfp(argv[ax], &fp)) == NULL) {
				err++;
				continue;
			}
			fsname = "";
		} else {
			/* assume arg is  a filesystem */
			if ((fs = getfsfile(argv[ax])) != NULL) {
				fsname = argv[ax];
				if (strcmp(".", argv[ax]) == 0)
					filename = argv[ax];
				else
					filename = fs->fs_spec;
			/* maybe it's the device name for a filesystem */
			} else if ((fs = getfsspec(argv[ax])) != NULL) {
				filename = argv[ax];
				fsname = fs->fs_file;
			/* probably a regular file */
			} else {
				filename = argv[ax];
				fsname = "";
			}
			if (stat(filename, &s)) {
				(void) fprintf(stderr, "%s: can't stat %s: ",
					progname, filename);
				perror("");
				err++;
				continue;
			}
			if (debug)
				(void) printf(
					"stat dev %x ino %d mode %x rdev %x\n",
					s.st_dev, s.st_ino, s.st_mode,
					s.st_rdev);
		}
		if (! pids_only) {
			(void) printf("%s\t%s", filename, fsname);
			if (!n_opt) {
				if ((s.st_mode & S_IFMT) == S_IFDIR)
					(void) printf("(directory)");
			}
			(void) printf("\n%-8.8s  %5s  %-6.6s  FD  %-14.14s",
				"USER", "PID", "TYPE", "CMD");
			if (!n_opt)
				(void) printf("  INODE");
			(void) printf("\n");
		}
		for (findf = procn = 0; procn < nproc; procn++) {
			procslot(procn, &p);
			flags = 0;
			if (p.p_stat == 0 || p.p_stat == SZOMB) 
				continue;
#ifdef sun
        		u = kvm_getu(kd, &p);
#else
			u = getuser(&p);
#endif

			if ( u == (struct user *)NULL)
				continue;
			if (debug)
				(void) printf("pid %d uid %d cmd %s\n", p.p_pid,
					p.p_uid, u->u_comm);
			if (!n_opt) {
				i = getinode(u->u_rdir, "rdir");
				if (check(&s, i)) {
					dirinode = s.st_ino;
					gotone(u, &p, -1, RDIR);
					findf++;
				}
				i = getinode(u->u_cdir, "cdir");
				if (check(&s, i)) {
					dirinode = s.st_ino;
					gotone(u, &p, -1, CDIR);
					findf++;
				}
			}
#ifdef	pyr
			if (u->u_fdheap) {
				fdspace = sizeof(caddr_t) * u->u_rlimit[RLIMIT_FDMAX].rlim_cur;
				fd_array = (struct file **)malloc(fdspace);
				eseek(kmem, (ls_t)u->u_ofile, 0, "u_ofile");
				eread(kmem, (char *)fd_array, fdspace, "u_ofile");
			}
			else
				fd_array = u->u_ofile_arr;

			for (filen = 0; filen < u->u_maxofile; filen++)
#else
#ifdef	DYNIX
			for (filen = 0; filen < u->u_nofile; filen++)
#else
			for (filen = 0; filen < NOFILE; filen++)
#endif
#endif
			{
				struct file f;

				flags = 0;
				if (n_opt) {
#ifdef	DYNIX
					if (u->u_lofile[filen].of_file != fp)
#else
#ifdef	pyr
					if (fd_array[filen] != fp)
#else
					if (u->u_ofile[filen] != fp)
#endif	pyr
#endif
						continue;
				} else {
#ifdef	DYNIX
					if (u->u_lofile[filen].of_file == NULL)
						continue;
#else
#ifdef	pyr
					if (fd_array[filen] == NULL)
						continue;
#else
					if (u->u_ofile[filen] == NULL)
						continue;
#endif	/* pyr */
#endif
				}

				if (k_opt)
#ifdef	DYNIX
					eseek(kmem, vtophys((ls_t)u->u_lofile[filen].of_file), 0, "file");
#else
				eseek(kmem, vtophys((ls_t)u->u_ofile[filen]), 0, "file");
#endif 
				else
#ifdef	DYNIX
					eseek(kmem, (ls_t)u->u_lofile[filen].of_file, 0, "file");
#else
#ifdef	pyr
				eseek(kmem, (ls_t)fd_array[filen], 0, "file");
#else
				eseek(kmem, (ls_t)u->u_ofile[filen], 0, "file");
#endif	/* pyr */
#endif
				eread(kmem, (char *)&f, sizeof(f), "file");

				if (f.f_count > 0) {
					if (n_opt && f.f_type == DTYPE_SOCKET) {
						gotone(u, &p, filen, SOCKET);
						findf++;
						continue;
					}
#if	defined(DTYPE_VNODE)
					if (f.f_type != DTYPE_VNODE)
#else
					if (f.f_type != DTYPE_INODE)
#endif
						continue;
#if	defined(DTYPE_VNODE)
					i = getinode((struct vnode *)f.f_data,
						"ofile");
#else
#ifdef	ultrix
					i = getinode((struct gnode *)f.f_data,
						"ofile");
#else
					i = getinode((struct inode *)f.f_data,
						"ofile");
#endif
#endif
					if (check(&s, i)) {
#if !defined(ultrix)
						opninode = i->i_number;
#else
						opninode = (int)i->g_req.gr_number;
#endif
						flags |= OFILE;
						if (f.f_flag & FEXLOCK) {
							flags |= EXFILE;
						}
						if (f.f_flag & FSHLOCK) {
							flags |= SHFILE;
						}
						gotone(u, &p, filen, flags);
						findf++;
					}
				}
			}
#ifdef	pyr
			if (u->u_fdheap)
				free(fd_array);
#endif
		}
		if (findf)
			nmct--;
		if (! pids_only) {
	    		(void) printf("\n");
			(void) fflush(stdout);
		}
	}
	if (pids_only && ppid != -1) {
		(void) printf("\n");
		(void) fflush(stdout);
	}
	exitval = (err || nmct) ? 1 : 0;
	exit(exitval);
}		

/*
 * print the name of the user owning process "p" and the pid of that process
 */
gotone(u, p, fd, f)
	struct user *u;
	struct proc *p;
	int fd;
	int f;
{
	char *ty, tybuf[8], *strcat(), *strcpy();
	struct passwd *getpwuid();
	register struct passwd *pw;

	/* only print pids and return */
	if (pids_only) {
		if (ppid != p->p_pid) {
			if (ppid != -1)
				(void) printf(" ");
			(void) printf("%d", p->p_pid);
			(void) fflush(stdout);
			ppid = p->p_pid;
		}
		return;
	}
	pw = getpwuid((int)p->p_uid);
	if (pw)
		(void) printf("%-8.8s  ", pw->pw_name );
	else
		(void) printf("%-8d  ", p->p_uid);
	(void) printf("%5d  ", p->p_pid);
	if (f & OFILE) {
		(void) strcpy(tybuf, "file");
		ty = tybuf;
		if (f & SHFILE)
			(void) strcat(ty, "/s");
		else if (f & EXFILE)
			(void) strcat(ty, "/x");
	} else if (f & CDIR)
		ty = "cwd";
	else if (f & RDIR)
		ty = "rdir";
	else if (f & SOCKET)
		ty = "sock";
	else
		ty = "";
	(void) printf("%-6.6s  ", ty);
	if (fd >= 0)
		(void) printf("%2d  ", fd);
	else
		(void) printf("    ");
	(void) printf("%-14.14s", u->u_comm);
	if (f & OFILE)
		(void) printf("  %5d", opninode);
	else if (f & (CDIR|RDIR))
		(void) printf("  %5d", dirinode);
	(void) printf("\n");
	return;
}

/*
 * is inode "i" on device "s"? returns TRUE or FALSE 
 */
check(s, i)
	struct stat *s;
#ifdef ultrix
	struct gnode *i;
#else
	struct inode *i;
#endif
{
	if (s == (struct stat *)NULL)
		return 0;
#ifdef ultrix
	if (i == (struct gnode *)NULL)
		return 0;
	if ((s->st_mode & S_IFMT) == S_IFBLK && s->st_rdev == i->g_dev)
			return 1;
	else if ((s->st_dev == i->g_dev) && (s->st_ino == i->g_req.gr_number))
			return 1;
#else
	if (i == (struct inode *)NULL) return 0;
	if ((s->st_mode & S_IFMT) == S_IFBLK && s->st_rdev == i->i_dev)
			return 1;
	else if ((s->st_dev == i->i_dev) && (s->st_ino == i->i_number))
			return 1;
#endif
#ifdef sun
	else if (s->st_rdev == i->i_dev && i->i_number == 0)
			return 1;
#endif
	else return 0;
}


/* 
 *	getinode - read an inode from from mem at address "addr"
 * 	      return pointer to inode struct. 
 */
#if defined(DTYPE_VNODE)
struct inode *
getinode(ip, s)
	struct vnode *ip;
	char *s;
{
	static struct inode i;
	static struct vnode v;
#if	defined(sun) || defined(pyr)
	struct snode sn;
#endif

	if (ip == NULL)
		return(NULL);
	if (k_opt)
		eseek(kmem, vtophys((ls_t)ip), 0, "vnode");
	else
		eseek(kmem, (ls_t)ip, 0, "vnode");
	eread(kmem, (char *)&v, sizeof(v), "vnode");
	if (debug)
		(void) printf("vnode %s at %x %x dev=%x vtype=%d inode@%x\n",
	 		s, ip, v.v_flag, v.v_rdev, v.v_type, v.v_data);
	if (k_opt)
		eseek(kmem, vtophys((ls_t)v.v_data), 0, "inode");
	else
		eseek(kmem, (ls_t)v.v_data, 0, "inode");
#if defined(sun) || defined(pyr)
#ifdef	pyr
	if (v.v_type == VBLK || v.v_type == VCHR)
#else
	if (v.v_type == VBLK || v.v_type == VCHR || v.v_type == VFIFO)
#endif
	{
		eread(kmem, (char *)&sn, sizeof(sn), "snode");
		if (debug)
			(void) printf(
			    "snode %s at %x %x dev=%x realvp=%x bdevvp=%x\n",
			    s, ip, sn.s_vnode.v_type, sn.s_dev,
			    sn.s_realvp, sn.s_bdevvp);
		if (sn.s_realvp || sn.s_bdevvp) {
			eseek(kmem,
				(sn.s_realvp) ? (ls_t)sn.s_realvp
					      : (ls_t)sn.s_bdevvp,
				0, "rvnode");
			eread(kmem, (char *)&v, sizeof(v), "rvnode");
			eseek(kmem, (ls_t)v.v_data, 0, "rinode");
		}
	}
#endif
	eread(kmem, (char *)&i, sizeof(i), "inode");
	if (debug)
		(void) printf("inode %s at %x %x dev=%x inode=%d vtype=%x\n",
		    s, v.v_data, i.i_flag, i.i_dev, i.i_number,
		    i.i_vnode.v_type);
	return &i;
}

#else
/* ARGSUSED */

#ifdef ultrix
struct gnode *
getinode(ip, s)
	struct gnode *ip;
#else

struct inode *
getinode(ip, s)
	struct inode *ip;
#endif

	char *s;
{
#if defined(ultrix) 
	static struct gnode i;
#else
	static struct inode i;
#endif

	eseek(kmem, (ls_t)ip, 0, "inode");
	eread(kmem, (char *)&i, sizeof(i), "inode");
	return &i;
}
#endif

#if !defined(sun)
/* 
 * get user page for proc "p" from core or swap
 * return pointer to user struct
 */
#ifdef	DYNIX
struct user *
getuser(p)
	struct proc *p;
{
	int btr;
	ls_t sp;
	static struct user *u = NULL;
	char *valloc();

	if (u == NULL) {
		if ((u = (struct user *) valloc(ctob(UPAGES))) == NULL) {
			(void) fprintf(stderr,
				"%s: can't allocate space for user structure\n",				progname);
			exit(1);
		}
	}
	btr = ctob(UPAGES);
	if ((p->p_flag & SLOAD) == 0) {
		if (k_opt)
			return (struct user *)NULL;
		sp = (ls_t) dtob(p->p_swaddr);
		if (lseek(swap, sp, 0) != sp) {
			if (debug) {
				(void) fprintf(stderr,
					"%s: error seeking to swap for %d: ",
					progname, p->p_pid);
				perror("");
			}
			return (struct user *)NULL;
		}
		if (read(swap, (char*)u, btr) != btr) {
			if (debug) {
				(void) fprintf(stderr,
				    "%s: error reading swap for %d: ",
				    progname, p->p_pid);
				perror("");
			}
			return (struct user *)NULL;
		}
		if (debug)
			(void) printf("read swap\n");
	} else {
		if (k_opt)
			(void) lseek(kmem, vtophys((ls_t)p->p_uarea), L_SET);
		else
			(void) lseek(kmem, (ls_t)p->p_uarea, L_SET);
		if (read(kmem, (char *)u, btr) != btr)
			return (struct user *)NULL;
	}
	return u;
}
#else
#ifdef	pyr
struct user *
getuser(p)
	struct proc *p;
{
	static struct user *u = NULL;
	char *valloc();

	if (u == NULL) {
		if ((u = (struct user *) valloc(ptob(UPAGES))) == NULL) {
			(void) fprintf(stderr,
				"%s: can't allocate space for user structure\n",				progname);
			exit(1);
		}
	}
	if (readublk(p->p_pid, u) == -1)
		return (struct user *)NULL;
	else
		return u;
}
#else
struct user *
getuser(p)
	struct proc *p;
{
	struct pte *ptep, apte;
	struct pte mypgtbl[NBPG/sizeof(struct pte)];
	int upage;
	char *up;
	static struct user user;

	/* easy way */
	if ((p->p_flag & SLOAD) == 0) {
		if (k_opt)
			return (struct user *)NULL;
		(void) lseek(swap, (ls_t)dtob(p->p_swaddr), 0);
		if (read(swap, (char *)&user, sizeof(struct user))==0) {
			(void) fprintf(stderr,
				"%s: can't get swapped user page\n",
				progname);
			return (struct user *)NULL;
		}
		if (debug)
			(void) printf("read swap\n");
	} else { 	/* boo */
		ptep = &Usrptma[btokmx(p->p_p0br) + p->p_szpt - 1];

		/* get the page table for the user page */
		(void) lseek(kmem, (ls_t)ptep, 0);
		if (read(kmem, (char *)&apte, sizeof(apte)) == 0) {
			(void) fprintf(stderr,
				"%s: can't get user page table\n",
				progname);
			return (struct user *)NULL;
		}

		/* now get this user's page table */
		eseek(mem, (ls_t)ctob(apte.pg_pfnum) ,0, "page tbl");
		if (read(mem, (char *)mypgtbl, sizeof(mypgtbl)) == 0) {
			(void) fprintf(stderr,
				"%s: can't get mypgtbl.\n", progname);
			return (struct user *)NULL;
		}
		/* now collect various pages of u area */
		for (upage = 0, up = (char *)&user; upage < sizeof(struct user)/NBPG; upage++) {
			eseek(mem, (ls_t)ctob(mypgtbl[NPTEPG-UPAGES+upage].pg_pfnum), 0, "u page");
			if (read(mem, up, NBPG) == 0) {
				(void) fprintf(stderr,
				    "%s: can't get page %d of user area.\n",
				    progname, upage);
				return(NULL);
			}
			up += NBPG;
		}
	}
	return &user;
}
#endif /* pyr */
#endif

#endif
/*
 * read with error checking
 */
void
eread(fd, p, size, s)
	int fd;
	char *p;
	int size;
	char *s;
{
	char buf[100];
	if (read(fd, p, size) != size) {
		if (!k_opt) {
			(void) fprintf(stderr, "%s: eread ", progname);
			perror("");
		}
		(void) sprintf(buf, "read error for %s\n", s);
		error(buf);
	}
}

/*
 * seek with error checking
 */
void
eseek(fd, off, whence, s)
	int fd;
	ls_t off;
	int whence;
	char *s;
{
	ls_t ret;
	char buf[100];

#ifdef pyr
	if (( ret = lseek(fd, off, whence)) == -1)
#else
	if (( ret = lseek(fd, off, whence)) != off)
#endif
	{
		(void) sprintf(buf, "seek for %s failed, wanted %o, got %o.\n",
			s, off, ret);
		error(buf);
	}
}

/*
 * print mesg "s", don't exit if we are processing a core, 
 * so that corrupt entries don't prevent further uncorrupted
 * entries from showing up.
 */
error(s)
	char *s;
{
	if (s && !k_opt)
		(void) fprintf(stderr, "%s: %s", progname, s);
	if (!k_opt)
		exit(1);
}

/*
 * get some symbols form the kernel
 */
getsyms()
{
	register i;

	if (k_opt) {
#ifdef	ultrix
		(void) nlist(namelist, nl);
#else	/* not ultrix */
		if (nlist(namelist, nl) == -1) {
			(void) fprintf(stderr,
				"%s: can't get name list from %s\n",
				progname, namelist);
			exit(1);
		}
#endif	/* ultrix */
	} else {
#ifdef	ultrix
		(void) nlist("/vmunix", nl);
#else	/* not ultrix */
#ifdef	DYNIX
		if (nlist("/dynix", nl) == -1)
#else	/* not DYNIX */
		if (nlist("/vmunix", nl) == -1)
#endif	/* DYNIX */
		{
			(void) fprintf(stderr,
				"%s: can't get name list from %s\n",
#ifdef	DYNIX
				progname, "/dynix");
#else	/* not DYNIX */
				progname, "/vmunix");
#endif	/* DYNIX */
			exit(1);
		}
#endif	/* ultrix */
	}

	for (i = 0; i < (sizeof(nl)/sizeof(nl[0]))-1; i++)
		if (nl[i].n_value == 0) {
			(void) fprintf(stderr, "%s: can't nlist symbol %s\n",
				progname, nl[i].n_name);
			exit(1);
		}

		eseek(kmem, (ls_t)(nl[X_PROC].n_value), 0, "procbase 1");
		eread(kmem, (char *)&procbase, sizeof(procbase), "procbase 1");
		eseek(kmem, (ls_t)(nl[X_NPROC].n_value), 0, "nproc");
		eread(kmem, (char *)&nproc, sizeof(nproc), "nproc");

#ifndef	DYNIX
	Usrptma = (struct pte *)nl[X_USRPTMA].n_value;
	usrpt = (struct pte *)nl[X_USRPT].n_value;	/* used by <vmmac.h>*/
#endif
	return;
}

/*
 * read proc table entry "n" into buffer "p"
 */
procslot(n, p)
	int n;
	struct proc *p;
{
	if (k_opt)
		eseek(kmem, vtophys((ls_t)(procbase + (long)(n * sizeof(struct proc)))), 0, "proc");
	else
		eseek(kmem, (ls_t)(procbase + (long)(n * sizeof(struct proc))), 0, "proc");
	eread(kmem, (char *)p, sizeof(struct proc), "proc");
	return;
}

/*
 * When looking at kernel data space through /dev/mem or
 * with a core file, do virtual memory mapping.
 */
ls_t
vtophys(vaddr)
	ls_t vaddr;
{
	u_int paddr;
	
#ifdef	i386
	if (vaddr < 8192)
		return vaddr;
#endif
	paddr = nl[X_SYSMAP].n_value;
	(void) lseek(kmem, (ls_t)paddr, 0);
	(void) read(kmem, (char *)&paddr, sizeof paddr);
	paddr = (int)((int *)paddr + (vaddr / NBPG));
	(void) lseek(kmem, (ls_t)paddr, 0);
	(void) read(kmem, (char *)&paddr, sizeof paddr);
#ifndef	i386
# define	PTBITS	0x1ff	/* 512 byte pages */
#else
# define	PTBITS	0xfff	/* 4096 byte pages */
#endif

	return ((ls_t)(paddr & ~PTBITS) | (vaddr & PTBITS));
}

/*
 * get file pointer for socket
 */
char *
getsockfp(cba, pfp)
	char *cba;
	struct file **pfp;
{
	register char *cp;
	struct file *socktofile();
	struct inpcb inpcb;
	static char nmbuf[128];
	struct socket sock;
	struct tcpcb tcpcb;
	long x;

/*
 * Convert PCB address from ASCII to hex.
 */
	for (cp = cba, x = 0l; *cp; cp++) {
		x <<= 4;
		if (*cp >= '0' && *cp <= '9')
			x += *cp - '0';
		else if (*cp >= 'a' && *cp <= 'f')
			x += *cp - 'a' + 10;
		else if (*cp >= 'A' && *cp <= 'F')
			x += *cp - 'A' + 10;
		else {
			(void) fprintf(stderr,
				"%s: non-hex address, %s\n", progname, cba);
			return(NULL);
		}
	}
/*
 * Read PCB and make sure it is in LISTEN or ESTABLISHED state.
 */
	eseek(kmem, (ls_t)x, 0, "tcpcb");
	eread(kmem, (char *)&tcpcb, sizeof(tcpcb), "tcpcb");
	if (tcpcb.t_state < TCPS_LISTEN || tcpcb.t_state > TCPS_ESTABLISHED) {
		(void) fprintf(stderr,
			"%s: PCB %x not in LISTEN to ESTABLISHED state\n",
			progname, x);
		return(NULL);
	}
	if (tcpcb.t_inpcb == (struct inpcb *)0) {
		(void) fprintf(stderr,
			"%s: PCB %x has no INPCB\n",
			progname, x);
		return(NULL);
	}
/*
 * Read INPCB for PCB and make sure it points back to the PCB.
 */
	eseek(kmem, (ls_t)tcpcb.t_inpcb, 0, "inpcb");
	eread(kmem, (char *)&inpcb, sizeof(inpcb), "inpcb");
	if ((caddr_t)x != inpcb.inp_ppcb) {
		(void) fprintf(stderr,
			"%s: INPCB for PCB %x not linked to it\n",
			progname, x);
		return(NULL);
	}
/*
 * Read the socket and make sure it points back to the INPCB.
 */
	eseek(kmem, (ls_t)inpcb.inp_socket, 0, "socket");
	eread(kmem, (char *)&sock, sizeof(sock), "socket");
	if (sock.so_pcb != (caddr_t)tcpcb.t_inpcb) {
		(void) fprintf(stderr,
			"%s: socket not linked to INPCB for PCB %x\n",
			progname, x);
		return(NULL);
	}
/*
 * Find the file structure that is linked to the socket.
 */
	if ((*pfp = socktofile((caddr_t)inpcb.inp_socket)) == NULL) {
		(void) fprintf(stderr,
			"%s: no file structure for socket of PCB %x\n",
			progname, x);
		return(NULL);
	}
/*
 * Construct a pseudo file name and return it.
 */
	(void) sprintf(nmbuf,
		"file %lx of socket %lx of INPCB %lx of PCB %lx",
		(long)*pfp, (long)inpcb.inp_socket, (long)tcpcb.t_inpcb, x);
	return(nmbuf);
}

/*
 * Convert a socket address to a file address.
 */
struct file *
socktofile(s)
	caddr_t s;
{
	register struct file *afile;
	char *calloc();
	register struct file *fp;
	static struct file *ftp;
	static int nfile = -1;
	static struct file *xfile = NULL;

/*
 * Read the size of file table, allocate space
 * for it, and read the file table pointer (once).
 */
	if (nfile < 0) {
		eseek(kmem, (ls_t)(nl[SNFILE].n_value), 0, "_nfile");
		eread(kmem, (char *)&nfile, sizeof(nfile), "_nfile");
		xfile = (struct file *) calloc((unsigned)nfile, sizeof (struct file));
		eseek(kmem, (ls_t)(nl[SFIL].n_value), 0, "_file");
		eread(kmem, (char *)&ftp, sizeof(ftp), "_file");
	}
/*
 * Read the file table and search for an in-use
 * socket file with a matching data address.
 */
	eseek(kmem, (ls_t)ftp, 0, "_file");
	eread(kmem, (char *)xfile, nfile * sizeof(struct file), "_file");
	for (fp = xfile, afile = ftp; fp < &xfile[nfile]; fp++, afile++) {
		if (fp->f_count && fp->f_type == DTYPE_SOCKET
		&&  s == fp->f_data)
			return(afile);
	}
	return(NULL);
}