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


#include "lsof.h"

#define	KERNEL
#include <sys/fs_types.h>
#undef	KERNEL


/*
 * process_node() - process gnode
 */

void
process_node(ga)
	caddr_t ga;			/* vnode kernel space address */
{
	struct fs_data f;
	struct gnode g;
	MALLOC_S l;
	struct mount m;
	struct mntinfo *mi;
	char *tn;
	enum vtype type;
	struct v_fs_data *vf;
	struct vnode *v = NULL;

# if	ULTRIXV>=40200
	char dev_ch[32];
	struct fifonode fn;
# endif

/*
 * Read the gnode.
 */
	if ( ! ga) {
		enter_nm("no gnode address");
		return;
	}
	if (readgnode(ga, &g)) {
		enter_nm(Namech);
		return;
	}

# if	defined(HASNCACHE)
	Lf->id = (unsigned long)g.g_id;
	Lf->na = (unsigned long)ga;
# endif	/* defined(HASNCACHE) */

/*
 * Determine the node type from the operations switch.
 */
	if (g.g_ops) {
		if (Nl[X_NFS_OPS].n_value != NULL
		&&   g.g_ops == (struct gnode_ops *)Nl[X_NFS_OPS].n_value)
			Ntype = N_NFS;

# if	ULTRIXV>=40200
		else if (Nl[X_CDFS_OPS].n_value != NULL
		&&  g.g_ops == (struct gnode_ops *)Nl[X_CDFS_OPS].n_value)
			Ntype = N_CDFS;
		else if (Nl[X_FIFO_OPS].n_value != NULL
		&&  g.g_ops == (struct gnode_ops *)Nl[X_FIFO_OPS].n_value)
			Ntype = N_FIFO;
		else if (Nl[X_UFS_OPS].n_value != NULL
		&&   g.g_ops == (struct gnode_ops *)Nl[X_UFS_OPS].n_value)
			Ntype = N_UFS;
# endif	/* ULTRIXV>=40200 */

	}
/*
 * Determine the lock type.
 */
	if (g.g_shlockc || g.g_exlockc) {
		if (g.g_shlockc && g.g_exlockc)
			Lf->lock = 'u';
		else if (g.g_shlockc)
			Lf->lock = 'R';
		else
			Lf->lock = 'W';
	}
/*
 * Get the mount structure and its fs_data structure.
 * (Ultrix 4.2 and above N_FIFO nodes don't have a mount structure.)
 */
	if (Ntype != N_FIFO) {
		if (g.g_mp == NULL
		||  kread((KA_T)g.g_mp, (char *)&m, sizeof(m))) {
			(void) sprintf(Namech, "bad mount for %#x at %#x",
				ga, g.g_mp);
			enter_nm(Namech);
			return;
		}
		if (m.m_fs_data == NULL
		||  kread((KA_T)m.m_fs_data, (char *)&f, sizeof(f))) {
			(void) sprintf(Namech,
				"bad fsdata (%#x) for mount at %#x ",
				m.m_fs_data, g.g_mp);
			enter_nm(Namech);
			return;
		}
	} else
		f.fd_path[0] = f.fd_devname[0] = '\0';
/*
 * If there is a further node, access it.
 */
	switch (Ntype) {

# if	ULTRIXV>=40200
	case N_FIFO:
		if (g.g_fifo == NULL
		||  kread((KA_T)g.g_fifo, (char *)&fn, sizeof(fn))) {
			(void) sprintf(Namech, "bad fifonode address (%#x)",
				g.g_fifo);
			(void) strcpy(Lf->type,
				((g.g_mode & GFMT) == GFPIPE) ? "PIPE"
							      : "FIFO");
			enter_nm(Namech);
		}
		break;
# endif	/* ULTRIXV>=40200 */

	case N_NFS:
		v = (struct vnode *)&g;
		vf = (struct v_fs_data *)&f;
		mi = (struct mntinfo *)&vf->fd_un.gvfs.mi;
	}
/*
 * Set the device and type for printing.
 */
	Lf->dev = g.g_dev;
	Lf->dev_def = 1;
	switch (Ntype) {
	case N_NFS:
		type = v->v_type;
		switch (v->v_type) {
		case VNON:
			tn = "VNON";
			break;
		case VREG:
			tn = "VREG";
			break;
		case VDIR:
			tn = "VDIR";
			break;
		case VBLK:
			tn = "VBLK";
			break;
		case VCHR:
			tn = "VCHR";
			Lf->dev = g.g_rdev;
			Lf->is_chr_dev = 1;
			break;
		case VLNK:
			tn = "VLNK";
			break;
		case VSOCK:
			tn = "VSOCK";
			break;
		case VBAD:
			tn = "VBAD";
			break;
		case VFIFO:
			tn = "VFIFO";
			break;
		default:
			tn = "VNON";
			break;
		}
		break;
	default:
		switch (g.g_mode & GFMT) {
		case GFPORT:
			tn = "PORT";
			type = VFIFO;
			break;
		case GFCHR:
			tn = "GCHR";
			type = VCHR;
			Lf->dev = g.g_rdev;
			Lf->is_chr_dev = 1;
			break;
		case GFDIR:
			tn = "GDIR";
			type = VDIR;
			break;
		case GFBLK:
			tn = "GBLK";
			type = VBLK;
			break;
		case GFREG:
			tn = "GREG";
			type = VREG;
			break;
		case GFLNK:
			tn = "GLNK";
			type = VLNK;
			break;
		case GFSOCK:
			tn = "SOCK";
			type = VSOCK;
			break;

# if	ULTRIXV>=40200
		case GFPIPE:
			Lf->dev_def = 0;
			(void) sprintf(dev_ch, "0x%08x", g.g_fifo);
			enter_dev_ch(dev_ch);
			tn = "PIPE";
			type = VFIFO;
			break;
# endif	/* ULTRIXV>=40200 */

		default:
			tn = "GNON";
			type = VNON;
		}
		break;
	}
	(void) strcpy(Lf->type, tn);
/*
 * Obtain the inode number.
 */
	if (Ntype != N_FIFO) {
		Lf->inode = (unsigned long)g.g_number;
		Lf->inp_ty = 1;
	}
/*
 * Obtain the file size.
 */
	if (Foffset)
		Lf->off_def = 1;
	else {

# if	ULTRIXV>=40200
		if (type == N_FIFO) {
			Lf->sz = (unsigned long)
				 (Lf->access == 'r') ? fn.fn_rptr : fn.fn_wptr;
			Lf->sz_def = 1;
		} else
# endif	/* ULTRIXV>=40200 */

		if (type == VREG || type == VDIR) {
			Lf->sz = (unsigned long)g.g_size;
			Lf->sz_def = 1;
		} else if (type == VCHR && !Fsize)
			Lf->off_def = 1;
	}
/*
 * Record an NFS file selection.
 */
	if (Ntype == N_NFS && Fnfs)
		Lf->sf |= SELNFS;
/*
 * Save the file system names.
 */
	if (f.fd_path[0] && (l = strlen(f.fd_path)) > 0) {
		if ((Lf->fsdir = (char *)malloc(l + 1)) == NULL) {
			(void) fprintf(stderr,
				"%s: no fs_data path name space, PID %d\n",
				Pn, Lp->pid);
			exit(1);
		}
		(void) strcpy(Lf->fsdir, f.fd_path);
	} else
		Lf->fsdir = NULL;
	if (f.fd_devname[0] && (l = strlen(f.fd_devname)) > 0) {
		if ((Lf->fsdev = (char *)malloc(l + 1)) == NULL) {
			(void) fprintf(stderr,
				"%s: no fs_data path name space, PID %d\n",
				Pn, Lp->pid);
			exit(1);
		}
		(void) strcpy(Lf->fsdev, f.fd_devname);
	} else
		Lf->fsdev = NULL;
/*
 * 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);
}
