/*
 *	lsof.c - list open files
 */


/*
 *	Lsof lists files opened by processes of:
 *
 *		AIX 3.1.[357]		(#define _IBMR2)
 *		Purdue DYNIX 3.0.12	(#define DYNIX)
 *		Sequent DYNIX 3.0.12	(#define DYNIX, #define SEQUENT)
 *		Sequent DYNIX 3.1.2	(#define DYNIX31)
 *		HP-UX 7.x		(#define hpux, #define HPUX7)
 *		HP-UX 8.x		(#define hpux, #define HPUX8)
 *		NeXTStep 2.[01]		(#define NeXT)
 *		SunOS 4.1.1		(#define sun)
 */

/*
 * Copyright 1991 Purdue Research Foundation, West Lafayette, Indiana
 * 47907.  All rights reserved.
 *
 * Written by Victor A. Abell
 *
 * This software is not subject to any license of the American Telephone
 * and Telegraph Company or the Regents of the University of California.
 *
 * Permission is granted to anyone to use this software for any purpose on
 * any computer system, and to alter it and redistribute it freely, subject
 * to the following restrictions:
 *
 * 1. Neither the author nor Purdue University are responsible for any
 *    consequences of the use of this software.
 *
 * 2. The origin of this software must not be misrepresented, either by
 *    explicit claim or by omission.  Credit to the author and Purdue
 *    University must appear in documentation and sources.
 *
 * 3. Altered versions must be plainly marked as such, and must not be
 *    misrepresented as being the original software.
 *
 * 4. This notice may not be removed or altered.
 */

#if	!defined(lint)
static char copyright[] =
"@(#) Copyright 1991 Purdue Research Foundation.\nAll rights reserved.\n";
#endif

static char Version[] = "1.0";


/*
 *	Usage:
 *
 *	    lsof [-d] [-h] [-l] [-n] [-N] [-p l] [-s] [-t] [-u l] [-U] [names]
 *
 *	where:
 *
 *		-d	Issue error messages about unreadable /dev
 *			subdirectories.
 *
 *		-h	List help.
 *
 *		-l	Do not convert User ID numbers to login names.
 *
 *		-n	List Internet network files.
 *
 *		-N	List NFS files.
 *
 *		-p l	List files for Process IDentifier list l -- comma
 *			separated list of numbers.
 *
 *		-s	Do not display file size.
 *
 *		-t	List terse output -- i. e., Process ID numbers without
 *			a header.
 *
 *		-u l	List files for user list l -- comma separated list of
 *			login names or User IDentification numbers.
 *
 *		-U	List Unix domain sockets.
 *
 *		names	are the path names of file systems, mount points,
 *			devices and files to locate.
 */

#if	defined(NeXT) && !defined(MACH)
/*
 * The definition of MACH for the NeXT is required for proper header
 * file configuration -- i. e., some header files have ``#ifdef MACH''
 * statements that affect the size of kernel structures.
 */

#define MACH	1
#endif

#include <sys/types.h>
#include <sys/param.h>

#include <ctype.h>
#include <errno.h>
#include <pwd.h>
#include <setjmp.h>
#include <stdio.h>

#include <sys/domain.h>
#include <sys/mbuf.h>
#include <sys/protosw.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/un.h>
#include <sys/unpcb.h>
#include <sys/vfs.h>
#include <sys/vnode.h>
#include <net/route.h>
#include <netinet/in.h>
#include <netinet/in_pcb.h>

#if	defined(DYNIX31)
#undef	SEQUENT
#undef	DYNIX
#define	DYNIX
#endif

#if	defined(DYNIX)
#include <mntent.h>
#include <strings.h>
#include <nlist.h>
#include <nfs/nfs.h>
#include <nfs/nfs_clnt.h>
#include <nfs/rnode.h>
#include <sys/dir.h>
#include <sys/file.h>
#include <sys/proc.h>
#define KERNEL
#include <sys/file.h>
#include <sys/inode.h>
#include <ufs/mount.h>
#undef KERNEL
#include <sys/user.h>

#if	!defined(DYNIX31)
/*
 * This is from sys/user.h.  It's ifdef KERNEL, though, and defining
 * KERNEL for user.h breaks other things.
 *
 * Open-file table extension object structure.
 */

struct  ofile_ext {
	struct  ofile_ext *oe_next;             /* list of unused entries */
	short           oe_nofile;              /* # ofile entries */
	short           oe_refcnt;              /* # proc's sharing this ext */
	short           oe_ccount;              /* # sharing proc's in memory */
	swblk_t         oe_swaddr;              /* disk address when swapped */
	sema_t          oe_mutex;               /* misc mutex */
	struct  ofile   *oe_ofile;              /* array of open files */
};
#endif

#endif

#if	defined(hpux)
#include <stdlib.h>
#include <dirent.h>
#include <mntent.h>
#include <string.h>
#include <nlist.h>
#include <rpc/types.h>
#include <nfs/nfs.h>
#include <nfs/nfs_clnt.h>
#include <nfs/rnode.h>
#include <nfs/snode.h>
#include <sys/file.h>
#include <sys/inode.h>

#if	defined(HPUX8)
#include <sys/pstat.h>
#endif

#include <sys/resource.h>
#include <sys/proc.h>
#include <sys/vmmac.h>
#include <sys/user.h>

/*
 * This is from <sys/mount.h>, defined under the _KERNEL symbol.
 * Unfortunately, defining _KERNEL causes <sys/mount.h> to include
 * other header files not in <sys>.
 */

struct mount {
	struct	mount *m_hforw;  /* forward hash pointer */
	struct	mount *m_hback;  /* backward hash pointer */
	struct	mount *m_rhforw; /* forward hash pointer for real device */
	struct	mount *m_rhback; /* backward hash pointer for real device */
	struct vfs	*m_vfsp; /* vfs structure for this filesystem */
	dev_t	m_dev;		 /* device mounted */
   };
#endif

#if	defined(_IBMR2)
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
#if	!defined(_KERNEL)
#define _KERNEL	1
#endif
#include <sys/file.h>
#undef	_KERNEL
#include <sys/mntctl.h>
#include <sys/sysmacros.h>
#include <sys/vattr.h>
#include <sys/vmount.h>
#include <procinfo.h>
#include <nfs/rnode.h>

/*
 * AIX 3.1.[357] doesn't supply the necessary cdrnode.h.
 */

struct cdrnode {
	caddr_t		f1[4];
	struct gnode	f2;
	dev_t		f3;
	ino_t		cn_inumber;	/* inode number */
	caddr_t		f4;
	cnt_t		f5[2];
	u_short		f6;
	uint		f7[2];
	uchar		f8[3];
	off_t		cn_size;	/* size of file in bytes */
};
#endif

#if	defined(NeXT)
#include <c.h>
#include <stdlib.h>
#include <string.h>
#include <mntent.h>
#include <nlist.h>
#include <signal.h>
#include <kern/queue.h>
#include <sys/policy.h>
#if	!defined(NCPUS)
#define NCPUS	1
#endif
#include <kern/task.h>
#include <netinet/in.h>
#include <rpc/rpc.h>
#include <rpc/xdr.h>
#include <nfs/nfs.h>
#include <nfs/nfs_clnt.h>
#include <nfs/rnode.h>
#include <sys/dir.h>
#include <sys/domain.h>
#if	!defined(KERNEL)
#define KERNEL
#endif
#include <sys/file.h>
#undef  KERNEL
#include <ufs/mount.h>
#include <sys/protosw.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
#include <sys/stat.h>
#include <sys/ucred.h>
#include <sys/un.h>
#include <sys/unpcb.h>
#if	!defined(SHOW_UTT)
#define SHOW_UTT
#endif
#include <sys/user.h>
#undef	SHOW_UTT
#include <sys/proc.h>
#include <sys/vfs.h>
#include <ufs/inode.h>

/*
 * The following substitution compensates for the snode.h that NeXT does
 * not supply in NeXTStep 2.0 or 2.1.  The value of interest is s_realvp.
 */

struct snode {
	struct	snode *s_next;		/* must be first */
	struct	vnode s_vnode;		/* vnode associated with this snode */
	struct	vnode *s_realvp;	/* vnode for the fs entry (if any) */
};
#endif

#if	defined(sun)
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
#include <kvm.h>
#include <mntent.h>
#include <nlist.h>
#include <signal.h>
#include <rpc/types.h>
#include <nfs/nfs.h>
#include <nfs/rnode.h>
#include <specfs/snode.h>
#include <sys/proc.h>
#include <sys/sysmacros.h>
#include <sys/user.h>
#include <tmpfs/tmpnode.h>
#include <ufs/inode.h>
#include <ufs/mount.h>
#if	!defined(KERNEL)
#define KERNEL	1
#endif
#include <sys/file.h>
#include <specfs/fifonode.h>
#undef	KERNEL
#endif

extern int errno;

extern struct passwd *getpwnam(), *getpwuid();

#if	defined(DYNIX) || defined(sun)
extern int nlist();
#endif

extern char *optarg;
extern int optind;
extern char *sys_errlist[];

#define DEVINCR		1024	/* device table malloc() increment */
#define IPROTOL		5	/* Internet protocol length */
#define LOGINML		8	/* login name length */
#define PIDINCR		10	/* PID table malloc() increment */
#define STATTMO		5	/* stat() timeout in seconds */
#define UIDINCR		10	/* UID table malloc() increment */
#define USERPRTL	8
#define V_REG		0	/* vnode is regular */
#define V_FIFO		1	/* vnode is a FIFO */
#define V_NFS		2	/* vnode is an NFS file system */
#define V_STREAM	3	/* vnode is a stream */
#define V_TMP		4	/* vnode is a tmpfs */

#if	defined(DYNIX)
#define MALLOC_P	char
#define FREE_P		MALLOC_P
#define MALLOC_S	unsigned
#define N_UNIX		"/dynix"
#define QSORT_P		char
#define STRNCPY_L	int
#define SWAP		"/dev/drum"
#define U_SIZE		sizeof(struct user)

#if	defined(DYNIX31)
#define strchr		index
#define strrchr		rindex
#endif

#if	defined(SEQUENT)
#define strchr		index
#define strrchr		rindex
#define	uid_t		int
#define	unp_addr	unp_remaddr
#endif

#endif

#if	defined(hpux)
#define MALLOC_P	char
#define FREE_P		void
#define MALLOC_S	unsigned
#define MOUNTED		MNT_MNTTAB
#define N_UNIX		"/hp-ux"
#define PROCSIZE	sizeof(struct proc)
#define QSORT_P		void
#define STRNCPY_L	size_t
#define SWAP		"/dev/swap"

#if	defined(HPUX7)
#define unp_addr	unp_locaddr
/*
 * HP-UX 7.x SWAP must be read in DEV_BSIZE chunks.
 */
#define U_SIZE		(((DEV_BSIZE+sizeof(struct user))/DEV_BSIZE)*DEV_BSIZE)
#endif

#if	defined(HPUX8)
#define	U_SIZE		sizeof(struct user)
#endif

#endif

#if	defined(_IBMR2)
#define MALLOC_P	void
#define FREE_P		MALLOC_P
#define MALLOC_S	size_t
#define PROCSIZE	sizeof(struct procinfo)
#define QSORT_P		void
#define STRNCPY_L	int
#define U_SIZE		sizeof(struct user)
#endif

#if	defined(NeXT)
#define MALLOC_P	void
#define FREE_P		MALLOC_P
#define MALLOC_S	size_t
#define PROCSIZE	sizeof(struct proc)
#define QSORT_P		void
#define STRNCPY_L	int
#define U_SIZE		sizeof(struct user)
#if	!defined(VMUNIX)
#define VMUNIX		"/mach"
#endif
#endif

#if	defined(sun)
#define CLONEMAJ	37	/* major device number for clone device */
#define MALLOC_P	char
#define FREE_P		MALLOC_P
#define MALLOC_S	unsigned
#define N_UNIX		"/vmunix"
#define PROCSIZE	sizeof(struct proc)
#define QSORT_P		char
#define STRNCPY_L	int
#define U_SIZE		sizeof(struct user)
#endif


/*
 * Global storage definitions
 */

#if	defined(sun)
struct clone {
	struct dev *dp;		/* pointer to device entry in Devtp[] */
	struct clone *next;

} *Clone = NULL;
#endif

char *Command;			/* command name */
dev_t Dev;			/* device number */
char Devch[32];			/* alternate characters for device printing */

struct dev {
	dev_t rdev;		/* device */
	char *name;		/* name */

} *Devtp = NULL;		/* device table pointer */

char Fd[8];			/* file descriptor for printing */
int Fdev = 0;			/* have device number flag */
int Fdevmsg = 0;		/* -d flag status */
int Fhelp = 0;			/* -h flag status */
int Fnet = 0;			/* -n flag status */
int Fnfs = 0;			/* -N flag status */
int Fprint = 0;			/* print line flag */
int Fsize = 1;			/* -s flag status */
int Fterse = 0;			/* -t flag status */
int Funix = 0;			/* -U flag status */
int Futol = 1;			/* -l flag status */
int Hdr = 0;			/* header print status */
long Inode = -1l;		/* inode number
				 *	-1: none (don't print anything)
				 *	-2: blank (print spaces) */
