/*
 * dnode.c - SunOS (Solaris 1.x and 2.x) node reading 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";
static char *rcsid = "$Id: dnode.c,v 1.34 96/03/08 14:04:46 abe Exp $";
#endif


#include "lsof.h"


_PROTOTYPE(static char *finddev,(dev_t *dev, int stream));
_PROTOTYPE(static void read_mi,(struct stdata *s, dev_t *dev, caddr_t so, int *so_st));

#if	defined(X_DOOR_OPS)
_PROTOTYPE(static int read_ndn,(caddr_t na, caddr_t da, struct door_node *d));
#endif	/* defined(X_DOOR_OPS) */

_PROTOTYPE(static int read_nfn,(caddr_t na, caddr_t fa, struct fifonode *f));
_PROTOTYPE(static int read_nhn,(caddr_t na, caddr_t ha, struct hsnode *h));
_PROTOTYPE(static int read_nin,(caddr_t na, caddr_t ia, struct inode *i));
_PROTOTYPE(static int read_npn,(caddr_t na, caddr_t pa, struct pcnode *p));
_PROTOTYPE(static int read_nrn,(caddr_t na, caddr_t ra, struct rnode *r));
_PROTOTYPE(static int read_nsn,(caddr_t na, caddr_t sa, struct snode *s));
_PROTOTYPE(static int read_ntn,(caddr_t na, caddr_t ta, struct tmpnode *t));
_PROTOTYPE(static int read_nvn,(caddr_t na, caddr_t va, struct vnode *v));
_PROTOTYPE(static int vop2ty,(struct vnode *vp));

#if	defined(HASPROCFS)
_PROTOTYPE(static int read_npi,(caddr_t na, struct vnode *v, struct pid *pids));
#endif	/* defined(HASPROCFS) */

#if	defined(solaris)
_PROTOTYPE(static void ent_fa,(caddr_t *a1, caddr_t *a2, char *d));
_PROTOTYPE(static int is_socket,(struct vnode *v));
_PROTOTYPE(static char isvlocked,(struct vnode *va));
_PROTOTYPE(static int read_cni,(struct snode *s, struct vnode *rv,
	struct vnode *v, struct snode *rs, struct dev_info *di, char *din,
	int dinl));
_PROTOTYPE(static int read_ncn,(caddr_t na, caddr_t ca, struct cnode *cn));
_PROTOTYPE(static int read_nln,(caddr_t na, caddr_t la, struct lnode *ln));
_PROTOTYPE(static int read_nnn,(caddr_t na, caddr_t nna, struct namenode *n));
_PROTOTYPE(static void savesockmod,(struct so_so *so, struct so_so *sop, int *so_st));
#endif	/* defined(solaris) */


#if	defined(solaris)
/*
 * ent_fa() - enter fattach addresses in NAME column addition
 */

static void
ent_fa(a1, a2, d)
	caddr_t *a1;			/* first fattach address (NULL OK) */
	caddr_t *a2;			/* second fattach address */
	char *d;			/* direction ("->" or "<-") */
{
	char buf[64], *cp;
	MALLOC_S len;

	if (Lf->nma)
		return;
	if (!a1)
		(void) sprintf(buf, "(FA:%s%#x)", d, *a2);
	else
		(void) sprintf(buf, " (FA:%#x%s%#x)", *a1, d, *a2);
	len = strlen(buf) + 1;
	if ((cp = (char *)malloc(len)) == NULL) {
		(void) fprintf(stderr,
			"%s: no space for fattach addresses at PID %d, FD %s\n",
			Pn, Lp->pid, Lf->fd);
		exit(1);
	}
	(void) strcpy(cp, buf);
	Lf->nma = cp;
}


/*
 * is_socket() - is the stream a socket?
 */

static int
is_socket(v)
	struct vnode *v;		/* vnode pointer */
{
	struct clone *c;

	if (!v->v_stream)
		return(0);
	for (c = Clone; c; c = c->next) {
		if (c->n && major(v->v_rdev) == minor(c->rdev)) {
			process_socket(v->v_stream, &c->nm[c->n]);
				return(1);
		}
	}
	return(0);
}


/*
 * isvlocked() - is a vnode locked
 */

static char
isvlocked(va)
	struct vnode *va;		/* local vnode address */
{

# if	solaris<20500
	struct filock f;
# endif	/* solaris<20500 */

	int l;

# if	solaris>=20300
	struct lock_descriptor ld;
#  if	solaris<20500
#define	LOCK_FLAGS	ld.flags
#define	LOCK_TYPE	ld.type
#  else	/* solaris>=20500 */
#define	LOCK_FLAGS	ld.l_state
#define	LOCK_TYPE	ld.l_type
#  endif	/* solaris<20500 */
# endif	/* solaris>=20300 */

	if (va->v_filocks == NULL)
		return(' ');

# if	solaris<20500
#  if	solaris>20300 || (solaris==20300 && defined(P101318) && P101318>=45)
	if (Ntype == N_NFS)
#  endif	/* solaris>20300 || (solaris==20300 && defined(P101318) && P101318>=45) */

	{
	    if (kread((KA_T)va->v_filocks, (char *)&f, sizeof(f)))
		return(' ');
	    if (f.set.l_whence == 0 && f.set.l_start == 0 && f.set.l_len == 0)
		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(l ? 'U' : 'u');
	    default:
		return('N');
	    }
	}
# endif	/* solaris<20500 */

# if	solaris>=20300
	if (kread((KA_T)va->v_filocks, (char *)&ld, sizeof(ld))
	||  !(LOCK_FLAGS & ACTIVE_LOCK))
		return(' ');
	switch (LOCK_TYPE) {
	case F_RDLCK:
	    return('R');
	case F_WRLCK:
	    return('W');
	case (F_RDLCK | F_WRLCK):
	    return('U');
	default:
	    return('L');
	}
# endif	/* solaris>=20500 */

}
#endif	/* defined(solaris) */


/*
 * finddev() - look up device by device number
 */

static char *
finddev(dev, stream)
	dev_t *dev;			/* device */
	int stream;			/* stream if 1 */
{
	struct clone *c;
	struct l_dev *dp;

#if	defined(solaris)
	struct pseudo *p;
#endif	/* defined(solaris) */

	if (!Sdev)
		readdev();
/*
 * Search for clone.
 */
	if (stream && Clone) {
		for (c = Clone; c; c = c->next) {
			if (major(*dev) == minor(c->rdev))
				return(c->nm);
		}
	}
/*
 * Search device table for match.
 */
	if ((dp = lkupdev(dev, 0)) != (struct l_dev *)NULL)
		return(dp->name);

#if	defined(solaris)
/*
 * Search for pseudo device match on major device only.
 */
	for (p = Pseudo; p; p = p->next) {
		if (major(*dev) == major(p->rdev))
			return(p->nm);
	}
#endif	/* defined(solaris) */

	return(NULL);
}


/*
 * process_node() - process vnode
 */

