/*
 * dnode.c - SGI IRIX 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";
static char *rcsid = "$Id: dnode.c,v 1.26 96/03/09 14:51:25 abe Exp Locker: abe $";
#endif


#include "lsof.h"


#if	_IRIXV>=50101
_PROTOTYPE(static char isvlocked,(struct vnode *va));
#endif	/* _IRIXV>=50101 */

#if	_IRIXV>=50200
_PROTOTYPE(static struct l_dev * finddev,(dev_t *dev, int stream));
#endif	/* _IRIXV>=50200 */



#if	_IRIXV>=50101


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

static char
isvlocked(va)
	struct vnode *va;		/* local vnode address */
{
	struct filock f;
	off_t l;

	if (va->v_filocks == NULL)
		return(' ');
	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('u');
	}
	return(' ');
}
#endif	/* _IRIXV>=50101 */


#if	_IRIXV>=50200
/*
 * finddev() - look up device by device number
 */

static struct l_dev *
finddev(dev, stream)
	dev_t *dev;			/* device */
	int stream;			/* stream if 1 */
{
	struct clone *c;
	struct l_dev *dp;
/*
 * Search device table for match.
 */
	if ((dp = lkupdev(dev, 0)) != (struct l_dev *)NULL)
		return(dp);
/*
 * Search for clone.
 */
	if (stream && Clone) {
		for (c = Clone; c; c = c->next) {
			if (major(*dev) == minor(Devtp[c->dx].rdev))
				return(&Devtp[c->dx]);
		}
	}
	return(NULL);
}
#endif	/* _IRIXV>=50200 */


#if	_IRIXV<50101
/*
 * process_node() - process node
 */

