/*
 * dnode.c - SCO UnixWare node functions for lsof
 */

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

#include "common.h"
#include <sys/fs/namenode.h>

#if UNIXWAREV >= 70000
#    undef IREAD
#    undef IWRITE
#    undef IEXEC
#endif /* UNIXWAREV>=70000 */

#if defined(HAS_UW_CFS)
#    include <fs/nsc_cfs/cnode.h>
#endif /* defined(HAS_UW_CFS) */

#include <sys/fs/ufs_inode.h>

#if defined(HASXNAMNODE)
#    include <sys/fs/xnamnode.h>
#endif /* defined(HASXNAMNODE) */

static void ent_fa(KA_T *a1, KA_T *a2, char *d);
static int get_vty(struct vnode *v, KA_T va, struct vfs *kv, int *fx);

#if UNIXWAREV < 70103
static int examine_stream(KA_T vs, struct queue *q, char *mn, char *sn,
                          KA_T *sqp);
#else  /* UNIXWAREV>=70103 */
static int examine_stream(KA_T vs, struct queue *q, char **mch, char **mn,
                          char *sn, KA_T *sqp);
static struct l_dev *findspdev(dev_t *dev, dev_t *rdev);
static void getspdev(void);
static int get_vty(struct vnode *v, KA_T va, struct vfs *kv, int *fx);
static struct l_dev *ismouse(struct vnode *va, struct l_ino *i, int fx,
                             struct vfs *kv);
#endif /* UNIXWAREV<70103 */

static struct l_dev *findstrdev(dev_t *dev, dev_t *rdev);
static enum lsof_lock_mode isvlocked(struct vnode *va);
static int readlino(int fx, struct vnode *v, struct l_ino *i);

/*
 * Local variables and definitions
 */

static struct protos {
    char *module; /* stream module name */
    char *proto;  /* TCP/IP protocol name */
} Protos[] = {
    {"tcpu", "TCP"},  {"udpu", "UDP"}, {"tcpl", "TCP"}, {"tcp", "TCP"},
    {"udpl", "UDP"},  {"udp", "UDP"},

#if UNIXWAREV < 70103
    {"icmp", "ICMP"}, {"ipu", "IP"},   {"ipl", "IP"},   {"ip", "IP"},
#endif /* UNIXWAREV<70103 */

};
#define NPROTOS (sizeof(Protos) / sizeof(struct protos))

#if UNIXWAREV >= 70103
static struct specdev {
    char *name;
    struct l_dev *dp;
} SpDev[] = {
    {"/dev/log", (struct l_dev *)NULL},
    {"/dev/mouse", (struct l_dev *)NULL},
};
#    define SPDEV_CT (sizeof(SpDev) / sizeof(struct specdev))
static int SpDevX = -1; /* SpDev[] maximum index */
#endif                  /* UNIXWAREV>=70103 */

/*
 * ent_fa() - enter fattach addresses in NAME column addition
 */

static void ent_fa(KA_T *a1, /* first fattach address (NULL OK) */
                   KA_T *a2, /* second fattach address */
                   char *d)  /* direction ("->" or "<-") */
{
    char buf[64], *cp, tbuf[32];
    MALLOC_S len;
    char fd[FDLEN];

    if (Lf->nma)
        return;
    if (!a1)
        (void)snpf(buf, sizeof(buf), "(FA:%s%s)", d,
                   print_kptr(*a2, (char *)NULL, 0));
    else
        (void)snpf(buf, sizeof(buf), " (FA:%s%s%s)",
                   print_kptr(*a1, tbuf, sizeof(tbuf)), d,
                   print_kptr(*a2, (char *)NULL, 0));
    len = strlen(buf) + 1;
    if ((cp = (char *)malloc(len)) == NULL) {
        fd_to_string(Lf->fd_type, Lf->fd_num, fd);
        (void)fprintf(stderr,
                      "%s: no space for fattach addresses at PID %d, FD %s\n",
                      Pn, Lp->pid, fd);
        Error(ctx);
    }
    (void)snpf(cp, len, "%s", buf);
    Lf->nma = cp;
}

/*
 * examine_stream() - examine stream
 */

