diff --git a/CHANGELOG b/CHANGELOG
index 2ffaba6..111c6af 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -10,6 +10,8 @@
 - cthon more cleanup and corrections.
 - cthon correction to host validation.
 - cthon fix submount operation broken by above.
+- cthon more parser corrections and attempt to fix multi-mounts
+  with various combinations of submounts (still broken).
 
 13/7/2006 autofs-5.0.1 rc1
 --------------------------
diff --git a/daemon/automount.c b/daemon/automount.c
index 21f0378..8fcf19a 100644
--- a/daemon/automount.c
+++ b/daemon/automount.c
@@ -243,8 +243,6 @@ static int umount_offsets(struct autofs_
 
 		sched_yield();
 
-		debug(ap->logopt, "umount offset %s", offset);
-
 		strcpy(key, base);
 		strcat(key, offset);
 		oe = cache_lookup_distinct(mc, key);
@@ -254,6 +252,8 @@ static int umount_offsets(struct autofs_
 			continue;
 		}
 
+		warn(ap->logopt, "umount offset %s", key);
+
 		/*
 		 * We're in trouble if umounting the triggers fails.
 		 * It should always succeed due to the expire design.
@@ -306,26 +306,16 @@ static int umount_ent(struct autofs_poin
 		rv = spawnll(log_debug, PATH_UMOUNT, PATH_UMOUNT, path, NULL);
 	}
 
-	status = pthread_mutex_lock(&ap->state_mutex);
-	if (status)
-		fatal(status);
-
 	/* We are doing a forced shutcwdown down so unlink busy mounts */
 	if (rv && (ap->state == ST_SHUTDOWN_FORCE || ap->state == ST_SHUTDOWN)) {
 		ret = stat(path, &st);
 		if (ret == -1 && errno == ENOENT) {
 			warn(ap->logopt, "mount point does not exist");
-			status = pthread_mutex_unlock(&ap->state_mutex);
-			if (status)
-				fatal(status);
 			return 0;
 		}
 
 		if (ret == 0 && !S_ISDIR(st.st_mode)) {
 			warn(ap->logopt, "mount point is not a directory");
-			status = pthread_mutex_unlock(&ap->state_mutex);
-			if (status)
-				fatal(status);
 			return 0;
 		}
 
@@ -353,10 +343,6 @@ static int umount_ent(struct autofs_poin
 		}
 	}
 
-	status = pthread_mutex_unlock(&ap->state_mutex);
-	if (status)
-		fatal(status);
-
 	return rv;
 }
 
@@ -559,7 +545,7 @@ int umount_multi(struct autofs_point *ap
 	if (!tree_get_mnt_list(mnts, &list, path, incl)) {
 		debug(ap->logopt, "no mounts found under %s", path);
 		check_rm_dirs(ap, path, incl);
-		return 1;
+		return 0;
 	}
 
 	left = 0;
@@ -581,6 +567,8 @@ int umount_multi(struct autofs_point *ap
 		debug(ap->logopt, "unmounting dir = %s", mptr->path);
 
 		if (umount_ent(ap, mptr->path, mptr->fs_type)) {
+			warn(ap->logopt, "could not umount dir %s",
+				mptr->path);
 			left++;
 		}
 	}
@@ -612,13 +600,11 @@ int umount_multi(struct autofs_point *ap
 				break;
 			}
 
-			if (!tree_is_mounted(mnts, buf)) {
-				if (umount_offsets(ap, mnts, buf)) {
-					warn(ap->logopt,
-					  "could not umount some offsets under %s",
-					  buf);
-					left++;
-				}
+			if (umount_offsets(ap, mnts, buf)) {
+				warn(ap->logopt,
+				     "could not umount some offsets under %s",
+				     buf);
+				left++;
 			}
 			free(de[n]);
 		}
@@ -670,35 +656,16 @@ int umount_autofs(struct autofs_point *a
 	/*
 	 * Since lookup.c is lazy about closing lookup modules
 	 * to prevent unneeded opens, we need to clean them up
-	 * before umount or the fs will be busy.
+	 * before umount.
 	 */
 	lookup_close_lookup(ap);
 
 	if (ap->type == LKP_INDIRECT) {
 		if (umount_all(ap, force) && !force)
 			return -1;
-
 		ret = umount_autofs_indirect(ap);
-	} else {
+	} else
 		ret = umount_autofs_direct(ap);
-	}
-
-	if (ap->submount) {
-		int status;
-
-		status = pthread_mutex_lock(&ap->parent->mounts_mutex);
-		if (status)
-			fatal(status);
-		ap->parent->submnt_count--;
-		list_del_init(&ap->mounts);
-		status = pthread_cond_signal(&ap->parent->mounts_cond);
-		if (status)
-			error(ap->logopt,
-			  "failed to signal submount umount notify condition");
-		status = pthread_mutex_unlock(&ap->parent->mounts_mutex);
-		if (status)
-			fatal(status);
-	}
 
 	return ret;
 }