void
process_node(va)
	caddr_t va;			/* vnode kernel space address */
{
	char dev_ch[32];
	dev_t dev;
	unsigned char dev_def = 1;
	struct fifonode f;
	struct hsnode h;
	struct inode i;
	struct vfs kv;
	struct vfs *la = NULL;
	int ni = 0;
	struct pcnode pc;
	struct rnode r;
	struct vnode *realvp = NULL;
	struct vnode rv;
	int rvs = 0;
	struct snode s;
	int so_st = 0;
	struct tmpnode t;
	char *tn;
	char *ty;
	enum vtype type;
	int unix_sock = 0;
	static struct vnode *v = (struct vnode *)NULL;
	struct l_vfs *vfs;
	struct stdata *vs;
	int vty, vty_tmp;

#if	defined(solaris)
	struct cnode cn;
	struct dev_info di;
	char din[DINAMEL];
	caddr_t fafr = NULL;
	caddr_t fato = NULL;
	struct vfs favfs;
	struct filock fi;
	struct lnode lo;
	struct namenode nn;
	int nns = 0;
	struct pcfs pcfs;
	struct snode rs;
	struct so_so soso;

# if	defined(HASPROCFS)
	struct procfsid *pfi;
	struct pid pids;
# endif	/* defined(HASPROCFS) */
#else	/* !defined(solaris) */
	long inum;
	struct lock_list ll;
	int soso;
#endif	/* defined(solaris) */

#if	defined(HAS_AFS)
	struct afsnode an;
#endif	/* defined(HAS_AFS) */

#if	defined(X_DOOR_OPS)
	caddr_t da = NULL;
	struct door_node dn;
#endif	/* defined(X_DOOR_OPS) */

/*
 * Read the vnode.
 */
	if ( ! va) {
		enter_nm("no vnode address");
		return;
	}
	if (!v) {

	/*
	 * Allocate space for the vnode or AFS vcache structure.
	 */

#if	defined(HAS_AFS)
		v = alloc_vcache();
#else	/* !defined(HAS_AFS) */
		v = (struct vnode *)malloc(sizeof(struct vnode));
#endif	/* defined(HAS_AFS) */

		if (!v) {
			(void) fprintf(stderr, "%s: can't allocate %s space\n",
				Pn,

#if	defined(HAS_AFS)
				"vcache"
#else	/* !defined(HAS_AFS) */
				"vnode"
#endif	/* defined(HAS_AFS) */

				);
			exit(1);
		}
	}
	if (readvnode((caddr_t)va, v)) {
                enter_nm(Namech);
                return;
        }

#if	defined(HASNCACHE)
	Lf->na = (KA_T)va;
#endif	/* defined(HASNCACHE) */

	vs = v->v_stream;

#if	defined(solaris)
/*
 * Check for a Solaris socket.
 */
	if (is_socket(v))
		return;
/*
 * Obtain the Solaris virtual file system structure.
 */
	if (v->v_vfsp && kread((KA_T)v->v_vfsp, (char *)&kv, sizeof(kv))) {

vfs_read_error:

		(void) sprintf(Namech, "vnode at %#x: can't read vfs: %#x",
			va, v->v_vfsp);
		enter_nm(Namech);
		return;
	}
/*
 * Derive the virtual file system structure's device number from
 * its file system ID for NFS and High Sierra file systems.
 */
	if (kv.vfs_fstype > 0 && kv.vfs_fstype <= Fsinfomax) {
		if (strcmp(Fsinfo[kv.vfs_fstype - 1], "nfs") == 0
		||  strcmp(Fsinfo[kv.vfs_fstype - 1], "nfs3") == 0
		||  strcmp(Fsinfo[kv.vfs_fstype - 1], "hsfs") == 0)
			kv.vfs_dev = (dev_t)kv.vfs_fsid.val[0];
	}
/*
 * Determine the Solaris vnode type.
 */
	if ((Ntype = vop2ty(v)) < 0)
		Ntype = N_REGLR;
	vty = Ntype;
	if (v->v_type == VFIFO)
			Ntype = N_FIFO;
	else if (vs) {
		Ntype = vty = N_STREAM;
		Lf->is_stream = 1;
	}
/*
 * See if another Solaris node has fattach'ed to this node.
 * Enter the node addresses in the NAME column addition if one has.
 */
	if (v->v_vfsmountedhere
	&&  kread((KA_T)v->v_vfsmountedhere, (char *)&favfs, sizeof(favfs)) == 0
	&&  favfs.vfs_fstype > 0 && favfs.vfs_fstype <= Fsinfomax
	&&  strcmp(Fsinfo[favfs.vfs_fstype - 1], "namefs") == 0
	&&  favfs.vfs_data)
		(void) ent_fa(&va, &favfs.vfs_data, "<-");
/*
 * See if this Solaris node has been fattach'ed to another node.
 * If it has, read the namenode, and enter the node addresses in
 * the NAME column addition.
 *
 * See if it's covering a socket as well and process accordingly.
 */
	if (vty == N_NM) {
	    if (read_nnn(va, v->v_data, &nn))
		return;
	    nns = 1;
	    if (nn.nm_mountpt)

# if	solaris>=20500
		ent_fa((Ntype == N_FIFO || v->v_type == VDOOR) ? NULL : &va,
			(caddr_t *)&nn.nm_mountpt, "->");
# else	/* solaris<20500 */
		ent_fa((Ntype == N_FIFO) ? NULL : &va,
			(caddr_t *)&nn.nm_mountpt, "->");
# endif	/* solaris>=20500 */

	    if (Ntype != N_FIFO
	    &&  nn.nm_filevp
	    &&  kread((KA_T)nn.nm_filevp, (char *)&rv, sizeof(rv)) == 0) {
		rvs = 1;
		if (is_socket(&rv))
			return;
	    }
	}
/*
 * See if this Solaris node is served by spec_vnodeops.
 */
	if (Nl[X_SPEC_OPS].n_value
	&&  Nl[X_SPEC_OPS].n_value == (unsigned long)v->v_op) 
		Ntype = N_SPEC;

/*
 * Determine the Solaris lock state.
 */
	Lf->lock = isvlocked(v);
/*
 * Establish the Solaris local virtual file system structure.
 */
	if (v->v_vfsp == NULL)
		vfs = NULL;
	else if ((vfs = readvfs(v->v_vfsp, &kv, v)) == NULL)
		goto vfs_read_error;
#else	/* !defined(solaris) */

/*
 * Determine the non-Solaris vnode type.
 */
	if ((Ntype = vop2ty(v)) < 0) {
		if (v->v_type == VFIFO)
			Ntype = N_FIFO;
		else if (v->v_type == VCHR && !v->v_vfsp && vs) {
			Ntype = N_STREAM;
			Lf->is_stream = 1;
		} else
			Ntype = N_REGLR;
	}
/*
 * See if this non-Solaris node is served by _spec_vnodeops.
 */
	vty = Ntype;
	if (Nl[X_SPEC_OPS].n_value
	&&  (unsigned long)v->v_op == Nl[X_SPEC_OPS].n_value)
		Ntype = N_SPEC;
/*
 * Read the virtual file system structures for High Sierra and PC file
 * system vnodes to get major/minor device numbers from word 0 of the
 * file system ID array.
 */
	if (Ntype == N_HSFS || Ntype == N_PCFS) {
		if (!v->v_vfsp
		||  kread((KA_T)v->v_vfsp, (char *)&kv, sizeof(kv))) {
			(void) sprintf(Namech,
				"vnode at %#x: can't read vfs: %#x",
				va, v->v_vfsp);
			enter_nm(Namech);
			return;
		}
		la = &kv;
	}
/*
 * Determine the non-Solaris lock type.
 */
	if (v->v_shlockc || v->v_exlockc) {
		if (v->v_shlockc && v->v_exlockc)
			Lf->lock = 'u';
		else if (v->v_shlockc)
			Lf->lock = 'R';
		else
			Lf->lock = 'W';
	}
	else if (v->v_filocks
	       &&  kread((KA_T)v->v_filocks, (char *)&ll, sizeof(ll)) == 0
	       &&  (ll.exclusive || ll.shared))
	{
		if (ll.exclusive && ll.shared)
			Lf->lock = 'u';
		else if (ll.shared)
			Lf->lock = 'R';
		else
			Lf->lock = 'W';
	}
/*
 * Establish the local virtual file system structure.
 */
	if (v->v_vfsp == NULL)
		vfs = NULL;
	else if ((vfs = readvfs(v->v_vfsp, la, v)) == NULL) {
                (void) sprintf(Namech, "vnode at %#x: can't read vfs: %#x",
			va, v->v_vfsp);
                enter_nm(Namech);
		return;
	}
#endif	/* defined(solaris) */

/*
 * Read the afsnode, cnode, door_node, fifonode, lnode, inode, pcnode, rnode,
 * snode * or tmpnode.
 */
	switch (Ntype) {
	case N_SPEC:
	
	/*
	 * A N_SPEC node is node that resides in in an underlying file system
	 * type -- e.g. NFS, HSFS.  Its vnode points to an snode.  Subsequent
	 * node structures are implied by the underlying node type.
	 */
		if (read_nsn(va, v->v_data, &s))
			return;
		realvp = s.s_realvp;

#if	defined(solaris)
		if (!realvp && s.s_commonvp) {
		    if (read_cni(&s, &rv, v, &rs, &di, din, sizeof(din))
		    == 1)
			return;
		    if (!rv.v_stream) {
			if (din[0]) {
			    (void) sprintf(Namech, "COMMON: %s", din);
			    Lf->is_com = 1;
			}
			ni = 1;
			break;
		    }
		}
#endif	/* defined(solaris) */

		if (!realvp) {
		    ni = 1;

		/*
		 * If the snode lacks a real vnode (and also lacks a
		 * Solaris common vnode), it's original type is N_STREAM,
		 * and it has a stream pointer, get the module names.
		 */
		    if (vty == N_STREAM && vs) {
			(void) strcpy(Lf->iproto, "STR");
			read_mi(vs, (dev_t *)&s.s_dev, (caddr_t)&soso, &so_st);
			vs = NULL;
		    }
		}
		break;

#if	defined(HAS_AFS)
	case N_AFS:
		if (readafsnode(va, v, &an))
			return;
		break;
#endif	/* defined(HAS_AFS) */

#if	defined(solaris)
	case N_CACHE:
		if (read_ncn(va, v->v_data, &cn))
			return;
		break;
#endif	/* defined(solaris) */

#if	defined(X_DOOR_OPS)
	case N_DOOR:
		if (read_ndn(va, v->v_data, &dn))
			return;
		da = va;
		break;
#endif	defined(X_DOOR_OPS)

	case N_NFS:
		if (read_nrn(va, v->v_data, &r))
			return;
		break;

#if	defined(solaris)
	case N_NM:
		if (nns)
			realvp = nn.nm_filevp;
		break;
#endif	/* defined(solaris) */

	case N_FIFO:

#if	defined(solaris)
	/*
	 * Solaris FIFO vnodes are usually linked to a fifonode.  One
	 * exception is a FIFO vnode served by nm_vnodeops; it is linked
	 * to a namenode, and the namenode points to the fifonode.
	 *
	 * Non-pipe fifonodes are linked to a vnode thorough fn_realvp.
	 */
		if (vty == N_NM && nns) {
		    if (nn.nm_filevp) {
			if (read_nfn(va, (caddr_t)nn.nm_filevp, &f))
			    return;
			realvp = NULL;
			vty = N_FIFO;
		    } else {
			(void) sprintf(Namech,
			    "FIFO namenode at %#x: no fifonode pointer",
			    v->v_data);
			return;
		    }
		} else {
		    if (read_nfn(va, v->v_data, &f))
			return;
		    realvp = f.fn_realvp;
		}
		if (!realvp) {
			Lf->inode = (unsigned long)f.fn_ino;
			Lf->inp_ty = 1;
			(void) sprintf(dev_ch, "0x%08x", v->v_data);
			enter_dev_ch(dev_ch);
			if (f.fn_flag & ISPIPE)
				(void) strcpy(Namech, "PIPE");

# if	solaris<20500
			if (f.fn_mate)
				(void) sprintf(endnm(), "->0x%08x", f.fn_mate);
# else	/* solaris>=20500 */
			if (f.fn_dest)
				(void) sprintf(endnm(), "->0x%08x", f.fn_dest);
# endif	/* solaris<20500 */
			break;
		}
#else	/* !defined(solaris) */
	/*
	 * A non-Solaris FIFO 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 (read_nfn(va, v->v_data, &f))
		    return;
		if ((realvp = f.fn_snode.s_realvp) == NULL) {
		    (void) sprintf(Namech,
			"fifonode at %#x has no successor", v->v_data);
		    enter_nm(Namech);
		    return;
		}
#endif	/* defined(solaris) */
		
		break;

	case N_HSFS:
		if (read_nhn(va, v->v_data, &h))
		    return;
		break;

#if	defined(solaris)
	case N_LOFS:
		do {
		    if (read_nln(va, v->v_data, &lo))
			return;
		    if ((realvp = lo.lo_vp) == (struct vnode *)NULL) {
			(void) sprintf(Namech, "lnode at %#x: no real vnode",
			    v->v_data);
			return;
		    }
		    if (read_nvn(v->v_data, (caddr_t)realvp, v))
			return;
		    vty_tmp = vop2ty(v);
		} while (vty_tmp == N_LOFS);
		break;
#endif	/* defined(solaris) */
		
	case N_PCFS:
		if (read_npn(va, v->v_data, &pc))
		    return;
		break;

#if	defined(HASPROCFS)
	case N_PROC:
		ni = 1;
		if (read_npi(va, v, &pids))
		    return;
		break;
#endif	/* defined(HASPROCFS) */

	case N_TMP:
		if (read_ntn(va, v->v_data, &t))
		    return;
		break;
	case N_STREAM:
		if (read_nsn(va, v->v_data, &s))
			return;
		if (vs) {
			(void) strcpy(Lf->iproto, "STR");
			read_mi(vs, (dev_t *)&s.s_dev, (caddr_t)&soso, &so_st);
			vs = NULL;
		}
		break;
	case N_REGLR:
	default:
		if (read_nin(va, v->v_data, &i))
		    return;
	}
/*
 * If the node has a real vnode pointer, follow it.
 */
	if (realvp) {
		if (rvs)
			*v = rv;
		else if (read_nvn(v->v_data, (caddr_t)realvp, v))
			return;
	/*
	 * If the original vnode type is N_STREAM, and if there is
	 * a stream pointer, get the module names.
	 */
		if (vty == N_STREAM && vs) {
			(void) strcpy(Lf->iproto, "STR");
			read_mi(vs, (dev_t *)&s.s_dev, (caddr_t)&soso, &so_st);
			vs = NULL;
		}
	/*
	 * Get the real vnode's type.
	 */
		if ((vty = vop2ty(v)) < 0) {

#if	defined(solaris)
			if (Ntype != N_FIFO && vs)
#else	/* !defined(solaris) */
			if (v->v_type == VCHR && !v->v_vfsp && v->v_stream)
#endif	/* defined(solaris) */

				vty = N_STREAM;
			else
				vty = N_REGLR;
		}
		if (Ntype == N_NM || Ntype == N_AFS)
			Ntype = vty;
	/*
	 * Base further processing on the "real" vnode.
	 */
		switch (vty) {

#if	defined(HAS_AFS)
		case N_AFS:
			if (readafsnode(va, v, &an))
				return;
			break;
#endif	/* defined(HAS_AFS) */

	
#if	defined(solaris)
		case N_CACHE:
			if (read_ncn(va, v->v_data, &cn))
				return;
			break;
#endif	/* defined(solaris) */

#if	defined(X_DOOR_OPS)
		case N_DOOR:
			if (read_ndn(va, v->v_data, &dn))
				return;
			da = va;
			break;
#endif	defined(X_DOOR_OPS)
	
		case N_HSFS:
			if (read_nhn(va, v->v_data, &h))
				return;
			break;
		case N_NFS:
			if (read_nrn(va, v->v_data, &r))
				return;
			break;

#if	defined(solaris)
		case N_NM:
			if (read_nnn(va, v->v_data, &nn))
				return;
			nns = 1;
			break;
#endif	/* defined(solaris) */

		case N_PCFS:
			if (read_npn(va, v->v_data, &pc))
				return;
			break;
		case N_STREAM:
			if (vs) {
				(void) strcpy(Lf->iproto, "STR");
				read_mi(vs, (dev_t *)&s.s_dev, (caddr_t)&soso,
				    &so_st);
				vs = NULL;
			}
			break;
		case N_TMP:
			if (read_ntn(va, v->v_data, &t))
				return;
			break;
		case N_REGLR:
		default:
			if (read_nin(va, v->v_data, &i))
				return;
			ni = 0;
		}

#if	defined(solaris)
	/*
	 * If this is a Solaris loopback node, use the "real" node type.
	 */
		if (Ntype == N_LOFS)
			Ntype = vty;
#endif	/* defined(solaris) */

	}
/*
 * Get device and type for printing.
 */
	switch (Ntype == N_FIFO ? vty : Ntype) {

#if	defined(HAS_AFS)
	case N_AFS:
		dev = an.dev;
		break;
#endif	/* defined(HAS_AFS) */

#if	defined(solaris)
	case N_CACHE:
	case N_HSFS:
	case N_PCFS:
		dev = kv.vfs_dev;
#else	/* !defined(solaris) */
	case N_HSFS:
	case N_PCFS:
		dev = kv.vfs_fsid.val[0] & 0xffff;
#endif	/* defined(solaris) */

		break;

#if	defined(X_DOOR_OPS)
	case N_DOOR:
		if (da) {
			(void) sprintf(dev_ch, "0x%08x", da);
			enter_dev_ch(dev_ch);
		}
		break;
#endif	/* defined(X_DOOR_OPS) */

	case N_NFS:
		dev = r.r_attr.va_fsid;
		break;

#if	defined(solaris)
	case N_NM:
		enter_dev_ch("    NMFS");
		break;
#endif	/* defined(solaris) */

#if	defined(HASPROCFS)
	case N_PROC:
		dev = kv.vfs_dev;
		break;
#endif	/* defined(HASPROCFS) */

	case N_SPEC:

#if	defined(solaris)
		if (((Ntype = vty) == N_STREAM) && so_st) {
			if (Funix)
				Lf->sf |= SELUNX;
			unix_sock = 1;
			if (soso.lux_dev.addr.tu_addr.ino)
			    dev = soso.lux_dev.addr.tu_addr.dev;
			else {
			    int dc, dl, dr;

# if	solaris<20400
			    dl = (soso.lux_dev.addr.tu_addr.dev >> 16) & 0xffff;
			    dr = (soso.rux_dev.addr.tu_addr.dev >> 16) & 0xffff;
# else	/* solaris>=20400 */
			    dl = soso.lux_dev.addr.tu_addr.dev & 0xffff;
			    dr = soso.rux_dev.addr.tu_addr.dev & 0xffff;
# endif	/* solaris<20400 */

			    dc = (dl << 16) | dr;
			    (void) sprintf(dev_ch, "0x%08x", dc);
			    enter_dev_ch(dev_ch);
			    dev_def = 0;
			}
		} else
			dev = s.s_dev;
#else	/* !defined(solaris) */
		Ntype = vty;
		dev = s.s_dev;
#endif	/* defined(solaris) */

		break;
	case N_STREAM:
		dev = s.s_dev;
		break;
	case N_TMP:
		dev = t.tn_attr.va_fsid;
		break;
	default:
		dev = (v->v_type == VCHR || v->v_type == VBLK || ni) ? v->v_rdev
								     : i.i_dev;
	}
	type = v->v_type;
	if (vfs && vfs->dir == NULL) {
		(void) completevfs(vfs, &dev);

#if	defined(HAS_AFS)
		if (vfs->dir && (Ntype == N_AFS || vty == N_AFS) && !AFSVfsp)
			AFSVfsp = v->v_vfsp;
#endif	/* defined(HAS_AFS) */

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

#if	defined(HAS_AFS)
	case N_AFS:
		if (an.ino_st) {
			Lf->inode = an.inode;
			Lf->inp_ty = 1;
		}
		break;
#endif	/* defined(HAS_AFS) */

#if	defined(solaris)
	case N_CACHE:
		Lf->inode = (unsigned long)cn.c_fileno;
		Lf->inp_ty = 1;
		break;
#endif	/* defined(solaris) */

	case N_HSFS:

#if	defined(solaris)
		Lf->inode = (unsigned long)h.hs_nodeid;
#else	/* !defined(solaris) */
		Lf->inode = (unsigned long)h.hs_dirent.ext_lbn;
#endif	/* defined(solaris) */

		Lf->inp_ty = 1;
		break;

	case N_NFS:
		Lf->inode = (unsigned long)r.r_attr.va_nodeid;
		Lf->inp_ty = 1;
		break;

#if	defined(solaris)
	case N_NM:
		Lf->inode = (unsigned long)nn.nm_vattr.va_nodeid;
		Lf->inp_ty = 1;
		break;
#endif	/* defined(solaris) */


#if	defined(HASPROCFS)
	case N_PROC:

	/*
	 * The proc file system inode number is defined when the
	 * prnode is read.
	 */
		break;
#endif	/* defined(HASPROCFS) */

	case N_PCFS:

#if	defined(solaris)
		if (kv.vfs_data
		&& kread((KA_T)kv.vfs_data, (char *)&pcfs, sizeof(pcfs)) == 0)
		{
			Lf->inode = (unsigned long)pc_makenodeid(pc.pc_eblkno,
						   pc.pc_eoffset,
						   &pc.pc_entry,
						   pcfs.pcfs_entps);
			Lf->inp_ty = 1;
		}
#else	/* !defined(solaris) */
		Lf->inode = (unsigned long)pc_makenodeid(pc.pc_eblkno,
							 pc.pc_eoffset,
							 &pc.pc_entry);
		Lf->inp_ty = 1;
#endif	/* defined(solaris) */

		break;

	case N_REGLR:
		if (!ni) {
			Lf->inode = (unsigned long)i.i_number;

#if	!defined(solaris)
			if (type != VBLK || Lf->inode)
#endif	/* !defined(solaris) */

			Lf->inp_ty = 1;
		}
		break;

#if	defined(solaris)
	case N_STREAM:
		if (so_st && soso.lux_dev.addr.tu_addr.ino) {
		    Lf->inode = (unsigned long)soso.lux_dev.addr.tu_addr.ino;
		    Lf->inp_ty = 1;
		}
		break;
#endif	/* defined(solaris) */

	case N_TMP:
		Lf->inode = (unsigned long)t.tn_attr.va_nodeid;
		Lf->inp_ty = 1;
		break;
	}
/*
 * Obtain the file size.
 */
	if (Foffset)
		Lf->off_def = 1;
	else {
		switch (Ntype) {

#if	defined(HAS_AFS)
		case N_AFS:
			Lf->sz = an.size;
			Lf->sz_def = 1;
			break;
#endif	/* defined(HAS_AFS) */

#if	defined(solaris)
		case N_CACHE:
			Lf->sz = (unsigned long)cn.c_size;
			Lf->sz_def = 1;
			break;
#endif	/* defined(solaris) */

		case N_HSFS:
			Lf->sz = (unsigned long)h.hs_dirent.ext_size;
			Lf->sz_def = 1;
			break;

#if	defined(solaris)
		case N_NM:
			Lf->sz = (unsigned long)nn.nm_vattr.va_size;
			Lf->sz_def = 1;
			break;
#endif	/* defined(solaris) */

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

			if ((type == VCHR || type == VBLK) && !Fsize)
				Lf->off_def = 1;
			else {

#if	defined(solaris)
				Lf->sz = (unsigned long)r.r_size;
#else	/* !defined(solaris) */
				Lf->sz = (unsigned long)r.r_attr.va_size;
#endif	/* defined(solaris) */

				Lf->sz_def = 1;
			}
			break;

		case N_PCFS:
			Lf->sz = (unsigned long)pc.pc_size;
			Lf->sz_def = 1;
			break;

#if	defined(HASPROCFS)
		case N_PROC:

		/*
		 * The proc file system size is defined when the
		 * prnode is read.
		 */
			break;
#endif	/* defined(HASPROCFS) */

		case N_REGLR:
			if (type == VREG || type == VDIR) {
				if (!ni) {
					Lf->sz = (unsigned long)i.i_size;
					Lf->sz_def = 1;
				}
			} else if ((type == VCHR || type == VBLK) && !Fsize)
				Lf->off_def = 1;
			break;
		case N_STREAM:
			if (!Fsize)
				Lf->off_def = 1;
			break;
		case N_TMP:
			Lf->sz = (unsigned long)t.tn_attr.va_size;
			Lf->sz_def = 1;
		}
	}
/*
 * Record an NFS selection.
 */
	if (Ntype == N_NFS && Fnfs)
		Lf->sf |= SELNFS;
/*
 * Save the file system names.
 */
	if (vfs && Ntype != N_NM && Ntype != N_DOOR) {
		Lf->fsdir = vfs->dir;
		Lf->fsdev = vfs->fsname;

#if	defined(HASFSINO)
		Lf->fs_ino = vfs->fs_ino;
#endif	/* defined(HASFSINO) */

	}

#if	!defined(solaris)
/*
 * If this is the current working or root directory, and there is a path
 * name, use it.
 */
	if (*Cwd && strcmp(Lf->fd, CWD) == 0)
		(void) strcpy(Namech, Cwd);
	else if (*Rtd && strcmp(Lf->fd, RTD) == 0)
		(void) strcpy(Namech, Rtd);
#endif	/* !defined(solaris) */

/*
 * 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";
		Lf->dev_def = dev_def;
		Lf->dev = dev;
		break;
	case VBLK:
		ty = "VBLK";
		Lf->dev_def = dev_def;
		Lf->dev = dev;
		break;
	case VCHR:
		Lf->dev = dev;
		Lf->dev_def = dev_def;
		ty = unix_sock ? "unix" : "VCHR";
		if (Lf->is_stream == 0 && Lf->is_com == 0)
			Lf->is_chr_dev = 1;
		break;

#if	defined(X_DOOR_OPS)
	case VDOOR:
		ty = "DOOR";
		break;
#endif	/* defined(X_DOOR_OPS) */

	case VLNK:
		ty = "VLNK";
		break;

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

	case VBAD:
		ty = "VBAD";
		break;
	case VFIFO:
		if (!Lf->dev_ch || Lf->dev_ch[0] == '\0') {
			Lf->dev = dev;
			Lf->dev_def = dev_def;
		}
		ty = "FIFO";
		break;
	default:
		if (type > 9999)
			(void) sprintf(Lf->type, "*%03d", type % 1000);
		else
			(void) sprintf(Lf->type, "%4d", type);
		(void) strcpy(Namech, "unknown type");
		ty = NULL;
	}
	if (ty)
		(void) strcpy(Lf->type, ty);

