/*
 * dnode.c - NetBSD and OpenBSD node functions for lsof
 */


/*
 * Copyright 1994 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 authors 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 authors 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.
 */

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


#include "lsof.h"


#if	defined(HAS_DINODE_U)
#define	DINODE_U	dinode_u
#else	/* !defined(HAS_DINODE_U) */
#define	DINODE_U	i_din
#endif	/* defined(HAS_DINODE_U) */

#if	defined(HASFDESCFS) && HASFDESCFS==1
_PROTOTYPE(static int lkup_dev_tty,(dev_t *dr, INODETYPE *ir));
#endif	/* defined(HASFDESCFS) && HASFDESCFS==1 */

#if	defined(HAS_UM_UFS)
#define	UFS1	UM_UFS1
#define	UFS2	UM_UFS2
#endif	/* defined(HAS_UM_UFS) */

#if	defined(HASPROCFS)
_PROTOTYPE(static void getmemsz,(pid_t pid));

# if	!defined(PGSHIFT)
#define	PGSHIFT	pgshift
# endif	/* !defined(PGSHIFT) */


/*
 * getmemsz() - get memory size of a /proc/<n>/mem entry
 */

static void
getmemsz(pid)
	pid_t pid;
{
	int n;
	struct vmspace vm;

#if	defined(HASKVMGETPROC2)
	struct kinfo_proc2 *p;
#else	/* !defined(HASKVMGETPROC2) */
	struct kinfo_proc *p;
#endif	/* defined(HASKVMGETPROC2) */

	for (n = 0, p = P; n < Np; n++, p++) {
	    if (p->P_PID == pid) {
		if (!p->P_VMSPACE
		||  kread((KA_T)p->P_VMSPACE, (char *)&vm, sizeof(vm)))
		    return;
# if	defined(OPENBSDV)
		Lf->sz = (SZOFFTYPE)((vm.vm_tsize + vm.vm_dsize
		       + vm.vm_ssize) * sysconf(_SC_PAGESIZE));
# else	/* !defined(OPENBSDV */
		Lf->sz = (SZOFFTYPE)ctob(vm.vm_tsize + vm.vm_dsize
						     + vm.vm_ssize);
# endif	/* defined(OPENBSDV) */

		Lf->sz_def = 1;
		return;
	    }
	}
}
#undef	PGSHIFT
#endif	/* defined(HASPROCFS) */


#if	defined(HASFDESCFS) && HASFDESCFS==1
/*
 * lkup_dev_tty() - look up /dev/tty
 */

static int
lkup_dev_tty(dr, ir)
	dev_t *dr;			/* place to return device number */
	INODETYPE *ir;			/* place to return inode number */
{
	int i;

	readdev(0);

# if	defined(HASDCACHE)

lkup_dev_tty_again:

# endif	/* defined(HASDCACHE) */

	for (i = 0; i < Ndev; i++) {
	    if (strcmp(Devtp[i].name, "/dev/tty") == 0) {

# if	defined(HASDCACHE)
		if (DCunsafe && !Devtp[i].v && !vfy_dev(&Devtp[i]))
		    goto lkup_dev_tty_again;
# endif	/* defined(HASDCACHE) */

		*dr = Devtp[i].rdev;
		*ir = Devtp[i].inode;
		return(1);
	    }
	}

# if	defined(HASDCACHE)
	if (DCunsafe) {
	    (void) rereaddev();
	    goto lkup_dev_tty_again;
	}
# endif	/* defined(HASDCACHE) */

	return(-1);
}
#endif	/* defined(HASFDESCFS) && HASFDESCFS==1 */


#if	defined(HASKQUEUE)
/*
 * process_kqueue() -- process kqueue file
 *
 * Strictly speaking this function should appear in dfile.c, because it is
 * a file processing function.  However, the Net and Open BSD sources don't
 * require a dfile.c, so this is the next best location for the function.
 */

void
process_kqueue(ka)
	KA_T ka;			/* kqueue file structure address */
{

# if	defined(OPENBSDV)
	struct kqueue kq;		/* kqueue structure */
# endif	/* defined(OPENBSDV) */

	(void) snpf(Lf->type, sizeof(Lf->type), "KQUEUE");
	enter_dev_ch(print_kptr(ka, (char *)NULL, 0));

# if	defined(OPENBSDV)
	if (!ka || kread(ka, (char *)&kq, sizeof(kq)))
	    return;
	(void) snpf(Namech, Namechl, "count=%d, state=%#x", kq.kq_count,
	    kq.kq_state);
	enter_nm(Namech);
# endif	/* defined(OPENBSDV) */

}
#endif	/* defined(HASKQUEUE) */


/*
 * process_node() - process vnode
 */

