xref: /original-bsd/usr.sbin/amd/amd/nfsx_ops.c (revision 4092c5cc)
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