ftp.nice.ch/pub/next/unix/file/ofiles.tar.gz#/ofiles/ofiles.c

This is ofiles.c in view mode; [Download] [Up]

/*
 *	ofiles.c - show open files
 */

/*
 * Copyright 1991 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 1991 Purdue Research Foundation.\nAll rights reserved.\n";
#endif

/*
 *	Ofiles displays files opened by processes of the NeXTStep 1.0a and
 *	2.0 systems for the NeXT work station.
 */

/*
 *	Usage:
 *
 *		ofiles [-h] [-n] [-N] [-p] [-P n] [-u] [-U n] [names]
 *
 *	where:
 *
 *		-h	Display help.
 *
 *		-n	Display Internet network files.
 *
 *		-N	Display NFS files.
 *
 *		-p	Display only Process ID numbers.
 *			(disables header)
 *
 *		-P n	Display files for process ID number n.
 *
 *		-u	Display Unix domain sockets.
 *
 *		-U n	Display files for User ID number n.
 *
 *		names	are the names of files to locate.
 */

/*
 * Compile options:
 *
 *	NS=xx	where xx is the NeXTStep version
 *			10 for version 1.0a
 *			20 for version 2.0
			(No other NeXTStep versions have been tested.)
 *
 *	VMUNIX	is the path to the kernel name list file
 *
 * See the Makefile for ways to supply these options.
 *
 */

#ifndef	MACH
#define MACH	1			/* for proper vnode definition */
#endif
#ifndef	NCPUS
#define NCPUS	1			/* number of CPU's */
#endif
#ifndef	NS
#define	NS	20			/* NeXTStep version */
#endif
#ifndef	VMUNIX
#define	VMUNIX	"/mach"			/* namelist file path */
#endif

#include <sys/param.h>
#include <c.h>
#include <errno.h>
#include <setjmp.h>
#include <signal.h>
#include <stdlib.h>
#include <stdio.h>
#include <mntent.h>
#include <string.h>
#include <nlist.h>

#if	NS<20
#include <sys/queue.h>
#else	/* NS>=20 */
#include <kern/queue.h>
#endif
#ifndef	KERNEL
#define	KERNEL
#endif
#include <sys/file.h>
#undef	KERNEL
#if	NS>=20
#include <sys/policy.h>
#endif
#ifndef	SHOW_UTT
#define	SHOW_UTT
#endif
#if	NS<20
#include "NS_1.0a_user.h"
#else	/* NS>=20 */
#include <sys/user.h>
#endif
#undef	SHOW_UTT
#include <sys/dir.h>
#include <sys/domain.h>
#include <sys/mbuf.h>
#include <sys/proc.h>
#include <sys/protosw.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
#include <sys/stat.h>
#if	NS>=20
#include <sys/ucred.h>
#endif
#include <sys/un.h>
#include <sys/unpcb.h>
#include <sys/vfs.h>
#include <sys/vnode.h>
#include <ufs/inode.h>
#if	NS<20
#include <sys/task.h>
#else	/* NS>=20 */
#include <kern/task.h>
#endif
#include <net/route.h>
#include <netinet/in.h>
#include <netinet/in_pcb.h>
#include <rpc/rpc.h>
#include <rpc/xdr.h>
#include <nfs/nfs.h>
#include <nfs/nfs_clnt.h>
#include <nfs/rnode.h>

extern int errno;
extern char *optarg;
extern int optind;
extern char *sys_errlist[];

static struct nlist nl[] = {
	{ {"_allproc"},      0, 0, 0 },
#define X_ALLPROC				0
	{ {"_nfs_vnodeops"}, 0, 0, 0},
#define X_NFS_OPS				1
	{  {""}, 	     0, 0, 0  },
};

#define	DEVINCR		1024	/* device table malloc() increment */
#define STATTMO		5	/* stat() timeout (seconds) */

char *Command;			/* command name */
dev_t Dev;			/* device number */
char Devch[32];			/* alternate characters for device printing */

struct dev {
	int key;		/* ((mode & S_IFMT) << 4) + (dev_t & 0xffff) */
	char *name;		/* /dev/<name> */

} *Devtp = NULL;		/* device table pointer */