char Iproto[IPROTOL+1];		/* Internet protocol name */

#if	defined(sun)
kvm_t *Kd;			/* kvm descriptor */
#endif

int Kmem = -1;			/* /dev/kmem file descriptor */

struct l_vfs {

	struct vfs *addr;	/* kernel address */

#if	defined(DYNIX) || defined(hpux) || defined(_IBMR2)
	dev_t dev;		/* device */
#endif
	char *dir;		/* mounted directory */
	char *fsname;		/* file system name */

#if	defined(_IBMR2)
	int vmt_flags;		/* vmount flags */
	int vmt_gfstype;	/* vmount gfs type */
#endif

	struct l_vfs *next;	/* next entry pointer */
} *Lvfs = NULL;			/* local vfs structure table */

#if	defined(HPUX7)
int Mem = -1;			/* /dev/mem file descriptor */
#endif

char Lock = ' ';		/* lock status */

struct mounts {
        dev_t dev;              /* st_dev */
        char *dir;              /* directory */
        char *fsname;           /* file system */
	ino_t inode;		/* st_ino */

#if	defined(DYNIX) || defined(_IBMR2) || defined(NeXT)
	u_short mode;		/* st_mode */
#endif

#if	defined(hpux) || defined(sun)
	mode_t mode;		/* st_mode */
#endif

        struct mounts *next;    /* forward link */
	dev_t rdev;		/* st_rdev */

} *Mtab = NULL;                 /* mounted devices */

int Mxpid = 0;			/* maximum PID table entries */
int Mxuid = 0;			/* maximum UID table entries */
char Namech[1024];		/* name characters for printing */
int Ndev = 0;			/* number of device table entries */

#if	defined(DYNIX)
struct nlist Nl[] = {
        { "_proc" },
#define X_PROC          0
        {"_nproc"},
#define X_NPROC         1
        {"_nfs_vnodeops"},
#define X_NFS_OPS	2
	{ "" },
};
#endif

#if	defined(hpux)
struct nlist Nl[] = {

#if	defined(hp9000s300)
        {"_proc"},
#define X_PROC          0
        {"_nproc"},
#define X_NPROC         1
        {"_nfs_vnodeops"},
#define X_NFS_OPS	2

#if	defined(HPUX7)
	{"_Usrptmap"},
#define X_USRPTMAP	3
	{"_usrpt"},
#define X_USRPT		4
#endif

#endif

#if	defined(hp9000s800)
	{"proc"},
#define X_PROC          0
	{"nproc"},
#define X_NPROC         1
        {"nfs_vnodeops"},
#define X_NFS_OPS	2

#if	defined(HPUX7)
	{"ubase"},
#define X_UBASE		3
	{"npids"},
#define X_NPIDS		4
#endif

#endif

	{ "" }
};
#endif

#if	defined(NeXT)

static struct nlist Nl[] = {
        { {"_allproc"},      0, 0, 0 },
#define X_ALLPROC                               0
        { {"_nfs_vnodeops"}, 0, 0, 0},
#define X_NFS_OPS                               1
        {  {""},             0, 0, 0  },
};
#endif

#if	defined(sun)
struct nlist Nl[] = {
        {"_nfs_vnodeops"},
#define X_NFS_OPS	0
	{ "_tmp_vnodeops"},
#define X_TMP_OPS	1
	{ "" }
};
#endif

int Npid = 0;			/* -p flag count */
int Nuid = 0;			/* -u flag count */

#if	defined(HPUX7) && defined(hp9000s800)
int npids;			/* number of PIDs (for uvadd()) */
struct proc *proc;		/* process table address (for uvadd()) */
#endif

#if	defined(hpux)
long Procaddr;			/* kernel process table entry address */
#endif

struct dev **Sdev = NULL;	/* pointer to device table pointers, sorted
				 * by device */

struct sfile {
	char *name;		/* file name */
	char *devnm;		/* device name (optional) */
	dev_t dev;		/* device */

#if	defined(_IBMR2)
	chan_t ch;		/* channel (last path component, if numeric) */
#endif

	u_short mode;		/* S_IFMT mode bits from stat() */
	int type;		/* file type: 0 = file system
				 *	      1 = regular file */
	ino_t i;		/* inode number */
	int f;			/* file found flag */
	struct sfile *next;	/* link to next entry */

} *Sfile = NULL;		/* chain of files to search for */

off_t Size;			/* file size */
int Size_def;			/* file size is defined */
int *Spid = NULL;		/* Process IDs to search for */
int *Suid = NULL;		/* User IDs to search for */

#if	defined(DYNIX) || defined(hpux)
int Swap = -1;			/* swap device file descriptor */
#endif

int Pid;			/* Process ID */
char *Pn;			/* program name */

jmp_buf Tmo_jbuf;		/* jump buffer for mount stat timeout */

char Type[8];			/* type for printing */
char User[USERPRTL+1];		/* User ID */

#if	defined(HPUX7) && defined(hp9000s300)
struct pte *Usrptmap;		/* user page table map pointer */
struct pte *usrpt;		/* user page table pointer
				 * (for bktomx from vmmac.h) */
#endif

#if	defined(HPUX7) && defined(hp9000s800)
struct user *ubase;		/* user area base (for uvadd()) */
#endif

int Vtype;			/* vnode type (see V_* symbols) */


int compdev(), getchan(), isfile(), kread(), readinode(),
    readlink(), readrnode(), readvnode(), statsafely();

char *endnm(), isglocked();

struct l_vfs *readvfs();

void printchdevname(), printfile(), printinaddr(), printiproto(),
     printline(), printsocket(), printuid(), printvnode(), readdev(),
     readmnt(), stkdir();

#if	defined(DYNIX)
char *malloc(), *realloc();
int stattimeout();
void completevfs();
u_short ntohs();
#endif

#if	defined(hpux)
int readsnode();
off_t lseek();
void completevfs(), stattimeout();
#endif

#if	defined(_IBMR2)
int readcdrnode(), readgnode();
void stattimeout();
#endif

#if	defined(NeXT)
int readsnode();
void completevfs(), stattimeout();
#endif

#if	defined(sun)
int readfifonode(), readsnode(), readtnode();
void completevfs(), stattimeout();
#endif

/*
 * Process structure redefinitions
 */

#if	defined(_IBMR2)
#define p_pid	pi_pid
#define p_stat	pi_stat
#define p_uid	pi_uid
#endif

/*
 * User structure redefinitions
 */

#if	defined(NeXT)
#define u_comm	uu_comm
#define u_cdir	uu_cdir
#endif


/*
 * main() - main program
 */