void
process_node(na)
	caddr_t na;			/* inode kernel space address */
{
	char dev_ch[32];
	struct filock fl;
	struct inode i;
	short ity;
	struct mounts *lm;
	struct mount m;
	struct module_info mi;
	int prdev;
	struct qinit qi;
	struct rnode r;
	struct stdata sd;
	struct queue sh;
	char *tn;
	int type;
/*
 * Read the inode.
 */
	if ( ! na) {
		enter_nm("no inode address");
		return;
	}
	if (readinode(na, &i)) {
		enter_nm(Namech);
		return;
	}
/*
 * Identify the node type.
 */
	ity = i.i_fstyp;
	type = i.i_ftype & IFMT;
	if (ity < 1 || ity >= Nfstyp || Fsinfo[ity].fs_name == NULL) {
		(void) sprintf(Namech, "unknown fstyp (%d) in inode", ity);
		enter_nm(Namech);
		return;
	}
	if (strcasecmp(Fsinfo[ity].fs_name, "NFS") == 0) {

	/*
	 * Get information on NFS file.
	 */
		Ntype = N_NFS;
		if (Fnfs)
			Lf->sf |- SELNFS;
		if (kread((KA_T)i.i_mntdev, (char *)&m, sizeof(m))) {
			(void) sprintf(Namech,
			    "can't read NFS mount structure (%#x)",
			    i.i_mntdev);
			enter_nm(Namech);
			return;
		}
		if (kread((KA_T)i.i_fsptr, (char *)&r, sizeof(r))) {
			(void) sprintf(Namech, "can't read rnode (%#x)",
			    i.i_fsptr);
			enter_nm(Namech);
			return;
		}
	} else if (strcasecmp(Fsinfo[ity].fs_name, "SOC") == 0) {

	/*
	 * Process a socket.
	 */
		process_socket((KA_T)i.i_fsptr);
		return;
	} else {

	/*
	 * Determine the node type from the inode file type.
	 */
		switch (type) {

		case IFBLK:
			Ntype = N_BLK;
			break;
		case IFCHR:
			Ntype = N_CHR;
			break;
		case IFIFO:
			Ntype = N_FIFO;
			break;
		case IFMPB:
		case IFMPC:
			Ntype = N_MPC;
			break;
		}
	}
/*
 * Obtain lock information.
 */
	if (i.i_filocks) {
		if ((kread((KA_T)i.i_filocks, (char *)&fl, sizeof(fl)))) {
			(void) sprintf(Namech, "can't read filock (%#x)",
				i.i_filocks);
			enter_nm(Namech);
			return;
		} else {
			if (fl.set.l_type == F_RDLCK)
				Lf->lock = 'R';
			else if (fl.set.l_type == F_WRLCK)
				Lf->lock = 'W';
			else if (fl.set.l_type == (F_RDLCK | F_WRLCK))
				Lf->lock = 'u';
		}
	}
/*
 * Determine the device.
 */
	switch (Ntype) {
	case N_BLK:
	case N_REGLR:
		Lf->dev = i.i_dev;
		Lf->dev_def = 1;
		break;
	case N_CHR:
		Lf->dev = i.i_rdev;
		Lf->dev_def = 1;
		if (i.i_sptr) {

		/*
		 * Follow the stream structure from its stdata
		 * pointer to the module information structure.
		 * Then read the first STRNML-1 characters of
		 * the module name.
		 */
			if (readstdata((struct stdata *)i.i_sptr, &sd)
			||  readsthead(sd.sd_wrq, &sh)
			||  readstqinit(sh.q_qinfo, &qi)
			||  readstmin(qi.qi_minfo, &mi)
			||  readstidnm(mi.mi_idname, Namech, STRNML-1)) {
				(void) sprintf(Namech,
					"no module name for stream at %#x",
					i.i_sptr);
			} else {
				Namech[STRNML-1] = '\0';
				Lf->is_stream = 1;
			}
		} else {
			if (strcasecmp(Fsinfo[ity].fs_name, "COM") == 0) {
				Ntype = N_COM;
				Lf->is_com = 1;
			} else
				Lf->is_chr_dev  = 1;
		}
		break;
	case N_FIFO:
		if (major(i.i_dev) == 0x7f &&  minor(i.i_dev) == 0xff) {
			(void) sprintf(dev_ch, "0x%08x", na);
			enter_dev_ch(dev_ch);
		}
		if ( ! Lf->dev_ch) {
			Lf->dev = i.i_dev;
			Lf->dev_def = 1;
		}
		break;
	case N_NFS:
		Lf->dev = m.m_dev;
		Lf->dev_def = 1;
		break;
	}
/*
 * Determine the inode number.
 */
	switch (Ntype) {
	case N_NFS:
		Lf->inode = (unsigned long)r.r_snfsattr.na_nodeid;
		Lf->inp_ty = 1;
		break;
	case N_BLK:
	case N_CHR:
	case N_COM:
	case N_FIFO:
	case N_REGLR:
		Lf->inode = (unsigned long)i.i_number;
		Lf->inp_ty = 1;
		break;
	}
/*
 * Determine the file size.
 */
	if (Foffset)
		Lf->off_def = 1;
	else {
		switch (Ntype) {
		case N_BLK:
			Lf->sz = (unsigned long)i.i_size;
			Lf->sz_def = 1;
			break;
		case N_CHR:
		case N_COM:
			if (!Fsize)
				Lf->off_def = 1;
			break;
		case N_FIFO:
			if (!Fsize)
				Lf->off_def = 1;
			break;
		case N_NFS:
			Lf->sz = (unsigned long)r.r_snfsattr.na_size;
			Lf->sz_def = 1;
			break;
		case N_REGLR:
			if (type == IFREG || type == IFDIR)
				Lf->sz = (unsigned long)i.i_size;
				Lf->sz_def = 1;
			break;
		}
	}
/*
 * Format the type name.
 */
	switch (type) {
	case IFDIR:
		tn = "DIR";
		break;
	case IFBLK:
		tn = "BLK";
		break;
	case IFCHR:
		tn = "CHR";
		break;
	case IFREG:
		tn = "REG";
		break;
	case IFMPC:
		tn = "MPC";
		break;
	case IFMPB:
		tn = "MPB";
		break;
	case IFIFO:
		tn = "FIFO";
		break;
	case IFLNK:
		tn = "LINK";
		break;
	default:
		if (type > 9999)
			(void) sprintf(Lf->type, "*%03d", type % 1000);
		else
			(void) sprintf(Lf->type, "%4d", type);
		(void) strcpy(Namech, "unknown inode type");
		tn = NULL;
	}
	if (tn)
		(void) strcpy(Lf->type, tn);
/*
 * Save the file system names.
 */
	switch (Ntype) {
	case N_BLK:
	case N_FIFO:
	case N_NFS:
	case N_REGLR:
		if (Lf->dev_def) {
			for (lm = Mtab; lm; lm = lm->next) {
				if (Lf->dev == lm->dev) {
					Lf->fsdir = lm->dir;
					Lf->fsdev = lm->fsname;

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

					break;
				}
			}
		}
		break;
	}
/*
 * If this is a IFCHR file and it's missing an inode number, try to
 * supply one.
 */
	if (Lf->inp_ty == 0 && type == IFCHR && Lf->dev_def)
		find_ch_ino();
/*
 * Test for specified file.
 */
	if (Sfile && is_file_named(NULL, type))
		Lf->sf |= SELNM;
/*
 * Enter name characters.
 */
	if (Namech[0])
		enter_nm(Namech);
}
#endif	/* _IRIXV<50101 */