static int examine_stream(struct lsof_context *ctx, /* context */
                          KA_T vs,         /* stream head's stdata kernel
                                            * address */
                          struct queue *q, /* queue structure buffer */

#if UNIXWAREV >= 70103
                          char **mch, /* important stream module name chain,
                                       * module names separated by "->" */
                          char **mn,  /* pointer to module name receiver */
#else                                 /* UNIXWAREV<70103 */
                          char *mn, /* module name receiver */
#endif                                /* UNIXWAREV>=70103 */

                          char *sn,  /* special module name */
                          KA_T *sqp) /* special module's q_ptr */
{
    struct module_info mi;
    KA_T qp;
    struct qinit qi;
    struct stdata sd;
    char tbuf[32];

#if UNIXWAREV >= 70103
    static char *ab = (char *)NULL;
    static MALLOC_S aba = (size_t)0;
    MALLOC_S al, len, naba, tlen;
    char *ap;
    char tmnb[STRNML + 1];
#endif /* UNIXWAREV>=70103 */

    /*
     * Read stream's head.
     */
    if (!vs || readstdata(vs, &sd)) {
        (void)snpf(Namech, Namechl, "can't read stream head from %s",
                   print_kptr(vs, (char *)NULL, 0));
        enter_nm(Namech);
        return (1);
    }
    if (!sd.sd_wrq) {
        enter_nm("no stream write queue");
        return (1);
    }
    /*
     * Examine the write queue.
     */

#if UNIXWAREV < 70103
    for (qp = (KA_T)sd.sd_wrq, *mn = '\0'; qp; qp = (KA_T)q->q_next)
#else  /* UNIXWAREV>=70103 */
    for (qp = (KA_T)sd.sd_wrq, al = (MALLOC_S)0, ap = ab, *mn = (char *)NULL,
        tmnb[sizeof(tmnb) - 1] = '\0';
         qp; qp = (KA_T)q->q_next)
#endif /* UNIXWAREV<70103 */

    {

        /*
         * Read stream queue entry.
         */
        if (kread(ctx, qp, (char *)q, sizeof(struct queue))) {
            (void)snpf(Namech, Namechl, "can't read stream queue from %s",
                       print_kptr(qp, (char *)NULL, 0));
            enter_nm(Namech);
            return (1);
        }
        /*
         * Read queue's information structure.
         */
        if (!q->q_qinfo || readstqinit((KA_T)q->q_qinfo, &qi)) {
            (void)snpf(Namech, Namechl, "can't read qinit for %s from %s",
                       print_kptr(qp, tbuf, sizeof(tbuf)),
                       print_kptr((KA_T)q->q_qinfo, (char *)NULL, 0));
            enter_nm(Namech);
            return (1);
        }
        /*
         * Read module information structure.
         */
        if (!qi.qi_minfo || readstmin((KA_T)qi.qi_minfo, &mi)) {
            (void)snpf(Namech, Namechl, "can't read module info for %s from %s",
                       print_kptr((KA_T)q->q_qinfo, tbuf, sizeof(tbuf)),
                       print_kptr((KA_T)qi.qi_minfo, (char *)NULL, 0));
            enter_nm(Namech);
            return (1);
        }
        /*
         * Read module name.
         */

#if UNIXWAREV < 70103
        if (!mi.mi_idname || kread(ctx, (KA_T)mi.mi_idname, mn, STRNML - 1))
#else  /* UNIXWAREV>=70103 */
        if (!mi.mi_idname || kread(ctx, (KA_T)mi.mi_idname, tmnb, STRNML))
#endif /* UNIXWAREV<70103 */

        {
            (void)snpf(Namech, Namechl, "can't read module name for %s from %s",
                       print_kptr((KA_T)qi.qi_minfo, tbuf, sizeof(tbuf)),
                       print_kptr((KA_T)mi.mi_idname, (char *)NULL, 0));
            enter_nm(Namech);
            return (1);
        }

#if UNIXWAREV < 70103
        *(mn + STRNML - 1) = '\0';
#endif /* UNIXWAREV<70103 */

        /*
         * Save the q_ptr of the first special module.
         */

#if UNIXWAREV < 70103
        if (!sn || *sqp || !q->q_ptr)
            continue;
        if (strcmp(mn, sn) == 0)
            *sqp = (KA_T)q->q_ptr;
#else  /* UNIXWAREV>=70103 */
        if (sn && !*sqp && q->q_ptr) {
            if (strcmp(tmnb, sn) == 0)
                *sqp = (KA_T)q->q_ptr;
        }
        /*
         * Assemble the module name chain.  Allocate space as required.
         * Skip null module names and some "uninteresting" ones.
         */
        len = strlen(tmnb);
        if (len && strcmp(tmnb, "strrhead") && strcmp(tmnb, "strwhead")) {
            tlen = len + 1 + (al ? 2 : 0);
            if ((tlen + al) > aba) {
                aba = tlen + al + 64; /* allocate some extra */
                if (!ab) {
                    ab = ap = (char *)malloc(aba);
                } else {
                    ab = (char *)realloc((MALLOC_P *)ab, aba);
                    if (al)
                        ap = ab + (al - 1);
                    else
                        ap = ab;
                }
                if (!ab) {
                    (void)fprintf(stderr, "%s: no space for stream chain", Pn);
                    Error(ctx);
                }
            }
            (void)snpf(ap, aba - (al - 1), "%s%s", (ap == ab) ? "" : "->",
                       tmnb);
            *mn = ap + ((ap == ab) ? 0 : 2);
            al += tlen;
            ap += (tlen - 1);
        }
#endif /* UNIXWAREV<70103 */
    }

#if UNIXWAREV >= 70103
    *mch = ab;
    if (!*mn)
        *mn = "";
#endif /* UNIXWAREV>=70103 */

    return (0);
}

#if UNIXWAREV >= 70103
/*
 * findspdev() - find special device by raw major device number
 */

static struct l_dev *findspdev(dev_t *dev,  /* containing device */
                               dev_t *rdev) /* raw device */
{
    int i;
    struct l_dev *dp;

    if (*dev != DevDev)
        return ((struct l_dev *)NULL);
    if (SpDevX < 0)
        (void)getspdev();
    for (i = 0; i < SpDevX; i++) {
        if (!(dp = SpDev[i].dp))
            continue;
        if (GET_MAJ_DEV(*rdev) == GET_MAJ_DEV(dp->rdev))
            return (dp);
    }
    return ((struct l_dev *)NULL);
}
#endif /* UNIXWAREV>=70103 */

/*
 * findstrdev() - look up stream device by device number
 */

static struct l_dev *findstrdev(dev_t *dev,  /* device */
                                dev_t *rdev) /* raw device */
{
    struct clone *c;
    struct l_dev *dp;
    /*
     * Search device table for match.
     */

#if HASDCACHE

findstrdev_again:

#endif /* HASDCACHE */

    if ((dp = lkupdev(dev, rdev, 0, 0)))
        return (dp);
    /*
     * Search for clone.
     */
    if (Clone) {
        for (c = Clone; c; c = c->next) {
            if (GET_MAJ_DEV(*rdev) == GET_MIN_DEV(Devtp[c->dx].rdev)) {

#if HASDCACHE
                if (DCunsafe && !Devtp[c->dx].v && !vfy_dev(&Devtp[c->dx]))
                    goto findstrdev_again;
#endif /* HASDCACHE */

                return (&Devtp[c->dx]);
            }
        }
    }

#if UNIXWAREV < 70103
    return ((struct l_dev *)NULL);
#else  /* UNIXWAREV>=70103 */
    /*
     * Search for non-clone clone.
     */
    return (findspdev(dev, rdev));
#endif /* UNIXWAREV<70103 */
}

#if UNIXWAREV >= 70103
/*
 * getspecdev() -- get Devtp[] pointers for "special" devices
 */