void
process_node(va)
	KA_T va;			/* vnode kernel space address */
{
	dev_t dev, rdev;
	unsigned char devs;
	unsigned char lt;
	unsigned char ns;
	unsigned char rdevs;
	char *ep, *ty;
	struct lockf lf, *lff, *lfp;
	struct inode i;
	struct mfsnode m;
	struct nfsnode n;
	enum nodetype {NONODE, CDFSNODE, DOSNODE, EXT2NODE, FDESCNODE, INODE,
		KERNFSNODE, MFSNODE, NFSNODE, PFSNODE, PTYFSNODE} nty;
	enum vtype type;
	struct vnode *v, vb;
	struct l_vfs *vfs;

#if	defined(HAS9660FS)
	dev_t iso_dev;
	INODETYPE iso_ino;
	long iso_nlink;
	int iso_stat;
	SZOFFTYPE iso_sz;
#endif	/* defined(HAS9660FS) */

#if	defined(HASFDESCFS)
	struct fdescnode f;

# if	HASFDESCFS==1
	static dev_t f_tty_dev;
	static INODETYPE f_tty_ino;
	static int f_tty_s = 0;
# endif	/* HASFDESCFS==1 */

#endif	/* defined(HASFDESCFS) */

#if	defined(HASEXT2FS)
# if	defined(HASI_E2FS_PTR)
	struct ext2fs_dinode ed;
# endif	/* defined(HASI_E2FS_PTR) */
	struct ext2fs_dinode *edp = (struct ext2fs_dinode *)NULL;
#endif	/* defined(HASEXT2FS) */

#if	defined(HASI_FFS1)
	unsigned char ffs = 0;
	unsigned char u1s = 0;
	unsigned char u2s = 0;
	struct ufs1_dinode u1;
	struct ufs2_dinode u2;
	struct ufsmount um;
#endif	/* defined(HASI_FFS1) */

#if	defined(HASKERNFS)
	struct kernfs_node kn;
	struct stat ksb;
	int ksbs;
	struct kern_target kt;
	int ktnl;
	char ktnm[MAXPATHLEN+1];
#endif	/* defined(HASKERNFS) */

#if	defined(HASMSDOSFS)
	struct denode d;
	u_long dpb;
	INODETYPE nn;
	struct msdosfsmount pm;
#endif	/* defined(HASMSDOSFS) */

#if	defined(HASNFSVATTRP)
	struct vattr nv;
#define	NVATTR	nv
#else	/* !defined(HASNFSVATTRP) */
#define	NVATTR	n.n_vattr
#endif	/* defined(HASNFSVATTRP) */

#if	defined(HASNULLFS)
	struct null_node nu;
	int sc = 0;
	struct l_vfs *nvfs = (struct l_vfs *)NULL;
#endif	/* defined(HASNULLFS) */

#if	defined(HASPROCFS)
	struct pfsnode p;
	struct procfsid *pfi;
	size_t sz;
#endif	/* defined(HASPROCFS) */

#if	defined(HASPTYFS)
	struct ptyfsnode pt;
	struct specinfo si;
#endif	/* defined(HASPTYFS) */

#if	defined(HASNULLFS)

process_overlaid_node:

	if (++sc > 1024) {
	    (void) snpf(Namech, Namechl, "too many overlaid nodes");
	    enter_nm(Namech);
	    return;
	}
#endif	/* defined(HASNULLFS) */

/*
 * Initialize miscellaneous variables.  This is done so that processing an
 * overlaid node will be a fresh start.
 */
	devs = rdevs = 0;
	nty = NONODE;
	Namech[0] = '\0';

#if	defined(HAS9660FS)
	iso_stat = 0;
#endif	/* defined(HAS9660FS) */

#if	defined(HASKERNFS)
	ksbs = 0;
#endif	/* defined(HASKERNFS) */

#if	defined(HASEXT2FS)
	edp = (struct ext2fs_dinode *)NULL;
#endif	/* defined(HASEXT2FS) */

#if	defined(HASI_FFS1)
	ffs = u1s = u2s = 0;
#endif	/* defined(HASI_FFS1) */

/*
 * Read the vnode.
 */
	if (!va) {
	    enter_nm("no vnode address");
	    return;
	}
	v = &vb;
	if (readvnode(va, v)) {
	    enter_nm(Namech);
	    return;
	}

#if	defined(HASNCACHE)
	Lf->na = va;
# if	defined(HASNCVPID)
	Lf->id = v->v_id;
# endif	/* defined(HASNCVPID) */
#endif	/* defined(HASNCACHE) */

#if	defined(HASFSTRUCT)
	Lf->fna = va;
	Lf->fsv |= FSV_NI;
#endif	/* defined(HASFSTRUCT) */

/*
 * Get the vnode type.
 */
	if (!v->v_mount)
	    vfs = (struct l_vfs *)NULL;
	else {
	    vfs = readvfs((KA_T)v->v_mount);
	    if (vfs) {
		if (strcmp(vfs->type, MOUNT_NFS) == 0)
		    Ntype = N_NFS;

#if	defined(HASKERNFS)
		else if (strcmp(vfs->type, MOUNT_KERNFS) == 0)
		    Ntype = N_KERN;
#endif	/* defined(HASKERNFS) */

#if	defined(HASPROCFS)
		else if (strcmp(vfs->type, MOUNT_PROCFS) == 0)
		    Ntype = N_PROC;
#endif	/* defined(HASPROCFS) */

#if	defined(HAS9660FS)
		else if (strcmp(vfs->type, MOUNT_CD9660) == 0)
		    Ntype = N_CDFS;
#endif	/* defined(HAS9660FS) */

	    }
	}
	if (Ntype == N_REGLR) {
	    switch (v->v_type) {
	    case VFIFO:
		Ntype = N_FIFO;
		break;
	    }
	}
/*
 * Read the successor node.
 */
	switch (v->v_tag) {

#if	defined(HAS9660FS)
	case VT_ISOFS:
	    if (read_iso_node(v, &iso_dev, &iso_ino, &iso_nlink, &iso_sz))
	    {
		(void) snpf(Namech, Namechl, "can't read iso_node at: %s",
		    print_kptr((KA_T)v->v_data, (char *)NULL, 0));
		enter_nm(Namech);
		return;
	    }
	    iso_stat = 1;
	    nty = CDFSNODE;
	    break;
#endif	/* defined(HAS9660FS) */

#if	defined(HASFDESCFS)
	case VT_FDESC:
	    if (!v->v_data
	    ||  kread((KA_T)v->v_data, (char *)&f, sizeof(f))) {
		(void) snpf(Namech, Namechl, "can't read fdescnode at: %x",
		    print_kptr((KA_T)v->v_data, (char *)NULL, 0));
		enter_nm(Namech);
		return;
	    }
	    nty = FDESCNODE;
	    break;
#endif	/* defined(HASFDESCFS) */

#if	defined(HASKERNFS)
	case VT_KERNFS:
	
	/*
	 * Read the kernfs_node.
	 */
	    if (!v->v_data
	    ||  kread((KA_T)v->v_data, (char *)&kn, sizeof(kn))) {
		if (v->v_type != VDIR || !(v->v_flag && VROOT)) {
		    (void) snpf(Namech, Namechl,
			"can't read kernfs_node at: %s",
			print_kptr((KA_T)v->v_data, (char *)NULL, 0));
		    enter_nm(Namech);
		    return;
		} else
		    kn.kf_kt = (struct kern_target *)NULL;
	    }
	/*
	 * Generate the /kern file name by reading the kern_target to which
	 * the kernfs_node points.
	 */
	    if (kn.kf_kt
	    &&  kread((KA_T)kn.kf_kt, (char *)&kt, sizeof(kt)) == 0
	    &&  (ktnl = (int)kt.kt_namlen) > 0
	    &&  kt.kt_name)
	    {
		if (ktnl > (sizeof(ktnm) - 1))
		    ktnl = sizeof(ktnm) - 1;
		if (!kread((KA_T)kt.kt_name, ktnm, ktnl)) {
		    ktnm[ktnl] = 0;
		    ktnl = strlen(ktnm);
		    if (ktnl > (MAXPATHLEN - strlen(_PATH_KERNFS) - 2)) {
			ktnl = MAXPATHLEN - strlen(_PATH_KERNFS) - 2;
			ktnm[ktnl] = '\0';
		    }
		    (void) snpf(Namech, Namechl, "%s/%s", _PATH_KERNFS, ktnm);
		}
	    }
	/*
	 * If this is the /kern root directory, its name, inode number and
	 * size are fixed; otherwise, safely stat() the file to get the
	 * inode number and size.
	 */
	    if (v->v_type == VDIR && (v->v_flag & VROOT)) {
		(void) snpf(Namech, Namechl, "%s", _PATH_KERNFS);
		ksb.st_ino = (ino_t)2;
		ksb.st_size = DEV_BSIZE;
		ksbs = 1;
	    } else if (Namech[0] && statsafely(Namech, &ksb) == 0)
		ksbs = 1;
	    nty = KERNFSNODE;
	    break;
#endif	/* defined(HASKERNFS) */

	case VT_MFS:
	    if (!v->v_data
	    ||  kread((KA_T)v->v_data, (char *)&m, sizeof(m))) {
		(void) snpf(Namech, Namechl, "can't read mfsnode at: %s",
		    print_kptr((KA_T)v->v_data, (char *)NULL, 0));
		enter_nm(Namech);
		return;
	    }
	    nty = MFSNODE;
	    break;

#if	defined(HASMSDOSFS)
	case VT_MSDOSFS:
	    if (!v->v_data
	    ||  kread((KA_T)v->v_data, (char *)&d, sizeof(d))) {
		(void) snpf(Namech, Namechl, "can't read denode at: %s",
		    print_kptr((KA_T)v->v_data, (char *)NULL, 0));
		enter_nm(Namech);
		return;
	    }
	    nty = DOSNODE;
	    break;
#endif	/* defined(HASMSDOSFS) */

	case VT_NFS:
	    if (!v->v_data
	    ||  kread((KA_T)v->v_data, (char *)&n, sizeof(n))) {
		(void) snpf(Namech, Namechl, "can't read nfsnode at: %s",
		    print_kptr((KA_T)v->v_data, (char *)NULL, 0));
		enter_nm(Namech);
		return;
	    }

#if	defined(HASNFSVATTRP)
	    if (!n.n_vattr
	    ||  kread((KA_T)n.n_vattr, (char *)&nv, sizeof(nv))) {
		(void) snpf(Namech, Namechl, "can't read n_vattr at: %x",
		    print_kptr((KA_T)n.n_vattr, (char *)NULL, 0));
		enter_nm(Namech);
		return;
	    }
#endif	/* defined(HASNFSVATTRP) */

	    nty = NFSNODE;
	    break;

#if	defined(HASNULLFS)
	case VT_NULL:
	    if ((sc == 1) && vfs)
		nvfs = vfs;
	    if (!v->v_data
	    ||  kread((KA_T)v->v_data, (char *)&nu, sizeof(nu))) {
		(void) snpf(Namech, Namechl, "can't read null_node at: %s",
		    print_kptr((KA_T)v->v_data, (char *)NULL, 0));
		enter_nm(Namech);
		return;
	    }
	    if (!nu.null_lowervp) {
		(void) snpf(Namech, Namechl, "null_node overlays nothing");
		enter_nm(Namech);
		return;
	    }
	    va = (KA_T)nu.null_lowervp;
	    goto process_overlaid_node;
#endif	/* defined(HASNULLFS) */

#if	defined(HASPROCFS)
	case VT_PROCFS:
	    if (!v->v_data
	    ||  kread((KA_T)v->v_data, (char *)&p, sizeof(p))) {
		(void) snpf(Namech, Namechl, "can't read pfsnode at: %s",
		    print_kptr((KA_T)v->v_data, (char *)NULL, 0));
		enter_nm(Namech);
		return;
	    }
	    nty = PFSNODE;
	    break;
#endif	/* defined(HASPROCFS) */

#if    defined(HASPTYFS)
	case VT_PTYFS:
	    if (!v->v_data
	    ||  kread((KA_T)v->v_data, (char *)&pt, sizeof(pt))) {
		(void) snpf(Namech, Namechl, "can't read ptyfsnode at: %s",
		    print_kptr((KA_T)v->v_data, (char *)NULL, 0));
		enter_nm(Namech);
		return;
	    }
	    nty = PTYFSNODE;
	    break;
#endif	/* defined(HASPTYFS) */

#if	defined(HASEXT2FS)
	case VT_EXT2FS:
#endif	/* defined(HASEXT2FS) */

#if	defined(HASLFS)
	case VT_LFS:
#endif	/* defined(HASLFS) */

	case VT_UFS:
	    if (!v->v_data
	    ||  kread((KA_T)v->v_data, (char *)&i, sizeof(i))) {
		(void) snpf(Namech, Namechl, "can't read inode at: %s",
		    print_kptr((KA_T)v->v_data, (char *)NULL, 0));
		enter_nm(Namech);
		return;
	    }

#if	defined(HASEXT2FS)
	    if (v->v_tag == VT_EXT2FS) {
		nty = EXT2NODE;

# if	defined(HASI_E2FS_PTR)
		if (i.DINODE_U.e2fs_din
		&&  !kread((KA_T)i.DINODE_U.e2fs_din, (char *)&ed, sizeof(ed)))
		    edp = &ed;
# else	/* !defined(HASI_E2FS_PTR) */
#  if	HASEXT2FS<2
		edp = &i.DINODE_U.e2fs_din;
#  else	/* HASEXT2FS>=2 */
		edp = &i.i_e2din;
#  endif	/* HASEXT2FS>=2 */
# endif	/* defined(HASI_E2FS_PTR) */

	    } else
#endif	/* defined(HASEXT2FS) */

	    {
		nty = INODE;

#if	defined(HASI_FFS1)
		/*
		 * If there are multiple FFS's, read the relevant structures.
		 */
		    if (i.i_ump
		    &&  !kread((KA_T)i.i_ump, (char *)&um, sizeof(um))) {
			if (um.um_fstype == UFS1) {
			    ffs = 1;
			    if (i.DINODE_U.ffs1_din
			    &&  !kread((KA_T)i.DINODE_U.ffs1_din, (char *)&u1,
				       sizeof(u1)))
			    {
				u1s = 1;
			    }
			} else if (um.um_fstype == UFS2) {
			    ffs = 2;
			    if (i.DINODE_U.ffs2_din
			    &&  !kread((KA_T)i.DINODE_U.ffs2_din, (char *)&u2,
				       sizeof(u2)))
			    {
				u2s = 1;
			    }
			}
		    }
#endif	/* defined(HASI_FFS1) */

	    }

	    if ((lff = i.i_lockf)) {

	    /*
	     * Determine the lock state.
	     */
		lfp = lff;
		do {
		    if (kread((KA_T)lfp, (char *)&lf, sizeof(lf)))
			break;
		    lt = 0;
		    switch(lf.lf_flags & (F_FLOCK|F_POSIX)) {
		    case F_FLOCK:
			if (Cfp && (struct file *)lf.lf_id == Cfp)
			    lt = 1;
			break;
		    case F_POSIX:
			if ((KA_T)lf.lf_id == Kpa)
			    lt = 1;

#if	defined(HAS_LWP_H) && !defined(HAS_LF_LWP)
			else {

			    struct lwp lw;

			    if (!kread((KA_T)lf.lf_id, (char *)&lw, sizeof(lw))
			    &&  (KA_T)lw.l_proc == Kpa)
				lt = 1;
			}
#endif	/* defined(HAS_LWP_H) && !defined(HAS_LF_LWP) */

			break;
		    }
		    if (!lt)
			continue;
		    if (lf.lf_start == (off_t)0
		    &&  lf.lf_end == 0xffffffffffffffffLL)
			lt = 1;
		    else
			lt = 0;
		    if (lf.lf_type == F_RDLCK)
			Lf->lock = lt ? 'R' : 'r';
		    else if (lf.lf_type == F_WRLCK)
			Lf->lock = lt ? 'W' : 'w';
		    else if (lf.lf_type == (F_RDLCK | F_WRLCK))
			Lf->lock = 'u';
		    break;
		} while ((lfp = lf.lf_next) && lfp != lff);
	    }
	    break;
	default:
	    if (v->v_type == VBAD || v->v_type == VNON)
		break;
	    (void) snpf(Namech, Namechl, "unknown file system type: %d",
		v->v_tag);
	    enter_nm(Namech);
	    return;
	}
/*
 * Get device and type for printing.
 */
	type = v->v_type;
	switch (nty) {


#if	defined(HASMSDOSFS)
	case DOSNODE:
	    dev = d.de_dev;
	    devs = 1;
	    break;
#endif	/* defined(HASMSDOSFS) */

#if	defined(HASFDESCFS)
	case FDESCNODE:

# if	defined(HASFDLINK)
	    if (f.fd_link
	    &&  !kread((KA_T)f.fd_link, Namech, Namechl - 1)) {
		Namech[Namechl - 1] = '\0';
		break;
	    }
# endif	/* defined(HASFDLINK) */

# if	HASFDESCFS==1
	    if (f.fd_type == Fctty) {
		if (f_tty_s == 0)
		    f_tty_s = lkup_dev_tty(&f_tty_dev, &f_tty_ino);
		if (f_tty_s == 1) {
		    dev = DevDev;
		    rdev = f_tty_dev;
		    Lf->inode = f_tty_ino;
		    devs = Lf->inp_ty = rdevs = 1;
		}
	    }
	    break;
# endif	/* HASFDESCFS==1 */
#endif	/* defined(HASFDESCFS) */

#if	defined(HASEXT2FS)
	case EXT2NODE:

	    dev = i.i_dev;
	    devs = 1;
	    if ((type == VCHR) || (type == VBLK)) {

# if	defined(HASI_E2FS_PTR)
		if (edp) {
		    rdev = edp->e2di_rdev;
		    rdevs = 1;
		}
# else	/* !defined(HASI_E2FS_PTR) */
#  if	HASEXT2FS<2
		rdev = i.DINODE_U.e2fs_din.e2di_rdev;
#  else	/* HASEXT2FS>=2 */
		rdev = i.i_e2din.e2di_rdev;
#  endif	/* HASEXT2FS>=2 */
		rdevs = 1;
# endif	/* defined(HASI_E2FS_PTR) */

	    }
	    break;
#endif	/* defined(HASEXT2FS) */

	case INODE:
	    dev = i.i_dev;
	    devs = 1;
	    if ((type == VCHR) || (type == VBLK)) {

#if	defined(HASI_FFS)
		rdev = i.i_ffs_rdev;
		rdevs = 1;
#else	/* !defined(HASI_FFS) */
# if	defined(HASI_FFS1)
		if (ffs == 1) {
		    if (u1s) {
			rdev = u1.di_rdev;
			rdevs = 1;
		    }
		} else if (ffs == 2) {
		    if (u2s) {
			rdev = u2.di_rdev;
			rdevs = 1;
		    }
		}
# else	/* !defined(HASI_FFS1) */
		rdev = i.i_rdev;
		rdevs = 1;
# endif	/* defined(HASI_FFS1) */
#endif	/* defined(HASI_FFS) */

	    }
	    break;

#if	defined(HASKERNFS)
	case KERNFSNODE:
	    if (vfs) {

# if	defined(HASSTATVFS)
		dev = (dev_t)vfs->fsid.__fsid_val[0];
# else	/* !defined(HASSTATVFS) */
		dev = (dev_t)vfs->fsid.val[0];
# endif	/* defined(HASSTATVFS) */

		devs = 1;
	    }
	    break;
#endif	/* defined(HASKERNFS) */

#if	defined(HAS9660FS)
	case CDFSNODE:
	    if (iso_stat) {
		dev = iso_dev;
		devs = 1;
	    }
	    break;
#endif	/* defined(HAS9660FS) */

	case NFSNODE:
	    dev = NVATTR.va_fsid;
	    devs = 1;
	    break;

#if	defined(HASPTYFS)
	case PTYFSNODE:
	    if (v->v_un.vu_specinfo
	    &&  !kread((KA_T)v->v_un.vu_specinfo, (char *)&si, sizeof(si))) {
		rdev = si.si_rdev;
		rdevs = 1;
	    }
	    if (vfs) {

# if	defined(HASSTATVFS)
		dev = (dev_t)vfs->fsid.__fsid_val[0];
# else	/* !defined(HASSTATVFS) */
		dev = (dev_t)vfs->fsid.val[0];
# endif	/* defined(HASSTATVFS) */

		devs = 1;
	    }
	    break;
#endif	/* defined(HASPTYFS) */

	}
/*
 * Obtain the inode number.
 */
	switch (nty) {

#if	defined(HASMSDOSFS)
	case DOSNODE:
	    if (d.de_pmp && !kread((KA_T)d.de_pmp, (char *)&pm, sizeof(pm))) {
		dpb = (u_long)(pm.pm_BytesPerSec / sizeof(struct direntry));
		if (d.de_Attributes & ATTR_DIRECTORY) {
		    if (d.de_StartCluster == MSDOSFSROOT)
			nn = (INODETYPE)1;
		    else
			nn = (INODETYPE)(cntobn(&pm, d.de_StartCluster) * dpb);
		} else {
		    if (d.de_dirclust == MSDOSFSROOT)
			nn = (INODETYPE)(roottobn(&pm, 0) * dpb);
		    else
			nn = (INODETYPE)(cntobn(&pm, d.de_dirclust) * dpb);
		    nn += (INODETYPE)(d.de_diroffset / sizeof(struct direntry));
		}
		Lf->inode = nn;
		Lf->inp_ty = 1;
	    }
	    break;
#endif	/* defined(HASMSDOSFS) */

#if	defined(HASEXT2FS)
	case EXT2NODE:
#endif	/* defined(HASEXT2FS) */

	case INODE:
	    Lf->inode = (INODETYPE)i.i_number;
	    Lf->inp_ty = 1;
	    break;

#if	defined(HASKERNFS)
	case KERNFSNODE:
	    if (ksbs) {
		Lf->inode = (INODETYPE)ksb.st_ino;
		Lf->inp_ty = 1;
	    }
	    break;
#endif	/* defined(HASKERNFS) */

#if	defined(HAS9660FS)
	case CDFSNODE:
	    if (iso_stat) {
		Lf->inode = iso_ino;
		Lf->inp_ty = 1;
	    }
	    break;
#endif	/* defined(HAS9660FS) */

	case NFSNODE:
	    Lf->inode = (INODETYPE)NVATTR.va_fileid;
	    Lf->inp_ty = 1;
	    break;

#if	defined(HASPROCFS)
	case PFSNODE:
	    Lf->inode = (INODETYPE)p.pfs_fileno;
	    Lf->inp_ty = 1;
	    break;
#endif	/* defined(HASPROCFS) */

#if	defined(HASPTYFS)
	case PTYFSNODE:
	    if (pt.ptyfs_type == PTYFSptc) {
		if (pt.ptyfs_fileno > 0x3fffffff)
		    Lf->inode = (INODETYPE)(pt.ptyfs_fileno & 0x3fffffff);
		else
		    Lf->inode = (INODETYPE)(pt.ptyfs_fileno - 1);
	    } else
		Lf->inode = (INODETYPE)pt.ptyfs_fileno;
	    Lf->inp_ty = 1;
	    break;
#endif	/* defined(HASPTYFS) */

	}

/*
 * Obtain the file size.
 */
	if (Foffset)
	    Lf->off_def = 1;
	else {
	    switch (Ntype) {

#if	defined(HAS9660FS)
	    case N_CDFS:
		if (iso_stat) {
		    Lf->sz = (SZOFFTYPE)iso_sz;
		    Lf->sz_def = 1;
		}
		break;
#endif	/* defined(HAS9660FS) */

	    case N_FIFO:
		if (!Fsize)
		    Lf->off_def = 1;
		break;

#if	defined(HASKERNFS)
	    case N_KERN:
		if (ksbs) {
		    Lf->sz = (SZOFFTYPE)ksb.st_size;
		    Lf->sz_def = 1;
		}
		break;
#endif	/* defined(HASKERNFS) */

	    case N_NFS:
		if (nty == NFSNODE) {
		    Lf->sz = (SZOFFTYPE)NVATTR.va_size;
		    Lf->sz_def = 1;
		}
		break;

#if	defined(HASPROCFS)
	    case N_PROC:
		if (nty == PFSNODE) {
		    switch (p.pfs_type) {
		    case Proot:
		    case Pproc:
			Lf->sz = (SZOFFTYPE)DEV_BSIZE;
			Lf->sz_def = 1;
			break;
		    case Pcurproc:
			Lf->sz = (SZOFFTYPE)DEV_BSIZE;
			Lf->sz_def = 1;
			break;
		    case Pmem:
			(void) getmemsz(p.pfs_pid);
			break;
		    case Pregs:
			Lf->sz = (SZOFFTYPE)sizeof(struct reg);
			Lf->sz_def = 1;
			break;

# if	defined(FP_QSIZE)
		    case Pfpregs:
			Lf->sz = (SZOFFTYPE)sizeof(struct fpreg);
			Lf->sz_def = 1;
			break;
# endif	/* defined(FP_QSIZE) */

		    }
		}
		break;
#endif	/* defined(HASPROCFS) */

	    case N_REGLR:
		if (type == VREG || type == VDIR) {
		    switch (nty) {
		    case INODE:

#if	defined(HASI_FFS)
			
			Lf->sz = (SZOFFTYPE)i.i_ffs_size;
			Lf->sz_def = 1;
			break;
#else	/* !defined(HASI_FFS) */
# if	defined(HASI_FFS1)

			if (ffs == 1) {
			    if (u1s) {
				Lf->sz = (SZOFFTYPE)u1.di_size;
				Lf->sz_def = 1;
			    }
			} else if (ffs == 2) {
			    if (u2s) {
				Lf->sz = (SZOFFTYPE)u2.di_size;
				Lf->sz_def = 1;
			    }
			}
			break;
# else	/* !defined(HASI_FFS1) */
			Lf->sz = (SZOFFTYPE)i.i_size;
			Lf->sz_def = 1;
# endif	/* defined(HASI_FFS1) */
#endif	/* defined(HASI_FFS) */

			break;


#if	defined(HASMSDOSFS)
		    case DOSNODE:
			Lf->sz = (SZOFFTYPE)d.de_FileSize;
			Lf->sz_def = 1;
			break;
#endif	/* defined(HASMSDOSFS) */

		    case MFSNODE:
			Lf->sz = (SZOFFTYPE)m.mfs_size;
			Lf->sz_def = 1;
			break;

#if	defined(HASEXT2FS)
		    case EXT2NODE:
# if	defined(HASI_E2FS_PTR)
			if (edp) {
			    Lf->sz = (SZOFFTYPE)edp->e2di_size;
			    Lf->sz_def = 1;
			}
# else	/* !defined(HASI_E2FS_PTR) */
			Lf->sz = (SZOFFTYPE)i.i_e2fs_size;
			Lf->sz_def = 1;
# endif	/* defined(HASI_E2FS_PTR) */
			break;
#endif	/* defined(HASEXT2FS) */

		    }
		} else if ((type == VCHR || type == VBLK) && !Fsize)
		    Lf->off_def = 1;
		break;
	    }
	}
/*
 * Record the link count.
 */
	if (Fnlink) {
	    switch(Ntype) {

#if	defined(HAS9660FS)
	    case N_CDFS:
		if (iso_stat) {
		    Lf->nlink = iso_nlink;
		    Lf->nlink_def = 1;
		}
		break;
#endif	/* defined(HAS9660FS) */

#if	defined(HASKERNFS)
	    case N_KERN:
		if (ksbs) {
		    Lf->nlink = (long)ksb.st_nlink;
		    Lf->nlink_def = 1;
		}
		break;
#endif	/* defined(HASKERNFS) */

	    case N_NFS:
		if (nty == NFSNODE) {
		    Lf->nlink = (long)NVATTR.va_nlink;
		    Lf->nlink_def = 1;
		}
		break;
	    case N_REGLR:
		switch (nty) {
		case INODE:

#if	defined(HASEFFNLINK)
		    Lf->nlink = (long)i.HASEFFNLINK;
#else	/* !defined(HASEFFNLINK) */
# if	defined(HASI_FFS)
		    Lf->nlink = (long)i.i_ffs_nlink;
# else	/* !defined(HASI_FFS) */
#  if	defined(HASI_FFS1)
		    if (ffs == 1) {
			if (u1s)
			    Lf->nlink = (long)u1.di_nlink;
		    } else if (ffs == 2) {
			if (u2s)
			    Lf->nlink = (long)u2.di_nlink;
		    }
#  else	/* !defined(HASI_FFS1) */

		    Lf->nlink = (long)i.i_nlink;
#  endif	/* defined(HASI_FFS1) */
# endif	/* defined(HASI_FFS) */
#endif	/* defined(HASEFFNLINK) */

		    Lf->nlink_def = 1;
		    break;

#if	defined(HASMSDOSFS)
		case DOSNODE:
		    Lf->nlink = (long)d.de_refcnt;
		    Lf->nlink_def = 1;
		    break;
#endif	/* defined(HASMSDOSFS) */

#if	defined(HASEXT2FS)
		case EXT2NODE:
# if	defined(HASI_E2FS_PTR)
		    if (edp) {
			Lf->nlink = (long)edp->e2di_nlink;
			Lf->nlink_def = 1;
		    }
# else	/* !defined(HASI_E2FS_PTR) */
		    Lf->nlink = (long)i.i_e2fs_nlink;
		    Lf->nlink_def = 1;
# endif	/* defined(HASI_E2FS_PTR) */

		    break;
	
#endif	/* defined(HASEXT2FS) */
		
		}
		break;
	    }
	    if (Lf->nlink_def && Nlink && (Lf->nlink < Nlink))
		Lf->sf |= SELNLINK;
	}
/*
 * Record an NFS file selection.
 */
	if (Ntype == N_NFS && Fnfs)
	    Lf->sf |= SELNFS;

#if	defined(HASNULLFS)
/*
 * If there is a saved nullfs vfs pointer, propagate its device number.
 */
	if (nvfs) {

# if	defined(HASSTATVFS)
	    dev = nvfs->fsid.__fsid_val[0];
# else	/* !defined(HASSTATVFS) */
	    dev = nvfs->fsid.val[0];
# endif	/* defined(HASSTATVFS) */

	    devs = 1;
	}
#endif	/* defined(HASNULLFS) */

/*
 * Save the file system names.
 */
	if (vfs) {
	    Lf->fsdir = vfs->dir;
	    Lf->fsdev = vfs->fsname;
	}
/*
 * Save the device numbers and their states.
 *
 * Format the vnode type, and possibly the device name.
 */
	Lf->dev = dev;
	Lf->dev_def = devs;
	Lf->rdev = rdev;
	Lf->rdev_def = rdevs;
	switch (type) {
	case VNON:
	    ty ="VNON";
	    break;
	case VREG:
	    ty = "VREG";
	    break;
	case VDIR:
	    ty = "VDIR";
	    break;
	case VBLK:
	    ty = "VBLK";
	    Ntype = N_BLK;
	    break;
	case VCHR:
	    ty = "VCHR";
	    Ntype = N_CHR;
	    break;
	case VLNK:
	    ty = "VLNK";
	    break;

#if	defined(VSOCK)
	case VSOCK:
	    ty = "SOCK";
	    break;
#endif	/* defined(VSOCK) */

	case VBAD:
	    ty = "VBAD";
	    break;
	case VFIFO:
	    ty = "FIFO";
	    break;
	default:
	    (void) snpf(Lf->type, sizeof(Lf->type), "%04o", (type & 0xfff));
	    ty = NULL;
	}
	if (ty)
	    (void) snpf(Lf->type, sizeof(Lf->type), "%s", ty);
	Lf->ntype = Ntype;
/*
 * Handle some special cases:
 *
 * 	ioctl(fd, TIOCNOTTY) files;
 *	/kern files
 *	memory node files;
 *	/proc files;
 *	ptyfs files.
 */

	if (type == VBAD)
	    (void) snpf(Namech, Namechl, "(revoked)");
	else if (nty == MFSNODE) {
	    Lf->dev_def = Lf->rdev_def = 0;
	    (void) snpf(Namech, Namechl, "%#x", m.mfs_baseoff);
	    enter_dev_ch("memory");
	}

#if	defined(HASPROCFS)
	else if (nty == PFSNODE) {
	    Lf->dev_def= Lf->rdev_def = 0;
	    ty = NULL;
	    (void) snpf(Namech, Namechl, "/%s", HASPROCFS);
	    switch (p.pfs_type) {
	    case Proot:
		ty = "PDIR";
		break;
	    case Pcurproc:
		ep = endnm(&sz);
		(void) snpf(ep, sz, "/curproc");
		ty = "PCUR";
		break;
	    case Pproc:
		ep = endnm(&sz);
		(void) snpf(ep, sz, "/%d", p.pfs_pid);
		ty = "PDIR";
		break;
	    case Pfile:
		ep = endnm(&sz);
		(void) snpf(ep, sz, "/%d/file", p.pfs_pid);
		ty = "PFIL";
		break;
	    case Pmem:
		ep = endnm(&sz);
		(void) snpf(ep, sz, "/%d/mem", p.pfs_pid);
		ty = "PMEM";
		break;
	    case Pregs:
		ep = endnm(&sz);
		(void) snpf(ep, sz, "/%d/regs", p.pfs_pid);
		ty = "PREG";
		break;
	    case Pfpregs:
		ep = endnm(&sz);
		(void) snpf(ep, sz, "/%d/fpregs", p.pfs_pid);
		ty = "PFPR";
		break;
	    case Pctl:
		ep = endnm(&sz);
		(void) snpf(ep, sz, "/%d/ctl", p.pfs_pid);
		ty = "PCTL";
		break;
	    case Pstatus:
		ep = endnm(&sz);
		(void) snpf(ep, sz, "/%d/status", p.pfs_pid);
		ty = "PSTA";
		break;
	    case Pnote:
		ep = endnm(&sz);
		(void) snpf(ep, sz, "/%d/note", p.pfs_pid);
		ty = "PNTF";
		break;
	    case Pnotepg:
		ep = endnm(&sz);
		(void) snpf(ep, sz, "/%d/notepg", p.pfs_pid);
		ty = "PGID";
		break;

# if	defined(Pfd)
	    case Pfd:
		ep = endnm(&sz);
		(void) snpf(ep, sz, "/%d/fd", p.pfs_pid);
		ty = "PFD";
		break;
# endif	/* defined(Pfd) */

# if	defined(Pmap)
	    case Pmap:
		ep = endnm(&sz);
		(void) snpf(ep, sz, "/%d/map", p.pfs_pid);
		ty = "PMAP";
		break;
# endif	/* defined(Pmap) */

# if	defined(Pmaps)
	    case Pmaps:
		ep = endnm(&sz);
		(void) snpf(ep, sz, "/%d/maps", p.pfs_pid);
		ty = "PMPS";
		break;
# endif	/* defined(Pmaps) */

	    }
	    if (ty)
		(void) snpf(Lf->type, sizeof(Lf->type), ty);
	}
#endif	/* defined(HASPROCFS) */

#if	defined(HASPTYFS)
	else if (nty == PTYFSNODE) {
	    (void) snpf(Namech, Namechl, "%s", Lf->fsdir);
	    Lf->nlink = 1;
	    Lf->nlink_def = 1;
	    switch (pt.ptyfs_type) {
	    case PTYFSpts:
		ep = endnm(&sz);
		(void) snpf(ep, sz, "/%lu", (unsigned long)pt.ptyfs_pty);
		break;
	    case PTYFSptc:
		ep = endnm(&sz);
		(void) snpf(ep, sz, "/%lu (master)",
		    (unsigned long)pt.ptyfs_pty);
		break;
	    case PTYFSroot:
		Lf->sz = 512;
		Lf->sz_def = 1;
		break;
	    }
	    if (ty)
		(void) snpf(Lf->type, sizeof(Lf->type), ty);
	}
#endif	/* defined(HASPTYFS) */

#if	defined(HASBLKDEV)
/*
 * If this is a VBLK file and it's missing an inode number, try to
 * supply one.
 */
	if ((Lf->inp_ty == 0) && (type == VBLK))
	    find_bl_ino();
#endif	/* defined(HASBLKDEV) */

/*
 * If this is a VCHR file and it's missing an inode number, try to
 * supply one.
 */
	if ((Lf->inp_ty == 0) && (type == VCHR))
	    find_ch_ino();
/*
 * Test for specified file.
 */

#if	defined(HASPROCFS)
	if (Ntype == N_PROC) {
	    if (Procsrch) {
		Procfind = 1;
		Lf->sf |= SELNM;
	    } else if (nty == PFSNODE) {
		for (pfi = Procfsid; pfi; pfi = pfi->next) {
		    if ((pfi->pid && pfi->pid == p.pfs_pid)
		    
# if	defined(HASPINODEN)
		    ||  ((Lf->inp_ty == 1) && (pfi->inode == Lf->inode))
# endif	/* defined(HASPINODEN) */

		    ) {
			pfi->f = 1;
			if (Namech[0] && pfi->nm)
			    (void) snpf(Namech, Namechl, "%s", pfi->nm);
			Lf->sf |= SELNM;
			break;
		    }
		}
	    }
	} else
#endif	/* defined(HASPROCFS) */

	{
	    if (Namech[0]) {
		enter_nm(Namech);
		ns = 1;
	    } else
		ns = 0;
	    if (Sfile && is_file_named((char *)NULL,
				       ((type == VCHR) || (type == VBLK)) ? 1
									  : 0))
	    {
		Lf->sf |= SELNM;
	    }
	    if (ns)
		Namech[0] = '\0';
	}
/*
 * Enter name characters.
 */
	if (Namech[0])
	    enter_nm(Namech);
}