char Fd[4];			/* file descriptor for printing */
int Fdev = 0;			/* have device number flag */
int Fhelp = 0;			/* -h flag status */
int Fnet = 0;			/* -n flag status */
int Fnfs = 0;			/* -N flag status */
int Fprint = 0;			/* print line flag */
int Fproc = 0;			/* -p flag status */
int Fpid = 0;			/* -P flag status */
int Fuid = 0;			/* -U flag status */
int Funix = 0;			/* -u flag status */
int Hdr = 0;			/* header print status */
int Inode = -1;			/* inode number (-1 if none) */
int Kmem = -1;			/* /dev/kmem fd */
int Lock = 0;			/* exclusive/shared lock count */
char Namech[1024];		/* name characters for printing */

struct mounts {
	char *dir;		/* directory */
	char *fsname;		/* file system */
	struct mounts *next;	/* forward link */
	dev_t dev;		/* device */

} *Mtab = NULL;			/* mounted devices */

int Ndev = 0;			/* number of device table entries */
struct dev **Sdev = NULL;	/* pointer to device table pointers, sorted
				 * by key */

struct sfile {
	char *name;		/* file name */
	dev_t dev;		/* device */
	u_short mode;		/* mode */
	ino_t i;		/* inode number */
	int f;			/* file found flag */
	struct sfile *next;	/* link to next entry */

} *Sfile = NULL;		/* chain of files to search for */

int Spid;			/* Process ID to search for */
int Suid;			/* User ID to search for */
int Pid;			/* Process ID */
char *Pn;			/* program name */
jmp_buf Tmo_jbuf;		/* stattimeout jump buffer */
char Type[5];			/* type for printing */
int Uid;			/* User ID */

int compdev(), printmnt();

char *endnm();

void printdevname(), printfile(), printinaddr(), printiproto(),
     printline(), printrnode(), printsocket(), printvnode(),
     readdev(), readmnt(), stattimeout();

