/*
 * dmnt.c - /dev/kmem-based HP-UX mount support 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 _TIME_T
typedef int time_t;
#endif /* defined(HPUXKERNBITS) && HPUXKERNBITS>=64 */

#include "common.h"

/*
 * Local static definitions
 */

/*
 * completevfs() - complete local vfs structure
 */
void

#if HPUXV >= 800
    completevfs(vfs, dev,
                v) struct l_vfs *vfs; /* local vfs structure pointer */
dev_t *dev;                           /* device */
struct vfs *v;                        /* kernel vfs structure */
#else                                 /* HPUXV<800 */
    completevfs(vfs, dev) struct l_vfs *vfs; /* local vfs structure pointer */
dev_t *dev;                                  /* device */
#endif                                /* HPUXV>=800 */

{
    struct mounts *mp;
    /*
     * If only Internet socket files are selected, don't bother completing the
     * local vfs structure.
     */
    if (Selinet)
        return;

#if HPUXV >= 800
    /*
     * On HP-UX 8 and above, first search the local mount table for a match on
     * the file system name from the vfs structure.
     */
    if (v) {
        for (mp = readmnt(); mp; mp = mp->next) {
            if (strcmp(mp->fsname, v->vfs_name) == 0) {
                vfs->dev = mp->dev;
                vfs->dir = mp->dir;
                vfs->fsname = mp->fsname;

#    if defined(HASFSINO)
                vfs->fs_ino = mp->inode;
#    endif /* defined(HASFSINO) */

                return;
            }
        }
    }
#endif /* HPUXV>=800 */

    /*
     * Search for a match on device number.
     */
    for (mp = readmnt(); mp; mp = mp->next) {
        if (mp->dev == *dev) {
            vfs->dev = mp->dev;
            vfs->dir = mp->dir;
            vfs->fsname = mp->fsname;

#if defined(HASFSINO)
            vfs->fs_ino = mp->inode;
#endif /* defined(HASFSINO) */

            return;
        }
    }

#if HPUXV >= 800
    /*
     * If the file system name and device number searches fail, use the
     * vfs structure name, if there is one.  Determine the device number
     * with statsafely().
     */
    if (v && v->vfs_name[0]) {

        struct stat sb;

        if (!(vfs->dir = mkstrcpy(v->vfs_name, (MALLOC_S *)NULL))) {
            (void)fprintf(stderr, "%s: no space for vfs name: ", Pn);
            safestrprt(v->vfs_name, stderr, 1);
            Error(ctx);
        }
        if (statsafely(v->vfs_name, &sb) == 0)
            vfs->dev = sb.st_dev;
        else
            vfs->dev = (dev_t)0;

#    if defined(HASFSINO)
        vfs->fs_ino = (INODETYPE)0;
#    endif /* defined(HASFSINO) */
    }
#endif /* HPUXV>=800 */
}

/*
 * readvfs() - read vfs structure
 */

struct l_vfs *readvfs(struct vnode *lv) /* local vnode */
{
    struct mount m;
    struct mntinfo mi;
    int ms;
    dev_t td;
    struct vfs v;
    struct l_vfs *vp;

    if (!lv->v_vfsp)
        return ((struct l_vfs *)NULL);
    for (vp = Lvfs; vp; vp = vp->next) {
        if ((KA_T)lv->v_vfsp == vp->addr)
            return (vp);
    }
    if ((vp = (struct l_vfs *)malloc(sizeof(struct l_vfs))) == NULL) {
        (void)fprintf(stderr, "%s: PID %d, no space for vfs\n", Pn, Lp->pid);
        Error(ctx);
    }
    vp->dev = 0;
    vp->dir = (char *)NULL;
    vp->fsname = (char *)NULL;

#if defined(HASFSINO)
    vp->fs_ino = 0;
#endif /* defined(HASFSINO) */

    if (lv->v_vfsp && kread(ctx, (KA_T)lv->v_vfsp, (char *)&v, sizeof(v))) {
        (void)free((FREE_P *)vp);
        return ((struct l_vfs *)NULL);
    }
    /*
     * Complete the mount information.
     */
    if (Ntype == N_NFS) {

        /*
         * The device number for an NFS file is found by following the vfs
         * private data pointer to an mntinfo structure.
         */
        if (v.vfs_data &&
            kread(ctx, (KA_T)v.vfs_data, (char *)&mi, sizeof(mi)) == 0) {

#if HPUXV < 1020
            td = (dev_t)makedev(255, (int)mi.mi_mntno);
#else  /* HPUXV>=1020 */
            td = mi.mi_mntno;
#endif /* HPUXV<1020 */

#if HPUXV >= 800
            (void)completevfs(vp, &td, (struct vfs *)NULL);
#else  /* HPUXV<800 */
            (void)completevfs(vp, &td);
#endif /* HPUXV>=800 */
        }
    } else {
        if (v.vfs_data) {
            if (kread(ctx, (KA_T)v.vfs_data, (char *)&m, sizeof(m)) == 0)
                ms = 1;
            else
                ms = 0;
        }

#if defined(HAS_AFS)
        /*
         * Fake the device number for an AFS device.
         */
        else if (Ntype == N_AFS) {
            m.m_dev = AFSDEV;
            ms = 1;
        }
#endif /* defined(HAS_AFS) */

        else
            ms = 0;
        if (ms)

#if HPUXV >= 800
#    if HPUXV < 1000
            (void)completevfs(vp, (dev_t *)&m.m_dev, &v);
#    else  /* HPUXV>=1000 */
            (void)completevfs(
                vp, v.vfs_dev ? (dev_t *)&v.vfs_dev : (dev_t *)&m.m_dev, &v);
#    endif /* HPUXV<1000 */
#else      /* HPUXV<800 */
            (void)completevfs(vp, (dev_t *)&m.m_dev);
#endif     /* HPUXV>=800 */
    }
    /*
     * Complete local vfs structure and link to the others.
     */
    vp->next = Lvfs;
    vp->addr = (KA_T)lv->v_vfsp;
    Lvfs = vp;
    return (vp);
}
