14957d392Spendry /*
24957d392Spendry * Copyright (c) 1990 Jan-Simon Pendry
34957d392Spendry * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
4*4092c5ccSbostic * Copyright (c) 1990, 1993
5*4092c5ccSbostic * The Regents of the University of California. All rights reserved.
64957d392Spendry *
74957d392Spendry * This code is derived from software contributed to Berkeley by
84957d392Spendry * Jan-Simon Pendry at Imperial College, London.
94957d392Spendry *
108a89c22cSpendry * %sccs.include.redist.c%
114957d392Spendry *
12*4092c5ccSbostic * @(#)nfsx_ops.c 8.1 (Berkeley) 06/06/93
13c626267eSpendry *
1410042f30Spendry * $Id: nfsx_ops.c,v 5.2.2.3 1992/05/31 16:13:07 jsp Exp $
15c626267eSpendry *
164957d392Spendry */
174957d392Spendry
184957d392Spendry #include "am.h"
194957d392Spendry
204957d392Spendry #ifdef HAS_NFSX
214957d392Spendry
224957d392Spendry /*
234957d392Spendry * NFS hierarchical mounts
244957d392Spendry *
254957d392Spendry * TODO: Re-implement.
264957d392Spendry */
274957d392Spendry
284957d392Spendry /*
294957d392Spendry * The rfs field contains a list of mounts to be done from
304957d392Spendry * the remote host.
314957d392Spendry */
324957d392Spendry typedef struct nfsx_mnt {
334957d392Spendry mntfs *n_mnt;
344957d392Spendry int n_error;
354957d392Spendry } nfsx_mnt;
364957d392Spendry
374957d392Spendry struct nfsx {
384957d392Spendry int nx_c; /* Number of elements in nx_v */
394957d392Spendry nfsx_mnt *nx_v; /* Underlying mounts */
404957d392Spendry nfsx_mnt *nx_try;
414957d392Spendry };
424957d392Spendry
434957d392Spendry static int nfsx_fmount P((mntfs*));
444957d392Spendry
nfsx_match(fo)454957d392Spendry static char *nfsx_match(fo)
464957d392Spendry am_opts *fo;
474957d392Spendry {
484957d392Spendry char *xmtab;
494957d392Spendry char *ptr;
504957d392Spendry int len;
514957d392Spendry
524957d392Spendry if (!fo->opt_rfs) {
534957d392Spendry plog(XLOG_USER, "nfsx: no remote filesystem specified");
544957d392Spendry return FALSE;
554957d392Spendry }
564957d392Spendry if (!fo->opt_rhost) {
574957d392Spendry plog(XLOG_USER, "nfsx: no remote host specified");
584957d392Spendry return FALSE;
594957d392Spendry }
604957d392Spendry
61c626267eSpendry #ifdef notdef
624957d392Spendry /* fiddle sublink, must be last... */
634957d392Spendry if (fo->opt_sublink) {
644957d392Spendry plog(XLOG_WARNING, "nfsx: sublink %s ignored", fo->opt_sublink);
654957d392Spendry free((voidp) fo->opt_sublink);
664957d392Spendry fo->opt_sublink = 0;
674957d392Spendry }
68c626267eSpendry #endif
69c626267eSpendry
70c626267eSpendry /* set default sublink */
71c626267eSpendry if (fo->opt_sublink == 0) {
72c626267eSpendry ptr = strchr(fo->opt_rfs, ',');
73c626267eSpendry if (ptr && ptr != (fo->opt_rfs + 1))
74c626267eSpendry fo->opt_sublink = strnsave(fo->opt_rfs + 1, ptr - fo->opt_rfs - 1);
75c626267eSpendry }
764957d392Spendry
774957d392Spendry /*
784957d392Spendry * Remove trailing ",..." from ${fs}
794957d392Spendry * After deslashifying, overwrite the end of ${fs} with "/"
804957d392Spendry * to make sure it is unique.
814957d392Spendry */
824957d392Spendry if (ptr = strchr(fo->opt_fs, ','))
834957d392Spendry *ptr = '\0';
844957d392Spendry deslashify(fo->opt_fs);
8510042f30Spendry /*
8610042f30Spendry * Bump string length to allow trailing /
8710042f30Spendry */
884957d392Spendry len = strlen(fo->opt_fs);
8910042f30Spendry fo->opt_fs = xrealloc(fo->opt_fs, len + 1 + 1);
904957d392Spendry ptr = fo->opt_fs + len;
914957d392Spendry /*
924957d392Spendry * Make unique...
934957d392Spendry */
944957d392Spendry *ptr++ = '/';
954957d392Spendry *ptr = '\0';
964957d392Spendry
974957d392Spendry /*
984957d392Spendry * Determine magic cookie to put in mtab
994957d392Spendry */
10010042f30Spendry xmtab = str3cat((char *) 0, fo->opt_rhost, ":", fo->opt_rfs);
1014957d392Spendry #ifdef DEBUG
1024957d392Spendry dlog("NFS: mounting remote server \"%s\", remote fs \"%s\" on \"%s\"",
1034957d392Spendry fo->opt_rhost, fo->opt_rfs, fo->opt_fs);
1044957d392Spendry #endif /* DEBUG */
1054957d392Spendry
1064957d392Spendry return xmtab;
1074957d392Spendry }
1084957d392Spendry
1094957d392Spendry static void nfsx_prfree P((voidp vp));
nfsx_prfree(vp)1104957d392Spendry static void nfsx_prfree(vp)
1114957d392Spendry voidp vp;
1124957d392Spendry {
1134957d392Spendry struct nfsx *nx = (struct nfsx *) vp;
1144957d392Spendry int i;
1154957d392Spendry
1164957d392Spendry for (i = 0; i < nx->nx_c; i++) {
1174957d392Spendry mntfs *m = nx->nx_v[i].n_mnt;
1184957d392Spendry if (m)
1194957d392Spendry free_mntfs(m);
1204957d392Spendry }
1214957d392Spendry
1224957d392Spendry free((voidp) nx->nx_v);
1234957d392Spendry free((voidp) nx);
1244957d392Spendry }
1254957d392Spendry
nfsx_init(mf)1264957d392Spendry static int nfsx_init(mf)
1274957d392Spendry mntfs *mf;
1284957d392Spendry {
1294957d392Spendry /*
1304957d392Spendry * mf_info has the form:
1314957d392Spendry * host:/prefix/path,sub,sub,sub
1324957d392Spendry */
1334957d392Spendry int i;
1344957d392Spendry int glob_error;
1354957d392Spendry struct nfsx *nx;
136c626267eSpendry int asked_for_wakeup = 0;
1374957d392Spendry
1384957d392Spendry nx = (struct nfsx *) mf->mf_private;
1394957d392Spendry
1404957d392Spendry if (nx == 0) {
1414957d392Spendry char **ivec;
1424957d392Spendry char *info = 0;
1434957d392Spendry char *host;
1444957d392Spendry char *pref;
1454957d392Spendry int error = 0;
1464957d392Spendry
1474957d392Spendry info = strdup(mf->mf_info);
1484957d392Spendry host = strchr(info, ':');
1494957d392Spendry if (!host) {
1504957d392Spendry error = EINVAL;
1514957d392Spendry goto errexit;
1524957d392Spendry }
1534957d392Spendry
1544957d392Spendry pref = host+1;
1554957d392Spendry host = info;
1564957d392Spendry
1574957d392Spendry /*
1584957d392Spendry * Split the prefix off from the suffices
1594957d392Spendry */
1604957d392Spendry ivec = strsplit(pref, ',', '\'');
1614957d392Spendry
1624957d392Spendry /*
1634957d392Spendry * Count array size
1644957d392Spendry */
1654957d392Spendry for (i = 0; ivec[i]; i++)
1664957d392Spendry ;
1674957d392Spendry
1684957d392Spendry nx = ALLOC(nfsx);
1694957d392Spendry mf->mf_private = (voidp) nx;
1704957d392Spendry mf->mf_prfree = nfsx_prfree;
1714957d392Spendry
1724957d392Spendry nx->nx_c = i - 1; /* i-1 because we don't want the prefix */
1734957d392Spendry nx->nx_v = (nfsx_mnt *) xmalloc(nx->nx_c * sizeof(nfsx_mnt));
1744957d392Spendry { char *mp = 0;
1754957d392Spendry char *xinfo = 0;
1764957d392Spendry char *fs = mf->mf_fo->opt_fs;
1774957d392Spendry char *rfs = 0;
1784957d392Spendry for (i = 0; i < nx->nx_c; i++) {
1794957d392Spendry char *path = ivec[i+1];
1804957d392Spendry rfs = str3cat(rfs, pref, "/", path);
1814957d392Spendry /*
1824957d392Spendry * Determine the mount point.
1834957d392Spendry * If this is the root, then don't remove
1844957d392Spendry * the trailing slash to avoid mntfs name clashes.
1854957d392Spendry */
1864957d392Spendry mp = str3cat(mp, fs, "/", rfs);
1874957d392Spendry normalize_slash(mp);
1884957d392Spendry deslashify(mp);
1894957d392Spendry /*
1904957d392Spendry * Determine the mount info
1914957d392Spendry */
1924957d392Spendry xinfo = str3cat(xinfo, host, *path == '/' ? "" : "/", path);
1934957d392Spendry normalize_slash(xinfo);
1944957d392Spendry if (pref[1] != '\0')
1954957d392Spendry deslashify(xinfo);
1964957d392Spendry #ifdef DEBUG
1974957d392Spendry dlog("nfsx: init mount for %s on %s", xinfo, mp);
1984957d392Spendry #endif
1994957d392Spendry nx->nx_v[i].n_error = -1;
200cc0207dcSpendry nx->nx_v[i].n_mnt = find_mntfs(&nfs_ops, mf->mf_fo, mp, xinfo, "", mf->mf_mopts, mf->mf_remopts);
2014957d392Spendry }
2024957d392Spendry if (rfs) free(rfs);
2034957d392Spendry if (mp) free(mp);
2044957d392Spendry if (xinfo) free(xinfo);
2054957d392Spendry }
2064957d392Spendry
2074957d392Spendry free((voidp) ivec);
2084957d392Spendry errexit:
2094957d392Spendry if (info)
2104957d392Spendry free(info);
2114957d392Spendry if (error)
2124957d392Spendry return error;
2134957d392Spendry }
2144957d392Spendry
2154957d392Spendry /*
2164957d392Spendry * Iterate through the mntfs's and call
2174957d392Spendry * the underlying init routine on each
2184957d392Spendry */
2194957d392Spendry glob_error = 0;
2204957d392Spendry for (i = 0; i < nx->nx_c; i++) {
2214957d392Spendry nfsx_mnt *n = &nx->nx_v[i];
2224957d392Spendry mntfs *m = n->n_mnt;
2234957d392Spendry int error = (*m->mf_ops->fs_init)(m);
2244957d392Spendry /*
2254957d392Spendry * If HARD_NFSX_ERRORS is defined, make any
2264957d392Spendry * initialisation failure a hard error and
2274957d392Spendry * fail the entire group. Otherwise only fail
228c626267eSpendry * if none of the group is mountable (see nfsx_fmount).
2294957d392Spendry */
2304957d392Spendry #ifdef HARD_NFSX_ERRORS
2314957d392Spendry if (error > 0)
2324957d392Spendry return error;
2334957d392Spendry #else
2344957d392Spendry if (error > 0)
2354957d392Spendry n->n_error = error;
2364957d392Spendry #endif
237c626267eSpendry else if (error < 0) {
2384957d392Spendry glob_error = -1;
239c626267eSpendry if (!asked_for_wakeup) {
240c626267eSpendry asked_for_wakeup = 1;
241c626267eSpendry sched_task(wakeup_task, (voidp) mf, (voidp) m);
242c626267eSpendry }
243c626267eSpendry }
2444957d392Spendry }
2454957d392Spendry
2464957d392Spendry return glob_error;
2474957d392Spendry }
2484957d392Spendry
2494957d392Spendry static void nfsx_cont P((int rc, int term, voidp closure));
nfsx_cont(rc,term,closure)2504957d392Spendry static void nfsx_cont(rc, term, closure)
2514957d392Spendry int rc;
2524957d392Spendry int term;
2534957d392Spendry voidp closure;
2544957d392Spendry {
2554957d392Spendry mntfs *mf = (mntfs *) closure;
2564957d392Spendry struct nfsx *nx = (struct nfsx *) mf->mf_private;
2574957d392Spendry nfsx_mnt *n = nx->nx_try;
2584957d392Spendry
2594957d392Spendry n->n_mnt->mf_flags &= ~(MFF_ERROR|MFF_MOUNTING);
260c626267eSpendry mf->mf_flags &= ~MFF_ERROR;
2614957d392Spendry
2624957d392Spendry /*
2634957d392Spendry * Wakeup anything waiting for this mount
2644957d392Spendry */
265c626267eSpendry wakeup((voidp) n->n_mnt);
2664957d392Spendry
2674957d392Spendry if (rc || term) {
2684957d392Spendry if (term) {
2694957d392Spendry /*
2704957d392Spendry * Not sure what to do for an error code.
2714957d392Spendry */
2724957d392Spendry plog(XLOG_ERROR, "mount for %s got signal %d", n->n_mnt->mf_mount, term);
2734957d392Spendry n->n_error = EIO;
2744957d392Spendry } else {
2754957d392Spendry /*
2764957d392Spendry * Check for exit status
2774957d392Spendry */
2784957d392Spendry errno = rc; /* XXX */
2794957d392Spendry plog(XLOG_ERROR, "%s: mount (nfsx_cont): %m", n->n_mnt->mf_mount);
2804957d392Spendry n->n_error = rc;
2814957d392Spendry }
2824957d392Spendry free_mntfs(n->n_mnt);
2834957d392Spendry n->n_mnt = new_mntfs();
2844957d392Spendry n->n_mnt->mf_error = n->n_error;
2854957d392Spendry n->n_mnt->mf_flags |= MFF_ERROR;
2864957d392Spendry } else {
2874957d392Spendry /*
2884957d392Spendry * The mount worked.
2894957d392Spendry */
2904957d392Spendry mf_mounted(n->n_mnt);
2914957d392Spendry n->n_error = 0;
292c626267eSpendry }
293c626267eSpendry
2944957d392Spendry /*
2954957d392Spendry * Do the remaining bits
2964957d392Spendry */
297c626267eSpendry if (nfsx_fmount(mf) >= 0) {
298c626267eSpendry wakeup((voidp) mf);
299c626267eSpendry mf->mf_flags &= ~MFF_MOUNTING;
3004957d392Spendry mf_mounted(mf);
3014957d392Spendry }
3024957d392Spendry }
3034957d392Spendry
3044957d392Spendry static int try_nfsx_mount P((voidp mv));
try_nfsx_mount(mv)3054957d392Spendry static int try_nfsx_mount(mv)
3064957d392Spendry voidp mv;
3074957d392Spendry {
3084957d392Spendry mntfs *mf = (mntfs *) mv;
3094957d392Spendry int error;
3104957d392Spendry
3114957d392Spendry mf->mf_flags |= MFF_MOUNTING;
3124957d392Spendry error = (*mf->mf_ops->fmount_fs)(mf);
3134957d392Spendry mf->mf_flags &= ~MFF_MOUNTING;
3144957d392Spendry return error;
3154957d392Spendry }
3164957d392Spendry
317c626267eSpendry static int nfsx_remount P((mntfs *mf, int fg));
nfsx_remount(mf,fg)318c626267eSpendry static int nfsx_remount(mf, fg)
3194957d392Spendry mntfs *mf;
320c626267eSpendry int fg;
3214957d392Spendry {
3224957d392Spendry struct nfsx *nx = (struct nfsx *) mf->mf_private;
3234957d392Spendry nfsx_mnt *n;
3244957d392Spendry int glob_error = -1;
3254957d392Spendry
3264957d392Spendry for (n = nx->nx_v; n < nx->nx_v + nx->nx_c; n++) {
3274957d392Spendry mntfs *m = n->n_mnt;
3284957d392Spendry if (n->n_error < 0) {
3294957d392Spendry if (!(m->mf_flags & MFF_MKMNT) && m->mf_ops->fs_flags & FS_MKMNT) {
3304957d392Spendry int error = mkdirs(m->mf_mount, 0555);
3314957d392Spendry if (!error)
3324957d392Spendry m->mf_flags |= MFF_MKMNT;
3334957d392Spendry }
3344957d392Spendry }
3354957d392Spendry }
3364957d392Spendry
3374957d392Spendry /*
3384957d392Spendry * Iterate through the mntfs's and mount each filesystem
3394957d392Spendry * which is not yet mounted.
3404957d392Spendry */
3414957d392Spendry for (n = nx->nx_v; n < nx->nx_v + nx->nx_c; n++) {
3424957d392Spendry mntfs *m = n->n_mnt;
3434957d392Spendry if (n->n_error < 0) {
3444957d392Spendry /*
3454957d392Spendry * Check fmount entry pt. exists
3464957d392Spendry * and then mount...
3474957d392Spendry */
3484957d392Spendry if (!m->mf_ops->fmount_fs) {
3494957d392Spendry n->n_error = EINVAL;
3504957d392Spendry } else {
3514957d392Spendry #ifdef DEBUG
3524957d392Spendry dlog("calling underlying fmount on %s", m->mf_mount);
3534957d392Spendry #endif
354c626267eSpendry if (!fg && foreground && (m->mf_ops->fs_flags & FS_MBACKGROUND)) {
3554957d392Spendry m->mf_flags |= MFF_MOUNTING; /* XXX */
3564957d392Spendry #ifdef DEBUG
3574957d392Spendry dlog("backgrounding mount of \"%s\"", m->mf_info);
3584957d392Spendry #endif
3594957d392Spendry nx->nx_try = n;
3604957d392Spendry run_task(try_nfsx_mount, (voidp) m, nfsx_cont, (voidp) mf);
3614957d392Spendry n->n_error = -1;
3624957d392Spendry return -1;
3634957d392Spendry } else {
3644957d392Spendry #ifdef DEBUG
3654957d392Spendry dlog("foreground mount of \"%s\" ...", mf->mf_info);
366c626267eSpendry #endif
3674957d392Spendry n->n_error = (*m->mf_ops->fmount_fs)(m);
3684957d392Spendry }
3694957d392Spendry }
3704957d392Spendry #ifdef DEBUG
3714957d392Spendry if (n->n_error > 0) {
3724957d392Spendry errno = n->n_error; /* XXX */
3734957d392Spendry dlog("underlying fmount of %s failed: %m", m->mf_mount);
3744957d392Spendry }
3754957d392Spendry #endif
3764957d392Spendry if (n->n_error == 0) {
3774957d392Spendry glob_error = 0;
3784957d392Spendry } else if (glob_error < 0) {
3794957d392Spendry glob_error = n->n_error;
3804957d392Spendry }
3814957d392Spendry }
3824957d392Spendry }
3834957d392Spendry
3844957d392Spendry return glob_error < 0 ? 0 : glob_error;
3854957d392Spendry }
3864957d392Spendry
387c626267eSpendry static int nfsx_fmount P((mntfs *mf));
nfsx_fmount(mf)388c626267eSpendry static int nfsx_fmount(mf)
389c626267eSpendry mntfs *mf;
390c626267eSpendry {
391c626267eSpendry return nfsx_remount(mf, FALSE);
392c626267eSpendry }
393c626267eSpendry
394c626267eSpendry /*
395c626267eSpendry * Unmount an NFS hierarchy.
396c626267eSpendry * Note that this is called in the foreground
397c626267eSpendry * and so may hang under extremely rare conditions.
398c626267eSpendry */
nfsx_fumount(mf)3994957d392Spendry static int nfsx_fumount(mf)
4004957d392Spendry mntfs *mf;
4014957d392Spendry {
4024957d392Spendry struct nfsx *nx = (struct nfsx *) mf->mf_private;
4034957d392Spendry nfsx_mnt *n;
4044957d392Spendry int glob_error = 0;
4054957d392Spendry
4064957d392Spendry /*
4074957d392Spendry * Iterate in reverse through the mntfs's and unmount each filesystem
4084957d392Spendry * which is mounted.
4094957d392Spendry */
4104957d392Spendry for (n = nx->nx_v + nx->nx_c - 1; n >= nx->nx_v; --n) {
4114957d392Spendry mntfs *m = n->n_mnt;
4124957d392Spendry /*
4134957d392Spendry * If this node has not been messed with
4144957d392Spendry * and there has been no error so far
4154957d392Spendry * then try and unmount.
4164957d392Spendry * If an error had occured then zero
4174957d392Spendry * the error code so that the remount
4184957d392Spendry * only tries to unmount those nodes
4194957d392Spendry * which had been successfully unmounted.
4204957d392Spendry */
4214957d392Spendry if (n->n_error == 0) {
4224957d392Spendry #ifdef DEBUG
4234957d392Spendry dlog("calling underlying fumount on %s", m->mf_mount);
4244957d392Spendry #endif
4254957d392Spendry n->n_error = (*m->mf_ops->fumount_fs)(m);
4264957d392Spendry if (n->n_error) {
4274957d392Spendry glob_error = n->n_error;
428c626267eSpendry n->n_error = 0;
4294957d392Spendry } else {
4304957d392Spendry /*
4314957d392Spendry * Make sure remount gets this node
4324957d392Spendry */
4334957d392Spendry n->n_error = -1;
4344957d392Spendry }
4354957d392Spendry }
4364957d392Spendry }
4374957d392Spendry
4384957d392Spendry /*
4394957d392Spendry * If any unmounts failed then remount the
4404957d392Spendry * whole lot...
4414957d392Spendry */
4424957d392Spendry if (glob_error) {
443c626267eSpendry glob_error = nfsx_remount(mf, TRUE);
444c626267eSpendry if (glob_error) {
445c626267eSpendry errno = glob_error; /* XXX */
4464957d392Spendry plog(XLOG_USER, "nfsx: remount of %s failed: %m", mf->mf_mount);
447c626267eSpendry }
4484957d392Spendry glob_error = EBUSY;
4494957d392Spendry } else {
4504957d392Spendry /*
4514957d392Spendry * Remove all the mount points
4524957d392Spendry */
4534957d392Spendry for (n = nx->nx_v; n < nx->nx_v + nx->nx_c; n++) {
4544957d392Spendry mntfs *m = n->n_mnt;
4554957d392Spendry if (n->n_error < 0) {
456c626267eSpendry if (m->mf_ops->fs_flags & FS_MKMNT) {
4574957d392Spendry (void) rmdirs(m->mf_mount);
458c626267eSpendry m->mf_flags &= ~MFF_MKMNT;
459c626267eSpendry }
4604957d392Spendry }
4614957d392Spendry free_mntfs(m);
4624957d392Spendry n->n_mnt = 0;
463c626267eSpendry n->n_error = -1;
4644957d392Spendry }
4654957d392Spendry }
4664957d392Spendry
4674957d392Spendry return glob_error;
4684957d392Spendry }
4694957d392Spendry
4704957d392Spendry /*
4714957d392Spendry * Ops structure
4724957d392Spendry */
4734957d392Spendry am_ops nfsx_ops = {
4744957d392Spendry "nfsx",
4754957d392Spendry nfsx_match,
4764957d392Spendry nfsx_init,
4774957d392Spendry auto_fmount,
4784957d392Spendry nfsx_fmount,
4794957d392Spendry auto_fumount,
4804957d392Spendry nfsx_fumount,
4814957d392Spendry efs_lookuppn,
4824957d392Spendry efs_readdir,
4834957d392Spendry 0, /* nfsx_readlink */
4844957d392Spendry 0, /* nfsx_mounted */
4854957d392Spendry 0, /* nfsx_umounted */
4864957d392Spendry find_nfs_srvr, /* XXX */
4874957d392Spendry /*FS_UBACKGROUND|*/FS_AMQINFO
4884957d392Spendry };
4894957d392Spendry
4904957d392Spendry #endif /* HAS_NFSX */
491