#if	defined(solaris)
/*
 * If this a Solaris common vnode/snode void some information.
 */
	if (Lf->is_com)
		Lf->sz_def = Lf->inp_ty = 0;
#endif	/* defined(solaris) */
/*
 * If this is a VCHR file and it's missing an inode number, try to
 * supply one.
 */

#if	defined(solaris)
	if (Lf->inp_ty == 0 && type == VCHR && Lf->dev_def)
#else	/* !defined(solaris) */
	if (Lf->inp_ty == 0 && (type == VCHR || type == VBLK) && Lf->dev_def)
#endif	/* defined(solaris) */

		find_ch_ino();
	if (Lf->inp_ty == 0 && Lf->is_stream && strcmp(Lf->iproto, "STR") == 0)
		Lf->inp_ty = 2;
/*
 * Test for specified file.
 */

#if	defined(HASPROCFS)
	if (Ntype == N_PROC) {
		if (Procsrch)
			Lf->sf |= SELNM;
		else {
			for (pfi = Procfsid; pfi; pfi = pfi->next) {
				if (pfi->pid == pids.pid_id) {
					Lf->sf |= SELNM;
					break;
				}
			}
		}
	} else
#endif	/* defined(HASPROCFS) */

	{
		if (Sfile && is_file_named(NULL, Ntype, type))
			Lf->sf |= SELNM;
	}