main(argc, argv)
	int argc;
	char *argv[];
{
	int c;
	int err = 0;
	char *fnm;
	int fprint;
	char *fsnm;
	int ftype;
	int i;
	int llen, llenx;
	struct mounts *mp;
	char *path;
	char *s;
	struct stat sb;
	int selflg, selpid, seluid;
	struct sfile *sfp;
	char syml[MAXPATHLEN];
	char *symlp;
	char symlx[MAXPATHLEN];

#if	defined(DYNIX)
	long kp;
	int nf, np;
	static struct ofile *ofp = NULL;
	struct proc *p;
	struct proc ps;
	int px;
	struct user *u;
	struct ofile *uf;
	unsigned ui;
	struct user us;
	static int xnf = 0;

#if	!defined(DYNIX31)
	struct ofile_ext ofx;
#endif

#if	defined(DYNIX31)
	struct ofile_tab oft;
#endif

#endif

#if	defined(hpux)

#if	defined(HPUX7)
	int k;
	char us[U_SIZE];	/* must read HP-UX SWAP in DEV_BSIZE chunks */
#endif

#if	defined(HPUX8)
	struct ofile_t *ofp;
	struct ofile_t oft;
	struct user us;
#endif

	int j;
	long kp;
	int np;
	struct proc *p;
	struct proc ps;
	int px;
	struct user *u;
#endif

#if	defined(_IBMR2)
	int np;
	struct procinfo *p;
	struct user *u;
	struct user us;
#endif

#if	defined(NeXT)
	MALLOC_S nb;
	int nf;
	struct proc *np, *p, *procp, ps;
	static MALLOC_S pnb = 0;
        struct task t;
        struct file **uf = NULL;
        struct utask *u, ut;
#endif

#if	defined(sun)
	int nf;
	struct proc *p;
	struct user *u;
	struct file **uf;
	unsigned ui;
	static int xnf = 0;
	static struct file **xuf = NULL;
#endif

/*
 * Save program name for messages.
 */
	if ((Pn = strrchr(argv[0], '/')) != NULL)
		Pn++;
	else
		Pn = argv[0];
/*
 * Process arguments.
 */
	while ((c = getopt(argc, argv, "dhlnNp:stu:U")) != EOF) {
		switch(c) {

		case 'd':
			Fdevmsg = 1;
			break;
		case 'h':
			Fhelp = 1;
			break;
		case 'l':
			Futol = 0;
			break;
		case 'n':
			Fnet = 1;
			break;
		case 'N':
			Fnfs = 1;
			break;
		case 'p':
			if (entpid(optarg))
				err++;
			break;
		case 's':
			Fsize = 0;
			break;
		case 't':
			Fterse = 1;
			break;
		case 'u':
			if (entuid(optarg))
				err++;
			break;
		case 'U':
			Funix = 1;
			break;
		case '?':
			err++;
			break;
		default:
			(void) fprintf(stderr, "%s: unknown option (%c)\n",
				Pn, c);
			err++;
		}
	}
/*
 * Read the mount table and process any file names.
 */
	(void) readmnt();
	for (i = optind; i < argc; i++) {

	/*
	 * Dereference a symbolic link.
	 */
		if ((llen = readlink(argv[i], syml, sizeof(syml) - 1)) >= 0) {
			syml[llen] = '\0';
			if (argv[i][0] == '/' && syml[0] != '/') {
				llenx = (strrchr(argv[i], '/') - argv[i]) + 1;
				if ((llenx + llen + 1) > sizeof(symlx)) {
					(void) fprintf(stderr,
					    "%s: sym link for %s too long\n",
					    Pn, argv[i]);
					exit(1);
				}
				(void) strncpy(symlx, argv[i],
					(STRNCPY_L)llenx);
				(void) strcpy(&symlx[llenx], syml);
				symlp = symlx;
				llen += llenx;
			} else
				symlp = syml;
			if ((path = (char *)malloc((MALLOC_S)(llen + 1)))
			== NULL) {
				(void) fprintf(stderr,
					"%s: no space for sym link of %s\n",
					Pn, argv[i]);
				exit(1);
			}
			(void) strcpy(path, symlp);
		} else
			path = argv[i];
	/*
	 * Check for file system argument.
	 */
		for (ftype = 1, mp = Mtab; mp; mp = mp->next) {
			if (strcmp(mp->dir, path) == 0) {
				ftype = 0;
				fnm = path;
				fsnm = mp->fsname;
				break;
			}
			if (strcmp(mp->fsname, path) == 0) {
				ftype = 0;
				fnm = mp->dir;
				fsnm = path;
				break;
			}
		}
		if (ftype) {
			fnm = path;
			fsnm = NULL;
		} else {
			sb.st_dev = mp->dev;
			sb.st_ino = mp->inode;
			sb.st_mode = mp->mode;
			sb.st_rdev = mp->rdev;
		}
	/*
	 * Stat the argument to obtain its mode and device.
	 */

		if (ftype && statsafely(fnm, &sb, STATTMO) != 0) {
			(void) fprintf(stderr, "%s: status error on %s: %s\n",
				Pn, fnm, sys_errlist[errno]);
			err++;
			continue;
		}
	/*
	 * Allocate an sfile structure and fill in the type, inode,
	 * find-flag and linkages.
	 */
		if ((sfp = (struct sfile *)malloc(sizeof(struct sfile)))
		== NULL) {
			(void) fprintf(stderr, "%s: no space for files\n", Pn);
			exit(1);
		}
		sfp->next = Sfile;
		Sfile = sfp;
		sfp->type = ftype;
		sfp->i = sb.st_ino;
		sfp->f = 0;
	/*
	 * Store the file name and file system name pointers in the sfile
	 * structure, allocating space as necessary.
	 */
		if (fnm == NULL || fnm == path)
			sfp->name = fnm;
		else {
		    if ((sfp->name = (char *)malloc((MALLOC_S)(strlen(fnm)+1)))
		    == NULL) {
			(void) fprintf(stderr,
			    "%s: no space for file name %s\n", Pn, fnm);
			exit(1);
		    }
		    (void) strcpy(sfp->name, fnm);
		}
		if (fsnm == NULL || fsnm == path)
			sfp->devnm = fsnm;
		else {
		    if ((sfp->devnm=(char *)malloc((MALLOC_S)(strlen(fsnm)+1)))
		    == NULL) {
			(void) fprintf(stderr,
			    "%s: no space for file system name %s\n", Pn, fsnm);
			exit(1);
		    }
		    (void) strcpy(sfp->devnm, fsnm);
		}
	/*
	 * Save the stat() buffer mode value in the sfile structure.
	 * Use st_rdev if the mode value is S_IFBLK or S_IFCHR; otherwise
	 * use st_dev.
	 */
		sfp->mode = sb.st_mode & S_IFMT;
		if (sfp->mode == S_IFBLK ||  sfp->mode == S_IFCHR)
			sfp->dev = sb.st_rdev;
		else
			sfp->dev = sb.st_dev;

#if	defined(_IBMR2)
	/*
	 * Save a (possible) AIX multiplexed channel number.
	 */
		sfp->ch = getchan(path);
#endif

	}
/*
 * List usage if error or if requested.
 */
	if (err || Fhelp) {
	    (void) fprintf(stderr,
		"%s %s usage: [-d] [-h] [-l] [-n] [-N] [-p l] [-s] [-t]",
		Pn, Version);
	    (void) fprintf(stderr,
		" [-u l] [-U] [names]\n");
	    (void) fprintf(stderr,
		"\t-d     issue /dev subdirectory error messages\n");
	    (void) fprintf(stderr,
		"\t-h     list help\n");
	    (void) fprintf(stderr,
		"\t-l     do not convert UID's to login names\n");
	    (void) fprintf(stderr,
		"\t-n     list Internet network files\n");
	    (void) fprintf(stderr,
		"\t-N     list NFS files\n");
	    (void) fprintf(stderr,
		"\t-p l   list files for comma-separated Process ID list l\n");
	    (void) fprintf(stderr,
 		"\t-s     do not display file size\n");
	    (void) fprintf(stderr,
		"\t-t     terse output -- Process ID numbers and no header\n");
	    (void) fprintf(stderr,
		"\t-u l   list files for comma-separated user list l ");
	    (void) fprintf(stderr,
		"(names or UIDs)\n");
	    (void) fprintf(stderr,
		"\t-U     list Unix domain sockets\n");
	    (void) fprintf(stderr,
		"\tnames  path names of file systems, mount points, devices");
	    (void) fprintf(stderr,
		" and\n\t       files to locate\n");
	    if (err)
		exit(1);
	    exit(0);
	}
/*
 * Open kernel memory accesses.
 *
 * Read and build device and mount tables.
 */
	if ((Kmem = open("/dev/kmem", O_RDONLY, 0)) < 0) {
		(void) fprintf(stderr, "%s: can't open /dev/kmem: %s\n",
			Pn, sys_errlist[errno]);
		exit(1);
	}

#if	defined(HPUX7)
	if ((Mem = open("/dev/mem", O_RDONLY, 0)) < 0) {
		(void) fprintf(stderr, "%s: can't open /dev/mem: %s",
			Pn, sys_errlist[errno]);
		exit(1);
	}
#endif

#if	defined(DYNIX) || defined(HPUX7)
	if ((Swap = open(SWAP, O_RDONLY, 0)) < 0) {
		(void) fprintf(stderr, "%s: /dev/drum: %s\n",
			Pn, sys_errlist[errno]);
		exit(1);
	}
#endif

#if	defined(NeXT)
        if (nlist(VMUNIX, Nl) < 0) {
                (void) fprintf(stderr, "%s: can't read namelist\n", Pn);
                exit(1);
        }
        if (Nl[X_ALLPROC].n_value == 0l) {
                (void) fprintf(stderr, "%s: no address for %s\n",
                        Pn, Nl[X_ALLPROC].n_un.n_name);
                exit(1);
        }
        if (kread((off_t)Nl[X_ALLPROC].n_value, (char *)&procp, sizeof(procp))){
                (void) fprintf(stderr,
                        "%s: can't read nl[X_ALLPROC].n_un.n_name: %s\n",
                        Pn, sys_errlist[errno]);
                exit(1);
        }
#endif

#if	defined(sun)
	if ((Kd = kvm_open(NULL, NULL, NULL, O_RDONLY, NULL)) == 0) {
		(void) sprintf("%s: kvm_open: %s", Pn, sys_errlist[errno]);
		exit(1);
	}
        if (nlist(N_UNIX, Nl) < 0) {
                (void) fprintf(stderr, "%s: can't read namelist\n", Pn);
                exit(1);
	}
        if (Nl[X_NFS_OPS].n_value == 0l) {
                (void) fprintf(stderr, "%s: no address for %s\n",
                        Pn, Nl[X_NFS_OPS].n_name);
                exit(1);
        }
#endif

	(void) readdev();
/*
 * Read the processs table.
 */

#if	defined(DYNIX) || defined(hpux)
	if (nlist(N_UNIX, Nl) < 0) {
                (void) fprintf(stderr, "%s: can't read namelist\n", Pn);
                exit(1);
	}
	if (Nl[X_PROC].n_value == NULL
	||  kread((off_t)Nl[X_PROC].n_value, (char *)&kp, sizeof(kp))
	||  Nl[X_NPROC].n_value == NULL
	||  kread((off_t)Nl[X_NPROC].n_value, (char *)&np, sizeof(np))
	||  kp == NULL || np == 0) {
		(void) fprintf(stderr, "%s: can't read proc table info\n",
			Pn);
		exit(1);
	}
#endif

#if	defined(HPUX7) && defined(hp9000s300)
	if ((Usrptmap = (struct pte *)Nl[X_USRPTMAP].n_value) == NULL) {
		(void) fprintf(stderr, "%s: can't get kernel's Usrptmap\n", Pn);
		exit(1);
	}
	if ((usrpt = (struct pte *)Nl[X_USRPT].n_value) == NULL) {
		(void) fprintf(stderr, "%s: can't get kernel's usrpt\n", Pn);
		exit(1);
	}
#endif

#if	defined(HPUX7) && defined(hp9000s800)
	proc = (struct proc *)kp;
	if ((ubase = (struct user *)Nl[X_UBASE].n_value) == NULL) {
		(void) fprintf(stderr, "%s: can't get kernel's ubase\n", Pn);
		exit(1);
	}
	if (Nl[X_NPIDS].n_value == NULL
	||  kread((off_t)Nl[X_NPIDS].n_value, (char *)&npids, sizeof(npids))) {
		(void) fprintf(stderr, "%s: can't get kernel's npids\n", Pn);
		exit(1);
	}
#endif

#if	defined(_IBMR2)
	if ((p = (struct procinfo *)malloc((size_t)PROCSIZE)) == NULL) {
		(void) fprintf(stderr,
			"%s: can't allocate space for 1 procinfo\n", Pn);
		exit(1);
	}
	np = 0;
	while (((np = getproc(p, np, PROCSIZE)) == -1) && errno == ENOSPC) {
		np = p->p_pid + 10;
		if ((p = (struct procinfo *)realloc((MALLOC_P *)p,
		    (size_t) (np * PROCSIZE))) == NULL) {
			(void) fprintf(stderr,
				"%s: no space for %ld procinfo's\n", Pn, np);
			exit(1);
		}
	}
#endif

#if	defined(sun)
	(void) kvm_setproc(Kd);
#endif

/*
 * Loop through the process table entries.
 */
	selflg = (Fnet || Fnfs || Funix || Npid || Nuid || Sfile) ? 0 : 1;
	selpid = (Fnet || Fnfs || Funix || Nuid || Sfile) ? 0 : 1;
	seluid = (Fnet || Fnfs || Funix || Sfile) ? 0 : 1;

#if	defined(DYNIX)
	for (p = &ps, px = 0, u = &us; px < np; px++)
#endif

#if	defined(HPUX7)
	for (p = &ps, px = 0, u = (struct user *)us; px < np; px++)
#endif

#if	defined(HPUX8)
	for (p = &ps, px = 0, u = &us; px < np; px++)
#endif

#if	defined(_IBMR2)
	for (; np; np--, p++)
#endif

#if	defined(NeXT)
	for (np = procp, p = &ps; np; np = ps.p_nxt)
#endif

#if	defined(sun)
	while ((p = kvm_nextproc(Kd)) != NULL)
#endif

	{

#if	defined(DYNIX)
		if (kread((off_t)(kp + (long)(px * sizeof(struct proc))),
		    (char *)&ps, sizeof(ps)))
			continue;
#endif

#if	defined(hpux)
		Procaddr = kp + (long)(px * sizeof(struct proc));
		if (kread((off_t)Procaddr, (char *)&ps, sizeof(ps)))
			continue;
#endif

#if	defined(NeXT)
                if (kread((off_t)np, (char *)&ps, sizeof(ps))) {
                        (void) fprintf(stderr,
                                "%s: can't read proc struct at %#x\n",
                                Pn, np);
                        exit(1);
                }
#endif

		if (p->p_stat == 0 || p->p_stat == SZOMB)
			continue;
		fprint = selflg;
		for (i = 0; fprint == 0 && i < Npid; i++) {
			if (Spid[i] == p->p_pid)
				fprint = 1;
		}
		if ( ! fprint && selpid)
			continue;

#if	defined(NeXT)
        /*
         * Read the task associated with the process, and the user
         * area assocated with the task.
         */
                if (kread((off_t) p->task, &t, sizeof(t)))
                        continue;
                if ((struct proc *)t.proc != np)
                        continue;
                if (kread((off_t) t.u_address, &ut, sizeof(ut)))
                        continue;
                if ((struct proc *)ut.uu_procp != np)
                        continue;
		u = &ut;
#endif

/*
 * Check for processes owned by specified user(s).
 */
		for (i = 0; fprint == 0 && i < Nuid; i++) {
			if (Suid[i] == p->p_uid)
				fprint = 1;
		}
		if ( ! fprint && seluid)
			continue;

#if	defined(DYNIX) || defined(hpux) || defined(_IBMR2) || defined(sun)
	/*
	 * Get the user area associated with the process.
	 */
#endif

#if	defined(DYNIX)
		if (getu(p, &us))
			continue;
#endif

#if	defined(hpux)
		if (getu(p, u))
			continue;
#endif

#if	defined(_IBMR2)
		u = &us;
		if (getuser(p, PROCSIZE, u, U_SIZE) != 0)
			continue;
#endif

#if	defined(sun)
		if ((u = kvm_getu(Kd, p)) == NULL)
			continue;
#endif

	/*
	 * Print information on the current directory.
	 */

#if	defined(DYNIX) || defined(HPUX7) || defined(_IBMR2) || defined(NeXT) || defined(sun)
		if (u->u_cdir) {
#endif

#if	defined(HPUX8)
		if (p->p_cdir) {
#endif

			Command = u->u_comm;
			Fdev = 0;
			Devch[0] = Iproto[0] = Type[0] = '\0';
		/*
		 * The following line should be:
		 *
		 *	(void) strcpy(Fd, " cwd");
		 *
		 * However, the 3.1.3 xlc compiler produces incorrect code
		 * for it when optimizing (-O).  The 3.1.5 xlc compiles the
		 * strcpy() correctly.
		 */
			(void) sprintf(Fd, "%4s", "cwd");
			Fprint = fprint;
			Inode = -1l;
			Lock = ' ';
			Namech[0] = '\0';
			Pid = p->p_pid;
			Size_def = 0;
			Vtype = V_REG;
			(void) printuid(p->p_uid);

#if	defined(DYNIX) || defined(HPUX7) || defined(_IBMR2) || defined(NeXT) || defined(sun)
			printvnode((caddr_t)u->u_cdir);
#endif

#if	defined(HPUX8)
			printvnode((caddr_t)p->p_cdir);
#endif
		}
	/*
	 * Loop through user's files.
	 */

#if	defined(DYNIX)

#if	!defined(DYNIX31)
	/*
	 * Under DYNIX, the file pointers may be located in the user
	 * structure or in an extension to it.  Determine which is the
	 * case and read the pointers.
	 */

	if (u->u_ofile_ext) {
		if (kread((off_t)u->u_ofile_ext, (char *)&ofx, sizeof(ofx)))
			nf = 0;
		else {
			nf = ofx.oe_nofile;
			ui = (unsigned)(ofx.oe_nofile * sizeof(struct ofile));
			if (ofp == NULL) {
				xnf = nf;
				if ((ofp = (struct ofile *)malloc(ui))
				== NULL) {
					(void) fprintf(stderr,
						"%s: no malloc ofile space\n",
						Pn);
					exit(1);
				}
			} else if (nf > xnf) {
				xnf = nf;
				if ((ofp = (struct ofile *)realloc(
					   (MALLOC_P *)ofp, ui))
				== NULL) {
					(void) fprintf(stderr,
						"%s: no realloc ofile space\n",
						Pn);
					exit(1);
				}
			}
			if (kread((off_t)ofx.oe_ofile, (char *)ofp, (int)ui))
				nf = 0;
			else {
				nf = ofx.oe_nofile;
				uf = ofp;
			}
		}
	} else {
		nf = NOFILE;
		uf = u->u_lofile;
	}
#endif

#if	defined(DYNIX31)
	/*
	 * Under DYNIX 3.1, the file pointers should be located in an extension
	 * to the user structure.  Determine if is the case and read the
	 * pointers.
	 */

	if (u->u_ofile_tab) {
		if (kread((off_t)u->u_ofile_tab, (char *)&oft, sizeof(oft)))
			nf = 0;
		else {
			nf = oft.oft_nofile;
			ui = (unsigned)(oft.oft_nofile * sizeof(struct ofile));
			if (ofp == NULL) {
				xnf = nf;
				if ((ofp = (struct ofile *)malloc(ui))
				== NULL) {
					(void) fprintf(stderr,
						"%s: no malloc ofile space\n",
						Pn);
					exit(1);
				}
			} else if (nf > xnf) {
				xnf = nf;
				if ((ofp = (struct ofile *)realloc(
					   (MALLOC_P *)ofp, ui))
				== NULL) {
					(void) fprintf(stderr,
						"%s: no realloc ofile space\n",
						Pn);
					exit(1);
				}
			}
			if (kread((off_t)oft.oft_ofile, (char *)ofp, (int)ui))
				nf = 0;
			else {
				nf = oft.oft_nofile;
				uf = ofp;
			}
		}
	} else {
		nf = NOFILE;
		uf = u->u_lofileXXX;
	}
#endif

#endif

#if	defined(NeXT)
	/*
	 * NeXTStep 2.0 and 2.1 file pointers come from a structure whose
	 * pointer is in the user area.
	 */
		nf = ut.uu_ofile_cnt;
                nb = (MALLOC_S) (sizeof(struct file) * nf);
		if (uf == NULL) {
			if ((uf = (struct file **)malloc(nb)) == NULL) {
				(void) fprintf(stderr,
					"%s: no file table space, process %d\n",
					Pn, p->p_pid);
				exit(1);
			}
			pnb = nb;
		} else if (nb > pnb) {
			if ((uf = (struct file **)realloc((MALLOC_P *)uf, nb))
			== NULL) {
				(void) fprintf(stderr,
					"%s: realloc file[]\n", Pn);
				exit(1);
			}
			pnb = nb;
		}
                if (kread((off_t)ut.uu_ofile, (char *)uf, nb))
                        continue;
#endif
	
#if	defined(sun)
	/*
	 * Under SunOS 4.1.1, the file pointers may be located in the
	 * user structure or in a separately allocated area.  Determine
	 * which is the case and read the pointers.
	 */
		if ((caddr_t)u->u_ofile
		== ((caddr_t)&u->u_ofile_arr[0] - (caddr_t)&u
		+ (caddr_t)p->p_uarea)) {
			nf = NOFILE_IN_U;
			uf = &u->u_ofile_arr[0];
		} else {
			nf = u->u_lastfile + 1;
			ui = nf * sizeof(struct file);
			if (xuf == NULL) {
				xnf = nf;
				if ((xuf = (struct file **)malloc(ui))
				== NULL) {
					(void) fprintf(stderr,
						"%s: malloc file[]\n", Pn);
					exit(1);
				}
			} else if (nf > xnf) {
				xnf = nf;
				if ((xuf = (struct file **)realloc(
					   (MALLOC_P *)xuf, ui))
				== NULL) {
					(void) fprintf(stderr,
						"%s: realloc file[]\n", Pn);
					exit(1);
				}
			}
			if (kread((off_t)u->u_ofile, (char *)xuf, (int)ui))
				nf = 0;
			uf = xuf;
		}
#endif

#if	defined(DYNIX)
		for (i = 0; i < nf; i++) {
			if (uf[i].of_file)
#endif

#if	defined(HPUX7)
		for (i = j = k = 0;; i++) {
			if (j >= SFDCHUNK) {

			/*
			 * Get next HP-UX file pointer "chunk".
			 */
			    while (++k < NFDCHUNKS && u->u_ofilep[k] == NULL)
				;
			    if (k >= NFDCHUNKS)
				break;
			    if (kread((off_t)u->u_ofilep[k],
				      (char *)&u->u_ofile,
				      sizeof(struct ofile_t)))
				break;
			    j = 0;
			}
			j++;
			if (u->u_ofile.ofile[j - 1])
#endif

#if	defined(HPUX8)
		for (i = 0, j = SFDCHUNK;; i++) {
			if (j >= SFDCHUNK) {
			    if (kread((off_t)p->p_ofilep, (char *)&ofp,
				       sizeof(ofp)))
			    {
				(void) fprintf(stderr,
					"%s: can't read ofilep from %#x\n",
					Pn, ofp);
				exit(1);
			    }
			    if (ofp == NULL)
				break;
			    if (kread((off_t)ofp, (char *)&oft, sizeof(oft))) {
				(void) fprintf(stderr,
					"%s: can't read ofile_t from %#x\n",
					Pn, ofp);
				exit(1);
			    }
			    j = 0;
			    p->p_ofilep++;
			}
			j++;
			if (oft.ofile[j - 1])
#endif

#if	defined(_IBMR2)
		for (i = 0; i < u->u_maxofile; i++) {
			if (u->u_ufd[i].fp)
#endif

#if	defined(NeXT) || defined(sun)
		for (i = 0; i < nf; i++) {
			if (uf[i])
#endif
			{

                                Command = u->u_comm;
                                Fdev = 0;
				Fprint = fprint;
                                Devch[0] = Iproto[0] = Type[0] = '\0';
                                (void) sprintf(Fd, "%4d", i);
                                Inode = -1l;
                                Lock = ' ';
                                Namech[0] = '\0';
                                Pid = p->p_pid;
				Size_def = 0;
				Vtype = V_REG;
				(void) printuid(p->p_uid);

#if	defined(DYNIX)
				printfile(uf[i].of_file);
#endif

#if	defined(HPUX7)
				printfile(u->u_ofile.ofile[j - 1]);
#endif

#if	defined(HPUX8)
				printfile(oft.ofile[j - 1]);
#endif

#if	defined(_IBMR2)
                                printfile(u->u_ufd[i].fp);
#endif

#if	defined(NeXT)
				printfile(uf[i]);
#endif

#if	defined(sun)
                                printfile(uf[i]);
#endif
			}
		}
	}
	for (sfp = Sfile; sfp; sfp = sfp->next) {
		if (sfp->f == 0)
			exit(1);
	}

#if	defined(DYNIX) || defined(_IBMR2) || defined(NeXT)
	exit(0);
#endif

#if	defined(hpux) || defined(sun)
	return(0);
#endif

}


/*
 * compdev() - compare device numbers
 */

compdev(p1, p2)
	struct dev **p1;
	struct dev **p2;
{
	if ((long)((*p1)->rdev) < (long)((*p2)->rdev))
		return(-1);
	if ((long)((*p1)->rdev) > (long)((*p2)->rdev))
		return(1);
	return(0);
}


#if	defined(DYNIX) || defined(hpux) || defined(NeXT) || defined(sun)
/*
 * completevfs() - complete local vfs structure
 */

void
completevfs(vfs, dev)
	struct l_vfs *vfs;		/* local vfs structure pointer */
	dev_t dev;			/* inode/rnode device */
{
	struct mounts *mp;

	for (mp = Mtab; mp; mp = mp->next) {
		if (mp->dev == dev) {

#if	defined(DYNIX) || defined(hpux)
			vfs->dev = mp->dev;
#endif

			vfs->dir = mp->dir;
			vfs->fsname = mp->fsname;
			return;
		}
	}
}
#endif


/*
 * endnm() - locate end of Namech
 */

char *
endnm()
{
	char *s;

	for (s = Namech; *s; s++)
		;
	return(s);
}


/*
 * entpid() - enter Process IDentifier for searching
 */

entpid(p)
	char *p;			/* PID string pointer */
{
	int i, pid;
	char *s;

	for (s = p; *s;) {
	/*
	 * Assemble Process IDentifier.
	 */
		for (pid = 0; *s && *s != ','; *s++) {
			if ( ! isascii(*s) || ! isdigit(*s)) {
				(void) fprintf(stderr,
					"%s: illegal PID specification: %s\n",
					Pn, p);
				return(1);
			}
			pid = (pid * 10) + *s - '0';
		}
		if (*s)
			s++;
	/*
	 * Avoid entering duplicates.
	 */
		for (i = 0; i < Npid; i++) {
			if (pid == Spid[i])
				break;
		}
		if (i < Npid)
			continue;
	/*
	 * Allocate PID table space.
	 */
		if (Npid >= Mxpid) {
			Mxpid += PIDINCR;
			if (Spid == NULL)
				Spid = (int *)malloc((MALLOC_S)
					(sizeof(int *) * Mxpid));
			else
				Spid = (int *)realloc((MALLOC_P *)Spid,
					(MALLOC_S)(sizeof(int *) * Mxpid));
			if (Spid == NULL) {
				(void) fprintf(stderr, "%s: no space for PIDs",
					Pn);
				exit(1);
			}
		}
		Spid[Npid++] = pid;
	}
	return(0);
}


/*
 * entuid() - enter User Identifier for searching
 */

entuid(u)
	char *u;			/* User IDentifier string pointer */
{
	int err, i, n;
	struct passwd *pw;
	char *s;
	char uid[LOGINML];

	for (err = 0, s = u; *s;) {
	/*
	 * Assemble next User IDentifier.
	 */
		for (i = n = 0; *s && *s != ','; i++, s++) {
			if (i >= LOGINML-1) {
				(void) fprintf(stderr,
					"%s: illegal UID in %s\n", Pn, u);
				return(1);
			}
			uid[i] = *s;
			if (n < 0)
				continue;
			if (isascii(*s) && isdigit(*s))
				n = (n * 10) + *s - '0';
			else
				n = -1;
		}
		if (*s)
			s++;
		if (n < 0) {
		       uid[i] = '\0';
		       if ((pw = getpwnam(uid)) == NULL) {
				(void) fprintf(stderr,
					"%s: can't get UID for %s\n",
					Pn, uid);
				err++;
				continue;
			} else
				n = pw->pw_uid;
		}
	/*
	 * Avoid entering duplicates.
	 */
		for (i = 0; i < Nuid; i++) {
			if (n == Suid[i])
				break;
		}
		if (i < Nuid)
			continue;
	/*
	 * Allocate space for User IDentifier.
	 */
		if (Nuid >= Mxuid) {
			Mxuid += UIDINCR;
			if (Suid == NULL)
				Suid = (int *)malloc((MALLOC_S)
					(sizeof(int *) * Mxuid));
			else
				Suid = (int *)realloc((MALLOC_P *)Suid,
					(MALLOC_S)(sizeof(int *) * Mxuid));
			if (Suid == NULL) {
				(void) fprintf(stderr, "%s: no space for UIDs",
					Pn);
				exit(1);
			}
		}
		Suid[Nuid++] = n;
	}
	return(err);
}


#if	defined(_IBMR2)
/*
 * getchan() - get channel from file path name
 */

int
getchan(p)
	char *p;			/* file path name */
{
	int ch;
	char *s;

	if ((s = strrchr(p, '/')) == NULL) 
		return(-1);
	if (*(++s) == '\0')
		return(-1);
	for (ch = 0; *s; s++) {
		if ( ! isascii(*s) || ! isdigit(*s))
			return(-1);
		ch = (ch * 10) + *s - '0';
	}
	return(ch);
}
#endif


#if	defined(DYNIX)
/*
 * getu() - get DYNIX user area
 */

getu(p, u)
	struct proc *p;			/* process area pointer */
	struct user *u;			/* user area destination */
{
	off_t sp;

	if ((p->p_flag & SLOAD) == 0) {
		sp = (off_t) dtob(p->p_swaddr);
		if (lseek(Swap, sp, L_SET) != sp
		||  read(Swap, (char*)u, U_SIZE) != U_SIZE)
			return(1);
	} else {
		if (kread((off_t)p->p_uarea, (char *)u, U_SIZE))
			return(1);
	}
	return(0);
}
#endif


#if	defined(hpux)
/*
 * getu() - get HP-UX user area
 */

getu(p, u)
	struct proc *p;			/* process area pointer */

#if	defined(HPUX7)
	char *u;			/* user area destination */
#endif

#if	defined(HPUX8)
	struct user *u;			/* user area destination */
#endif

{

#if	defined(HPUX7)
	long sw;

#if	defined(hp9000s300)
	struct pte pte1, pte2;
	off_t pte_off, pte_addr;
#endif
#endif

#if	defined(HPUX8)
	char *c, *s;
	int i;
	struct pst_status ps;
#endif

#if	defined(HPUX7)
/*
 * Read the HP-UX 7.x user area from the swap file or memory.
 */
	if ((p->p_flag & SLOAD) == 0) {

	/*
	 * If the process is not loaded, read the user area from the swap file.
	 */
		sw = (long)p->p_swaddr;

#if	defined(hp9000s800)
		sw += (long)ctod(btoc(STACKSIZE * NBPG));
#endif

		if (lseek(Swap, (off_t)dtob(sw), L_SET) == (off_t)-1
		||  read(Swap, u, U_SIZE) != U_SIZE)
			return(1);
		return(0);
	}

/*
 * Read the HP-UX 7.x user area via the page table.
 */

#if	defined(hp9000s300)
	pte_off = (off_t) &Usrptmap[btokmx(p->p_p0br) + p->p_szpt - 1];
	if (kread(pte_off, (char *)&pte1, sizeof(pte1)))
		return(1);
	pte_addr = (off_t) (ctob(pte1.pg_pfnum + 1)
		 - ((UPAGES + FLOAT) * sizeof(pte2)));
	if (lseek(Mem, pte_addr, L_SET) == (off_t)-1
	||  read(Mem, (char *)&pte2, sizeof(pte2)) != sizeof(pte2))
		return(1);
	if (lseek(Mem, (off_t)ctob(pte2.pg_pfnum), L_SET) == (off_t)-1
	||  read(Mem, u, sizeof(struct user)) != sizeof(struct user))
		return(1);
#endif

#if	defined(hp9000s800)
	if (kread((off_t)uvadd((struct proc *)Procaddr),u,sizeof(struct user)))
		return(1);
#endif
#endif	/* HPUX7 */

#if	defined(HPUX8)
/*
 * Use the undocumented HP-UX 8.x pstat() syscall to read process status.
 *
 * (HP won't release pstat(2) documentation to customers who have paid for
 * the inclusion of the syscall in HP-UX.  You figure that one out.)
 */
	(void) bzero(u, U_SIZE);
	if (pstat(PSTAT_PROC, &ps, sizeof(ps), 0, p->p_pid) != 1) {
		(void) fprintf(stderr, "%s: can't pstat process %d: %s\n",
			Pn, p->p_pid, sys_errlist[errno]);
		return(1);
	}
/*
 * Scan the pst_cmd command buffer and skip to the last component of the
 * first path name.  Also skip any leading `-', signifying a login shell.
 * Copy the result to u_comm[].
 */
	c = ps.pst_cmd;
	ps.pst_cmd[PST_CLEN - 1] = '\0';	/* paranoia */
	if (*c == '/') {
		for (s = c; *s && *s != ' '; s++) {
			if (*s == '/')
				c = s + 1;
		}
	}
	if (*c == '-')
		c++;
	for (i = 0; i < MAXCOMLEN; i++) {
		if (*c == '\0' || *c == ' ' || *c == '/')
			break;
		u->u_comm[i] = *c++;
	}
	u->u_comm[i] = '\0';
/*
 * Copy other process status values to the user area, as required.
 */
#endif	/* HPUX8 */

	return(0);
}
#endif


/*
 * isfile() - is file selected for printing
 */

isfile(d, ty, ch, i)
	dev_t d;			/* device */
	enum vtype ty;			/* vnode type */

#if	defined(DYNIX) || defined(hpux) || defined(NeXT) || defined(sun) 
	int ch;				/* dummy */
#endif

#if	defined(_IBMR2)
	chan_t ch;			/* gnode channel */
#endif

	long i;			 	/* inode */

/* ARGSUSED */

{
	int f;
	struct sfile *s;

	for (f = 0, s = Sfile; s; s = s->next) {

#if	defined(_IBMR2)
	/*
	 * Check for a regular AIX multiplexed file.  Match the channel if
	 * it was supplied.
	 */
		if (s->type && s->mode == S_IFCHR && d == s->dev
		&& ty == VMPC) {
			if (s->ch < 0 || (s->ch >= 0 && ch == s->ch)) {
				f = 1;
				break;
			}
		}
#endif

#if	defined(sun)
	/*
	 * Check for a Sun clone file.
	 */
		if (Vtype == V_STREAM && major(s->dev) == CLONEMAJ
		&& major(d) == minor(s->dev)) {
			f = 1;
			break;
		}
#endif

	/*
	 * Check for a regular file or directory -- the device and
	 * inode numbers must match.
	 */
		if (s->type) {
			if (d == s->dev && (ino_t)i == s->i) {
				f = 1;
				break;
			}
			continue;
		}
	/*
	 * Check for a file system match.
	 * Try to avoid matching VCHR files to non-character devices.
	 */
		if (d == s->dev) {
			if ( ! (ty == VCHR && s->mode != S_IFCHR)) {
				f = 1;
				break;
			}
		}
	}
/*
 * Convert the name if a match occurred.
 */
	if (f) {
		(void) strcpy(Namech, s->name);

#if	defined(_IBMR2)
		if (ty == VMPC && s->ch < 0)
			(void) sprintf(endnm(), "/%d", ch);
#endif

		if (s->devnm)
			(void) sprintf(endnm(), " (%s)", s->devnm);
		s->f = 1;
		return(1);
	}
	return(0);
}


#if	defined(_IBMR2)
/*
 * isglocked() - is a gnode locked
 */

char
isglocked(ga)
	struct gnode *ga;		/* local gnode address */
{

	struct filock f;
	off_t l;

	if (ga->gn_filocks == NULL)
		return(' ');
	if (kread((off_t)ga->gn_filocks, &f, sizeof(f)))
		return(' ');
	if (f.set.l_whence == 0 && f.set.l_start == 0 && f.set.l_len == MAXEND)
		l = 1;
	else
		l = 0;
	switch (f.set.l_type & (F_RDLCK | F_WRLCK)) {

	case F_RDLCK:
		return((l) ? 'R' : 'r');
	case F_WRLCK:
		return((l) ? 'W' : 'w');
	case (F_RDLCK + F_WRLCK):
		return('*');
	}
	return(' ');
}
#endif


/*
 * kread() - read from kernel memory
 */

int
kread(addr, buf, len)
	off_t addr;			/* kernel memory address */
	char *buf;			/* buffer to receive data */
	int len;			/* length to read */
{
	int br;

#if	defined(DYNIX) || defined(_IBMR2) || defined(hpux) || defined(NeXT)
	if (lseek(Kmem, addr, L_SET) == (off_t)-1)
		return(-1);
	br = read(Kmem, buf, len);
#endif

#if	defined(sun)
	br = kvm_read(Kd, (u_long)addr, buf, len);
#endif

	return((br == len) ? 0 : 1);
}


/*
 * printchdevname() - print character device name
 */

void
printchdevname(rdev, chan)
	dev_t rdev;			/* device */

#if	defined(DYNIX) || defined(hpux) || defined(NeXT) || defined(sun)
	int chan;			/* dummy */
#endif

#if	defined(_IBMR2)
	chan_t chan;			/* channel */
#endif

/* ARGSUSED */

{

#if	defined(sun)
	struct clone *c;
#endif

	int low, hi, mid;
	struct dev *dp;


#if	defined(sun)
/*
 * If this is a SunOS stream vnode, search for the clone parent.
 */
	if (Vtype == V_STREAM && Clone) {
		for (c = Clone; c; c = c->next) {
			dp = c->dp;
			if (major(rdev) == minor(dp->rdev))
				goto found_device;
		}
	}
#endif

	low = mid = 0;
	hi = Ndev - 1;
        while (low <= hi) {
                mid = (low + hi) / 2;
		dp = Sdev[mid];
		if ((long)rdev < (long)dp->rdev)
			hi = mid - 1;
		else if ((long)rdev > (long)dp->rdev)
                        low = mid + 1;
                else {

#if	defined(sun)

found_device:

#endif

#if	defined(DYNIX) || defined(hpux) || defined(NeXT) || defined(sun)
			(void) strcpy(Namech, dp->name);
#endif

#if	defined(_IBMR2)
			if (chan < 0)
				(void) strcpy(Namech, dp->name);
			else
				(void) sprintf(Namech, "%s/%d", dp->name,
					chan);
#endif

			return;
		}
        }
	(void) strcpy(Namech, "name unknown");
}


#if	defined(DTYPE_GNODE)
/*
 * printdevice() - print device file
 */

printdevice(va)
	caddr_t va;			/* vnode's kernel address */
{
	struct vnode v;

	if (readvnode(va, &v)) {
                printline();
                return;
        }
	(void) strcpy(Type, "dev");
	printline();
}
#endif


/*
 * printfile() - print file information
 */

void
printfile(fp)
	struct file *fp;		/* kernel file table address */
{
	struct file f;

	if (kread((off_t) fp, (char *) &f, sizeof(f))) {
		(void) sprintf(Namech, "can't read file struct from %#x", fp);
	} else {
		if (f.f_count) {
			switch (f.f_type) {

			case DTYPE_VNODE:
				printvnode(f.f_data);
				break;

			case DTYPE_SOCKET:
				printsocket((caddr_t)f.f_data);
				break;

#if	defined(DTYPE_GNODE)
			case DTYPE_GNODE:
				printdevice(f.f_data);
				break;
#endif

			default:
				(void) sprintf(Namech,
				    "unknown file struct type %#x at %#x\n",
				    f.f_type, fp);
				printline();
			}
			return;
		}
	}
	return;
}


/*
 * printinaddr() - print Internet address
 */

void
printinaddr(ia, p)
	struct in_addr *ia;		/* Internet address */
	u_short p;			/* port */
{
	unsigned char *u;

	if (ia->s_addr == INADDR_ANY) {
		(void) sprintf(endnm(), "*:%d", p);
		return;
	}
	u = (unsigned char *) ia;
	(void) sprintf(endnm(), "%u.%u.%u.%u:%u", u[0], u[1], u[2], u[3], p);
}


/*
 * printiproto() - print Internet protocol name
 */

void
printiproto(p)
	int p;				/* protocol number */
{
	int i;
	static int m = -1;
	char *s;

	switch(p) {

#if	defined(IPPROTO_TCP)
	case IPPROTO_TCP:
		s = "TCP";
		break;
#endif

#if	defined(IPPROTO_UDP)
	case IPPROTO_UDP:
		s = "UDP";
		break;
#endif

#if	defined(IPPROTO_IP)
	case IPPROTO_IP:
		s = "IP";
		break;
#endif

#if	defined(IPPROTO_ICMP)
	case IPPROTO_ICMP:
		s = "ICMP";
		break;
#endif

#if	defined(IPPROTO_IGMP)
	case IPPROTO_IGMP:
		s = "IGMP";
		break;
#endif

#if	defined(IPPROTO_GGP)
	case IPPROTO_GGP:
		s = "GGP";
		break;
#endif

#if	defined(IPPROTO_EGP)
	case IPPROTO_EGP:
		s = "EGP";
		break;
#endif

#if	defined(IPPROTO_PUP)
	case IPPROTO_PUP:
		s = "PUP";
		break;
#endif

#if	defined(IPPROTO_IDP)
	case IPPROTO_IDP:
		s = "IDP";
		break;
#endif

#if	defined(IPPROTO_ND)
	case IPPROTO_ND:
		s = "ND";
		break;
#endif

#if	defined(IPPROTO_RAW)
	case IPPROTO_RAW:
		s = "RAW";
		break;
#endif

#if	defined(IPPROTO_HELLO)
	case IPPROTO_HELLO:
		s = "HELLO";
		break;
#endif

#if	defined(IPPROTO_PXP)
	case IPPROTO_PXP:
		s = "PXP";
		break;
#endif

#if	defined(IPPROTO_RAWIP)
	case IPPROTO_RAWIP:
		s = "RAWIP";
		break;
#endif

#if	defined(IPPROTO_RAWIF)
	case IPPROTO_RAWIF:
		s = "RAWIF";
		break;
#endif

	default:
		s = NULL;
	}
	if (s)
		(void) sprintf(Iproto, "%*.*s", IPROTOL, IPROTOL, s);
	else {	
		if (m < 0) {
			for (i = 0, m = 1; i < IPROTOL-1; i++)
				m *= 10;
		}
		(void) sprintf(Iproto, "%d?", p % m);
	}
}


/*
 * printline() - print output line
 */

void
printline()
{
	if (Fprint == 0)
		return;
	if (Fterse) {
		(void) printf("%d\n", Pid);
		return;
	}
	if (Hdr == 0) {

#if	defined(DYNIX) || defined(_IBMR2) || defined(NeXT) || defined(sun)
	    (void) printf("COMMAND     PID     USER   FD  TYPE     DEVICE");
#endif

#if	defined(hpux)
	    (void) printf("COMMAND     PID     USER   FD  TYPE       DEVICE");
#endif

	    if (Fsize)
		(void) printf("     SIZE");
	    (void)printf("   INODE/NAME\n");
	}
	Hdr++;
	(void) printf("%-9.9s%6d %8s %4s%c %4.4s ",
			Command ? Command : "",
			Pid,
			User,
			Fd,
			Lock,
			Type
	);
	if (Fdev)

#if	defined(DYNIX) || defined(_IBMR2) || defined(NeXT) || defined(sun)
		(void) printf(" %4d,%4d ", major(Dev), minor(Dev));
#endif

#if	defined(hpux)
		(void) printf("%3d,0x%06x ", major(Dev), minor(Dev));
#endif

	else {
		if (Devch[0])

#if	defined(DYNIX) || defined(_IBMR2) || defined(NeXT) || defined(sun)
			(void) printf("%s ", Devch);
		else
			(void) printf("           ");
#endif

#if	defined(hpux)
			(void) printf("  %s ", Devch);
		else
			(void) printf("             ");
#endif

	}
	if (Fsize) {
		if (Size_def)
			(void) printf("%8d ", Size);
		else
			(void) printf("         ");
	}
	if (Inode >= 0)
		(void) printf("%7ld ", Inode);
	else if (Inode == -2l) {
		if (Iproto[0] == '\0')
			(void) printf("%7s ", "");
		else
			(void) printf("%7.7s ", Iproto);
	}
	(void) printf("%s\n", Namech);
}


/*
 * printsocket() - print socket
 */

void
printsocket(sa)
	caddr_t sa;			/* socket address in kernel */
{
	int fam;

#if	defined(DYNIX) || defined(HPUX8) || defined(_IBMR2) || defined(NeXT) || defined(sun)
	struct domain d;
#endif

#if	defined(_IBMR2)
	struct gnode g;
	struct inode i;
	int is = 0;
	struct vnode v;
#endif

	struct inpcb inp;
	struct mbuf mb;
	struct protosw p;
	struct socket s;
	struct sockaddr_un *ua;
	struct unpcb uc, unp;

        (void) strcpy(Type, "sock");
	Inode = -2l;
	if (sa == NULL) {
		(void) sprintf(Namech, "no socket address");
		printline();
		return;
	}
        if (kread((off_t) sa, (char *) &s, sizeof(s))) {
                (void) sprintf(Namech, "can't read socket struct from %#x",
			sa);
                printline();
                return;
        }
        if (s.so_proto == NULL
	||  kread((off_t) s.so_proto, (char *) &p, sizeof(p))) {
                (void) strcpy(Namech, "no protocol switch");
                printline();
                return;
        }

#if	defined(DYNIX) || defined(HPUX8) || defined(_IBMR2) || defined(NeXT) || defined(sun)
        if (kread((off_t) p.pr_domain, (char *) &d, sizeof(d))) {
                (void) sprintf(Namech, "can't read domain struct from %#x",
                        p.pr_domain);
                printline();
                return;
        }
#endif

/*
 * Process socket by the associated domain family.
 */

#if	defined(DYNIX) || defined(HPUX8) || defined(_IBMR2) || defined(NeXT) || defined(sun)
	switch ((fam = d.dom_family))
#endif

#if	defined(HPUX7)
	switch ((fam = p.pr_family))
#endif

	{
	case AF_INET:
		if (Fnet)
			Fprint = 1;
		(void) strcpy(Type, "inet");
	/*
	 * Read Internet protocol control block.
	 */
		if (s.so_pcb == NULL
		|| kread((off_t) s.so_pcb, (char *) &inp, sizeof(inp)))
			return;
		if ((struct socket *)sa != inp.inp_socket)
			return;
		printiproto(p.pr_protocol);
		(void) sprintf(Devch, "0x%08x",
			      (inp.inp_ppcb == NULL) ? s.so_pcb
						     : inp.inp_ppcb);

#if	defined(DYNIX)
		printinaddr(&inp.inp_laddr, ntohs(inp.inp_lport));
#endif

#if	defined(hpux) || defined(_IBMR2) || defined(NeXT) || defined(sun)
		printinaddr(&inp.inp_laddr, inp.inp_lport);
#endif

		if (inp.inp_faddr.s_addr != INADDR_ANY || inp.inp_fport != 0) {
			(void) strcat(endnm(), "->");

#if	defined(DYNIX)
		printinaddr(&inp.inp_faddr, ntohs(inp.inp_fport));
#endif

#if	defined(hpux) || defined(_IBMR2) || defined(NeXT) || defined(sun)
			printinaddr(&inp.inp_faddr, inp.inp_fport);
#endif

		}
		break;

	case AF_UNIX:
		if (Funix)
			Fprint = 1;
		(void) strcpy(Type, "unix");
	/*
	 * Read Unix protocol control block and the Unix address structure.
	 */

		(void) sprintf(Devch, "0x%08x", sa);
		if (kread((off_t) s.so_pcb, (char *) &unp, sizeof(unp))) {
			(void) sprintf(Namech, "can't read unpcb at %#x",
				s.so_pcb);
			break;
		}
		if ((struct socket *)sa != unp.unp_socket) {
			(void) sprintf(Namech, "unp_socket (%#x) mismatch",
				unp.unp_socket);
			break;
		}
		if (unp.unp_addr) {
		    if (kread((off_t) unp.unp_addr, (char *) &mb, sizeof(mb))) {
			(void) sprintf(Namech,
				"can't read unp_addr at %#x",
				unp.unp_addr);
			break;
		    }
		    ua = (struct sockaddr_un *)(((char *)&mb) + mb.m_off);
		} else {
			ua = (struct sockaddr_un *)&mb;
			(void) bzero((char *)ua, sizeof(struct sockaddr_un));
			ua->sun_family = AF_UNSPEC;
		}
	/*
	 * Print information on Unix socket that has no address bound
	 * to it, although it may be connected to another Unix domain
	 * socket as a pipe.
	 */
		if (ua->sun_family != AF_UNIX) {
			if (ua->sun_family == AF_UNSPEC) {
				if (unp.unp_conn) {
					if (kread((off_t) unp.unp_conn,
						(char *) &uc, sizeof(uc))) {
					    (void) sprintf(Namech,
						"can't read unp_conn at %#x",
						unp.unp_conn);
					} else {
					    (void) sprintf(Namech,
						"->0x%08x", uc.unp_socket);
					}
				} else
					(void) strcpy(Namech, "->(none)");
			} else
				(void) sprintf(Namech,
					"unknown sun_family (%d)",
					ua->sun_family);
			break;
		}

#if	defined(_IBMR2)
	/*
	 * Read any associated vnode and then read its gnode and inode.
	 */
		g.gn_type = VSOCK;
		if (unp.unp_vnode && readvnode(unp.unp_vnode, &v) == 0) {
			if (v.v_gnode && readgnode(v.v_gnode, &g) == 0) {
				Lock = isglocked(&g);
				if (g.gn_type == VSOCK && g.gn_data
				&& readinode(g.gn_data, &i) == 0)
					is = 1;
			}
		}
	/*
	 * Print Unix socket information.
	 */
		if (is) {
			Dev = i.i_dev;
			Fdev = 1;
			Devch[0] = '\0';
			Inode = (long)i.i_number;
		}
#endif

		(void) sprintf(Namech, "%.*s",
			mb.m_len - sizeof(ua->sun_family),
			ua->sun_path[0] ? ua->sun_path : "no address");
		break;

	default:
		(void) sprintf(Namech, "unknown family %#x", fam);
	}
	printline();
}


/*
 * printuid() - print User ID or login name
 */

void
printuid(u)
	uid_t u;			/* User ID number */
{
	static int p = 0;
	static uid_t pu;
	struct passwd *pw;

	if (p && u == pu)
		return;
	p = 1;
	pu = u;
	if (Futol && (pw = getpwuid(u)) != NULL)
		(void) sprintf(User, "%*.*s", USERPRTL, USERPRTL, pw->pw_name);
	else
		(void) sprintf(User, "%*d", USERPRTL, u);
}


/*
 * printvnode() - print vnode
 */

void
printvnode(va)
	caddr_t va;			/* vnode kernel space address */
{

	dev_t dev;
	struct inode i;
	int prdev;
	struct rnode r;
	char *ty;
	enum vtype type;
	struct vnode v;
	struct l_vfs *vfs;

#if	defined(NeXT)
	struct vnode rv;
	struct snode s;
#endif

#if	defined(_IBMR2)
	struct cdrnode c;
	struct gnode g;
#endif

#if	defined(sun)
	struct fifonode f;
	struct vnode rv;
	struct snode s;
	struct tmpnode t;
#endif

/*
 * Read the vnode.
 */
	if (readvnode((caddr_t)va, &v)) {
                printline();
                return;
        }


#if	defined(DYNIX) || defined(hpux) || defined(NeXT) || defined(sun)
/*
 * Determine the DYNIX, HP-UX, NeXT and SunOS vnode type.
 */
	if ((unsigned long)v.v_op == Nl[X_NFS_OPS].n_value)
		Vtype = V_NFS;

#if	defined(sun)
	else if ((unsigned long)v.v_op == Nl[X_TMP_OPS].n_value)
		Vtype = V_TMP;
#endif

	else if (v.v_type == VFIFO)
		Vtype = V_FIFO;

#if	defined(sun)
	else if (v.v_type == VCHR && !v.v_vfsp && v.v_stream)
		Vtype = V_STREAM;
#endif

/*
 * Determine the DYNIX, HP-UX, NeXT or SunOS lock type.
 */
	if (v.v_shlockc || v.v_exlockc) {
		if (v.v_shlockc && v.v_exlockc)
			Lock = '*';
		else if (v.v_shlockc)
			Lock = 'R';
		else
			Lock = 'W';
	}
#endif

/*
 * Read the virtual file system structure.
 */
	if ((vfs = readvfs(v.v_vfsp)) == NULL) {
                (void) sprintf(Namech, "can't read vfs for %#x at %#x", v,
			v.v_vfsp);
                printline();
		return;
	}

#if	defined(_IBMR2)
/*
 * Determine the AIX vnode type.
 */
	if (vfs->vmt_flags & MNT_REMOTE)
		Vtype = V_NFS;
/*
 * Read the AIX gnode and the associated inode or rnode.
 */

	if (v.v_gnode) {
		if (readgnode(v.v_gnode, &g)) {
			printline();
			return;
		}
	} else {
		(void) sprintf(Namech, "vnode at %#x has no gnode\n", va);
		printline();
		return;
	}
	Lock = isglocked(&g);
	if (Vtype == V_NFS) {
		if (g.gn_data == NULL || readrnode(g.gn_data, &r)) {
			(void) sprintf(Namech,
				"remote gnode at %#x has no rnode", v.v_gnode);
			printline();
			return;
		}
	} else {
		if (vfs->vmt_gfstype == MNT_CDROM) {
			if (g.gn_data == NULL || readcdrnode(g.gn_data, &c)) {
				(void) sprintf(Namech,
					"gnode at %#x has no cdrnode",
					v.v_gnode);
				printline();
				return;
			}
			i.i_number = c.cn_inumber;
			i.i_size = (off_t)c.cn_size;
		} else if (g.gn_data == NULL || readinode(g.gn_data, &i)) {
			(void) sprintf(Namech, "gnode at %#x has no inode",
				v.v_gnode);
			printline();
			return;
		}
	}
#endif

#if	defined(DYNIX) || defined(hpux) || defined(NeXT) || defined(sun)
/*
 * Read the DYNIX, HP-UX, NeXT or SunOS fifonode, inode, rnode, snode or
 * tmpnode.
 */
	switch (Vtype) {
	case V_NFS:
		if (!v.v_data || readrnode((caddr_t)v.v_data, &r)) {
			(void) sprintf(Namech,
				"vnode at %#x: can't read rnode (%#x)",
				va, v.v_data);
			printline();
			return;
		}
		break;

#if	defined(sun)
	case V_FIFO:

	/*
	 * A Sun FIFO's vnode is linked to a fifonode.  The s_realvp
	 * pointer of the snode contained in the fifonode points to
	 * a vnode that points to the inode.  (Whew!)
	 */
		if (!v.v_data || readfifonode(v.v_data, &f)) {
			(void) sprintf(Namech,
				"vnode at %#x: can't read fifonode (%#x)",
				va, v.v_data);
			printline();
			return;
		}
		if (f.fn_snode.s_realvp) {
			if (readvnode((caddr_t)f.fn_snode.s_realvp, &rv)) {
			    (void) sprintf(Namech,
				"fifonode at %#x: can't read real vnode (%#x)",
				v.v_data, f.fn_snode.s_realvp);
			    printline();
			    return;
			}
			if (!rv.v_data || readinode(rv.v_data, &i)) {
				(void) sprintf(Namech,
				    "fifonode at %#x: can't read inode (%#x)",
				    v.v_data, rv.v_data);
				printline();
				return;
			}
		} else {
			printline();
			return;
		}
		break;
	case V_STREAM:
		if (!v.v_data || readsnode((caddr_t)v.v_data, &s)) {
			(void) sprintf(Namech,
				"vnode at %#x: can't read snode (%#x)",
				va, v.v_data);
			printline();
			return;
		}
		break;
	case V_TMP:
		if (!v.v_data || readtnode((caddr_t)v.v_data, &t)) {
			(void) sprintf(Namech,
				"vnode at %#x: can't read tnode (%#x)",
				va, v.v_data);
			printline();
			return;
		}
		break;
#endif

	case V_REG:
	default:

#if	defined(NeXT) || defined(sun)
	/*
	 * NeXT and Sun VCHR vnodes point to an snode.  The snode's s_realvp
	 * usually points to a real vnode, which points to an inode.
	 */
		if (v.v_type == VCHR) {
			if (!v.v_data || readsnode(v.v_data, &s)) {
				(void) sprintf(Namech,
					"vnode at %#x: can't read snode(%#x)",
					va, v.v_data);
				printline();
				return;
			}
			if (s.s_realvp) {
			    if (readvnode((caddr_t)s.s_realvp, &rv)) {
				(void) sprintf(Namech,
				    "snode at %#x: can't read real vnode (%#x)",
				    v.v_data, s.s_realvp);
				printline();
				return;
			    }
			    if (!rv.v_data || readinode(rv.v_data, &i)) {
				(void) sprintf(Namech,
					"snode at %#x: can't read inode (%#x)",
					v.v_data, rv.v_data);
				printline();
				return;
			    }
			} else
				(void) bzero((char *)&i, sizeof(i));
			break;
		}
#endif

		if (!v.v_data || readinode(v.v_data, &i)) {
			(void) sprintf(Namech,
				"vnode at %#x: can't read inode (%#x)",
				va, v.v_data);
			printline();
			return;
		}
	}
#endif

/*
 * Get device and type for printing.
 */

#if	defined(DYNIX)
	switch(Vtype) {
	case V_NFS:

	/*
	 * Neither the rnode nor the vnode under DYNIX 3.0.12 contains the
	 * correct device number, so it's reclaimed (if possible) from the
	 * local, virtual file system table entry (put there by completevfs()
	 * from information placed in Mtab by readmnt()).
	 */
		dev = vfs->dev;
		break;
	default:
		dev = (v.v_type == VCHR) ? v.v_rdev : i.i_dev;
	}
	type = v.v_type;
	if (vfs->dir == NULL)
		(void) completevfs(vfs, dev);
#endif

#if	defined(hpux)
	if (Vtype == V_NFS)
		dev = vfs->dev;
	else
		dev = (v.v_type == VCHR) ? v.v_rdev : i.i_dev;
	type = v.v_type;
#endif

#if	defined(_IBMR2)
	if (Vtype == V_NFS)
		dev = vfs->dev;
	else
		dev = g.gn_rdev;
	type = g.gn_type;
#endif

#if	defined(NeXT)
	switch (Vtype) {
	case V_NFS:
		dev = r.r_attr.va_fsid;
		if (dev & 0x8000)
			dev |= 0xff00;
		break;
	case V_REG:
		dev = (v.v_type == VCHR) ? v.v_rdev : i.i_dev;
	}
	type = v.v_type;
	if (vfs->dir == NULL)
		(void) completevfs(vfs, dev);
#endif

#if	defined(sun)
	switch (Vtype) {
	case V_NFS:
		dev = r.r_attr.va_fsid;
		break;
	case V_STREAM:
		dev = s.s_dev;
		break;
	case V_TMP:
		dev = t.tn_attr.va_fsid;
		break;
	default:
		dev = (v.v_type == VCHR) ? v.v_rdev : i.i_dev;
	}
	type = v.v_type;
	if (vfs->dir == NULL)
		(void) completevfs(vfs, dev);
#endif

/*
 * Obtain the inode number.
 */

#if	defined(DYNIX)
	switch (Vtype) {
	case V_NFS:
		Inode = (long)r.r_nfsattr.na_nodeid;
		break;
	case V_FIFO:
	case V_REG:
		Inode = (long)i.i_number;
	}
#endif

#if	defined(hpux)
	switch (Vtype) {
	case V_NFS:
		Inode = (long)r.r_nfsattr.na_nodeid;
		break;
	case V_FIFO:
	case V_REG:
		Inode = (long)i.i_number;
	}
#endif

#if	defined(_IBMR2)
	Inode = (long)(Vtype == V_NFS) ? r.r_attr.va_serialno : i.i_number;
#endif

#if	defined(NeXT)
	switch(Vtype) {
	case V_NFS:
		Inode = (long)r.r_attr.va_nodeid;
		break;
	case V_REG:
		Inode = (long)i.i_number;
	}
#endif

#if	defined(sun)
	switch (Vtype) {
	case V_NFS:
		Inode = (long)r.r_attr.va_nodeid;
		break;
	case V_FIFO:
	case V_REG:
		Inode = (long)i.i_number;
		break;
	case V_TMP:
		Inode = (long)t.tn_attr.va_nodeid;
		break;
	case V_STREAM:
		Inode = -2l;
	}
#endif

/*
 * Obtain the file size.
 */
	switch (Vtype) {
	case V_NFS:

#if	defined(DYNIX) || defined(hpux)
		Size = r.r_nfsattr.na_size;
#endif

#if	defined(_IBMR2) || defined(NeXT) || defined(sun)
		Size = r.r_attr.va_size;
#endif

		Size_def = 1;
		break;
	case V_REG:
		Size = i.i_size;
		Size_def = 1;
	}

/*
 * Format the name characters.
 */
	if (Vtype == V_NFS && Fnfs)
		Fprint = 1;
	(void) sprintf(Namech, "%s (%s)",
		(vfs->dir) ? vfs->dir : "",
		(vfs->fsname) ? vfs->fsname : "");
/*
 * Test for specified file.
 */
	prdev = 1;
	if (Sfile && Fprint == 0) {

#if	defined(DYNIX) || defined(hpux) || defined(NeXT) || defined(sun)
		Fprint = isfile(dev, type, 0, Inode);
#endif

#if	defined(_IBMR2)
		Fprint = isfile(dev, type, g.gn_chan, Inode);
#endif

		if (Fprint == 0)
			return;
		prdev = 0;
	}
/*
 * Format the vnode type, and possibly the device name.
 */
	switch (type) {

	case VNON:
		ty ="VNON";
		break;
	case VREG:
	case VDIR:
		ty = (type == VREG) ? "VREG" : "VDIR";
		Fdev = 1;
		Dev = dev;
		break;
	case VBLK:
		ty = "VBLK";
		break;
	case VCHR:
		Dev = dev;
		Fdev = 1;
		if (prdev)
			(void) printchdevname(Dev, -1);
		ty = "VCHR";
		break;
	case VLNK:
		ty = "VLNK";
		break;
	case VSOCK:
		ty = "SOCK";
		break;
	case VBAD:
		ty = "VBAD";
		break;
	case VFIFO:
		Dev = dev;
		Fdev = 1;
		ty = "FIFO";
		break;

#if	defined(_IBMR2)
	case VMPC:
		Dev = g.gn_rdev;
		Fdev = 1;
		Inode = -2l;
		if (prdev)
			(void) printchdevname(g.gn_rdev, g.gn_chan);
		ty = "VMPC";
		break;
#endif

	default:
		(void) sprintf(Type, "%4d", type);
		(void) strcpy(Namech, "unknown type");
		ty = NULL;
	}
	if (ty)
		(void) strcpy(Type, ty);
/*
 * Print the line (at last) if printing has been selected.
 */
	printline();
}


#if	defined(_IBMR2)
/*
 * readcdrnode() - read CD-ROM node
 */

int
readcdrnode(ca, c)
	caddr_t ca;			/* cdrnode kernel address */
	struct cdrnode *c;		/* cdrnode buffer */
{
	if (kread((off_t)ca, (char *)c, sizeof(struct cdrnode))) {
		(void) sprintf(Namech, "can't read cdrnode at %#x", ca);
		return(1);
	}
	return(0);
}
#endif


/*
 * readdev() - read names, modes and device types of everything in /dev
 */

void
readdev()
{

	DIR *dfp;
	int dn = 0;
	char **dstk = NULL;
	int dx = 0;
	int err = 0;
	int i = 0;
	MALLOC_S nl;
	char path[MAXNAMLEN+1];
	int pl;
	struct stat sb;

#if	defined(DYNIX) || defined(NeXT)
	struct direct *dp;
#endif

#if	defined(hpux) || defined(_IBMR2) || defined(sun)
	struct dirent *dp;
#endif

#if	defined(sun)
	struct clone *c;
#endif

	(void) stkdir(&dstk, &dn, &dx, "/dev");
/*
 * Unstack the next /dev or /dev/<subdirectory> directory.
 */
	while (--dx >= 0) {
		(void) strcpy(path, dstk[dx]);
		if ((dfp = opendir(path)) == NULL) {
			if (Fdevmsg)
				(void) fprintf(stderr, "%s: can't open %s\n",
					Pn, path);
			continue;
		}
		(void) strcat(path, "/");
		pl = strlen(path);
		(void) free((FREE_P *)dstk[dx]);
		dstk[dx] = NULL;
	/*
	 * Scan the directory.
	 */
		for (dp = readdir(dfp); dp; dp = readdir(dfp)) {
			if (dp->d_ino == 0 || dp->d_name[0] == '.')
				continue;
		/*
		 * Form the full path name and get its status.
		 */
			if ((nl = pl + dp->d_namlen) >= sizeof(path)) {
				(void) fprintf(stderr,
					"%s: /dev entry name too long: %s\n",
					Pn, dp->d_name);
				exit(1);
			}
			(void) strncpy(&path[pl], dp->d_name,
				      (STRNCPY_L)dp->d_namlen);
			path[nl++] = '\0';
			if (lstat(path, &sb) != 0) {
				(void) fprintf(stderr,
					"%s: can't lstat %s: %s\n",
					Pn, path, sys_errlist[errno]);
				err++;
				continue;
			}
		/*
		 * If it's a subdirectory, stack its name for later
		 * processing.
		 */
			if ((sb.st_mode & S_IFMT) == S_IFDIR) {
				(void) stkdir(&dstk, &dn, &dx, path);
				continue;
			}
		/*
		 * Skip all but character devices.
		 */
			if ((sb.st_mode & S_IFMT) != S_IFCHR)
				continue;
		/*
		 * Make room for another Devtp[] entry.
		 */
			if (i >= Ndev) {
				Ndev += DEVINCR;
				if (Devtp == NULL)
				    Devtp = (struct dev *)malloc(
					(MALLOC_S)(sizeof(struct dev) * Ndev));
				else
				    Devtp = (struct dev *)realloc(
					(MALLOC_P *)Devtp,
					(MALLOC_S)(sizeof(struct dev)*Ndev));
				if (Devtp == NULL) {
					(void) fprintf(stderr,
						"%s: no space for devices\n",
						Pn);
					exit(1);
				}
			}
		/*
		 * Store the name and device number in the Devtp[] entry.
		 */
			Devtp[i].rdev = sb.st_rdev;
			if ((Devtp[i].name = (char *)malloc(nl)) == NULL) {
				(void) fprintf(stderr,
					"%s: no space for /dev/%s\n",
					Pn, dp->d_name);
				exit(1);
			}
			(void) strcpy(Devtp[i].name, path);

#if	defined(sun)
		/*
		 * Save the locations of the SunOS clone devices.
		 */
			if (major(Devtp[i].rdev) == CLONEMAJ) {
				if ((c =
				   (struct clone *)malloc(sizeof(struct clone)))
				== NULL) {
					(void) fprintf(stderr,
						"%s: no space for clone\n", Pn);
					exit(1);
				}
				c->dp = &Devtp[i];
				c->next = Clone;
				Clone = c;
			}
#endif

			i++;
		}
		(void) closedir(dfp);
	}
/*
 * Free any directory stack space.
 */
	if (dstk != NULL)
		(void) free((FREE_P *)dstk);
/*
 * Reduce the Devtp[] table to its minimum size.
 */
	if (Ndev > i) {
		Ndev = i;
		Devtp = (struct dev *)realloc((MALLOC_P *)Devtp,
		      (MALLOC_S)(sizeof(struct dev) * Ndev));
	}
	if (err)
		exit(1);
/*
 * Allocate sorting pointers and sort them by Devtp[] device number.
 */
	if ((Sdev = (struct dev **)malloc((MALLOC_S)(sizeof(struct dev *)
	    * Ndev)))
	== NULL) {
		(void) fprintf(stderr, "%s: no space for device pointers\n",
			Pn);
		exit(1);
	}
	for (i = 0; i < Ndev; i++) {
		Sdev[i] = &Devtp[i];
	}
	(void) qsort((QSORT_P *)Sdev,(size_t)Ndev,(size_t)sizeof(struct dev *),
		compdev);
}


#if	defined(sun)
/*
 * readfifonode() - read fifonode
 */

int
readfifonode(fa, f)
	caddr_t fa;			/* fifonode kernel address */
	struct fifonode *f;		/* fifonode buffer */
{
	if (kread((off_t)fa, (char *)f, sizeof(struct fifonode))) {
		(void) sprintf(Namech, "can't read fifonode at %#x", fa);
		return(1);
	}
	return(0);
}
#endif


#if	defined(_IBMR2)
/*
 * readgnode() - read gnode
 */

int
readgnode(ga, g)
	caddr_t ga;			/* gnode kernel address */
	struct gnode *g;		/* gnode buffer */
{
	if (kread((off_t)ga, g, sizeof(struct gnode))) {
		(void) sprintf(Namech, "can't read gnode at %#x", ga);
		return(1);
	}
	return(0);
}
#endif


/*
 * readinode() - read inode
 */

int
readinode(ia, i)
	caddr_t ia;			/* inode kernel address */
	struct inode *i;		/* inode buffer */
{
	if (kread((off_t)ia, (char *)i, sizeof(struct inode))) {
		(void) sprintf(Namech, "can't read inode at %#x", ia);
		return(1);
	}
	return(0);
}


#if	defined(DYNIX) || defined(hpux) || defined(NeXT) || defined(sun) 
/*
 * readmnt() - read mount table
 */

void
readmnt()
{
	int err = 0;
	FILE *mfp;
	struct mntent *mp;
	struct mounts *mtp;
	struct stat sb;

        if ((mfp = setmntent(MOUNTED, "r")) == NULL) {
                (void) fprintf(stderr, "%s: can't access %s\n", Pn, MOUNTED);
                exit(1);
        }
        while ((mp = getmntent(mfp)) != NULL) {
                if (statsafely(mp->mnt_dir, &sb, STATTMO))
                        continue;
		if ((mtp = (struct mounts *)malloc(sizeof(struct mounts)))
		== NULL) {
			err = 1;
			break;
		}
		if ((mtp->dir = (char *)malloc(
				(MALLOC_S)(strlen(mp->mnt_dir)+1)))
		== NULL) {
			err = 1;
			break;
		}
		(void) strcpy(mtp->dir, mp->mnt_dir);
		if ((mtp->fsname = (char *)malloc(
				   (MALLOC_S)(strlen(mp->mnt_fsname)+1)))
		== NULL) {
			err = 1;
			break;
		}
		(void) strcpy(mtp->fsname, mp->mnt_fsname);
		mtp->next = Mtab;
		mtp->dev = sb.st_dev;
		mtp->inode = sb.st_ino;
		mtp->mode = sb.st_mode;
		mtp->rdev = sb.st_rdev;
		Mtab = mtp;
        }
        (void) endmntent(mfp);
	if (err) {
		(void) fprintf(stderr, "%s: no space for mount at %s (%s)\n",
			Pn, mp->mnt_fsname, mp->mnt_dir);
		exit(1);
	}
}
#endif


#if	defined(_IBMR2)
/*
 * readmnt() - read mount table
 */

void
readmnt()
{
	int err = 0;
	char *dir, *fs, *h;
	int fsl;
	struct mounts *mtp;
	int nm;
	struct stat sb;
	unsigned sz;
	struct vmount *v, *vt;

/*
 * Read the table of vmount structures.
 */
	for (sz = sizeof(struct vmount);;) {
		if ((vt = (struct vmount *)malloc(sz)) == NULL) {
			(void) fprintf(stderr,
				"%s: no space for vmount table\n", Pn);
			exit(1);
		}
		nm = mntctl(MCTL_QUERY, sz, vt);
		if (nm > 0) {
			if (vt->vmt_revision != VMT_REVISION) {
				(void) fprintf(stderr,
					"%s: stale file system, rev %d != %d\n",
					Pn, vt->vmt_revision, VMT_REVISION);
				exit(1);
			}
			break;
		}
		if (nm == 0) {
			sz = (unsigned)vt->vmt_revision;
			(void) free((FREE_P *)vt);
		} else {
			(void) fprintf(stderr, "%s: mntctl error: %s\n",
				Pn, sys_errlist[errno]);
			exit(1);
		}
	}
/*
 * Scan the vmount structures and build Mtab.
 */
	for (v = vt; nm--; v = (struct vmount *)((char *)v + v->vmt_length)) {
		dir = (char *)vmt2dataptr(v, VMT_STUB);
		fs = (char *)vmt2dataptr(v, VMT_OBJECT);
		h = (char *)vmt2dataptr(v, VMT_HOST);
		fsl = strlen(fs);
		if (v->vmt_flags & MNT_REMOTE)
			fsl += strlen(h) + 1;
                if (statsafely(dir, &sb, STATTMO))
                        continue;
		if ((mtp = (struct mounts *)malloc(sizeof(struct mounts)))
		== NULL) {
			err = 1;
			break;
		}
		if ((mtp->dir = (char *)malloc(strlen(dir) + 1)) == NULL) {
			err = 1;
			break;
		}
		(void) strcpy(mtp->dir, dir);
		if ((mtp->fsname = (char *)malloc(fsl + 1)) == NULL) {
			err = 1;
			break;
		}
		if (v->vmt_flags & MNT_REMOTE)
			(void) sprintf(mtp->fsname, "%s:%s", h, fs);
		else
			(void) strcpy(mtp->fsname, fs);
		mtp->dev = sb.st_dev;
		mtp->inode = sb.st_ino;
		mtp->mode = sb.st_mode;
		mtp->rdev = sb.st_rdev;
		mtp->next = Mtab;
		Mtab = mtp;
        }
	if (err) {
		(void) fprintf(stderr, "%s: no space for mount at %s (%s)\n",
			Pn, fs, dir);
		exit(1);
	}
	(void) free((FREE_P *)vt);
}
#endif


/*
 * readrnode() - read rnode
 */

int
readrnode(ra, r)
	caddr_t ra;			/* rnode kernel space address */
	struct rnode *r;		/* rnode buffer pointer */
{
	if (kread((off_t)ra, (char *)r, sizeof(struct rnode))) {
		(void) sprintf(Namech, "can't read rnode at %#x", ra);
		return(1);
	}
	return(0);
}


#if	defined(NeXT) || defined(sun)
/*
 * readsnode() - read snode
 */

int
readsnode(sa, s)
	caddr_t sa;			/* snode kernel space address */
	struct snode *s;		/* snode buffer pointer */
{
	if (kread((off_t)sa, (char *)s, sizeof(struct snode))) {
		(void) sprintf(Namech, "can't read snode at %#x", sa);
		return(1);
	}
	return(0);
}
#endif


#if	defined(sun)
/*
 * readtnode() - read tmpnode
 */

int
readtnode(ta, t)
	caddr_t ta;			/* tmpnode kernel space address */
	struct tmpnode *t;		/* tmpnode buffer pointer */
{
	if (kread((off_t)ta, (char *)t, sizeof(struct tmpnode))) {
		(void) sprintf(Namech, "can't read tmpnode at %#x", ta);
		return(1);
	}
	return(0);
}
#endif


/*
 * readvfs() - read vfs structure
 */

struct l_vfs *
readvfs(va)
	struct vfs *va;			/* vfs structure kernel address
					 * - e. g., v.v_vfsp */
{
	struct vfs v;
	struct l_vfs *vp;

#if	defined(DYNIX) ||defined(hpux) || defined(sun)
	struct mount m;
#endif

#if	defined(DYNIX) || defined(hpux)
	struct mntinfo mi;
#endif

#if	defined(_IBMR2)
	struct gfs g;
	void *mp;
	char *s1, *s2;
	unsigned slen;
	u_long ul;
	struct vmount *vm;
#endif

	for (vp = Lvfs; vp; vp = vp->next) {
		if (va == vp->addr)
			return(vp);
	}
	if ((vp = (struct l_vfs *)malloc(sizeof(struct l_vfs))) == NULL) {
		(void) fprintf(stderr, "%s: no space for vfs\n", Pn);
		exit(1);
	}

#if	defined(DYNIX) || defined(hpux)
	vp->dev = 0;
#endif

	vp->dir = NULL;
	vp->fsname = NULL;

#if	defined(sun)
/*
 * SunOS vnodes of type VCHR that have a non-null v_stream pointer
 * represent streams and have no virtual file system pointer.
 */

#endif

#if	defined(DYNIX) ||defined(hpux) || defined(_IBMR2) || defined(NeXT)
	if (!va)
		goto vfs_exit;
#endif

	if (va && kread((off_t)va, (char *)&v, sizeof(v))) {

#if	defined(DYNIX) || defined(hpux) || defined(_IBMR2) || defined(NeXT)

vfs_exit:

#endif

		(void) free((FREE_P *)vp);
		return(NULL);
	}

#if	defined(_IBMR2)
/*
 * Locate AIX mount information.
 */
	if (kread((off_t) v.vfs_gfs, &g, sizeof(g)))
		goto vfs_exit;
	if (kread((off_t) v.vfs_mdata + sizeof(u_long), &ul, sizeof(ul)))
		goto vfs_exit;
	if ((mp = malloc((size_t) ul)) == NULL) {
		(void) fprintf(stderr, "%s: no space for mount data\n", Pn);
		exit(1);
	}
	if (kread((off_t) v.vfs_mdata, mp, (int) ul)) {
		(void) free((FREE_P *)mp);
		goto vfs_exit;
	}
	vm = (struct vmount *)mp;
	vp->vmt_flags = vm->vmt_flags;
	vp->vmt_gfstype = vm->vmt_gfstype;
	vp->dev = (dev_t)vm->vmt_fsid.fsid_dev;
	if ((s1 = vmt2dataptr(vm, VMT_STUB)) != NULL) {
		if ((vp->dir = (char *)malloc(strlen(s1) + 1)) == NULL) {

readvfs_aix1:
			(void) fprintf(stderr, "%s: readvfs, no space\n", Pn);
			exit(1);
		}
		(void) strcpy(vp->dir, s1);
	} else
		vp->dir = NULL;
	s1 = vmt2dataptr(vm, VMT_HOST);
	if ((s2 = vmt2dataptr(vm, VMT_OBJECT)) == NULL || *s1 == '\0')
		s2 = g.gfs_name;
	if (s1 == NULL && s2 == NULL)
		vp->fsname = NULL;
	else {
		slen = s2 ? strlen(s2) : 0;
		if (vm->vmt_flags & MNT_REMOTE)
			slen += (s1 ? strlen(s1) : 0) + 1;
		if ((vp->fsname = (char *)malloc(slen + 1)) == NULL)
			goto readvfs_aix1;
		if (vm->vmt_flags & MNT_REMOTE)
			(void) sprintf(vp->fsname, "%s:%s",
				s1 ? s1 : "", s2 ? s2 : "");
		else
			(void) strcpy(vp->fsname, s2 ? s2 : "");
	}
	(void) free((FREE_P *)mp);
#endif

/*
 * Complete DYNIX, HP-UX and SunOS mount information.
 */

#if	defined(DYNIX) || defined(hpux)
	if (Vtype == V_NFS) {

	/*
	 * DYNIX and HP-UX NFS vnode device values have a major number of 255.
	 * The minor number is a serial number found in the mntinfo
	 * structure to which the virtual file system's vfs_data points.
	 */ 
		if (v.vfs_data
		&&  kread((off_t)v.vfs_data, (char *)&mi, sizeof(mi)) == 0)
			(void) completevfs(vp, makedev(255, mi.mi_mntno));
	} else {
		if (kread((off_t)v.vfs_data, (char *)&m, sizeof(m)) == 0)
			(void) completevfs(vp, m.m_dev);
	}
#endif

#if	defined(sun)
	if (va && v.vfs_data && kread((off_t)v.vfs_data, (char *)&m, sizeof(m))
	== 0)
		(void) completevfs(vp, m.m_dev);
#endif

	vp->next = Lvfs;
	vp->addr = va;
	Lvfs = vp;
	return(vp);
}


/*
 * readvnode() - read vnode
 */

int
readvnode(va, v)
	caddr_t va;			/* vnode kernel space address */
	struct vnode *v;		/* vnode buffer pointer */
{
	if (kread((off_t)va, (char *)v, sizeof(struct vnode))) {
		(void) sprintf(Namech, "can't read vnode at %#x", va);
		return(1);
	}
	return(0);
}


/*
 * statsafely() - stat path safely (i. e., with timeout)
 */

statsafely(path, buf, tm)
        char *path;
        struct stat *buf;
        int tm;
{
        int err;
        static int sverr;

        if (tm == 0)
                return(stat(path, buf));
        sverr = errno;
        if (setjmp(Tmo_jbuf)) {
                (void) alarm(0);
                (void) signal(SIGALRM, SIG_IGN);
                errno = ETIMEDOUT;
                return(-1);
        }
        (void) signal(SIGALRM, stattimeout);
        (void) alarm((unsigned)tm);
        err = stat(path, buf);
        if (err != 0)
                sverr = errno;
        (void) alarm(0);
        (void) signal(SIGALRM, SIG_IGN);
        errno = sverr;
        return(err);
}


/*
 * stattimeout() - time out a stat() call
 */

#if	defined(DYNIX)
int
#endif

#if	defined(hpux) || defined(_IBMR2) || defined(NeXT) || defined(sun)
void
#endif

stattimeout()
{
        (void) alarm(0);
        (void) signal(SIGALRM, SIG_IGN);
        longjmp(Tmo_jbuf, 1);
}


/*
 * stkdir() - stack directory name
 */

void
stkdir(d, n, x, p)
	char ***d;		/* array of directory pointers */
	int *n;			/* number of pointers */
	int *x;			/* current index */
	char *p;		/* directory path */
{
	if (*d == NULL) {

	/*
	 * Allocate first entry.
	 */
		if ((*d = (char **)malloc(sizeof(char *))) == NULL) {

stkdir_nospace:

			(void) fprintf(stderr,
				"%s: no space for directory stack at %s\n",
				Pn, p);
			exit(1);
		}
		*n = 1;
		*x = 0;
	} else if (*x >= *n) {

	/*
	 * Allocate additional space as required.
	 */
		*n += 1;
		if ((*d = (char **)realloc((MALLOC_P *)*d,
		          (MALLOC_S)(*n * sizeof(char *))))
		== NULL)
			goto stkdir_nospace;
	}
/*
 * Allocate space for the name, copy it there and put its pointer on the stack.
 */
	if (((*d)[*x] = (char *)malloc((MALLOC_S)(strlen(p) + 1))) == NULL) {
		(void) fprintf(stderr, "%s: no space for %s\n", Pn, p);
		exit(1);
	}
	(void) strcpy((*d)[*x], p);
	*x += 1;
}
