/*
 * 5799-WZQ (C) COPYRIGHT = NONE
 * LICENSED MATERIALS - PROPERTY OF IBM
 */
/* $Header:mtab.c 12.0$ */
/* $ACIS:mtab.c 12.0$ */
/* $Source: /ibm/acis/usr/src/ibm/rvd/client/RCS/mtab.c,v $ */

#ifndef lint
static char *rcsid = "$Header:mtab.c 12.0$";
#endif

#ifndef lint
static char *rcsid_mtab_c = "$Header:mtab.c 12.0$";
#endif
/*
 * $Author: root $
 * $Source: /ibm/acis/usr/src/ibm/rvd/client/RCS/mtab.c,v $
 */
#define _MTAB_C_

#include <sys/nfs_defines.h>
#include "mTab.h"
#include "util.h"

static int mtab_dirty = FALSE;
static int mtab_n = -1;
static int mtab_fd = -1;
static mtab_t mtab_db[NMOUNT];

static int _dflag = 0;
#define debug if(_dflag)printf

void
mtab_debugOn()
{
    _dflag = 1;
}

void
mtab_debugOff()
{
    _dflag = 0;
}


int				     /* => # mtab entries or -errno */
mtab_init()
{
    int mtablen = MTAB_LEN;
    char *db = (char *)mtab_db;

    if (mtab_n >= 0)
        return(mtab_n);

    debug("mtab$init()\n");

    if (util_yankFile(MTAB, &db, &mtablen, &mtab_fd))
        return(-errno);

    mtab_n = mtablen / sizeof(mtab_t);
    mtab_n = mtab_compress();

    debug("mtab$init: => %d\n", mtab_n);
    return(mtab_n);
}


#ifndef VFS
void
mtab_reset()
{
    debug("mtab$reset()\n");
    bzero((char *)mtab_db, MTAB_LEN);
    close(mtab_fd);
    mtab_n = mtab_fd = -1;
}
#endif


#ifndef VFS
mtab_p				     /* => (mtab_t *) or NULL */
mtab_byDir(dir)
    char *dir;
{
    register mtab_t *m;

    debug("mtab$byDir(%s)\n", dir);

    if (mtab_init() < 0) {
        debug("mtab$byDir: init failed\n");
        return(errno=0,ZMTAB);
    }

    for (m = mtab_db; m < &mtab_db[mtab_n]; m++) {
        debug("mtab$byDir: '%s' vs[%d] '%s'\n", dir, MTAB_DIR, m->m_path);
        if (!strncmp(dir, m->m_path, MTAB_DIR))
            return(m);
    }

    debug("mtab$byDir: not found\n");
    return(errno=0,ZMTAB);
}
#endif


mtab_p				     /* => (mtab_t *) or NULL */
mtab_byNam(dev)
    char *dev;
{
    register mtab_t *m;

    debug("mtab$byNam(%s)\n", dev);

    if (mtab_init() < 0) {
        debug("mtab$byNam: init failed\n");
        return(errno=0,ZMTAB);
    }

    dev = basename(dev);

    for (m = mtab_db; m < &mtab_db[mtab_n]; m++) {
        debug("mtab$byNam: '%s' vs[%d] '%s'\n", m->m_dname, MTAB_DEV, dev);
        if (!strncmp(m->m_dname, dev, MTAB_DEV))
            return(m);
    }

    debug("mtab$byNam: not found\n");
    return(errno=0,ZMTAB);
}