#if	_IRIXV>=50101
/*
 * process_node() - process node
 */

void
process_node(na)
	caddr_t na;			/* vnode kernel space address */
{
	dev_t dev;
	char dev_ch[32];
	struct fifonode f;
	int fx;
	struct inode i;
	int is = 0;
	struct vfs kv;
	struct module_info mi;
	char mn[STRNML];
	struct pipenode p;
	struct qinit qi;
	struct rnode r;
	struct snode rs;
	struct vnode rv, v;
	struct snode s;
	struct stdata sd;
	struct queue sh;
	char *ty;
	enum vtype type;
	struct l_vfs *vfs;
	int xs = 0;
	int xt = 0;

# if	defined(HASPROCFS)
	static long pgsz = -1L;
	struct proc proc;
	struct procfsid *pfi;
	struct prnode prn;
# endif

# if	_IRIXV>=50200
	struct l_dev *dp;
	int j;
# endif	/* _IRIXV>=50200 */

# if	_IRIXV>=60200
	struct xfsnode xfs;
# endif	/* _IRIXV>=60200 */

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

# if	defined(HASNCACHE)
	Lf->na = (unsigned long)na;
#  if	defined(HASNCAPID)
	Lf->id = (unsigned long)v.v_namecap;
#  endif	/* defined(HASNCAPID( */
# endif	/* defined(HASNCACHE) */

/*
 * Determine the vnode type.
 */
	if (v.v_vfsp && kread((KA_T)v.v_vfsp, (char *)&kv, sizeof(kv)) == 0) {
	/*
	 * Check the file system type.
	 */
		fx = kv.vfs_fstype;
		if (fx > 0 && fx <= Fsinfomax) {
			if (strcmp(Fsinfo[fx-1], "fifofs") == 0)
				Ntype = N_FIFO;
			else if (strcmp(Fsinfo[fx-1], "nfs") == 0)
			    Ntype = N_NFS;
			else if (strcmp(Fsinfo[fx-1], "socket") == 0) {
				process_socket((caddr_t)v.v_data);
				return;
			} else if (strcmp(Fsinfo[fx-1], "pipefs") == 0)
				Ntype = N_PIPE;

# if	defined(HASPROCFS)
			else if (strcmp(Fsinfo[fx-1], HASPROCFS) == 0)
				Ntype = N_PROC;
# endif	/* defined(HASPROCFS) */

# if	_IRIXV>=60200
			else if (strcmp(Fsinfo[fx-1], "xfs") == 0)
				xt = N_XFS;
# endif	/* _IRIXV>=060200 */

		}
	}
	if (Ntype == N_REGLR) {
		if (v.v_type == VFIFO)
			Ntype = N_FIFO;
		else if (v.v_stream) {
			Ntype = N_STREAM;
			Lf->is_stream = 1;
		}
	}
/*
 * Determine the lock state.
 */
	Lf->lock = isvlocked(&v);
/*
 * Establish the local virtual file system structure.
 */
	if (v.v_vfsp == NULL)
		vfs = NULL;
	else {
	    if ((vfs = readvfs(v.v_vfsp, &kv)) == NULL) {
		(void) sprintf(Namech, "bad vfs for %#x at %#x", na, v.v_vfsp);
		enter_nm(Namech);
		return;
	    }
	}
/*
 * Read the fifonode, inode, pipenode, rnode, snode, or xfsnode.
 */
	switch (Ntype) {
	case N_FIFO:

	/*
	 * IRIX 5.1.1 FIFO vnodes are linked to a fifonode.
	 * Non-pipe fifonodes are linked to a vnode thorough fn_realvp.
	 */
	    if (!v.v_data || readfifonode(v.v_data, &f)) {
		(void) sprintf(Namech,
		    "vnode at %#x: can't read fifonode at: %#x", na, v.v_data);
		enter_nm(Namech);
		return;
	    }
	    if (f.fn_realvp) {
		if (readvnode((caddr_t)f.fn_realvp, &rv)) {
		    (void) sprintf(Namech,
			"fifonode at %#x: can't read vnode at: %#x",
			v.v_data, f.fn_realvp);
		    enter_nm(Namech);
		    return;
		}
		if (!rv.v_data) {
		    (void) sprintf(Namech,
			"fifonode at %#x: no successor address", v.v_data);
		    enter_nm(Namech);
		    return;
		}

# if	_IRIXV>=60200
		if (xt == N_XFS) {
		    if (kread((KA_T)rv.v_data, (char *)&xfs, sizeof(xfs))) {
			(void) sprintf(Namech,
			    "fifonode at %#x: can't read xfsnode at: %#x",
			    v.v_data, rv.v_data);
			enter_nm(Namech);
			return;
		    }
		    xs = 1;
		} else
# endif	/* _IRIXV>=60200 */

		{
		    if (readinode((struct inode *)rv.v_data, &i)) {
			(void) sprintf(Namech,
			    "fifonode at %#x: can't read inode at: %#x",
			    v.v_data, rv.v_data);
			enter_nm(Namech);
			return;
		    }
		    is = 1;
		}
	    } else {
		(void) sprintf(Namech,
		    "fifonode at %#x: no real vnode pointer", v.v_data);
		enter_nm(Namech);
		return;
	    }
	    break;
	case N_NFS:
	    if (!v.v_data || readrnode((caddr_t)v.v_data, &r)) {
		(void) sprintf(Namech,
		    "vnode at %#x: can't read rnode at: %#x", na, v.v_data);
		enter_nm(Namech);
		return;
	    }
	    break;
	case N_PIPE:
	    if (!v.v_data || readpipenode((caddr_t)v.v_data, &p)) {
		(void) sprintf(Namech,
		    "vnode at %#x: can't read pipenode at: %#x", na, v.v_data);
		enter_nm(Namech);
		return;
	    }
	    break;

# if	defined(HASPROCFS)
	
	case N_PROC:

	/*
	 * Read the proc file system node and associated information.
	 */
	    if (v.v_data == NULL
	    ||  kread((KA_T)v.v_data, (char *)&prn, sizeof(prn))) {
		(void) sprintf(Namech,
		    "vnode at %#x: can't read prnode at: %#x", na, v.v_data);
		enter_nm(Namech);
		return;
	    }
	    if (prn.pr_proc == NULL) {
		if (v.v_type == VDIR) {
		    (void) sprintf(Namech, "/%s%s", HASPROCFS,
			(prn.pr_type == PR_PROCDIR) ? "" : HASPINFO);
		    enter_nm(Namech);
		    Lf->inode = (unsigned long)((prn.pr_type == PR_PROCDIR)
			      ? PR_ROOTINO
			      : PR_ROOTINO+1);
		    Lf->inp_ty = 1;
		    proc.p_pid = (pid_t)Lf->inode;
		} else {
		    (void) sprintf(Namech, "/%s%s/???", HASPROCFS,
			(prn.pr_type == PR_PROCDIR) ? "" : HASPINFO);
		    enter_nm(Namech);
		    Lf->inp_ty = 0;
		}
		break;
	    }
	    if (kread((KA_T)prn.pr_proc, (char *)&proc, sizeof(proc))) {
		(void) sprintf(Namech,
		    "prnode at %#x: can't read proc (%#x)",
		    v.v_data, prn.pr_proc);
		enter_nm(Namech);
		return;
	    }
	    if (pgsz < 0L)
		pgsz = sysconf(_SC_PAGESIZE);
	    Lf->sz = (unsigned long)(pgsz * proc.p_size);
	    Lf->sz_def = 1;
	    (void) sprintf(Namech, "/%s%s/%0*d", HASPROCFS,
		(prn.pr_type == PR_PROCDIR) ? "" : HASPINFO,
		PNSIZ, proc.p_pid);
	    Lf->inode = (unsigned long)ptoi(proc.p_pid);
	    Lf->inp_ty = 1;
	    enter_nm(Namech);
	    break;
# endif	/* HASPROCFS */

	case N_STREAM:
	    if (!v.v_data || readsnode((caddr_t)v.v_data, &s)) {
		(void) sprintf(Namech,
		    "vnode at %#x: can't read snode at: %#x", na, v.v_data);
		enter_nm(Namech);
		return;
	    }
	    if (v.v_stream) {

	    /*
	     * Follow the stream structure from its stdata pointer to the
	     * module information structure.  Then read the first STRNML-1
	     * characters of the module name.
	     */
		if (readstdata(v.v_stream, &sd) == 0
		&&  readsthead(sd.sd_wrq, &sh) == 0
		&&  readstqinit(sh.q_qinfo, &qi) == 0
		&&  readstmin(qi.qi_minfo,&mi) == 0
		&&  readstidnm(mi.mi_idname, mn, STRNML-1) == 0) {
		    mn[STRNML-1] = '\0';
		    if (mn[0]) {

#if	_IRIXV>=50200
			Namech[0] = '\0';
			j = 0;
			if ((dp = finddev((dev_t *)&v.v_rdev, 1)) != NULL) {
			    (void) strcpy(Namech, dp->name);
			    j += strlen(dp->name);
			}
			if ((j + 2) <= MAXPATHLEN - 1) {
			    (void) strcpy(&Namech[j], "->");
			    j += 2;
			    if ((j + strlen(mn)) <= MAXPATHLEN - 1)
				(void) strcpy(&Namech[j], mn);
			}
#else	/* _IRIXV<50200 */
			(void) strcpy(Namech, mn);
#endif	/* _IRIXV>=50200 */

		    }
		}
	    }
	    break;
	case N_REGLR:
	default:

	/*
	 * IRIX 5.1.1 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 at: %#x",
			na, v.v_data);
		    enter_nm(Namech);
		    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);
			enter_nm(Namech);
			return;
		    }
		    if (!rv.v_data) {
			(void) sprintf(Namech,
			    "snode at %#x: no successor address", v.v_data);
			enter_nm(Namech);
			return;
		    }

# if	_IRIXV>=60200
		    if (xt == N_XFS) {
			if (kread((KA_T)rv.v_data, (char *)&xfs, sizeof(xfs))) {
			    (void) sprintf(Namech,
				"snode at %#x: can't read xfsnode at: %#x",
				v.v_data, rv.v_data);
			    enter_nm(Namech);
			    return;
		    	}
			xs = 1;
		    } else
# endif	/* _IRIXV>=60200 */

		    {
			if (readinode((struct inode *)rv.v_data, &i)) {
			    (void) sprintf(Namech,
				"snode at %#x: can't read inode at: %#x",
				v.v_data, rv.v_data);
			    enter_nm(Namech);
			    return;
			}
			is = 1;
		    }
		}
	    /*
	     * When an IRIX 5.1.1 snode has no s_realvp, but does have
	     * a s_commonvp, follow s_commonvp to a common vnode and then
	     * to a common snode.
	     */
		else if (s.s_commonvp) {
		    if (readvnode((caddr_t)s.s_commonvp, &rv)) {
			  (void) sprintf(Namech,
				"snode at %#x: can't read real vnode at: %#x",
				v.v_data, s.s_commonvp);
			    enter_nm(Namech);
			    return;
		    }
		    if (!rv.v_data || readsnode(rv.v_data, &rs)) {
			(void) sprintf(Namech,
			    "vnode at %#x: can't read snode at: %#x",
			    s.s_commonvp, rv.v_data);
			enter_nm(Namech);
			return;
		    }
		}
		break;
	    }
	    if (!v.v_data) {
		(void) sprintf(Namech,
		    "vnode at %#x: no successor address", na);
		enter_nm(Namech);
		return;
	    }

