Blob Blame History Raw
autofs-5.1.0-beta1 - allow empty value for some map options

From: Ian Kent <raven@themaw.net>

Some map options may be given but left blank, possibly with the intent
the mount location mount attempt will not be done or fail, such as when
the delay option is also given.

autofs doesn't implement the delay option but it shouldn't fail to parse
these locations so that a valid locations in the list can be tried.
---
 CHANGELOG           |    1 
 lib/parse_subs.c    |   12 +++-
 modules/amd_parse.y |   36 ++++++++++++++
 modules/amd_tok.l   |   35 ++++++++++++--
 modules/parse_amd.c |  125 ++++++++++++++++++++++++++++++++--------------------
 5 files changed, 155 insertions(+), 54 deletions(-)

--- autofs-5.0.7.orig/CHANGELOG
+++ autofs-5.0.7/CHANGELOG
@@ -124,6 +124,7 @@
 - add plus to path match pattern.
 - fix multi entry ldap option handling.
 - cleanup options in amd_parse.c
+- allow empty value for some map options.
 
 25/07/2012 autofs-5.0.7
 =======================
--- autofs-5.0.7.orig/lib/parse_subs.c
+++ autofs-5.0.7/lib/parse_subs.c
@@ -889,14 +889,20 @@ char *merge_options(const char *opt1, co
 	char *tok, *ptr = NULL;
 	size_t len;
 
-	if (!opt1 && !opt2)
+	if ((!opt1 || !*opt1) && (!opt2 || !*opt2))
 		return NULL;
 
-	if (!opt2)
+	if (!opt2 || !*opt2) {
+		if (!*opt1)
+			return NULL;
 		return strdup(opt1);
+	}
 
-	if (!opt1)
+	if (!opt1 || !*opt1) {
+		if (!*opt2)
+			return NULL;
 		return strdup(opt2);
+	}
 
 	if (!strcmp(opt1, opt2))
 		return strdup(opt1);
--- autofs-5.0.7.orig/modules/amd_parse.y
+++ autofs-5.0.7/modules/amd_parse.y
@@ -335,6 +335,15 @@ option_assignment: MAP_OPTION OPTION_ASS
 			YYABORT;
 		}
 	}
+	| MAP_OPTION OPTION_ASSIGN
+	{
+		if (!strcmp($1, "fs"))
+			entry.fs = amd_strdup("");
+		else {
+			amd_notify($1);
+			YYABORT;
+		}
+	}
 	| FS_OPTION OPTION_ASSIGN FS_OPT_VALUE
 	{
 		if (!strcmp($1, "rhost"))
@@ -358,6 +367,19 @@ option_assignment: MAP_OPTION OPTION_ASS
 			YYABORT;
 		}
 	}
+	| FS_OPTION OPTION_ASSIGN
+	{
+		if (!strcmp($1, "rhost"))
+			entry.rhost = amd_strdup("");
+		else if (!strcmp($1, "rfs"))
+			entry.rfs = amd_strdup("");
+		else if (!strcmp($1, "dev"))
+			entry.dev = amd_strdup("");
+		else {
+			amd_notify($1);
+			YYABORT;
+		}
+	}
 	| MNT_OPTION OPTION_ASSIGN options
 	{
 		memset(opts, 0, sizeof(opts));
@@ -370,6 +392,20 @@ option_assignment: MAP_OPTION OPTION_ASS
 		else {
 			amd_notify($1);
 			YYABORT;
+		}
+	}
+	| MNT_OPTION OPTION_ASSIGN
+	{
+		memset(opts, 0, sizeof(opts));
+		if (!strcmp($1, "opts"))
+			entry.opts = amd_strdup("");
+		else if (!strcmp($1, "addopts"))
+			entry.addopts = amd_strdup("");
+		else if (!strcmp($1, "remopts"))
+			entry.remopts = amd_strdup("");
+		else {
+			amd_notify($1);
+			YYABORT;
 		}
 	}
 	| MAP_OPTION OPTION_ASSIGN CACHE_OPTION