#ifndef VFS
int				     /* => errno */
mtab_mount(spec, dir, type)
    char *spec;
    char *dir;
    char *type;
{
    register mtab_t *mp;

    debug("mtab$mount(%s, %s, %s)\n", spec,dir,type);

#ifndef VFS
    if (mount(spec, dir, strcmp(type, FSTAB_RO)==0) < 0) {
        debug("mtab$mount: => errno %d\n", errno);
        return(errno);
    }
#else /* !VFS */
    {
    struct ufs_args ufs_data;

    ufs_data.fspec = spec;
    if (mount(MOUNT_UFS, dir, (strcmp(type, FSTAB_RO)==0), &ufs_data)<0) {
	perror(dir);
        debug("mtab$mount: => errno %d\n", errno);
        return(errno);
    }
    }
#endif /* !VFS */

    if (mtab_init() < 0) {
        debug("mtab$mount: init failed\n");
        return(errno=0);
    }

    spec = basename(spec);

    for (mp = mtab_db; mp < &mtab_db[NMOUNT]; mp++) {
        debug("mtab$mount: %s vs[%d] %s\n", mp->m_dname, MTAB_DEV, spec);
        if (!strncmp(mp->m_dname, spec, MTAB_DEV))
            goto Replace;
        if (mp->m_path[0] == NIL) {
            mtab_n++;		     /* at end of list; expand list... */
            goto Replace;
        }
    }

    debug("mtab$mount: mtab-kernel not in sync!\n");
    return(errno=0);

Replace:
    strncpy(mp->m_dname, spec, MTAB_DEV);
    strncpy(mp->m_path, dir, MTAB_DIR);
    strcpy(mp->m_type, type);

    mtab_dirty = TRUE;

    debug("mtab$mount: mtab_n=%d\n", mtab_n);
    return(errno=0);
}
#endif


static mtab_t mtab_zilch;

#ifndef VFS
int				     /* => errno */
mtab_umount(spec)
    char *spec;
{
    register mtab_t *mp;

    debug("mtab$umount(%s)\n",spec);

    sync();

    if (unmount(spec) < 0) {
        debug("mtab$umount: => errno %d\n", errno);
        return(errno);
    }

    if (mtab_init() < 0) {
        debug("mtab$umount: init failed\n");
        return(errno);
    }

    spec = basename(spec);

    for (mp = mtab_db; mp < &mtab_db[mtab_n]; mp++) {
        debug("mtab$umount: %s vs[%d] %s\n",mp->m_dname,MTAB_DEV,spec);
        if (!strncmp(mp->m_dname, spec, MTAB_DEV)) {
            --mtab_n;
            debug("mtab$umount: %s on %s (mtab_n %d)\n",
                mp->m_dname, mp->m_path, mtab_n);
            if (mp != &mtab_db[mtab_n]) {
                debug("mtab$umount: move last\n");
                *mp = mtab_db[mtab_n];
            } else {
                debug("mtab$umount: zero last\n");
            }
            mtab_db[mtab_n] = mtab_zilch;
            mtab_dirty = TRUE;
            debug("mtab$umount: mtab_n=%d\n",mtab_n);
            return(errno=0);
        }
    }

    debug("mtab$umount: %s not found\n", spec);
    return(errno=0);
}
#endif


#ifndef VFS
void
mtab_sync()
{
    register int fd;

    debug("mtab$sync(mtab_n=%d)\n", mtab_n);

    if (mtab_n < 0 || mtab_dirty == FALSE) {
        debug("mtab$sync: no init or nothing to sync\n");
        return;
    }

    fd = creat(MTAB, MTAB_MOD);
    write(fd, (char *)mtab_db, mtab_n * sizeof(mtab_t));
    close(fd);

    errno = 0;
}
#endif


int				     /* => # of real entries in mtab_db[] */
mtab_compress()
{
    register int n;
    register mtab_t *mp, *runner;

    debug("mtab$compress()\n");

    if (mtab_n < 0) {
        debug("mtab$compress: bad seq; no init\n");
        panic("bad calling sequence: mtab$compress() before mtab$init()");
    }

    for (n = 0, mp = runner = mtab_db; runner < &mtab_db[mtab_n]; runner++) {
        if (runner->m_path[0]) {
            debug("mtab$compress: %s on %s\n", runner->m_dname, runner->m_path);
            n++;
            if (runner != mp)
                *mp++ = *runner;
            else
                mp++;
        }
    }

    for ( ; mp < &mtab_db[NMOUNT]; mp++)
        *mp = mtab_zilch;

    debug("mtab$compress: => mtab_n=%d\n", n);
    return(n);
}
