| /* |
| * 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 */ |