# if	_IRIXV>=60200
	    if (xt == N_XFS) {
		if (kread((KA_T)v.v_data, (char *)&xfs, sizeof(xfs))) {
		    (void) sprintf(Namech,
			"vnode at %#x: can't read xfsnode at: %#x",
			na, v.v_data);
		    enter_nm(Namech);
		    return;
		}
		xs = 1;
	     } else
# endif	/* _IRIXV>=60200 */

	     {
		if (readinode((struct inode *)v.v_data, &i)) {
		    (void) sprintf(Namech,
			"vnode at %#x: can't read inode at: %#x",
			na, v.v_data);
		    enter_nm(Namech);
		    return;
		}
		is = 1;
	    }
	}
/*
 * Get device and type for printing.
 */
	switch (Ntype) {

# if	defined(HASPROCFS)
	case N_PROC:
# endif

	case N_NFS:
		dev = kv.vfs_dev;
		break;
	case N_PIPE:
		dev = v.v_rdev;
		break;
	default:
		if (v.v_type == VCHR)
			dev = v.v_rdev;

# if	_IRIXV>=60200
		else if (xs)
			dev = xfs.x_dev;
# endif	/* _IRIXV>=060200 */

		else if (is)
			dev = i.i_dev;
		else
			dev = v.v_rdev;
	}
	type = v.v_type;
	if (vfs && vfs->dir == NULL)
		(void) completevfs(vfs, &dev);