/*
 * Enter name characters.
 */
	if (Namech[0])
		enter_nm(Namech);
}


#if	defined(solaris)
/*
 * read_cni() - read common snode information
 */

static int
read_cni(s, rv, v, rs, di, din, dinl)
	struct snode *s;		/* starting snode */
	struct vnode *rv;		/* "real" vnode receiver */
	struct vnode *v;		/* starting vnode */
	struct snode *rs;		/* "real" snode receiver */
	struct dev_info *di;		/* dev_info structure receiver */
	char *din;			/* device info name receiver */
	int dinl;			/* sizeof(*din) */
{
	if (read_nvn(v->v_data, (caddr_t)s->s_commonvp, rv))
		return(1);
	if (read_nsn((caddr_t)s->s_commonvp, rv->v_data, rs))
		return(1);
	*din = '\0';
	if (rs->s_dip) {
	    if (kread((KA_T)rs->s_dip, (char *)di, sizeof(struct dev_info))) {
		(void) sprintf(Namech,
		    "common snode at %#x: no dev info: %#x",
		    rv->v_data, rs->s_dip);
		enter_nm(Namech);
		return(1);
	    }
	    if (di->devi_name
	    &&  kread((KA_T)di->devi_name, din, dinl-1) == 0)
		din[dinl-1] = '\0';
	}
	return(0);
}
#endif	/* defined(solaris) */