--- autofs-5.0.7.orig/modules/amd_tok.l
+++ autofs-5.0.7/modules/amd_tok.l
@@ -177,9 +177,14 @@ CUTSEP		(\|\||\/)
 }
 
 <MAPOPTVAL>{
-	{NL} |
+	{NL} {
+		BEGIN(INITIAL);
+		yyless(1);
+	}
+
 	\x00 {
 		BEGIN(INITIAL);
+		return SEPERATOR;
 		yyless(1);
 	}
 
@@ -217,9 +222,14 @@ CUTSEP		(\|\||\/)
 }
 
 <FSOPTVAL>{
-	{NL} |
+	{NL} {
+		BEGIN(INITIAL);
+		yyless(1);
+	}
+
 	\x00 {
 		BEGIN(INITIAL);
+		return SEPERATOR;
 		yyless(1);
 	}
 
@@ -242,9 +252,14 @@ CUTSEP		(\|\||\/)
 }
 
 <MNTOPTVAL>{
-	{NL} |
+	{NL} {
+		BEGIN(INITIAL);
+		yyless(1);
+	}
+
 	\x00 {
 		BEGIN(INITIAL);
+		return SEPERATOR;
 		yyless(1);
 	}
 
@@ -269,9 +284,14 @@ CUTSEP		(\|\||\/)
 }
 
 <SELOPTVAL>{
-	{NL} |
+	{NL} {
+		BEGIN(INITIAL);
+		yyless(1);
+	}
+
 	\x00 {
 		BEGIN(INITIAL);
+		return SEPERATOR;
 		yyless(1);
 	}
 
@@ -296,9 +316,14 @@ CUTSEP		(\|\||\/)
 }
 
 <SELARGVAL>{
-	{NL} |
+	{NL} {
+		BEGIN(INITIAL);
+		yyless(1);
+	}
+
 	\x00 {
 		BEGIN(INITIAL);
+		return SEPERATOR;
 		yyless(1);
 	}
 
--- autofs-5.0.7.orig/modules/parse_amd.c
+++ autofs-5.0.7/modules/parse_amd.c
@@ -683,7 +683,7 @@ static struct substvar *expand_entry(str
 	unsigned int logopt = ap->logopt;
 	char *expand;
 
-	if (entry->rhost) {
+	if (entry->rhost && *entry->rhost) {
 		char *host = strdup(entry->rhost);
 		char *nn;
 		if (!host) {
@@ -720,7 +720,7 @@ next:
 		sv = macro_addvar(sv, "sublink", 7, entry->sublink);
 	}
 
-	if (entry->rfs) {
+	if (entry->rfs && *entry->rfs) {
 		if (expand_selectors(ap, entry->rfs, &expand, sv)) {
 			debug(logopt, MODPREFIX
 			      "rfs expand(\"%s\") -> %s", entry->rfs, expand);
@@ -730,7 +730,7 @@ next:
 		sv = macro_addvar(sv, "rfs", 3, entry->rfs);
 	}
 
-	if (entry->fs) {
+	if (entry->fs && *entry->fs) {
 		if (expand_selectors(ap, entry->fs, &expand, sv)) {
 			debug(logopt, MODPREFIX
 			      "fs expand(\"%s\") -> %s", entry->fs, expand);
@@ -740,7 +740,7 @@ next:
 		sv = macro_addvar(sv, "fs", 2, entry->fs);
 	}
 
-	if (entry->opts) {
+	if (entry->opts && *entry->opts) {
 		if (expand_selectors(ap, entry->opts, &expand, sv)) {
 			debug(logopt, MODPREFIX
 			      "ops expand(\"%s\") -> %s", entry->opts, expand);
@@ -750,7 +750,7 @@ next:
 		sv = macro_addvar(sv, "opts", 4, entry->opts);
 	}
 
-	if (entry->addopts) {
+	if (entry->addopts && *entry->addopts) {
 		if (expand_selectors(ap, entry->addopts, &expand, sv)) {
 			debug(logopt, MODPREFIX
 			      "addopts expand(\"%s\") -> %s",
@@ -761,7 +761,7 @@ next:
 		sv = macro_addvar(sv, "addopts", 7, entry->addopts);
 	}
 
-	if (entry->remopts) {
+	if (entry->remopts && *entry->remopts) {
 		if (expand_selectors(ap, entry->remopts, &expand, sv)) {
 			debug(logopt, MODPREFIX
 			      "remopts expand(\"%s\") -> %s",
@@ -781,7 +781,7 @@ static void expand_merge_options(struct
 {
 	char *tmp;
 
-	if (entry->opts) {
+	if (entry->opts && *entry->opts) {
 		if (!expand_selectors(ap, entry->opts, &tmp, sv))
 			error(ap->logopt, MODPREFIX "failed to expand opts");
 		else {
@@ -790,7 +790,7 @@ static void expand_merge_options(struct
 		}
 	}
 
-	if (entry->addopts) {
+	if (entry->addopts && *entry->addopts) {
 		if (!expand_selectors(ap, entry->addopts, &tmp, sv))
 			error(ap->logopt, MODPREFIX "failed to expand addopts");
 		else {
@@ -799,7 +799,7 @@ static void expand_merge_options(struct
 		}
 	}
 
-	if (entry->remopts) {
+	if (entry->remopts && *entry->remopts) {
 		if (!expand_selectors(ap, entry->remopts, &tmp, sv))
 			error(ap->logopt, MODPREFIX "failed to expand remopts");
 		else {
@@ -832,11 +832,13 @@ static struct substvar *merge_entry_opti
 			entry->opts = tmp;
 			sv = macro_addvar(sv, "opts", 4, entry->opts);
 		}
-		tmp = strdup(entry->opts);
-		if (tmp) {
-			free(entry->remopts);
-			entry->remopts = tmp;
-			sv = macro_addvar(sv, "remopts", 7, entry->remopts);
+		if (*entry->opts) {
+			tmp = strdup(entry->opts);
+			if (tmp) {
+				free(entry->remopts);
+				entry->remopts = tmp;
+				sv = macro_addvar(sv, "remopts", 7, entry->remopts);
+			}
 		}
 		return sv;
 	}
@@ -853,7 +855,7 @@ static struct substvar *merge_entry_opti
 			entry->opts = tmp;
 			sv = macro_addvar(sv, "opts", 4, entry->opts);
 		}
-	} else if (entry->addopts) {
+	} else if (entry->addopts && *entry->addopts) {
 		tmp = strdup(entry->addopts);
 		if (tmp) {
 			info(ap->logopt, MODPREFIX
@@ -875,7 +877,7 @@ static struct substvar *merge_entry_opti
 			entry->remopts = tmp;
 			sv = macro_addvar(sv, "remopts", 7, entry->remopts);
 		}
-	} else if (entry->addopts) {
+	} else if (entry->addopts && *entry->addopts) {
 		tmp = strdup(entry->addopts);
 		if (tmp) {
 			info(ap->logopt, MODPREFIX
@@ -910,6 +912,7 @@ static int do_link_mount(struct autofs_p
 			 struct amd_entry *entry, unsigned int flags)
 {
 	char target[PATH_MAX + 1];
+	const char *opts = (entry->opts && *entry->opts) ? entry->opts : NULL;
 	int ret;
 
 	if (entry->sublink)
@@ -922,7 +925,7 @@ static int do_link_mount(struct autofs_p
 
 	/* For a sublink this might cause an external mount */
 	ret = do_mount(ap, ap->path,
-		       name, strlen(name), target, "bind", entry->opts);
+		       name, strlen(name), target, "bind", opts);
 	if (!ret)
 		goto out;
 
@@ -967,12 +970,13 @@ static int do_generic_mount(struct autof
 			    struct amd_entry *entry, const char *target,
 			    unsigned int flags)
 {
+	const char *opts = (entry->opts && *entry->opts) ? entry->opts : NULL;
 	unsigned int umount = 0;
 	int ret = 0;
 
 	if (!entry->fs) {
-		ret = do_mount(ap, ap->path, name, strlen(name),
-			       target, entry->type, entry->opts);
+		ret = do_mount(ap, ap->path, name,
+			       strlen(name), target, entry->type, opts);
 	} else {
 		/*
 		 * Careful, external mounts may get mounted
@@ -981,7 +985,7 @@ static int do_generic_mount(struct autof
 		 */
 		if (!is_mounted(_PATH_MOUNTED, entry->fs, MNTS_REAL)) {
 			ret = do_mount(ap, entry->fs, "/", 1,
-				       target, entry->type, entry->opts);
+				       target, entry->type, opts);
 			if (ret)
 				goto out;
 			umount = 1;
@@ -999,7 +1003,7 @@ static int do_nfs_mount(struct autofs_po
 {
 	char target[PATH_MAX + 1];
 	unsigned int proximity;
-	char *opts = entry->opts;
+	char *opts = (entry->opts && *entry->opts) ? entry->opts : NULL;
 	unsigned int umount = 0;
 	int ret = 0;
 
@@ -1008,7 +1012,7 @@ static int do_nfs_mount(struct autofs_po
 	strcat(target, entry->rfs);
 
 	proximity = get_network_proximity(entry->rhost);
-	if (proximity == PROXIMITY_OTHER && entry->remopts)
+	if (proximity == PROXIMITY_OTHER && entry->remopts && *entry->remopts)
 		opts = entry->remopts;
 
 	if (!entry->fs) {
@@ -1120,7 +1124,7 @@ static int do_host_mount(struct autofs_p
 			goto out;
 	}
 
-	if (entry->opts) {
+	if (entry->opts && *entry->opts) {
 		argv[0] = entry->opts;
 		argv[1] = NULL;
 		pargv = argv;
@@ -1180,9 +1184,13 @@ static unsigned int validate_auto_option
 	/*
 	 * The amd manual implies all the mount type auto options
 	 * are optional but I don't think there's much point if
-	 * no map is given.
+	 * no map is given. If the option has been intentionally
+	 * left blank the mount must be expected to fail so don't
+	 * report the error.
 	 */
-	if (!entry->fs) {
+	if (!*entry->fs)
+		return 0;
+	else if (!entry->fs) {
 		error(logopt, MODPREFIX
 		      "%s: file system not given", entry->type);
 		return 0;
@@ -1201,11 +1209,19 @@ static unsigned int validate_nfs_options
 					 struct amd_entry *entry)
 {
 	/*
-	 * Required option rhost will always have a value.
-	 * It is set from ${host} if it is found to be NULL
-	 * earlier in the parsing process.
+	 * Required option rhost will always have a value unless
+	 * it has been intentionally left blank. It is set from
+	 * ${host} if it is found to be NULL earlier in the parsing
+	 * process. Don't report the error if it has been left blank
+	 * or if the fs option has been left blank since the mount is
+	 * expected to fail.
 	 */
-	if (!entry->rfs) {
+	if (!entry->rfs || !*entry->rfs) {
+		if (!*entry->rfs)
+			return 0;
+		/* Map option fs has been intentionally left blank */
+		if (entry->fs && !*entry->fs)
+			return 0;
 		if (entry->fs)
 			entry->rfs = strdup(entry->fs);
 		if (!entry->rfs) {
@@ -1226,14 +1242,22 @@ static unsigned int validate_generic_opt
 					     unsigned long fstype,
 					     struct amd_entry *entry)
 {
+	/*
+	 * If dev or rfs are empty in the map entry the mount is
+	 * expected to fail so don't report the error.
+	 */
 	if (fstype != AMD_MOUNT_TYPE_LOFS) {
-		if (!entry->dev) {
+		if (!*entry->dev)
+			return 0;
+		else if (!entry->dev) {
 			error(logopt, MODPREFIX
 			      "%s: mount device not given", entry->type);
 			return 0;
 		}
 	} else {
-		if (!entry->rfs) {
+		if (!*entry->rfs)
+			return 0;
+		else if (!entry->rfs) {
 			/*
 			 * Can't use entry->type as the mount type to reprot
 			 * the error since entry->type == "bind" not "lofs".
@@ -1270,11 +1294,14 @@ static unsigned int validate_host_option
 					  struct amd_entry *entry)
 {
 	/*
-	 * Not really that useful since rhost is always non-null
-	 * because it will have the the value of the host name if
-	 * it isn't set in the map entry.
+	 * rhost is always non-null, unless it is intentionally left
+	 * empty, because it will have the the value of the host name
+	 * if it isn't given in the map entry. Don't report an error
+	 * if it has been left empty since it's expected to fail.
 	 */
-	if (!entry->rhost) {
+	if (!*entry->rhost)
+		return 0;
+	else if (!entry->rhost) {
 		error(logopt, MODPREFIX
 		      "%s: remote host name not given", entry->type);
 		return 0;
@@ -1382,7 +1409,7 @@ void dequote_entry(struct autofs_point *
 		}
 	}
 
-	if (entry->fs) {
+	if (entry->fs && *entry->fs) {
 		res = dequote(entry->fs, strlen(entry->fs), ap->logopt);
 		if (res) {
 			debug(ap->logopt,
@@ -1393,7 +1420,7 @@ void dequote_entry(struct autofs_point *
 		}
 	}
 
-	if (entry->rfs) {
+	if (entry->rfs && *entry->rfs) {
 		res = dequote(entry->rfs, strlen(entry->rfs), ap->logopt);
 		if (res) {
 			debug(ap->logopt,
@@ -1404,7 +1431,7 @@ void dequote_entry(struct autofs_point *
 		}
 	}
 
-	if (entry->opts) {
+	if (entry->opts && *entry->opts) {
 		res = dequote(entry->opts, strlen(entry->opts), ap->logopt);
 		if (res) {
 			debug(ap->logopt,
@@ -1415,7 +1442,7 @@ void dequote_entry(struct autofs_point *
 		}
 	}
 
-	if (entry->remopts) {
+	if (entry->remopts && *entry->remopts) {
 		res = dequote(entry->remopts, strlen(entry->remopts), ap->logopt);
 		if (res) {
 			debug(ap->logopt,
@@ -1426,7 +1453,7 @@ void dequote_entry(struct autofs_point *
 		}
 	}
 
-	if (entry->addopts) {
+	if (entry->addopts && *entry->addopts) {
 		res = dequote(entry->addopts, strlen(entry->addopts), ap->logopt);
 		if (res) {
 			debug(ap->logopt,
@@ -1446,6 +1473,10 @@ static void normalize_sublink(unsigned i
 	char *new;
 	size_t len;
 
+	/* Normalizing sublink requires a non-blank fs option */
+	if (!*entry->fs)
+		return;
+
 	if (entry->sublink && *entry->sublink != '/') {
 		len = strlen(entry->fs) + strlen(entry->sublink) + 2;
 		new = malloc(len);
@@ -1559,37 +1590,39 @@ static struct amd_entry *dup_defaults_en
 			entry->fs = tmp;
 	}
 
-	if (defaults->rfs) {
+	/* These shouldn't be blank in a defaults entry but ... */
+
+	if (defaults->rfs && *defaults->rfs) {
 		tmp = strdup(defaults->rfs);
 		if (tmp)
 			entry->rfs = tmp;
 	}
 
-	if (defaults->rhost) {
+	if (defaults->rhost && *defaults->rfs) {
 		tmp = strdup(defaults->rhost);
 		if (tmp)
 			entry->rhost = tmp;
 	}
 
-	if (defaults->dev) {
+	if (defaults->dev && *defaults->dev) {
 		tmp = strdup(defaults->dev);
 		if (tmp)
 			entry->dev = tmp;
 	}
 
-	if (defaults->opts) {
+	if (defaults->opts && *defaults->opts) {
 		tmp = strdup(defaults->opts);
 		if (tmp)
 			entry->opts = tmp;
 	}
 
-	if (defaults->addopts) {
+	if (defaults->addopts && *defaults->addopts) {
 		tmp = strdup(defaults->addopts);
 		if (tmp)
 			entry->addopts = tmp;
 	}
 
-	if (defaults->remopts) {
+	if (defaults->remopts && *defaults->remopts) {
 		tmp = strdup(defaults->remopts);
 		if (tmp)
 			entry->remopts = tmp;