/*
 * Obtain the inode number.
 */
	switch (Ntype) {
	case N_NFS:
		Lf->inode = (unsigned long)r.r_nfsattr.na_nodeid;
		Lf->inp_ty = 1;
		break;
	case N_PIPE:
		Lf->inode = (unsigned long)p.pi_ino;
		Lf->inp_ty = 1;
		break;

# if	defined(HASPROCFS)
	case N_PROC:

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

	case N_FIFO:
		if ( ! f.fn_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 (f.fn_mate)
				(void) sprintf(endnm(), "->0x%08x", f.fn_mate);
			break;
		}
		/* fall through */
	case N_REGLR:
		if (is) {
			Lf->inode = (unsigned long)i.i_number;
			Lf->inp_ty = 1;
		}

# if	_IRIXV>=60200
		else if (xs) {
			Lf->inode = xfs.x_ino;
			Lf->inp_ty = 1;
		}
# endif	/* _IRIXV>=060200 */

		break;
	}
/*
 * Obtain the file size.
 */
	if (Foffset)
		Lf->off_def = 1;
	else {
		switch (Ntype) {
		case N_FIFO:
		case N_STREAM:
			if (!Fsize)
				Lf->off_def = 1;
			break;
		case N_NFS:
			Lf->sz = (unsigned long)r.r_nfsattr.na_size;
			Lf->sz_def = 1;
			break;
		case N_PIPE:
			Lf->sz = (unsigned long)p.pi_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 (is) {
					Lf->sz = (unsigned long)i.i_size;
					Lf->sz_def = 1;
				}

# if	_IRIXV>=60200
				else if (xs) {
					Lf->sz = xfs.x_size;
					Lf->sz_def = 1;
				}
# endif	/* _IRIXV>=060200 */

			} else if (type == VCHR && !Fsize)
				Lf->off_def = 1;
			break;
		}
	}