#if	defined(X_DOOR_OPS)
/*
 * read_ndn() - read node's door node
 */

static int
read_ndn(na, da, dn)
	caddr_t na;			/* containing node's address */
	caddr_t da;			/* door node address */
	struct door_node *dn;		/* door node receiver */
{
	if (!da || kread((KA_T)da, (char *)dn, sizeof(struct door_node))) {
		(void) sprintf(Namech,
			"node at %#x: can't read door_node: %#x", na, da);
		enter_nm(Namech);
		return(1);
	}
	return(0);
}
#endif	/* defined(X_DOOR_OPS) */



/*
 * read_mi() - read stream's module information
 */

static void
read_mi(s, dev, so, so_st)
	struct stdata *s;			/* stream pointer */
	dev_t *dev;				/* device pointer */
	caddr_t so;				/* so_so return (Solaris) */
	int *so_st;				/* so_so status */
{
	char *cp;
	int i, j, k, nl;
	KA_T ka, qp;
	struct module_info mi;
	char mn[STRNML];
	struct stdata sd;
	struct queue q;
	struct qinit qi;

/*
 * If there is no stream pointer, or we can't read the stream head,
 * return.
 */
	if (!s)
		return;
	if (kread((KA_T)s, (char *)&sd, sizeof(sd))) {
		(void) sprintf(Namech, "can't read stream head: %#x", s);
		return;
	}
/*
 * Follow the stream head to each of its queue structures, retrieving the
 * module names from each queue's q_info->qi_minfo->mi_idname chain of
 * structures.  Separate each additional name from the previous one with
 * "->".
 *
 * Ignore failures to read all but queue structure chain entries.
 *
 * Ignore module names that end in "head".
 */
	k = 0;
	Namech[0] = '\0';
	if ((cp = finddev(dev, 1)) != NULL) {
		(void) strcpy(Namech, cp);
		k = strlen(Namech);
	}
	nl = sizeof(mn) - 1;
	mn[nl] = '\0';
	qp = (KA_T)sd.sd_wrq;
	for (i = 0; qp && i < 20; i++, qp = (KA_T)q.q_next) {
		if (kread(qp, (char *)&q, sizeof(q)))
			break;
		if ((ka = (KA_T)q.q_qinfo) == (KA_T)NULL
		||  kread(ka, (char *)&qi, sizeof(qi)))
			continue;
		if ((ka = (KA_T)qi.qi_minfo) == (KA_T)NULL
		||  kread(ka, (char *)&mi, sizeof(mi)))
			continue;
		if ((ka = (KA_T)mi.mi_idname) == (KA_T)NULL
		||  kread(ka, mn, nl))
			continue;
		if ((j = strlen(mn)) < 1)
			continue;
		if (j >= 4 && strcmp(&mn[j - 4], "head") == 0)
			continue;

#if	defined(solaris)
		if (strcmp(mn, "sockmod") == 0) {

		/*
		 * Save the Solaris sockmod device and inode numbers.
		 */
		    if (so) {

			struct so_so s;

			if (kread((KA_T)q.q_ptr, (char *)&s, sizeof(s)) == 0)
			    (void) savesockmod(&s, (struct so_so *)so, so_st);
		    }
		}
#endif	/* defined(solaris) */

		if (k) {
			if ((k + 2) > (MAXPATHLEN - 1))
				break;
			(void) strcpy(&Namech[k], "->");
			k += 2;
		}
		if ((k + j) > (MAXPATHLEN - 1))
			break;
		(void) strcpy(&Namech[k], mn);
		k += j;
	}
}


