diff options
Diffstat (limited to 'usr.sbin/amd/amd/nfsx_ops.c')
-rw-r--r-- | usr.sbin/amd/amd/nfsx_ops.c | 516 |
1 files changed, 516 insertions, 0 deletions
diff --git a/usr.sbin/amd/amd/nfsx_ops.c b/usr.sbin/amd/amd/nfsx_ops.c new file mode 100644 index 000000000000..ba18cdcfebe8 --- /dev/null +++ b/usr.sbin/amd/amd/nfsx_ops.c @@ -0,0 +1,516 @@ +/* + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)nfsx_ops.c 8.1 (Berkeley) 6/6/93 + * + * $Id: nfsx_ops.c,v 5.2.2.3 1992/05/31 16:13:07 jsp Exp $ + * + */ + +#include "am.h" + +#ifdef HAS_NFSX + +/* + * NFS hierarchical mounts + * + * TODO: Re-implement. + */ + +/* + * The rfs field contains a list of mounts to be done from + * the remote host. + */ +typedef struct nfsx_mnt { + mntfs *n_mnt; + int n_error; +} nfsx_mnt; + +struct nfsx { + int nx_c; /* Number of elements in nx_v */ + nfsx_mnt *nx_v; /* Underlying mounts */ + nfsx_mnt *nx_try; +}; + +static int nfsx_fmount P((mntfs*)); + +static char *nfsx_match(fo) +am_opts *fo; +{ + char *xmtab; + char *ptr; + int len; + + if (!fo->opt_rfs) { + plog(XLOG_USER, "nfsx: no remote filesystem specified"); + return FALSE; + } + if (!fo->opt_rhost) { + plog(XLOG_USER, "nfsx: no remote host specified"); + return FALSE; + } + +#ifdef notdef + /* fiddle sublink, must be last... */ + if (fo->opt_sublink) { + plog(XLOG_WARNING, "nfsx: sublink %s ignored", fo->opt_sublink); + free((voidp) fo->opt_sublink); + fo->opt_sublink = 0; + } +#endif + + /* set default sublink */ + if (fo->opt_sublink == 0) { + ptr = strchr(fo->opt_rfs, ','); + if (ptr && ptr != (fo->opt_rfs + 1)) + fo->opt_sublink = strnsave(fo->opt_rfs + 1, ptr - fo->opt_rfs - 1); + } + + /* + * Remove trailing ",..." from ${fs} + * After deslashifying, overwrite the end of ${fs} with "/" + * to make sure it is unique. + */ + if (ptr = strchr(fo->opt_fs, ',')) + *ptr = '\0'; + deslashify(fo->opt_fs); + /* + * Bump string length to allow trailing / + */ + len = strlen(fo->opt_fs); + fo->opt_fs = xrealloc(fo->opt_fs, len + 1 + 1); + ptr = fo->opt_fs + len; + /* + * Make unique... + */ + *ptr++ = '/'; + *ptr = '\0'; + + /* + * Determine magic cookie to put in mtab + */ + xmtab = str3cat((char *) 0, fo->opt_rhost, ":", fo->opt_rfs); +#ifdef DEBUG + dlog("NFS: mounting remote server \"%s\", remote fs \"%s\" on \"%s\"", + fo->opt_rhost, fo->opt_rfs, fo->opt_fs); +#endif /* DEBUG */ + + return xmtab; +} + +static void nfsx_prfree P((voidp vp)); +static void nfsx_prfree(vp) +voidp vp; +{ + struct nfsx *nx = (struct nfsx *) vp; + int i; + + for (i = 0; i < nx->nx_c; i++) { + mntfs *m = nx->nx_v[i].n_mnt; + if (m) + free_mntfs(m); + } + + free((voidp) nx->nx_v); + free((voidp) nx); +} + +static int nfsx_init(mf) +mntfs *mf; +{ + /* + * mf_info has the form: + * host:/prefix/path,sub,sub,sub + */ + int i; + int glob_error; + struct nfsx *nx; + int asked_for_wakeup = 0; + + nx = (struct nfsx *) mf->mf_private; + + if (nx == 0) { + char **ivec; + char *info = 0; + char *host; + char *pref; + int error = 0; + + info = strdup(mf->mf_info); + host = strchr(info, ':'); + if (!host) { + error = EINVAL; + goto errexit; + } + + pref = host+1; + host = info; + + /* + * Split the prefix off from the suffices + */ + ivec = strsplit(pref, ',', '\''); + + /* + * Count array size + */ + for (i = 0; ivec[i]; i++) + ; + + nx = ALLOC(nfsx); + mf->mf_private = (voidp) nx; + mf->mf_prfree = nfsx_prfree; + + nx->nx_c = i - 1; /* i-1 because we don't want the prefix */ + nx->nx_v = (nfsx_mnt *) xmalloc(nx->nx_c * sizeof(nfsx_mnt)); + { char *mp = 0; + char *xinfo = 0; + char *fs = mf->mf_fo->opt_fs; + char *rfs = 0; + for (i = 0; i < nx->nx_c; i++) { + char *path = ivec[i+1]; + rfs = str3cat(rfs, pref, "/", path); + /* + * Determine the mount point. + * If this is the root, then don't remove + * the trailing slash to avoid mntfs name clashes. + */ + mp = str3cat(mp, fs, "/", rfs); + normalize_slash(mp); + deslashify(mp); + /* + * Determine the mount info + */ + xinfo = str3cat(xinfo, host, *path == '/' ? "" : "/", path); + normalize_slash(xinfo); + if (pref[1] != '\0') + deslashify(xinfo); +#ifdef DEBUG + dlog("nfsx: init mount for %s on %s", xinfo, mp); +#endif + nx->nx_v[i].n_error = -1; + nx->nx_v[i].n_mnt = find_mntfs(&nfs_ops, mf->mf_fo, mp, xinfo, "", mf->mf_mopts, mf->mf_remopts); + } + if (rfs) free(rfs); + if (mp) free(mp); + if (xinfo) free(xinfo); + } + + free((voidp) ivec); +errexit: + if (info) + free(info); + if (error) + return error; + } + + /* + * Iterate through the mntfs's and call + * the underlying init routine on each + */ + glob_error = 0; + for (i = 0; i < nx->nx_c; i++) { + nfsx_mnt *n = &nx->nx_v[i]; + mntfs *m = n->n_mnt; + int error = (*m->mf_ops->fs_init)(m); + /* + * If HARD_NFSX_ERRORS is defined, make any + * initialisation failure a hard error and + * fail the entire group. Otherwise only fail + * if none of the group is mountable (see nfsx_fmount). + */ +#ifdef HARD_NFSX_ERRORS + if (error > 0) + return error; +#else + if (error > 0) + n->n_error = error; +#endif + else if (error < 0) { + glob_error = -1; + if (!asked_for_wakeup) { + asked_for_wakeup = 1; + sched_task(wakeup_task, (voidp) mf, (voidp) m); + } + } + } + + return glob_error; +} + +static void nfsx_cont P((int rc, int term, voidp closure)); +static void nfsx_cont(rc, term, closure) +int rc; +int term; +voidp closure; +{ + mntfs *mf = (mntfs *) closure; + struct nfsx *nx = (struct nfsx *) mf->mf_private; + nfsx_mnt *n = nx->nx_try; + + n->n_mnt->mf_flags &= ~(MFF_ERROR|MFF_MOUNTING); + mf->mf_flags &= ~MFF_ERROR; + + /* + * Wakeup anything waiting for this mount + */ + wakeup((voidp) n->n_mnt); + + if (rc || term) { + if (term) { + /* + * Not sure what to do for an error code. + */ + plog(XLOG_ERROR, "mount for %s got signal %d", n->n_mnt->mf_mount, term); + n->n_error = EIO; + } else { + /* + * Check for exit status + */ + errno = rc; /* XXX */ + plog(XLOG_ERROR, "%s: mount (nfsx_cont): %m", n->n_mnt->mf_mount); + n->n_error = rc; + } + free_mntfs(n->n_mnt); + n->n_mnt = new_mntfs(); + n->n_mnt->mf_error = n->n_error; + n->n_mnt->mf_flags |= MFF_ERROR; + } else { + /* + * The mount worked. + */ + mf_mounted(n->n_mnt); + n->n_error = 0; + } + + /* + * Do the remaining bits + */ + if (nfsx_fmount(mf) >= 0) { + wakeup((voidp) mf); + mf->mf_flags &= ~MFF_MOUNTING; + mf_mounted(mf); + } +} + +static int try_nfsx_mount P((voidp mv)); +static int try_nfsx_mount(mv) +voidp mv; +{ + mntfs *mf = (mntfs *) mv; + int error; + + mf->mf_flags |= MFF_MOUNTING; + error = (*mf->mf_ops->fmount_fs)(mf); + mf->mf_flags &= ~MFF_MOUNTING; + return error; +} + +static int nfsx_remount P((mntfs *mf, int fg)); +static int nfsx_remount(mf, fg) +mntfs *mf; +int fg; +{ + struct nfsx *nx = (struct nfsx *) mf->mf_private; + nfsx_mnt *n; + int glob_error = -1; + + for (n = nx->nx_v; n < nx->nx_v + nx->nx_c; n++) { + mntfs *m = n->n_mnt; + if (n->n_error < 0) { + if (!(m->mf_flags & MFF_MKMNT) && m->mf_ops->fs_flags & FS_MKMNT) { + int error = mkdirs(m->mf_mount, 0555); + if (!error) + m->mf_flags |= MFF_MKMNT; + } + } + } + + /* + * Iterate through the mntfs's and mount each filesystem + * which is not yet mounted. + */ + for (n = nx->nx_v; n < nx->nx_v + nx->nx_c; n++) { + mntfs *m = n->n_mnt; + if (n->n_error < 0) { + /* + * Check fmount entry pt. exists + * and then mount... + */ + if (!m->mf_ops->fmount_fs) { + n->n_error = EINVAL; + } else { +#ifdef DEBUG + dlog("calling underlying fmount on %s", m->mf_mount); +#endif + if (!fg && foreground && (m->mf_ops->fs_flags & FS_MBACKGROUND)) { + m->mf_flags |= MFF_MOUNTING; /* XXX */ +#ifdef DEBUG + dlog("backgrounding mount of \"%s\"", m->mf_info); +#endif + nx->nx_try = n; + run_task(try_nfsx_mount, (voidp) m, nfsx_cont, (voidp) mf); + n->n_error = -1; + return -1; + } else { +#ifdef DEBUG + dlog("foreground mount of \"%s\" ...", mf->mf_info); +#endif + n->n_error = (*m->mf_ops->fmount_fs)(m); + } + } +#ifdef DEBUG + if (n->n_error > 0) { + errno = n->n_error; /* XXX */ + dlog("underlying fmount of %s failed: %m", m->mf_mount); + } +#endif + if (n->n_error == 0) { + glob_error = 0; + } else if (glob_error < 0) { + glob_error = n->n_error; + } + } + } + + return glob_error < 0 ? 0 : glob_error; +} + +static int nfsx_fmount P((mntfs *mf)); +static int nfsx_fmount(mf) +mntfs *mf; +{ + return nfsx_remount(mf, FALSE); +} + +/* + * Unmount an NFS hierarchy. + * Note that this is called in the foreground + * and so may hang under extremely rare conditions. + */ +static int nfsx_fumount(mf) +mntfs *mf; +{ + struct nfsx *nx = (struct nfsx *) mf->mf_private; + nfsx_mnt *n; + int glob_error = 0; + + /* + * Iterate in reverse through the mntfs's and unmount each filesystem + * which is mounted. + */ + for (n = nx->nx_v + nx->nx_c - 1; n >= nx->nx_v; --n) { + mntfs *m = n->n_mnt; + /* + * If this node has not been messed with + * and there has been no error so far + * then try and unmount. + * If an error had occured then zero + * the error code so that the remount + * only tries to unmount those nodes + * which had been successfully unmounted. + */ + if (n->n_error == 0) { +#ifdef DEBUG + dlog("calling underlying fumount on %s", m->mf_mount); +#endif + n->n_error = (*m->mf_ops->fumount_fs)(m); + if (n->n_error) { + glob_error = n->n_error; + n->n_error = 0; + } else { + /* + * Make sure remount gets this node + */ + n->n_error = -1; + } + } + } + + /* + * If any unmounts failed then remount the + * whole lot... + */ + if (glob_error) { + glob_error = nfsx_remount(mf, TRUE); + if (glob_error) { + errno = glob_error; /* XXX */ + plog(XLOG_USER, "nfsx: remount of %s failed: %m", mf->mf_mount); + } + glob_error = EBUSY; + } else { + /* + * Remove all the mount points + */ + for (n = nx->nx_v; n < nx->nx_v + nx->nx_c; n++) { + mntfs *m = n->n_mnt; + if (n->n_error < 0) { + if (m->mf_ops->fs_flags & FS_MKMNT) { + (void) rmdirs(m->mf_mount); + m->mf_flags &= ~MFF_MKMNT; + } + } + free_mntfs(m); + n->n_mnt = 0; + n->n_error = -1; + } + } + + return glob_error; +} + +/* + * Ops structure + */ +am_ops nfsx_ops = { + "nfsx", + nfsx_match, + nfsx_init, + auto_fmount, + nfsx_fmount, + auto_fumount, + nfsx_fumount, + efs_lookuppn, + efs_readdir, + 0, /* nfsx_readlink */ + 0, /* nfsx_mounted */ + 0, /* nfsx_umounted */ + find_nfs_srvr, /* XXX */ + /*FS_UBACKGROUND|*/FS_AMQINFO +}; + +#endif /* HAS_NFSX */ |