/*
 * Record an NFS file selection.
 */
	if (Ntype == N_NFS && Fnfs)
		Lf->sf |= SELNFS;
/*
 * Save the file system names.
 */
	if (vfs) {
		Lf->fsdir = vfs->dir;
		Lf->fsdev = vfs->fsname;

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

	}

#if	_IRIXV<60200
/*
 * If the IRIX version is below 6.2, this is the current working or
 * root directory, and the user structure had a path name, use it.
 */
	if ( ! Sfile) {
		if (*Cwd && strcmp(Lf->fd, CWD) == 0)
			(void) strcpy(Namech, Cwd);
		else if (*Rtd && strcmp(Lf->fd, RTD) == 0)
			(void) strcpy(Namech, Rtd);
	}
#endif	/* _IRIXV<60200 */

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

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

	case VBAD:
		ty = "VBAD";
		break;
	case VFIFO:
		if (!Lf->dev_ch || Lf->dev_ch[0] == '\0') {
			Lf->dev = dev;
			Lf->dev_def = 1;
		}
		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);
/*
 * Indicate a pipe.
 */
	if (Ntype == N_PIPE) {
		if (Namech[0])
			(void) strcpy(endnm(), " (PIPE)");
		else if (vfs) {
			(void) sprintf(Namech, "%s %s%s%s (PIPE)",
				(vfs->dir)    ? vfs->dir    : "",
				(vfs->fsname) ? "("         : "",
				(vfs->fsname) ? vfs->fsname : "",
				(vfs->fsname) ? ")"         : "");
		} else
			(void) strcpy(Namech, "(PIPE)");
	}
/*
 * If this is a VCHR file and it's missing an inode number, try to
 * supply one.
 */
	if ((!Lf->inp_ty || !Lf->inode) && type == VCHR && Lf->dev_def)
		find_ch_ino();
	if (Ntype == N_STREAM && Lf->inp_ty == 0) {
		(void) strcpy(Lf->iproto, "STR");
		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	defined(HASPINFO)
		
		/*
		 * Check for a match on any HASPINFO file.
		 */
		    if (pfi->type == 2) {
			if (prn.pr_type == PR_PSINFO) {
			    Lf->sf |= SELNM;
			    break;
			} else
			    continue;
		    }
#  endif	/* HASPINFO */

		/*
		 * Check for a match on PID.
		 */
		    if (pfi->pid == proc.p_pid) {

#  if	defined(HASPINFO)

		    /*
		     * Check for a match on type.
		     */
			if ((prn.pr_type == PR_PROCDIR && pfi->type != 0)
			||  (prn.pr_type == PR_PSINFO  && pfi->type != 1))
			    continue;
#  endif

			Lf->sf |= SELNM;
			break;
		    }
		}
	    }
	} else
# endif	/* HASPROCFS */

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