#if	defined(solaris)
/*
 * read_ncn(na, ca, cn) - read node's cache node
 */

static int
read_ncn(na, ca, cn)
	caddr_t na;			/* containing node's address */
	caddr_t ca;			/* cache node address */
	struct cnode *cn;		/* cache node receiver */
{
	if (!ca || kread((KA_T)ca, (char *)cn, sizeof(struct cnode))) {
		(void) sprintf(Namech,
			"node at %#x: can't read cnode: %#x", na, ca);
		enter_nm(Namech);
		return(1);
	}
	return(0);
}
#endif	/* defined(solaris) */


/*
 * read_nfn() - read node's fifonode
 */

static int
read_nfn(na, fa, f)
	caddr_t na;			/* containing node's address */
	caddr_t fa;			/* fifonode address */
	struct fifonode *f;		/* fifonode receiver */
{
	if (!fa || readfifonode(fa, f)) {
		(void) sprintf(Namech,
			"node at %#x: can't read fifonode: %#x", na, fa);
		enter_nm(Namech);
		return(1);
	}
	return(0);
}


/*
 * read_nhn() - read node's High Sierra node
 */

static int
read_nhn(na, ha, h)
	caddr_t na;			/* containing node's address */
	caddr_t ha;			/* hsnode address */
	struct hsnode *h;		/* hsnode receiver */
{
	if (!ha || readhsnode(ha, h)) {
		(void) sprintf(Namech,
			"node at %#x: can't read hsnode: %#x", na, ha);
		enter_nm(Namech);
		return(1);
	}
	return(0);
}


/*
 * read_nin() - read node's inode
 */

static int
read_nin(na, ia, i)
	caddr_t na;			/* containing node's address */
	caddr_t ia;			/* kernel inode address */
	struct inode *i;		/* inode receiver */
{
	if (!ia || readinode((struct inode *)ia, i)) {
		(void) sprintf(Namech,
			"node at %#x: can't read inode: %#x", na, ia);
		enter_nm(Namech);
		return(1);
	}
	return(0);
}


