/*
 * dnode.c - /dev/kmem-based HP-UX 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";
#endif

#if defined(HPUXKERNBITS) && HPUXKERNBITS >= 64
#    define _INO_T
typedef int ino_t;
#    define _TIME_T
typedef int time_t;
#endif /* defined(HPUXKERNBITS) && HPUXKERNBITS>=64 */

#include "common.h"
#include <sys/inode.h>

#if HPUXV >= 900
static void enter_nma(char *b);
static enum lsof_lock_mode islocked(KA_T lp);
#endif /* HPUXV>=900 */

static int getnodety(struct vnode *v);
static int readinode(KA_T ia, struct inode *i);
static int read_nmn(KA_T na, KA_T ia, struct mvfsnode *m);

#if HPUXV >= 900
/*
 * enter_nma() - enter NAME column addition
 */

static void enter_nma(b) char *b; /* addition buffer */
{
    if (Lf->nma)
        return;
    if (strlen(b) < 1)
        return;
    Lf->nma = mkstrcpy(b, (MALLOC_S *)NULL);
}

/*
 * islocked() - is node locked?
 */

static enum lsof_lock_mode islocked(KA_T lp) /* local locklist struct pointer */
{
    static int ety = -1;
    static unsigned int ei = 0;
    static SZOFFTYPE el = 0;
    int l;
    struct locklist ll;
    KA_T llf, llp;

    if (!(llf = (KA_T)lp))
        return LSOF_LOCK_NONE;
    llp = llf;
    /*
     * Compute the end test value the first time through.
     */

    if (ety == -1) {

#    if HPUXV < 1020
        ety = 0;
        ei = 0x7fffffff;
#    else  /* HPUXV>=1020 */
        if (sizeof(ll.ll_end) == 4) {
            ety = 0;
            ei = 0x80000000;
        } else {
            ety = 1;
            el = 0x10000000000ll;
        }
#    endif /* HPUXV<1020 */
    }

    /*
     * Search the locklist chain for this process.
     */
    do {
        if (kread(ctx, llp, (char *)&ll, sizeof(ll)))
            return LSOF_LOCK_NONE;

#    if !defined(L_REMOTE)
#        define L_REMOTE 0x1 /* from HP-UX 9.01 */
#    endif                   /* !defined(L_REMOTE) */

#    if HPUXV < 1010
        if (ll.ll_flags & L_REMOTE || ll.ll_proc != (KA_T)Kpa)
#    else  /* HPUXV>=1010 */
        if (ll.ll_flags & L_REMOTE || (KA_T)ll.ll_kthreadp != Ktp)
#    endif /* HPUXV<1010 */

            continue;
        l = 0;
        if (ll.ll_start == 0) {
            switch (ety) {
            case 0:
                if (ll.ll_end == ei)
                    l = 1;
                break;
            case 1:
                if (ll.ll_end == el)
                    l = 1;
                break;
            }
        }
        if (ll.ll_type == F_WRLCK)
            return l ? LSOF_LOCK_WRITE_FULL : LSOF_LOCK_WRITE_PARTIAL;
        else if (ll.ll_type == F_RDLCK)
            return l ? LSOF_LOCK_READ_FULL : LSOF_LOCK_READ_PARTIAL;
        return LSOF_LOCK_NONE;
    }

#    if HPUXV < 1010
    while ((llp = (KA_T)ll.ll_link) && llp != llf);
#    else  /* HPUXV>=1010 */
    while ((llp = (KA_T)ll.ll_fwd) && llp != llf);
#    endif /* HPUXV<1010 */

    return LSOF_LOCK_NONE;
}
#endif /* HPUXV>=900 */

/*
 * getnodety() - get node type
 */