static void getspdev() {
    struct l_dev *dp;
    int i, j, n;

    if (SpDevX >= 0)
        return;
    /*
     * Scan Devtp[] for the devices named in SpDev[].
     */
    for (i = n = 0; (i < Ndev) && (n < SPDEV_CT); i++) {
        dp = Sdev[i];
        for (j = 0; j < SPDEV_CT; j++) {
            if (SpDev[j].dp)
                continue;
            if (strcmp(SpDev[j].name, dp->name) == 0) {
                SpDev[j].dp = dp;
                n++;
                SpDevX = j + 1;
                break;
            }
        }
    }
    if (SpDevX < 0)
        SpDevX = 0;
}
#endif /* UNIXWAREV>=70103 */

/*
 * get_vty() - get vnode type
 *
 * return: vnode type as an N_* symbol value
 *	   N_REGLR if no special file system type applies
 *	   -1 if the vnode type is VUNNAMED
 *	   -2 if the vfs structure has an illegal type index
 *	   -3 if the vfs structure can't be read
 */

static int get_vty(struct lsof_context *ctx, /* context */
                   struct vnode *v,          /* vnode to test */
                   KA_T va,                  /* vnode's kernel address */
                   struct vfs *kv, /* copy of vnode's kernel vfs struct */
                   int *fx)        /* file system type index */
{
    int fxt;
    int nty = N_REGLR;
    char tbuf[32];

    if (v->v_type == VUNNAMED) {
        *fx = 0;
        return (-1);
    }
    if (!v->v_vfsp) {
        *fx = 0;
        if ((v->v_type == VFIFO) || v->v_stream)
            return (N_STREAM);
        return (N_REGLR);
    }
    if (!kread(ctx, (KA_T)v->v_vfsp, (char *)kv, sizeof(struct vfs))) {

        /*
         * Check the file system type.
         */
        fxt = kv->vfs_fstype;
        if (fxt > 0 && fxt <= Fsinfomax) {
            if (!strcmp(Fsinfo[fxt - 1], "fifofs"))
                nty = N_FIFO;
            else if (!strcmp(Fsinfo[fxt - 1], "nfs"))
                nty = N_NFS;
            else if (!strcmp(Fsinfo[fxt - 1], "namefs"))
                nty = N_NM;
            else if (!strcmp(Fsinfo[fxt - 1], "nsc_cfs"))
                nty = N_CFS;

#if defined(HASPROCFS)
            else if (!strcmp(Fsinfo[fxt - 1], "proc"))
                nty = N_PROC;
#endif /* defined(HASPROCFS) */

        } else {
            (void)snpf(Namech, Namechl, "vnode@%s: bad file system index (%d)",
                       print_kptr(va, (char *)NULL, 0), fxt);
            enter_nm(Namech);
            return (-2);
        }
    } else {
        (void)snpf(Namech, Namechl, "vnode@%s: bad vfs pointer (%s)",
                   print_kptr(va, tbuf, sizeof(tbuf)),
                   print_kptr((KA_T)v->v_vfsp, (char *)NULL, 0));
        enter_nm(Namech);
        return (-3);
    }
    if (nty == N_REGLR) {
        if (v->v_type == VFIFO)
            nty = N_FIFO;
        else if (v->v_stream)
            nty = N_STREAM;
    }
    *fx = fxt;
    return (nty);
}

#if UNIXWAREV >= 70103
/*
 * ismouse() - is vnode attached to /dev/mouse
 */

static struct l_dev *ismouse(struct vnode *va, /* local vnode address */
                             struct l_ino *i,  /* local inode structure */
                             int fx,           /* file system index */
                             struct vfs *kv) /* copy of kernel VFS structure */
{
    struct l_dev *dp;
    int j;

    if ((fx < 1) || (fx > Fsinfomax))
        return ((struct l_dev *)NULL);
    if ((dp = findspdev(&kv->vfs_dev, &va->v_rdev))) {
        i->dev = kv->vfs_dev;
        i->dev_def = 1;
        i->nlink = (long)0;
        i->nlink_def = 0;
        i->nm = (char *)NULL;
        i->number = dp->inode;
        i->number_def = 1;
        i->rdev = va->v_rdev;
        i->rdev_def = 0;
        i->size = (SZOFFTYPE)0;
        i->size_def = 0;
        Ntype = N_REGLR;
    }
    return (dp);
}
#endif /* UNIXWAREV>=70103 */

/*
 * isvlocked() - is a vnode locked
 */

static enum lsof_lock_mode isvlocked(struct lsof_context *ctx, /* context */
                                     struct vnode *va) /* local vnode address */
{
    struct filock f;
    KA_T flf, flp;
    int i, l;

    if (!(flf = (KA_T)va->v_filocks))
        return LSOF_LOCK_NONE;
    flp = flf;
    i = 0;
    do {
        if (i++ > 1000)
            break;
        if (kread(ctx, flp, (char *)&f, sizeof(f)))
            break;
        if (f.set.l_sysid || f.set.l_pid != (pid_t)Lp->pid)
            continue;
        if (!f.set.l_whence && !f.set.l_start

#if UNIXWAREV >= 70101
#    if UNIXWAREV < 70103
            && (f.set.l_len == 0x7fffffffffffffff)
#    else  /* UNIXWAREV>=70103 */
            && (f.set.l_len == 0x7fffffffffffffffLL)
#    endif /* UNIXWAREV<70103 */
#else      /* UNIXWAREV<70101 */
            && ((f.set.l_len == 0) || (f.set.l_len == 0x7fffffff))
#endif     /* UNIXWAREV>=70101*/

        )
            l = 1;
        else
            l = 0;
        switch (f.set.l_type & (F_RDLCK | F_WRLCK)) {
        case F_RDLCK:
            return l ? LSOF_LOCK_READ_FULL : LSOF_LOCK_READ_PARTIAL;
        case F_WRLCK:
            return l ? LSOF_LOCK_WRITE_FULL : LSOF_LOCK_WRITE_PARTIAL;
        case (F_RDLCK + F_WRLCK):
            return LSOF_LOCK_READ_WRITE;
        default:
            return LSOF_LOCK_NONE;
        }
    } while (flp != (KA_T)f.next && (flp = (KA_T)f.next) && flp != flf);
    return LSOF_LOCK_NONE;
}

