summaryrefslogtreecommitdiff
path: root/dialects/darwin/kmem/dnode.c
diff options
context:
space:
mode:
Diffstat (limited to 'dialects/darwin/kmem/dnode.c')
-rw-r--r--dialects/darwin/kmem/dnode.c1038
1 files changed, 1038 insertions, 0 deletions
diff --git a/dialects/darwin/kmem/dnode.c b/dialects/darwin/kmem/dnode.c
new file mode 100644
index 0000000..d634c62
--- /dev/null
+++ b/dialects/darwin/kmem/dnode.c
@@ -0,0 +1,1038 @@
+/*
+ * dnode.c - Darwin node functions for /dev/kmem-based 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.11 2006/03/27 23:24:50 abe Exp $";
+#endif
+
+
+#include "lsof.h"
+
+
+/*
+ * Local function prototypes
+ */
+
+#if DARWINV<600
+_PROTOTYPE(static int lkup_dev_tty,(dev_t *dr, dev_t *rdr, INODETYPE *ir));
+#endif /* DARWINV<600 */
+
+#if DARWINV>=800
+_PROTOTYPE(static char *getvpath,(KA_T va, struct vnode *rv));
+_PROTOTYPE(static int readvname,(KA_T addr, char *buf, int buflen));
+#endif /* DARWINV>=800 */
+
+
+#if DARWINV>=800
+/*
+ * getvpath() - get vnode path
+ * adapted from build_path() (.../bsd/vfs/vfs_subr.c)
+ */
+
+static char *
+getvpath(va, rv)
+ KA_T va; /* kernel address of the rightmost
+ * vnode in the path */
+ struct vnode *rv; /* pointer to rightmost vnode */
+{
+ char *ap;
+ static char *bp = (char *)NULL;
+ static size_t bl = (size_t)(MAXPATHLEN + MAXPATHLEN + 1);
+ static char *cb = (char *)NULL;
+ static size_t cbl = (size_t)0;
+ static int ce = 0;
+ struct mount mb;
+ int pl, vnl;
+ char *pp, vn[MAXPATHLEN+1];
+ struct vnode vb;
+ KA_T vas = va;
+/*
+ * Initialize the path assembly.
+ */
+ if (!bp) {
+ if (!(bp = (char *)malloc((MALLOC_S)bl))) {
+ (void) fprintf(stderr, "%s: no space (%d) for path assembly\n",
+ Pn, (int)bl);
+ Exit(1);
+ }
+ }
+ pp = bp + bl - 1;
+ *pp = '\0';
+ pl = 0;
+/*
+ * Process the starting vnode.
+ */
+ if (!va)
+ return(0);
+ if ((rv->v_flag & VROOT) && rv->v_mount) {
+
+ /*
+ * This is the root of a file system and it has a mount structure.
+ * Read the mount structure.
+ */
+ if (kread((KA_T)rv->v_mount, (char *)&mb, sizeof(mb)))
+ return(0);
+ if (mb.mnt_flag & MNT_ROOTFS) {
+
+ /*
+ * This is the root file system, so the path is "/".
+ */
+ pp--;
+ *pp = '/';
+ pl = 1;
+ goto getvpath_alloc;
+ } else {
+
+ /*
+ * Get the covered vnode's pointer and read it. Use it to
+ * form the path.
+ */
+ if ((va = (KA_T)mb.mnt_vnodecovered)) {
+ if (readvnode(va, &vb))
+ return(0);
+ }
+ }
+ } else {
+
+ /*
+ * Use the supplied vnode.
+ */
+ vb = *rv;
+ }
+/*
+ * Accumulate the path from the vnode chain.
+ */
+ while (va && ((KA_T)vb.v_parent != va)) {
+ if (!vb.v_name) {
+
+ /*
+ * If there is no name pointer or parent, the assembly is complete.
+ */
+ if (vb.v_parent) {
+
+ /*
+ * It is an error if there is a parent but no name.
+ */
+ return((char *)NULL);
+ }
+ break;
+ }
+ /*
+ * Read the name and add it to the assembly.
+ */
+ if ((vnl = readvname((KA_T)vb.v_name, vn, sizeof(vn))) <= 0)
+ return((char *)NULL);
+ if ((vnl + 1 + pl + 1) > bl)
+ return((char *)NULL);
+ memmove((void *)(pp - vnl), (void *)vn, vnl);
+ pp -= (vnl + 1);
+ *pp = '/';
+ pl += vnl + 1;
+ if ((va == vas) && (vb.v_flag & VROOT)) {
+
+ /*
+ * This is the starting vnode and it is a root vnode. Read its
+ * mount structure.
+ */
+ if (vb.v_mount) {
+ if (kread((KA_T)vb.v_mount, (char *)&mb, sizeof(mb)))
+ return((char *)NULL);
+ if (mb.mnt_vnodecovered) {
+
+ /*
+ * If there's a covered vnode, read it and use it's parent
+ * vnode pointer.
+ */
+ if ((va = (KA_T)mb.mnt_vnodecovered)) {
+ if (readvnode(va, &vb))
+ return((char *)NULL);
+ va = (KA_T)vb.v_parent;
+ }
+ } else
+ va = (KA_T)NULL;
+ } else
+ va = (KA_T)NULL;
+ } else
+ va = (KA_T)vb.v_parent;
+ /*
+ * If there's a parent vnode, read it.
+ */
+ if (va) {
+ if (readvnode(va, &vb))
+ return((char *)NULL);
+ if ((vb.v_flag & VROOT) && vb.v_mount) {
+
+ /*
+ * The mount point has been reached. Read the mount structure
+ * and use its covered vnode pointer.
+ */
+ if (kread((KA_T)vb.v_mount, (char *)&mb, sizeof(mb)))
+ return((char *)NULL);
+ if ((va = (KA_T)mb.mnt_vnodecovered)) {
+ if (readvnode(va, &vb))
+ return((char *)NULL);
+ }
+ }
+ }
+ }
+/*
+ * As a special case the following code attempts to trim a path that is
+ * larger than MAXPATHLEN by seeing if the lsof process CWD can be removed
+ * from the start of the path to make it MAXPATHLEN characters or less.
+ */
+ if (pl > MAXPATHLEN) {
+
+ /*
+ * Get the cwd. If that can't be done, return an error.
+ */
+ if (ce)
+ return((char *)NULL);
+ if (!cb) {
+ if (!(cb = (char *)malloc((MALLOC_S)(MAXPATHLEN + 1)))) {
+ (void) fprintf(stderr, "%s: no space (%d) for CWD\n",
+ Pn, (int)bl);
+ Exit(1);
+ }
+ if (!getcwd(cb, (size_t)(MAXPATHLEN + 1))) {
+ if (!Fwarn) {
+ (void) fprintf(stderr, "%s: WARNING: can't get CWD\n",
+ Pn);
+ }
+ ce = 1;
+ return((char *)NULL);
+ }
+ cb[MAXPATHLEN - 1] = '\0';
+ if (!(cbl = (size_t)strlen(cb))) {
+ if (!Fwarn) {
+ (void) fprintf(stderr, "%s: WARNING: CWD is NULL\n",
+ Pn);
+ }
+ ce = 1;
+ return((char *)NULL);
+ }
+ }
+ /*
+ * See if trimming the CWD shortens the path to MAXPATHLEN or less.
+ */
+ if ((pl <= cbl) || strncmp(cb, pp, cbl))
+ return((char *)NULL);
+ pp += cbl;
+ pl -= cbl;
+ if (cb[cbl - 1] == '/') {
+
+ /*
+ * The CWD ends in a '/', so the path must not begin with one. If
+ * it does, no trimming can be done.
+ */
+ if (*pp == '/')
+ return((char *)NULL);
+ } else {
+
+ /*
+ * The CWD doesn't end in a '/', so the path must begin with one.
+ * If it doesn't, no trimming can be done.
+ */
+ if (*pp != '/')
+ return((char *)NULL);
+ /*
+ * Skip all leading path '/' characters. Some characters must
+ * remain.
+ */
+ while ((pl > 0) && (*pp == '/')) {
+ pp++;
+ pl--;
+ }
+ if (!pl)
+ return((char *)NULL);
+ }
+ }
+/*
+ * Allocate space for the assembled path, including terminator, and return its
+ * pointer.
+ */
+
+getvpath_alloc:
+
+ if (!(ap = (char *)malloc(pl + 1))) {
+ (void) fprintf(stderr, "%s: no getvpath space (%d)\n",
+ Pn, pl + 1);
+ Exit(1);
+ }
+ (void) memmove(ap, pp, pl + 1);
+ return(ap);
+}
+#endif /* DARWINV>=800 */
+
+
+#if DARWINV<600
+/*
+ * lkup_dev_tty() - look up /dev/tty
+ */
+
+static int
+lkup_dev_tty(dr, rdr, ir)
+ dev_t *dr; /* place to return device number */
+ dev_t *rdr; /* place to return raw device number */
+ INODETYPE *ir; /* place to return inode number */
+{
+ int i;
+
+ readdev(0);
+ for (i = 0; i < Ndev; i++) {
+ if (strcmp(Devtp[i].name, "/dev/tty") == 0) {
+ *dr = DevDev;
+ *rdr = Devtp[i].rdev;
+ *ir = (INODETYPE)Devtp[i].inode;
+ return(1);
+ }
+ }
+ return(-1);
+}
+#endif /* DARWINV<600 */
+
+
+/*
+ * process_node() - process vnode
+ */
+
+void
+process_node(va)
+ KA_T va; /* vnode kernel space address */
+{
+ dev_t dev = (dev_t)0;
+ dev_t rdev = (dev_t)0;
+ unsigned char devs = 0;
+ unsigned char rdevs = 0;
+
+#if DARWINV<800
+ struct devnode *d = (struct devnode *)NULL;
+ struct devnode db;
+ unsigned char lt;
+ char dev_ch[32];
+
+# if defined(HASFDESCFS)
+ struct fdescnode *f = (struct fdescnode *)NULL;
+ struct fdescnode fb;
+# endif /* defined(HASFDESCFS) */
+
+ static INODETYPE fi;
+ static dev_t fdev, frdev;
+ static int fs = 0;
+ struct inode *i = (struct inode *)NULL;
+ struct inode ib;
+ struct lockf lf, *lff, *lfp;
+ struct nfsnode *n = (struct nfsnode *)NULL;
+ struct nfsnode nb;
+#else /* DARWINV>=800 */
+ struct stat sb;
+ char *vn;
+#endif /* DARWINV<800 */
+
+ char *ty;
+ enum vtype type;
+ struct vnode *v, vb;
+ struct l_vfs *vfs;
+
+#if DARWINV<600
+ struct hfsnode *h = (struct hfsnode *)NULL;
+ struct hfsnode hb;
+ struct hfsfilemeta *hm = (struct hfsfilemeta *)NULL;
+ struct hfsfilemeta hmb;
+#else /* DARWINV>=600 */
+# if DARWINV<800
+ struct cnode *h = (struct cnode *)NULL;
+ struct cnode hb;
+ struct filefork *hf = (struct filefork *)NULL;
+ struct filefork hfb;
+# endif /* DARWINV<800 */
+#endif /* DARWINV<600 */
+
+#if defined(HAS9660FS)
+ dev_t iso_dev;
+ int iso_dev_def = 0;
+ INODETYPE iso_ino;
+ long iso_links;
+ int iso_stat = 0;
+ SZOFFTYPE iso_sz;
+#endif /* defined(HAS9660FS) */
+
+/*
+ * Read the vnode.
+ */
+ if ( ! va) {
+ enter_nm("no vnode address");
+ return;
+ }
+ v = &vb;
+ if (readvnode(va, v)) {
+ enter_nm(Namech);
+ return;
+ }
+ type = v->v_type;
+
+#if defined(HASNCACHE)
+ Lf->na = va;
+# if defined(HASNCVPID)
+ Lf->id = v->v_id;
+# endif /* defined(HASNCVPID) */
+#endif /* defined(HASNCACHE) */
+
+#if defined(HASFSTRUCT)
+ Lf->fna = va;
+ Lf->fsv |= FSV_NI;
+#endif /* defined(HASFSTRUCT) */
+
+/*
+ * Get the vnode type.
+ */
+ if (!v->v_mount)
+ vfs = (struct l_vfs *)NULL;
+ else {
+ vfs = readvfs((KA_T)v->v_mount);
+ if (vfs) {
+ if (strcasecmp(vfs->typnm, "nfs") == 0)
+ Ntype = N_NFS;
+
+#if DARWINV<130
+ else if (strcasecmp(vfs->typnm, "afpfs") == 0)
+ Ntype = N_AFPFS;
+#endif /* DARWINV<130 */
+
+ }
+ }
+ if (Ntype == N_REGLR) {
+ switch (v->v_type) {
+ case VFIFO:
+ Ntype = N_FIFO;
+ break;
+ default:
+ break;
+ }
+ }
+
+#if DARWINV<800
+/*
+ * Define the specific node pointer.
+ */
+ switch (v->v_tag) {
+
+# if DARWINV>120
+ case VT_AFP:
+ break;
+# endif /* DARWINV>120 */
+
+# if DARWINV>120
+ case VT_CDDA:
+ break;
+# endif /* DARWINV>120 */
+
+# if DARWINV>120
+ case VT_CIFS:
+ break;
+# endif /* DARWINV>120 */
+
+ case VT_DEVFS:
+ if (!v->v_data
+ || kread((KA_T)v->v_data, (char *)&db, sizeof(db))) {
+ (void) snpf(Namech, Namechl, "no devfs node: %#x", v->v_data);
+ enter_nm(Namech);
+ return;
+ }
+ d = &db;
+ break;
+
+# if defined(HASFDESCFS)
+ case VT_FDESC:
+ if (!v->v_data
+ || kread((KA_T)v->v_data, (char *)&fb, sizeof(fb))) {
+ (void) snpf(Namech, Namechl, "no fdesc node: %s",
+ print_kptr((KA_T)v->v_data, (char *)NULL, 0));
+ enter_nm(Namech);
+ return;
+ }
+ f = &fb;
+ break;
+# endif /* defined(HASFDESCFS) */
+
+ case VT_HFS:
+
+# if DARWINV<130
+ if (Ntype != N_AFPFS) {
+# endif /* DARWINV<130 */
+
+ if (!v->v_data
+ || kread((KA_T)v->v_data, (char *)&hb, sizeof(hb))) {
+ (void) snpf(Namech, Namechl, "no hfs node: %s",
+ print_kptr((KA_T)v->v_data, (char *)NULL, 0));
+ enter_nm(Namech);
+ return;
+ }
+ h = &hb;
+
+# if DARWINV<600
+ if (!h->h_meta
+ || kread((KA_T)h->h_meta, (char *)&hmb, sizeof(hmb))) {
+ (void) snpf(Namech, Namechl, "no hfs node metadata: %s",
+ print_kptr((KA_T)v->v_data, (char *)NULL, 0));
+ enter_nm(Namech);
+ return;
+ }
+ hm = &hmb;
+# else /* DARWINV>=600 */
+ if (v->v_type == VDIR)
+ break;
+ if (h->c_rsrc_vp == v)
+ hf = h->c_rsrcfork;
+ else
+ hf = h->c_datafork;
+ if (!hf
+ || kread((KA_T)hf, (char *)&hfb, sizeof(hfb))) {
+ (void) snpf(Namech, Namechl, "no hfs node fork: %s",
+ print_kptr((KA_T)v->v_data, (char *)NULL, 0));
+ enter_nm(Namech);
+ return;
+ }
+ hf = &hfb;
+# endif /* DARWINV<600 */
+
+# if DARWINV<130
+ }
+# endif /* DARWINV<130 */
+
+ break;
+
+# if defined(HAS9660FS)
+ case VT_ISOFS:
+ if (read_iso_node(v, &iso_dev, &iso_dev_def, &iso_ino, &iso_links,
+ &iso_sz))
+ {
+ (void) snpf(Namech, Namechl, "no iso node: %s",
+ print_kptr((KA_T)v->v_data, (char *)NULL, 0));
+ enter_nm(Namech);
+ return;
+ }
+ iso_stat = 1;
+ break;
+# endif /* defined(HAS9660FS) */
+
+ case VT_NFS:
+ if (!v->v_data
+ || kread((KA_T)v->v_data, (char *)&nb, sizeof(nb))) {
+ (void) snpf(Namech, Namechl, "no nfs node: %s",
+ print_kptr((KA_T)v->v_data, (char *)NULL, 0));
+ enter_nm(Namech);
+ return;
+ }
+ n = &nb;
+ break;
+
+# if DARWINV>120
+ case VT_UDF:
+ break;
+# endif /* DARWINV>120 */
+
+ case VT_UFS:
+ if (!v->v_data
+ || kread((KA_T)v->v_data, (char *)&ib, sizeof(ib))) {
+ (void) snpf(Namech, Namechl, "no ufs node: %s",
+ print_kptr((KA_T)v->v_data, (char *)NULL, 0));
+ enter_nm(Namech);
+ return;
+ }
+ i = &ib;
+ if ((lff = i->i_lockf)) {
+
+ /*
+ * Determine the lock state.
+ */
+ lfp = lff;
+ do {
+ if (kread((KA_T)lfp, (char *)&lf, sizeof(lf)))
+ break;
+ lt = 0;
+ switch (lf.lf_flags & (F_FLOCK|F_POSIX)) {
+ case F_FLOCK:
+ if (Cfp && (struct file *)lf.lf_id == Cfp)
+ lt = 1;
+ break;
+ case F_POSIX:
+ if ((KA_T)lf.lf_id == Kpa)
+ lt = 1;
+ break;
+ }
+ if (!lt)
+ continue;
+ if (lf.lf_start == (off_t)0
+ && lf.lf_end == 0xffffffffffffffffLL)
+ lt = 1;
+ else
+ lt = 0;
+ if (lf.lf_type == F_RDLCK)
+ Lf->lock = lt ? 'R' : 'r';
+ else if (lf.lf_type == F_WRLCK)
+ Lf->lock = lt ? 'W' : 'w';
+ else if (lf.lf_type == (F_RDLCK | F_WRLCK))
+ Lf->lock = 'u';
+ break;
+ } while ((lfp = lf.lf_next) && lfp != lff);
+ }
+ break;
+
+# if DARWINV>120
+ case VT_WEBDAV:
+ break;
+# endif /* DARWINV>120 */
+
+ default:
+ if (v->v_type == VBAD || v->v_type == VNON)
+ break;
+ (void) snpf(Namech, Namechl, "unknown file system type: %d",
+ v->v_tag);
+ enter_nm(Namech);
+ return;
+ }
+/*
+ * Get device and type for printing.
+ */
+ if (n) {
+ dev = n->n_vattr.va_fsid;
+ devs = 1;
+ } else if (i) {
+ dev = i->i_dev;
+ devs = 1;
+ if ((type == VCHR) || (type == VBLK)) {
+ rdev = i->i_rdev ;
+ rdevs = 1;
+ }
+ }
+
+# if defined(HASFDESCFS)
+ else if (f) {
+ if (f->fd_link
+ && !kread((KA_T)f->fd_link, Namech, Namechl -1))
+ Namech[Namechl - 1] = '\0';
+
+# if DARWINV<600
+ else if (f->fd_type == Fctty) {
+ if (fs == 0)
+ fs = lkup_dev_tty(&fdev, &frdev, &fi);
+ if (fs == 1) {
+ dev = fdev;
+ rdev = frdev;
+ devs = Lf->inp_ty = rdevs = 1;
+ Lf->inode = fi;
+ }
+ }
+ }
+# endif /* DARWINV<600 */
+# endif /* defined(HASFDESCFS) */
+
+ else if (h) {
+
+# if DARWINV<600
+ dev = hm->h_dev;
+# else /* DARWINV>=600 */
+ dev = h->c_dev;
+# endif /* DARWINV<600 */
+
+ devs = 1;
+ if ((type == VCHR) || (type == VBLK)) {
+
+# if DARWINV<600
+ rdev = hm->h_rdev;
+# else /* DARWINV>=600 */
+ rdev = h->c_rdev;
+# endif /* DARWINV<600 */
+
+ rdevs = 1;
+ }
+ } else if (d) {
+ dev = DevDev;
+ devs = 1;
+ rdev = d->dn_typeinfo.dev;
+ rdevs = 1;
+ }
+
+# if defined(HAS9660FS)
+ else if (iso_stat && iso_dev_def) {
+ dev = iso_dev;
+ devs = Lf->inp_ty = 1;
+ }
+# endif /* defined(HAS9660FS) */
+
+
+/*
+ * Obtain the inode number.
+ */
+ if (i) {
+ Lf->inode = (INODETYPE)i->i_number;
+ Lf->inp_ty = 1;
+ } else if (n) {
+ Lf->inode = (INODETYPE)n->n_vattr.va_fileid;
+ Lf->inp_ty = 1;
+ } else if (h) {
+
+# if DARWINV<600
+ Lf->inode = (INODETYPE)hm->h_nodeID;
+# else /* DARWINV>=600 */
+ Lf->inode = (INODETYPE)h->c_fileid;
+# endif /* DARWINV<600 */
+
+ Lf->inp_ty = 1;
+ }
+
+# if defined(HAS9660FS)
+ else if (iso_stat) {
+ Lf->inode = iso_ino;
+ Lf->inp_ty = 1;
+ }
+# endif /* defined(HAS9660FS) */
+
+/*
+ * Obtain the file size.
+ */
+ if (Foffset)
+ Lf->off_def = 1;
+ else {
+ switch (Ntype) {
+ case N_FIFO:
+ if (!Fsize)
+ Lf->off_def = 1;
+ break;
+ case N_NFS:
+ if (n) {
+ Lf->sz = (SZOFFTYPE)n->n_vattr.va_size;
+ Lf->sz_def = 1;
+ }
+ break;
+
+# if DARWINV<130
+ case N_AFPFS:
+ break;
+# endif /* DARWINV<130 */
+
+ case N_REGLR:
+ if (type == VREG || type == VDIR) {
+ if (i) {
+ Lf->sz = (SZOFFTYPE)i->i_size;
+ Lf->sz_def = 1;
+ } else if (h) {
+
+# if DARWINV<600
+ Lf->sz = (type == VDIR) ? (SZOFFTYPE)hm->h_size
+ : (SZOFFTYPE)h->fcbEOF;
+# else /* DARWINV>=600 */
+ if (type == VDIR)
+ Lf->sz = (SZOFFTYPE)h->c_nlink * 128;
+ else
+ Lf->sz = (SZOFFTYPE)hf->ff_size;
+# endif /* DARWINV<600 */
+
+ Lf->sz_def = 1;
+ }
+
+# if defined(HAS9660FS)
+ else if (iso_stat) {
+ Lf->sz = (SZOFFTYPE)iso_sz;
+ Lf->sz_def = 1;
+ }
+# endif /* defined(HAS9660FS) */
+
+ }
+ else if ((type == VCHR || type == VBLK) && !Fsize)
+ Lf->off_def = 1;
+ break;
+ }
+ }
+/*
+ * Record the link count.
+ */
+ if (Fnlink) {
+ switch(Ntype) {
+ case N_NFS:
+ if (n) {
+ Lf->nlink = (long)n->n_vattr.va_nlink;
+ Lf->nlink_def = 1;
+ }
+ break;
+
+# if DARWINV<130
+ case N_AFPFS:
+ break;
+# endif /* DARWINV<130 */
+
+ case N_REGLR:
+ if (i) {
+ Lf->nlink = (long)i->i_nlink;
+ Lf->nlink_def = 1;
+ } else if (h) {
+
+# if DARWINV<600
+ Lf->nlink = (long)hm->h_nlink;
+# else /* DARWINV>=600 */
+ Lf->nlink = (long)h->c_nlink;
+# endif /* DARWINV<600 */
+
+ Lf->nlink_def = 1;
+ }
+
+# if defined(HAS9660FS)
+ else if (iso_stat) {
+ Lf->nlink = iso_links;
+ Lf->nlink_def = 1;
+ }
+# endif /* defined(HAS9660FS) */
+
+ break;
+ }
+ if (Lf->nlink_def && Nlink && (Lf->nlink < Nlink))
+ Lf->sf |= SELNLINK;
+ }
+#else /* DARWINV>=800 */
+
+/*
+ * Process a vnode for Darwin >= 8.0.
+ */
+ if ((vn = getvpath(va, v))) {
+
+ /*
+ * If the vnode yields a path, get the file's information by doing
+ * a "safe" stat(2) of the path.
+ */
+ if (!statsafely(vn, &sb)) {
+
+ /*
+ * Save file size or offset.
+ */
+ if (Foffset) {
+ Lf->off_def = 1;
+ } else {
+ switch (Ntype) {
+ case N_FIFO:
+ if (!Fsize)
+ Lf->off_def = 1;
+ break;
+ case N_NFS:
+ case N_REGLR:
+ if (type == VREG || type == VDIR) {
+ Lf->sz = sb.st_size;
+ Lf->sz_def = 1;
+ } else if ((type == VCHR || type == VBLK) && !Fsize)
+ Lf->off_def = 1;
+ break;
+ }
+ }
+ /*
+ * Save node number.
+ */
+ Lf->inode = (INODETYPE)sb.st_ino;
+ Lf->inp_ty = 1;
+ /*
+ * Optionally save link count.
+ */
+ if (Fnlink) {
+ Lf->nlink = sb.st_nlink;
+ Lf->nlink_def = 1;
+ }
+ /*
+ * Save device number and path.
+ */
+ switch (v->v_tag) {
+ case VT_DEVFS:
+ if (vn)
+ (void) free((FREE_P *)vn);
+ dev = DevDev;
+ devs = 1;
+ break;
+ default :
+ Lf->V_path = vn;
+ dev = sb.st_dev;
+ devs = 1;
+ break;
+ }
+ /*
+ * Save character and block device number.
+ */
+ if ((type == VCHR) || (type == VBLK)) {
+ rdev = sb.st_rdev;
+ rdevs = 1;
+ }
+ } else {
+
+ /*
+ * Indicate a stat(2) failure in Namech[].
+ */
+ (void) snpf(Namech, Namechl, "stat(%s): %s", vn,
+ strerror(errno));
+ (void) free((FREE_P *)vn);
+ }
+ /*
+ * Record an NFS file.
+ */
+ if (vfs && !strcmp(vfs->typnm, "nfs"))
+ Ntype = N_NFS;
+ }
+#endif /* DARWINV>=800 */
+
+/*
+ * 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;
+ }
+/*
+ * Save the device numbers and their states.
+ *
+ * Format the vnode type, and possibly the device name.
+ */
+ Lf->dev = dev;
+ Lf->dev_def = devs;
+ Lf->rdev = rdev;
+ Lf->rdev_def = rdevs;
+ switch (type) {
+ case VNON:
+ ty ="VNON";
+ break;
+ case VREG:
+ ty = "VREG";
+ break;
+ case VDIR:
+ ty = "VDIR";
+ break;
+ case VBLK:
+ ty = "VBLK";
+ Ntype = N_BLK;
+ break;
+ case VCHR:
+ ty = "VCHR";
+ Ntype = N_CHR;
+ break;
+ case VLNK:
+ ty = "VLNK";
+ break;
+
+#if defined(VSOCK)
+ case VSOCK:
+ ty = "SOCK";
+ break;
+#endif /* defined(VSOCK) */
+
+ case VBAD:
+ ty = "VBAD";
+ break;
+ case VFIFO:
+ ty = "FIFO";
+ break;
+ default:
+ (void) snpf(Lf->type, sizeof(Lf->type), "%04o", (type & 0xfff));
+ ty = (char *)NULL;
+ }
+ if (ty)
+ (void) snpf(Lf->type, sizeof(Lf->type), "%s", ty);
+ Lf->ntype = Ntype;
+/*
+ * Handle some special cases:
+ *
+ * ioctl(fd, TIOCNOTTY) files;
+ * memory node files;
+ * /proc files.
+ */
+ if (type == VBAD)
+ (void) snpf(Namech, Namechl, "(revoked)");
+
+#if defined(HASBLKDEV)
+/*
+ * If this is a VBLK file and it's missing an inode number, try to
+ * supply one.
+ */
+ if ((Lf->inp_ty == 0) && (type == VBLK))
+ find_bl_ino();
+#endif /* defined(HASBLKDEV) */
+
+/*
+ * If this is a VCHR file and it's missing an inode number, try to
+ * supply one.
+ */
+ if ((Lf->inp_ty == 0) && (type == VCHR))
+ find_ch_ino();
+/*
+ * Test for specified file.
+ */
+ if (Sfile && is_file_named((char *)NULL,
+ ((type == VCHR) || (type == VBLK) ? 1
+ : 0)))
+ Lf->sf |= SELNM;
+/*
+ * Enter name characters.
+ */
+ if (Namech[0])
+ enter_nm(Namech);
+}
+
+
+#if DARWINV>=800
+/*
+ * readvname() - read vnode's path name
+ */
+
+static int
+readvname(addr, buf, buflen)
+ KA_T addr; /* kernel v_path address */
+ char *buf; /* receiving buffer */
+ int buflen; /* sizeof(buf) */
+{
+ int n, rl;
+/*
+ * Read the name 32 characters at a time, until a NUL character
+ * has been read or the buffer has been filled.
+ */
+ for (n = 0; n < buflen; addr += 32, n += 32) {
+ rl = buflen - n;
+ if (rl > 32)
+ rl = 32;
+ if (kread(addr, &buf[n], rl))
+ return(0);
+ buf[n + rl] = '\0';
+ if ((rl = (int)strlen(&buf[n])) < 32) {
+ return(n + rl);
+ }
+ }
+ return(0);
+}
+#endif /* DARWINV>=800 */