static int getnodety(struct vnode *v) /* local vnode copy */
{

#if defined(HAS_AFS)
    static int afs = 0; /* AFS test status: -1 = no AFS
                         *		     0 = not tested
                         *		     1 = AFS present */
    struct afsnode an;
#endif /* defined(HAS_AFS) */

    static int ft = 1;
    static KA_T avops;
    static KA_T cvops;
    static KA_T fvops;
    static KA_T mvops;
    static KA_T nvops;
    static KA_T nvops3;
    static KA_T nv3ops;
    static KA_T pvops;
    static KA_T svops;
    static KA_T uvops;
    static KA_T vvops;
    /*
     * Do first-time only operations.
     */
    if (ft) {
        if (get_Nl_value("avops", Drive_Nl, &avops) < 0)
            avops = (unsigned long)0;
        if (get_Nl_value("cvops", Drive_Nl, &cvops) < 0)
            cvops = (unsigned long)0;
        if (get_Nl_value("fvops", Drive_Nl, &fvops) < 0)
            fvops = (unsigned long)0;
        if (get_Nl_value("mvops", Drive_Nl, &mvops) < 0)
            mvops = (unsigned long)0;
        if (get_Nl_value("nvops", Drive_Nl, &nvops) < 0)
            nvops = (unsigned long)0;
        if (get_Nl_value("nvops3", Drive_Nl, &nvops3) < 0)
            nvops3 = (unsigned long)0;
        if (get_Nl_value("nv3ops", Drive_Nl, &nv3ops) < 0)
            nv3ops = (unsigned long)0;
        if (get_Nl_value("pvops", Drive_Nl, &pvops) < 0)
            pvops = (unsigned long)0;
        if (get_Nl_value("svops", Drive_Nl, &svops) < 0)
            svops = (unsigned long)0;
        if (get_Nl_value("uvops", Drive_Nl, &uvops) < 0)
            uvops = (unsigned long)0;
        if (get_Nl_value("vvops", Drive_Nl, &vvops) < 0)
            vvops = (unsigned long)0;
        ft = 0;
    }
    /*
     * Determine the vnode type.
     */
    if (uvops && uvops == (unsigned long)v->v_op)
        return (N_REGLR);
    else if (nvops && nvops == (unsigned long)v->v_op)
        return (N_NFS);
    else if (nvops3 && nvops3 == (unsigned long)v->v_op)
        return (N_NFS);
    else if (nv3ops && nv3ops == (unsigned long)v->v_op)
        return (N_NFS);
    else if (mvops && mvops == (unsigned long)v->v_op)
        return (N_MVFS);

#if defined(HASVXFS)
    else if (vvops && vvops == (unsigned long)v->v_op)
        return (N_VXFS);
#endif /* defined(HASVXFS) */

#if HPUXV >= 1000
    else if (cvops && cvops == (unsigned long)v->v_op)
        return (N_CDFS);
    else if (fvops && fvops == (unsigned long)v->v_op)
        return (N_FIFO);
    else if (pvops && pvops == (unsigned long)v->v_op)
        return (N_PIPE);
    else if (svops && svops == (unsigned long)v->v_op)
        return (N_SPEC);
#else  /* HPUXV<1000 */
    else if (v->v_type == VFIFO)
        return (N_FIFO);
#endif /* HPUXV<1000 */

#if defined(HAS_AFS)
    /*
     * Caution: this AFS test should be the last one.
     */

    else if (avops) {
        if (avops == (unsigned long)v->v_op)
            return (N_AFS);
        else {

        unknown_v_op:
            (void)snpf(Namech, Namechl, "unknown file system type; v_op: %s",
                       print_kptr((KA_T)v->v_op, (char *)NULL, 0));
            enter_nm(Namech);
            return (-1);
        }
    } else if (v->v_data || !v->v_vfsp)
        goto unknown_v_op;
    else {
        switch (afs) {
        case -1:
            goto unknown_v_op;
        case 0:
            if (!hasAFS(v)) {
                afs = -1;
                goto unknown_v_op;
            }
            afs = 1;
            return (N_AFS);
            break;
        case 1:
            if (v->v_vfsp == AFSVfsp)
                return (N_AFS);
            else
                goto unknown_v_op;
        }
    }
#else  /* !defined(HAS_AFS) */
    else {
        (void)snpf(Namech, Namechl, "unknown file system type; v_op: %s",
                   print_kptr((KA_T)v->v_op, (char *)NULL, 0));
        enter_nm(Namech);
        return (-1);
    }
#endif /* defined(HAS_AFS) */
}

/*
 * process_node() - process vnode
 */

void process_node(va) KA_T va; /* vnode kernel space address */