#if	defined(HAS_SYS_PIPEH)
/*
 * process_pipe() - process a file structure whose type is DTYPE_PIPE
 */

void
process_pipe(pa)
	KA_T pa;			/* pipe structure kernel address */
{
	char *ep;
	struct pipe p;
	size_t sz;

	if (!pa || kread((KA_T)pa, (char *)&p, sizeof(p))) {
	    (void) snpf(Namech, Namechl,
		"can't read DTYPE_PIPE pipe struct: %#s",
		print_kptr(pa, (char *)NULL, 0));
	    enter_nm(Namech);
	    return;
	}
	(void) snpf(Lf->type, sizeof(Lf->type), "PIPE");
	enter_dev_ch(print_kptr(pa, (char *)NULL, 0));
	if (Foffset)
	    Lf->off_def = 1;
	else {
	    Lf->sz = (SZOFFTYPE)p.pipe_buffer.size;
	    Lf->sz_def = 1;
	}
	if (p.pipe_peer)
	    (void) snpf(Namech, Namechl, "->%s",
		print_kptr((KA_T)p.pipe_peer, (char *)NULL, 0));
	else
	    Namech[0] = '\0';
	if (p.pipe_buffer.cnt) {
	    ep = endnm(&sz);
	    (void) snpf(ep, sz, ", cnt=%d", p.pipe_buffer.cnt);
	}
	if (p.pipe_buffer.in) {
	    ep = endnm(&sz);
	    (void) snpf(ep, sz, ", in=%d", p.pipe_buffer.in);
	}
	if (p.pipe_buffer.out) {
	    ep = endnm(&sz);
	    (void) snpf(ep, sz, ", out=%d", p.pipe_buffer.out);
	}
/*
 * Enter name characters.
 */
	if (Namech[0])
	    enter_nm(Namech);
}
#endif	/* defined(HAS_SYS_PIPEH) */
