summaryrefslogtreecommitdiffstats
path: root/support
diff options
context:
space:
mode:
authorSteinar H. Gunderson <sesse@debian.org>2006-12-26 23:58:48 +0100
committerNeil Brown <neilb@suse.de>2007-02-05 09:06:26 +1100
commitb5a542ab44c4d3430cf68dcacc60f06a204b15cd (patch)
treec2f25cf34a86a74e73604853d5ba540c80eb818a /support
parente673ca14c730ae4ed9e2acaea764c669d2b00433 (diff)
downloadnfs-utils-b5a542ab44c4d3430cf68dcacc60f06a204b15cd.tar.gz
nfs-utils-b5a542ab44c4d3430cf68dcacc60f06a204b15cd.tar.xz
nfs-utils-b5a542ab44c4d3430cf68dcacc60f06a204b15cd.zip
Allow default options in /etc/exports
Implement default options in /etc/exports, to fix a long-standing wishlist bug in Debian. (The user claims the syntax matches that of OpenBSD.) This makes it possible to write "/srv/www -sync,no_subtree_check host1 host2 host3" instead of having to write (sync,no_subtree_check) over and over and over again, driving the administrator slowly mad. Such option lines can be placed anywhere on the line, and affects anything after them (I do not know if OpenBSD allows this). The patch is slightly convoluted in order to avoid triggering spurious warnings; for instance, we want "/srv/www -sync host1" to trigger a warning, but not "/srv/www -sync,no_subtree_check host1" or "/srv/www -sync host1(no_subtree_check)". There was also a suggestion for a truly global (ie. per-file) option list, but this seemed like the safest bet, given that it matches that of other implementations. Also, the man page is updated with information on the new possibilities, and an example. Signed-off-by: Steinar H. Gunderson <sesse@debian.org> Signed-off-by: Neil Brown <neilb@suse.de>
Diffstat (limited to 'support')
-rw-r--r--support/nfs/exports.c82
1 files changed, 54 insertions, 28 deletions
diff --git a/support/nfs/exports.c b/support/nfs/exports.c
index 2d31781..9b010dc 100644
--- a/support/nfs/exports.c
+++ b/support/nfs/exports.c
@@ -39,12 +39,13 @@ int export_errno;
static char *efname = NULL;
static XFILE *efp = NULL;
static int first;
+static int has_default_opts, has_default_subtree_opts;
static int *squids = NULL, nsquids = 0,
*sqgids = NULL, nsqgids = 0;
static int getexport(char *exp, int len);
static int getpath(char *path, int len);
-static int parseopts(char *cp, struct exportent *ep, int warn);
+static int parseopts(char *cp, struct exportent *ep, int warn, int *had_subtree_opt_ptr);
static int parsesquash(char *list, int **idp, int *lenp, char **ep);
static int parsenum(char **cpp);
static int parsemaptype(char *type);
@@ -68,7 +69,7 @@ setexportent(char *fname, char *type)
struct exportent *
getexportent(int fromkernel, int fromexports)
{
- static struct exportent ee;
+ static struct exportent ee, def_ee;
char exp[512], *hostname;
char rpath[MAXPATHLEN+1];
char *opt, *sp;
@@ -78,31 +79,36 @@ getexportent(int fromkernel, int fromexports)
return NULL;
freesquash();
- ee.e_flags = EXPORT_DEFAULT_FLAGS;
- /* some kernels assume the default is sync rather than
- * async. More recent kernels always report one or other,
- * but this test makes sure we assume same as kernel
- * Ditto for wgather
- */
- if (fromkernel) {
- ee.e_flags &= ~NFSEXP_ASYNC;
- ee.e_flags &= ~NFSEXP_GATHERED_WRITES;
- }
- ee.e_maptype = CLE_MAP_IDENT;
- ee.e_anonuid = 65534;
- ee.e_anongid = 65534;
- ee.e_squids = NULL;
- ee.e_sqgids = NULL;
- ee.e_mountpoint = NULL;
- ee.e_nsquids = 0;
- ee.e_nsqgids = 0;
if (first || (ok = getexport(exp, sizeof(exp))) == 0) {
- ok = getpath(ee.e_path, sizeof(ee.e_path));
+ has_default_opts = 0;
+ has_default_subtree_opts = 0;
+
+ def_ee.e_flags = EXPORT_DEFAULT_FLAGS;
+ /* some kernels assume the default is sync rather than
+ * async. More recent kernels always report one or other,
+ * but this test makes sure we assume same as kernel
+ * Ditto for wgather
+ */
+ if (fromkernel) {
+ def_ee.e_flags &= ~NFSEXP_ASYNC;
+ def_ee.e_flags &= ~NFSEXP_GATHERED_WRITES;
+ }
+ def_ee.e_maptype = CLE_MAP_IDENT;
+ def_ee.e_anonuid = 65534;
+ def_ee.e_anongid = 65534;
+ def_ee.e_squids = NULL;
+ def_ee.e_sqgids = NULL;
+ def_ee.e_mountpoint = NULL;
+ def_ee.e_nsquids = 0;
+ def_ee.e_nsqgids = 0;
+
+ ok = getpath(def_ee.e_path, sizeof(def_ee.e_path));
if (ok <= 0)
return NULL;
- strncpy (ee.m_path, ee.e_path, sizeof (ee.m_path) - 1);
- ee.m_path [sizeof (ee.m_path) - 1] = '\0';
+
+ strncpy (def_ee.m_path, def_ee.e_path, sizeof (def_ee.m_path) - 1);
+ def_ee.m_path [sizeof (def_ee.m_path) - 1] = '\0';
ok = getexport(exp, sizeof(exp));
}
if (ok < 0) {
@@ -111,6 +117,23 @@ getexportent(int fromkernel, int fromexports)
return NULL;
}
first = 0;
+
+ /* Check for default options */
+ if (exp[0] == '-') {
+ if (parseopts(exp + 1, &def_ee, 0, &has_default_subtree_opts) < 0)
+ return NULL;
+
+ has_default_opts = 1;
+
+ ok = getexport(exp, sizeof(exp));
+ if (ok < 0) {
+ xlog(L_ERROR, "expected client(options...)");
+ export_errno = EINVAL;
+ return NULL;
+ }
+ }
+
+ ee = def_ee;
/* Check for default client */
if (ok == 0)
@@ -130,7 +153,8 @@ getexportent(int fromkernel, int fromexports)
}
*sp = '\0';
} else {
- xlog(L_WARNING, "No options for %s %s: suggest %s(sync) to avoid warning", ee.e_path, exp, exp);
+ if (!has_default_opts)
+ xlog(L_WARNING, "No options for %s %s: suggest %s(sync) to avoid warning", ee.e_path, exp, exp);
}
if (strlen(hostname) >= sizeof(ee.e_hostname)) {
syntaxerr("client name too long");
@@ -140,7 +164,7 @@ getexportent(int fromkernel, int fromexports)
strncpy(ee.e_hostname, hostname, sizeof (ee.e_hostname) - 1);
ee.e_hostname[sizeof (ee.e_hostname) - 1] = '\0';
- if (parseopts(opt, &ee, fromexports) < 0)
+ if (parseopts(opt, &ee, fromexports && !has_default_subtree_opts, NULL) < 0)
return NULL;
/* resolve symlinks */
@@ -293,7 +317,7 @@ mkexportent(char *hname, char *path, char *options)
ee.e_path[sizeof (ee.e_path) - 1] = '\0';
strncpy (ee.m_path, ee.e_path, sizeof (ee.m_path) - 1);
ee.m_path [sizeof (ee.m_path) - 1] = '\0';
- if (parseopts(options, &ee, 0) < 0)
+ if (parseopts(options, &ee, 0, NULL) < 0)
return NULL;
return &ee;
}
@@ -301,7 +325,7 @@ mkexportent(char *hname, char *path, char *options)
int
updateexportent(struct exportent *eep, char *options)
{
- if (parseopts(options, eep, 0) < 0)
+ if (parseopts(options, eep, 0, NULL) < 0)
return 0;
return 1;
}
@@ -310,7 +334,7 @@ updateexportent(struct exportent *eep, char *options)
* Parse option string pointed to by cp and set mount options accordingly.
*/
static int
-parseopts(char *cp, struct exportent *ep, int warn)
+parseopts(char *cp, struct exportent *ep, int warn, int *had_subtree_opt_ptr)
{
int had_subtree_opt = 0;
char *flname = efname?efname:"command line";
@@ -461,6 +485,8 @@ out:
flname, flline,
ep->e_hostname, ep->e_path);
+ if (had_subtree_opt_ptr)
+ *had_subtree_opt_ptr = had_subtree_opt;
return 1;
}