diff --git a/CHANGELOG b/CHANGELOG
index 48d811a..93a4df5 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -2,6 +2,7 @@
 ---------------------
 - code cleanup.
 - fix race for current map source.
+- cthon map parser corrections.
 
 13/7/2006 autofs-5.0.1 rc1
 --------------------------
diff --git a/daemon/automount.c b/daemon/automount.c
index 23c123f..95eba4b 100644
--- a/daemon/automount.c
+++ b/daemon/automount.c
@@ -1368,8 +1368,8 @@ void *handle_mounts(void *arg)
 	 * So, the solution is a recipe for disaster.
 	 * Hope we don't get a really busy system!
 	 */
-	/* sleep(1); */
-	sched_yield();
+	sleep(5);
+	/* sched_yield(); */
 
 	return NULL;
 }
diff --git a/include/automount.h b/include/automount.h
index 908b308..8a5b800 100644
--- a/include/automount.h
+++ b/include/automount.h
@@ -28,6 +28,7 @@ #include "master.h"
 #include "macros.h"
 #include "log.h"
 #include "rpc_subs.h"
+#include "parse_subs.h"
 
 #ifdef WITH_DMALLOC
 #include <dmalloc.h>
@@ -115,6 +116,7 @@ #define CHE_UPDATED	0x0002
 #define CHE_RMPATH	0x0004
 #define CHE_MISSING	0x0008
 #define CHE_COMPLETED	0x0010
+#define CHE_DUPLICATE	0x0020
 
 #define HASHSIZE		77
 #define NEGATIVE_TIMEOUT	10
diff --git a/lib/Makefile b/lib/Makefile
index 5eddebb..5c4d022 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -8,12 +8,12 @@ include ../Makefile.rules
 
 SRCS = cache.c cat_path.c rpc_subs.c mounts.c log.c nsswitch.c \
 	master_tok.l master_parse.y nss_tok.c nss_parse.tab.c \
-	args.c alarm.c macros.c master.c defaults.c
+	args.c alarm.c macros.c master.c defaults.c parse_subs.c
 RPCS = mount.h mount_clnt.c mount_xdr.c
 OBJS = cache.o mount_clnt.o mount_xdr.o cat_path.o rpc_subs.o \
 	mounts.o log.o nsswitch.o master_tok.o master_parse.tab.o \
 	nss_tok.o nss_parse.tab.o args.o alarm.o macros.o master.o \
-	defaults.o
+	defaults.o parse_subs.o
 
 YACCSRC = nss_tok.c nss_parse.tab.c nss_parse.tab.h \
 	  master_tok.c master_parse.tab.c master_parse.tab.h
