/*
 * dmnt.c - SCO OpenServer mount support functions for lsof
 */

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

#include "common.h"

/*
 * Local static definitions
 */

/*
 * readmnt() - read mount table
 */

struct mounts *readmnt() {
    int br, fd;
    int bx = sizeof(struct mnttab);
    char *cp;
    char dvnm[MAXPATHLEN], fsnm[MAXPATHLEN];
    MALLOC_S dvnml, fsnml;
    MALLOC_S len;
    char *ln = (char *)NULL;
    struct mnttab m;
    struct mounts *mtp;
    struct stat sb;

    if (Lmi || Lmist)
        return (Lmi);
    /*
     * Open access to the mount table.
     */
    if ((fd = open(MNTTAB, O_RDONLY, 0)) < 0) {
        (void)fprintf(stderr, "%s: can't open %s\n", Pn, MNTTAB);
        Error(ctx);
    }
    /*
     * Read the first mount table entry.
     */
    br = read(fd, (char *)&m, bx);
    dvnml = fsnml = 0;
    /*
     * Process the next complete mount table entry.
     */
    while (br == bx) {
        if (!dvnml) {

            /*
             * Start the device and file system name assemblies.
             */
            dvnml = strlen(m.mt_dev);
            if (dvnml >= MAXPATHLEN)
                dvnml = MAXPATHLEN - 1;
            (void)strncpy(dvnm, m.mt_dev, dvnml);
            dvnm[dvnml] = '\0';
            fsnml = strlen(m.mt_filsys);
            if (fsnml >= MAXPATHLEN)
                fsnml = MAXPATHLEN - 1;
            (void)strncpy(fsnm, m.mt_filsys, fsnml);
            fsnm[fsnml] = '\0';
        }
        while ((br = read(fd, (char *)&m, bx)) == bx &&
               strcmp(m.mt_filsys, "nothing") == 0 &&
               strcmp(m.mt_dev, "nowhere") == 0) {

            /*
             * Add the "nothing/nowhere" extensions to the assemblies.
             */
            len = strlen(&m.mt_dev[8]);
            if (len >= (MAXPATHLEN - dvnml))
                len = MAXPATHLEN - dvnml - 1;
            if (len) {
                (void)strncpy(&dvnm[dvnml], &m.mt_dev[8], len);
                dvnml += len;
                dvnm[dvnml] = '\0';
            }
            len = strlen(&m.mt_filsys[8]);
            if (len >= (MAXPATHLEN - fsnml))
                len = MAXPATHLEN - fsnml - 1;
            if (len) {
                (void)strncpy(&fsnm[fsnml], &m.mt_filsys[8], len);
                fsnml += len;
                fsnm[fsnml] = '\0';
            }
        }
        /*
         * Skip automount place markers.
         */
        if ((cp = strrchr(dvnm, ':')) && strncmp(cp, ":(pid", 5) == 0) {
            dvnml = fsnml = 0;
            continue;
        }
        /*
         * Interpolate a possible symbolic directory link.
         */
        if (ln) {
            (void)free((FREE_P *)ln);
            ln = (char *)NULL;
        }
        if (!(ln = Readlink(fsnm))) {
            if (!Fwarn) {
                (void)fprintf(stderr,
                              "      Output information may be incomplete.\n");
            }
            dvnml = fsnml = 0;
            continue;
        }
        if (*ln != '/')
            continue;
        if (ln == fsnm) {

            /*
             * Allocate space for a copy of the file system name.
             */
            if (!(ln = mkstrcpy(fsnm, (MALLOC_S *)NULL))) {

            no_space_for_mount:

                (void)fprintf(stderr, "%s: no space for mount at ", Pn);
                safestrprt(fsnm, stderr, 0);
                (void)fprintf(stderr, " (");
                safestrprt(dvnm, stderr, 0);
                (void)fprintf(stderr, ")\n");
                Error(ctx);
            }
        }
        /*
         * Stat() the directory.
         */
        if (statsafely(ln, &sb)) {
            if (!Fwarn) {
                (void)fprintf(stderr,
                              "%s: WARNING: can't stat() file system: ", Pn);
                safestrprt(fsnm, stderr, 1);
                (void)fprintf(stderr,
                              "      Output information may be incomplete.\n");
            }
            dvnml = fsnml = 0;
            continue;
        }
        /*
         * Allocate and fill a local mount structure.
         */
        if (!(mtp = (struct mounts *)malloc(sizeof(struct mounts))))
            goto no_space_for_mount;
        mtp->dir = ln;
        ln = (char *)NULL;
        mtp->next = Lmi;
        mtp->dev = sb.st_dev;
        mtp->rdev = sb.st_rdev;
        mtp->inode = (INODETYPE)sb.st_ino;
        mtp->mode = sb.st_mode;
        /*
         * Interpolate a possible file system (mounted-on) device name link
         */
        if (!(cp = mkstrcpy(dvnm, (MALLOC_S *)NULL)))
            goto no_space_for_mount;
        mtp->fsname = cp;
        ln = Readlink(cp);
        /*
         * Stat() the file system (mounted-on) name and add file system
         * information to the local mount table entry.
         */
        if (statsafely(ln, &sb))
            sb.st_mode = 0;
        mtp->fsnmres = ln;
        ln = (char *)NULL;
        mtp->fs_mode = sb.st_mode;
        Lmi = mtp;
        dvnml = fsnml = 0;
    }
    (void)close(fd);
    /*
     * Clean up and return the local mount information table address.
     */
    if (ln)
        (void)free((FREE_P *)ln);
    Lmist = 1;
    return (Lmi);
}