#if	defined(solaris)
/*
 * read_nln(na, la, ln) - read node's loopback node
 */

static int
read_nln(na, la, ln)
	caddr_t na;			/* containing node's address */
	caddr_t la;			/* loopback node address */
	struct lnode *ln;		/* loopback node receiver */
{
	if (!la || kread((KA_T)la, (char *)ln, sizeof(struct lnode))) {
		(void) sprintf(Namech,
			"node at %#x: can't read lnode: %#x", na, la);
		enter_nm(Namech);
		return(1);
	}
	return(0);
}


/*
 * read_ndn() - read node's namenode
 */

static int
read_nnn(na, nna, nn)
	caddr_t na;			/* containing node's address */
	caddr_t nna;			/* namenode address */
	struct namenode *nn;		/* namenode receiver */
{
	if (!nna || kread((KA_T)nna, (char *)nn, sizeof(struct namenode))) {
		(void) sprintf(Namech,
			"node at %#x: can't read namenode: %#x", na, nna);
		enter_nm(Namech);
		return(1);
	}
	return(0);
}
#endif	/* defined(solaris) */


#if	defined(HASPROCFS)
/*
 * read_npi() - read node's /proc file system information
 */

static int
read_npi(na, v, pids)
	caddr_t na;			/* containing node's address */
	struct vnode *v;		/* containing vnode */
	struct pid *pids;		/* pid structure receiver */
{
	struct as as;
	struct proc p;
	struct prnode pr;

	if (!v->v_data || kread((KA_T)v->v_data, (char *)&pr, sizeof(pr))) {
		(void) sprintf(Namech,
			"node at %#x: can't read prnode: %#x", na, v->v_data);
		enter_nm(Namech);
		return;
	}
	if (pr.pr_proc == NULL) {
		if (v->v_type == VDIR) {
			(void) sprintf(Namech, "/%s", HASPROCFS);
			enter_nm(Namech);
			Lf->inode = PR_ROOTINO;
			Lf->inp_ty = 1;
		} else {
			(void) sprintf(Namech, "/%s/???", HASPROCFS);
			enter_nm(Namech);
			Lf->inp_ty = 0;
		}
		return(0);
	}
	if (kread((KA_T)pr.pr_proc, (char *)&p, sizeof(p))) {
		(void) sprintf(Namech,
			"prnode at %#x: can't read proc: %#x",
			v->v_data, pr.pr_proc);
		enter_nm(Namech);
		return(1);
	}
	if (!p.p_pidp
	||  kread((KA_T)p.p_pidp, (char *)pids, sizeof(struct pid))) {
		(void) sprintf(Namech,
			"proc struct at %#x: can't read pid: %#x",
			pr.pr_proc, p.p_pidp);
		enter_nm(Namech);
		return(1);
	}
	if (p.p_as && kread((KA_T)p.p_as, (char *)&as, sizeof(as)) == 0) {
		Lf->sz = (unsigned long)as.a_size;
		Lf->sz_def = 1;
	}
	(void) sprintf(Namech, "/%s/%0*d", HASPROCFS, PNSIZ, pids->pid_id);
	Lf->inode = (unsigned long)ptoi(pids->pid_id);
	Lf->inp_ty = 1;
	enter_nm(Namech);
	return(0);
}
#endif	/* defined(HASPROCFS) */


/*
 * read_npn() - read node's pcnode
 */

static int
read_npn(na, pa, p)
	caddr_t na;			/* containing node's address */
	caddr_t pa;			/* pcnode address */
	struct pcnode *p;		/* pcnode receiver */
{
	if (pa == NULL || kread((KA_T)pa, (char *)p, sizeof(struct pcnode))) {
		(void) sprintf(Namech,
			"node at %#x: can't read pcnode: %#x", na, pa);
		enter_nm(Namech);
		return(1);
	}
	return(0);
}


/*
 * read_nrn() - read node's rnode
 */

static int
read_nrn(na, ra, r)
	caddr_t na;			/* containing node's address */
	caddr_t ra;			/* rnode address */
	struct rnode *r;		/* rnode receiver */
{
	if (!ra || readrnode(ra, r)) {
		(void) sprintf(Namech,
			"node at %#x: can't read rnode: %#x", na, ra);
		enter_nm(Namech);
		return(1);
	}
	return(0);
}


/*
 * read_nsn() - read node's snode
 */

static int
read_nsn(na, sa, s)
	caddr_t na;			/* containing node's address */
	caddr_t sa;			/* snode address */
	struct snode *s;		/* snode receiver */
{
	if (!sa || readsnode((caddr_t)sa, s)) {
		(void) sprintf(Namech,
			"node at %#x: can't read snode: %#x", na, sa);
		enter_nm(Namech);
		return(1);
	}
	return(0);
}


/*
 * read_ntn() - read node's tmpnode
 */

static int
read_ntn(na, ta, t)
	caddr_t na;			/* containing node's address */
	caddr_t ta;			/* tmpnode address */
	struct tmpnode *t;		/* tmpnode receiver */
{
	if (!ta || readtnode(ta, t)) {
		(void) sprintf(Namech,
			"node at %#x: can't read tnode: %#x", na, ta);
		enter_nm(Namech);
		return(1);
	}
	return(0);
}


/*
 * read_nvn() - read node's vnode
 */

static int
read_nvn(na, va, v)
	caddr_t na;			/* node's address */
	caddr_t va;			/* vnode address */
	struct vnode *v;		/* vnode receiver */
{
	if (readvnode(va, v)) {
		(void) sprintf(Namech,
			"node at %#x: can't read real vnode: %#x", na, va);
		enter_nm(Namech);
		return(1);
	}
	return(0);
}


#if	defined(solaris)
/*
 * savesockmod() - save addresses from sockmod so_so structure
 */