diff --git a/lib/cache.c b/lib/cache.c
index 6736a88..ffc4c9b 100644
--- a/lib/cache.c
+++ b/lib/cache.c
@@ -446,6 +446,7 @@ static void cache_add_ordered_offset(str
 {
 	struct list_head *p;
 	struct mapent *this;
+	int status = CHE_OK;
 
 	list_for_each(p, head) {
 		size_t tlen;
@@ -456,15 +457,15 @@ static void cache_add_ordered_offset(str
 
 		eq = strncmp(this->key, me->key, tlen);
 		if (!eq && tlen == strlen(me->key))
-			goto done;
+			return;
 
 		if (eq > 0) {
 			list_add_tail(&me->multi_list, p);
-			goto done;
+			return;
 		}
 	}
 	list_add_tail(&me->multi_list, p);
-done:
+
 	return;
 }
 
@@ -478,7 +479,11 @@ int cache_add_offset(struct mapent_cache
 	if (!owner)
 		return CHE_FAIL;
 
-	ret = cache_update(mc, owner->source, key, mapent, age);
+	me = cache_lookup_distinct(mc, key);
+	if (me && me != owner)
+		return CHE_DUPLICATE;
+
+	ret = cache_add(mc, owner->source, key, mapent, age);
 	if (ret == CHE_FAIL) {
 		warn(LOGOPT_ANY, "failed to add key %s to cache", key);
 		return CHE_FAIL;
diff --git a/modules/lookup_file.c b/modules/lookup_file.c
index 913af6a..a515d70 100644
--- a/modules/lookup_file.c
+++ b/modules/lookup_file.c
@@ -182,6 +182,8 @@ static int read_one(FILE *f, char *key, 
 				state = st_begin;
 				if (gotten == got_plus)
 					goto got_it;
+				if (escape != esc_val)
+					goto got_it;
 			} else if (isspace(ch) && !escape) {
 				getting = got_real;
 				state = st_entspc;
@@ -192,7 +194,7 @@ static int read_one(FILE *f, char *key, 
 				if (key_len == KEY_MAX_LEN) {
 					state = st_badent;
 					error(LOGOPT_ANY,
-					      MODPREFIX "Map key \"%s...\" "
+					      MODPREFIX "map key \"%s...\" "
 					      "is too long.  The maximum key "
 					      "length is %d", key,
 					      KEY_MAX_LEN);
@@ -214,8 +216,12 @@ static int read_one(FILE *f, char *key, 
 			break;
 
 		case st_badent:
-			if (ch == '\n')
+			if (ch == '\n') {
 				state = st_begin;
+				if (gotten == got_real || gotten == getting)
+					goto got_it;
+				goto next;
+			}
 			break;
 
 		case st_entspc:
@@ -232,6 +238,16 @@ static int read_one(FILE *f, char *key, 
 
 		case st_getent:
 			if (ch == '\n') {
+				nch = getc(f);
+				if (nch != EOF && isblank(nch)) {
+					state = st_badent;
+					ungetc(nch, f);
+					error(LOGOPT_ANY, MODPREFIX 
+					      "bad map entry \"%s...\" for key "
+					      "\"%s\"", mapent, key);
+					break;
+				}
+				ungetc(nch, f);
 				state = st_begin;
 				if (gotten == got_real || gotten == getting)
 					goto got_it;
@@ -245,7 +261,7 @@ static int read_one(FILE *f, char *key, 
 				ungetc(nch, f);
 			} else {
 				error(LOGOPT_ANY,
-				      MODPREFIX "Map entry \"%s...\" for key "
+				      MODPREFIX "map entry \"%s...\" for key "
 				      "\"%s\" is too long.  The maximum entry"
 				      " size is %d", mapent, key,
 				      MAPENT_MAX_LEN);
@@ -640,15 +656,36 @@ int lookup_read_map(struct autofs_point 
 			master_free_mapent_sources(iap->entry, 0);
 			master_free_mapent(iap->entry);
 		} else {
-			if (ap->type == LKP_INDIRECT && *key == '/')
+			char *dq_key, *dq_mapent; 
+
+			dq_key = dequote(key, strlen(key), ap->logopt);
+			if (!dq_key)
 				continue;
 
-			if (ap->type == LKP_DIRECT && *key != '/')
+			if (*dq_key == '/') {
+				if (ap->type == LKP_INDIRECT) {
+					free(dq_key);
+					continue;
+				}
+			} else {
+				if (ap->type == LKP_DIRECT) {
+					free(dq_key);
+					continue;
+				}
+			}
+
+			dq_mapent = dequote(mapent, strlen(mapent), ap->logopt); 
+			if (!dq_mapent) {
+				free(dq_key);
 				continue;
+			}
 
 			cache_writelock(mc);
-			cache_update(mc, source, key, mapent, age);
+			cache_update(mc, source, dq_key, dq_mapent, age);
 			cache_unlock(mc);
+
+			free(dq_key);
+			free(dq_mapent);
 		}
 
 		if (feof(f))
diff --git a/modules/lookup_ldap.c b/modules/lookup_ldap.c
index 9a7794d..7986d3b 100644
--- a/modules/lookup_ldap.c
+++ b/modules/lookup_ldap.c
@@ -1146,6 +1146,7 @@ static int read_one_map(struct autofs_po
 
 	while (e) {
 		char *mapent = NULL;
+		char *dq_key, *dq_mapent;
 
 		keyValue = ldap_get_values(ldap, e, entry);
 
@@ -1227,18 +1228,37 @@ static int read_one_map(struct autofs_po
 		}
 		ldap_value_free(values);
 
-		if (**keyValue == '/' && strlen(*keyValue) == 1)
-			**keyValue = '*';
-
-		if (ap->type == LKP_INDIRECT && **keyValue == '/')
+		dq_key = dequote(*keyValue, strlen(*keyValue), ap->logopt);
+		if (!dq_key)
 			goto next;
 
-		if (ap->type == LKP_DIRECT && **keyValue != '/')
+		if (*dq_key == '/' && strlen(dq_key) == 1)
+			*dq_key = '*';
+
+		if (*dq_key == '/') {
+			if (ap->type == LKP_INDIRECT) {
+				free(dq_key);
+				goto next;
+			}
+		} else {
+			if (ap->type == LKP_DIRECT) {
+				free(dq_key);
+				goto next;
+			}
+		}
+
+		dq_mapent = dequote(mapent, strlen(mapent), ap->logopt);
+		if (!mapent) {
+			free(dq_key);
 			goto next;
+		}
 
 		cache_writelock(mc);
-		cache_update(mc, source, *keyValue, mapent, age);
+		cache_update(mc, source, dq_key, dq_mapent, age);
 		cache_unlock(mc);
+
+		free(dq_key);
+		free(dq_mapent);
 next:
 		if (mapent) {
 			free(mapent);
diff --git a/modules/lookup_nisplus.c b/modules/lookup_nisplus.c
index cb5d620..4049f1b 100644
--- a/modules/lookup_nisplus.c
+++ b/modules/lookup_nisplus.c
@@ -202,6 +202,8 @@ int lookup_read_map(struct autofs_point 
 	result_count = NIS_RES_NUMOBJ(result);
 
 	while (result_count--) {
+		char *dq_key, *dq_mapent;
+
 		this = &result->objects.objects_val[current++];
 		key = ENTRY_VAL(this, 0);
 		/*
@@ -211,16 +213,35 @@ int lookup_read_map(struct autofs_point 
 		if (*key == '+')
 			continue;
 
-		if (ap->type == LKP_INDIRECT && *key == '/')
+		dq_key = dequote(key, ENTRY_LEN(this, 0), ap->logopt);
+		if (!dq_key)
 			continue;
 
-		if (ap->type == LKP_DIRECT && *key != '/')
-			continue;
+		if (*dq_key == '/') {
+			if (ap->type == LKP_INDIRECT) {
+				free(dq_key);
+				continue;
+			}
+		} else {
+			if (ap->type == LKP_DIRECT) {
+				free(dq_key);
+				continue;
+			}
+		}
 
 		mapent = ENTRY_VAL(this, 1);
+		dq_mapent = dequote(mapent, ENTRY_LEN(this, 1), ap->logopt);
+		if (!dq_mapent) {
+			free(dq_key);
+			continue;
+		}
+
 		cache_writelock(mc);
-		cache_update(mc, source, key, mapent, age);
+		cache_update(mc, source, dq_key, dq_mapent, age);
 		cache_unlock(mc);
+
+		free(dq_key);
+		free(dq_mapent);
 	}
 
 	nis_freeresult(result);
diff --git a/modules/lookup_yp.c b/modules/lookup_yp.c
index 4114aaa..741e6ec 100644
--- a/modules/lookup_yp.c
+++ b/modules/lookup_yp.c
@@ -248,8 +248,7 @@ int yp_all_callback(int status, char *yp
 	struct map_source *source = cbdata->source;
 	struct mapent_cache *mc = source->mc;
 	time_t age = cbdata->age;
-	char *key;
-	char *mapent;
+	char *key, *mapent;
 	int ret;
 
 	if (status != YP_TRUE)
@@ -262,23 +261,35 @@ int yp_all_callback(int status, char *yp
 	if (*ypkey == '+')
 		return 0;
 
-	if (ap->type == LKP_INDIRECT && *ypkey == '/')
-		return 0;
-
-	if (ap->type == LKP_DIRECT && *ypkey != '/')
+	key = dequote(ypkey, ypkeylen, ap->logopt);
+	if (!key)
 		return 0;
 
-	key = alloca(ypkeylen + 1);
-	strncpy(key, ypkey, ypkeylen);
-	*(key + ypkeylen) = '\0';
+	if (*key == '/') {
+		if (ap->type == LKP_INDIRECT) {
+			free(key);
+			return 0;
+		}
+	} else {
+		if (ap->type == LKP_DIRECT) {
+			free(key);
+			return 0;
+		}
+	}
 
-	mapent = alloca(vallen + 1);
-	strncpy(mapent, val, vallen);
-	*(mapent + vallen) = '\0';
+	mapent = dequote(val, vallen, ap->logopt);
+	if (!mapent) {
+		free(key);
+		return 0;
+	}
 
 	cache_writelock(mc);
 	ret = cache_update(mc, source, key, mapent, age);
 	cache_unlock(mc);
+
+	free(key);
+	free(mapent);
+
 	if (ret == CHE_FAIL)
 		return -1;
 
diff --git a/modules/mount_nfs.c b/modules/mount_nfs.c
index 72a9c53..0ab2faf 100644
--- a/modules/mount_nfs.c
+++ b/modules/mount_nfs.c
@@ -227,7 +227,7 @@ int mount_mount(struct autofs_point *ap,
 
 			err = spawnll(log_debug,
 				     PATH_MOUNT, PATH_MOUNT, "-t",
-				     "nfs", SLOPPYOPT "-o", nfsoptions,
+				     "nfs", "-o", nfsoptions,
 				     loc, fullpath, NULL);
 		} else {
 			debug(ap->logopt,
diff --git a/modules/parse_sun.c b/modules/parse_sun.c
index d415660..929698f 100644
--- a/modules/parse_sun.c
+++ b/modules/parse_sun.c
@@ -214,116 +214,6 @@ int expandsunent(const char *src, char *
 	return len;
 }
 
-/*
- * Skip whitespace in a string; if we hit a #, consider the rest of the
- * entry a comment.
- */
-const char *skipspace(const char *whence)
-{
-	while (1) {
-		switch (*whence) {
-		case ' ':
-		case '\b':
-		case '\t':
-		case '\n':
-		case '\v':
-		case '\f':
-		case '\r':
-			whence++;
-			break;
-		case '#':	/* comment: skip to end of string */
-			while (*whence != '\0')
-				whence++;
-			/* FALLTHROUGH */
-
-		default:
-			return whence;
-		}
-	}
-}
-
-/*
- * Check a string to see if a colon appears before the next '/'.
- */
-int check_colon(const char *str)
-{
-	char *ptr = (char *) str;
-
-	while (*ptr && *ptr != ':' && *ptr != '/') {
-		ptr++;
-	}
-
-	if (!*ptr || *ptr == '/')
-		return 0;
-
-	return 1;
-}
-
-/* Get the length of a chunk delimitered by whitespace */
-int chunklen(const char *whence, int expect_colon)
-{
-	int n = 0;
-	int quote = 0;
-
-	for (; *whence; whence++, n++) {
-		switch (*whence) {
-		case '\\':
-			if( quote ) {
-				break;
-			} else {
-				quote = 1;
-				continue;
-			}
-		case ':':
-			if (expect_colon)
-				expect_colon = 0;
-			continue;
-		case ' ':
-		case '\t':
-			/* Skip space or tab if we expect a colon */
-			if (expect_colon)
-				continue;
-		case '\b':
-		case '\n':
-		case '\v':
-		case '\f':
-		case '\r':
-		case '#':
-		case '\0':
-			if (!quote)
-				return n;
-			/* FALLTHROUGH */
-		default:
-			break;
-		}
-		quote = 0;
-	}
-
-	return n;
-}
-
-/*
- * Compare str with pat.  Return 0 if compare equal or
- * str is an abbreviation of pat of no less than mchr characters.
- */
-int strmcmp(const char *str, const char *pat, int mchr)
-{
-	int nchr = 0;
-
-	while (*str == *pat) {
-		if (!*str)
-			return 0;
-		str++;
-		pat++;
-		nchr++;
-	}
-
-	if (!*str && nchr > mchr)
-		return 0;
-
-	return *pat - *str;
-}
-
 int parse_init(int argc, const char *const *argv, void **context)
 {
 	struct parse_context *ctxt;
@@ -476,33 +366,6 @@ int parse_init(int argc, const char *con
 	}
 }
 
-static char *dequote(const char *str, int len, unsigned int logopt)
-{
-	char *ret = malloc(len + 1);
-	char *cp = ret;
-	const char *scp;
-	int origlen = len;
-	int quote = 0;
-
-	if (ret == NULL)
-		return NULL;
-
-	for (scp = str; len > 0 && *scp; scp++, len--) {
-		if (*scp == '\\' && !quote ) {
-			quote = 1;
-			continue;
-		}
-		quote = 0;
-		*cp++ = *scp;
-	}
-	*cp = '\0';
-
-	debug(logopt,
-	      MODPREFIX "dequote(\"%.*s\") -> %s", origlen, str, ret);
-
-	return ret;
-}
-
 static const char *parse_options(const char *str, char **ret, unsigned int logopt)
 {
 	const char *cp = str;
@@ -757,7 +620,7 @@ add_offset_entry(struct autofs_point *ap
 	struct mapent_cache *mc;
 	char m_key[PATH_MAX + 1];
 	char m_mapent[MAPENT_MAX_LEN + 1];
-	int m_key_len, m_mapent_len;
+	int p_len, m_key_len, m_options_len, m_mapent_len;
 	int ret;
 
 	source = ap->entry->current;
@@ -766,34 +629,54 @@ add_offset_entry(struct autofs_point *ap
 
 	mc = source->mc;
 
-	m_key_len = m_root_len + strlen(path) + 1;
-	if (m_key_len > PATH_MAX) {
+	if (!*path || !*loc) {
 		error(ap->logopt,
-		      MODPREFIX "multi mount key too long - ignored");
+		      MODPREFIX "syntax error in offset %s -> %s", path, loc);
+		return CHE_FAIL;
+	}
+
+	p_len = strlen(path);
+	/* Trailing '/' causes us pain */
+	if (path[p_len - 1] == '/')
+		p_len--;
+	m_key_len = m_root_len + p_len;
+	if (m_key_len > PATH_MAX) {
+		error(ap->logopt, MODPREFIX "multi mount key too long");
 		return CHE_FAIL;
 	}
 	strcpy(m_key, m_root);
-	strcat(m_key, path);
+	strncat(m_key, path, p_len);
+	m_key[m_key_len] = '\0';
 
-	m_mapent_len = strlen(myoptions) + strlen(loc) + 3;
-	if (m_mapent_len > MAPENT_MAX_LEN) {
-		error(ap->logopt,
-		      MODPREFIX "multi mount mapent too long - ignored");
+	m_options_len = 0;
+	if (*myoptions)
+		m_options_len = strlen(myoptions) + 2;
+
+	m_mapent_len = strlen(loc);
+	if (m_mapent_len + m_options_len > MAPENT_MAX_LEN) {
+		error(ap->logopt, MODPREFIX "multi mount mapent too long");
 		return CHE_FAIL;
 	}
-	strcpy(m_mapent, "-");
-	strcat(m_mapent, myoptions);
-	strcat(m_mapent, " ");
-	strcat(m_mapent, loc);
 
-	debug(ap->logopt,
-	      MODPREFIX
-	      "adding multi-mount offset %s -> %s", path, m_mapent);
+	if (*myoptions) {
+		strcpy(m_mapent, "-");
+		strcat(m_mapent, myoptions);
+		strcat(m_mapent, " ");
+		strcat(m_mapent, loc);
+	} else
+		strcpy(m_mapent, loc);
 
 	cache_writelock(mc);
 	ret = cache_add_offset(mc, name, m_key, m_mapent, age);
 	cache_unlock(mc);
 
+	if (ret == CHE_OK)
+		debug(ap->logopt, MODPREFIX
+		      "added multi-mount offset %s -> %s", path, m_mapent);
+	else
+		debug(ap->logopt, MODPREFIX
+		      "syntax error in offset %s -> %s", path, loc);
+
 	return ret;
 }
 
@@ -862,21 +745,164 @@ cont:
 	return 1;
 }
 
-static void parse_sun_cleanup(struct mapent_cache *mc, const char *name,
-			 char *options, char *path, char *myoptions)
+static int validate_location(char *loc)
 {
-	cache_writelock(mc);
-	cache_delete_offset_list(mc, name);
-	cache_unlock(mc);
+	char *ptr = loc;
 
-	if (options)
-		free(options);
+	/* We don't know much about these */
+	if (*ptr == '/')
+		return 1;
+
+	/* If a ':' is present now it must be a host name */
+	if (check_colon(ptr)) {
+		if (!isalpha(*ptr++))
+			return 0;
 
-	if (path)
-		free(path);
+		while (*ptr && *ptr != ':') {
+			if (!(isalnum(*ptr) ||
+			    *ptr == '-' || *ptr == '.' || *ptr == ','))
+				return 0;
+			ptr++;
+		}
+
+		if (*ptr && *ptr == ':')
+			ptr++;
+	}
+
+	/* Must always be something following */
+	if (!*ptr)
+		return 0;
+
+	return 1;
+}
 
-	if (myoptions)
+static int parse_mapent(const char *ent, char *g_options, char **options, char **location, int logopt)
+{
+	char buf[MAX_ERR_BUF];
+	const char *p;
+	char *myoptions, *loc;
+	int l;
+
+	p = ent;
+
+	myoptions = strdup(g_options);
+	if (!myoptions) {
+		char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
+		error(logopt, MODPREFIX "strdup: %s", estr);
+		return 0;
+	}
+
+	/* Local options are appended to per-map options */
+	if (*p == '-') {
+		do {
+			char *tmp, *newopt = NULL;
+
+			p = parse_options(p, &newopt, logopt);
+
+			tmp = concat_options(myoptions, newopt);
+			if (!tmp) {
+				char *estr;
+				estr = strerror_r(errno, buf, MAX_ERR_BUF);
+				error(logopt, MODPREFIX
+				      "concat_options: %s", estr);
+				free(myoptions);
+				return 0;
+			}
+			myoptions = tmp;
+
+			p = skipspace(p);
+		} while (*p == '-');
+	}
+
+	/* Location can't begin with a '/' */
+	if (*p == '/') {
+		error(logopt, MODPREFIX "error location begins with \"/\"");
+		free(myoptions);
+		return 0;
+	}
+
+	/* Skip ':' escape */
+	if (*p == ':')
+		p++;
+
+	l = chunklen(p, check_colon(p));
+	loc = dequote(p, l, logopt);
+	if (!loc) {
+		error(logopt, MODPREFIX "out of memory");
 		free(myoptions);
+		return 0;
+	}
+
+	if (!validate_location(loc)) {
+		error(logopt, MODPREFIX "invalid location");
+		free(myoptions);
+		free(loc);
+		return 0;
+	}
+
+	debug(logopt, MODPREFIX "dequote(\"%.*s\") -> %s", l, p, loc);
+
+	p += l;
+	p = skipspace(p);
+
+	while (*p && *p != '/') {
+		char *ent;
+
+		/* Location can't begin with a '/' */
+		if (*p == '/') {
+			error(logopt,
+			      MODPREFIX "error location begins with \"/\"");
+			free(myoptions);
+			free(loc);
+			return 0;
+		}
+
+		/* Skip ':' escape */
+		if (*p == ':')
+			p++;
+
+		l = chunklen(p, check_colon(p));
+		ent = dequote(p, l, logopt);
+		if (!ent) {
+			error(logopt, MODPREFIX "out of memory");
+			free(myoptions);
+			free(loc);
+			return 0;
+		}
+
+		if (!validate_location(ent)) {
+			error(logopt,
+			      MODPREFIX "invalid location %s", ent);
+			free(ent);
+			free(myoptions);
+			free(loc);
+			return 0;
+		}
+
+		debug(logopt, MODPREFIX "dequote(\"%.*s\") -> %s", l, p, ent);
+
+		loc = realloc(loc, strlen(loc) + l + 2);
+		if (!loc) {
+			error(logopt, MODPREFIX "out of memory");
+			free(ent);
+			free(myoptions);
+			free(loc);
+			return 0;
+		}
+
+		strcat(loc, " ");
+		strcat(loc, ent);
+
+		free(ent);
+
+		p += l;
+		p = skipspace(p);
+	}
+
+	*options = myoptions;
+	*location = loc;
+
+	return (p - ent);
 }
 
 /*
@@ -898,7 +924,7 @@ int parse_mount(struct autofs_point *ap,
 	char buf[MAX_ERR_BUF];
 	struct map_source *source;
 	struct mapent_cache *mc;
-	struct mapent *me;
+	struct mapent *me, *ro;
 	char *pmapent, *options;
 	const char *p;
 	int mapent_len, rv = 0;
@@ -977,9 +1003,6 @@ int parse_mount(struct autofs_point *ap,
 	if (check_is_multi(p)) {
 		char *m_root = NULL;
 		int m_root_len;
-		char *root_path = NULL;
-		char *root_loc = NULL;
-		char *root_options = NULL;
 		time_t age = time(NULL);
 		int l;
 
@@ -1041,8 +1064,7 @@ int parse_mount(struct autofs_point *ap,
 
 		/* It's a multi-mount; deal with it */
 		do {
-			char *myoptions = strdup(options);
-			char *path, *loc;
+			char *path, *myoptions, *loc;
 			int status;
 
 			if (myoptions == NULL) {
@@ -1055,86 +1077,50 @@ int parse_mount(struct autofs_point *ap,
 			if (*p != '/') {
 				l = 0;
 				path = dequote("/", 1, ap->logopt);
+				debug(ap->logopt,
+				      MODPREFIX "dequote(\"/\") -> %s", path);
 			} else {
 				l = chunklen(p, 0);
 				path = dequote(p, l, ap->logopt);
+				debug(ap->logopt, MODPREFIX
+				      "dequote(\"%.*s\") -> %s", l, p, path);
 			}
 
 			if (!path) {
 				error(ap->logopt, MODPREFIX "out of memory");
-				parse_sun_cleanup(mc, name, options, NULL, myoptions);
+				cache_writelock(mc);
+				cache_delete_offset_list(mc, name);
+				cache_unlock(mc);
+				free(options);
 				return 1;
 			}
 
-			p += l;
-			p = skipspace(p);
-
-			/* Local options are appended to per-map options */
-			if (*p == '-') {
-				do {
-					char *newopt = NULL;
-
-					p = parse_options(p, &newopt, ap->logopt);
-					myoptions = concat_options(myoptions, newopt);
-
-					if (myoptions == NULL) {
-						char *estr;
-						estr = strerror_r(errno, buf, MAX_ERR_BUF);
-						error(ap->logopt, MODPREFIX
-						      "multi concat_options: %s", estr);
-						parse_sun_cleanup(mc, name,
-							options, NULL, NULL);
-						return 1;
-					}
-					p = skipspace(p);
-				} while (*p == '-');
+			if (!*path) {
+				error(ap->logopt, MODPREFIX "invalid path");
+				cache_writelock(mc);
+				cache_delete_offset_list(mc, name);
+				cache_unlock(mc);
+				free(path);
+				free(options);
+				return 1;
 			}
 
-			/* Skip over colon escape */
-			if (*p == ':')
-				p++;
+			p += l;
+			p = skipspace(p);
 
-			l = chunklen(p, check_colon(p));
-			loc = dequote(p, l, ap->logopt);
-			if (!loc) {
-				error(ap->logopt, MODPREFIX "out of memory");
-				parse_sun_cleanup(mc, name, options, path, myoptions);
+			l = parse_mapent(p, options, &myoptions, &loc, ap->logopt);
+			if (!l) {
+				cache_writelock(mc);
+				cache_delete_offset_list(mc, name);
+				cache_unlock(mc);
+				free(path);
+				free(options);
 				return 1;
 			}
 
 			p += l;
 			p = skipspace(p);
 
-			while (*p && *p != '/') {
-				char *ent;
-
-				l = chunklen(p, check_colon(p));
-				ent = dequote(p, l, ap->logopt);
-				if (!ent) {
-					error(ap->logopt, MODPREFIX "out of memory");
-					parse_sun_cleanup(mc, name,
-						options, path, myoptions);
-					return 1;
-				}
-
-				loc = realloc(loc, strlen(loc) + l + 2);
-				if (!loc) {
-					error(ap->logopt, MODPREFIX "out of memory");
-					parse_sun_cleanup(mc, name,
-						options, path, myoptions);
-					free(ent);
-					return 1;
-				}
-
-				strcat(loc, " ");
-				strcat(loc, ent);
-
-				free(ent);
-
-				p += l;
-				p = skipspace(p);
-			}
-
 			master_source_current_wait(ap->entry);
 			ap->entry->current = source;
 
@@ -1142,61 +1128,70 @@ int parse_mount(struct autofs_point *ap,
 						m_root, m_root_len,
 						path, myoptions, loc, age);
 
-			if (!strcmp(path, "/")) {
-				root_path = strdup(path);
-				if (!root_path) {
-					error(ap->logopt, MODPREFIX "out of memory");
-					parse_sun_cleanup(mc, name,
-						options, path, myoptions);
-					return 1;
-				}
-				root_loc = strdup(loc);
-				if (!root_loc) {
-					error(ap->logopt, MODPREFIX "out of memory");
-					parse_sun_cleanup(mc, name,
-						options, path, myoptions);
-					free(root_path);
-					return 1;
-				}
-				root_options = strdup(myoptions);
-				if (!root_options) {
-					error(ap->logopt, MODPREFIX "out of memory");
-					parse_sun_cleanup(mc, name,
-						options, path, myoptions);
-					free(root_loc);
-					free(root_path);
-					return 1;
-				}
+			if (status != CHE_OK) {
+				error(ap->logopt, MODPREFIX "error adding multi-mount");
+				cache_writelock(mc);
+				cache_delete_offset_list(mc, name);
+				cache_unlock(mc);
+				free(path);
+				free(options);
+				free(myoptions);
+				free(loc);
+				return 1;
 			}
+
 			free(loc);
 			free(path);
 			free(myoptions);
 		} while (*p == '/');
 
-		if (root_path) {
-			rv = sun_mount(ap, m_root, root_path, strlen(root_path),
-				root_loc, strlen(root_loc), root_options, ctxt);
+		/* Mount root offset if it exists */
+		cache_readlock(mc);
+		ro = cache_lookup_offset("/", "/", strlen(m_root), &me->multi_list);
+		if (ro) {
+			char *myoptions, *loc;
 
-			free(root_path);
-			free(root_loc);
-			free(root_options);
+			rv = parse_mapent(ro->mapent,
+				options, &myoptions, &loc, ap->logopt);
+			if (!rv) {
+				cache_unlock(mc);
+				error(ap->logopt,
+				      MODPREFIX "mount of root offset failed");
+				cache_writelock(mc);
+				cache_delete_offset_list(mc, name);
+				cache_unlock(mc);
+				free(options);
+				return 1;
+			}
+
+			rv = sun_mount(ap, m_root,
+				"/", 1, loc, strlen(loc), myoptions, ctxt);
+
+			free(myoptions);
+			free(loc);
 
 			if (rv < 0) {
+				cache_unlock(mc);
 				error(ap->logopt,
 				      MODPREFIX
 				      "mount multi-mount root %s failed", name);
 				cache_writelock(mc);
 				cache_delete_offset_list(mc, name);
 				cache_unlock(mc);
+				free(options);
 				return rv;
 			}
 		}
 
-		cache_readlock(mc);
 		if (!mount_multi_triggers(ap, m_root, me, "/")) {
+			cache_unlock(mc);
 			error(ap->logopt,
 			      MODPREFIX "failed to mount offset triggers");
-			rv = 1;
+			cache_writelock(mc);
+			cache_delete_offset_list(mc, name);
+			cache_unlock(mc);
+			free(options);
+			return 1;
 		}
 		cache_unlock(mc);
 
@@ -1209,6 +1204,14 @@ int parse_mount(struct autofs_point *ap,
 		int loclen;
 		int l;
 
+		/* Location can't begin with a '/' */
+		if (*p == '/') {
+			error(ap->logopt,
+			      MODPREFIX "error location begins with \"/\"");
+			free(options);
+			return 1;
+		}
+
 		if (*p == ':')
 			p++;	/* Sun escape for entries starting with / */
 
@@ -1220,6 +1223,23 @@ int parse_mount(struct autofs_point *ap,
 			return 1;
 		}
 
+		if (!*loc) {
+			error(ap->logopt, MODPREFIX "invalid location");
+			free(loc);
+			free(options);
+			return 1;
+		}
+
+		if (!validate_location(loc)) {
+			error(ap->logopt, MODPREFIX "invalid location");
+			free(loc);
+			free(options);
+			return 1;
+		}
+
+		debug(ap->logopt,
+		      MODPREFIX "dequote(\"%.*s\") -> %s", l, p, loc);
+
 		p += l;
 		p = skipspace(p);
 
@@ -1230,14 +1250,27 @@ int parse_mount(struct autofs_point *ap,
 			ent = dequote(p, l, ap->logopt);
 			if (!ent) {
 				error(ap->logopt, MODPREFIX "out of memory");
+				free(loc);
 				free(options);
 				return 1;
 			}
 
+			if (!validate_location(ent)) {
+				error(ap->logopt, MODPREFIX "invalid location");
+				free(ent);
+				free(loc);
+				free(options);
+				return 1;
+			}
+
+			debug(ap->logopt,
+			      MODPREFIX "dequote(\"%.*s\") -> %s", l, p, ent);
+
 			loc = realloc(loc, strlen(loc) + l + 2);
 			if (!loc) {
 				error(ap->logopt, MODPREFIX "out of memory");
 				free(ent);
+				free(loc);
 				free(options);
 				return 1;
 			}
@@ -1269,7 +1302,7 @@ int parse_mount(struct autofs_point *ap,
 		/* non-strict failure to normal failure for ordinary mount */
 		if (rv < 0)
 			rv = -rv;
-			
+
 		free(loc);
 		free(options);
 