{

#if defined(HAS_AFS)
    struct afsnode an;
#endif /* defined(HAS_AFS) */

    dev_t dev, rdev;
    int devs = 0;
    struct inode i;
    int ins = 0;
    struct mvfsnode m;
    struct rnode r;
    int rdevs = 0;
    int rns = 0;
    char tbuf[32];
    enum vtype type;
    static struct vnode *v = (struct vnode *)NULL;
    struct l_vfs *vfs;
    int vty;

#if HPUXV >= 900
    char fb[128];
    int fns = 0;
    int rp, sz, wp;
    struct vnode rv;
    struct snode s;
#endif /* HPUXV>=900 */

#if HPUXV >= 1000
    struct cdnode c;
    struct fifonode f;
    struct vattr vat;
    int vats = 0;
#endif /* HPUXV>=1000 */

    /*
     * Read the vnode.
     */
    if (!va) {
        enter_nm("no vnode address");
        return;
    }
    if (!v) {

        /*
         * Allocate space for the vnode or AFS vcache structure.
         */

#if defined(HAS_AFS)
        v = alloc_vcache();
#else  /* !defined(HAS_AFS) */
        v = (struct vnode *)malloc(sizeof(struct vnode));
#endif /* defined(HAS_AFS) */

        if (!v) {
            (void)fprintf(stderr, "%s: can't allocate %s space\n", Pn,

#if defined(HAS_AFS)
                          "vcache"
#else  /* !defined(HAS_AFS) */
                          "vnode"
#endif /* defined(HAS_AFS) */

            );
            Error(ctx);
        }
    }
    if (readvnode(va, v)) {
        enter_nm(Namech);
        return;
    }

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

#if defined(HASFSTRUCT)
    Lf->fna = va;
    Lf->fsv |= FSV_NI;
#endif /* defined(HASFSTRUCT) */

    /*
     * Get the primary vnode type.
     */
    vty = getnodety(v);
    if (vty == -1)
        return;
    Ntype = vty;
    /*
     * Determine lock type.
     */

#if HPUXV < 900
    if (v->v_shlockc || v->v_exlockc) {
        if (v->v_shlockc && v->v_exlockc)
            Lf->lock = LSOF_LOCK_READ_WRITE;
        else if (v->v_shlockc)
            Lf->lock = LSOF_LOCK_READ_FULL;
        else
            Lf->lock = LSOF_LOCK_WRITE_FULL;
    }
#else /* HPUXV>900 */
#    if HPUXV >= 1000
    Lf->lock = islocked((KA_T)v->v_locklist);
#    endif /* HPUXV>=1000 */
#endif     /* HPUXV<900 */

    /*
     * Establish the local virtual file system structure.
     */
    if (!v->v_vfsp)
        vfs = (struct l_vfs *)NULL;
    else if (!(vfs = readvfs(v))) {
        (void)snpf(Namech, Namechl, "can't read vfs for %s at %s",
                   print_kptr(va, tbuf, sizeof(tbuf)),
                   print_kptr((KA_T)v->v_vfsp, (char *)NULL, 0));
        enter_nm(Namech);
        return;
    }
    /*
     * Read the cdnode, fifonode, inode, rnode, snode, or vache struct.
     */
    switch (Ntype) {

#if defined(HAS_AFS)
    case N_AFS:
        if (readafsnode(va, v, &an))
            return;
        break;
#endif /* defined(HAS_AFS) */

#if defined(HASVXFS)
    case N_VXFS:
        if (!v->v_data || read_vxnode(v, vfs, &dev, &devs, &rdev, &rdevs)) {
            (void)snpf(Namech, Namechl, "vnode at %s: can't read vx_inode (%s)",
                       print_kptr(va, tbuf, sizeof(tbuf)),
                       print_kptr((KA_T)v->v_data, (char *)NULL, 0));
            enter_nm(Namech);
            return;
        }
        break;
#endif /* defined(HASVXFS) */

#if HPUXV >= 1000
    case N_CDFS:
        if (!v->v_data || kread(ctx, (KA_T)v->v_data, (char *)&c, sizeof(c))) {
            (void)snpf(Namech, Namechl, "vnode at %s: can't read cdnode (%s)",
                       print_kptr(va, tbuf, sizeof(tbuf)),
                       print_kptr((KA_T)v->v_data, (char *)NULL, 0));
            enter_nm(Namech);
            return;
        }
        break;
    case N_FIFO:
    case N_PIPE:
        if (!v->v_data || kread(ctx, (KA_T)v->v_data, (char *)&f, sizeof(f))) {
            (void)snpf(Namech, Namechl, "vnode at %s: can't read fifonode (%s)",
                       print_kptr(va, tbuf, sizeof(tbuf)),
                       print_kptr((KA_T)v->v_data, (char *)NULL, 0));
            enter_nm(Namech);
            return;
        }
        fns = 1;
        if (f.fn_vap &&
            kread(ctx, (KA_T)f.fn_vap, (char *)&vat, sizeof(vat)) == 0)
            vats = 1;
        break;
#endif /* HPUXV>=1000 */

    case N_MVFS:
        if (read_nmn(va, (KA_T)v->v_data, &m))
            return;
        break;
    case N_NFS:
        if (!v->v_data || readrnode((KA_T)v->v_data, &r)) {
            (void)snpf(Namech, Namechl, "vnode at %s: can't read rnode (%s)",
                       print_kptr(va, tbuf, sizeof(tbuf)),
                       print_kptr((KA_T)v->v_data, (char *)NULL, 0));
            enter_nm(Namech);
            return;
        }
        rns = 1;
        break;

#if HPUXV >= 1000
    case N_SPEC:
        if ((v->v_type == VBLK) || (v->v_type == VCHR)) {
            if (!v->v_data || readsnode((KA_T)v->v_data, &s)) {
                (void)snpf(Namech, Namechl, "vnode at %s: can't read snode(%s)",
                           print_kptr(va, tbuf, sizeof(tbuf)),
                           print_kptr((KA_T)v->v_data, (char *)NULL, 0));
                enter_nm(Namech);
                return;
            }
            if (!s.s_realvp || readvnode((KA_T)s.s_realvp, &rv)) {
                (void)snpf(Namech, Namechl,
                           "snode at %s: can't read real vnode (%s)",
                           print_kptr((KA_T)v->v_data, tbuf, sizeof(tbuf)),
                           print_kptr((KA_T)s.s_realvp, (char *)NULL, 0));
                enter_nm(Namech);
                return;
            }

#    if defined(HASVXFS)
            if (getnodety(&rv) == N_VXFS) {
                if (!rv.v_data ||
                    read_vxnode(&rv, vfs, &dev, &devs, &rdev, &rdevs)) {
                    (void)snpf(Namech, Namechl,
                               "vnode at %s: can't read vx_inode (%s)",
                               print_kptr(va, tbuf, sizeof(tbuf)),
                               print_kptr((KA_T)rv.v_data, (char *)NULL, 0));
                    enter_nm(Namech);
                    return;
                }
                Ntype = N_VXFS;
                break;
            }
#    endif /* defined(HASVXFS) */

            if (!rv.v_data || readinode((KA_T)rv.v_data, &i)) {
                (void)snpf(Namech, Namechl,
                           "snode at %s: can't read inode (%s)",
                           print_kptr((KA_T)v->v_data, tbuf, sizeof(tbuf)),
                           print_kptr((KA_T)rv.v_data, (char *)NULL, 0));
                enter_nm(Namech);
                return;
            }
            ins = 1;
            break;
        }
        if (!v->v_data || readinode((KA_T)v->v_data, &i)) {
            (void)snpf(Namech, Namechl, "vnode at %s: can't read inode (%s)",
                       print_kptr(va, tbuf, sizeof(tbuf)),
                       print_kptr((KA_T)v->v_data, (char *)NULL, 0));
            enter_nm(Namech);
            return;
        }
        ins = 1;
        break;
#endif /* HPUXV>=1000 */

#if HPUXV >= 900 && HPUXV < 1000
    case N_FIFO:
        if (v->v_fstype == VNFS_FIFO) {
            if (!v->v_data || readsnode((KA_T)v->v_data, &s)) {
                (void)snpf(Namech, Namechl,
                           "vnode at %s: can't read snode (%s)",
                           print_kptr(va, tbuf, sizeof(tbuf)),
                           print_kptr((KA_T)v->v_data, (char *)NULL, 0));
                enter_nm(Namech);
                return;
            }
            if (!s.s_realvp || readvnode((KA_T)s.s_realvp, &rv)) {
                (void)snpf(Namech, Namechl,
                           "snode at %s: can't read real vnode (%s)",
                           print_kptr((KA_T)v->v_data, tbuf, sizeof(tbuf)),
                           print_kptr((KA_T)s.s_realvp, (char *)NULL, 0));
                enter_nm(Namech);
                return;
            }
            if (!rv.v_data || readrnode((KA_T)rv.v_data, &r)) {
                (void)snpf(Namech, Namechl,
                           "snode at %s: can't read real rnode (%s)",
                           print_kptr((KA_T)v->v_data, tbuf, sizeof(tbuf)),
                           print_kptr((KA_T)s.s_realvp, (char *)NULL, 0));
                enter_nm(Namech);
                return;
            }
            rns = 1;
            break;
        }
        /* fall through */
#endif /* HPUXV>=900 && HPUXV<1000 */

    case N_REGLR:
    default:
        if (!v->v_data || readinode((KA_T)v->v_data, &i)) {
            (void)snpf(Namech, Namechl, "vnode at %s: can't read inode (%s)",
                       print_kptr(va, tbuf, sizeof(tbuf)),
                       print_kptr((KA_T)v->v_data, (char *)NULL, 0));
            enter_nm(Namech);
            return;
        }
        ins = 1;

#if HPUXV >= 900 && HPUXV < 1000
        if (v->v_type == VFIFO)
            Ntype = N_FIFO;
#endif /* HPUXV>=900 && HPUXV<1000 */
    }

#if HPUXV >= 900 && HPUXV < 1000
    Lf->lock = islocked((KA_T)i.i_locklist);
#endif /* HPUXV>=900 && HPUXV<1000 */

    /*
     * Get device and type for printing.
     */
    switch (Ntype) {

#if defined(HAS_AFS)
    case N_AFS:
        dev = an.dev;
        devs = 1;
        break;
#endif /* defined(HAS_AFS) */

    case N_MVFS:
        if (vfs) {
            dev = vfs->dev;
            devs = 1;
        }
        break;
    case N_NFS:
        dev = vfs ? vfs->dev : 0;
        devs = 1;
        break;

#if HPUXV >= 1000
    case N_CDFS:
        dev = c.cd_dev;
        devs = 1;
        break;
    case N_FIFO:
    case N_PIPE:
        if (vfs && vfs->fsname) {
            dev = vfs->dev;
            devs = 1;
        } else if (vats && (dev_t)vat.va_fsid != NODEV) {
            dev = (dev_t)vat.va_fsid;
            devs = 1;
        } else
            enter_dev_ch(print_kptr(va, (char *)NULL, 0));
        break;
#endif /* _HPUX>=1000 */

#if defined(HASVXFS)
    case N_VXFS:
        /* obtained via read_vxnode */
        break;
#endif /* defined(HASVXFS) */

    case N_SPEC:
    default:

#if HPUXV >= 800
        if (vfs && vfs->fsname) {
            dev = vfs->dev;
            devs = 1;
        } else if (ins) {
            dev = i.i_dev;
            devs = 1;
        }
        if ((v->v_type == VBLK) || (v->v_type == VCHR)) {
            rdev = v->v_rdev;
            rdevs = 1;
        }
#else  /* HPUXV<800 */
        if (ins) {
            dev = i.i_dev;
            devs = 1;
        }
        if ((v->v_type == VCHR) || (v->v_type == VBLK)) {
            rdev = v->v_rdev;
            rdevs = 1;
        }
#endif /* HPUXV>=800 */
    }
    type = v->v_type;
    /*
     * Obtain the inode number.
     */
    switch (Ntype) {

#if defined(HAS_AFS)
    case N_AFS:
        if (an.ino_st) {
            Lf->inode = (INODETYPE)an.inode;
            Lf->inp_ty = 1;
        }
        break;
#endif /* defined(HAS_AFS) */

    case N_MVFS:
        Lf->inode = (INODETYPE)m.m_ino;
        Lf->inp_ty = 1;
        break;
    case N_NFS:

#if HPUXV < 1030
        Lf->inode = (INODETYPE)r.r_nfsattr.na_nodeid;
#else  /* HPUXV>=1030 */
        Lf->inode = (INODETYPE)r.r_attr.va_nodeid;
#endif /* HPUXV<1030 */

        Lf->inp_ty = 1;
        break;

#if HPUXV >= 1000
    case N_CDFS:
        Lf->inode = (INODETYPE)c.cd_num;
        Lf->inp_ty = 1;
        break;
    case N_FIFO:
    case N_PIPE:
        if (vats) {
            Lf->inode = (INODETYPE)vat.va_nodeid;
            Lf->inp_ty = 1;
        } else {
            Lf->inode = (INODETYPE)v->v_nodeid;
            Lf->inp_ty = 1;
        }
        break;
#endif /* HPUXV>=1000 */

#if defined(HASVXFS)
    case N_VXFS:
        /* set in read_vxnode() */
        break;
#endif /* defined(HASVXFS) */

#if HPUXV < 1000
    case N_FIFO:

#    if HPUXV >= 900
        if (rns) {
            Lf->inode = (INODETYPE)r.r_nfsattr.na_nodeid;
            Lf->inp_ty = 1;
            break;
        }
#    endif /* HPUXV>=900 */
           /* fall through */

#endif /* HPUXV<1000 */

    case N_BLK:
    case N_REGLR:
    case N_SPEC:
        if (ins) {
            Lf->inode = (INODETYPE)i.i_number;
            Lf->inp_ty = 1;
        }
    }

#if HPUXV >= 1030
    /*
     * Check for an HP-UX 10.30 and above stream.
     */
    if (v->v_stream) {
        KA_T ip, pcb;
        char *pn = (char *)NULL;

        Lf->dev = dev;
        Lf->dev_def = devs;
        Lf->rdev = rdev;
        Lf->rdev_def = rdevs;
        if (read_mi((KA_T)v->v_stream, &ip, &pcb, &pn))
            return;
        if (ip && pcb) {
            process_stream_sock(ip, pcb, pn, type);
            return;
        }
        Lf->is_stream = 1;
    }
#endif /* HPUXV>=1030 */

    /*
     * Obtain the file size.
     */
    switch (Ntype) {
#if defined(HAS_AFS)
    case N_AFS:
        Lf->sz = (SZOFFTYPE)an.size;
        Lf->sz_def = 1;
        break;
#endif /* defined(HAS_AFS) */

#if HPUXV >= 1000
    case N_CDFS:
        Lf->sz = (SZOFFTYPE)c.cd_cdc.cdc_size;
        Lf->sz_def = 1;
        break;
    case N_PIPE:
        if (vats) {
            Lf->sz = (SZOFFTYPE)vat.va_size;
            Lf->sz_def = 1;
        }
        break;
#endif /* HPUXV>=1000 */

#if HPUXV >= 900
    case N_FIFO:

#    if HPUXV < 1000
        if (ins) {
            rp = i.i_frptr;
            sz = (int)i.i_fifosize;
            wp = i.i_fwptr;
        } else if (rns)
            Lf->sz = (SZOFFTYPE)r.r_nfsattr.na_size;
#    else  /* HPUXV>=1000 */
        if (fns) {
            rp = f.fn_rptr;
            sz = f.fn_size;
            wp = f.fn_wptr;
        }
#    endif /* HPUXV<1000 */

        if (Lf->access != LSOF_FILE_ACCESS_READ &&
            Lf->access != LSOF_FILE_ACCESS_WRITE) {
            if (fns || ins) {
                (void)snpf(fb, sizeof(fb), "rd=%#x; wr=%#x", rp, wp);
                (void)enter_nma(fb);
            }
            if (fns || ins || rns) {
                Lf->sz = (SZOFFTYPE)sz;
                Lf->sz_def = 1;
            }
            break;
        }
        if (fns || ins) {
            Lf->off =
                (unsigned long)((Lf->access == LSOF_FILE_ACCESS_READ) ? rp
                                                                      : wp);
            Lf->off_def = 1;
            (void)snpf(fb, sizeof(fb), "%s=%#x",
                       (Lf->access == LSOF_FILE_ACCESS_READ) ? "rd" : "wr",
                       (Lf->access == LSOF_FILE_ACCESS_READ) ? rp : wp);
            (void)enter_nma(fb);
        }
        break;
#endif /* HPUXV>=900 */

    case N_MVFS:
        /* The location of the file size isn't known. */
        break;
    case N_NFS:

#if HPUXV < 1030
        Lf->sz = (SZOFFTYPE)r.r_nfsattr.na_size;
#else  /* HPUXV>=1030 */
        Lf->sz = (SZOFFTYPE)r.r_attr.va_size;
#endif /* HPUXV<1030 */

        Lf->sz_def = 1;
        break;

#if defined(HASVXFS)
    case N_VXFS:
        /* set in read_vxnode() */
        break;
#endif /* defined(HASVXFS) */

    case N_SPEC:
    case N_REGLR:
        if (!(type == VCHR || type == VBLK) && ins) {
            Lf->sz = (SZOFFTYPE)i.i_size;
            Lf->sz_def = 1;
        }
        break;
    }
    /*
     * Record link count.
     */
    switch (Ntype) {

#if defined(HAS_AFS)
    case N_AFS:
        Lf->nlink = an.nlink;
        Lf->nlink_def = an.nlink_st;
        break;
#endif /* defined(HAS_AFS) */

    case N_MVFS:
        /* The location of the link count isn't known. */
        break;
    case N_NFS:

#if HPUXV < 1030
        Lf->nlink = r.r_nfsattr.na_nlink;
#else  /* HPUXV>=1030 */
        Lf->nlink = r.r_attr.va_nlink;
#endif /* HPUXV<1030 */

        Lf->nlink_def = 1;
        break;

#if HPUXV >= 1000
    case N_CDFS: /* no link count? */
        break;
#endif /* HPUXV>=1000 */

    case N_FIFO:
    case N_PIPE:

#if HPUXV >= 1000
        if (vats) {
            Lf->nlink = (long)vat.va_nlink;
            Lf->nlink_def = 1;
        }
#endif /* HPUXV>=1000 */

        break;

#if defined(HASVXFS)
    case N_VXFS:
        /* set in read_vxnode() */
        break;
#endif /* defined(HASVXFS) */

    case N_SPEC:
    default:
        if (ins) {
            Lf->nlink = (long)i.i_nlink;
            Lf->nlink_def = 1;
        }
        break;
    }
    if (Nlink && Lf->nlink_def && (Lf->nlink < Nlink))
        Lf->sf |= SELNLINK;
    /*
     * 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;

#if defined(HASFSINO)
        Lf->fs_ino = vfs->fs_ino;
#endif /* defined(HASFSINO) */
    }
    /*
     * 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:
        Lf->type = LSOF_FILE_VNODE_VNON;
        break;
    case VREG:
    case VDIR:
        Lf->type = (type == VREG) ? LSOF_FILE_VNODE_VREG : LSOF_FILE_VNODE_VDIR;
        break;
    case VBLK:
        Lf->type = LSOF_FILE_VNODE_VBLK;
        Ntype = N_BLK;
        break;
    case VCHR:
        Lf->type = LSOF_FILE_VNODE_VCHR;
        Ntype = N_CHR;
        break;
    case VLNK:
        Lf->type = LSOF_FILE_VNODE_VLNK;
        break;

#if defined(VSOCK)
    case VSOCK:
        Lf->type = LSOF_FILE_VNODE_VSOCK;
        break;
#endif /* defined(VSOCK) */

    case VBAD:
        Lf->type = LSOF_FILE_VNODE_VBAD;
        break;
    case VFIFO:
        switch (Ntype) {

#if HPUXV >= 1000
        case N_FIFO:
            Lf->type = LSOF_FILE_VNODE_VFIFO;
            break;
        case N_PIPE:
            Lf->type = LSOF_FILE_PIPE;
            break;
#endif /* HPUXV>=1000 */

        default:
            Lf->type = LSOF_FILE_FIFO;
        }
        break;
    default:
        Lf->type = LSOF_FILE_UNKNOWN_RAW;
        Lf->unknown_file_type_number = type;
    }
    Lf->ntype = Ntype;

#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);
}

/*
 * readinode() - read inode
 */

static int readinode(ia, i)
KA_T ia;         /* inode kernel address */
struct inode *i; /* inode buffer */
{
    if (kread(ctx, (KA_T)ia, (char *)i, sizeof(struct inode))) {
        (void)snpf(Namech, Namechl, "can't read inode at %s",
                   print_kptr(ia, (char *)NULL, 0));
        return (1);
    }
    return (0);
}

/*
 * read_nmn() - read node's mvfsnode
 */

static int read_nmn(na, ma, m)
KA_T na;            /* containing node's address */
KA_T ma;            /* kernel mvfsnode address */
struct mvfsnode *m; /* mvfsnode receiver */
{
    char tbuf[32];

    if (!ma || kread(ctx, (KA_T)ma, (char *)m, sizeof(struct mvfsnode))) {
        (void)snpf(Namech, Namechl, "node at %s: can't read mvfsnode: %s",
                   print_kptr(na, tbuf, sizeof(tbuf)),
                   print_kptr(ma, (char *)NULL, 0));
        enter_nm(Namech);
        return (1);
    }
    return (0);
}