main(argc, argv)
	int argc;
	char *argv[];
{
	int c, err, i, nb, ndev;
	struct file f;
#if	NS>=20
	struct file **ofp = NULL;
#endif
	struct proc *np, p, *procp;
	struct sfile *sfp;
	struct stat sb;
	struct task t;
	struct utask ut;
/*
 * Save program name for messages.
 */
	if ((Pn = strrchr(argv[0], '/')) != NULL)
		Pn++;
	else
		Pn = argv[0];
/*
 * Process arguments.
 */
	while ((c = getopt(argc, argv, "hnNpP:uU:")) != EOF) {
		switch(c) {

		case 'h':
			Fhelp = 1;
			break;
		case 'n':
			Fnet = 1;
			break;
		case 'N':
			Fnfs = 1;
			break;
		case 'p':
			Fproc = 1;
			break;
		case 'P':
			Fpid = 1;
			Spid = atoi(optarg);
			break;
		case 'u':
			Funix = 1;
			break;
		case 'U':
			Fuid = 1;
			Suid = atoi(optarg);
			break;
		case '?':
			err++;
			break;
		default:
			(void) fprintf(stderr, "%s: unknown option (%c)\n",
				Pn, c);
			err++;
		}
	}
/*
 * Process any file names.
 */
	for (i = optind; i < argc; i++) {
		if (stat(argv[i], &sb) != 0) {
			(void) fprintf(stderr, "%s: can't find %s: %s\n",
				Pn, argv[i], sys_errlist[errno]);
			err++;
			continue;
		}
		if ((sfp = (struct sfile *)malloc(sizeof(struct sfile)))
		== NULL) {
			(void) fprintf(stderr, "%s: no space for files\n", Pn);
			exit(1);
		}
		sfp->next = Sfile;
		Sfile = sfp;
		sfp->name = argv[i];
		if ((sfp->mode = (sb.st_mode & S_IFMT)) == S_IFCHR
		||   sfp->mode == S_IFBLK
		||   (sb.st_dev & 0x8000))
			sfp->dev = sb.st_rdev;
		else
			sfp->dev = sb.st_dev;
		sfp->i = sb.st_ino;
		sfp->f = 0;
	}
/*
 * Display usage if error or if requested.
 */
	if (err || Fhelp) {
	    (void) fprintf(stderr,
		"%s usage: [-h] [-n] [-N] [-p] [-P n] [-u] [-U n]", Pn);
	    (void) fprintf(stderr,
		" [names]\n");
	    (void) fprintf(stderr,
		"\t-h     display help\n");
	    (void) fprintf(stderr,
		"\t-l n   set lines per header to n (0 for no header)");
	    (void) fprintf(stderr,
		"\t-n     display Internet network files\n");
	    (void) fprintf(stderr,
		"\t-N     display NFS files\n");
	    (void) fprintf(stderr,
		"\t-p     display only Process ID numbers (disables header)\n");
	    (void) fprintf(stderr,
		"\t-P n   display files for process ID number n\n");
	    (void) fprintf(stderr,
		"\t-u     display Unix domain sockets\n");
	    (void) fprintf(stderr,
		"\t-U n   display files for User ID number n\n");
	    (void) fprintf(stderr,
		"\tnames  of files to locate\n");
	    if (err)
		exit(1);
	    exit(0);
	}
/*
 * Open /dev/kmem and read selected names from VMUNIX.
 *
 * Read and build device and mount tables.
 */
	if ((Kmem = open("/dev/kmem", O_RDONLY, 0)) < 0) {
		(void) fprintf(stderr, "%s: can't open /dev/kmem: %s\n",
			Pn, sys_errlist[errno]);
		exit(1);
	}
	if (nlist(VMUNIX, nl) == -1) {
		(void) fprintf(stderr, "%s: can't read namelist\n", Pn);
		exit(1);
	}
	if (nl[X_ALLPROC].n_value == 0l) {
		(void) fprintf(stderr, "%s: no address for %s\n",
			Pn, nl[X_ALLPROC].n_un.n_name);
		exit(1);
	}
	if (kread((off_t)nl[X_ALLPROC].n_value, (char *)&procp, sizeof(procp))
	!= sizeof(procp)) {
		(void) fprintf(stderr,
			"%s: can't read nl[X_ALLPROC].n_un.n_name: %s\n",
			Pn, sys_errlist[errno]);
		exit(1);
	}
	(void) readdev();
	(void) readmnt();
/*
 * Read the processes on the "all processes" list.
 */
	for(np = procp; np; np = p.p_nxt) {
		if (kread((off_t) np, &p, sizeof(p)) != sizeof(p)) {
			(void) fprintf(stderr,
				"%s: can't read proc struct at %x\n",
				Pn, np);
			exit(1);
		}
		if (Fpid && p.p_pid != Spid)
			continue;
	/*
	 * Read the task associated with the process, and the user
	 * area assocated with the task.
	 */
		if (kread((off_t) p.task, &t, sizeof(t)) != sizeof(t))
			continue;
		if ((struct proc *)t.proc != np)
			continue;
		if (kread((off_t) t.u_address, &ut, sizeof(ut)) != sizeof(ut))
			continue;
		if ((struct proc *)ut.uu_procp != np)
			continue;
		if (Fuid && Suid != p.p_uid)
			continue;
	/*
	 * Print information on the current directory.
	 */
		if (ut.uu_cdir) {
			Command = ut.uu_comm;
			Fdev = 0;
			Devch[0] = Type[0] = '\0';
			(void) strcpy(Fd, "cd");
			Fprint = (Fnet || Fnfs || Funix || Sfile) ? 0 : 1;
			Inode = -1;
			Lock = 0;
			Namech[0] = '\0';
			Pid = p.p_pid;
			Uid = p.p_uid;
			printvnode(ut.uu_cdir);
		}
#if	NS>=20
	/*
	 * Get the file pointers from the user area.
	 */
		if (ofp != NULL)
			(void) free(ofp);
		nb = sizeof(struct file) * ut.uu_ofile_cnt;
		if ((ofp = (struct file **)malloc((size_t)nb)) == NULL) {
			(void) fprintf(stderr,
				"%s: no file table space, process %d\n",
				Pn, p.p_pid);
			exit(1);
		}
		if (kread((off_t) ut.uu_ofile, ofp, nb) != nb)
			continue;
#endif
	/*
	 * Print information on all the files referenced from the user area.
	 */
#if	NS>=20
		for (i = 0; i < ut.uu_ofile_cnt; i++) {
			if (ofp[i]) {
#else	/* NS<20 */
		for (i = 0; i < NOFILE; i++) {
			if (ut.uu_ofile[i]) {
#endif
				Command = ut.uu_comm;
				Fdev = 0;
				Devch[0] = Type[0] = '\0';
				(void) sprintf(Fd, "%2d", i);
				Fprint = (Fnet || Fnfs || Funix || Sfile) ? 0
									  : 1;
				Inode = -1;
				Lock = 0;
				Namech[0] = '\0';
				Pid = p.p_pid;
				Uid = p.p_uid;
#if	NS>=20
				printfile(ofp[i]);
#else	/* NS<20 */
				printfile(ut.uu_ofile[i]);
#endif
			}
		}
	}
	for (sfp = Sfile; sfp; sfp = sfp->next) {
		if (sfp->f == 0)
			exit(1);
	}
	exit(0);
}


/*
 * compdev() - compare device numbers
 */

compdev(p1, p2)
	struct dev **p1;
	struct dev **p2;
{
	if ((*p1)->key < (*p2)->key)
		return(-1);
	if ((*p1)->key == (*p2)->key)
		return(0);
	return(1);
}


/*
 * endnm() - locate end of Namech
 */

char *
endnm()
{
	char *s;

	for (s = Namech; *s; s++)
		;
	return(s);
}


/*
 * isfile() - is file selected for printing
 */

isfile(d, i)
	dev_t d;			/* device */
	ino_t i;		 	/* inode */
{
	struct sfile *s;

	for (s = Sfile; s; s = s->next) {
		if (d == s->dev) {
			if (s->mode == S_IFCHR || s->mode == S_IFBLK
			|| i == s->i) {
				(void) strcat(Namech, s->name);
				s->f = 1;
				return(1);
			}
		}
	}
	return(0);
}


/*
 * kread() - read from kernel memory
 */

kread(addr, buf, len)
	off_t addr;			/* kernel memory address */
	char *buf;			/* buffer to receive data */
	int len;			/* length to read */
{
	if (lseek(Kmem, addr, L_SET) < 0)
		return(-1);
	return(read(Kmem, buf, len));
}

/*
 * printdevname() - print device name
 */

void
printdevname(mode, rdev)
	u_short mode;			/* S_IFMT mode */
	dev_t rdev;			/* device */
{
	int key, low, hi, mid;
	struct dev *dp;

	key = (mode << 4) + (rdev & 0xffff);
	low = mid = 0;
	hi = Ndev;
        while (low <= hi) {
                mid = (low + hi) / 2;
		dp = Sdev[mid];
		if (key < dp->key)
                        hi = mid - 1;
                else if (key > dp->key)
                        low = mid + 1;
                else {
			(void) sprintf(Namech, "/dev/%s", dp->name);
			return;
		}
        }
	(void) strcpy(Namech, "name unknown");
}


/*
 * printfile() - print file information
 */

void
printfile(fp)
	struct file *fp;		/* kernel file table address */
{
	struct file f;

	if (kread((off_t) fp, (char *) &f, sizeof(f)) != sizeof(f)) {
		(void) sprintf(Namech, "can't read file struct from %x", fp);
	} else {
		if (f.f_count) {
			if (f.f_type == DTYPE_VNODE) {
				printvnode(f.f_data);
			} else {
				printsocket(f.f_data);
			}
		}
	}
	return;
}


/*
 * printinaddr() - print Internet address
 */

void
printinaddr(ia, p)
	struct in_addr *ia;		/* Internet address */
	u_short p;			/* port */
{
	unsigned char *u;

	if (ia->s_addr == INADDR_ANY) {
		(void) sprintf(endnm(), "*:%d", p);
		return;
	}
	u = (unsigned char *) ia;
	(void) sprintf(endnm(), "%u.%u.%u.%u:%u", u[0], u[1], u[2], u[3], p);
}


/*
 * printiproto(p) - print Internet protocol name
 */

void
printiproto(p)
	int p;				/* protocol number */
{
	char *s;

	switch(p) {
#ifdef IPPROTO_TCP
	case IPPROTO_TCP:
		s = "TCP";
		break;
#endif
#ifdef IPPROTO_UDP
	case IPPROTO_UDP:
		s = "UDP";
		break;
#endif
#ifdef IPPROTO_IP
	case IPPROTO_IP:
		s = "IP";
		break;
#endif
#ifdef IPPROTO_ICMP
	case IPPROTO_ICMP:
		s = "ICMP";
		break;
#endif
#ifdef IPPROTO_IGMP
	case IPPROTO_IGMP:
		s = "IGMP";
		break;
#endif
#ifdef IPPROTO_GGP
	case IPPROTO_GGP:
		s = "GGP";
		break;
#endif
#ifdef IPPROTO_EGP
	case IPPROTO_EGP:
		s = "EGP";
		break;
#endif
#ifdef IPPROTO_PUP
	case IPPROTO_PUP:
		s = "PUP";
		break;
#endif
#ifdef IPPROTO_IDP
	case IPPROTO_IDP:
		s = "IDP";
		break;
#endif
#ifdef IPPROTO_ND
	case IPPROTO_ND: return "nd";
		s = "ND";
		break;
#endif
#ifdef IPPROTO_RAW
	case IPPROTO_RAW:
		s = "RAW";
		break;
#endif
	default:
		s = "unknown";
	}
	(void) sprintf(Devch, "%8.8s", s);
}


/*
 * printmnt(dev) - print mount entry for device
 */

printmnt(rdev)
	dev_t rdev;			/* device */
{
	struct mounts *mtp;

	if (rdev & 0x8000)
		rdev |= 0xff00;
	for (mtp = Mtab; mtp; mtp = mtp->next) {
		if (rdev == mtp->dev) {
			(void) sprintf(Namech, "%s (%s)", mtp->dir,
				mtp->fsname);
			return(1);
		}
	}
	return(0);
}


/*
 * printrnode() - print NFS information from rnode
 */

void
printrnode(vp)
	struct vnode *vp;
{
	struct inode ic;
	struct mntinfo m;
	struct rnode r;
	char *s;
	struct vfs v;
	struct vnode vc;
/*
 * Read associated rnode, vfs structure and mntinfo structures.
 */
	if (vp->v_vfsp == NULL) {
		(void) sprintf(Namech, "no vfs address in %x", vp);
		printline();
		return;
	}
	if (kread((off_t) vp->v_data, &r, sizeof(r)) != sizeof(r)) {
		(void) sprintf(Namech, "can't read rnode at %x", vp->v_data);
		printline();
		return;
	}
	if (kread((off_t) vp->v_vfsp, &v, sizeof(v)) != sizeof(v)) {
		(void) sprintf(Namech, "can't read vfs at %x", vp->v_vfsp);
		printline();
		return;
	}
	if (v.vfs_data == NULL) {
		(void) sprintf(Namech, "no mntinfo address in %x", vp->v_vfsp);
		printline();
		return;
	}
	if (kread((off_t) v.vfs_data, &m, sizeof(m)) != sizeof(m)) {
		(void) sprintf(Namech, "can't read mntinfo at %x", v.vfs_data);
		printline();
		return;
	}
	if (Fnfs)
		Fprint = 1;
	else if (Sfile)
#if	NS<20
		Fprint = isfile((dev_t)(r.r_nfsattr.na_rdev & 0xffff),
			        (ino_t)r.r_nfsattr.na_nodeid);
#else	/* NS>=20 */
		Fprint = isfile(vp->v_rdev, (ino_t)r.r_attr.va_nodeid);
#endif
	if (Namech[0] == '\0')
#if	NS<20
		(void) sprintf(Namech, "%s (%s)", v.vfs_name, m.mi_hostname);
#else	/* NS>=20 */
		(void) printmnt((dev_t)r.r_attr.va_fsid);
#endif
/*
 * If the vfs structure covers another vnode (the mount point), and we
 * don't know the file name, read the covered vnode and associated inode.
 */
	if (v.vfs_vnodecovered && Namech[0] == '\0') {
		if (kread((off_t) v.vfs_vnodecovered, &vc, sizeof(vc))
		== sizeof(vc)) {
			if (vc.v_type == VDIR && vc.v_data) {
				if (kread((off_t) vc.v_data, &ic, sizeof(ic))
				== sizeof(ic)) {
					printdevname(S_IFBLK, ic.i_dev);
					(void) sprintf(endnm(), "%s (%s)",
						Namech[0] ? "" : "NFS",
						m.mi_hostname);
				}
			}
		}
	}
/*
 * Display the remote device, remote inode and host name.
 */
#if	NS<20
	Dev = (dev_t)r.r_nfsattr.na_fsid;
#else	/* NS>=20 */
	Dev = (dev_t)r.r_attr.va_fsid;
#endif
	Fdev = 1;
#if	NS<20
	Inode = (ino_t)r.r_nfsattr.na_nodeid;
#else	/* NS>=20 */
	Inode = (ino_t)r.r_attr.va_nodeid;
#endif
	if (Namech[0] == '\0')
		(void) sprintf(endnm(), "NFS (%s)", m.mi_hostname);
	printline();
}


/*
 * printline() - print output line
 */

void
printline()
{
	if (Fprint == 0)
		return;
	if (Fproc) {
		(void) printf("%d\n", Pid);
		return;
	}
	if (Hdr == 0) {
		(void) printf("COMMAND   PID   UID FD TYPE   DEVICE INODE");
		(void) printf(" NAME/[LOCAL][REMOTE]\n");
	}
	Hdr++;
	(void) printf("%-7.7s %5d %5d %2s%c%4.4s ",
			Command,
			Pid,
			Uid,
			Fd,
			Lock ? '*' : ' ',
			Type
	);
	if (Fdev)
		(void) printf(" %3d,%3d ", (Dev >> 8) & 0xff, Dev &0xff);
	else {
		if (Devch[0])
			(void) printf("%8.8s ", Devch);
		else
			(void) printf("         ");
	}
	if (Inode >= 0)
		(void) printf("%5d ", Inode);
	else
		(void) printf("      ");
	(void) printf("%s\n", Namech);
}


/*
 * printsocket(sp) - print socket
 */

void
printsocket(sp)
	caddr_t *sp;			/* socket's kernel address */
{
	struct domain d;
	struct inode i;
	struct inpcb inp;
	int is = 0;
	struct mbuf mb;
	struct protosw p;
	struct socket s;
	char *sep;
	struct sockaddr_un *ua;
	struct unpcb uc, unp;
	struct vnode v;
/*
 * Read the socket, the associated protocol switch table entry, and the
 * associated domain structure.
 */
	(void) strcpy(Type, "sock");
	if (kread((off_t) sp, (char *) &s, sizeof(s)) != sizeof(s)) {
		(void) sprintf(Namech, "can't read socket struct from %x", sp);
		printline();
		return;
	}
	if (kread((off_t) s.so_proto, (char *) &p, sizeof(p)) != sizeof(p)) {
		(void) sprintf(Namech, "can't read protosw struct from %x",
			s.so_proto);
		printline();
		return;
	}
	if (kread((off_t) p.pr_domain, (char *) &d, sizeof(d)) != sizeof(d)) {
		(void) sprintf(Namech, "can't read domain struct from %x",
			p.pr_domain);
		printline();
		return;
	}
/*
 * Process socket by the associated domain family.
 */
	switch (d.dom_family) {

	case AF_INET:
		if (Fnet)
			Fprint = 1;
		(void) strcpy(Type, "inet");
	/*
	 * Read Internet protocol control block.
	 */
		if (kread((off_t) s.so_pcb, (char *) &inp, sizeof(inp))
		!= sizeof(inp))
			return;
		if ((struct socket *)sp != inp.inp_socket)
			return;
		printiproto(p.pr_protocol);
		if (inp.inp_laddr.s_addr != INADDR_ANY || inp.inp_lport != 0) {
			printinaddr(&inp.inp_laddr, inp.inp_lport);
			sep = "->";
		} else
			sep = "";
		if (inp.inp_faddr.s_addr != INADDR_ANY || inp.inp_fport != 0) {
			(void) sprintf(endnm(), "%s", sep);
			printinaddr(&inp.inp_faddr, inp.inp_fport);
		}
		break;

	case AF_UNIX:
		if (Funix)
			Fprint = 1;
		(void) strcpy(Type, "unix");
	/*
	 * Read Unix protocol control block and the Unix address structure.
	 */
		(void) sprintf(Devch, "%8x", sp);
		if (kread((off_t) s.so_pcb, (char *) &unp, sizeof(unp))
		!= sizeof(unp)) {
			(void) sprintf(Namech, "can't read unpcb at %x",
				s.so_pcb);
			break;
		}
		if ((struct socket *)sp != unp.unp_socket) {
			(void) sprintf(Namech, "unp_socket (%x) mismatch",
				unp.unp_socket);
			break;
		}
		if (unp.unp_addr) {
			if (kread((off_t) unp.unp_addr, (char *) &mb,
			    sizeof(mb))
			!= sizeof(mb)) {
				(void) sprintf(Namech,
					"can't read unp_addr at %x",
					unp.unp_addr);
				break;
			}
			ua = (struct sockaddr_un *)(((char *)&mb) + mb.m_off);
		} else {
			ua = (struct sockaddr_un *)&mb;
			(void) bzero((char *)ua, sizeof(struct sockaddr_un));
			ua->sun_family = AF_UNSPEC;
		}
	/*
	 * Print information on Unix socket that has no address bound
	 * to it, although it may be connected to another Unix domain
	 * socket as a pipe.
	 */
		if (ua->sun_family != AF_UNIX) {
			if (ua->sun_family == AF_UNSPEC) {
				if (unp.unp_conn) {
					if (kread((off_t) unp.unp_conn,
						(char *) &uc, sizeof(uc))
					!= sizeof(uc)) {
					    (void) sprintf(Namech,
						"can't read unp_conn at %x",
						unp.unp_conn);
					} else {
					    (void) sprintf(Namech,
						"->unix %8x", uc.unp_socket);
					}
				} else
					(void) strcpy(Namech, "no address");
			} else
				(void) sprintf(Namech,
					"unknown sun_family (%d)",
					ua->sun_family);
			break;
		}
	/*
	 * Read any associated vnode and then read its assocated inode.
	 */
		if (unp.unp_vnode) {
			if (kread((off_t) unp.unp_vnode, &v, sizeof(v))
			== sizeof(v)) {
				if (v.v_type == VSOCK) {
					if (kread((off_t) v.v_data, &i,
					    sizeof(i))
					== sizeof(i))
						is = 1;
				}
			}
		}
	/*
	 * Print Unix socket information.
	 */
		if (is) {
			Dev = i.i_dev;
			Fdev = 1;
			Devch[0] = '\0';
			Inode = i.i_number;
			if (Sfile) {
				if (isfile(i.i_dev, i.i_number))
					Fprint = 1;
				break;
			}
		}
		(void) sprintf(Namech, "%.*s",
			mb.m_len - sizeof(ua->sun_family),
			ua->sun_path[0] ? ua->sun_path : "no address");
		break;

	default:
		(void) strcpy(Type, "sock");
		(void) strcpy(Namech, "unknown");
	}
	printline();
}


/*
 * printvnode() - print vnode
 */

void
printvnode(p)
	caddr_t p;			/* vnode's kernel address */
{
	struct inode i;
	int j;
	struct vnode v;

	if (kread((off_t) p, &v, sizeof(v)) != sizeof(v)) {
		(void) sprintf(Namech, "can't read vnode at %x", v);
		printline();
		return;
	}
	Lock = v.v_shlockc + v.v_exlockc;
	switch (v.v_type) {

	case VNON:
		(void) strcpy(Type, "VNON");
		break;
	case VREG:
	case VDIR:
		(void) strcpy(Type, (v.v_type == VREG) ? "VREG" : "VDIR");
		if (v.v_data == NULL) {
			(void) sprintf(Namech, "no inode/rnode address in %x",
				p);
		    break;
		}
		if (v.v_op == (struct vnodeops *)nl[X_NFS_OPS].n_value) {
			(void) printrnode(&v);
			return;
		}
		if (kread((off_t) v.v_data, &i, sizeof(i)) != sizeof(i)) {
			(void) sprintf(Namech, "can't read inode at %x",
				v.v_data);
		    break;
		}
		Dev = i.i_dev;
		Fdev = 1;
		Inode = i.i_number;
		if (Sfile) {
			if (isfile(i.i_dev, i.i_number))
				Fprint = 1;
			break;
		}
		if (printmnt(i.i_dev) == 0)
			printdevname(S_IFBLK, i.i_dev);
		break;
	case VBLK:
		(void) strcpy(Type, "VBLK");
		break;
	case VCHR:
		Dev = v.v_rdev;
		Fdev = 1;
		(void) strcpy(Type, "VCHR");
		if (Sfile) {
			if (isfile(v.v_rdev, 0))
				Fprint = 1;
			break;
		}
		printdevname(S_IFCHR, v.v_rdev);
		break;
	case VLNK:
		(void) strcpy(Type, "VLNK");
		break;
	case VSOCK:
		(void) strcpy(Type, "VSOCK");
		break;
	case VBAD:
		(void) strcpy(Type, "VBAD");
		break;
	case VFIFO:
		(void) strcpy(Type, "VFIFO");
		break;
	case VSTR:
		(void) strcpy(Type, "VSTR");
		break;
	default:
		(void) sprintf(Type, "%4d", v.v_type);
		(void) strcpy(Namech, "unknown type");
	}
	printline();
	return;
}


/*
 * readdev() - read names, modes and device types of everything in /dev
 */

void
readdev()
{
	DIR *dfp;
	struct direct *dp;
	u_short mode;
	int err, i;
	char path[MAXNAMLEN+1];
	struct stat sb;

	if ((dfp = opendir("/dev")) == NULL) {
		(void) fprintf(stderr, "%s: can't open /dev\n", Pn);
		exit(1);
	}
	(void) strcpy(path, "/dev/");
	for (err = i = 0, dp = readdir(dfp); dp; dp = readdir(dfp)) {
		if (dp->d_fileno == 0)
			continue;
		if (dp->d_name[0] == '.')
			continue;
		(void) strcpy(&path[5], dp->d_name);
		if (stat(path, &sb) != 0) {
			(void) fprintf(stderr, "%s: can't stat %s: %s\n",
				Pn, path, sys_errlist[errno]);
			err++;
			continue;
		}
		if ((mode = (sb.st_mode & S_IFMT)) != S_IFCHR
		&&   mode != S_IFBLK)
			continue;
		if (i >= Ndev) {
			Ndev += DEVINCR;
			if (Devtp == NULL)
				Devtp = (struct dev *)malloc(
				      (size_t)((sizeof(struct dev)) * Ndev));
			else
				Devtp = (struct dev *)realloc((void *)Devtp,
				      (size_t)(sizeof(struct dev) * Ndev));
			if (Devtp == NULL) {
				(void) fprintf(stderr,
					"%s: no space for devices\n", Pn);
				exit(1);
			}
		}
		Devtp[i].key = (mode << 4) + (sb.st_rdev & 0xffff);
		if ((Devtp[i].name = (char *)malloc((unsigned)(dp->d_namlen+1)))
		== NULL) {
			(void) fprintf(stderr, "%s: no space for /dev/%s\n",
				Pn, dp->d_name);
			exit(1);
		}
		(void) strcpy(Devtp[i].name, dp->d_name);
		i++;
	}
	if (Ndev > i) {
		Ndev = i;
		Devtp = (struct dev *)realloc((void *)Devtp,
		      (size_t)(sizeof(struct dev) * Ndev));
	}
	(void) closedir(dfp);
	if (err)
		exit(1);
	if ((Sdev = (struct dev **)malloc((size_t)(sizeof(struct dev *)
	    * Ndev)))
	== NULL) {
		(void) fprintf(stderr, "%s: no space for device pointers\n",
			Pn);
		exit(1);
	}
	for (i = 0; i < Ndev; i++) {
		Sdev[i] = &Devtp[i];
	}
	(void) qsort((void *)Sdev, (size_t)Ndev, (size_t)sizeof(struct dev *),
		compdev);
}


/*
 * readmnt() - read mount table
 */

void
readmnt()
{
	int err = 0;
	FILE *mfp;
	struct mntent *mp;
	struct mounts *mtp;
	struct stat sb;

        if ((mfp = setmntent(MOUNTED, "r")) == NULL) {
                (void) fprintf(stderr, "%s: can't access %s\n", Pn, MOUNTED);
                exit(1);
        }
        while ((mp = getmntent(mfp)) != NULL) {
                if (statsafely(mp->mnt_dir, &sb, STATTMO))
                        continue;
		if ((mtp = (struct mounts *)malloc(sizeof(struct mounts)))
		== NULL) {
			err = 1;
			break;
		}
		if ((mtp->dir = (char *)malloc(strlen(mp->mnt_dir)+1))
		== NULL) {
			err = 1;
			break;
		}
		(void) strcpy(mtp->dir, mp->mnt_dir);
		if ((mtp->fsname = (char *)malloc(strlen(mp->mnt_fsname)+1))
		== NULL) {
			err = 1;
			break;
		}
		(void) strcpy(mtp->fsname, mp->mnt_fsname);
		mtp->dev = sb.st_dev;
		mtp->next = Mtab;
		Mtab = mtp;
        }
        (void) endmntent(mfp);
	if (err) {
		(void) fprintf(stderr, "%s: no space for mount at %s (%s)\n",
			Pn, mp->mnt_fsname, mp->mnt_dir);
		exit(1);
	}
}


/*
 * statsafely() - stat path safely (i. e., with timeout)
 */

statsafely(path, buf, tm)
        char *path;
        struct stat *buf;
        int tm;
{
        int err;
        static int sverr;

        if (tm == 0)
                return(stat(path, buf));
        sverr = errno;
        if (setjmp(Tmo_jbuf)) {
                (void) alarm(0);
                (void) signal(SIGALRM, SIG_IGN);
                errno = ETIMEDOUT;
                return(-1);
        }
        (void) signal(SIGALRM, stattimeout);
        (void) alarm((unsigned)tm);
        err = stat(path, buf);
        if (err != 0)
                sverr = errno;
        (void) alarm(0);
        (void) signal(SIGALRM, SIG_IGN);
        errno = sverr;
        return(err);
}


/*
 * stattimeout() - time out a stat() call
 */

void
stattimeout()
{
        (void) alarm(0);
        (void) signal(SIGALRM, SIG_IGN);
        longjmp(Tmo_jbuf, 1);
}

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.