static void
savesockmod(so, sop, so_st)
	struct so_so *so;		/* new so_so structure pointer */
	struct so_so *sop;		/* previous so_so structure pointer */
	int *so_st;			/* status of *sop (0 if not loaded) */
{
	dev_t d1, d2, d3;

#define	luxadr	lux_dev.addr.tu_addr
#define	luxdev	lux_dev.addr.tu_addr.dev
#define	luxino	lux_dev.addr.tu_addr.ino
#define	ruxadr	rux_dev.addr.tu_addr
#define	ruxdev	rux_dev.addr.tu_addr.dev
#define	ruxino	rux_dev.addr.tu_addr.ino

/*
 * If either address in the new structure is missing a device number, clear
 * its corresponding inode number.  Then sort the inode-less device numbers.
 */
	if (!so->luxdev)
	    so->luxino = (ino_t)0;
	if (!so->ruxdev)
	    so->ruxino = (ino_t)0;
	if (!so->luxino && !so->ruxino) {
	    if (so->luxdev > so->ruxdev) {
		d2 = so->luxdev;
		d1 = so->luxdev = so->ruxdev;
		so->ruxdev = d2;
	    } else {
		d1 = so->luxdev;
		d2 = so->ruxdev;
	    }
	} else
	    d1 = d2 = (dev_t)0;
/*
 * If the previous structure hasn't been loaded, save the new one in it with
 * adjusted or sorted addresses.
 */
	if (!*so_st) {
	    if (so->luxdev && so->luxino) {
		*sop = *so;
		sop->ruxdev = (dev_t)0;
		sop->ruxino = (ino_t)0;
		*so_st = 1;
		return;
	    }
	    if (so->ruxdev && so->ruxino) {
		*sop = *so;
		sop->luxadr = sop->ruxadr;
		sop->ruxdev = (dev_t)0;
		sop->ruxino = (ino_t)0;
		*so_st = 1;
		return;
	    }
	    *sop = *so;
	    *so_st = 1;
	    return;
	}
/*
 * See if the new sockmod addresses need to be merged with the previous
 * ones:
 *
 *	*  Don't merge if the previous so_so structure's lux_dev has a non-
 *	   zero device and a non-zero inode number.
 *
 *	*  If either of the device/inode pairs in the new structure is non-
 *	   zero, propagate them to the previous so_so structure.
 *
 *	*  Don't merge if the both device numbers in the new structure are
 *	   zero.
 */
	if (sop->luxdev && sop->luxino)
	    return;
	if (so->luxdev && so->luxino) {
	    sop->luxadr = so->luxadr;
	    sop->ruxdev = (dev_t)0;
	    sop->ruxino = (ino_t)0;
	    return;
	}
	if (so->ruxdev && so->ruxino) {
	    sop->luxadr = so->ruxadr;
	    sop->ruxdev = (dev_t)0;
	    sop->ruxino = (ino_t)0;
	    return;
	}
	if (!so->luxdev && !so->ruxdev)
	    return;
/*
 * Check the previous structure's device numbers:
 *
 *	*  If both are zero, replace the previous structure with the new one.
 *
 *	*  Choose the minimum and maximum non-zero device numbers contained in
 *	   either structure.
 */
	if (!sop->luxdev && !sop->ruxdev) {
	    *sop = *so;
	    return;
	}
	if (!sop->luxdev && (d1 || d2)) {
	    if (d1) {
		sop->luxdev = d1;
		d1 = (dev_t)0;
	    } else {
		sop->luxdev = d2;
		d2 = (dev_t)0;
	    }
	    if (sop->luxdev > sop->ruxdev) {
		d3 = sop->luxdev;
		sop->luxdev = sop->ruxdev;
		sop->ruxdev = d3;
	    }
	}
	if (!sop->ruxdev && (d1 || d2)) {
	    if (d1) {
		sop->ruxdev = d1;
		d1 = (dev_t)0;
	    } else {
		sop->ruxdev = d2;
		d2 = (dev_t)0;
	    }
	    if (sop->luxdev > sop->ruxdev) {
		d3 = sop->luxdev;
		sop->luxdev = sop->ruxdev;
		sop->ruxdev = d3;
	    }
	}
	if (sop->luxdev && sop->ruxdev) {
	    if (d1) {
		if (d1 < sop->luxdev)
		    sop->luxdev = d1;
		else if (d1 > sop->ruxdev)
		    sop->ruxdev = d1;
	    }
	    if (d2) {
		if (d2 < sop->luxdev)
		    sop->luxdev = d2;
		else if (d2 > sop->ruxdev)
		    sop->ruxdev = d2;
	    }
	}
}
#endif	/* defined(solaris) */


/*
 * vop2ty() - convert vnode operation switch address to internal type
 */

static int
vop2ty(vp)
	struct vnode *vp;		/* vnode pointer */
{

#if	defined(HAS_AFS)
	int afs = 0;			/* afs test status: -1 = no AFS
					 *		     0 = not tested
					 *		     1 = AFS */
#endif	/* defined(HAS_AFS) */

	if (!vp->v_op)
		return(-1);
	if (Nl[X_NFS_OPS].n_value
	&& (unsigned long)vp->v_op == Nl[X_NFS_OPS].n_value)
		return(N_NFS);
	else if (Nl[X_NFS3_OPS].n_value
	     && (unsigned long)vp->v_op == Nl[X_NFS3_OPS].n_value)
		return(N_NFS);
	else if (Nl[X_TMP_OPS].n_value
	     && (unsigned long)vp->v_op == Nl[X_TMP_OPS].n_value)
		return(N_TMP);
	else if (Nl[X_HSFS_OPS].n_value
	     && (unsigned long)vp->v_op == Nl[X_HSFS_OPS].n_value)
		return(N_HSFS);
	else if ((Nl[X_PC_DOPS].n_value
	     && (unsigned long)vp->v_op == Nl[X_PC_DOPS].n_value)
	     ||  (Nl[X_PC_FOPS].n_value
	     &&   (unsigned long)vp->v_op == Nl[X_PC_FOPS].n_value))
		return(N_PCFS);

#if	defined(X_CACHE_OPS)
	else if (Nl[X_CACHE_OPS].n_value
	     && (unsigned long)vp->v_op == Nl[X_CACHE_OPS].n_value)
		return(N_CACHE);
#endif	/* defined(X_CACHE_OPS) */

#if	defined(X_DOOR_OPS)
	else if (Nl[X_DOOR_OPS].n_value
	     && (unsigned long)vp->v_op == Nl[X_DOOR_OPS].n_value)
		return(N_DOOR);
#endif	/* defined(X_DOOR_OPS) */

#if	defined(X_FIFO_OPS)
	else if (Nl[X_FIFO_OPS].n_value
	     && (unsigned long)vp->v_op == Nl[X_FIFO_OPS].n_value)
		return(N_FIFO);
#endif	/* defined(X_FIFO_OPS) */

#if	defined(X_LOFS_OPS)
	else if (Nl[X_LOFS_OPS].n_value
	     && (unsigned long)vp->v_op == Nl[X_LOFS_OPS].n_value)
		return(N_LOFS);
#endif	/* defined(X_FIFO_OPS) */

#if	defined(solaris)
	else if (Nl[X_NM_OPS].n_value
	     && (unsigned long)vp->v_op == Nl[X_NM_OPS].n_value)
		return(N_NM);
#endif	/* defined(solaris) */

# if	defined(X_PROC_OPS)
	else if (Nl[X_PROC_OPS].n_value
	     && (unsigned long)vp->v_op == Nl[X_PROC_OPS].n_value)
		return(N_PROC);
#endif	/* defined(X_PROC_OPS) */

#if	defined(HAS_AFS)
/*
 * Caution: this should be the last test in vop2ty().
 */
	else if (Nl[X_AFS_OPS].n_value) {
		if ((unsigned long)vp->v_op == Nl[X_AFS_OPS].n_value)
			return(N_AFS);
		else
			return(-1);
	}
	if (vp->v_data || !vp->v_vfsp)
		return(-1);
	switch (afs) {
	case -1:
		return(-1);
	case 0:
		if (!hasAFS(vp)) {
			afs = -1;
			return(-1);
		}
		afs = 1;
		return(N_AFS);
	case 1:
		if (vp->v_vfsp == AFSVfsp)
			return(N_AFS);
	}
	return(-1);

#else	/* !defined(HAS_AFS) */
	return(-1);
#endif	/* defined(HAS_AFS) */

}
