/*
 * dnode.c - RISCos 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.6 96/01/11 12:55:14 abe Exp $";
#endif


#include "lsof.h"


/*
 * process_node() - process vnode
 */

void
process_node(va)
	caddr_t va;			/* vnode kernel space address */
{
	char dev_ch[32];
	dev_t dev;
	struct l_dev *dp;
	struct fifonode f;
	int ft = 0;
	struct inode i;
	int j;
	struct module_info mi;
	char mn[STRNML];
	int ni = 0;
	struct qinit qi;
	struct rnode r;
	struct snode s;
	struct stdata sd;
	struct queue sh;
	char *ty;
	enum vtype type;
	struct vnode v, rv;
	struct l_vfs *vfs;
/*
 * Read the vnode.
 */
	if ( ! va) {
		enter_nm("no vnode address");
		return;
	}
	if (readvnode((caddr_t)va, &v)) {
                enter_nm(Namech);
                return;
        }

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

/*
 * Determine the vnode type.
 */
	if (Nl[X_NFS_OPS].n_value
	&& (unsigned long)v.v_op == Nl[X_NFS_OPS].n_value)
		Ntype = N_NFS;
	else if (v.v_type == VFIFO)
		Ntype = N_FIFO;
/*
 * Determine the 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';
	}
/*
 * Establish the local virtual file system structure.
 */
	if (!v.v_vfsp)
		vfs = NULL;
	else if ((vfs = readvfs(v.v_vfsp)) == NULL) {
                (void) sprintf(Namech, "can't read vfs for %#x at %#x", va,
			v.v_vfsp);
                enter_nm(Namech);
		return;
	}
/*
 * Read the fifonode, inode, rnode, or snode.
 */
	switch (Ntype) {
	case N_NFS:
		if (!v.v_data || readrnode((caddr_t)v.v_data, &r)) {
			(void) sprintf(Namech,
				"vnode at %#x: can't read rnode (%#x)",
				va, v.v_data);
			enter_nm(Namech);
			return;
		}
		break;
	case N_FIFO:
		if (readfifonode(v.v_data, &f)
		||  f.fn_snode.s_vnode.v_data != v.v_data)
			ft = 0;
		else
			ft = 3;
		switch (ft) {
		case 3:
		    if (f.fn_snode.s_realvp
		    &&  readvnode((KA_T)f.fn_snode.s_realvp, (char *)&rv) == 0)
		    {
			if (rv.v_data
			&&  readinode((struct inode *)rv.v_data, &i) == 0
			&&  i.i_vnode.v_data == rv.v_data)
			    ft = 1;
		    }
		    (void) sprintf(dev_ch, "0x%08x", v.v_data);
		    enter_dev_ch(dev_ch);
		    break;
		default:
		    (void) strcpy(Namech, "no fifonode");
		}
		break;
	case N_REGLR:
	default:

	/*
	 * RISCos VCHR vnodes point to snodes.  All others point to inodes.
	 */
		if (v.v_type == VCHR) {
			if (!v.v_data || readsnode(v.v_data, &s)) {
			    (void) sprintf(Namech,
				"vnode at %#x: can't read snode(%#x)",
				va, v.v_data);
			    enter_nm(Namech);
			    return;
			}
			if (s.s_realvp) {

			/*
			 * If there is a real vnode pointer in the snode,
			 * this is just an ordinary character file.  Read
			 * the real vnode and the inode it points to.
			 */
			    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
			    ||  readinode((struct inode *)rv.v_data, &i)) {
				(void) sprintf(Namech,
					"snode at %#x: can't read inode (%#x)",
					v.v_data, rv.v_data);
				enter_nm(Namech);
				return;
			    }
			} else {
			    ni = 1;
			/*
			 * If there is no real vnode pointer, but there is
			 * a stream pointer, this may be a stream.  Follow
			 * the stream to its head, then to its module name.
			 * If there is a name, then call this a stream.
			 */
			    if (v.v_stream && 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]) {
				    (void) strcpy(Namech, "STR:");
				    j = strlen(Namech);
				    if ((dp = lkupdev((dev_t *)&s.s_dev, 0))
				    != NULL) {
					(void) strcpy(&Namech[j], 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);
				    }
				    Lf->is_stream = 1;
				    Ntype = N_STREAM;
				}
			    }
			}
			break;
		}
		if (!v.v_data || readinode((struct inode *)v.v_data, &i)) {
			(void) sprintf(Namech,
				"vnode at %#x: can't read inode (%#x)",
				va, v.v_data);
			enter_nm(Namech);
			return;
		}
	}
/*
 * Get device and type for printing.
 */
	switch(Ntype) {
	case N_NFS:
		dev = r.r_attr.va_fsid;
		break;
	case N_STREAM:
		dev = (dev_t)s.s_dev;
		break;
	default:
		dev = (v.v_type == VCHR || ni) ? v.v_rdev : i.i_dev;
		break;
	}
	type = v.v_type;
	if (vfs && vfs->dir == NULL)
		(void) completevfs(vfs, &dev);
/*
 * Obtain the inode number.
 */
	switch (Ntype) {
	case N_FIFO:
		if (ft == 1 && !ni) {
			Lf->inode = (unsigned long)i.i_number;
			Lf->inp_ty = 1;
		}
		break;
	case N_NFS:
		Lf->inode = (unsigned long)r.r_attr.va_nodeid;
		Lf->inp_ty = 1;
		break;
	case N_REGLR:
		if (!ni) {
			Lf->inode = (unsigned long)i.i_number;
			Lf->inp_ty = 1;
		}
	}
/*
 * Obtain the file size.
 */
	if (Foffset)
		Lf->off_def = 1;
	else {
		switch (Ntype) {
		case N_FIFO:
			if (!Fsize && ft == 3) {
				Lf->off = (unsigned long)
					  (Lf->access == 'r') ? f.fn_rptr
							      : f.fn_wptr;
				Lf->off_def = 1;
			}
			break;
		case N_NFS:
			Lf->sz = (unsigned long)r.r_attr.va_size;
			Lf->sz_def = 1;
			break;
		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 && !Fsize)
				Lf->off_def = 1;
			break;
		case N_STREAM:
			if (!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) {
		if (ft <= 1 || Ntype != N_FIFO) {
			Lf->fsdir = vfs->dir;
			Lf->fsdev = vfs->fsname;

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

		}
	}
/*
 * 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 = Lf->is_chr_dev = 1;
		ty = "VCHR";
		break;
	case VLNK:
		ty = "VLNK";
		break;

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

	case VBAD:
		ty = "VBAD";
		break;
	case VFIFO:
		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 this is a VCHR file and it's missing an inode number, try to
 * supply one.
 */
	if (Lf->inp_ty == 0 && type == VCHR && 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);
}