@@ -778,28 +745,35 @@ static int get_pkt(struct autofs_point *
 		}
 
 		if (fds[1].revents & POLLIN) {
-			enum states next_state;
+			enum states next_state, post_state;
+			size_t read_size = sizeof(next_state);
+			int state_pipe;
 			int status;
 
-			status = pthread_mutex_lock(&ap->state_mutex);
-			if (status)
-				fatal(status);
+			next_state = post_state = ST_INVAL;
+
+			state_mutex_lock(ap);
 
-			if (fullread(ap->state_pipe[0], &next_state, sizeof(next_state)))
+			state_pipe = ap->state_pipe[0];
+
+			if (fullread(state_pipe, &next_state, read_size)) {
+				state_mutex_unlock(ap);
 				continue;
+			}
 
-			if (next_state != ap->state) {
+			if (next_state != ST_INVAL && next_state != ap->state) {
 				if (next_state != ST_SHUTDOWN)
-					st_add_task(ap, next_state);
+					post_state = next_state;
 				else
 					ap->state = ST_SHUTDOWN;
 			}
 
-			status = pthread_mutex_unlock(&ap->state_mutex);
-			if (status)
-				fatal(status);
+			state_mutex_unlock(ap);
 
-			if (ap->state == ST_SHUTDOWN)
+			if (post_state != ST_INVAL)
+				st_add_task(ap, post_state);
+
+			if (next_state == ST_SHUTDOWN)
 				return -1;
 		}
 
@@ -837,7 +811,7 @@ int do_expire(struct autofs_point *ap, c
 	if (ret == 0)
 		msg("expired %s", buf);
 	else
-		error(ap->logopt, "error while expiring %s", buf);
+		warn(ap->logopt, "couldn't complet expire of %s", buf);
 
 	tree_free_mnt_tree(mnts);
 
@@ -1238,23 +1212,26 @@ static void handle_mounts_cleanup(void *
 	struct autofs_point *ap;
 	char path[PATH_MAX + 1];
 	char buf[MAX_ERR_BUF];
-	unsigned int clean = 0;
+	unsigned int clean = 0, submount;
 
 	ap = (struct autofs_point *) arg;
 
+	submount = ap->submount;
+
 	strcpy(path, ap->path);
-	if (!ap->submount && strcmp(ap->path, "/-") && ap->dir_created)
+	if (!submount && strcmp(ap->path, "/-") && ap->dir_created)
 		clean = 1;
 
-	/* Make sure alarms are cleared */
-	alarm_delete(ap);
-
-	umount_autofs(ap, 1);
-
 	/* If we have been canceled then we may hold the state mutex. */
 	mutex_operation_wait(&ap->state_mutex);
 
-	master_remove_mapent(ap->entry);
+	st_remove_tasks(ap);
+	umount_autofs(ap, 1);
+
+	if (submount)
+		master_signal_submount(ap);
+	else
+		master_remove_mapent(ap->entry);
 	master_free_mapent_sources(ap->entry, 1);
 	master_free_mapent(ap->entry);
 
@@ -1271,7 +1248,7 @@ static void handle_mounts_cleanup(void *
 	msg("shut down path %s", path);
 
 	/* If we are the last tell the state machine to shutdown */
-	if (master_list_empty(master_list))
+	if (!submount && master_list_empty(master_list))
 		kill(getpid(), SIGTERM);
 
 	return;
@@ -1287,9 +1264,7 @@ void *handle_mounts(void *arg)
 	pthread_cleanup_push(return_start_status, &suc);
 	pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cancel_state);
 
-	status = pthread_mutex_lock(&ap->state_mutex);
-	if (status)
-		fatal(status);
+	state_mutex_lock(ap);
 
 	status = pthread_mutex_lock(&suc.mutex);
 	if (status) {
@@ -1300,9 +1275,7 @@ void *handle_mounts(void *arg)
 	if (mount_autofs(ap) < 0) {
 		crit(ap->logopt, "mount of %s failed!", ap->path);
 		suc.status = 1;
-		status = pthread_mutex_unlock(&ap->state_mutex);
-		if (status)
-			fatal(status);
+		state_mutex_unlock(ap);
 		umount_autofs(ap, 1);
 		pthread_exit(NULL);
 	}
@@ -1315,33 +1288,26 @@ void *handle_mounts(void *arg)
 
 	/* We often start several automounters at the same time.  Add some
 	   randomness so we don't all expire at the same time. */
-	if (ap->exp_timeout)
+	if (!ap->submount && ap->exp_timeout)
 		alarm_add(ap, ap->exp_runfreq + rand() % ap->exp_runfreq);
 
-	status = pthread_mutex_unlock(&ap->state_mutex);
-	if (status)
-		fatal(status);
-
 	pthread_cleanup_push(handle_mounts_cleanup, ap);
 	pthread_setcancelstate(cancel_state, &cancel_state);
 
+	state_mutex_unlock(ap);
+
 	while (ap->state != ST_SHUTDOWN) {
 		if (handle_packet(ap)) {
 			int ret, result;
 
-			status = pthread_mutex_lock(&ap->state_mutex);
-			if (status)
-				fatal(status);
-
+			state_mutex_lock(ap);
 			/*
 			 * For a direct mount map all mounts have already gone
 			 * by the time we get here.
 			 */
 			if (ap->type == LKP_DIRECT) {
 				status = 1;
-				status = pthread_mutex_unlock(&ap->state_mutex);
-				if (status)
-					fatal(status);
+				state_mutex_unlock(ap);
 				break;
 			}
 
@@ -1351,24 +1317,13 @@ void *handle_mounts(void *arg)
 			 */
 			ret = ioctl(ap->ioctlfd, AUTOFS_IOC_ASKUMOUNT, &result);
 			if (ret == -1) {
-				status = pthread_mutex_unlock(&ap->state_mutex);
-				if (status)
-					fatal(status);
+				state_mutex_unlock(ap);
 				break;
 			}
 
 			/* OK to exit */
-			if (result) {
-				status = pthread_mutex_unlock(&ap->state_mutex);
-				if (status)
-					fatal(status);
-				break;
-			}
-
-			if (ap->state == ST_SHUTDOWN) {
-				status = pthread_mutex_unlock(&ap->state_mutex);
-				if (status)
-					fatal(status);
+			if (ap->state == ST_SHUTDOWN || result) {
+				state_mutex_unlock(ap);
 				break;
 			}
 
@@ -1376,29 +1331,14 @@ void *handle_mounts(void *arg)
 			warn(ap->logopt,
 			     "can't shutdown: filesystem %s still busy",
 			     ap->path);
-			alarm_add(ap, ap->exp_runfreq);
+			if (!ap->submount)
+				alarm_add(ap, ap->exp_runfreq);
 			nextstate(ap->state_pipe[1], ST_READY);
 
-			status = pthread_mutex_unlock(&ap->state_mutex);
-			if (status)
-				fatal(status);
+			state_mutex_unlock(ap);
 		}
 	}
 
-	status = pthread_mutex_lock(&ap->mounts_mutex);
-	if (status)
-		fatal(status);
-
-	while (ap->submnt_count) {
-		status = pthread_cond_wait(&ap->mounts_cond, &ap->mounts_mutex);
-		if (status)
-			fatal(status);
-	}
-
-	status = pthread_mutex_unlock(&ap->mounts_mutex);
-	if (status)
-		fatal(status);
-
 	pthread_cleanup_pop(1);
 
 	/*
diff --git a/daemon/direct.c b/daemon/direct.c
index 3905ed0..89c8db2 100644
--- a/daemon/direct.c
+++ b/daemon/direct.c
@@ -493,16 +493,20 @@ int umount_autofs_offset(struct autofs_p
 
 	rv = umount(me->key);
 	if (rv == -1) {
-		if (errno == ENOENT) {
+		switch (errno) {
+		case ENOENT:
 			warn(ap->logopt, "mount point does not exist");
 			return 0;
-		} else if (errno == EBUSY) {
+			break;
+		case EBUSY:
 			warn(ap->logopt, "mount point %s is in use", me->key);
 			if (ap->state != ST_SHUTDOWN_FORCE)
-				return 0;
-		} else if (errno == ENOTDIR) {
+				return 1;
+			break;
+		case ENOTDIR:
 			error(ap->logopt, "mount point is not a directory");
 			return 0;
+			break;
 		}
 		goto force_umount;
 	}
@@ -684,11 +688,13 @@ void *expire_proc_direct(void *arg)
 		pthread_exit(NULL);
 	}
 
+	pthread_cleanup_push(expire_cleanup, ea);
+
 	status = pthread_mutex_unlock(&ea->mutex);
 	if (status)
 		fatal(status);
 
-	pthread_cleanup_push(expire_cleanup, ea);
+	master_notify_submounts(ap, ap->state);
 
 	/* Get a list of real mounts and expire them if possible */
 	mnts = get_mnt_list(_PROC_MOUNTS, "/", 0);
diff --git a/daemon/indirect.c b/daemon/indirect.c
index 0c47cfd..7bde7ec 100644
--- a/daemon/indirect.c
+++ b/daemon/indirect.c
@@ -280,7 +280,8 @@ int mount_autofs_indirect(struct autofs_
 
 int umount_autofs_indirect(struct autofs_point *ap)
 {
-	int rv;
+	char buf[MAX_ERR_BUF];
+	int ret, rv;
 
 	/*
 	 * Since submounts look after themselves the parent never knows
@@ -290,10 +291,13 @@ int umount_autofs_indirect(struct autofs
 	 */
 	if (ap->submount) {
 		struct master_mapent *entry = ap->parent->entry;
-		struct map_source *map = entry->first;
+		struct map_source *map;
 		struct mapent_cache *mc;
 		struct mapent *me;
 
+		pthread_cleanup_push(master_source_lock_cleanup, entry);
+		master_source_readlock(entry);
+		map = entry->first;
 		while (map) {
 			mc = map->mc;
 			cache_readlock(mc);
@@ -307,6 +311,13 @@ int umount_autofs_indirect(struct autofs
 			cache_unlock(mc);
 			map = map->next;
 		}
+		pthread_cleanup_pop(1);
+	}
+
+	/* If we are trying to shutdown make sure we can umount */
+	if (!ioctl(ap->ioctlfd, AUTOFS_IOC_ASKUMOUNT, &ret)) {
+		if (!ret)
+			warn(ap->logopt, "mount still busy %s", ap->path);
 	}
 
 	if (ap->ioctlfd >= 0) {
@@ -373,7 +384,7 @@ void *expire_proc_indirect(void *arg)
 	unsigned int now;
 	int offsets, submnts, count;
 	int ioctlfd;
-	int status;
+	int status, ret;
 
 	ea = (struct expire_args *) arg;
 
@@ -395,11 +406,13 @@ void *expire_proc_indirect(void *arg)
 		pthread_exit(NULL);
 	}
 
+	pthread_cleanup_push(expire_cleanup, ea);
+
 	status = pthread_mutex_unlock(&ea->mutex);
 	if (status)
 		fatal(status);
 
-	pthread_cleanup_push(expire_cleanup, ea);
+	master_notify_submounts(ap, ap->state);
 
 	/* Get a list of real mounts and expire them if possible */
 	mnts = get_mnt_list(_PROC_MOUNTS, ap->path, 0);
@@ -518,28 +531,13 @@ void *expire_proc_indirect(void *arg)
 	}
 
 	/* If we are trying to shutdown make sure we can umount */
-	status = pthread_mutex_lock(&ap->mounts_mutex);
-	if (status)
-		fatal(status);
-
-	if (!list_empty(&ap->submounts)) {
-		ea->status = 1;
-	} else {
-		int ret;
-
-		if (!ioctl(ap->ioctlfd, AUTOFS_IOC_ASKUMOUNT, &ret)) {
-			if (!ret) {
-				warn(ap->logopt,
-				      "mount still busy %s", ap->path);
-				ea->status = 1;
-			}
+	if (!ioctl(ap->ioctlfd, AUTOFS_IOC_ASKUMOUNT, &ret)) {
+		if (!ret) {
+			warn(ap->logopt, "mount still busy %s", ap->path);
+			ea->status = 1;
 		}
 	}
 
-	status = pthread_mutex_unlock(&ap->mounts_mutex);
-	if (status)
-		fatal(status);
-
 	pthread_cleanup_pop(1);
 
 	return NULL;
diff --git a/daemon/state.c b/daemon/state.c
index 212b2c2..e74674a 100644
--- a/daemon/state.c
+++ b/daemon/state.c
@@ -33,6 +33,10 @@ static LIST_HEAD(state_queue);
 static unsigned int signaled = 0;
 static void st_set_thid(struct autofs_point *, pthread_t);
 
+static pthread_mutex_t task_mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t task_cond = PTHREAD_COND_INITIALIZER;
+static unsigned int task_signaled;
+
 int do_mount_autofs_direct(struct autofs_point *, struct mnt_list *, struct mapent *);
 
 void dump_state_queue(void)
@@ -83,18 +87,12 @@ void expire_cleanup(void *arg)
 	int statefd;
 	enum states next = ST_INVAL;
 	int success;
-	int status;
 
 	ea = (struct expire_args *) arg;
 	ap = ea->ap;
 	success = ea->status;
 
-	status = pthread_mutex_lock(&ap->state_mutex);
-	if (status) {
-		error(ap->logopt, "state mutex lock failed");
-		free(ea);
-		return;
-	}
+	state_mutex_lock(ap);
 
 	debug(ap->logopt,
 	      "got thid %lu path %s stat %d",
@@ -105,6 +103,7 @@ void expire_cleanup(void *arg)
 	/* Check to see if expire process finished */
 	if (thid == ap->exp_thread) {
 		ap->exp_thread = 0;
+		st_set_thid(ap, 0);
 
 		switch (ap->state) {
 		case ST_EXPIRE:
@@ -113,11 +112,13 @@ void expire_cleanup(void *arg)
 			/* If we're a submount and we've just
 			   pruned or expired everything away,
 			   try to shut down */
-			if (ap->submount && !success && ap->state != ST_SHUTDOWN) {
+			if (ap->submount && !success) {
 				next = ST_SHUTDOWN_PENDING;
 				break;
 			}
-			alarm_add(ap, ap->exp_runfreq);
+
+			if (!ap->submount)
+				alarm_add(ap, ap->exp_runfreq);
 			/* FALLTHROUGH */
 
 		case ST_READY:
@@ -134,7 +135,8 @@ #else
 
 			/* Failed shutdown returns to ready */
 			warn(ap->logopt, "filesystem %s still busy", ap->path);
-			alarm_add(ap, ap->exp_runfreq);
+			if (!ap->submount)
+				alarm_add(ap, ap->exp_runfreq);
 			next = ST_READY;
 			break;
 #endif
@@ -157,9 +159,7 @@ #endif
 	if (next != ST_INVAL)
 		nextstate(statefd, next);
 
-	status = pthread_mutex_unlock(&ap->state_mutex);
-	if (status)
-		error(ap->logopt, "state mutex unlock failed");
+	state_mutex_unlock(ap);
 
 	free(ea);
 
@@ -173,22 +173,8 @@ static unsigned int st_ready(struct auto
 
 	ap->state = ST_READY;
 
-	if (ap->submount) {
-		int status;
-
-		status = pthread_mutex_lock(&ap->parent->mounts_mutex);
-		if (status)
-			fatal(status);
-
-		status = pthread_cond_signal(&ap->parent->mounts_cond);
-		if (status)
-			error(ap->logopt,
-			      "failed to signal submount notify condition");
-
-		status = pthread_mutex_unlock(&ap->parent->mounts_mutex);
-		if (status)
-			fatal(status);
-	}
+	if (ap->submount)
+		master_signal_submount(ap);
 
 	return 1;
 }
@@ -298,22 +284,17 @@ static void do_readmap_cleanup(void *arg
 {
 	struct readmap_args *ra;
 	struct autofs_point *ap;
-	int status;
 
 	ra = (struct readmap_args *) arg;
 
 	ap = ra->ap;
 	ap->readmap_thread = 0;
 
-	status = pthread_mutex_lock(&ap->state_mutex);
-	if (status)
-		fatal(status);
+	state_mutex_lock(ap);
 
 	nextstate(ap->state_pipe[1], ST_READY);
 
-	status = pthread_mutex_unlock(&ap->state_mutex);
-	if (status)
-		fatal(status);
+	state_mutex_unlock(ap);
 
 	free(ra);
 
@@ -485,7 +466,8 @@ static unsigned int st_prepare_shutdown(
 	debug(ap->logopt, "state %d path %s", ap->state, ap->path);
 
 	/* Turn off timeouts for this mountpoint */
-	alarm_delete(ap);
+	if (!ap->submount)
+		alarm_delete(ap);
 
 	assert(ap->state == ST_READY || ap->state == ST_EXPIRE);
 	ap->state = ST_SHUTDOWN_PENDING;
@@ -496,7 +478,8 @@ static unsigned int st_prepare_shutdown(
 	case EXP_ERROR:
 	case EXP_PARTIAL:
 		/* It didn't work: return to ready */
-		alarm_add(ap, ap->exp_runfreq);
+		if (!ap->submount)
+			alarm_add(ap, ap->exp_runfreq);
 		nextstate(ap->state_pipe[1], ST_READY);
 		return 0;
 
@@ -513,7 +496,8 @@ static unsigned int st_force_shutdown(st
 	debug(ap->logopt, "state %d path %s", ap->state, ap->path);
 
 	/* Turn off timeouts for this mountpoint */
-	alarm_delete(ap);
+	if (!ap->submount)
+		alarm_delete(ap);
 
 	assert(ap->state == ST_READY || ap->state == ST_EXPIRE);
 	ap->state = ST_SHUTDOWN_FORCE;
@@ -524,7 +508,8 @@ static unsigned int st_force_shutdown(st
 	case EXP_ERROR:
 	case EXP_PARTIAL:
 		/* It didn't work: return to ready */
-		alarm_add(ap, ap->exp_runfreq);
+		if (!ap->submount)
+			alarm_add(ap, ap->exp_runfreq);
 		nextstate(ap->state_pipe[1], ST_READY);
 		return 0;
 
@@ -542,12 +527,14 @@ static unsigned int st_prune(struct auto
 	ap->state = ST_PRUNE;
 
 	/* Turn off timeouts while we prune */
-	alarm_delete(ap);
+	if (!ap->submount)
+		alarm_delete(ap);
 
 	switch (expire_proc(ap, 1)) {
 	case EXP_ERROR:
 	case EXP_PARTIAL:
-		alarm_add(ap, ap->exp_runfreq);
+		if (!ap->submount)
+			alarm_add(ap, ap->exp_runfreq);
 		nextstate(ap->state_pipe[1], ST_READY);
 		return 0;
 
@@ -565,12 +552,14 @@ static unsigned int st_expire(struct aut
 	ap->state = ST_EXPIRE;
 
 	/* Turn off timeouts while we expire */
-	alarm_delete(ap);
+	if (!ap->submount)
+		alarm_delete(ap);
 
 	switch (expire_proc(ap, 0)) {
 	case EXP_ERROR:
 	case EXP_PARTIAL:
-		alarm_add(ap, ap->exp_runfreq);
+		if (!ap->submount)
+			alarm_add(ap, ap->exp_runfreq);
 		nextstate(ap->state_pipe[1], ST_READY);
 		return 0;
 
@@ -583,20 +572,24 @@ static unsigned int st_expire(struct aut
 /* Insert alarm entry on ordered list. */
 int st_add_task(struct autofs_point *ap, enum states state)
 {
-	struct list_head *head = &state_queue;
+	struct list_head *head;
 	struct list_head *p;
 	struct state_queue *new;
 	unsigned int empty = 1;
 	int status;
 
+	state_mutex_lock(ap);
+
 	/* Task termination marker, poke state machine */
 	if (state == ST_READY) {
+		st_ready(ap);
+
+		state_mutex_unlock(ap);
+
 		status = pthread_mutex_lock(&mutex);
 		if (status)
 			fatal(status);
 
-		st_ready(ap);
-
 		signaled = 1;
 		status = pthread_cond_signal(&cond);
 		if (status)
@@ -609,6 +602,13 @@ int st_add_task(struct autofs_point *ap,
 		return 1;
 	}
 
+	if (ap->state == ST_SHUTDOWN) {
+		state_mutex_unlock(ap);
+		return 1;
+	}
+
+	state_mutex_unlock(ap);
+
 	new = malloc(sizeof(struct state_queue));
 	if (!new)
 		return 0;
@@ -620,15 +620,12 @@ int st_add_task(struct autofs_point *ap,
 	INIT_LIST_HEAD(&new->list);
 	INIT_LIST_HEAD(&new->pending);
 
-	/* If we are shutting down get rid on all tasks */
-/*	if (ap->state == ST_SHUTDOWN_PENDING ||
-	    ap->state == ST_SHUTDOWN_FORCE)
-		st_remove_tasks(ap);
-*/
 	status = pthread_mutex_lock(&mutex);
 	if (status)
 		fatal(status);
 
+	head = &state_queue;
+
 	/* Add to task queue for autofs_point ? */
 	list_for_each(p, head) {
 		struct state_queue *task;
@@ -660,7 +657,7 @@ int st_add_task(struct autofs_point *ap,
 
 void st_remove_tasks(struct autofs_point *ap)
 {
-	struct list_head *head = &state_queue;
+	struct list_head *head;
 	struct list_head *p, *q;
 	struct state_queue *task, *waiting;
 	int status;
@@ -669,6 +666,8 @@ void st_remove_tasks(struct autofs_point
 	if (status)
 		fatal(status);
 
+	head = &state_queue;
+
 	if (list_empty(head)) {
 		status = pthread_mutex_unlock(&mutex);
 		if (status)
@@ -707,22 +706,33 @@ void st_remove_tasks(struct autofs_point
 		fatal(status);
 }
 
-static int run_state_task(struct state_queue *task)
+static void *do_run_task(void *arg)
 {
+	struct state_queue *task;
 	struct autofs_point *ap;
-	enum states state;
-	enum states next_state;
-	int status, ret = 1;
+	enum states next_state, state;
+	int status, ret;
+ 
+	status = pthread_mutex_lock(&task_mutex);
+	if (status)
+		fatal(status);
 
+	task = (struct state_queue *) arg;
 	ap = task->ap;
-	status = pthread_mutex_lock(&ap->state_mutex);
+	next_state = task->state;
+
+	task_signaled = 1;
+	status = pthread_cond_signal(&task_cond);
 	if (status)
 		fatal(status);
 
-	state = ap->state;
-	next_state = task->state;
+	status = pthread_mutex_unlock(&task_mutex);
+	if (status)
+		fatal(status);
 
-/*	debug("task %p state %d next %d", task, state, task->state); */
+	state_mutex_lock(ap);
+
+	state = ap->state;
 
 	if (next_state != state) {
 		switch (next_state) {
@@ -752,11 +762,41 @@ static int run_state_task(struct state_q
 		}
 	}
 
-	status = pthread_mutex_unlock(&ap->state_mutex);
+	state_mutex_unlock(ap);
+
+	return;
+}
+
+static int run_state_task(struct state_queue *task)
+{
+	pthread_t thid;
+	int status;
+
+	status = pthread_mutex_lock(&task_mutex);
+	if (status)
+		fatal(status);
+
+	status = pthread_create(&thid, &thread_attr, do_run_task, task);
+	if (status) {
+		error(task->ap->logopt, "error running task");
+		status = pthread_mutex_unlock(&task_mutex);
+		if (status)
+			fatal(status);
+		return 0;
+	}
+
+	task_signaled = 0;
+	while (!task_signaled) {
+		status = pthread_cond_wait(&task_cond, &task_mutex);
+		if (status)
+			fatal(status);
+	}
+
+	status = pthread_mutex_unlock(&task_mutex);
 	if (status)
 		fatal(status);
 
-	return ret;
+	return 1;
 }
 
 static void st_set_thid(struct autofs_point *ap, pthread_t thid)
@@ -776,7 +816,7 @@ static void st_set_thid(struct autofs_po
 
 static void *st_queue_handler(void *arg)
 {
-	struct list_head *head = &state_queue;
+	struct list_head *head;
 	struct list_head *p;
 	int status;
 
@@ -784,6 +824,8 @@ static void *st_queue_handler(void *arg)
 	if (status)
 		fatal(status);
 
+	head = &state_queue;
+
 	while (1) {
 		/*
 		 * If the state queue list is empty, wait until an
@@ -853,10 +895,10 @@ static void *st_queue_handler(void *arg)
 					run_state_task(task);
 					continue;
 				}
-
-				if (task->cancel)
+/*
+				if (task->thid && task->cancel)
 					pthread_cancel(task->thid);
-
+*/
 				/* Still busy */
 				if (task->thid) {
 					status = pthread_kill(task->thid, 0);
diff --git a/include/automount.h b/include/automount.h
index a71606e..a689046 100644
--- a/include/automount.h
+++ b/include/automount.h
@@ -84,18 +84,19 @@ #define LKP_FAIL	0x0001
 
 #define LKP_INDIRECT	0x0002
 #define LKP_DIRECT	0x0004
-#define LKP_NOMATCH	0x0008
-#define LKP_MATCH	0x0010
-#define LKP_NEXT	0x0020
-#define LKP_MOUNT	0x0040
-#define LKP_WILD	0x0080
-#define LKP_LOOKUP	0x0100
-#define LKP_GHOST	0x0200
-#define LKP_REREAD	0x0400
-#define LKP_EMPTY	0x0800
-#define LKP_ERR_FORMAT	0x1000
-#define LKP_ERR_MOUNT	0x2000
-#define LKP_NOTSUP	0x4000
+#define LKP_MULTI	0x0008
+#define LKP_NOMATCH	0x0010
+#define LKP_MATCH	0x0020
+#define LKP_NEXT	0x0040
+#define LKP_MOUNT	0x0080
+#define LKP_WILD	0x0100
+#define LKP_LOOKUP	0x0200
+#define LKP_GHOST	0x0400
+#define LKP_REREAD	0x0800
+#define LKP_EMPTY	0x1000
+#define LKP_ERR_FORMAT	0x2000
+#define LKP_ERR_MOUNT	0x4000
+#define LKP_NOTSUP	0x8000
 
 #define MAX_ERR_BUF	128
 
@@ -185,7 +186,7 @@ const char **copy_argv(int argc, const c
 int compare_argv(int argc1, const char **argv1, int argc2, const char **argv2);
 int free_argv(int argc, const char **argv);
 
-void dump_core(void);
+inline void dump_core(void);
 int sigchld_start_handler(void);
 int sigchld_block(void);
 int sigchld_unblock(void);
@@ -435,6 +436,7 @@ struct autofs_point {
 	struct autofs_point *parent;	/* Owner of mounts list for submount */
 	pthread_mutex_t mounts_mutex;	/* Protect mount lists */
 	pthread_cond_t mounts_cond;	/* Submounts condition variable */
+	unsigned int mounts_signaled;	/* Submount signals task complete */
 	struct list_head mounts;	/* List of autofs mounts at current level */
 	unsigned int submount;		/* Is this a submount */
 	unsigned int submnt_count;	/* Number of submounts */
@@ -454,6 +456,7 @@ int expire_offsets_direct(struct autofs_
 int mount_autofs_indirect(struct autofs_point *ap);
 int mount_autofs_direct(struct autofs_point *ap);
 int mount_autofs_offset(struct autofs_point *ap, struct mapent *me, int is_autofs_fs);
+void submount_signal_parent(struct autofs_point *ap, unsigned int success);
 int umount_autofs(struct autofs_point *ap, int force);
 int umount_autofs_indirect(struct autofs_point *ap);
 int do_umount_autofs_direct(struct autofs_point *ap, struct mnt_list *mnts, struct mapent *me);
@@ -466,6 +469,34 @@ int handle_packet_missing_direct(struct 
 void rm_unwanted(const char *path, int incl, dev_t dev);
 int count_mounts(struct autofs_point *ap, const char *path);
 
+#define state_mutex_lock(ap) \
+do { \
+	int status = pthread_mutex_lock(&ap->state_mutex); \
+	if (status) \
+		fatal(status); \
+} while(0)
+
+#define state_mutex_unlock(ap) \
+do{ \
+	int status = pthread_mutex_unlock(&ap->state_mutex); \
+	if (status) \
+		fatal(status); \
+} while (0)
+
+#define mounts_mutex_lock(ap) \
+do { \
+	int status = pthread_mutex_lock(&ap->mounts_mutex); \
+	if (status) \
+		fatal(status); \
+} while (0)
+
+#define mounts_mutex_unlock(ap) \
+do { \
+	int status = pthread_mutex_unlock(&ap->mounts_mutex); \
+	if (status) \
+		fatal(status); \
+} while(0)
+
 /* Expire alarm handling routines */
 int alarm_start_handler(void);
 int alarm_add(struct autofs_point *ap, time_t seconds);
diff --git a/include/master.h b/include/master.h
index dcd77eb..57760a6 100644
--- a/include/master.h
+++ b/include/master.h
@@ -93,9 +93,25 @@ void master_free_mapent_sources(struct m
 void master_free_mapent(struct master_mapent *);
 struct master *master_new(const char *, unsigned int, unsigned int);
 int master_read_master(struct master *, time_t, int);
+void master_notify_submounts(struct autofs_point *, enum states);
+void master_signal_submount(struct autofs_point *);
 void master_notify_state_change(struct master *, int);
 int master_mount_mounts(struct master *, time_t, int);
 int master_list_empty(struct master *);
 int master_kill(struct master *);
 
+#define master_mutex_lock() \
+do { \
+	int status = pthread_mutex_lock(&master_mutex); \
+	if (status) \
+		fatal(status); \
+} while (0)
+
+#define master_mutex_unlock() \
+do { \
+	int status = pthread_mutex_unlock(&master_mutex); \
+	if (status) \
+		fatal(status); \
+} while (0)
+
 #endif
diff --git a/include/parse_subs.h b/include/parse_subs.h
index 7c23429..e87cea5 100644
--- a/include/parse_subs.h
+++ b/include/parse_subs.h
@@ -23,6 +23,7 @@ int check_colon(const char *);
 int chunklen(const char *, int);
 int strmcmp(const char *, const char *, int);
 char *dequote(const char *, int, unsigned int);
-char *sanitize_path(const char *, int);
+int span_space(const char *, unsigned int);
+char *sanitize_path(const char *, int, unsigned int, unsigned int);
 
 #endif
diff --git a/lib/alarm.c b/lib/alarm.c
index dc90b59..8124796 100755
--- a/lib/alarm.c
+++ b/lib/alarm.c
@@ -26,12 +26,27 @@ static pthread_mutex_t mutex = PTHREAD_M
 static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
 static LIST_HEAD(alarms);
 
+#define alarm_lock() \
+do { \
+	int status = pthread_mutex_lock(&mutex); \
+	if (status) \
+		fatal(status); \
+} while (0)
+
+#define alarm_unlock() \
+do { \
+	int status = pthread_mutex_unlock(&mutex); \
+	if (status) \
+		fatal(status); \
+} while (0)
+
 void dump_alarms(void)
 {
-	struct list_head *head = &alarms;
+	struct list_head *head;
 	struct list_head *p;
 
 	pthread_mutex_lock(&mutex);
+	head = &alarms;
 	list_for_each(p, head) {
 		struct alarm *this;
 
@@ -44,7 +59,7 @@ void dump_alarms(void)
 /* Insert alarm entry on ordered list. */
 int alarm_add(struct autofs_point *ap, time_t seconds)
 {
-	struct list_head *head = &alarms;
+	struct list_head *head;
 	struct list_head *p;
 	struct alarm *new;
 	time_t now = time(NULL);
@@ -60,9 +75,9 @@ int alarm_add(struct autofs_point *ap, t
 	new->cancel = 0;
 	new->time = now + seconds;
 
-	status = pthread_mutex_lock(&mutex);
-	if (status)
-		fatal(status);
+	alarm_lock();
+
+	head = &alarms;
 
 	/* Check if we have a pending alarm */
 	if (!list_empty(head)) {
@@ -95,29 +110,25 @@ int alarm_add(struct autofs_point *ap, t
 			fatal(status);
 	}
 
-	status = pthread_mutex_unlock(&mutex);
-	if (status)
-		fatal(status);
+	alarm_unlock();
 
 	return 1;
 }
 
 void alarm_delete(struct autofs_point *ap)
 {
-	struct list_head *head = &alarms;
+	struct list_head *head;
 	struct list_head *p;
 	struct alarm *current;
 	unsigned int signal_cancel = 0;
 	int status;
 
-	status = pthread_mutex_lock(&mutex);
-	if (status)
-		fatal(status);
+	alarm_lock();
+
+	head = &alarms;
 
 	if (list_empty(head)) {
-		status = pthread_mutex_unlock(&mutex);
-		if (status)
-			fatal(status);
+		alarm_unlock();
 		return;
 	}
 
@@ -149,22 +160,22 @@ void alarm_delete(struct autofs_point *a
 			fatal(status);
 	}
 
-	status = pthread_mutex_unlock(&mutex);
-	if (status)
-		fatal(status);
+	alarm_unlock();
+
+	return;
 }
 
 static void *alarm_handler(void *arg)
 {
-	struct list_head *head = &alarms;
+	struct list_head *head;
 	struct autofs_point *ap;
 	struct timespec expire;
 	time_t now;
 	int status;
 
-	status = pthread_mutex_lock(&mutex);
-	if (status)
-		fatal(status);
+	alarm_lock();
+
+	head = &alarms;
 
 	while (1) {
 		struct alarm *current;
@@ -192,15 +203,11 @@ static void *alarm_handler(void *arg)
 				continue;
 			}
 
-			status = pthread_mutex_lock(&ap->state_mutex);
-			if (status)
-				fatal(status);
+			state_mutex_lock(ap);
 
 			nextstate(ap->state_pipe[1], ST_EXPIRE);
 
-			status = pthread_mutex_unlock(&ap->state_mutex);
-			if (status)
-				fatal(status);
+			state_mutex_unlock(ap);
 
 			free(current);
 			continue;
@@ -227,18 +234,12 @@ static void *alarm_handler(void *arg)
 				break;
 
 			list_del(&current->list);
+			free(current);
 
-			status = pthread_mutex_lock(&ap->state_mutex);
-			if (status)
-				fatal(status);
-
-			nextstate(ap->state_pipe[1], ST_EXPIRE);
-
-			status = pthread_mutex_unlock(&ap->state_mutex);
-			if (status)
-				fatal(status);
+			alarm_unlock();
+			st_add_task(ap, ST_EXPIRE);
+			alarm_lock();
 
-			free(current);
 			break;
 		}
 	}
diff --git a/lib/master.c b/lib/master.c
index 1fe17bb..6bf21ad 100644
--- a/lib/master.c
+++ b/lib/master.c
@@ -131,6 +131,13 @@ void master_free_autofs_point(struct aut
 	if (!ap)
 		return;
 
+	if (ap->submount) {
+		mounts_mutex_lock(ap);
+		ap->parent->submnt_count--;
+		list_del(&ap->mounts);
+		mounts_mutex_unlock(ap);
+	}
+
 	status = pthread_mutex_destroy(&ap->state_mutex);
 	if (status)
 		fatal(status);
@@ -291,15 +298,11 @@ struct map_source *master_find_map_sourc
 	struct map_source *source = NULL;
 	int status;
 
-	status = pthread_mutex_lock(&master_mutex);
-	if (status)
-		fatal(status);
+	master_mutex_lock();
 
 	source = __master_find_map_source(entry, type, format, argc, argv);
 
-	status = pthread_mutex_unlock(&master_mutex);
-	if (status)
-		fatal(status);
+	master_mutex_unlock();
 
 	return source;
 }
@@ -558,9 +561,7 @@ struct master_mapent *master_find_mapent
 	struct list_head *head, *p;
 	int status;
 
-	status = pthread_mutex_lock(&master_mutex);
-	if (status)
-		fatal(status);
+	master_mutex_lock();
 
 	head = &master->mounts;
 	list_for_each(p, head) {
@@ -569,16 +570,12 @@ struct master_mapent *master_find_mapent
 		entry = list_entry(p, struct master_mapent, list);
 
 		if (!strcmp(entry->path, path)) {
-			status = pthread_mutex_unlock(&master_mutex);
-			if (status)
-				fatal(status);
+			master_mutex_unlock();
 			return entry;
 		}
 	}
 
-	status = pthread_mutex_unlock(&master_mutex);
-	if (status)
-		fatal(status);
+	master_mutex_unlock();
 
 	return NULL;
 }
@@ -630,33 +627,26 @@ void master_add_mapent(struct master *ma
 {
 	int status;
 
-	status = pthread_mutex_lock(&master_mutex);
-	if (status)
-		fatal(status);
-
+	master_mutex_lock();
 	list_add_tail(&entry->list, &master->mounts);
-
-	status = pthread_mutex_unlock(&master_mutex);
-	if (status)
-		fatal(status);
+	master_mutex_unlock();
 
 	return;
 }
 
 void master_remove_mapent(struct master_mapent *entry)
 {
+	struct autofs_point *ap;
 	int status;
 
-	status = pthread_mutex_lock(&master_mutex);
-	if (status)
-		fatal(status);
+	master_mutex_lock();
 
 	if (!list_empty(&entry->list))
 		list_del_init(&entry->list);
 
-	status = pthread_mutex_unlock(&master_mutex);
-	if (status)
-		fatal(status);
+	master_mutex_unlock();
+
+	return;
 }
 
 void master_free_mapent_sources(struct master_mapent *entry, unsigned int free_cache)
@@ -749,73 +739,84 @@ int master_read_master(struct master *ma
 
 	master_mount_mounts(master, age, readall);
 
-	status = pthread_mutex_lock(&master_mutex);
-	if (status)
-		fatal(status);
+	master_mutex_lock();
 
 	if (list_empty(&master->mounts)) {
 		error(LOGOPT_ANY, "no mounts in table");
-		status = pthread_mutex_unlock(&master_mutex);
-		if (status)
-			fatal(status);
+		master_mutex_unlock();
 		return 0;
 	}
 
-	status = pthread_mutex_unlock(&master_mutex);
-	if (status)
-		fatal(status);
+	master_mutex_unlock();
 
 	return 1;
 }
 
 static void notify_submounts(struct autofs_point *ap, enum states state)
 {
-	struct list_head *head;
 	struct list_head *p;
 	struct autofs_point *this;
 	int status;
 
-	status = pthread_mutex_lock(&ap->mounts_mutex);
-	if (status)
-		fatal(status);
-
-	head = &ap->submounts;
-	p = head->next;
-	while (p != head) {
-		unsigned int empty;
+	mounts_mutex_lock(ap);
 
+	list_for_each(p, &ap->submounts) {
 		this = list_entry(p, struct autofs_point, mounts);
-		p = p->next;
 
-		empty = list_empty(&this->submounts);
+		if (!list_empty(&this->submounts))
+			notify_submounts(this, state);
 
-		status = pthread_mutex_lock(&this->state_mutex);
-		if (status)
-			fatal(status);
+		state_mutex_lock(this);
 
-		if (!empty) {
-			pthread_mutex_unlock(&ap->mounts_mutex);
-			notify_submounts(this, state);
-			pthread_mutex_lock(&ap->mounts_mutex);
+		if (this->state == ST_SHUTDOWN) {
+			state_mutex_unlock(this);
+			continue;
 		}
 
 		nextstate(this->state_pipe[1], state);
 
-		status = pthread_mutex_unlock(&this->state_mutex);
-		if (status)
-			fatal(status);
+		state_mutex_unlock(this);
 
-		status = pthread_cond_wait(&ap->mounts_cond, &ap->mounts_mutex);
-		if (status) {
-			error(LOGOPT_ANY, "wait for submount failed");
-			fatal(status);
+		ap->mounts_signaled = 0;
+		while (!ap->mounts_signaled) {
+			status = pthread_cond_wait(&ap->mounts_cond, &ap->mounts_mutex);
+			if (status)
+				fatal(status);
 		}
 	}
 
-	status = pthread_mutex_unlock(&ap->mounts_mutex);
+	mounts_mutex_unlock(ap);
+
+	return;
+}
+
+void master_notify_submounts(struct autofs_point *ap, enum states state)
+{
+	/* Initiate from master entries only */
+	if (ap->submount || list_empty(&ap->submounts))
+		return;
+	master_mutex_lock();
+	notify_submounts(ap, state);
+	master_mutex_unlock();
+	return;
+}
+
+void master_signal_submount(struct autofs_point *ap)
+{
+	int status;
+
+	if (!ap->parent)
+		return;
+
+	mounts_mutex_lock(ap->parent);
+
+	ap->parent->mounts_signaled = 1;
+	status = pthread_cond_signal(&ap->parent->mounts_cond);
 	if (status)
 		fatal(status);
 
+	mounts_mutex_unlock(ap->parent);
+
 	return;
 }
 
@@ -824,41 +825,40 @@ void master_notify_state_change(struct m
 	struct master_mapent *entry;
 	struct autofs_point *ap;
 	struct list_head *p;
-	enum states next = ST_INVAL;
 	int state_pipe;
 	int status;
 
-	status = pthread_mutex_lock(&master_mutex);
-	if (status)
-		fatal(status);
+	master_mutex_lock();
 
 	list_for_each(p, &master->mounts) {
+		enum states next = ST_INVAL;
+
 		entry = list_entry(p, struct master_mapent, list);
 
 		ap = entry->ap;
 
-		if (ap->state == ST_INVAL)
-			return;
+		state_mutex_lock(ap);
 
-		status = pthread_mutex_lock(&ap->state_mutex);
+		if (ap->state == ST_SHUTDOWN)
+			goto next;
 
 		state_pipe = ap->state_pipe[1];
 
 		switch (sig) {
 		case SIGTERM:
 			if (ap->state != ST_SHUTDOWN &&
-			    ap->state != ST_SHUTDOWN_PENDING) {
+			    ap->state != ST_SHUTDOWN_PENDING &&
+			    ap->state != ST_SHUTDOWN_FORCE) {
 				next = ST_SHUTDOWN_PENDING;
-				notify_submounts(ap, next);
 				nextstate(state_pipe, next);
 			}
 			break;
 #ifdef ENABLE_FORCED_SHUTDOWN
 		case SIGUSR2:
 			if (ap->state != ST_SHUTDOWN &&
-			    ap->state != ST_SHUTDOWN_FORCE) {
+			    ap->state != ST_SHUTDOWN_FORCE &&
+			    ap->state != ST_SHUTDOWN_PENDING) {
 				next = ST_SHUTDOWN_FORCE;
-				notify_submounts(ap, next);
 				nextstate(state_pipe, next);
 			}
 			break;
@@ -866,14 +866,11 @@ #endif
 		case SIGUSR1:
 			assert(ap->state == ST_READY);
 			next = ST_PRUNE;
-			notify_submounts(ap, next);
 			nextstate(state_pipe, next);
 			break;
 		}
-
-		status = pthread_mutex_unlock(&ap->state_mutex);
-		if (status)
-			fatal(status);
+next:
+		state_mutex_unlock(ap);
 
 		if (next != ST_INVAL)
 			debug(ap->logopt,
@@ -881,9 +878,7 @@ #endif
 			      sig, ap->path, ap->state, next);
 	}
 
-	status = pthread_mutex_unlock(&master_mutex);
-	if (status)
-		fatal(status);
+	master_mutex_unlock();
 
 	return;
 }
@@ -946,11 +941,9 @@ static void shutdown_entry(struct master
 
 	ap = entry->ap;
 
-	debug(ap->logopt, "shutting down %s", entry->path);
+	debug(ap->logopt, "%s", entry->path);
 
-	status = pthread_mutex_lock(&ap->state_mutex);
-	if (status)
-		fatal(status);
+	state_mutex_lock(ap);
 
 	state_pipe = ap->state_pipe[1];
 
@@ -958,12 +951,9 @@ static void shutdown_entry(struct master
 	if (ret == -1)
 		goto next;
 
-	notify_submounts(ap, ST_SHUTDOWN_PENDING);
 	nextstate(state_pipe, ST_SHUTDOWN_PENDING);
 next:
-	status = pthread_mutex_unlock(&ap->state_mutex);
-	if (status)
-		fatal(status);
+	state_mutex_unlock(ap);
 
 	return;
 }
@@ -1030,9 +1020,7 @@ static void check_update_map_sources(str
 
 	/* The map sources have changed */
 	if (map_stale) {
-		status = pthread_mutex_lock(&ap->state_mutex);
-		if (status)
-			fatal(status);
+		state_mutex_lock(ap);
 
 		state_pipe = entry->ap->state_pipe[1];
 
@@ -1040,9 +1028,7 @@ static void check_update_map_sources(str
 		if (ret != -1)
 			nextstate(state_pipe, ST_READMAP);
 
-		status = pthread_mutex_unlock(&ap->state_mutex);
-		if (status)
-			fatal(status);
+		state_mutex_unlock(ap);
 	}
 
 	return;
@@ -1053,9 +1039,7 @@ int master_mount_mounts(struct master *m
 	struct list_head *p, *head;
 	int status;
 
-	status = pthread_mutex_lock(&master_mutex);
-	if (status)
-		fatal(status);
+	master_mutex_lock();
 
 	head = &master->mounts;
 	p = head->next;
@@ -1079,9 +1063,7 @@ int master_mount_mounts(struct master *m
 
 		check_update_map_sources(this, readall);
 
-		status = pthread_mutex_lock(&ap->state_mutex);
-		if (status)
-			fatal(status);
+		state_mutex_lock(ap);
 
 		state_pipe = this->ap->state_pipe[1];
 
@@ -1089,9 +1071,7 @@ int master_mount_mounts(struct master *m
 		ret = fstat(state_pipe, &st);
 		save_errno = errno;
 
-		status = pthread_mutex_unlock(&ap->state_mutex);
-		if (status)
-			fatal(status);
+		state_mutex_unlock(ap);
 
 		if (ret == -1 && save_errno == EBADF)
 			if (!master_do_mount(this)) {
@@ -1101,9 +1081,7 @@ int master_mount_mounts(struct master *m
 		}
 	}
 
-	status = pthread_mutex_unlock(&master_mutex);
-	if (status)
-		fatal(status);
+	master_mutex_unlock();
 
 	return 1;
 }
@@ -1113,16 +1091,12 @@ int master_list_empty(struct master *mas
 	int status;
 	int res = 0;
 
-	status = pthread_mutex_lock(&master_mutex);
-	if (status)
-		fatal(status);
+	master_mutex_lock();
 
 	if (list_empty(&master->mounts))
 		res = 1;
 
-	status = pthread_mutex_unlock(&master_mutex);
-	if (status)
-		fatal(status);
+	master_mutex_unlock();
 
 	return res;
 }
diff --git a/lib/parse_subs.c b/lib/parse_subs.c
index ab5de39..5847eb0 100644
--- a/lib/parse_subs.c
+++ b/lib/parse_subs.c
@@ -16,7 +16,7 @@
  * ----------------------------------------------------------------------- */
 
 #include <stdlib.h>
-#include "log.h"
+#include "automount.h"
 
 /*
  * Skip whitespace in a string; if we hit a #, consider the rest of the
@@ -153,9 +153,11 @@ char *dequote(const char *str, int origl
 				continue;
 			}
 
-			if (*scp == '\\') {
-				quote = 1;
-				continue;
+			if (!dquote) {
+				if (*scp == '\\') {
+					quote = 1;
+					continue;
+				}
 			}
 		}
 		quote = 0;
@@ -172,28 +174,76 @@ char *dequote(const char *str, int origl
 	return ret;
 }
 
-char *sanitize_path(const char *path, int origlen)
+int span_space(const char *str, unsigned int maxlen)
 {
-	char *ret = malloc(origlen + 1);
-	char *cp = ret;
+	const char *p = str;
+	unsigned int len = 0;
+
+	while (!isblank(*(p++)) && len++ < maxlen) {
+		if (*p == '\\') {
+			p += 2;
+			len += 2;
+		}
+	}
+	return len;
+}
+
+char *sanitize_path(const char *path, int origlen, unsigned int type, unsigned int logopt)
+{
+	char *slash, *cp, *s_path;
 	const char *scp;
 	int len = origlen;
-	unsigned int seen_slash = 0, quote = 0;
+	unsigned int seen_slash = 0, quote = 0, dquote = 0;
 
-	if (ret == NULL)
+	if (type & (LKP_INDIRECT | LKP_DIRECT)) {
+		slash = strchr(path, '/');
+		if (slash) {
+			if (type == LKP_INDIRECT)
+				return NULL;
+			if (*path != '/')
+				return NULL;
+		} else {
+			if (type == LKP_DIRECT)
+				return NULL;
+		}
+	}
+
+	s_path = malloc(origlen + 1);
+	if (!s_path)
 		return NULL;
 
-	for (scp = path; len > 0 && *scp; scp++, len--) {
+	for (cp = s_path, scp = path; len > 0; scp++, len--) {
 		if (!quote) {
-			if (*scp == '\\') {
-				quote = 1;
+			if (*scp == '"') {
+				if (dquote)
+					dquote = 0;
+				else
+					dquote = 1;
 				continue;
 			}
 
+			if (!dquote) {
+				/* Badness in string - go away */
+				if (*scp < 32) {
+					free(s_path);
+					return NULL;
+				}
+
+				if (*scp == '\\') {
+					quote = 1;
+					continue;
+				} 
+			}
+
+			/*
+			 * Not really proper but we get problems with
+			 * paths with multiple slashes. The kernel
+			 * compresses them so when we get a query there
+			 * should be only single slashes.
+			 */
 			if (*scp == '/') {
 				if (seen_slash)
 					continue;
-
 				seen_slash = 1;
 			} else
 				seen_slash = 0;
@@ -203,9 +253,15 @@ char *sanitize_path(const char *path, in
 	}
 	*cp = '\0';
 
+	if (dquote) {
+		debug(logopt, "unmatched quote in %.*s", origlen, path);
+		free(s_path);
+		return NULL;
+	}
+
 	if (origlen > 1 && *(cp - 1) == '/')
 		*(cp - 1) = '\0';
 
-	return ret;
+	return s_path;
 }
 
diff --git a/modules/lookup_file.c b/modules/lookup_file.c
index 81ade74..1a3ee13 100644
--- a/modules/lookup_file.c
+++ b/modules/lookup_file.c
@@ -113,7 +113,7 @@ int lookup_init(const char *mapfmt, int 
 	return 0;
 }
 
-static int read_one(FILE *f, char *key, char *mapent)
+static int read_one(FILE *f, char *key, unsigned *k_len, char *mapent, unsigned *m_len)
 {
 	char *kptr, *p;
 	int mapent_len, key_len;
@@ -228,11 +228,25 @@ static int read_one(FILE *f, char *key, 
 			if (ch == '\n')
 				state = st_begin;
 			else if (!isspace(ch) || escape) {
+				if (escape) {
+					if (escape == esc_char)
+						break;
+					if (ch <= 32) {
+						getting = got_nothing;
+						state = st_badent;
+						break;
+					}
+					p = mapent;
+					*(p++) = '\\';
+					*(p++) = ch;
+					mapent_len = 2;
+				} else {
+					p = mapent;
+					*(p++) = ch;
+					mapent_len = 1;
+				}
 				state = st_getent;
-				p = mapent;
 				gotten = getting;
-				*(p++) = ch;
-				mapent_len = 1;
 			}
 			break;
 
@@ -240,8 +254,8 @@ static int read_one(FILE *f, char *key, 
 			if (ch == '\n') {
 				nch = getc(f);
 				if (nch != EOF && isblank(nch)) {
-					state = st_badent;
 					ungetc(nch, f);
+					state = st_badent;
 					gotten = got_nothing;
 					warn(LOGOPT_ANY, MODPREFIX 
 					      "bad map entry \"%s...\" for key "
@@ -276,6 +290,9 @@ static int read_one(FILE *f, char *key, 
 		if (gotten == got_nothing)
 			goto next;
 
+		*k_len = key_len;
+		*m_len = mapent_len;
+
 		return 1;
 
 	      next:
@@ -329,7 +346,7 @@ int lookup_read_master(struct master *ma
 	char *ent;
 	struct stat st;
 	FILE *f;
-	int entry;
+	int entry, path_len, ent_len;
 
 	if (master->recurse)
 		return NSS_STATUS_UNAVAIL;
@@ -368,7 +385,7 @@ int lookup_read_master(struct master *ma
 
 	master_init_scan();
 	while(1) {
-		entry = read_one(f, path, ent);
+		entry = read_one(f, path, &path_len, ent, &ent_len);
 		if (!entry) {
 			if (feof(f))
 				break;
@@ -404,7 +421,7 @@ int lookup_read_master(struct master *ma
 
 			master->name = save_name;
 		} else {
-			blen = strlen(path) + 1 + strlen(ent) + 1;
+			blen = path_len + 1 + ent_len + 1;
 			buffer = malloc(blen);
 			if (!buffer) {
 				error(LOGOPT_ANY,
@@ -576,7 +593,7 @@ int lookup_read_map(struct autofs_point 
 	char *mapent;
 	struct stat st;
 	FILE *f;
-	int entry;
+	int entry, k_len, m_len;
 
 	source = ap->entry->current;
 	ap->entry->current = NULL;
@@ -618,7 +635,7 @@ int lookup_read_map(struct autofs_point 
 	}
 
 	while(1) {
-		entry = read_one(f, key, mapent);
+		entry = read_one(f, key, &k_len, mapent, &m_len);
 		if (!entry) {
 			if (feof(f))
 				break;
@@ -657,36 +674,17 @@ int lookup_read_map(struct autofs_point 
 			master_free_mapent_sources(iap->entry, 0);
 			master_free_mapent(iap->entry);
 		} else {
-			char *dq_key, *dq_mapent; 
-
-			dq_key = dequote(key, strlen(key), ap->logopt);
-			if (!dq_key)
-				continue;
+			char *s_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);
+			s_key = sanitize_path(key, k_len, ap->type, ap->logopt);
+			if (!s_key)
 				continue;
-			}
 
 			cache_writelock(mc);
-			cache_update(mc, source, dq_key, dq_mapent, age);
+			cache_update(mc, source, s_key, mapent, age);
 			cache_unlock(mc);
 
-			free(dq_key);
-			free(dq_mapent);
+			free(s_key);
 		}
 
 		if (feof(f))
@@ -702,6 +700,7 @@ int lookup_read_map(struct autofs_point 
 		return NSS_STATUS_UNAVAIL;
 	}
 	ctxt->mtime = st.st_mtime;
+	source->age = age;
 
 	fclose(f);
 
@@ -721,7 +720,7 @@ static int lookup_one(struct autofs_poin
 	char mapent[MAPENT_MAX_LEN + 1];
 	time_t age = time(NULL);
 	FILE *f;
-	int entry, ret;
+	int entry, ret, k_len, m_len;
 
 	source = ap->entry->current;
 	ap->entry->current = NULL;
@@ -737,7 +736,7 @@ static int lookup_one(struct autofs_poin
 	}
 
 	while(1) {
-		entry = read_one(f, mkey, mapent);
+		entry = read_one(f, mkey, &k_len, mapent, &m_len);
 		if (entry) {
 			/*
 			 * If key starts with '+' it has to be an
@@ -773,11 +772,30 @@ static int lookup_one(struct autofs_poin
 
 				if (status)
 					return CHE_COMPLETED;
-			} else if (strncmp(mkey, key, key_len) == 0) {
+			} else {
+				char *s_key; 
+				int eq;
+
+				s_key = sanitize_path(mkey, k_len, ap->type, ap->logopt);
+				if (!s_key)
+					continue;
+
+				if (key_len != strlen(s_key)) {
+					free(s_key);
+					continue;
+				}
+
+				eq = strncmp(s_key, key, key_len);
+				if (eq != 0)
+					continue;
+
+				free(s_key);
+
 				fclose(f);
 				cache_writelock(mc);
 				ret = cache_update(mc, source, key, mapent, age);
 				cache_unlock(mc);
+
 				return ret;
 			}
 		}
@@ -799,7 +817,7 @@ static int lookup_wild(struct autofs_poi
 	char mapent[MAPENT_MAX_LEN + 1];
 	time_t age = time(NULL);
 	FILE *f;
-	int entry, ret;
+	int entry, ret, k_len, m_len;
 
 	source = ap->entry->current;
 	ap->entry->current = NULL;
@@ -815,7 +833,7 @@ static int lookup_wild(struct autofs_poi
 	}
 
 	while(1) {
-		entry = read_one(f, mkey, mapent);
+		entry = read_one(f, mkey, &k_len, mapent, &m_len);
 		if (entry) {
 			/*
 			 * If key starts with '+' it has to be an
@@ -848,7 +866,13 @@ static int lookup_wild(struct autofs_poi
 
 				if (status)
 					return CHE_COMPLETED;
-			} else if (strncmp(mkey, "*", 1) == 0) {
+			} else {
+				int eq;
+
+				eq = (*mkey == '*' && k_len == 1);
+				if (eq == 0)
+					continue;
+
 				fclose(f);
 				cache_writelock(mc);
 				ret = cache_update(mc, source, "*", mapent, age);
@@ -1029,7 +1053,7 @@ int lookup_mount(struct autofs_point *ap
 
 	cache_readlock(mc);
 	me = cache_lookup(mc, key);
-	if (me) {
+	if (me && me->mapent) {
 		pthread_cleanup_push(cache_lock_cleanup, mc);
 		mapent_len = strlen(me->mapent);
 		mapent = alloca(mapent_len + 1);
diff --git a/modules/lookup_hosts.c b/modules/lookup_hosts.c
index 16fd1bd..7255794 100644
--- a/modules/lookup_hosts.c
+++ b/modules/lookup_hosts.c
@@ -107,6 +107,8 @@ int lookup_read_map(struct autofs_point 
 	if (status)
 		error(LOGOPT_ANY, MODPREFIX "failed to unlock hostent mutex");
 
+	source->age = age;
+
 	return NSS_STATUS_SUCCESS;
 }
 
diff --git a/modules/lookup_ldap.c b/modules/lookup_ldap.c
index 0bcd249..8c627b4 100644
--- a/modules/lookup_ldap.c
+++ b/modules/lookup_ldap.c
@@ -1078,8 +1078,8 @@ static int read_one_map(struct autofs_po
 	char *query;
 	LDAPMessage *result, *e;
 	char *class, *info, *entry;
-	char **keyValue = NULL;
-	char **values = NULL;
+	struct berval **bvKey;
+	struct berval **bvValues;
 	char *attrs[3];
 	int scope = LDAP_SCOPE_SUBTREE;
 	LDAP *ldap;
@@ -1146,11 +1146,14 @@ static int read_one_map(struct autofs_po
 
 	while (e) {
 		char *mapent = NULL;
-		char *dq_key, *dq_mapent;
+		char *k_val;
+		ber_len_t k_len;
+		size_t mapent_len;
+		char *s_key;
 
-		keyValue = ldap_get_values(ldap, e, entry);
+		bvKey = ldap_get_values_len(ldap, e, entry);
 
-		if (!keyValue || !*keyValue) {
+		if (!bvKey || !*bvKey) {
 			e = ldap_next_entry(ldap, e);
 			continue;
 		}
@@ -1159,27 +1162,30 @@ static int read_one_map(struct autofs_po
 		 * By definition keys must be unique within
 		 * each map entry
 		 */
-		if (ldap_count_values(keyValue) > 1) {
+		if (ldap_count_values_len(bvKey) > 1) {
 			error(ap->logopt,
 			      MODPREFIX
-			      "key %s has duplicate entries - ignoring",
-			      *keyValue);
+			      "key %.*s has duplicate entries - ignoring",
+			      bvKey[0]->bv_len, bvKey[0]->bv_val);
 			goto next;
 		}
 
+		k_val = bvKey[0]->bv_val;
+		k_len = bvKey[0]->bv_len;
+
 		/*
 		 * Ignore keys beginning with '+' as plus map
 		 * inclusion is only valid in file maps.
 		 */
-		if (**keyValue == '+') {
+		if (*k_val == '+') {
 			warn(ap->logopt,
 			     MODPREFIX
 			     "ignoreing '+' map entry - not in file map");
 			goto next;
 		}
 
-		values = ldap_get_values(ldap, e, info);
-		if (!values || !*values) {
+		bvValues = ldap_get_values_len(ldap, e, info);
+		if (!bvValues || !*bvValues) {
 			debug(ap->logopt,
 			      MODPREFIX "no %s defined for %s", info, query);
 			goto next;
@@ -1196,9 +1202,10 @@ static int read_one_map(struct autofs_po
 		 * how to force an ordering.
 		 * 
 		 */
-		count = ldap_count_values(values);
+		count = ldap_count_values_len(bvValues);
 		for (i = 0; i < count; i++) {
-			int v_len = strlen(values[i]);
+			char *v_val = bvValues[i]->bv_val;
+			ber_len_t v_len = bvValues[i]->bv_len;
 
 			if (!mapent) {
 				mapent = malloc(v_len + 1);
@@ -1207,17 +1214,22 @@ static int read_one_map(struct autofs_po
 					estr = strerror_r(errno, buf, MAX_ERR_BUF);
 					error(ap->logopt,
 					      MODPREFIX "malloc: %s", estr);
+					ldap_value_free_len(bvValues);
 					goto next;
 				}
-				strcpy(mapent, values[i]);
+				strncpy(mapent, v_val, v_len);
+				mapent[v_len] = '\0';
+				mapent_len = v_len;
 			} else {
-				int new_size = strlen(mapent) + v_len + 2;
+				int new_size = mapent_len + v_len + 2;
 				char *new_me;
 				new_me = realloc(mapent, new_size);
 				if (new_me) {
 					mapent = new_me;
 					strcat(mapent, " ");
-					strcat(mapent, values[i]);
+					strncat(mapent, v_val, v_len);
+					mapent[new_size] = '\0';
+					mapent_len = new_size;
 				} else {
 					char *estr;
 					estr = strerror_r(errno, buf, MAX_ERR_BUF);
@@ -1226,46 +1238,30 @@ static int read_one_map(struct autofs_po
 				}
 			}
 		}
-		ldap_value_free(values);
+		ldap_value_free_len(bvValues);
 
-		dq_key = dequote(*keyValue, strlen(*keyValue), ap->logopt);
-		if (!dq_key)
-			goto next;
-
-		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);
+		if (*k_val == '/' && k_len == 1) {
+			if (ap->type == LKP_DIRECT)
 				goto next;
-			}
+			*k_val = '*';
 		}
 
-		dq_mapent = dequote(mapent, strlen(mapent), ap->logopt);
-		if (!mapent) {
-			free(dq_key);
+		s_key = sanitize_path(k_val, k_len, ap->type, ap->logopt);
+		if (!s_key)
 			goto next;
-		}
 
 		cache_writelock(mc);
-		cache_update(mc, source, dq_key, dq_mapent, age);
+		cache_update(mc, source, s_key, mapent, age);
 		cache_unlock(mc);
 
-		free(dq_key);
-		free(dq_mapent);
+		free(s_key);
 next:
 		if (mapent) {
 			free(mapent);
 			mapent = NULL;
 		}
 
-		ldap_value_free(keyValue);
+		ldap_value_free_len(bvKey);
 		e = ldap_next_entry(ldap, e);
 	}
 
@@ -1275,6 +1271,8 @@ next:
 	ldap_msgfree(result);
 	unbind_ldap_connection(ldap, ctxt);
 
+	source->age = age;
+
 	return NSS_STATUS_SUCCESS;
 }
 
@@ -1307,12 +1305,11 @@ static int lookup_one(struct autofs_poin
 	char *query;
 	LDAPMessage *result, *e;
 	char *class, *info, *entry;
-	char **keyValue;
-	char **values = NULL;
+	struct berval **bvKey;
+	struct berval **bvValues;
 	char *attrs[3];
 	int scope = LDAP_SCOPE_SUBTREE;
 	LDAP *ldap;
-	char *mapent = NULL;
 	unsigned int wild = 0;
 	int ret = CHE_MISSING;
 
@@ -1390,34 +1387,43 @@ static int lookup_one(struct autofs_poin
 	}
 
 	while (e) {
-		keyValue = ldap_get_values(ldap, e, entry);
+		char *mapent = NULL;
+		char *k_val;
+		ber_len_t k_len;
+		char *s_key;
+		size_t mapent_len;
 
-		if (!keyValue || !*keyValue) {
+		bvKey = ldap_get_values_len(ldap, e, entry);
+		if (!bvKey || !*bvKey) {
 			e = ldap_next_entry(ldap, e);
 			continue;
 		}
 
 		/* By definition keys must be unique within each map entry */
-		if (ldap_count_values(keyValue) > 1) {
+		if (ldap_count_values_len(bvKey) > 1) {
 			error(ap->logopt,
-			      MODPREFIX "key %s has duplicate entries",
-			      *keyValue);
+			      MODPREFIX "key %.*s has duplicate entries",
+			      bvKey[0]->bv_len, bvKey[0]->bv_val);
 			ret = CHE_FAIL;
 			goto next;
 		}
 
 		debug(ap->logopt, MODPREFIX "examining first entry");
 
-		values = ldap_get_values(ldap, e, info);
-		if (!values || !*values) {
+		k_val = bvKey[0]->bv_val;
+		k_len = bvKey[0]->bv_len;
+
+		bvValues = ldap_get_values_len(ldap, e, info);
+		if (!bvValues || !*bvValues) {
 			debug(ap->logopt,
 			      MODPREFIX "no %s defined for %s", info, query);
 			goto next;
 		}
 
-		count = ldap_count_values(values);
+		count = ldap_count_values_len(bvValues);
 		for (i = 0; i < count; i++) {
-			int v_len = strlen(values[i]);
+			char *v_val = bvValues[i]->bv_val;
+			ber_len_t v_len = bvValues[i]->bv_len;
 
 			if (!mapent) {
 				mapent = malloc(v_len + 1);
@@ -1426,17 +1432,22 @@ static int lookup_one(struct autofs_poin
 					estr = strerror_r(errno, buf, MAX_ERR_BUF);
 					error(ap->logopt,
 					      MODPREFIX "malloc: %s", estr);
-					continue;
+					ldap_value_free_len(bvValues);
+					goto next;
 				}
-				strcpy(mapent, values[i]);
+				strncpy(mapent, v_val, v_len);
+				mapent[v_len] = '\0';
+				mapent_len = v_len;
 			} else {
-				int new_size = strlen(mapent) + v_len + 2;
+				int new_size = mapent_len + v_len + 2;
 				char *new_me;
 				new_me = realloc(mapent, new_size);
 				if (new_me) {
 					mapent = new_me;
 					strcat(mapent, " ");
-					strcat(mapent, values[i]);
+					strncat(mapent, v_val, v_len);
+					mapent[new_size] = '\0';
+					mapent_len = new_size;
 				} else {
 					char *estr;
 					estr = strerror_r(errno, buf, MAX_ERR_BUF);
@@ -1445,35 +1456,34 @@ static int lookup_one(struct autofs_poin
 				}
 			}
 		}
-		ldap_value_free(values);
-
-		if (**keyValue == '/') {
-			if (ap->type == LKP_INDIRECT) {
-				if (strlen(*keyValue) == 1) {
-					wild = 1;
-					**keyValue = '*';
-					cache_writelock(mc);
-					cache_update(mc,
-						source, *keyValue, mapent, age);
-					cache_unlock(mc);
-				}
-				goto next;
-			}
-		} else {
+		ldap_value_free_len(bvValues);
+
+		if (*k_val == '/' && k_len == 1) {
 			if (ap->type == LKP_DIRECT)
 				goto next;
+			wild = 1;
+			cache_writelock(mc);
+			cache_update(mc, source, "*", mapent, age);
+			cache_unlock(mc);
+			goto next;
 		}
 
+		s_key = sanitize_path(k_val, k_len, ap->type, ap->logopt);
+		if (!s_key)
+			goto next;
+
 		cache_writelock(mc);
-		ret = cache_update(mc, source, *keyValue, mapent, age);
+		ret = cache_update(mc, source, s_key, mapent, age);
 		cache_unlock(mc);
+
+		free(s_key);
 next:
 		if (mapent) {
 			free(mapent);
 			mapent = NULL;
 		}
 
-		ldap_value_free(keyValue);
+		ldap_value_free_len(bvKey);
 		e = ldap_next_entry(ldap, e);
 	}
 
diff --git a/modules/lookup_nisplus.c b/modules/lookup_nisplus.c
index 4bc8820..4ea7609 100644
--- a/modules/lookup_nisplus.c
+++ b/modules/lookup_nisplus.c
@@ -202,10 +202,13 @@ int lookup_read_map(struct autofs_point 
 	result_count = NIS_RES_NUMOBJ(result);
 
 	while (result_count--) {
-		char *dq_key, *dq_mapent;
+		char *s_key;
+		size_t len;
 
 		this = &result->objects.objects_val[current++];
 		key = ENTRY_VAL(this, 0);
+		len = ENTRY_LEN(this, 0);
+
 		/*
 		 * Ignore keys beginning with '+' as plus map
 		 * inclusion is only valid in file maps.
@@ -213,39 +216,23 @@ int lookup_read_map(struct autofs_point 
 		if (*key == '+')
 			continue;
 
-		dq_key = dequote(key, ENTRY_LEN(this, 0), ap->logopt);
-		if (!dq_key)
+		s_key = sanitize_path(key, len, ap->type, ap->logopt);
+		if (!s_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, dq_key, dq_mapent, age);
+		cache_update(mc, source, s_key, mapent, age);
 		cache_unlock(mc);
 
-		free(dq_key);
-		free(dq_mapent);
+		free(s_key);
 	}
 
 	nis_freeresult(result);
 
+	source->age = age;
+
 	return NSS_STATUS_SUCCESS;
 }
 
diff --git a/modules/lookup_yp.c b/modules/lookup_yp.c
index fcee26b..dec4a21 100644
--- a/modules/lookup_yp.c
+++ b/modules/lookup_yp.c
@@ -248,7 +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, *mapent;
+	char *tmp, *key, *mapent;
 	int ret;
 
 	if (status != YP_TRUE)
@@ -261,34 +261,19 @@ int yp_all_callback(int status, char *yp
 	if (*ypkey == '+')
 		return 0;
 
-	key = dequote(ypkey, ypkeylen, ap->logopt);
+	key = sanitize_path(ypkey, ypkeylen, ap->type, ap->logopt);
 	if (!key)
 		return 0;
 
-	if (*key == '/') {
-		if (ap->type == LKP_INDIRECT) {
-			free(key);
-			return 0;
-		}
-	} else {
-		if (ap->type == LKP_DIRECT) {
-			free(key);
-			return 0;
-		}
-	}
-
-	mapent = dequote(val, vallen, ap->logopt);
-	if (!mapent) {
-		free(key);
-		return 0;
-	}
+	mapent = alloca(vallen + 1);
+	strncpy(mapent, val, vallen);
+	*(mapent + vallen) = '\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;
@@ -301,16 +286,18 @@ int lookup_read_map(struct autofs_point 
 	struct lookup_context *ctxt = (struct lookup_context *) context;
 	struct ypall_callback ypcb;
 	struct callback_data ypcb_data;
+	struct map_source *source;
 	char *mapname;
 	int err;
 
-	ypcb_data.ap = ap;
-	ypcb_data.source = ap->entry->current;
-	ypcb_data.age = age;
-
+	source = ap->entry->current;
 	ap->entry->current = NULL;
 	master_source_current_signal(ap->entry);
 
+	ypcb_data.ap = ap;
+	ypcb_data.source = source;
+	ypcb_data.age = age;
+
 	ypcb.foreach = yp_all_callback;
 	ypcb.data = (char *) &ypcb_data;
 
@@ -342,6 +329,8 @@ int lookup_read_map(struct autofs_point 
 		return NSS_STATUS_NOTFOUND;
 	}
 
+	source->age = age;
+
 	return NSS_STATUS_SUCCESS;
 }
 
diff --git a/modules/mount_autofs.c b/modules/mount_autofs.c
index 768bcbf..95fe00d 100644
--- a/modules/mount_autofs.c
+++ b/modules/mount_autofs.c
@@ -58,28 +58,26 @@ int mount_mount(struct autofs_point *ap,
 	struct autofs_point *nap;
 	char buf[MAX_ERR_BUF];
 	char *options, *p;
-	int ret, rlen;
+	int ret;
+	struct list_head *l;
 
-	/* Root offset of multi-mount */
-	if (*name == '/' && name_len == 1) {
-		rlen = strlen(root);
-		name_len = 0;
-	} else if (*name == '/')
-		rlen = 0;
-	else
-		rlen = strlen(root);
-
-	fullpath = alloca(rlen + name_len + 2);
+	fullpath = alloca(strlen(root) + name_len + 2);
 	if (!fullpath) {
 		char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
 		error(ap->logopt, MODPREFIX "alloca: %s", estr);
 		return 1;
 	}
 
-	if (rlen)
-		sprintf(fullpath, "%s/%s", root, name);
-	else
-		sprintf(fullpath, "%s", name);
+	/* Root offset of multi-mount */
+	if (*name == '/' && name_len == 1)
+		strcpy(fullpath, root);
+	else if (*name == '/')
+		strcpy(fullpath, name);
+	else {
+		strcpy(fullpath, root);
+		strcat(fullpath, "/");
+		strcat(fullpath, name);
+	}
 
 	if (is_mounted(_PATH_MOUNTED, fullpath, MNTS_REAL)) {
 		error(ap->logopt,
@@ -201,14 +199,14 @@ int mount_mount(struct autofs_point *ap,
 	suc.done = 0;
 	suc.status = 0;
 
-	pthread_mutex_lock(&ap->mounts_mutex);
+	mounts_mutex_lock(ap);
 
 	if (pthread_create(&thid, &thread_attr, handle_mounts, nap)) {
 		crit(ap->logopt,
 		     MODPREFIX
 		     "failed to create mount handler thread for %s",
 		     fullpath);
-		pthread_mutex_unlock(&ap->mounts_mutex);
+		mounts_mutex_unlock(ap);
 		status = pthread_mutex_unlock(&suc.mutex);
 		if (status)
 			fatal(status);
@@ -221,7 +219,7 @@ int mount_mount(struct autofs_point *ap,
 	while (!suc.done) {
 		status = pthread_cond_wait(&suc.cond, &suc.mutex);
 		if (status) {
-			pthread_mutex_unlock(&ap->mounts_mutex);
+			mounts_mutex_unlock(ap);
 			pthread_mutex_unlock(&suc.mutex);
 			fatal(status);
 		}
@@ -230,17 +228,18 @@ int mount_mount(struct autofs_point *ap,
 	if (suc.status) {
 		crit(ap->logopt,
 		     MODPREFIX "failed to create submount for %s", fullpath);
-		pthread_mutex_unlock(&ap->mounts_mutex);
+		mounts_mutex_unlock(ap);
 		status = pthread_mutex_unlock(&suc.mutex);
 		if (status)
 			fatal(status);
+		master_free_mapent(entry);
 		return 1;
 	}
 
 	ap->submnt_count++;
 	list_add(&nap->mounts, &ap->submounts);
 
-	pthread_mutex_unlock(&ap->mounts_mutex);
+	mounts_mutex_unlock(ap);
 
 	status = pthread_mutex_unlock(&suc.mutex);
 	if (status)
diff --git a/modules/parse_sun.c b/modules/parse_sun.c
index 50f086d..c6dffef 100644
--- a/modules/parse_sun.c
+++ b/modules/parse_sun.c
@@ -807,7 +807,7 @@ static int parse_mapent(const char *ent,
 	l = chunklen(p, check_colon(p));
 	loc = dequote(p, l, logopt);
 	if (!loc) {
-		error(logopt, MODPREFIX "out of memory");
+		warn(logopt, MODPREFIX "possible missing location");
 		free(myoptions);
 		return 0;
 	}
@@ -1039,45 +1039,32 @@ int parse_mount(struct autofs_point *ap,
 
 		/* It's a multi-mount; deal with it */
 		do {
-			char *tmp, *path, *myoptions, *loc;
+			char *path, *myoptions, *loc;
+			unsigned int s_len = 0;
 			int status;
 
 			if (*p != '/') {
 				l = 0;
-				tmp = dequote("/", 1, ap->logopt);
+				path = dequote("/", 1, ap->logopt);
 				debug(ap->logopt,
-				      MODPREFIX "dequote(\"/\") -> %s", tmp);
+				      MODPREFIX "dequote(\"/\") -> %s", path);
 			} else {
-				l = chunklen(p, 0);
-				tmp = dequote(p, l, ap->logopt);
+				l = span_space(p, mapent_len - (p - pmapent));
+				path = sanitize_path(p, l, LKP_MULTI, ap->logopt);
 				debug(ap->logopt, MODPREFIX
-				      "dequote(\"%.*s\") -> %s", l, p, tmp);
+				      "dequote(\"%.*s\") -> %s", l, p, path);
 			}
 
-			if (!tmp) {
-				error(ap->logopt, MODPREFIX "out of memory");
-				cache_readlock(mc);
-				cache_multi_lock(mc);
-				cache_delete_offset_list(mc, name);
-				cache_multi_unlock(mc);
-				cache_unlock(mc);
-				free(options);
-				return 1;
-			}
-
-			path = sanitize_path(tmp, strlen(tmp));
 			if (!path) {
-				warn(ap->logopt, MODPREFIX "invalid path");
+				error(ap->logopt, MODPREFIX "out of memory");
 				cache_readlock(mc);
 				cache_multi_lock(mc);
 				cache_delete_offset_list(mc, name);
 				cache_multi_unlock(mc);
 				cache_unlock(mc);
-				free(tmp);
 				free(options);
 				return 1;
 			}
-			free(tmp);
 
 			p += l;
 			p = skipspace(p);