/*
 * process_node() - process node
 */

void process_node(struct lsof_context *ctx, /* context */
                  KA_T na)                  /* vnode kernel space address */
{
    char *cp, *ep;
    dev_t dev, rdev;
    unsigned char devs = 0;
    unsigned char rdevs = 0;
    unsigned char ni = 0;
    struct l_dev *dp;
    struct fifonode f;
    int fx, rfx;
    struct l_ino i;
    int is = 1;
    int j, k;
    KA_T ka;
    struct vfs kv, rkv;

#if UNIXWAREV < 70103
    struct module_info mi;
    char mn[STRNML];
#else  /* UNIXWAREV>=70103 */
    char *mch, *mn;
#endif /* UNIXWAREV<70103 */

    struct mnode mno;
    MALLOC_S msz;
    struct namenode nn;
    int px;
    struct queue q;
    struct rnode r;
    struct vnode rv, v;
    struct snode s;
    unsigned char sd = 1;
    struct so_so so;
    KA_T sqp = (KA_T)NULL;
    size_t sz;
    char tbuf[32];
    enum vtype type;
    struct sockaddr_un ua;

#if defined(HASPROCFS)
    struct as as;
    struct proc p;
    KA_T pa;
    struct procfsid *pfi;
    long pid;
    struct prnode pr;
#    if UNIXWAREV < 20102
    struct pid pids;
#    else  /* UNIXWAREV>=20102 */
    struct prcommon prc;
#    endif /* UNIXWAREV>=20102 */
#endif     /* defined(HASPROCFS) */

    /*
     * Read the vnode.
     */
    if (!na) {
        enter_nm("no vnode address");
        return;
    }
    if (readvnode((KA_T)na, &v)) {
        enter_nm(Namech);
        return;
    }

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

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

    /*
     * Determine the vnode type.
     */
    if ((Ntype = get_vty(&v, na, &kv, &fx)) < 0) {
        if (Ntype == -1)
            Lf->sf = 0;
        return;
    }
    /*
     * Determine the lock state.
     */

get_lock_state:

    Lf->lock = isvlocked(&v);
    /*
     * Read the fifonode, inode, namenode, prnode, rnode, snode, ...
     */
    switch (Ntype) {
    case N_FIFO:
        if (!v.v_data || readfifonode((KA_T)v.v_data, &f)) {
            (void)snpf(Namech, Namechl, "vnode@%s: can't read fifonode (%s)",
                       print_kptr(na, tbuf, sizeof(tbuf)),
                       print_kptr((KA_T)v.v_data, (char *)NULL, 0));
            enter_nm(Namech);
            return;
        }
        if (f.fn_realvp) {
            if (readvnode((KA_T)f.fn_realvp, &rv)) {
                (void)snpf(Namech, Namechl,
                           "fifonode@%s: can't read real vnode (%s)",
                           print_kptr((KA_T)v.v_data, tbuf, sizeof(tbuf)),
                           print_kptr((KA_T)f.fn_realvp, (char *)NULL, 0));
                enter_nm(Namech);
                return;
            }

#if defined(HASNCACHE)
            Lf->na = (KA_T)f.fn_realvp;
#endif /* defined(HASNCACHE) */

            if (!rv.v_data || (is = readlino(fx, &rv, &i))) {
                (void)snpf(Namech, Namechl,
                           "fifonode@%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;
            }
        } else
            ni = 1;
        break;
    case N_NFS:
        if (!v.v_data || readrnode((KA_T)v.v_data, &r)) {
            (void)snpf(Namech, Namechl, "vnode@%s: can't read rnode (%s)",
                       print_kptr(na, tbuf, sizeof(tbuf)),
                       print_kptr((KA_T)v.v_data, (char *)NULL, 0));
            enter_nm(Namech);
            return;
        }
        break;
    case N_NM:
        if (!v.v_data || kread(ctx, (KA_T)v.v_data, (char *)&nn, sizeof(nn))) {
            (void)snpf(Namech, Namechl, "vnode@%s: no namenode (%s)",
                       print_kptr(na, tbuf, sizeof(tbuf)),
                       print_kptr((KA_T)v.v_data, (char *)NULL, 0));
            enter_nm(Namech);
            return;
        }
        i.dev = nn.nm_vattr.va_fsid;
        i.rdev = nn.nm_vattr.va_rdev;
        i.number = (INODETYPE)nn.nm_vattr.va_nodeid;
        i.size = nn.nm_vattr.va_size;
        if (!nn.nm_mountpt)
            break;
        /*
         * The name node is mounted over/to another vnode.  Process that node.
         */
        (void)ent_fa(&na, (KA_T *)&nn.nm_mountpt, "->");
        if (kread(ctx, (KA_T)nn.nm_mountpt, (char *)&rv, sizeof(rv))) {
            (void)snpf(Namech, Namechl,
                       "vnode@%s: can't read namenode's mounted vnode (%s)",
                       print_kptr(na, tbuf, sizeof(tbuf)),
                       print_kptr((KA_T)nn.nm_mountpt, (char *)NULL, 0));
            return;
        }
        if ((Ntype = get_vty(&rv, (KA_T)nn.nm_mountpt, &rkv, &rfx)) < 0) {
            if (Ntype == -1)
                Lf->sf = 0;
            return;
        }
        /*
         * Unless the mounted-over/to node is another "namefs" node, promote
         * it to the vnode of interest.
         */
        if (Ntype == N_NM)
            break;
        fx = rfx;
        kv = rkv;
        v = rv;
        goto get_lock_state;

#if defined(HASPROCFS)
    case N_PROC:
        ni = 1;
        if (!v.v_data || kread(ctx, (KA_T)v.v_data, (char *)&pr, sizeof(pr))) {
            (void)snpf(Namech, Namechl, "vnode@%s: can't read prnode (%s)",
                       print_kptr(na, tbuf, sizeof(tbuf)),
                       print_kptr((KA_T)v.v_data, (char *)NULL, 0));
            enter_nm(Namech);
            return;
        }

#    if UNIXWAREV >= 20102
        i.number = (INODETYPE)pr.pr_ino;
        sd = 0;
        if (pr.pr_common &&
            !kread(ctx, (KA_T)pr.pr_common, (char *)&prc, sizeof(prc))) {
            pid = (long)prc.prc_pid;
            switch (pr.pr_type) {
            case PR_PIDDIR:
                (void)snpf(Namech, Namechl, "/%s/%ld", HASPROCFS, pid);
                break;
            case PR_AS:
                (void)snpf(Namech, Namechl, "/%s/%ld/as", HASPROCFS, pid);
                break;
            case PR_CTL:
                (void)snpf(Namech, Namechl, "/%s/%ld/ctl", HASPROCFS, pid);
                break;
            case PR_STATUS:
                (void)snpf(Namech, Namechl, "/%s/%ld/status", HASPROCFS, pid);
                break;
            case PR_MAP:
                (void)snpf(Namech, Namechl, "/%s/%ld/map", HASPROCFS, pid);
                break;
            case PR_CRED:
                (void)snpf(Namech, Namechl, "/%s/%ld/cred", HASPROCFS, pid);
                break;
            case PR_SIGACT:
                (void)snpf(Namech, Namechl, "/%s/%ld/sigact", HASPROCFS, pid);
                break;
            case PR_OBJECTDIR:
                (void)snpf(Namech, Namechl, "/%s/%ld/object", HASPROCFS, pid);
                break;
            case PR_LWPDIR:
                (void)snpf(Namech, Namechl, "/%s/%ld/lwp", HASPROCFS, pid);
                break;
            case PR_LWPIDDIR:
                (void)snpf(Namech, Namechl, "/%s/%ld/lwp/%d", HASPROCFS, pid,
                           prc.prc_lwpid);
                break;
            case PR_LWPCTL:
                (void)snpf(Namech, Namechl, "/%s/%ld/lwp/%d/lwpctl", HASPROCFS,
                           pid, prc.prc_lwpid);
                break;
            case PR_LWPSTATUS:
                (void)snpf(Namech, Namechl, "/%s/%ld/lwp/%d/lwpstatus",
                           HASPROCFS, pid, prc.prc_lwpid);
                break;
            case PR_LWPSINFO:
                (void)snpf(Namech, Namechl, "/%s/%ld/lwp/%d/lwpsinfo",
                           HASPROCFS, pid, prc.prc_lwpid);
                break;
            }
        } else
            pid = 0l;
        break;
#    else  /* UNIXWAREV<20102 */
        if (!pr.pr_proc) {
            sd = 0;
            pid = 0l;
            if (v.v_type == VDIR)
                i.number = (INODETYPE)PR_ROOTINO;
            else
                i.number = (INODETYPE)0;
            break;
        }
        if (kread(ctx, (KA_T)pr.pr_proc, (char *)&p, sizeof(p))) {
            (void)snpf(Namech, Namechl, "prnode@%s: can't read proc (%s)",
                       print_kptr((KA_T)v.v_data, tbuf, sizeof(tbuf)),
                       print_kptr((KA_T)pr.pr_proc, (char *)NULL, 0));
            enter_nm(Namech);
            return;
        }
        if (!p.p_pidp ||
            kread(ctx, (KA_T)p.p_pidp, (char *)&pids, sizeof(pids))) {
            (void)snpf(Namech, Namechl,
                       "proc struct at %s: can't read pid (%s)",
                       print_kptr((KA_T)pr.pr_proc, tbuf, sizeof(tbuf)),
                       print_kptr((KA_T)p.p_pidp, (char *)NULL, 0));
            enter_nm(Namech);
            return;
        }
        pid = (long)pids.pid_id;
        (void)snpf(Namech, Namechl, "/%s/%ld", HASPROCFS, pid);
        i.number = (INODETYPE)(pid + PR_INOBIAS);
        if (!p.p_as || kread(ctx, (KA_T)p.p_as, (char *)&as, sizeof(as)))
            sd = 0;
        else
            i.size = as.a_size;
        break;
#    endif /* UNIXWAREV>=20102 */
#endif     /* defined(HASPROCFS) */

    case N_STREAM:
        if (v.v_stream) {
            Lf->is_stream = ni = 1;

#if UNIXWAREV >= 70101
            if (process_unix_sockstr(&v, na)) {

                /*
                 * The stream is a UNIX socket stream.  No more need be done;
                 * process_unix_stream() has done it all.
                 */
                return;
            }
#endif /* UNIXWAREV>=70101 */

            /*
             * Get the queue pointer and module name at the end of the stream.
             * The module name identifies socket streams.
             */
            if (examine_stream((KA_T)v.v_stream, &q,

#if UNIXWAREV >= 70103
                               &mch, &mn,
#else  /* UNIXWAREV<70103 */
                               mn,
#endif /* UNIXWAREV>=70103 */

                               "sockmod", &sqp))
                return;
            for (px = 0; px < NPROTOS; px++) {
                if (strcmp(mn, Protos[px].module) == 0) {
                    process_socket(Protos[px].proto, &q);
                    return;
                }
            }
            /*
             * If this stream has a "sockmod" module with a non-NULL q_ptr,
             * try to use it to read an so_so structure.
             */
            if (sqp && kread(ctx, sqp, (char *)&so, sizeof(so)) == 0)
                break;
            sqp = (KA_T)NULL;
            (void)snpf(Namech, Namechl, "STR");
            j = strlen(Namech);
            if (v.v_type == VCHR) {
                /*
                 * If this is a VCHR stream, look up the device name and record
                 * it.
                 */
                if ((dp = findstrdev(&DevDev, (dev_t *)&v.v_rdev))) {
                    Lf->inode = dp->inode;
                    Lf->inp_ty = 1;
                    Namech[j++] = ':';
                    k = strlen(dp->name);
                    if ((j + k) <= (Namechl - 1)) {
                        (void)snpf(&Namech[j], Namechl - j, "%s", dp->name);
                        j += k;
                        if ((cp = strrchr(Namech, '/')) && *(cp + 1) == '\0') {
                            *cp = '\0';
                            j--;
                        }
                    }
                }
            }
            /*
             * Follow the "STR" and possibly the device name with "->" and
             * the module name or the stream's significant module names.
             */
            if ((j + 2) <= (Namechl - 1)) {
                (void)snpf(&Namech[j], Namechl - j, "->");
                j += 2;
            }

#if UNIXWAREV < 70103
            if (mn[0]) {
                if ((j + strlen(mn)) <= (Namechl - 1))
                    (void)snpf(&Namech[j], Namechl - j, mn);
#else  /* UNIXWAREV>=70103 */
            if (*mch) {
                if ((j + strlen(mch)) <= (Namechl - 1))
                    (void)snpf(&Namech[j], Namechl - j, mch);
#endif /* UNIXWAREV<70103 */

            } else {
                if ((j + strlen("none")) <= (Namechl - 1))
                    (void)snpf(&Namech[j], Namechl - j, "none");
            }
        }
        break;
    case N_REGLR:
    default:

        /*
         * Follow a VBLK or VCHR vnode to its snode, then to its real vnode,
         * finally to its inode.
         */
        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@%s: can't read snode (%s)",
                           print_kptr(na, tbuf, sizeof(tbuf)),
                           print_kptr((KA_T)v.v_data, (char *)NULL, 0));
                enter_nm(Namech);
                return;
            }
            if (s.s_realvp) {
                if (readvnode((KA_T)s.s_realvp, &rv)) {
                    (void)snpf(Namech, Namechl,
                               "snode@%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 || (is = readlino(fx, &rv, &i))) {
                    (void)snpf(Namech, Namechl,
                               "snode@%s: unknown inode@%s; fx=",
                               print_kptr((KA_T)v.v_data, tbuf, sizeof(tbuf)),
                               print_kptr((KA_T)rv.v_data, (char *)NULL, 0));
                    ep = endnm(&sz);
                    if (fx < 1 || fx > Fsinfomax)
                        (void)snpf(ep, sz, "%d", fx);
                    else
                        (void)snpf(ep, sz, "%s", Fsinfo[fx - 1]);
                    enter_nm(Namech);
                    return;
                }
            }
            /*
             * If there's no real vnode, look for a common vnode and a
             * common snode.
             */
            else if ((ka = (KA_T)s.s_commonvp)) {
                if (readvnode(ka, &rv)) {
                    (void)snpf(Namech, Namechl,
                               "snode@%s: can't read common vnode (%s)",
                               print_kptr((KA_T)v.v_data, tbuf, sizeof(tbuf)),
                               print_kptr((KA_T)ka, (char *)NULL, 0));
                    enter_nm(Namech);
                    return;
                }

#if UNIXWAREV >= 70103
                if (!rv.v_vfsp) {
                    if ((dp = ismouse(&rv, &i, fx, &kv))) {
                        (void)snpf(Namech, Namechl, "STR:%s", dp->name);
                        break;
                    }
                }
#endif /* UNIXWAREV>=70103 */

                if (get_vty(&rv, ka, &rkv, &rfx) < 0)
                    Lf->is_com = ni = 1;
                else {
                    if ((is = readlino(rfx, &rv, &i))) {
                        (void)snpf(Namech, Namechl,
                                   "vnode@%s: unknown successor@%s; fx=",
                                   print_kptr((KA_T)ka, tbuf, sizeof(tbuf)),
                                   print_kptr((KA_T)v.v_data, (char *)NULL, 0));
                        ep = endnm(&sz);
                        if (rfx < 1 || rfx > Fsinfomax)
                            (void)snpf(ep, sz, "%d", rfx);
                        else
                            (void)snpf(ep, sz, "%s", Fsinfo[rfx - 1]);
                        enter_nm(Namech);
                        return;
                    }
                }
            } else
                ni = 1;
            break;
        }

#if UNIXWAREV >= 70103
        else if (v.v_type == VNON) {
            ni = 1;
            break;
        }
#endif /* UNIXWAREV>=70103 */

        if (v.v_data == NULL) {
            (void)snpf(Namech, Namechl, "vnode@%s: no further information",
                       print_kptr(na, (char *)NULL, 0));
            enter_nm(Namech);
            return;
        }
        /*
         * Read inode information.
         */
        if ((is = readlino(fx, &v, &i))) {
            (void)snpf(Namech, Namechl, "vnode@%s: unknown successor@%s; fx=",
                       print_kptr(na, tbuf, sizeof(tbuf)),
                       print_kptr((KA_T)v.v_data, (char *)NULL, 0));
            ep = endnm(&sz);
            if (fx < 1 || fx > Fsinfomax)
                (void)snpf(ep, sz, "%d", fx);
            else
                (void)snpf(ep, sz, "%s", Fsinfo[fx - 1]);
            enter_nm(Namech);
            return;
        }
    }
    /*
     * Get device and type for printing.
     */
    switch (Ntype) {
    case N_NFS:
        dev = r.r_attr.va_fsid;
        devs = 1;
        break;

#if defined(HASPROCFS)
    case N_PROC:
        dev = kv.vfs_dev;
        devs = 1;
        break;
#endif /* defined(HASPROCFS) */

    case N_STREAM:
        if (sqp) {
            if (so.lux_dev.size >= 8) {
                dev = DevDev;
                rdev = so.lux_dev.addr.tu_addr.dev;
                devs = rdevs = 1;
            } else
                enter_dev_ch(print_kptr(sqp, (char *)NULL, 0));
            break;
        }
        if (v.v_type == VFIFO) {
            KA_T ta;

            if ((ta = (KA_T)(v.v_data ? v.v_data : v.v_stream)))
                enter_dev_ch(print_kptr(ta, (char *)NULL, 0));
            break;
        }
        /* fall through */
    default:
        if (!ni) {
            dev = i.dev;
            devs = (Ntype == N_CFS) ? i.dev_def : 1;
        } else if ((Ntype == N_STREAM) &&
                   ((v.v_type == VCHR) || (v.v_type == VBLK))) {
            dev = DevDev;
            devs = 1;
        }
        if ((v.v_type == VCHR) || (v.v_type == VBLK)) {
            rdev = v.v_rdev;
            rdevs = (Ntype == N_CFS) ? i.rdev_def : 1;
        }
    }
    type = v.v_type;
    /*
     * Obtain the inode number.
     */
    switch (Ntype) {

    case N_NFS:
        Lf->inode = (INODETYPE)r.r_attr.va_nodeid;
        Lf->inp_ty = 1;
        break;

#if defined(HASPROCFS)
    case N_PROC:
        Lf->inode = i.number;
        Lf->inp_ty = 1;
        break;
#endif /* defined(HASPROCFS) */

    case N_FIFO:
        if (!f.fn_realvp) {
            enter_dev_ch(print_kptr((KA_T)v.v_data, (char *)NULL, 0));
            Lf->inode = (INODETYPE)f.fn_ino;
            Lf->inp_ty = 1;
            if (f.fn_flag & ISPIPE)
                (void)snpf(Namech, Namechl, "PIPE");
            if (f.fn_mate) {
                ep = endnm(&sz);
                (void)snpf(ep, sz, "->%s",
                           print_kptr((KA_T)f.fn_mate, (char *)NULL, 0));
            }
            break;
        }
        /* fall through */
    case N_CFS:
    case N_REGLR:
        if (!ni) {
            Lf->inode = i.number;
            Lf->inp_ty = (Ntype == N_CFS) ? i.number_def : 1;
        }
        break;
    case N_STREAM:
        if (sqp && so.lux_dev.size >= 8) {
            Lf->inode = (INODETYPE)so.lux_dev.addr.tu_addr.ino;
            Lf->inp_ty = 1;
        }
    }
    /*
     * Obtain the file size.
     */
    switch (Ntype) {

    case N_FIFO:
    case N_STREAM:
        break;
    case N_NFS:
        Lf->sz = (SZOFFTYPE)r.r_attr.va_size;
        Lf->sz_def = sd;
        break;

#if defined(HASPROCFS)
    case N_PROC:

#    if UNIXWAREV < 70103
        Lf->sz = (SZOFFTYPE)i.size;
        Lf->sz_def = sd;
#    else  /* UNIXWAREV>=70103 */
        Lf->sz = (SZOFFTYPE)0;
        Lf->sz_def = 0;
#    endif /* UNIXWAREV<70103 */

        break;
#endif /* defined(HASPROCFS) */

    case N_CFS:
    case N_REGLR:
        if ((type == VREG) || (type == VDIR)) {
            if (!ni) {
                Lf->sz = (SZOFFTYPE)i.size;
                Lf->sz_def = (Ntype == N_CFS) ? i.size_def : sd;
            }
        }
        break;
    }
    /*
     * Record link count.
     */
    switch (Ntype) {
    case N_FIFO:
        Lf->nlink = (long)f.fn_open;
        Lf->nlink_def = 1;
        break;
    case N_NFS:
        Lf->nlink = (long)r.r_attr.va_nlink;
        Lf->nlink_def = 1;
        break;

#if defined(HASPROCFS)
    case N_PROC:
#endif /* defined(HASPROCFS) */

    case N_CFS:
    case N_REGLR:
        if (!ni) {
            Lf->nlink = (long)i.nlink;
            Lf->nlink_def = i.nlink_def;
        }
        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;
    /*
     * Defer file system info lookup until printname().
     */
    Lf->lmi_srch = 1;
    /*
     * Save the device numbers and their states.
     *
     * Format the vnode type, and possibly the device name.
     */
    if (type != VFIFO) {
        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:
        Lf->type = LSOF_FILE_VNODE_VREG;
        break;
    case VDIR:
        Lf->type = 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;
        if (Lf->is_stream == 0)
            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 /* VSOCK */

    case VBAD:
        Lf->type = LSOF_FILE_VNODE_VBAD;
        break;
    case VFIFO:
        if (!Lf->dev_ch || Lf->dev_ch[0] == '\0') {
            Lf->dev = dev;
            Lf->dev_def = devs;
            Lf->rdev = rdev;
            Lf->rdev_def = rdevs;
        }
        Lf->type = LSOF_FILE_VNODE_VFIFO;
        break;
    case VUNNAMED:
        Lf->type = LSOF_FILE_VNODE_VUNNAMED;
        break;
    default:
        Lf->type = LSOF_FILE_UNKNOWN_RAW;
        Lf->unknown_file_type_number = type;
    }
    Lf->ntype = Ntype;
    /*
     * If this is a VBLK file and it's missing an inode number, try to
     * supply one.
     */
    if ((Lf->inp_ty == 0) && (Lf->ntype == N_BLK))
        find_bl_ino();
    /*
     * 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();
    /*
     * If this is a stream with a "sockmod" module whose q_ptr leads to an
     * so_so structure, assume it's a UNIX domain socket and try to get
     * the path.  Clear the is_stream status.
     */
    if (Ntype == N_STREAM && sqp) {
        if (Funix)
            Lf->sf |= SELUNX;
        Lf->type = LSOF_FILE_UNIX;
        if (!Namech[0] && so.laddr.buf && so.laddr.len == sizeof(ua) &&
            !kread(ctx, (KA_T)so.laddr.buf, (char *)&ua, sizeof(ua))) {
            ua.sun_path[sizeof(ua.sun_path) - 1] = '\0';
            (void)snpf(Namech, Namechl, "%s", ua.sun_path);
            if (Sfile && is_file_named(Namech, 0))
                Lf->sf = SELNM;
            if (so.lux_dev.size >= 8) {
                Lf->inode = (INODETYPE)so.lux_dev.addr.tu_addr.ino;
                Lf->inp_ty = 1;
            }
        }
        if (so.so_conn) {
            ep = endnm(&sz);
            (void)snpf(ep, sz, "->%s",
                       print_kptr((KA_T)so.so_conn, (char *)NULL, 0));
        }
        Lf->is_stream = 0;
    }
    /*
     * Test for specified file.
     */

#if defined(HASPROCFS)
    if (Ntype == N_PROC) {
        if (Procsrch) {
            Procfind = 1;
            Lf->sf |= SELNM;
        } else {
            for (pfi = Procfsid; pfi; pfi = pfi->next) {

                if ((pfi->pid && pid && pfi->pid == (pid_t)pid)

#    if defined(HASPINODEN)
                    || ((Lf->inp_ty == 1) && (Lf->inode == pfi->inode))
#    endif /* defined(HASPINODEN) */

                ) {
                    pfi->f = 1;
                    Lf->sf |= SELNM;
                    if (!Namech[0] && pfi->nm) {
                        (void)strncpy(Namech, pfi->nm, Namechl - 1);
                        Namech[Namechl - 1] = '\0';
                    }
                    break;
                }
            }
        }
    } else
#endif /* defined(HASPROCFS) */

    {
        if (Sfile && is_file_named((char *)NULL,
                                   ((type == VCHR) || (type == VBLK)) ? 1 : 0))
            Lf->sf |= SELNM;
    }
    /*
     * Enter name characters.  If there's an l_ino structure with a file name
     * pointer, and no name column addition exists, make what the l_ino file
     * name pointer addresses a name column addition.
     */
    if (!Lf->nma && !is && i.nm) {
        if ((msz = (MALLOC_S)strlen(i.nm))) {
            if (!(cp = (char *)malloc(msz + 1))) {
                (void)fprintf(
                    stderr,
                    "%s: can't allocate %d bytes for l_ino name addition\n",
                    msz, Pn);
                Error(ctx);
            }
            (void)snpf(cp, msz + 1, "%s", i.nm);
            Lf->nma = cp;
        }
    }
    if (Namech[0])
        enter_nm(Namech);
}

/*
 * readlino() - read local inode information
 */

static int readlino(struct lsof_context *ctx, int fx, /* file system index */
                    struct vnode *v, /* vnode pointing to inode */
                    struct l_ino *i) /* local inode */
{

#if defined(HAS_UW_CFS)
    cnode_t cn;
#endif /* defined(HAS_UW_CFS) */

    struct vnode fa;
    struct mnode mn;
    struct inode sn;

#if defined(HASXNAMNODE)
    struct xnamnode xn;
#endif /* defined(HASXNAMNODE) */

    i->nlink_def = 0;
    if (fx < 1 || fx > Fsinfomax || !v->v_data)
        return (1);
    if (!strcmp(Fsinfo[fx - 1], "fifofs") || !strcmp(Fsinfo[fx - 1], "sfs") ||
        !strcmp(Fsinfo[fx - 1], "ufs")) {
        if (kread(ctx, (KA_T)v->v_data, (char *)&sn, sizeof(sn)))
            return (1);
        i->dev = sn.i_dev;
        i->dev_def = 1;
        i->rdev = v->v_rdev;
        i->rdev_def = 1;
        i->nlink = (long)sn.i_nlink;
        i->nlink_def = 1;
        i->nm = (char *)NULL;
        i->number = (INODETYPE)sn.i_number;
        i->size = (SZOFFTYPE)sn.i_size;
        i->size_def = 1;
        return (0);
    }

#if defined(HAS_UW_CFS)
    else if (!strcmp(Fsinfo[fx - 1], "nsc_cfs")) {
        if (kread(ctx, (KA_T)v->v_data, (char *)&cn, sizeof(cn)))
            return (1);
        if (cn.c_attr.va_mask & AT_FSID) {
            i->dev = cn.c_attr.va_fsid;
            i->dev_def = 1;
        } else
            i->dev_def = 0;
        i->rdev = v->v_rdev;
        i->rdev_def = 1;
        if (cn.c_attr.va_mask & AT_NLINK) {
            i->nlink = cn.c_attr.va_nlink;
            i->nlink_def = 1;
        } else
            i->nlink_def = 0;
        i->nm = (char *)NULL;
        if (cn.c_attr.va_mask & AT_NODEID) {
            i->number = (INODETYPE)cn.c_attr.va_nodeid;
            i->number_def = 1;
        } else
            i->number_def = 0;
        if (cn.c_attr.va_mask & AT_SIZE) {
            i->size = cn.c_attr.va_size;
            i->size_def = 1;
        } else
            i->size_def = 0;
        return (0);
    }
#endif /* defined(HAS_UW_CFS) */

    else if (!strcmp(Fsinfo[fx - 1], "s5"))
        return (reads5lino(v, i));
    else if (!strcmp(Fsinfo[fx - 1], "vxfs"))
        return (readvxfslino(v, i));
    else if (!strcmp(Fsinfo[fx - 1], "bfs"))
        return (readbfslino(v, i));

#if defined(HASXNAMNODE)
    else if (!strcmp(Fsinfo[fx - 1], "xnamfs") ||
             !strcmp(Fsinfo[fx - 1], "XENIX")) {
        if (kread(ctx, (KA_T)v->v_data, (char *)&xn, sizeof(xn)))
            return (1);
        i->dev = xn.x_dev;
        i->nlink = (long)xn.x_count;
        i->nlink_def = 1;
        i->nm = (char *)NULL;
        i->rdev = xn.x_fsid;
        i->size = xn.x_size;
        return (0);
    }
#endif /* defined(HASXNAMNODE) */

    else if (!strcmp(Fsinfo[fx - 1], "memfs")) {
        if (kread(ctx, (KA_T)v->v_data, (char *)&mn, sizeof(mn)))
            return (1);
        i->dev = mn.mno_fsid;
        i->dev_def = 1;
        i->nlink = (long)mn.mno_nlink;
        i->nlink_def = 1;
        i->nm = (char *)NULL;
        i->number = (INODETYPE)mn.mno_nodeid;
        i->number_def = 1;
        i->rdev = mn.mno_rdev;
        i->rdev = mn.mno_rdev;
        i->size = (SZOFFTYPE)mn.mno_size;
        i->size_def = 1;
        return (0);
    }

#if UNIXWAREV >= 70000
    else if (!strcmp(Fsinfo[fx - 1], "cdfs"))
        return readcdfslino(v, i);
    else if (!strcmp(Fsinfo[fx - 1], "dosfs"))
        return readdosfslino(v, i);
#endif /* UNIXWAREV>=70000 */

    return (1);
}
