rpms/autofs/F-8 autofs-5.0.2-handle-zero-length-nis-key-update.patch, NONE, 1.1 autofs-5.0.3-add-missing-uris-list-locking.patch, NONE, 1.1 autofs-5.0.3-add-replicated-debug-logging.patch, NONE, 1.1 autofs-5.0.3-add-umount_wait-parameter.patch, NONE, 1.1 autofs-5.0.3-allow-dir-create-on-nfs-root.patch, NONE, 1.1 autofs-5.0.3-check-direct-path-len.patch, NONE, 1.1 autofs-5.0.3-check-for-kernel-automount-fix.patch, NONE, 1.1 autofs-5.0.3-check-for-kernel-automount.patch, NONE, 1.1 autofs-5.0.3-check-replicated-list-after-probe.patch, NONE, 1.1 autofs-5.0.3-clear-stale-on-map-read.patch, NONE, 1.1 autofs-5.0.3-dont-abuse-ap-ghost-field.patch, NONE, 1.1 autofs-5.0.3-dont-block-on-expire.patch, NONE, 1.1 autofs-5.0.3-dont-readmap-on-hup-for-new-mount.patch, NONE, 1.1 autofs-5.0.3-dont-use-proc-for-is-running-check.patch, NONE, 1.1 autofs-5.0.3-expire-thread-create-cond-handling.patch, NONE, 1.1 autofs-5.0.3-fix-couple-of-memory-leaks.patch, NONE, 1.1 autofs-5.0.3-fix-fd-leak-at-multi-mount-fail.patch, NONE, 1.1 autofs-5.0.3-fix-get-user-info-check.patch, NONE, 1.1 autofs-5.0.3-fix-ifc-buff-size-fix-2.patch, NONE, 1.1 autofs-5.0.3-fix-ifc-buff-size.patch, NONE, 1.1 autofs-5.0.3-fix-included-browse-map-not-found.patch, NONE, 1.1 autofs-5.0.3-fix-incorrect-multi-mount-mountpoint.patch, NONE, 1.1 autofs-5.0.3-fix-multi-mount-race.patch, NONE, 1.1 autofs-5.0.3-fix-multi-source-messages.patch, NONE, 1.1 autofs-5.0.3-fix-nfs4-colon-escape.patch, NONE, 1.1 autofs-5.0.3-fix-percent-hack.patch, NONE, 1.1 autofs-5.0.3-fix-proximity-other-timeout.patch, NONE, 1.1 autofs-5.0.3-fix-rootless-direct-multi-mount-expire.patch, NONE, 1.1 autofs-5.0.3-library-reload-fix.patch, NONE, 1.1 autofs-5.0.3-lookup-next-soucre-stale-entry.patch, NONE, 1.1 autofs-5.0.3-make-handle_mounts-startup-cond-distinct.patch, NONE, 1.1 autofs-5.0.3-map-type-in-map-name-fix.patch, NONE, 1.1 autofs-5.0.3-map-type-in-map-name.patch, NONE, 1.1 autofs-5.0.3-mount-thread-create-cond-handling-fix.patch, NONE, 1.1 autofs-5.0.3-mtab-as-proc-mounts-fix.patch, NONE, 1.1 autofs-5.0.3-mtab-as-proc-mounts.patch, NONE, 1.1 autofs-5.0.3-nisplus-partial-and-free.patch, NONE, 1.1 autofs-5.0.3-nss-source-any.patch, NONE, 1.1 autofs-5.0.3-override-is-running-check.patch, NONE, 1.1 autofs-5.0.3-refactor-mount-request-vars.patch, NONE, 1.1 autofs-5.0.3-remove-redundant-dns-name-lookups.patch, NONE, 1.1 autofs-5.0.3-submount-shutdown-recovery-12-fix.patch, NONE, 1.1 autofs-5.0.3-submount-shutdown-recovery-12.patch, NONE, 1.1 autofs-5.0.3-update-replicated-doco.patch, NONE, 1.1 autofs-5.0.3-use-dev-urandom.patch, NONE, 1.1 autofs-5.0.3-wait-submount-expire-complete.patch, NONE, 1.1 autofs.spec, 1.239, 1.240

Ian Kent iankent at fedoraproject.org
Mon Nov 10 05:30:27 UTC 2008


Author: iankent

Update of /cvs/pkgs/rpms/autofs/F-8
In directory cvs1.fedora.phx.redhat.com:/tmp/cvs-serv30461

Modified Files:
	autofs.spec 
Added Files:
	autofs-5.0.2-handle-zero-length-nis-key-update.patch 
	autofs-5.0.3-add-missing-uris-list-locking.patch 
	autofs-5.0.3-add-replicated-debug-logging.patch 
	autofs-5.0.3-add-umount_wait-parameter.patch 
	autofs-5.0.3-allow-dir-create-on-nfs-root.patch 
	autofs-5.0.3-check-direct-path-len.patch 
	autofs-5.0.3-check-for-kernel-automount-fix.patch 
	autofs-5.0.3-check-for-kernel-automount.patch 
	autofs-5.0.3-check-replicated-list-after-probe.patch 
	autofs-5.0.3-clear-stale-on-map-read.patch 
	autofs-5.0.3-dont-abuse-ap-ghost-field.patch 
	autofs-5.0.3-dont-block-on-expire.patch 
	autofs-5.0.3-dont-readmap-on-hup-for-new-mount.patch 
	autofs-5.0.3-dont-use-proc-for-is-running-check.patch 
	autofs-5.0.3-expire-thread-create-cond-handling.patch 
	autofs-5.0.3-fix-couple-of-memory-leaks.patch 
	autofs-5.0.3-fix-fd-leak-at-multi-mount-fail.patch 
	autofs-5.0.3-fix-get-user-info-check.patch 
	autofs-5.0.3-fix-ifc-buff-size-fix-2.patch 
	autofs-5.0.3-fix-ifc-buff-size.patch 
	autofs-5.0.3-fix-included-browse-map-not-found.patch 
	autofs-5.0.3-fix-incorrect-multi-mount-mountpoint.patch 
	autofs-5.0.3-fix-multi-mount-race.patch 
	autofs-5.0.3-fix-multi-source-messages.patch 
	autofs-5.0.3-fix-nfs4-colon-escape.patch 
	autofs-5.0.3-fix-percent-hack.patch 
	autofs-5.0.3-fix-proximity-other-timeout.patch 
	autofs-5.0.3-fix-rootless-direct-multi-mount-expire.patch 
	autofs-5.0.3-library-reload-fix.patch 
	autofs-5.0.3-lookup-next-soucre-stale-entry.patch 
	autofs-5.0.3-make-handle_mounts-startup-cond-distinct.patch 
	autofs-5.0.3-map-type-in-map-name-fix.patch 
	autofs-5.0.3-map-type-in-map-name.patch 
	autofs-5.0.3-mount-thread-create-cond-handling-fix.patch 
	autofs-5.0.3-mtab-as-proc-mounts-fix.patch 
	autofs-5.0.3-mtab-as-proc-mounts.patch 
	autofs-5.0.3-nisplus-partial-and-free.patch 
	autofs-5.0.3-nss-source-any.patch 
	autofs-5.0.3-override-is-running-check.patch 
	autofs-5.0.3-refactor-mount-request-vars.patch 
	autofs-5.0.3-remove-redundant-dns-name-lookups.patch 
	autofs-5.0.3-submount-shutdown-recovery-12-fix.patch 
	autofs-5.0.3-submount-shutdown-recovery-12.patch 
	autofs-5.0.3-update-replicated-doco.patch 
	autofs-5.0.3-use-dev-urandom.patch 
	autofs-5.0.3-wait-submount-expire-complete.patch 
Log Message:
* Mon Nov 10 2008 Ian Kent <ikent at redhat.com> - 5.0.2-30
- sync. with F-9 bug fixes.
  - fix lexer ambiguity in match when map type name is included in map name.
  - check for nohide mounts.
  - ignore nsswitch sources that aren't supported.
  - don't abuse the ap->ghost field on NFS mount.
  - multi-map doesn't pickup NIS updates automatically.
  - eliminate redundant DNS name lookups.
  - mount thread create condition handling fix.
  - allow directory create on NFS root.
  - check direct mount path length.
  - fix incorrect in check in get user info.
  - fix a couple of memory leaks.
  - don't close file handle for rootless direct mounti-mount at mount.
  - wait submount expire thread completion when expire successful.
  - add inadvertantly ommitted server list locking in LDAP module.
  - add map-type-in-map-name fix patch to sync with upstream and RHEL.
  - don't readmap on HUP for new mount.
  - add NIS_PARTIAL to map entry not found check and fix use after free bug.
  - fix fd leak at multi-mount non-fatal mount fail.
  - fix incorrect multi-mount mountpoint calcualtion.
  - add upstream bug fixes
  - bug fix for mtab check.
  - bug fix for zero length nis key.
  - update for ifc buffer handling.
  - bug fix for kernel automount handling.
  - add command line option to override is running check.
  - don't use proc fs for is running check.
  - fix fail on included browse map not found.
  - fix incorrect multi source messages.
  - clear stale flag on map read.
  - fix proximity other rpc ping timeout.
  - refactor mount request vars code.
  - make handle_mounts startup condition distinct.
  - fix submount shutdown handling.
  - try not to block on expire.
  - add configuration paramter UMOUNT_WAIT.
  - fix multi mount race.
  - fix nfs4 colon escape handling.
  - check replicated list after probe.
  - add replicated server selection debug logging.
  - update replicated server selection documentation.
  - use /dev/urandom instead of /dev/random.
  - check for mtab pointing to /proc/mounts.
  - fix interface config buffer size.
  - fix percent hack heap corruption.
  - fix segv during library re-open.
  - fix incorrect pthreads condition handling for expire requests.


autofs-5.0.2-handle-zero-length-nis-key-update.patch:

--- NEW FILE autofs-5.0.2-handle-zero-length-nis-key-update.patch ---
autofs-5.0.3 - handle zero length nis key update

From: Ian Kent <raven at themaw.net>

A zero length key is invalid but so is a single character
non-printable key and it causes the parser to get confused
as well.
---

 modules/lookup_yp.c |   17 +++++++++++++++++
 1 file changed, 17 insertions(+)


--- autofs-5.0.2.orig/modules/lookup_yp.c
+++ autofs-5.0.2/modules/lookup_yp.c
@@ -19,6 +19,7 @@
 #include <unistd.h>
 #include <time.h>
 #include <signal.h>
+#include <ctype.h>
 #include <sys/param.h>
 #include <sys/types.h>
 #include <sys/stat.h>
@@ -168,6 +169,14 @@ int yp_all_master_callback(int status, c
 	if (status != YP_TRUE)
 		return status;
 
+	/* Ignore zero length and single non-printable char keys */
+	if (ypkeylen == 0 || (ypkeylen == 1 && !isprint(*ypkey))) {
+		warn(logopt, MODPREFIX
+		     "ignoring invalid map entry, zero length or "
+		     "single character non-printable key");
+		return 0;
+	}
+
 	/*
 	 * Ignore keys beginning with '+' as plus map
 	 * inclusion is only valid in file maps.
@@ -263,6 +272,14 @@ int yp_all_callback(int status, char *yp
 	if (status != YP_TRUE)
 		return status;
 
+	/* Ignore zero length and single non-printable char keys */
+	if (ypkeylen == 0 || (ypkeylen == 1 && !isprint(*ypkey))) {
+		warn(logopt, MODPREFIX
+		     "ignoring invalid map entry, zero length or "
+		     "single character non-printable key");
+		return 0;
+	}
+
 	/*
 	 * Ignore keys beginning with '+' as plus map
 	 * inclusion is only valid in file maps.

autofs-5.0.3-add-missing-uris-list-locking.patch:

--- NEW FILE autofs-5.0.3-add-missing-uris-list-locking.patch ---
autofs-5.0.3 - add missing uris list locking

From: Ian Kent <raven at themaw.net>

Add inadvertantly ommitted server list locking in LDAP module.
---

 include/lookup_ldap.h |    1 +
 modules/lookup_ldap.c |   39 ++++++++++++++++++++++++++++++++++++++-
 2 files changed, 39 insertions(+), 1 deletion(-)


--- autofs-5.0.3.orig/include/lookup_ldap.h
+++ autofs-5.0.3/include/lookup_ldap.h
@@ -54,6 +54,7 @@ struct lookup_context {
  	 * sdns is the list of basdns to check, done in the order
  	 * given in configuration.
  	 */
+	pthread_mutex_t uris_mutex;
 	struct list_head *uri;
 	char *cur_host;
 	struct ldap_searchdn *sdns;
--- autofs-5.0.3.orig/modules/lookup_ldap.c
+++ autofs-5.0.3/modules/lookup_ldap.c
@@ -122,6 +122,22 @@ int ldap_parse_page_control(LDAP *ldap, 
 }
 #endif /* HAVE_LDAP_PARSE_PAGE_CONTROL */
 
+static void uris_mutex_lock(struct lookup_context *ctxt)
+{
+	int status = pthread_mutex_lock(&ctxt->uris_mutex);
+	if (status)
+		fatal(status);
+	return;
+}
+
+static void uris_mutex_unlock(struct lookup_context *ctxt)
+{
+	int status = pthread_mutex_unlock(&ctxt->uris_mutex);
+	if (status)
+		fatal(status);
+	return;
+}
+
 int bind_ldap_anonymous(unsigned logopt, LDAP *ldap, struct lookup_context *ctxt)
 {
 	int rv;
@@ -627,16 +643,20 @@ static LDAP *find_server(unsigned logopt
 	LIST_HEAD(tmp);
 
 	/* Try each uri in list, add connect fails to tmp list */
+	uris_mutex_lock(ctxt);
 	p = ctxt->uri->next;
 	while(p != ctxt->uri) {
 		this = list_entry(p, struct ldap_uri, list);
-		p = p->next;
+		uris_mutex_unlock(ctxt);
 		debug(logopt, "trying server %s", this->uri);
 		ldap = connect_to_server(logopt, this->uri, ctxt);
 		if (ldap) {
 			info(logopt, "connected to uri %s", this->uri);
+			uris_mutex_lock(ctxt);
 			break;
 		}
+		uris_mutex_lock(ctxt);
+		p = p->next;
 		list_del_init(&this->list);
 		list_add_tail(&this->list, &tmp);
 	}
@@ -648,6 +668,7 @@ static LDAP *find_server(unsigned logopt
 	list_splice(ctxt->uri, &tmp);
 	INIT_LIST_HEAD(ctxt->uri);
 	list_splice(&tmp, ctxt->uri);
+	uris_mutex_unlock(ctxt);
 
 	return ldap;
 }
@@ -662,14 +683,18 @@ static LDAP *do_reconnect(unsigned logop
 		return ldap;
 	}
 
+	uris_mutex_lock(ctxt);
 	this = list_entry(ctxt->uri->next, struct ldap_uri, list);
+	uris_mutex_unlock(ctxt);
 	ldap = do_connect(logopt, this->uri, ctxt);
 	if (ldap)
 		return ldap;
 
 	/* Failed to connect, put at end of list */
+	uris_mutex_lock(ctxt);
 	list_del_init(&this->list);
 	list_add_tail(&this->list, ctxt->uri);
+	uris_mutex_unlock(ctxt);
 
 #ifdef WITH_SASL
 	autofs_sasl_dispose(ctxt);
@@ -1203,6 +1228,8 @@ done:
 
 static void free_context(struct lookup_context *ctxt)
 {
+	int ret;
+
 	if (ctxt->schema) {
 		free(ctxt->schema->map_class);
 		free(ctxt->schema->map_attr);
@@ -1235,6 +1262,9 @@ static void free_context(struct lookup_c
 		free(ctxt->base);
 	if (ctxt->uri)
 		defaults_free_uris(ctxt->uri);
+	ret = pthread_mutex_destroy(&ctxt->uris_mutex);
+	if (ret)
+		fatal(ret);
 	if (ctxt->sdns)
 		defaults_free_searchdns(ctxt->sdns);
 	free(ctxt);
@@ -1286,6 +1316,13 @@ int lookup_init(const char *mapfmt, int 
 	}
 	memset(ctxt, 0, sizeof(struct lookup_context));
 
+	ret = pthread_mutex_init(&ctxt->uris_mutex, NULL);
+	if (ret) {
+		error(LOGOPT_ANY, MODPREFIX "failed to init uris mutex");
+		free(ctxt);
+		return 1;
+	}
+
 	/* If a map type isn't explicitly given, parse it like sun entries. */
 	if (mapfmt == NULL)
 		mapfmt = MAPFMT_DEFAULT;

autofs-5.0.3-add-replicated-debug-logging.patch:

--- NEW FILE autofs-5.0.3-add-replicated-debug-logging.patch ---
autofs-5.0.3 - add replicated server selection debug logging

From: Ian Kent <raven at themaw.net>

Add some debug logging to the replicated server selection code.
---

 modules/replicated.c |   86 +++++++++++++++++++++++++++++++++++++++------------
 1 file changed, 66 insertions(+), 20 deletions(-)


--- autofs-5.0.2.orig/modules/replicated.c
+++ autofs-5.0.2/modules/replicated.c
@@ -404,6 +404,10 @@ static unsigned int get_nfs_info(unsigne
 	double taken = 0;
 	int status, count = 0;
 
+	debug(logopt,
+	      "called for host %s proto %s version 0x%x",
+	      host->name, proto, version);
+
 	memset(&parms, 0, sizeof(struct pmap));
 
 	parms.pm_prog = NFS_PROGRAM;
@@ -428,11 +432,17 @@ static unsigned int get_nfs_info(unsigne
 		status = rpc_ping_proto(rpc_info);
 		gettimeofday(&end, &tz);
 		if (status) {
-			if (random_selection)
+			double reply;
+			if (random_selection) {
 				/* Random value between 0 and 1 */
-				taken += ((float) random())/((float) RAND_MAX+1);
-			else
-				taken += elapsed(start, end);;
+				reply = ((float) random())/((float) RAND_MAX+1);
+				debug(logopt,
+				      "nfs v4 random selection time: %f", reply);
+			} else {
+				reply = elapsed(start, end);
+				debug(logopt, "nfs v4 rpc ping time: %f", reply);
+			}
+			taken += reply;
 			count++;
 			supported = NFS4_SUPPORTED;
 		}
@@ -470,11 +480,17 @@ v3_ver:
 		status = rpc_ping_proto(rpc_info);
 		gettimeofday(&end, &tz);
 		if (status) {
-			if (random_selection)
+			double reply;
+			if (random_selection) {
 				/* Random value between 0 and 1 */
-				taken += ((float) random())/((float) RAND_MAX+1);
-			else
-				taken += elapsed(start, end);;
+				reply = ((float) random())/((float) RAND_MAX+1);
+				debug(logopt,
+				      "nfs v3 random selection time: %f", reply);
+			} else {
+				reply = elapsed(start, end);
+				debug(logopt, "nfs v3 rpc ping time: %f", reply);
+			}
+			taken += reply;
 			count++;
 			supported |= NFS3_SUPPORTED;
 		}
@@ -504,11 +520,17 @@ v2_ver:
 		status = rpc_ping_proto(rpc_info);
 		gettimeofday(&end, &tz);
 		if (status) {
-			if (random_selection)
+			double reply;
+			if (random_selection) {
 				/* Random value between 0 and 1 */
-				taken += ((float) random())/((float) RAND_MAX+1);
-			else
-				taken += elapsed(start, end);;
+				reply = ((float) random())/((float) RAND_MAX+1);
+				debug(logopt,
+				      "nfs v2 random selection time: %f", reply);
+			} else {
+				reply = elapsed(start, end);;
+				debug(logopt, "nfs v2 rpc ping time: %f", reply);
+			}
+			taken += reply;
 			count++;
 			supported |= NFS2_SUPPORTED;
 		}
@@ -533,6 +555,9 @@ done_ver:
 		/* Allow for user bias */
 		if (host->weight)
 			host->cost *= (host->weight + 1);
+
+		debug(logopt, "host %s cost %ld weight %d",
+		      host->name, host->cost, host->weight);
 	}
 
 	return supported;
@@ -603,6 +628,9 @@ static int get_supported_ver_and_cost(un
 	time_t timeout = RPC_TIMEOUT;
 	int status;
 
+	debug(logopt,
+	      "called with host %s version 0x%x", host->name, version);
+
 	memset(&pm_info, 0, sizeof(struct conn_info));
 	memset(&rpc_info, 0, sizeof(struct conn_info));
 	memset(&parms, 0, sizeof(struct pmap));
@@ -681,11 +709,14 @@ static int get_supported_ver_and_cost(un
 		status = rpc_ping_proto(&rpc_info);
 		gettimeofday(&end, &tz);
 		if (status) {
-			if (random_selection)
+			if (random_selection) {
 				/* Random value between 0 and 1 */
 				taken = ((float) random())/((float) RAND_MAX+1);
-			else
+				debug(logopt, "random selection time %f", taken);
+			} else {
 				taken = elapsed(start, end);
+				debug(logopt, "rpc ping time %f", taken);
+			}
 		}
 	}
 done:
@@ -705,6 +736,8 @@ done:
 		if (host->weight)
 			host->cost *= (host->weight + 1);
 
+		debug(logopt, "cost %ld weight %d", host->cost, host->weight);
+
 		return 1;
 	}
 
@@ -811,18 +844,31 @@ int prune_host_list(unsigned logopt, str
 	max_udp_count = mmax(v4_udp_count, v3_udp_count, v2_udp_count);
 	max_count = max(max_tcp_count, max_udp_count);
 
-	if (max_count == v4_tcp_count)
+	if (max_count == v4_tcp_count) {
 		selected_version = NFS4_TCP_SUPPORTED;
-	else if (max_count == v3_tcp_count)
+		debug(logopt,
+		      "selected subset of hosts that support NFS4 over TCP");
+	} else if (max_count == v3_tcp_count) {
 		selected_version = NFS3_TCP_SUPPORTED;
-	else if (max_count == v2_tcp_count)
+		debug(logopt,
+		      "selected subset of hosts that support NFS3 over TCP");
+	} else if (max_count == v2_tcp_count) {
 		selected_version = NFS2_TCP_SUPPORTED;
-	else if (max_count == v4_udp_count)
+		debug(logopt,
+		      "selected subset of hosts that support NFS2 over TCP");
+	} else if (max_count == v4_udp_count) {
 		selected_version = NFS4_UDP_SUPPORTED;
-	else if (max_count == v3_udp_count)
+		debug(logopt,
+		      "selected subset of hosts that support NFS4 over UDP");
+	} else if (max_count == v3_udp_count) {
 		selected_version = NFS3_UDP_SUPPORTED;
-	else if (max_count == v2_udp_count)
+		debug(logopt,
+		      "selected subset of hosts that support NFS3 over UDP");
+	} else if (max_count == v2_udp_count) {
 		selected_version = NFS2_UDP_SUPPORTED;
+		debug(logopt,
+		      "selected subset of hosts that support NFS2 over UDP");
+	}
 
 	/* Add local and hosts with selected version to new list */
 	this = *list;

autofs-5.0.3-add-umount_wait-parameter.patch:

--- NEW FILE autofs-5.0.3-add-umount_wait-parameter.patch ---
autofs-5.0.3 - add configuration paramter UMOUNT_WAIT

From: Ian Kent <raven at themaw.net>

To try and prevent expire delays when trying to umount from a server
that is not available we limit the time that we wait for a response
from the spawned umount process before sending it a SIGTERM signal.
This patch adds a configuration parameter to allow this wait to be
changed if needed.
---

 daemon/spawn.c                 |    2 +-
 include/defaults.h             |    2 ++
 lib/defaults.c                 |   13 +++++++++++++
 man/auto.master.5.in           |    6 ++++++
 redhat/autofs.sysconfig.in     |    4 ++++
 samples/autofs.conf.default.in |    4 ++++
 6 files changed, 30 insertions(+), 1 deletions(-)


diff --git a/daemon/spawn.c b/daemon/spawn.c
index e3c355e..6b26c41 100644
--- a/daemon/spawn.c
+++ b/daemon/spawn.c
@@ -502,7 +502,7 @@ int spawn_umount(unsigned logopt, ...)
 	unsigned int options;
 	unsigned int retries = MTAB_LOCK_RETRIES;
 	int ret, printed = 0;
-	unsigned int wait = 12;
+	unsigned int wait = defaults_get_umount_wait();
 
 #ifdef ENABLE_MOUNT_LOCKING
 	options = SPAWN_OPT_LOCK;
diff --git a/include/defaults.h b/include/defaults.h
index 6e4f52a..12534ec 100644
--- a/include/defaults.h
+++ b/include/defaults.h
@@ -24,6 +24,7 @@
 
 #define DEFAULT_TIMEOUT			600
 #define DEFAULT_NEGATIVE_TIMEOUT	60
+#define DEFAULT_UMOUNT_WAIT		12
 #define DEFAULT_BROWSE_MODE		1
 #define DEFAULT_LOGGING			0
 
@@ -59,6 +60,7 @@ struct ldap_schema *defaults_get_schema(void);
 struct ldap_searchdn *defaults_get_searchdns(void);
 void defaults_free_searchdns(struct ldap_searchdn *);
 unsigned int defaults_get_append_options(void);
+unsigned int defaults_get_umount_wait(void);
 const char *defaults_get_auth_conf_file(void);
 
 #endif
diff --git a/lib/defaults.c b/lib/defaults.c
index 8149549..21d76d2 100644
--- a/lib/defaults.c
+++ b/lib/defaults.c
@@ -45,6 +45,7 @@
 #define ENV_NAME_VALUE_ATTR		"VALUE_ATTRIBUTE"
 
 #define ENV_APPEND_OPTIONS		"APPEND_OPTIONS"
+#define ENV_UMOUNT_WAIT			"UMOUNT_WAIT"
 #define ENV_AUTH_CONF_FILE		"AUTH_CONF_FILE"
 
 static const char *default_master_map_name = DEFAULT_MASTER_MAP_NAME;
@@ -320,6 +321,7 @@ unsigned int defaults_read_config(unsigned int to_syslog)
 		    check_set_config_value(key, ENV_NAME_ENTRY_ATTR, value, to_syslog) ||
 		    check_set_config_value(key, ENV_NAME_VALUE_ATTR, value, to_syslog) ||
 		    check_set_config_value(key, ENV_APPEND_OPTIONS, value, to_syslog) ||
+		    check_set_config_value(key, ENV_UMOUNT_WAIT, value, to_syslog) ||
 		    check_set_config_value(key, ENV_AUTH_CONF_FILE, value, to_syslog))
 			;
 	}
@@ -647,6 +649,17 @@ unsigned int defaults_get_append_options(void)
 	return res;
 }
 
+unsigned int defaults_get_umount_wait(void)
+{
+	long wait;
+
+	wait = get_env_number(ENV_UMOUNT_WAIT);
+	if (wait < 0)
+		wait = DEFAULT_UMOUNT_WAIT;
+
+	return (unsigned int) wait;
+}
+
 const char *defaults_get_auth_conf_file(void)
 {
 	char *cf;
diff --git a/man/auto.master.5.in b/man/auto.master.5.in
index 49a711c..9cc5f02 100644
--- a/man/auto.master.5.in
+++ b/man/auto.master.5.in
@@ -174,6 +174,12 @@ Set the default timeout for caching failed key lookups (program default
 60). If the equivalent command line option is given it will override this
 setting.
 .TP
+.B UMOUNT_WAIT
+Set the default time to wait for a response from a spawned umount(8)
+before sending it a SIGTERM. Note that we still need to wait for the
+RPC layer to timeout before the sub-process exits so this isn't ideal
+but it is the best we can do.
+.TP
 .B BROWSE_MODE
 Maps are browsable by default (program default "yes").
 .TP
diff --git a/redhat/autofs.sysconfig.in b/redhat/autofs.sysconfig.in
index 636763a..ce64feb 100644
--- a/redhat/autofs.sysconfig.in
+++ b/redhat/autofs.sysconfig.in
@@ -14,6 +14,10 @@ TIMEOUT=300
 #
 #NEGATIVE_TIMEOUT=60
 #
+# UMOUNT_WAIT - time to wait for a response from umount(8).
+#
+#UMOUNT_WAIT=12
+#
 # BROWSE_MODE - maps are browsable by default.
 #
 BROWSE_MODE="no"
diff --git a/samples/autofs.conf.default.in b/samples/autofs.conf.default.in
index 086ba4f..0231e1d 100644
--- a/samples/autofs.conf.default.in
+++ b/samples/autofs.conf.default.in
@@ -14,6 +14,10 @@ TIMEOUT=300
 #
 #NEGATIVE_TIMEOUT=60
 #
+# UMOUNT_WAIT - time to wait for a response from umount(8).
+#
+#UMOUNT_WAIT=12
+#
 # BROWSE_MODE - maps are browsable by default.
 #
 BROWSE_MODE="no"

autofs-5.0.3-allow-dir-create-on-nfs-root.patch:

--- NEW FILE autofs-5.0.3-allow-dir-create-on-nfs-root.patch ---
autofs-5.0.3 - allow directory create on NFS root

From: Matthias Koenig <mkoenig at suse.de>

autofs will not create the autofs mountpoint path if the filesystem is
not a locally mounted filesystem (e.g. a NFS mounted filesystem).

contained_in_local_fs() returns false in this case. This is intentional
but breaks clients that have an NFS root filesystem. In this case we
shouldn't impose this restriction.
---

 lib/mounts.c |    8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)


--- autofs-5.0.2.orig/lib/mounts.c
+++ autofs-5.0.2/lib/mounts.c
@@ -363,7 +363,13 @@ int contained_in_local_fs(const char *pa
 		if (!strncmp(path, this->path, len)) {
 			if (len > 1 && pathlen > len && path[len] != '/')
 				continue;
-			else if (this->fs_name[0] == '/') {
+			else if (len == 1 && this->path[0] == '/') {
+				/*
+				 * always return true on rootfs, we don't
+				 * want to break diskless clients.
+				 */
+				ret = 1;
+			} else if (this->fs_name[0] == '/') {
 				if (strlen(this->fs_name) > 1) {
 					if (this->fs_name[1] != '/')
 						ret = 1;

autofs-5.0.3-check-direct-path-len.patch:

--- NEW FILE autofs-5.0.3-check-direct-path-len.patch ---
autofs-5.0.3 - check direct mount path length

From: Ian Kent <raven at themaw.net>

The length of the path corresponding to a direct mount can't be
checked in the kernel so we need to check it will fit into the
request structire before going ahead with the mount. The name
field of the request structure is also to short and so is increased
to PATH_MAX.
---

 daemon/direct.c     |   15 +++++++++++++--
 include/automount.h |    2 +-
 2 files changed, 14 insertions(+), 3 deletions(-)


--- autofs-5.0.2.orig/daemon/direct.c
+++ autofs-5.0.2/daemon/direct.c
@@ -1411,7 +1411,7 @@ static void *do_mount_direct(void *arg)
 	}
 
 cont:
-	status = lookup_nss_mount(ap, NULL, mt.name, strlen(mt.name));
+	status = lookup_nss_mount(ap, NULL, mt.name, mt.len);
 	/*
 	 * Direct mounts are always a single mount. If it fails there's
 	 * nothing to undo so just complain
@@ -1454,7 +1454,7 @@ int handle_packet_missing_direct(struct 
 	struct pending_args *mt;
 	char buf[MAX_ERR_BUF];
 	int status = 0;
-	int ioctlfd, cl_flags, state;
+	int ioctlfd, len, cl_flags, state;
 
 	pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &state);
 
@@ -1525,6 +1525,16 @@ int handle_packet_missing_direct(struct 
 		return 1;
 	}
 
+	len = strlen(me->key);
+	if (len >= PATH_MAX) {
+		error(ap->logopt, "direct mount path too long %s", me->key);
+		send_fail(ap->logopt, ioctlfd, pkt->wait_queue_token);
+		close(ioctlfd);
+		cache_unlock(mc);
+		pthread_setcancelstate(state, NULL);
+		return 1;
+	}
+
 	mt = malloc(sizeof(struct pending_args));
 	if (!mt) {
 		char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
@@ -1553,6 +1563,7 @@ int handle_packet_missing_direct(struct 
 	mt->ioctlfd = ioctlfd;
 	mt->mc = mc;
 	strcpy(mt->name, me->key);
+	mt->len = len;
 	mt->dev = me->dev;
 	mt->type = NFY_MOUNT;
 	mt->uid = pkt->uid;
--- autofs-5.0.2.orig/include/automount.h
+++ autofs-5.0.2/include/automount.h
@@ -409,7 +409,7 @@ struct pending_args {
 	int type;			/* Type of packet */
 	int ioctlfd;			/* Mount ioctl fd */
 	struct mapent_cache *mc;	/* Cache Containing entry */
-	char name[KEY_MAX_LEN];		/* Name field of the request */
+	char name[PATH_MAX];		/* Name field of the request */
 	dev_t dev;			/* device number of mount */
 	unsigned int len;		/* Name field len */
 	uid_t uid;			/* uid of requestor */

autofs-5.0.3-check-for-kernel-automount-fix.patch:

--- NEW FILE autofs-5.0.3-check-for-kernel-automount-fix.patch ---
autofs-5.0.3 - check for kernel automount fix

From: Ian Kent <raven at themaw.net>

Look in the correct mount table for kernel automounted "nohide"
mounts.
---

 daemon/direct.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)


diff --git a/daemon/direct.c b/daemon/direct.c
index afb354e..13f572c 100644
--- a/daemon/direct.c
+++ b/daemon/direct.c
@@ -709,7 +709,7 @@ int mount_autofs_offset(struct autofs_point *ap, struct mapent *me, const char *
 			 * the kernel NFS client.
 			 */
 			if (me->multi != me &&
-			    is_mounted(_PATH_MOUNTED, mountpoint, MNTS_REAL))
+			    is_mounted(_PROC_MOUNTS, mountpoint, MNTS_REAL))
 				return MOUNT_OFFSET_IGNORE;
 
 			/* 

autofs-5.0.3-check-for-kernel-automount.patch:

--- NEW FILE autofs-5.0.3-check-for-kernel-automount.patch ---
autofs 5.0.3 - check for exported mounts automatically mounted by kernel

From: Ian Kent <raven at themaw.net>

If a server exports file systems that are automatically mounted by
the kernel client autofs will mistakenly over mount them when it
constructs and mounts its multi-mount triggers.

This patch makes autofs check for this case and ignores them if the
kernel mounts them while it mounts multi-mount triggers.

We don't want to fight with NFS over mounting these because it
confuses autofs and they magically go away when the owner mount is
umounted. This isn't ideal because autofs will mount these mounts
while constructing its multi-mount triggers but it is unavoidable
at the moment.
---

 daemon/direct.c     |   26 ++++++++++++++++++--------
 include/automount.h |    4 ++++
 lib/parse_subs.c    |   26 ++++++++++++++++++--------
 3 files changed, 40 insertions(+), 16 deletions(-)


--- autofs-5.0.2.orig/daemon/direct.c
+++ autofs-5.0.2/daemon/direct.c
@@ -664,12 +664,12 @@ int mount_autofs_offset(struct autofs_po
 		if (ap->state != ST_READMAP)
 			warn(ap->logopt,
 			      "trigger %s already mounted", me->key);
-		return 0;
+		return MOUNT_OFFSET_OK;
 	}
 
 	if (me->ioctlfd != -1) {
 		error(ap->logopt, "active offset mount %s", me->key);
-		return -1;
+		return MOUNT_OFFSET_FAIL;
 	}
 
 	status = pthread_once(&key_mnt_params_once, key_mnt_params_init);
@@ -683,7 +683,7 @@ int mount_autofs_offset(struct autofs_po
 			crit(ap->logopt,
 			  "mnt_params value create failed for offset mount %s",
 			  me->key);
-			return 0;
+			return MOUNT_OFFSET_OK;
 		}
 		mp->options = NULL;
 
@@ -697,12 +697,22 @@ int mount_autofs_offset(struct autofs_po
 	if (!mp->options) {
 		mp->options = make_options_string(ap->path, ap->kpipefd, "offset");
 		if (!mp->options)
-			return 0;
+			return MOUNT_OFFSET_OK;
 	}
 
 	/* In case the directory doesn't exist, try to mkdir it */
 	if (mkdir_path(me->key, 0555) < 0) {
 		if (errno == EEXIST) {
+			/*
+			 * If the mount point directory is a real mount
+			 * and it isn't the root offset then it must be
+			 * a mount that has been automatically mounted by
+			 * the kernel NFS client.
+			 */
+			if (me->multi != me &&
+			    is_mounted(_PROC_MOUNTS, me->key, MNTS_REAL))
+				return MOUNT_OFFSET_IGNORE;
+
 			/* 
 			 * If we recieve an error, and it's EEXIST
 			 * we know the directory was not created.
@@ -721,13 +731,13 @@ int mount_autofs_offset(struct autofs_po
 			debug(ap->logopt,
 			     "can't create mount directory: %s, %s",
 			     me->key, estr);
-			return -1;
+			return MOUNT_OFFSET_FAIL;
 		} else {
 			char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
 			crit(ap->logopt,
 			     "failed to create mount directory: %s, %s",
 			     me->key, estr);
-			return -1;
+			return MOUNT_OFFSET_FAIL;
 		}
 	} else {
 		/* No errors so the directory was successfully created */
@@ -787,7 +797,7 @@ int mount_autofs_offset(struct autofs_po
 
 	debug(ap->logopt, "mounted trigger %s", me->key);
 
-	return 0;
+	return MOUNT_OFFSET_OK;
 
 out_close:
 	close(ioctlfd);
@@ -797,7 +807,7 @@ out_err:
 	if (stat(me->key, &st) == 0 && me->dir_created)
 		 rmdir_path(ap, me->key, st.st_dev);
 
-	return -1;
+	return MOUNT_OFFSET_FAIL;
 }
 
 static int expire_direct(int ioctlfd, const char *path, unsigned int when, unsigned int logopt)
--- autofs-5.0.2.orig/include/automount.h
+++ autofs-5.0.2/include/automount.h
@@ -468,6 +468,10 @@ struct autofs_point {
 
 /* Standard functions used by daemon or modules */
 
+#define	MOUNT_OFFSET_OK		0
+#define	MOUNT_OFFSET_FAIL	-1
+#define MOUNT_OFFSET_IGNORE	-2
+
 void *handle_mounts(void *arg);
 int umount_multi(struct autofs_point *ap, const char *path, int incl);
 int send_ready(unsigned logopt, int ioctlfd, unsigned int wait_queue_token);
--- autofs-5.0.2.orig/lib/parse_subs.c
+++ autofs-5.0.2/lib/parse_subs.c
@@ -390,7 +390,7 @@ int mount_multi_triggers(struct autofs_p
 	struct list_head *pos = NULL;
 	unsigned int fs_path_len;
 	unsigned int mounted;
-	int start;
+	int ret, start;
 
 	fs_path_len = strlen(root) + strlen(base);
 	if (fs_path_len > PATH_MAX)
@@ -411,15 +411,25 @@ int mount_multi_triggers(struct autofs_p
 		}
 
 		oe = cache_lookup_offset(base, offset, start, &me->multi_list);
-		if (!oe)
+		if (!oe || !oe->mapent)
 			goto cont;
 
 		debug(ap->logopt, "mount offset %s", oe->key);
 
-		if (mount_autofs_offset(ap, oe) < 0)
-			warn(ap->logopt, "failed to mount offset");
-		else
+		ret = mount_autofs_offset(ap, oe);
+		if (ret >= MOUNT_OFFSET_OK)
 			mounted++;
+		else {
+			if (ret != MOUNT_OFFSET_IGNORE)
+				warn(ap->logopt, "failed to mount offset");
+			else {
+				debug(ap->logopt,
+				      "ignoring \"nohide\" trigger %s",
+				      oe->key);
+				free(oe->mapent);
+				oe->mapent = NULL;
+			}
+		}
 cont:
 		offset = cache_get_offset(base,
 				offset, start, &me->multi_list, &pos);
@@ -457,7 +467,7 @@ int umount_multi_triggers(struct autofs_
 
 		oe = cache_lookup_offset(mm_base, offset, start, &me->multi_list);
 		/* root offset is a special case */
-		if (!oe || (strlen(oe->key) - start) == 1)
+		if (!oe || !oe->mapent || (strlen(oe->key) - start) == 1)
 			continue;
 
 		/*
@@ -481,7 +491,7 @@ int umount_multi_triggers(struct autofs_
 	while ((offset = cache_get_offset(mm_base, offset, start, mm_root, &pos))) {
 		oe = cache_lookup_offset(mm_base, offset, start, &me->multi_list);
 		/* root offset is a special case */
-		if (!oe || (strlen(oe->key) - start) == 1)
+		if (!oe || !oe->mapent || (strlen(oe->key) - start) == 1)
 			continue;
 
 		debug(ap->logopt, "umount offset %s", oe->key);
@@ -505,7 +515,7 @@ int umount_multi_triggers(struct autofs_
 		if (is_mounted(_PATH_MOUNTED, root, MNTS_REAL)) {
 			info(ap->logopt, "unmounting dir = %s", root);
 			if (umount_ent(ap, root)) {
-				if (!mount_multi_triggers(ap, root, me, "/"))
+				if (mount_multi_triggers(ap, root, me, "/") < 0)
 					warn(ap->logopt,
 					     "failed to remount offset triggers");
 				return left++;

autofs-5.0.3-check-replicated-list-after-probe.patch:

--- NEW FILE autofs-5.0.3-check-replicated-list-after-probe.patch ---
autofs-5.0.3 - check replicated list after probe

From: Ian Kent <raven at themaw.net>

When checking a list of servers for proximity and NFS version
the list may become empty after after the initial probe. This
case isn't handled and this patch adds it.
---

 modules/replicated.c |    9 +++++++++
 1 file changed, 9 insertions(+)


--- autofs-5.0.2.orig/modules/replicated.c
+++ autofs-5.0.2/modules/replicated.c
@@ -768,6 +768,15 @@ int prune_host_list(unsigned logopt, str
 		this = next;
 	}
 
+	/*
+	 * The list of hosts that aren't proximity local may now
+	 * be empty if we haven't been able probe any so we need
+	 * to check again for a list containing only proximity
+	 * local hosts.
+	 */
+	if (!first)
+		return 1;
+
 	last = this;
 
 	/* Select NFS version of highest number of closest servers */

autofs-5.0.3-clear-stale-on-map-read.patch:

--- NEW FILE autofs-5.0.3-clear-stale-on-map-read.patch ---
autofs-5.0.3 - clear stale flag on map read

From: Ian Kent <raven at themaw.net>

We're not properly clearing the map stale flag after a map re-read
which causes a re-read after every lookup for master map entries
that have the "browse" option set. I removed the line that did
this at some point in the past and I must have had a reason to
do so. We'll have to wait and see what shows up after fixing
it.
---

 daemon/lookup.c |    2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)


diff --git a/daemon/lookup.c b/daemon/lookup.c
index d33aadc..2277623 100644
--- a/daemon/lookup.c
+++ b/daemon/lookup.c
@@ -298,6 +298,8 @@ static int do_read_map(struct autofs_point *ap, struct map_source *map, time_t a
 
 	status = lookup->lookup_read_map(ap, age, lookup->context);
 
+	map->stale = 0;
+
 	/*
 	 * For maps that don't support enumeration return success
 	 * and do whatever we must to have autofs function with an

autofs-5.0.3-dont-abuse-ap-ghost-field.patch:

--- NEW FILE autofs-5.0.3-dont-abuse-ap-ghost-field.patch ---
autofs-5.0.3 - don't abuse the ap->ghost field on NFS mount

From: Ian Kent <raven at themaw.net>

Using the ap->ghost field in the autofs mount point struct, to prevent
the mount point directory from being removed, when attempting a bind
mount when an NFS mount is local may lead to incorrectly reading and
ghosting the map. This can happen if a mount request comes in during
a map re-read when the autofs map doesn't have the browse option set.
This patch corrects that by using the existence check in the bind mount
module instead of the hack of changing the struct field.
---

 modules/mount_bind.c |    2 +-
 modules/mount_nfs.c  |   11 -----------
 2 files changed, 1 insertion(+), 12 deletions(-)


--- autofs-5.0.2.orig/modules/mount_bind.c
+++ autofs-5.0.2/modules/mount_bind.c
@@ -144,7 +144,7 @@ int mount_mount(struct autofs_point *ap,
 			if (ap->type != LKP_INDIRECT)
 				return 1;
 
-			if ((!ap->ghost && name_len) || !existed)
+			if ((!ap->ghost && name_len) && !existed)
 				rmdir_path(ap, fullpath, ap->dev);
 
 			return err;
--- autofs-5.0.2.orig/modules/mount_nfs.c
+++ autofs-5.0.2/modules/mount_nfs.c
@@ -62,7 +62,6 @@ int mount_mount(struct autofs_point *ap,
 {
 	char *fullpath, buf[MAX_ERR_BUF];
 	struct host *this, *hosts = NULL;
-	unsigned int save_ghost = ap->ghost;
 	unsigned int vers;
 	char *nfsoptions = NULL;
 	int len, rlen, status, err, existed = 1;
@@ -186,13 +185,6 @@ int mount_mount(struct autofs_point *ap,
 	if (!status)
 		existed = 0;
 
-	/*
-	 * We need to stop the bind mount module from removing the
-	 * mount point directory if a bind attempt fails so abuse
-	 * the ap->ghost field for this.
-	 */
-	ap->ghost = 1;
-
 	this = hosts;
 	while (this) {
 		char *loc, *port_opt = NULL;
@@ -229,7 +221,6 @@ int mount_mount(struct autofs_point *ap,
 			/* Success - we're done */
 			if (!err) {
 				free_host_list(&hosts);
-				ap->ghost = save_ghost;
 				return 0;
 			}
 
@@ -271,7 +262,6 @@ int mount_mount(struct autofs_point *ap,
 			info(ap->logopt, MODPREFIX "mounted %s on %s", loc, fullpath);
 			free(loc);
 			free_host_list(&hosts);
-			ap->ghost = save_ghost;
 			return 0;
 		}
 
@@ -281,7 +271,6 @@ int mount_mount(struct autofs_point *ap,
 
 forced_fail:
 	free_host_list(&hosts);
-	ap->ghost = save_ghost;
 
 	/* If we get here we've failed to complete the mount */
 

autofs-5.0.3-dont-block-on-expire.patch:

--- NEW FILE autofs-5.0.3-dont-block-on-expire.patch ---
autofs-5.0.3 - try not to block on expire

From: Ian Kent <raven at themaw.net>

When a server is not available umount and any stat statfs and related
function calls may block for a significant amount of time. This effects
expire timeouts a lot due to their synchronous nature. This patch limits
the time we wait on spawned umounts and elininates calls to functions
that would block. This allows us to retry the umount on the next expire
event and continue the expire of remaining mounts.
---

 daemon/automount.c |   34 +++++++++++++++++-------------
 daemon/direct.c    |   29 +++++---------------------
 daemon/indirect.c  |   26 ++++++++---------------
 daemon/spawn.c     |   59 +++++++++++++++++++++++++++++++++++++++++++----------
 include/master.h   |    1 
 lib/master.c       |   23 ++++++++++++++++++++
 lib/mounts.c       |   48 +------------------------------------------
 7 files changed, 110 insertions(+), 110 deletions(-)


--- autofs-5.0.2.orig/daemon/automount.c
+++ autofs-5.0.2/daemon/automount.c
@@ -247,9 +247,17 @@ static int walk_tree(const char *base, i
 						  int, void *), int incl, unsigned logopt, void *arg)
 {
 	char buf[PATH_MAX + 1];
-	struct stat st;
+	struct stat st, *pst = &st;
+	int ret;
+
+	if (!is_mounted(_PATH_MOUNTED, base, MNTS_REAL))
+		ret = lstat(base, pst);
+	else {
+		pst = NULL;
+		ret = 0;
+	}
 
-	if (lstat(base, &st) != -1 && (fn) (logopt, base, &st, 0, arg)) {
+	if (ret != -1 && (fn) (logopt, base, pst, 0, arg)) {
 		if (S_ISDIR(st.st_mode)) {
 			struct dirent **de;
 			int n;
@@ -283,7 +291,7 @@ static int walk_tree(const char *base, i
 			free(de);
 		}
 		if (incl)
-			(fn) (logopt, base, &st, 1, arg);
+			(fn) (logopt, base, pst, 1, arg);
 	}
 	return 0;
 }
@@ -294,6 +302,9 @@ static int rm_unwanted_fn(unsigned logop
 	char buf[MAX_ERR_BUF];
 	struct stat newst;
 
+	if (!st)
+		return 0;
+
 	if (when == 0) {
 		if (st->st_dev != dev)
 			return 0;
@@ -344,8 +355,8 @@ static int counter_fn(unsigned logopt, c
 {
 	struct counter_args *counter = (struct counter_args *) arg;
 
-	if (S_ISLNK(st->st_mode) || (S_ISDIR(st->st_mode) 
-		&& st->st_dev != counter->dev)) {
+	if (!st || (S_ISLNK(st->st_mode) || (S_ISDIR(st->st_mode)
+		&& st->st_dev != counter->dev))) {
 		counter->count++;
 		return 0;
 	}
@@ -512,9 +523,8 @@ static int umount_subtree_mounts(struct 
 int umount_multi(struct autofs_point *ap, const char *path, int incl)
 {
 	struct mapent_cache *nc;
-	struct statfs fs;
 	int is_autofs_fs;
-	int ret, left;
+	int left;
 
 	debug(ap->logopt, "path %s incl %d", path, incl);
 
@@ -526,13 +536,9 @@ int umount_multi(struct autofs_point *ap
 	}
 	cache_unlock(nc);
 
-	ret = statfs(path, &fs);
-	if (ret == -1) {
-		error(ap->logopt, "could not stat fs of %s", path);
-		return 1;
-	}
-
-	is_autofs_fs = fs.f_type == (__SWORD_TYPE) AUTOFS_SUPER_MAGIC ? 1 : 0;
+	is_autofs_fs = 0;
+	if (master_find_submount(ap, path))
+		is_autofs_fs = 1;
 
 	left = 0;
 
--- autofs-5.0.2.orig/daemon/direct.c
+++ autofs-5.0.2/daemon/direct.c
@@ -152,7 +152,7 @@ int do_umount_autofs_direct(struct autof
 
 	retries = UMOUNT_RETRIES;
 	while ((rv = umount(me->key)) == -1 && retries--) {
-		struct timespec tm = {0, 100000000};
+		struct timespec tm = {0, 200000000};
 		if (errno != EBUSY)
 			break;
 		nanosleep(&tm, NULL);
@@ -604,7 +604,7 @@ int umount_autofs_offset(struct autofs_p
 
 	retries = UMOUNT_RETRIES;
 	while ((rv = umount(me->key)) == -1 && retries--) {
-		struct timespec tm = {0, 100000000};
+		struct timespec tm = {0, 200000000};
 		if (errno != EBUSY)
 			break;
 		nanosleep(&tm, NULL);
@@ -705,7 +705,7 @@ int mount_autofs_offset(struct autofs_po
 			 * the kernel NFS client.
 			 */
 			if (me->multi != me &&
-			    is_mounted(_PROC_MOUNTS, me->key, MNTS_REAL))
+			    is_mounted(_PATH_MOUNTED, me->key, MNTS_REAL))
 				return MOUNT_OFFSET_IGNORE;
 
 			/* 
@@ -807,17 +807,7 @@ out_err:
 
 static int expire_direct(int ioctlfd, const char *path, unsigned int when, unsigned int logopt)
 {
-	char buf[MAX_ERR_BUF];
-	int ret, retries;
-	struct stat st;
-
-	if (fstat(ioctlfd, &st) == -1) {
-		char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
-		error(logopt, "fstat failed: %s", estr);
-		return 0;
-	}
-
-	retries = (count_mounts(logopt, path, st.st_dev) + 1) * EXPIRE_RETRIES;
+	int ret, retries = EXPIRE_RETRIES;
 
 	while (retries--) {
 		struct timespec tm = {0, 100000000};
@@ -911,7 +901,6 @@ void *expire_proc_direct(void *arg)
 
 		if (!strcmp(next->fs_type, "autofs")) {
 			struct stat st;
-			struct statfs fs;
 			int ioctlfd;
 
 			cache_unlock(me->mc);
@@ -932,14 +921,8 @@ void *expire_proc_direct(void *arg)
 				continue;
 			}
 
-			if (statfs(next->path, &fs) == -1) {
-				pthread_setcancelstate(cur_state, NULL);
-				warn(ap->logopt,
-				    "fstatfs failed for %s", next->path);
-				continue;
-			}
-
-			if (fs.f_type != (__SWORD_TYPE) AUTOFS_SUPER_MAGIC) {
+			/* It's got a mount, deal with in the outer loop */
+			if (tree_is_mounted(mnts, me->key, MNTS_REAL)) {
 				pthread_setcancelstate(cur_state, NULL);
 				continue;
 			}
--- autofs-5.0.2.orig/daemon/indirect.c
+++ autofs-5.0.2/daemon/indirect.c
@@ -285,7 +285,7 @@ int umount_autofs_indirect(struct autofs
 
 	retries = UMOUNT_RETRIES;
 	while ((rv = umount(ap->path)) == -1 && retries--) {
-		struct timespec tm = {0, 100000000};
+		struct timespec tm = {0, 200000000};
 		if (errno != EBUSY)
 			break;
 		nanosleep(&tm, NULL);
@@ -368,17 +368,7 @@ force_umount:
 
 static int expire_indirect(struct autofs_point *ap, int ioctlfd, const char *path, unsigned int when)
 {
-	char buf[MAX_ERR_BUF];
-	int ret, retries;
-	struct stat st;
-
-	if (fstat(ioctlfd, &st) == -1) {
-		char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
-		error(ap->logopt, "fstat failed: %s", estr);
-		return 0;
-	}
-
-	retries = (count_mounts(ap->logopt, path, st.st_dev) + 1) * EXPIRE_RETRIES;
+	int ret, retries = EXPIRE_RETRIES;
 
 	while (retries--) {
 		struct timespec tm = {0, 100000000};
@@ -512,7 +502,6 @@ void *expire_proc_indirect(void *arg)
 			left++;
 		pthread_setcancelstate(cur_state, NULL);
 	}
-	pthread_cleanup_pop(1);
 
 	/*
 	 * If there are no more real mounts left we could still
@@ -520,12 +509,17 @@ void *expire_proc_indirect(void *arg)
 	 * umount them here.
 	 */
 	if (mnts) {
+		int retries;
 		pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cur_state);
-		ret = expire_indirect(ap, ap->ioctlfd, ap->path, now);
-		if (!ret)
-			left++;
+		retries = (count_mounts(ap->logopt, ap->path, ap->dev) + 1);
+		while (retries--) {
+			ret = expire_indirect(ap, ap->ioctlfd, ap->path, now);
+			if (!ret)
+				left++;
+		}
 		pthread_setcancelstate(cur_state, NULL);
 	}
+	pthread_cleanup_pop(1);
 
 	count = offsets = submnts = 0;
 	mnts = get_mnt_list(_PROC_MOUNTS, ap->path, 0);
--- autofs-5.0.2.orig/daemon/spawn.c
+++ autofs-5.0.2/daemon/spawn.c
@@ -89,13 +89,43 @@ void reset_signals(void)
 
 #define ERRBUFSIZ 2047		/* Max length of error string excl \0 */
 
-static int do_spawn(unsigned logopt, unsigned int options, const char *prog, const char *const *argv)
+static int timed_read(int pipe, char *buf, size_t len, int time)
+{
+	struct timeval timeout = { 0, 0 };
+	struct timeval *tout = NULL;
+	fd_set wset, rset;
+	int ret;
+
+	FD_ZERO(&rset);
+	FD_SET(pipe, &rset);
+	wset = rset;
+
+	if (time != -1) {
+		timeout.tv_sec = time;
+		tout = &timeout;
+	}
+
+	ret = select(pipe + 1, &rset, &wset, NULL, tout);
+	if (ret <= 0) {
+		if (ret == 0)
+			ret = -ETIMEDOUT;
+		return ret;
+	}
+
+	while ((ret = read(pipe, buf, len)) == -1 && errno == EINTR);
+
+	return ret;
+}
+
+static int do_spawn(unsigned logopt, unsigned int wait,
+		    unsigned int options, const char *prog,
+		    const char *const *argv)
 {
 	pid_t f;
 	int ret, status, pipefd[2];
 	char errbuf[ERRBUFSIZ + 1], *p, *sp;
 	int errp, errn;
-	int cancel_state;
+	int flags, cancel_state;
 	unsigned int use_lock = options & SPAWN_OPT_LOCK;
 	unsigned int use_access = options & SPAWN_OPT_ACCESS;
 	sigset_t allsigs, tmpsig, oldsig;
@@ -183,12 +213,15 @@ static int do_spawn(unsigned logopt, uns
 			return -1;
 		}
 
+		if ((flags = fcntl(pipefd[0], F_GETFD, 0)) != -1) {
+			flags |= FD_CLOEXEC;
+			fcntl(pipefd[0], F_SETFD, flags);
+		}
+
 		errp = 0;
 		do {
-			while ((errn =
-				read(pipefd[0], errbuf + errp, ERRBUFSIZ - errp)) == -1
-			       && errno == EINTR);
-
+			errn = timed_read(pipefd[0],
+					  errbuf + errp, ERRBUFSIZ - errp, wait);
 			if (errn > 0) {
 				errp += errn;
 
@@ -213,6 +246,9 @@ static int do_spawn(unsigned logopt, uns
 			}
 		} while (errn > 0);
 
+		if (errn == -ETIMEDOUT)
+			kill(f, SIGTERM);
+
 		close(pipefd[0]);
 
 		if (errp > 0) {
@@ -238,7 +274,7 @@ static int do_spawn(unsigned logopt, uns
 
 int spawnv(unsigned logopt, const char *prog, const char *const *argv)
 {
-	return do_spawn(logopt, SPAWN_OPT_NONE, prog, argv);
+	return do_spawn(logopt, -1, SPAWN_OPT_NONE, prog, argv);
 }
 
 int spawnl(unsigned logopt, const char *prog, ...)
@@ -259,7 +295,7 @@ int spawnl(unsigned logopt, const char *
 	while ((*p++ = va_arg(arg, char *)));
 	va_end(arg);
 
-	return do_spawn(logopt, SPAWN_OPT_NONE, prog, (const char **) argv);
+	return do_spawn(logopt, -1, SPAWN_OPT_NONE, prog, (const char **) argv);
 }
 
 int spawn_mount(unsigned logopt, ...)
@@ -307,7 +343,7 @@ int spawn_mount(unsigned logopt, ...)
 	va_end(arg);
 
 	while (retries--) {
-		ret = do_spawn(logopt, options, prog, (const char **) argv);
+		ret = do_spawn(logopt, -1, options, prog, (const char **) argv);
 		if (ret & MTAB_NOTUPDATED) {
 			struct timespec tm = {3, 0};
 
@@ -406,7 +442,7 @@ int spawn_bind_mount(unsigned logopt, ..
 	va_end(arg);
 
 	while (retries--) {
-		ret = do_spawn(logopt, options, prog, (const char **) argv);
+		ret = do_spawn(logopt, -1, options, prog, (const char **) argv);
 		if (ret & MTAB_NOTUPDATED) {
 			struct timespec tm = {3, 0};
 
@@ -466,6 +502,7 @@ int spawn_umount(unsigned logopt, ...)
 	unsigned int options;
 	unsigned int retries = MTAB_LOCK_RETRIES;
 	int ret, printed = 0;
+	unsigned int wait = 12;
 
 #ifdef ENABLE_MOUNT_LOCKING
 	options = SPAWN_OPT_LOCK;
@@ -488,7 +525,7 @@ int spawn_umount(unsigned logopt, ...)
 	va_end(arg);
 
 	while (retries--) {
-		ret = do_spawn(logopt, options, prog, (const char **) argv);
+		ret = do_spawn(logopt, wait, options, prog, (const char **) argv);
 		if (ret & MTAB_NOTUPDATED) {
 			/*
 			 * If the mount succeeded but the mtab was not
--- autofs-5.0.2.orig/include/master.h
+++ autofs-5.0.2/include/master.h
@@ -91,6 +91,7 @@ void master_source_lock_cleanup(void *);
 void master_source_current_wait(struct master_mapent *);
 void master_source_current_signal(struct master_mapent *);
 struct master_mapent *master_find_mapent(struct master *, const char *);
+struct autofs_point *master_find_submount(struct autofs_point *, const char *);
 struct master_mapent *master_new_mapent(struct master *, const char *, time_t);
 void master_add_mapent(struct master *, struct master_mapent *);
 void master_remove_mapent(struct master_mapent *);
--- autofs-5.0.2.orig/lib/master.c
+++ autofs-5.0.2/lib/master.c
@@ -602,6 +602,29 @@ struct master_mapent *master_find_mapent
 	return NULL;
 }
 
+struct autofs_point *master_find_submount(struct autofs_point *ap, const char *path)
+{
+	struct list_head *head, *p;
+
+	mounts_mutex_lock(ap);
+
+	head = &ap->submounts;
+	list_for_each(p, head) {
+		struct autofs_point *submount;
+
+		submount = list_entry(p, struct autofs_point, mounts);
+
+		if (!strcmp(submount->path, path)) {
+			mounts_mutex_unlock(ap);
+			return submount;
+		}
+	}
+
+	mounts_mutex_unlock(ap);
+
+	return NULL;
+}
+
 struct master_mapent *master_new_mapent(struct master *master, const char *path, time_t age)
 {
 	struct master_mapent *entry;
--- autofs-5.0.2.orig/lib/mounts.c
+++ autofs-5.0.2/lib/mounts.c
@@ -1073,55 +1073,11 @@ free_tsv:
 
 int umount_ent(struct autofs_point *ap, const char *path)
 {
-	struct stat st;
-	struct statfs fs;
-	int sav_errno;
-	int status, is_smbfs = 0;
-	int ret, rv = 1;
-
-	ret = statfs(path, &fs);
-	if (ret == -1) {
-		warn(ap->logopt, "could not stat fs of %s", path);
-		is_smbfs = 0;
-	} else {
-		int cifsfs = fs.f_type == (__SWORD_TYPE) CIFS_MAGIC_NUMBER;
-		int smbfs = fs.f_type == (__SWORD_TYPE) SMB_SUPER_MAGIC;
-		is_smbfs = (cifsfs | smbfs) ? 1 : 0;
-	}
-
-	status = lstat(path, &st);
-	sav_errno = errno;
-
-	if (status < 0)
-		warn(ap->logopt, "lstat of %s failed with %d", path, status);
-
-	/*
-	 * lstat failed and we're an smbfs fs returning an error that is not
-	 * EIO or EBADSLT or the lstat failed so it's a bad path. Return
-	 * a fail.
-	 *
-	 * EIO appears to correspond to an smb mount that has gone away
-	 * and EBADSLT relates to CD changer not responding.
-	 */
-	if (!status && (S_ISDIR(st.st_mode) && st.st_dev != ap->dev)) {
-		rv = spawn_umount(ap->logopt, path, NULL);
-	} else if (is_smbfs && (sav_errno == EIO || sav_errno == EBADSLT)) {
-		rv = spawn_umount(ap->logopt, path, NULL);
-	}
+	int rv;
 
+	rv = spawn_umount(ap->logopt, path, NULL);
 	/* 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");
-			return 0;
-		}
-
-		if (ret == 0 && !S_ISDIR(st.st_mode)) {
-			warn(ap->logopt, "mount point is not a directory");
-			return 0;
-		}
-
 		if (ap->state == ST_SHUTDOWN_FORCE) {
 			info(ap->logopt, "forcing umount of %s", path);
 			rv = spawn_umount(ap->logopt, "-l", path, NULL);

autofs-5.0.3-dont-readmap-on-hup-for-new-mount.patch:

--- NEW FILE autofs-5.0.3-dont-readmap-on-hup-for-new-mount.patch ---
autofs-5.0.3 - don't readmap on HUP for new mount

From: Ian Kent <raven at themaw.net>

If we're performing a new mount during a HUP signal then
we will read the map during the mount.
---

 lib/master.c |    7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)


--- autofs-5.0.3.orig/lib/master.c
+++ autofs-5.0.3/lib/master.c
@@ -1108,8 +1108,6 @@ int master_mount_mounts(struct master *m
 		}
 		cache_unlock(nc);
 
-		check_update_map_sources(this, readall);
-
 		st_mutex_lock();
 
 		state_pipe = this->ap->state_pipe[1];
@@ -1120,11 +1118,14 @@ int master_mount_mounts(struct master *m
 
 		st_mutex_unlock();
 
-		if (ret == -1 && save_errno == EBADF)
+		if (!ret)
+			check_update_map_sources(this, readall);
+		else if (ret == -1 && save_errno == EBADF) {
 			if (!master_do_mount(this)) {
 				list_del_init(&this->list);
 				master_free_mapent_sources(ap->entry, 1);
 				master_free_mapent(ap->entry);
+			}
 		}
 	}
 

autofs-5.0.3-dont-use-proc-for-is-running-check.patch:

--- NEW FILE autofs-5.0.3-dont-use-proc-for-is-running-check.patch ---
autofs-5.0.3 - don't use proc for is running check

From: Ian Kent <raven at themaw.net>

Using /proc/<pid>/cmdline to check if the daemon is running allows
any user to create a trivial program called "automount" and prevent
the system automounter from running simply by executing it and
leaving it running. This patch makes autofs use a flag file for this
check instead.
---

 Makefile.conf.in   |    3 
 aclocal.m4         |   16 ++++
 configure          |   35 +++++++++
 configure.in       |   17 ++++
 daemon/Makefile    |    5 -
 daemon/automount.c |   95 +++++++-------------------
 daemon/flag.c      |  192 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 7 files changed, 293 insertions(+), 70 deletions(-)
 create mode 100644 daemon/flag.c


--- autofs-5.0.2.orig/Makefile.conf.in
+++ autofs-5.0.2/Makefile.conf.in
@@ -74,6 +74,9 @@ autofsmapdir = @mapdir@
 # Location for autofs fifos
 autofsfifodir = @fifodir@
 
+# Location for autofs flag file
+autofsflagdir = @flagdir@
+
 # Where to install the automount program
 sbindir = @sbindir@
 
--- autofs-5.0.2.orig/aclocal.m4
+++ autofs-5.0.2/aclocal.m4
@@ -136,6 +136,22 @@ AC_DEFUN(AF_FIFO_D,
   done
 fi])
 
+dnl --------------------------------------------------------------------------
+dnl AF_FLAG_D
+dnl
+dnl Check the location of the autofs flag file directory
+dnl --------------------------------------------------------------------------
+AC_DEFUN(AF_FLAG_D,
+[if test -z "$flagdir"; then
+  for flag_d in /var/run /tmp; do
+    if test -z "$flagdir"; then
+      if test -d "$flag_d"; then
+        flagdir="$flag_d"
+      fi
+    fi
+  done
+fi])
+
 dnl ----------------------------------- ##                   -*- Autoconf -*-
 dnl Check if --with-dmalloc was given.  ##
 dnl From Franc,ois Pinard               ##
--- autofs-5.0.2.orig/configure
+++ autofs-5.0.2/configure
@@ -655,6 +655,7 @@ initdir
 confdir
 mapdir
 fifodir
+flagdir
 DMALLOCLIB
 MOUNT
 HAVE_MOUNT
@@ -1295,6 +1296,7 @@ Optional Packages:
   --with-confdir=DIR	  use DIR for autofs configuration files
   --with-mapdir=PATH	  look in PATH for mount maps used by the automounter
   --with-fifodir=PATH	   use PATH as the directory for fifos used by the automounter
+  --with-flagdir=PATH	   use PATH as the directory for the flag file used by the automounter
   --with-dmalloc          use dmalloc, as in
 			  http://www.dmalloc.com/dmalloc.tar.gz
   --with-hesiod=DIR	  enable Hesiod support (libs and includes in DIR)
@@ -1876,6 +1878,36 @@ echo "${ECHO_T}$fifodir" >&6; }
 
 
 #
+# The user can specify --with-flagdir=PATH to specify where autofs flag file goes
+#
+if test -z "$flagdir"; then
+  for flag_d in /var/run /tmp; do
+    if test -z "$flagdir"; then
+      if test -d "$flag_d"; then
+        flagdir="$flag_d"
+      fi
+    fi
+  done
+fi
+
+# Check whether --with-flagdir was given.
+if test "${with_flagdir+set}" = set; then
+  withval=$with_flagdir; if test -z "$withval" -o "$withval" = "yes" -o "$withval" = "no"
+	then
+		:
+	else
+		filagdir="${withval}"
+	fi
+
+fi
+
+{ echo "$as_me:$LINENO: checking for autofs flag file directory" >&5
+echo $ECHO_N "checking for autofs flag file directory... $ECHO_C" >&6; }
+{ echo "$as_me:$LINENO: result: $flagdir" >&5
+echo "${ECHO_T}$flagdir" >&6; }
+
+
+#
 # Optional include dmalloc
 #
 { echo "$as_me:$LINENO: checking if malloc debugging is wanted" >&5
@@ -6247,6 +6279,7 @@ initdir!$initdir$ac_delim
 confdir!$confdir$ac_delim
 mapdir!$mapdir$ac_delim
 fifodir!$fifodir$ac_delim
+flagdir!$flagdir$ac_delim
 DMALLOCLIB!$DMALLOCLIB$ac_delim
 MOUNT!$MOUNT$ac_delim
 HAVE_MOUNT!$HAVE_MOUNT$ac_delim
@@ -6297,7 +6330,7 @@ LIBOBJS!$LIBOBJS$ac_delim
 LTLIBOBJS!$LTLIBOBJS$ac_delim
 _ACEOF
 
-  if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 89; then
+  if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 90; then
     break
   elif $ac_last_try; then
     { { echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5
--- autofs-5.0.2.orig/configure.in
+++ autofs-5.0.2/configure.in
@@ -96,6 +96,23 @@ AC_MSG_RESULT([$fifodir])
 AC_SUBST(fifodir)
 
 #
+# The user can specify --with-flagdir=PATH to specify where autofs flag file goes
+#
+AF_FLAG_D()
+AC_ARG_WITH(flagdir,
+[  --with-flagdir=PATH	   use PATH as the directory for the flag file used by the automounter],
+	if test -z "$withval" -o "$withval" = "yes" -o "$withval" = "no"
+	then
+		:
+	else
+		filagdir="${withval}"
+	fi
+)
+AC_MSG_CHECKING([for autofs flag file directory])
+AC_MSG_RESULT([$flagdir])
+AC_SUBST(flagdir)
+
+#
 # Optional include dmalloc
 #
 AM_WITH_DMALLOC()
--- autofs-5.0.2.orig/daemon/Makefile
+++ autofs-5.0.2/daemon/Makefile
@@ -6,9 +6,9 @@
 include ../Makefile.rules
 
 SRCS = automount.c indirect.c direct.c spawn.c module.c mount.c \
-	lookup.c state.c
+	lookup.c state.c flag.c
 OBJS = automount.o indirect.o direct.o spawn.o module.o mount.o \
-	lookup.o state.o
+	lookup.o state.o flag.o
 
 version := $(shell cat ../.version)
 
@@ -17,6 +17,7 @@ CFLAGS += -DAUTOFS_LIB_DIR=\"$(autofslib
 CFLAGS += -DAUTOFS_MAP_DIR=\"$(autofsmapdir)\"
 CFLAGS += -DAUTOFS_CONF_DIR=\"$(autofsconfdir)\"
 CFLAGS += -DAUTOFS_FIFO_DIR=\"$(autofsfifodir)\"
+CFLAGS += -DAUTOFS_FLAG_DIR=\"$(autofsflagdir)\"
 CFLAGS += -DVERSION_STRING=\"$(version)\"
 LDFLAGS += -rdynamic
 LIBS = -ldl
--- autofs-5.0.2.orig/daemon/automount.c
+++ autofs-5.0.2/daemon/automount.c
@@ -81,6 +81,8 @@ pthread_key_t key_thread_stdenv_vars;
 
 #define MAX_OPEN_FILES		10240
 
+int aquire_flag_file(void);
+void release_flag_file(void);
 static int umount_all(struct autofs_point *ap, int force);
 
 extern pthread_mutex_t master_mutex;
@@ -1098,7 +1100,7 @@ static int handle_packet(struct autofs_p
 	return -1;
 }
 
-static void become_daemon(unsigned foreground)
+static void become_daemon(unsigned foreground, unsigned daemon_check)
 {
 	FILE *pidfp;
 	char buf[MAX_ERR_BUF];
@@ -1118,9 +1120,14 @@ static void become_daemon(unsigned foreg
 	}
 
 	/* Detach from foreground process */
-	if (foreground)
+	if (foreground) {
+		if (daemon_check && !aquire_flag_file()) {
+			fprintf(stderr, "%s: program is already running.\n",
+				program);
+			exit(1);
+		}
 		log_to_stderr();
-	else {
+	} else {
 		pid = fork();
 		if (pid > 0) {
 			int r;
@@ -1136,6 +1143,13 @@ static void become_daemon(unsigned foreg
 		}
 		close(start_pipefd[0]);
 
+		if (daemon_check && !aquire_flag_file()) {
+			fprintf(stderr, "%s: program is already running.\n",
+				program);
+			close(start_pipefd[1]);
+			exit(1);
+		}
+
 		/*
 		 * Make our own process group for "magic" reason: processes that share
 		 * our pgrp see the raw filesystem behind the magic.
@@ -1143,6 +1157,7 @@ static void become_daemon(unsigned foreg
 		if (setsid() == -1) {
 			char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
 			fprintf(stderr, "setsid: %s", estr);
+			close(start_pipefd[1]);
 			exit(1);
 		}
 		log_to_syslog();
@@ -1617,64 +1632,6 @@ static void key_thread_stdenv_vars_destr
 	return;
 }
 
-static int is_automount_running(void)
-{
-	FILE *fp;
-	DIR *dir;
-	struct dirent entry;
-	struct dirent *result;
-	char path[PATH_MAX + 1], buf[PATH_MAX];
-
-	if ((dir = opendir("/proc")) == NULL) {
-		fprintf(stderr, "cannot opendir(/proc)\n");
-		exit(1);
-	}
-
-	while (readdir_r(dir, &entry, &result) == 0) {
-		int path_len, pid = 0;
-
-		if (!result)
-			break;
-
-		if (*entry.d_name == '.')
-			continue;
-
-		if (!strcmp(entry.d_name, "self"))
-			continue;
-
-		if (!isdigit(*entry.d_name))
-			continue;
-
-		pid = atoi(entry.d_name);
-		if (pid == getpid())
-			continue;
-
-		path_len = sprintf(path, "/proc/%s/cmdline", entry.d_name);
-		if (path_len >= PATH_MAX) {
-			fprintf(stderr,
-				"buffer to small for /proc path\n");
-			return -1;
-		}
-		path[path_len] = '\0';
-
-		fp = fopen(path, "r");
-		if (fp) {
-			int c, len = 0;
-
-			while (len < 127 && (c = fgetc(fp)) != EOF && c)
-				buf[len++] = c;
-			buf[len] = '\0';
-
-			if (strstr(buf, "automount"))
-				return pid;
-			fclose(fp);
-		}
-	}
-	closedir(dir);
-
-	return 0;
-}
-
 static void usage(void)
 {
 	fprintf(stderr,
@@ -1973,11 +1930,6 @@ int main(int argc, char *argv[])
 		exit(exit_code);
 	}
 
-	if (daemon_check && is_automount_running() > 0) {
-		fprintf(stderr, "%s: program is already running.\n",
-			program);
-		exit(1);
-	}
 #if 0
 	if (!load_autofs4_module()) {
 		fprintf(stderr, "%s: can't load %s filesystem module.\n",
@@ -2009,7 +1961,7 @@ int main(int argc, char *argv[])
 		     "can't increase core file limit - continuing");
 #endif
 
-	become_daemon(foreground);
+	become_daemon(foreground, daemon_check);
 
 	if (argc == 0)
 		master_list = master_new(NULL, timeout, ghost);
@@ -2020,6 +1972,7 @@ int main(int argc, char *argv[])
 		logerr("%s: can't create master map %s",
 			program, argv[0]);
 		close(start_pipefd[1]);
+		release_flag_file();
 		exit(1);
 	}
 
@@ -2027,6 +1980,7 @@ int main(int argc, char *argv[])
 		logerr("%s: failed to init thread attribute struct!",
 		     program);
 		close(start_pipefd[1]);
+		release_flag_file();
 		exit(1);
 	}
 
@@ -2035,6 +1989,7 @@ int main(int argc, char *argv[])
 		logerr("%s: failed to set detached thread attribute!",
 		     program);
 		close(start_pipefd[1]);
+		release_flag_file();
 		exit(1);
 	}
 
@@ -2044,6 +1999,7 @@ int main(int argc, char *argv[])
 		logerr("%s: failed to set stack size thread attribute!",
 		       program);
 		close(start_pipefd[1]);
+		release_flag_file();
 		exit(1);
 	}
 #endif
@@ -2060,6 +2016,7 @@ int main(int argc, char *argv[])
 		       program);
 		master_kill(master_list);
 		close(start_pipefd[1]);
+		release_flag_file();
 		exit(1);
 	}
 
@@ -2067,6 +2024,7 @@ int main(int argc, char *argv[])
 		logerr("%s: failed to create alarm handler thread!", program);
 		master_kill(master_list);
 		close(start_pipefd[1]);
+		release_flag_file();
 		exit(1);
 	}
 
@@ -2074,6 +2032,7 @@ int main(int argc, char *argv[])
 		logerr("%s: failed to create FSM handler thread!", program);
 		master_kill(master_list);
 		close(start_pipefd[1]);
+		release_flag_file();
 		exit(1);
 	}
 
@@ -2086,6 +2045,7 @@ int main(int argc, char *argv[])
 		*pst_stat = 3;
 		res = write(start_pipefd[1], pst_stat, sizeof(*pst_stat));
 		close(start_pipefd[1]);
+		release_flag_file();
 		exit(3);
 	}
 
@@ -2102,6 +2062,7 @@ int main(int argc, char *argv[])
 		pid_file = NULL;
 	}
 	closelog();
+	release_flag_file();
 
 #ifdef LIBXML2_WORKAROUND
 	if (dh)
--- /dev/null
+++ autofs-5.0.2/daemon/flag.c
@@ -0,0 +1,192 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * flag.c - autofs flag file management
+ *
+ * Copyright 2008 Red Hat, Inc. All rights reserved.
+ * Copyright 2008 Ian Kent <raven at themaw.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139,
+ * USA; either version 2 of the License, or (at your option) any later
+ * version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * ----------------------------------------------------------------------- */
+
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <time.h>
+#include <unistd.h>
+#include <string.h>
+#include <alloca.h>
+#include <stdio.h>
+#include <signal.h>
+#include <errno.h>
+
+#define MAX_PIDSIZE	20
+#define FLAG_FILE	AUTOFS_FLAG_DIR "/autofs-running"
+
+/* Flag for already existing flag file. */
+static int we_created_flagfile = 0;
+
+/* file descriptor of flag file */
+static int fd = -1;
+
+static int flag_is_owned(int fd)
+{
+	int pid = 0, tries = 3;
+
+	while (tries--) {
+		char pidbuf[MAX_PIDSIZE + 1];
+		int got;
+
+		lseek(fd, 0, SEEK_SET);
+		got = read(fd, pidbuf, MAX_PIDSIZE);
+		/*
+		 * We add a terminator to the pid to verify write complete.
+		 * If the write isn't finished in 300 milliseconds then it's
+		 * probably a stale lock file.
+		 */
+		if (got > 0 && pidbuf[got - 1] == '\n') {
+			sscanf(pidbuf, "%d", &pid);
+			break;
+		} else {
+			struct timespec t = { 0, 100000000 };
+			struct timespec r;
+
+			while (nanosleep(&t, &r) == -1 && errno == EINTR)
+				memcpy(&t, &r, sizeof(struct timespec));
+
+			continue;
+		}
+
+		/* Stale flagfile */
+		if (!tries)
+			return 0;
+	}
+
+
+	if (pid) {
+		int ret;
+
+		ret = kill(pid, 0);
+		/*
+		 * If lock file exists but is not owned by a process
+		 * we return unowned status so we can get rid of it
+		 * and continue.
+		 */
+		if (ret == -1 && errno == ESRCH)
+			return 0;
+	} else {
+		/*
+		 * Odd, no pid in file - so what should we do?
+		 * Assume something bad happened to owner and
+		 * return unowned status.
+		 */
+		return 0;
+	}
+
+	return 1;
+}
+
+/* Remove flag file. */
+void release_flag_file(void)
+{
+	if (fd > 0) {
+		close(fd);
+		fd = -1;
+	}
+
+	if (we_created_flagfile) {
+		unlink(FLAG_FILE);
+		we_created_flagfile = 0;
+	}
+}
+
+/* * Try to create flag file */
+int aquire_flag_file(void)
+{
+	char *linkf;
+	int len;
+
+	len = strlen(FLAG_FILE) + MAX_PIDSIZE;
+	linkf = alloca(len + 1);
+	snprintf(linkf, len, "%s.%d", FLAG_FILE, getpid());
+
+	/*
+	 * Repeat until it was us who made the link or we find the
+	 * flag file already exists. If an unexpected error occurs
+	 * we return 0 claiming the flag file exists which may not
+	 * really be the case.
+	 */
+	while (!we_created_flagfile) {
+		int errsv, i, j;
+
+		i = open(linkf, O_WRONLY|O_CREAT, 0);
+		if (i < 0) {
+			release_flag_file();
+			return 0;
+		}
+		close(i);
+
+		j = link(linkf, FLAG_FILE);
+		errsv = errno;
+
+		(void) unlink(linkf);
+
+		if (j < 0 && errsv != EEXIST) {
+			release_flag_file();
+			return 0;
+		}
+
+		fd = open(FLAG_FILE, O_RDWR);
+		if (fd < 0) {
+			/* Maybe the file was just deleted? */
+			if (errno == ENOENT)
+				continue;
+			release_flag_file();
+			return 0;
+		}
+
+		if (j == 0) {
+			char pidbuf[MAX_PIDSIZE + 1];
+			int pidlen;
+
+			pidlen = sprintf(pidbuf, "%d\n", getpid());
+			if (write(fd, pidbuf, pidlen) != pidlen) {
+				release_flag_file();
+				return 0;
+			}
+
+			we_created_flagfile = 1;
+		} else {
+			/*
+			 * Someone else made the link.
+			 * If the flag file is not owned by anyone clean
+			 * it up and try again, otherwise return fail.
+			 */
+			if (!flag_is_owned(fd)) {
+				close(fd);
+				fd = -1;
+				unlink(FLAG_FILE);
+				continue;
+			}
+
+			release_flag_file();
+			return 0;
+		}
+
+		close(fd);
+		fd = -1;
+	}
+
+	return 1;
+}
+

autofs-5.0.3-expire-thread-create-cond-handling.patch:

--- NEW FILE autofs-5.0.3-expire-thread-create-cond-handling.patch ---
autofs-5.0.3 - fix incorrect pthreads condition handling for expire requests.

From: Ian Kent <raven at themaw.net>

Occassionally, when starting an expire thread we can attempt to use the
structure for parameter communication after it has been freed. This patch
resolves this issue.
---

 daemon/direct.c   |   40 +++++++++++++++++++++-------------------
 daemon/indirect.c |   28 +++++++++++++++-------------
 2 files changed, 36 insertions(+), 32 deletions(-)


--- autofs-5.0.3.orig/daemon/direct.c
+++ autofs-5.0.3/daemon/direct.c
@@ -1033,55 +1033,53 @@ static void expire_mutex_unlock(void *ar
 
 static void *do_expire_direct(void *arg)
 {
-	struct pending_args *mt;
+	struct pending_args *args, mt;
 	struct autofs_point *ap;
 	size_t len;
 	int status, state;
 
-	mt = (struct pending_args *) arg;
+	args = (struct pending_args *) arg;
 
 	status = pthread_mutex_lock(&ea_mutex);
 	if (status)
 		fatal(status);
 
-	ap = mt->ap;
+	memcpy(&mt, args, sizeof(struct pending_args));
+
+	ap = mt.ap;
 
-	mt->signaled = 1;
-	status = pthread_cond_signal(&mt->cond);
+	args->signaled = 1;
+	status = pthread_cond_signal(&args->cond);
 	if (status)
 		fatal(status);
 
 	expire_mutex_unlock(NULL);
 
-	pthread_cleanup_push(free_pending_args, mt);
-	pthread_cleanup_push(pending_cond_destroy, mt);
-	pthread_cleanup_push(expire_send_fail, mt);
+	pthread_cleanup_push(expire_send_fail, &mt);
 
-	len = _strlen(mt->name, KEY_MAX_LEN);
+	len = _strlen(mt.name, KEY_MAX_LEN);
 	if (!len) {
-		warn(ap->logopt, "direct key path too long %s", mt->name);
+		warn(ap->logopt, "direct key path too long %s", mt.name);
 		/* TODO: force umount ?? */
 		pthread_exit(NULL);
 	}
 
-	status = do_expire(ap, mt->name, len);
+	status = do_expire(ap, mt.name, len);
 	pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &state);
 	if (status)
-		send_fail(ap->logopt, mt->ioctlfd, mt->wait_queue_token);
+		send_fail(ap->logopt, mt.ioctlfd, mt.wait_queue_token);
 	else {
 		struct mapent *me;
-		cache_readlock(mt->mc);
-		me = cache_lookup_distinct(mt->mc, mt->name);
+		cache_readlock(mt.mc);
+		me = cache_lookup_distinct(mt.mc, mt.name);
 		me->ioctlfd = -1;
-		cache_unlock(mt->mc);
-		send_ready(ap->logopt, mt->ioctlfd, mt->wait_queue_token);
-		close(mt->ioctlfd);
+		cache_unlock(mt.mc);
+		send_ready(ap->logopt, mt.ioctlfd, mt.wait_queue_token);
+		close(mt.ioctlfd);
 	}
 	pthread_setcancelstate(state, NULL);
 
 	pthread_cleanup_pop(0);
-	pthread_cleanup_pop(1);
-	pthread_cleanup_pop(1);
 
 	return NULL;
 }
@@ -1198,6 +1196,8 @@ int handle_packet_expire_direct(struct a
 	cache_unlock(mc);
 	master_source_unlock(ap->entry);
 
+	pthread_cleanup_push(free_pending_args, mt);
+	pthread_cleanup_push(pending_cond_destroy, mt);
 	pthread_cleanup_push(expire_mutex_unlock, NULL);
 	pthread_setcancelstate(state, NULL);
 
@@ -1212,6 +1212,8 @@ int handle_packet_expire_direct(struct a
 	}
 
 	pthread_cleanup_pop(1);
+	pthread_cleanup_pop(1);
+	pthread_cleanup_pop(1);
 
 	return 0;
 }
--- autofs-5.0.3.orig/daemon/indirect.c
+++ autofs-5.0.3/daemon/indirect.c
@@ -596,40 +596,38 @@ static void expire_mutex_unlock(void *ar
 
 static void *do_expire_indirect(void *arg)
 {
-	struct pending_args *mt;
+	struct pending_args *args, mt;
 	struct autofs_point *ap;
 	int status, state;
 
-	mt = (struct pending_args *) arg;
+	args = (struct pending_args *) arg;
 
 	status = pthread_mutex_lock(&ea_mutex);
 	if (status)
 		fatal(status);
 
-	ap = mt->ap;
+	memcpy(&mt, args, sizeof(struct pending_args));
 
-	mt->signaled = 1;
-	status = pthread_cond_signal(&mt->cond);
+	ap = mt.ap;
+
+	args->signaled = 1;
+	status = pthread_cond_signal(&args->cond);
 	if (status)
 		fatal(status);
 
 	expire_mutex_unlock(NULL);
 
-	pthread_cleanup_push(free_pending_args, mt);
-	pthread_cleanup_push(pending_cond_destroy, mt);
-	pthread_cleanup_push(expire_send_fail, mt);
+	pthread_cleanup_push(expire_send_fail, &mt);
 
-	status = do_expire(mt->ap, mt->name, mt->len);
+	status = do_expire(mt.ap, mt.name, mt.len);
 	pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &state);
 	if (status)
-		send_fail(ap->logopt, ap->ioctlfd, mt->wait_queue_token);
+		send_fail(ap->logopt, ap->ioctlfd, mt.wait_queue_token);
 	else
-		send_ready(ap->logopt, ap->ioctlfd, mt->wait_queue_token);
+		send_ready(ap->logopt, ap->ioctlfd, mt.wait_queue_token);
 	pthread_setcancelstate(state, NULL);
 
 	pthread_cleanup_pop(0);
-	pthread_cleanup_pop(1);
-	pthread_cleanup_pop(1);
 
 	return NULL;
 }
@@ -682,6 +680,8 @@ int handle_packet_expire_indirect(struct
 		return 1;
 	}
 
+	pthread_cleanup_push(free_pending_args, mt);
+	pthread_cleanup_push(pending_cond_destroy, mt);
 	pthread_cleanup_push(expire_mutex_unlock, NULL);
 	pthread_setcancelstate(state, NULL);
 
@@ -696,6 +696,8 @@ int handle_packet_expire_indirect(struct
 	}
 
 	pthread_cleanup_pop(1);
+	pthread_cleanup_pop(1);
+	pthread_cleanup_pop(1);
 
 	return 0;
 }

autofs-5.0.3-fix-couple-of-memory-leaks.patch:

--- NEW FILE autofs-5.0.3-fix-couple-of-memory-leaks.patch ---
autofs-5.0.3 - fix a couple of memory leaks

From: Ian Kent <raven at themaw.net>


---

 daemon/lookup.c     |    5 ++++-
 modules/parse_sun.c |   14 ++++++++++----
 2 files changed, 14 insertions(+), 5 deletions(-)


--- autofs-5.0.2.orig/daemon/lookup.c
+++ autofs-5.0.2/daemon/lookup.c
@@ -996,8 +996,11 @@ int lookup_prune_cache(struct autofs_poi
 
 			key = strdup(me->key);
 			me = cache_enumerate(mc, me);
-			if (!key || *key == '*')
+			if (!key || *key == '*') {
+				if (key)
+					free(key);
 				continue;
+			}
 
 			path = make_fullpath(ap->path, key);
 			if (!path) {
--- autofs-5.0.2.orig/modules/parse_sun.c
+++ autofs-5.0.2/modules/parse_sun.c
@@ -462,11 +462,17 @@ static char *concat_options(char *left, 
 	char buf[MAX_ERR_BUF];
 	char *ret;
 
-	if (left == NULL || *left == '\0')
-		return strdup(right);
+	if (left == NULL || *left == '\0') {
+		ret = strdup(right);
+		free(right);
+		return ret;
+	}
 
-	if (right == NULL || *right == '\0')
-		return strdup(left);
+	if (right == NULL || *right == '\0') {
+		ret = strdup(left);
+		free(left);
+		return ret;
+	}
 
 	ret = malloc(strlen(left) + strlen(right) + 2);
 

autofs-5.0.3-fix-fd-leak-at-multi-mount-fail.patch:

--- NEW FILE autofs-5.0.3-fix-fd-leak-at-multi-mount-fail.patch ---
autofs-5.0.3 - fix fd leak at multi-mount fail

From: Ian Kent <raven at themaw.net>

Fix file handle being left open following a multi-mount non-fatal mount
fail.
---

 daemon/direct.c |   12 ++++++++++--
 1 files changed, 10 insertions(+), 2 deletions(-)


diff --git a/daemon/direct.c b/daemon/direct.c
index 13f572c..b94601a 100644
--- a/daemon/direct.c
+++ b/daemon/direct.c
@@ -1303,12 +1303,20 @@ static void *do_mount_direct(void *arg)
 	pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &state);
 	if (status) {
 		struct mapent *me;
+		struct statfs fs;
+		unsigned int close_fd = 0;
+
+		if (statfs(mt.name, &fs) == -1 ||
+		   (fs.f_type == AUTOFS_SUPER_MAGIC &&
+		    !master_find_submount(ap, mt.name)))
+			close_fd = 1;
 		cache_writelock(mt.mc);
-		me = cache_lookup_distinct(mt.mc, mt.name);
-		if (me)
+		if (!close_fd && (me = cache_lookup_distinct(mt.mc, mt.name)))
 			me->ioctlfd = mt.ioctlfd;
 		send_ready(ap->logopt, mt.ioctlfd, mt.wait_queue_token);
 		cache_unlock(mt.mc);
+		if (close_fd)
+			close(mt.ioctlfd);
 		info(ap->logopt, "mounted %s", mt.name);
 	} else {
 		send_fail(ap->logopt, mt.ioctlfd, mt.wait_queue_token);

autofs-5.0.3-fix-get-user-info-check.patch:

--- NEW FILE autofs-5.0.3-fix-get-user-info-check.patch ---
autofs-5.0.3 - fix incorrect if check in get user info

From: Ian Kent <raven at themaw.net>

Fix an if statement checking the wrong value in the get user info code.
---

 daemon/direct.c   |    2 +-
 daemon/indirect.c |    2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)


--- autofs-5.0.2.orig/daemon/direct.c
+++ autofs-5.0.2/daemon/direct.c
@@ -1337,7 +1337,7 @@ static void *do_mount_direct(void *arg)
 	}
 
 	tsv->home = strdup(pw.pw_dir);
-	if (!tsv->user) {
+	if (!tsv->home) {
 		error(ap->logopt, "failed to malloc buffer for home");
 		free(pw_tmp);
 		free(tsv->user);
--- autofs-5.0.2.orig/daemon/indirect.c
+++ autofs-5.0.2/daemon/indirect.c
@@ -768,7 +768,7 @@ static void *do_mount_indirect(void *arg
 	}
 
 	tsv->home = strdup(pw.pw_dir);
-	if (!tsv->user) {
+	if (!tsv->home) {
 		error(ap->logopt, "failed to malloc buffer for home");
 		free(pw_tmp);
 		free(tsv->user);

autofs-5.0.3-fix-ifc-buff-size-fix-2.patch:

--- NEW FILE autofs-5.0.3-fix-ifc-buff-size-fix-2.patch ---
autofs-5.0.3 - fix ifc buff size fix 2

From: Ian Kent <raven at themaw.net>

For the case of a large number of interfaces there can be
a lot of malloc(3)s for every mount which could slow things
down. So we remember the maximum allocation size and use it
in subsequent allocations.
---

 modules/replicated.c |   12 ++++++++++--
 1 files changed, 10 insertions(+), 2 deletions(-)


diff --git a/modules/replicated.c b/modules/replicated.c
index 35a6675..b435f4b 100644
--- a/modules/replicated.c
+++ b/modules/replicated.c
@@ -62,7 +62,10 @@
 #ifndef MAX_ERR_BUF
 #define MAX_ERR_BUF		512
 #endif
+
 #define MAX_IFC_BUF		2048
+static int volatile ifc_buf_len = MAX_IFC_BUF;
+static int volatile ifc_last_len = 0;
 
 #define MASK_A  0x7F000000
 #define MASK_B  0xBFFF0000
@@ -97,7 +100,7 @@ void seed_random(void)
 
 static int alloc_ifreq(struct ifconf *ifc, int sock)
 {
-	int ret, lastlen = 0, len = MAX_IFC_BUF;
+	int ret, lastlen = ifc_last_len, len = ifc_buf_len;
 	char err_buf[MAX_ERR_BUF], *buf;
 
 	while (1) {
@@ -119,7 +122,7 @@ static int alloc_ifreq(struct ifconf *ifc, int sock)
 			return 0;
 		}
 
-		if (ifc->ifc_len == lastlen)
+		if (ifc->ifc_len <= lastlen)
 			break;
 
 		lastlen = ifc->ifc_len;
@@ -127,6 +130,11 @@ static int alloc_ifreq(struct ifconf *ifc, int sock)
 		free(buf);
 	}
 
+	if (lastlen != ifc_last_len) {
+		ifc_last_len = lastlen;
+		ifc_buf_len = len;
+	}
+
 	return 1;
 }
 

autofs-5.0.3-fix-ifc-buff-size.patch:

--- NEW FILE autofs-5.0.3-fix-ifc-buff-size.patch ---
autofs-5.0.3 - fix interface config buffer size

From: Ian Kent <raven at themaw.net>

When getting the interface configuration information autofs uses a
fixed size buffer for the interface information. If there are many
interfaces this causes the check to fail.
---

 modules/replicated.c |   51 +++++++++++++++++++++++++++++++++++++++++++--------
 1 file changed, 43 insertions(+), 8 deletions(-)


--- autofs-5.0.2.orig/modules/replicated.c
+++ autofs-5.0.2/modules/replicated.c
@@ -95,6 +95,41 @@ void seed_random(void)
 	return;
 }
 
+static int alloc_ifreq(struct ifconf *ifc, int sock)
+{
+	int ret, lastlen = 0, len = MAX_IFC_BUF;
+	char err_buf[MAX_ERR_BUF], *buf;
+
+	while (1) {
+		buf = malloc(len);
+		if (!buf) {
+			char *estr = strerror_r(errno, err_buf, MAX_ERR_BUF);
+			logerr("malloc: %s", estr);
+			return 0;
+		}
+
+		ifc->ifc_len = sizeof(buf);
+		ifc->ifc_req = (struct ifreq *) buf;
+
+		ret = ioctl(sock, SIOCGIFCONF, ifc);
+		if (ret == -1) {
+			char *estr = strerror_r(errno, err_buf, MAX_ERR_BUF);
+			logerr("ioctl: %s", estr);
+			free(buf);
+			return 0;
+		}
+
+		if (ifc->ifc_len == lastlen)
+			break;
+
+		lastlen = ifc->ifc_len;
+		len += MAX_IFC_BUF;
+		free(buf);
+	}
+
+	return 1;
+}
+
 static unsigned int get_proximity(const char *host_addr, int addr_len)
 {
 	struct sockaddr_in *msk_addr, *if_addr;
@@ -122,12 +157,7 @@ static unsigned int get_proximity(const 
 		fcntl(sock, F_SETFD, cl_flags);
 	}
 
-	ifc.ifc_len = sizeof(buf);
-	ifc.ifc_req = (struct ifreq *) buf;
-	ret = ioctl(sock, SIOCGIFCONF, &ifc);
-	if (ret == -1) {
-		char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
-		logerr("ioctl: %s", estr);
+	if (!alloc_ifreq(&ifc, sock)) {
 		close(sock);
 		return PROXIMITY_ERROR;
 	}
@@ -138,7 +168,7 @@ static unsigned int get_proximity(const 
 	i = 0;
 	ptr = (char *) &ifc.ifc_buf[0];
 
-	while (ptr < buf + ifc.ifc_len) {
+	while (ptr < (char *) ifc.ifc_req + ifc.ifc_len) {
 		ifr = (struct ifreq *) ptr;
 
 		switch (ifr->ifr_addr.sa_family) {
@@ -147,6 +177,7 @@ static unsigned int get_proximity(const 
 			ret = memcmp(&if_addr->sin_addr, hst_addr, addr_len);
 			if (!ret) {
 				close(sock);
+				free(ifc.ifc_req);
 				return PROXIMITY_LOCAL;
 			}
 			break;
@@ -162,7 +193,7 @@ static unsigned int get_proximity(const 
 	i = 0;
 	ptr = (char *) &ifc.ifc_buf[0];
 
-	while (ptr < buf + ifc.ifc_len) {
+	while (ptr < (char *) ifc.ifc_req + ifc.ifc_len) {
 		ifr = (struct ifreq *) ptr;
 
 		switch (ifr->ifr_addr.sa_family) {
@@ -178,6 +209,7 @@ static unsigned int get_proximity(const 
 				char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
 				logerr("ioctl: %s", estr);
 				close(sock);
+				free(ifc.ifc_req);
 				return PROXIMITY_ERROR;
 			}
 
@@ -186,6 +218,7 @@ static unsigned int get_proximity(const 
 
 			if ((ia & mask) == (ha & mask)) {
 				close(sock);
+				free(ifc.ifc_req);
 				return PROXIMITY_SUBNET;
 			}
 
@@ -208,6 +241,7 @@ static unsigned int get_proximity(const 
 
 			if ((ia & mask) == (ha & mask)) {
 				close(sock);
+				free(ifc.ifc_req);
 				return PROXIMITY_NET;
 			}
 			break;
@@ -221,6 +255,7 @@ static unsigned int get_proximity(const 
 	}
 
 	close(sock);
+	free(ifc.ifc_req);
 
 	return PROXIMITY_OTHER;
 }

autofs-5.0.3-fix-included-browse-map-not-found.patch:

--- NEW FILE autofs-5.0.3-fix-included-browse-map-not-found.patch ---
autofs-5.0.3 - fix fail on included browse map not found

From: Ian Kent <raven at themaw.net>

When looking up nsswitch sources, if nsswitch action check tells us
to continue we need to set the returned result to success so we
don't return a false failure.
---

 daemon/lookup.c |    2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)


diff --git a/daemon/lookup.c b/daemon/lookup.c
index 29a1491..3c22a35 100644
--- a/daemon/lookup.c
+++ b/daemon/lookup.c
@@ -545,6 +545,8 @@ int lookup_nss_read_map(struct autofs_point *ap, struct map_source *source, time
 				map = NULL;
 				break;
 			}
+
+			result = NSS_STATUS_SUCCESS;
 		}
 		pthread_cleanup_pop(1);
 

autofs-5.0.3-fix-incorrect-multi-mount-mountpoint.patch:

--- NEW FILE autofs-5.0.3-fix-incorrect-multi-mount-mountpoint.patch ---
autofs-5.0.3 - fix incorrect multi-mount mountpoint

From: Ian Kent <raven at themaw.net>

Fix case where an incorrect mount point path was being used when
mounting a multi-mount component.
---

 modules/parse_sun.c |    8 +++++++-
 1 files changed, 7 insertions(+), 1 deletions(-)


diff --git a/modules/parse_sun.c b/modules/parse_sun.c
index 333f8a5..5a39113 100644
--- a/modules/parse_sun.c
+++ b/modules/parse_sun.c
@@ -1248,8 +1248,14 @@ static int mount_subtree(struct autofs_point *ap, struct mapent *me,
 				return 1;
 			}
 		} else if (rv < 0) {
+			char *mm_root_base = alloca(strlen(mm_root) + strlen(mm_base) + 1);
+	
 			move = MOUNT_MOVE_NONE;
-			ret = mount_multi_triggers(ap, me->multi, mm_root, start, mm_base);
+
+			strcpy(mm_root_base, mm_root);
+			strcat(mm_root_base, mm_base);
+
+			ret = mount_multi_triggers(ap, me->multi, mm_root_base, start, mm_base);
 			if (ret == -1) {
 				error(ap->logopt, MODPREFIX
 					 "failed to mount offset triggers");

autofs-5.0.3-fix-multi-mount-race.patch:

--- NEW FILE autofs-5.0.3-fix-multi-mount-race.patch ---
autofs-5.0.3 - fix multi mount race.

From: Ian Kent <raven at themaw.net>

When using multi-mounts it is possible for a path walk to walk into
a mount tree before it is completely setup which leads to autofs
incorrectly failing to perform mounts.

For example, for the multi-mount

mm1
     /om1       <server1>:/<path1>
     /om2       <server2>:/<path2>
     /om2/om21  <server3>:/<path3>
     /om2/om22  <server3>:/<path4>

when a path walk hits mm1/om2 <serverr2>:/<path2> is mounted on top of
mm1/om2. If a path walk comes along before the multi-mount offsets for
mm1/om2 are setup it doesn't see that mm1/om2 is pending. This happens
because the lookup gets to mm1/om2, which is within the mm1 file system,
and is covered by a mount trigger mounted at mm1/om2, and the the trigger
itself is covered by the <server3>:/<path3> mount. So the walk follows
the stack up to the mount at <server3>:/<path3>, never seeing that the
trigger mm1/om2 is currently pending.

In the example above mm1/om2 could also be a submount.

To resolve this the mount tree needs to be created under a temporary
directory and moved into place once setup in one operation.
---

 daemon/automount.c      |   32 ++-
 daemon/direct.c         |   40 ++--
 daemon/indirect.c       |   55 +++---
 daemon/lookup.c         |    6 
 daemon/state.c          |    2 
 include/automount.h     |   12 -
 include/master.h        |    1 
 include/mounts.h        |    4 
 lib/master.c            |   20 +-
 lib/mounts.c            |   21 +-
 modules/mount_autofs.c  |   61 +++----
 modules/mount_bind.c    |   43 +---
 modules/mount_changer.c |   34 +--
 modules/mount_ext2.c    |   40 +---
 modules/mount_generic.c |   40 +---
 modules/mount_nfs.c     |   41 +---
 modules/parse_sun.c     |  414 ++++++++++++++++++++++++++++++++++++------------
 17 files changed, 519 insertions(+), 347 deletions(-)


--- autofs-5.0.2.orig/daemon/automount.c
+++ autofs-5.0.2/daemon/automount.c
@@ -489,7 +489,7 @@ static int umount_subtree_mounts(struct 
 		pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cur_state);
 		/* Lock the closest parent nesting point for umount */
 		cache_multi_lock(me->parent);
-		if (umount_multi_triggers(ap, root, me, base)) {
+		if (umount_multi_triggers(ap, me, root, base)) {
 			warn(ap->logopt,
 			     "some offset mounts still present under %s", path);
 			left++;
@@ -572,7 +572,7 @@ static int umount_all(struct autofs_poin
 	return left;
 }
 
-int umount_autofs(struct autofs_point *ap, int force)
+int umount_autofs(struct autofs_point *ap, const char *root, int force)
 {
 	int ret = 0;
 
@@ -589,7 +589,7 @@ int umount_autofs(struct autofs_point *a
 	if (ap->type == LKP_INDIRECT) {
 		if (umount_all(ap, force) && !force)
 			return -1;
-		ret = umount_autofs_indirect(ap);
+		ret = umount_autofs_indirect(ap, root);
 	} else
 		ret = umount_autofs_direct(ap);
 
@@ -754,7 +754,7 @@ out_free:
 	return ret;
 }
 
-static int destroy_logpri_fifo(struct autofs_point *ap)
+int destroy_logpri_fifo(struct autofs_point *ap)
 {
 	int ret = -1;
 	int fd = ap->logpri_fifo;
@@ -1056,7 +1056,7 @@ static int autofs_init_ap(struct autofs_
 	return 0;
 }
 
-static int mount_autofs(struct autofs_point *ap)
+static int mount_autofs(struct autofs_point *ap, const char *root)
 {
 	int status = 0;
 
@@ -1066,7 +1066,7 @@ static int mount_autofs(struct autofs_po
 	if (ap->type == LKP_DIRECT)
 		status = mount_autofs_direct(ap);
 	else
-		status = mount_autofs_indirect(ap);
+		status = mount_autofs_indirect(ap, root);
 
 	if (status < 0)
 		return -1;
@@ -1531,10 +1531,12 @@ void *handle_mounts(void *arg)
 	struct startup_cond *suc;
 	struct autofs_point *ap;
 	int cancel_state, status = 0;
+	char *root;
 
 	suc = (struct startup_cond *) arg;
 
 	ap = suc->ap;
+	root = strdup(suc->root);
 
 	pthread_cleanup_push(return_start_status, suc);
 	pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cancel_state);
@@ -1545,14 +1547,24 @@ void *handle_mounts(void *arg)
 		fatal(status);
 	}
 
-	if (mount_autofs(ap) < 0) {
+	if (!root) {
+		crit(ap->logopt, "failed to alloc string root");
+		suc->status = 1;
+		pthread_setcancelstate(cancel_state, NULL);
+		pthread_exit(NULL);
+	}
+
+	if (mount_autofs(ap, root) < 0) {
 		crit(ap->logopt, "mount of %s failed!", ap->path);
 		suc->status = 1;
-		umount_autofs(ap, 1);
+		umount_autofs(ap, root, 1);
+		free(root);
 		pthread_setcancelstate(cancel_state, NULL);
 		pthread_exit(NULL);
 	}
 
+	free(root);
+
 	if (ap->ghost && ap->type != LKP_DIRECT)
 		info(ap->logopt, "ghosting enabled");
 
@@ -1615,7 +1627,7 @@ void *handle_mounts(void *arg)
 			 * to check for possible recovery.
 			 */
 			if (ap->type == LKP_DIRECT) {
-				umount_autofs(ap, 1);
+				umount_autofs(ap, NULL, 1);
 				break;
 			}
 
@@ -1625,7 +1637,7 @@ void *handle_mounts(void *arg)
 			 * so we can continue. This can happen if a lookup
 			 * occurs while we're trying to umount.
 			 */
-			ret = umount_autofs(ap, 1);
+			ret = umount_autofs(ap, NULL, 1);
 			if (!ret)
 				break;
 
--- autofs-5.0.2.orig/daemon/direct.c
+++ autofs-5.0.2/daemon/direct.c
@@ -646,7 +646,7 @@ force_umount:
 	return rv;
 }
 
-int mount_autofs_offset(struct autofs_point *ap, struct mapent *me)
+int mount_autofs_offset(struct autofs_point *ap, struct mapent *me, const char *root, const char *offset)
 {
 	char buf[MAX_ERR_BUF];
 	struct mnt_params *mp;
@@ -654,6 +654,7 @@ int mount_autofs_offset(struct autofs_po
 	struct stat st;
 	int ioctlfd, cl_flags, status, ret;
 	const char *type, *map_name = NULL;
+	char mountpoint[PATH_MAX];
 
 	if (is_mounted(_PROC_MOUNTS, me->key, MNTS_AUTOFS)) {
 		if (ap->state != ST_READMAP)
@@ -695,8 +696,11 @@ int mount_autofs_offset(struct autofs_po
 			return MOUNT_OFFSET_OK;
 	}
 
+	strcpy(mountpoint, root);
+	strcat(mountpoint, offset);
+
 	/* In case the directory doesn't exist, try to mkdir it */
-	if (mkdir_path(me->key, 0555) < 0) {
+	if (mkdir_path(mountpoint, 0555) < 0) {
 		if (errno == EEXIST) {
 			/*
 			 * If the mount point directory is a real mount
@@ -705,7 +709,7 @@ int mount_autofs_offset(struct autofs_po
 			 * the kernel NFS client.
 			 */
 			if (me->multi != me &&
-			    is_mounted(_PATH_MOUNTED, me->key, MNTS_REAL))
+			    is_mounted(_PATH_MOUNTED, mountpoint, MNTS_REAL))
 				return MOUNT_OFFSET_IGNORE;
 
 			/* 
@@ -725,13 +729,13 @@ int mount_autofs_offset(struct autofs_po
 			char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
 			debug(ap->logopt,
 			     "can't create mount directory: %s, %s",
-			     me->key, estr);
+			     mountpoint, estr);
 			return MOUNT_OFFSET_FAIL;
 		} else {
 			char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
 			crit(ap->logopt,
 			     "failed to create mount directory: %s, %s",
-			     me->key, estr);
+			     mountpoint, estr);
 			return MOUNT_OFFSET_FAIL;
 		}
 	} else {
@@ -741,7 +745,7 @@ int mount_autofs_offset(struct autofs_po
 
 	debug(ap->logopt,
 	      "calling mount -t autofs " SLOPPY " -o %s automount %s",
-	      mp->options, me->key);
+	      mp->options, mountpoint);
 
 	type = ap->entry->maps->type;
 	if (type && !strcmp(ap->entry->maps->type, "hosts")) {
@@ -753,22 +757,18 @@ int mount_autofs_offset(struct autofs_po
 	} else
 		map_name = me->mc->map->argv[0];
 
-	ret = mount(map_name, me->key, "autofs", MS_MGC_VAL, mp->options);
+	ret = mount(map_name, mountpoint, "autofs", MS_MGC_VAL, mp->options);
 	if (ret) {
-		crit(ap->logopt, "failed to mount autofs path %s", me->key);
-		goto out_err;
-	}
-
-	if (ret != 0) {
 		crit(ap->logopt,
-		     "failed to mount autofs offset trigger %s", me->key);
+		     "failed to mount offset trigger %s at %s",
+		     me->key, mountpoint);
 		goto out_err;
 	}
 
 	/* Root directory for ioctl()'s */
-	ioctlfd = open(me->key, O_RDONLY);
+	ioctlfd = open(mountpoint, O_RDONLY);
 	if (ioctlfd < 0) {
-		crit(ap->logopt, "failed to create ioctl fd for %s", me->key);
+		crit(ap->logopt, "failed to create ioctl fd for %s", mountpoint);
 		goto out_umount;
 	}
 
@@ -782,7 +782,7 @@ int mount_autofs_offset(struct autofs_po
 	ret = fstat(ioctlfd, &st);
 	if (ret == -1) {
 		error(ap->logopt,
-		     "failed to stat direct mount trigger %s", me->key);
+		     "failed to stat direct mount trigger %s", mountpoint);
 		goto out_close;
 	}
 
@@ -790,17 +790,17 @@ int mount_autofs_offset(struct autofs_po
 
 	close(ioctlfd);
 
-	debug(ap->logopt, "mounted trigger %s", me->key);
+	debug(ap->logopt, "mounted trigger %s at %s", me->key, mountpoint);
 
 	return MOUNT_OFFSET_OK;
 
 out_close:
 	close(ioctlfd);
 out_umount:
-	umount(me->key);
+	umount(mountpoint);
 out_err:
-	if (stat(me->key, &st) == 0 && me->dir_created)
-		 rmdir_path(ap, me->key, st.st_dev);
+	if (stat(mountpoint, &st) == 0 && me->dir_created)
+		 rmdir_path(ap, mountpoint, st.st_dev);
 
 	return MOUNT_OFFSET_FAIL;
 }
--- autofs-5.0.2.orig/daemon/indirect.c
+++ autofs-5.0.2/daemon/indirect.c
@@ -83,7 +83,7 @@ static int unlink_mount_tree(struct auto
 	return ret;
 }
 
-static int do_mount_autofs_indirect(struct autofs_point *ap)
+static int do_mount_autofs_indirect(struct autofs_point *ap, const char *root)
 {
 	time_t timeout = ap->exp_timeout;
 	char *options = NULL;
@@ -109,11 +109,11 @@ static int do_mount_autofs_indirect(stru
 		goto out_err;
 
 	/* In case the directory doesn't exist, try to mkdir it */
-	if (mkdir_path(ap->path, 0555) < 0) {
+	if (mkdir_path(root, 0555) < 0) {
 		if (errno != EEXIST && errno != EROFS) {
 			crit(ap->logopt,
 			     "failed to create autofs directory %s",
-			     ap->path);
+			     root);
 			goto out_err;
 		}
 		/* If we recieve an error, and it's EEXIST or EROFS we know
@@ -134,9 +134,10 @@ static int do_mount_autofs_indirect(stru
 	} else
 		map_name = ap->entry->maps->argv[0];
 
-	ret = mount(map_name, ap->path, "autofs", MS_MGC_VAL, options);
+	ret = mount(map_name, root, "autofs", MS_MGC_VAL, options);
 	if (ret) {
-		crit(ap->logopt, "failed to mount autofs path %s", ap->path);
+		crit(ap->logopt,
+		     "failed to mount autofs path %s at %s", ap->path, root);
 		goto out_rmdir;
 	}
 
@@ -145,7 +146,7 @@ static int do_mount_autofs_indirect(stru
 	options = NULL;
 
 	/* Root directory for ioctl()'s */
-	ap->ioctlfd = open(ap->path, O_RDONLY);
+	ap->ioctlfd = open(root, O_RDONLY);
 	if (ap->ioctlfd < 0) {
 		crit(ap->logopt,
 		     "failed to create ioctl fd for autofs path %s", ap->path);
@@ -163,13 +164,13 @@ static int do_mount_autofs_indirect(stru
 
 	if (ap->exp_timeout)
 		info(ap->logopt,
-		    "mounted indirect mount on %s "
+		    "mounted indirect mount for %s "
 		    "with timeout %u, freq %u seconds", ap->path,
 	 	    (unsigned int) ap->exp_timeout,
 		    (unsigned int) ap->exp_runfreq);
 	else
 		info(ap->logopt,
-		    "mounted indirect mount on %s with timeouts disabled",
+		    "mounted indirect mount for %s with timeouts disabled",
 		    ap->path);
 
 	fstat(ap->ioctlfd, &st);
@@ -178,10 +179,10 @@ static int do_mount_autofs_indirect(stru
 	return 0;
 
 out_umount:
-	umount(ap->path);
+	umount(root);
 out_rmdir:
 	if (ap->dir_created)
-		rmdir_path(ap, ap->path, ap->dev);
+		rmdir(root);
 out_err:
 	if (options)
 		free(options);
@@ -193,7 +194,7 @@ out_err:
 	return -1;
 }
 
-int mount_autofs_indirect(struct autofs_point *ap)
+int mount_autofs_indirect(struct autofs_point *ap, const char *root)
 {
 	time_t now = time(NULL);
 	int status;
@@ -207,11 +208,11 @@ int mount_autofs_indirect(struct autofs_
 		return -1;
 	}
 
-	status = do_mount_autofs_indirect(ap);
+	status = do_mount_autofs_indirect(ap, root);
 	if (status < 0)
 		return -1;
 
-	map = lookup_ghost(ap);
+	map = lookup_ghost(ap, root);
 	if (map & LKP_FAIL) {
 		if (map & LKP_DIRECT) {
 			error(ap->logopt,
@@ -230,7 +231,7 @@ int mount_autofs_indirect(struct autofs_
 	return 0;
 }
 
-static void close_mount_fds(struct autofs_point *ap)
+void close_mount_fds(struct autofs_point *ap)
 {
 	/*
 	 * Since submounts look after themselves the parent never knows
@@ -255,11 +256,17 @@ static void close_mount_fds(struct autof
 	return;
 }
 
-int umount_autofs_indirect(struct autofs_point *ap)
+int umount_autofs_indirect(struct autofs_point *ap, const char *root)
 {
 	char buf[MAX_ERR_BUF];
+	char mountpoint[PATH_MAX + 1];
 	int ret, rv, retries;
 
+	if (root)
+		strcpy(mountpoint, root);
+	else
+		strcpy(mountpoint, ap->path);
+
 	/* If we are trying to shutdown make sure we can umount */
 	rv = ioctl(ap->ioctlfd, AUTOFS_IOC_ASKUMOUNT, &ret);
 	if (rv == -1) {
@@ -284,7 +291,7 @@ int umount_autofs_indirect(struct autofs
 	sched_yield();
 
 	retries = UMOUNT_RETRIES;
-	while ((rv = umount(ap->path)) == -1 && retries--) {
+	while ((rv = umount(mountpoint)) == -1 && retries--) {
 		struct timespec tm = {0, 200000000};
 		if (errno != EBUSY)
 			break;
@@ -296,13 +303,13 @@ int umount_autofs_indirect(struct autofs
 		case ENOENT:
 		case EINVAL:
 			error(ap->logopt,
-			      "mount point %s does not exist", ap->path);
+			      "mount point %s does not exist", mountpoint);
 			close_mount_fds(ap);
 			return 0;
 			break;
 		case EBUSY:
 			debug(ap->logopt,
-			      "mount point %s is in use", ap->path);
+			      "mount point %s is in use", mountpoint);
 			if (ap->state == ST_SHUTDOWN_FORCE) {
 				close_mount_fds(ap);
 				goto force_umount;
@@ -321,11 +328,11 @@ int umount_autofs_indirect(struct autofs
 					return 0;
 				}
 #endif
-				ap->ioctlfd = open(ap->path, O_RDONLY);
+				ap->ioctlfd = open(mountpoint, O_RDONLY);
 				if (ap->ioctlfd < 0) {
 					warn(ap->logopt,
 					     "could not recover autofs path %s",
-					     ap->path);
+					     mountpoint);
 					close_mount_fds(ap);
 					return 0;
 				}
@@ -355,12 +362,12 @@ int umount_autofs_indirect(struct autofs
 force_umount:
 	if (rv != 0) {
 		warn(ap->logopt,
-		     "forcing umount of indirect mount %s", ap->path);
-		rv = umount2(ap->path, MNT_DETACH);
+		     "forcing umount of indirect mount %s", mountpoint);
+		rv = umount2(mountpoint, MNT_DETACH);
 	} else {
-		info(ap->logopt, "umounted indirect mount %s", ap->path);
+		info(ap->logopt, "umounted indirect mount %s", mountpoint);
 		if (ap->submount)
-			rm_unwanted(ap->logopt, ap->path, 1, ap->dev);
+			rm_unwanted(ap->logopt, mountpoint, 1, ap->dev);
 	}
 
 	return rv;
--- autofs-5.0.2.orig/daemon/lookup.c
+++ autofs-5.0.2/daemon/lookup.c
@@ -565,7 +565,7 @@ int lookup_nss_read_map(struct autofs_po
 	return 0;
 }
 
-int lookup_ghost(struct autofs_point *ap)
+int lookup_ghost(struct autofs_point *ap, const char *root)
 {
 	struct master_mapent *entry = ap->entry;
 	struct map_source *map;
@@ -611,12 +611,12 @@ int lookup_ghost(struct autofs_point *ap
 				goto next;
 			}
 
-			fullpath = alloca(strlen(me->key) + strlen(ap->path) + 3);
+			fullpath = alloca(strlen(me->key) + strlen(root) + 3);
 			if (!fullpath) {
 				warn(ap->logopt, "failed to allocate full path");
 				goto next;
 			}
-			sprintf(fullpath, "%s/%s", ap->path, me->key);
+			sprintf(fullpath, "%s/%s", root, me->key);
 
 			ret = stat(fullpath, &st);
 			if (ret == -1 && errno != ENOENT) {
--- autofs-5.0.2.orig/daemon/state.c
+++ autofs-5.0.2/daemon/state.c
@@ -393,7 +393,7 @@ static void *do_readmap(void *arg)
 
 	if (ap->type == LKP_INDIRECT) {
 		lookup_prune_cache(ap, now);
-		status = lookup_ghost(ap);
+		status = lookup_ghost(ap, ap->path);
 	} else {
 		struct mapent *me, *ne, *nested;
 		mnts = tree_make_mnt_tree(_PROC_MOUNTS, "/");
--- autofs-5.0.2.orig/include/automount.h
+++ autofs-5.0.2/include/automount.h
@@ -230,7 +230,7 @@ int lookup_nss_read_master(struct master
 int lookup_nss_read_map(struct autofs_point *ap, struct map_source *source, time_t age);
 int lookup_enumerate(struct autofs_point *ap,
 	int (*fn)(struct autofs_point *,struct mapent *, int), time_t now);
-int lookup_ghost(struct autofs_point *ap);
+int lookup_ghost(struct autofs_point *ap, const char *root);
 int lookup_nss_mount(struct autofs_point *ap, struct map_source *source, const char *name, int name_len);
 void lookup_close_lookup(struct autofs_point *ap);
 int lookup_prune_cache(struct autofs_point *ap, time_t age);
@@ -332,6 +332,7 @@ struct startup_cond {
 	pthread_mutex_t mutex;
 	pthread_cond_t  cond;
 	struct autofs_point *ap;
+	char *root;
 	unsigned int done;
 	unsigned int status;
 };
@@ -427,12 +428,13 @@ int do_expire(struct autofs_point *ap, c
 void *expire_proc_indirect(void *);
 void *expire_proc_direct(void *);
 int expire_offsets_direct(struct autofs_point *ap, struct mapent *me, int now);
-int mount_autofs_indirect(struct autofs_point *ap);
+int mount_autofs_indirect(struct autofs_point *ap, const char *root);
 int mount_autofs_direct(struct autofs_point *ap);
-int mount_autofs_offset(struct autofs_point *ap, struct mapent *me);
+int mount_autofs_offset(struct autofs_point *ap, struct mapent *me, const char *root, const char *offset);
 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);
+void close_mount_fds(struct autofs_point *ap);
+int umount_autofs(struct autofs_point *ap, const char *root, int force);
+int umount_autofs_indirect(struct autofs_point *ap, const char *root);
 int do_umount_autofs_direct(struct autofs_point *ap, struct mnt_list *mnts, struct mapent *me);
 int umount_autofs_direct(struct autofs_point *ap);
 int umount_autofs_offset(struct autofs_point *ap, struct mapent *me);
--- autofs-5.0.2.orig/include/master.h
+++ autofs-5.0.2/include/master.h
@@ -91,6 +91,7 @@ void master_source_lock_cleanup(void *);
 void master_source_current_wait(struct master_mapent *);
 void master_source_current_signal(struct master_mapent *);
 struct master_mapent *master_find_mapent(struct master *, const char *);
+struct autofs_point *__master_find_submount(struct autofs_point *, const char *);
 struct autofs_point *master_find_submount(struct autofs_point *, const char *);
 struct master_mapent *master_new_mapent(struct master *, const char *, time_t);
 void master_add_mapent(struct master *, struct master_mapent *);
--- autofs-5.0.2.orig/include/mounts.h
+++ autofs-5.0.2/include/mounts.h
@@ -85,7 +85,7 @@ int tree_find_mnt_ents(struct mnt_list *
 int tree_is_mounted(struct mnt_list *mnts, const char *path, unsigned int type);
 void set_tsd_user_vars(unsigned int, uid_t, gid_t);
 int umount_ent(struct autofs_point *, const char *);
-int mount_multi_triggers(struct autofs_point *, char *, struct mapent *, const char *);
-int umount_multi_triggers(struct autofs_point *, char *, struct mapent *, const char *);
+int mount_multi_triggers(struct autofs_point *, struct mapent *, const char *, unsigned int, const char *);
+int umount_multi_triggers(struct autofs_point *, struct mapent *, char *, const char *);
 
 #endif
--- autofs-5.0.2.orig/lib/master.c
+++ autofs-5.0.2/lib/master.c
@@ -602,27 +602,32 @@ struct master_mapent *master_find_mapent
 	return NULL;
 }
 
-struct autofs_point *master_find_submount(struct autofs_point *ap, const char *path)
+struct autofs_point *__master_find_submount(struct autofs_point *ap, const char *path)
 {
 	struct list_head *head, *p;
 
-	mounts_mutex_lock(ap);
-
 	head = &ap->submounts;
 	list_for_each(p, head) {
 		struct autofs_point *submount;
 
 		submount = list_entry(p, struct autofs_point, mounts);
 
-		if (!strcmp(submount->path, path)) {
-			mounts_mutex_unlock(ap);
+		if (!strcmp(submount->path, path))
 			return submount;
-		}
 	}
 
+	return NULL;
+}
+
+struct autofs_point *master_find_submount(struct autofs_point *ap, const char *path)
+{
+	struct autofs_point *submount;
+
+	mounts_mutex_lock(ap);
+	submount = __master_find_submount(ap, path);
 	mounts_mutex_unlock(ap);
 
-	return NULL;
+	return submount;
 }
 
 struct master_mapent *master_new_mapent(struct master *master, const char *path, time_t age)
@@ -955,6 +960,7 @@ static int master_do_mount(struct master
 	}
 
 	suc.ap = ap;
+	suc.root = ap->path;
 	suc.done = 0;
 	suc.status = 0;
 
--- autofs-5.0.2.orig/lib/mounts.c
+++ autofs-5.0.2/lib/mounts.c
@@ -1105,7 +1105,8 @@ int umount_ent(struct autofs_point *ap, 
 	return rv;
 }
 
-int mount_multi_triggers(struct autofs_point *ap, char *root, struct mapent *me, const char *base)
+int mount_multi_triggers(struct autofs_point *ap, struct mapent *me,
+			 const char *root, unsigned int start, const char *base)
 {
 	char path[PATH_MAX + 1];
 	char *offset = path;
@@ -1113,17 +1114,13 @@ int mount_multi_triggers(struct autofs_p
 	struct list_head *pos = NULL;
 	unsigned int fs_path_len;
 	unsigned int mounted;
-	int ret, start;
+	int ret;
 
-	fs_path_len = strlen(root) + strlen(base);
+	fs_path_len = start + strlen(base);
 	if (fs_path_len > PATH_MAX)
 		return -1;
 
-	strcpy(path, root);
-	strcat(path, base);
-
 	mounted = 0;
-	start = strlen(root);
 	offset = cache_get_offset(base, offset, start, &me->multi_list, &pos);
 	while (offset) {
 		int plen = fs_path_len + strlen(offset);
@@ -1137,9 +1134,9 @@ int mount_multi_triggers(struct autofs_p
 		if (!oe || !oe->mapent)
 			goto cont;
 
-		debug(ap->logopt, "mount offset %s", oe->key);
+		debug(ap->logopt, "mount offset %s at %s", oe->key, root);
 
-		ret = mount_autofs_offset(ap, oe);
+		ret = mount_autofs_offset(ap, oe, root, offset);
 		if (ret >= MOUNT_OFFSET_OK)
 			mounted++;
 		else {
@@ -1161,7 +1158,7 @@ cont:
 	return mounted;
 }
 
-int umount_multi_triggers(struct autofs_point *ap, char *root, struct mapent *me, const char *base)
+int umount_multi_triggers(struct autofs_point *ap, struct mapent *me, char *root, const char *base)
 {
 	char path[PATH_MAX + 1];
 	char *offset;
@@ -1198,7 +1195,7 @@ int umount_multi_triggers(struct autofs_
 		 * nonstrict mount fail.
 		 */
 		oe_base = oe->key + strlen(root);
-		left += umount_multi_triggers(ap, root, oe, oe_base);
+		left += umount_multi_triggers(ap, oe, root, oe_base);
 
 		if (oe->ioctlfd != -1)
 			left++;
@@ -1238,7 +1235,7 @@ int umount_multi_triggers(struct autofs_
 		if (is_mounted(_PATH_MOUNTED, root, MNTS_REAL)) {
 			info(ap->logopt, "unmounting dir = %s", root);
 			if (umount_ent(ap, root)) {
-				if (mount_multi_triggers(ap, root, me, "/") < 0)
+				if (mount_multi_triggers(ap, me, root, strlen(root), "/") < 0)
 					warn(ap->logopt,
 					     "failed to remount offset triggers");
 				return left++;
--- autofs-5.0.2.orig/modules/mount_autofs.c
+++ autofs-5.0.2/modules/mount_autofs.c
@@ -48,7 +48,7 @@ int mount_mount(struct autofs_point *ap,
 {
 	struct startup_cond suc;
 	pthread_t thid;
-	char *fullpath;
+	char *realpath, *mountpoint;
 	const char **argv;
 	int argc, status, ghost = ap->ghost;
 	time_t timeout = ap->exp_timeout;
@@ -60,32 +60,32 @@ int mount_mount(struct autofs_point *ap,
 	struct autofs_point *nap;
 	char buf[MAX_ERR_BUF];
 	char *options, *p;
-	int ret;
-
-	fullpath = alloca(strlen(root) + name_len + 2);
-	if (!fullpath) {
-		char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
-		logerr(MODPREFIX "alloca: %s", estr);
-		return 1;
-	}
+	int len, ret;
 
 	/* 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,
-		      MODPREFIX 
-		      "warning: about to mount over %s, continuing",
-		      fullpath);
-		return 0;
+	len = strlen(root);
+	if (root[len - 1] == '/') {
+		realpath = alloca(strlen(ap->path) + name_len + 2);
+		mountpoint = alloca(len + 1);
+		strcpy(realpath, ap->path);
+		strcat(realpath, "/");
+		strcat(realpath, name);
+		len--;
+		strncpy(mountpoint, root, len);
+		mountpoint[len] = '\0';
+	} else if (*name == '/') {
+		realpath = alloca(name_len + 1);
+		mountpoint = alloca(len + 1);
+		strcpy(mountpoint, root);
+		strcpy(realpath, name);
+	} else {
+		realpath = alloca(len + name_len + 2);
+		mountpoint = alloca(len + name_len + 2);
+		strcpy(mountpoint, root);
+		strcat(mountpoint, "/");
+		strcpy(realpath, mountpoint);
+		strcat(mountpoint, name);
+		strcat(realpath, name);
 	}
 
 	options = NULL;
@@ -136,12 +136,12 @@ int mount_mount(struct autofs_point *ap,
 	}
 
 	debug(ap->logopt,
-	      MODPREFIX "fullpath=%s what=%s options=%s",
-	      fullpath, what, options);
+	      MODPREFIX "mountpoint=%s what=%s options=%s",
+	      mountpoint, what, options);
 
 	master = ap->entry->master;
 
-	entry = master_new_mapent(master, fullpath, ap->entry->age);
+	entry = master_new_mapent(master, realpath, ap->entry->age);
 	if (!entry) {
 		error(ap->logopt,
 		      MODPREFIX "failed to malloc master_mapent struct");
@@ -228,6 +228,7 @@ int mount_mount(struct autofs_point *ap,
 	}
 
 	suc.ap = nap;
+	suc.root = mountpoint;
 	suc.done = 0;
 	suc.status = 0;
 
@@ -235,7 +236,7 @@ int mount_mount(struct autofs_point *ap,
 		crit(ap->logopt,
 		     MODPREFIX
 		     "failed to create mount handler thread for %s",
-		     fullpath);
+		     realpath);
 		handle_mounts_startup_cond_destroy(&suc);
 		mounts_mutex_unlock(ap);
 		master_free_map_source(source, 1);
@@ -256,7 +257,7 @@ int mount_mount(struct autofs_point *ap,
 
 	if (suc.status) {
 		crit(ap->logopt,
-		     MODPREFIX "failed to create submount for %s", fullpath);
+		     MODPREFIX "failed to create submount for %s", realpath);
 		handle_mounts_startup_cond_destroy(&suc);
 		mounts_mutex_unlock(ap);
 		master_free_map_source(source, 1);
--- autofs-5.0.2.orig/modules/mount_bind.c
+++ autofs-5.0.2/modules/mount_bind.c
@@ -74,34 +74,24 @@ int mount_mount(struct autofs_point *ap,
 	char *fullpath;
 	char buf[MAX_ERR_BUF];
 	int err;
-	int i, rlen;
+	int i, len;
 
 	/* Root offset of multi-mount */
-	if (*name == '/' && name_len == 1) {
-		rlen = strlen(root);
-		name_len = 0;
+	len = strlen(root);
+	if (root[len - 1] == '/') {
+		fullpath = alloca(len);
+		len = snprintf(fullpath, len, "%s", root);
 	/* Direct mount name is absolute path so don't use root */
-	} else if (*name == '/')
-		rlen = 0;
-	else
-		rlen = strlen(root);
-
-	fullpath = alloca(rlen + name_len + 2);
-	if (!fullpath) {
-		char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
-		logerr(MODPREFIX "alloca: %s", estr);
-		return 1;
+	} else if (*name == '/') {
+		fullpath = alloca(len + 1);
+		len = sprintf(fullpath, "%s", root);
+	} else {
+		fullpath = alloca(len + name_len + 2);
+		len = sprintf(fullpath, "%s/%s", root, name);
 	}
+	fullpath[len] = '\0';
 
-	if (name_len) {
-		if (rlen)
-			sprintf(fullpath, "%s/%s", root, name);
-		else
-			sprintf(fullpath, "%s", name);
-	} else
-		sprintf(fullpath, "%s", root);
-
-	i = strlen(fullpath);
+	i = len;
 	while (--i > 0 && fullpath[i] == '/')
 		fullpath[i] = '\0';
 
@@ -125,13 +115,6 @@ int mount_mount(struct autofs_point *ap,
 		if (!status)
 			existed = 0;
 
-		if (is_mounted(_PATH_MOUNTED, fullpath, MNTS_REAL)) {
-			error(ap->logopt,
-			      MODPREFIX "warning: %s is already mounted",
-			      fullpath);
-			return 0;
-		}
-
 		debug(ap->logopt,
 		      MODPREFIX
 		      "calling mount --bind " SLOPPY " -o %s %s %s",
--- autofs-5.0.2.orig/modules/mount_changer.c
+++ autofs-5.0.2/modules/mount_changer.c
@@ -49,34 +49,24 @@ int mount_mount(struct autofs_point *ap,
 	char *fullpath;
 	char buf[MAX_ERR_BUF];
 	int err;
-	int rlen, status, existed = 1;
+	int len, status, existed = 1;
 
 	fstype = "iso9660";
 
 	/* Root offset of multi-mount */
-	if (*name == '/' && name_len == 1) {
-		rlen = strlen(root);
-		 name_len = 0;
+	len = strlen(root);
+	if (root[len - 1] == '/') {
+		fullpath = alloca(len);
+		len = snprintf(fullpath, len, "%s", root);
 	/* Direct mount name is absolute path so don't use root */
-	} else if (*name == '/')
-		rlen = 0;
-	else
-		rlen = strlen(root);
-
-	fullpath = alloca(rlen + name_len + 2);
-	if (!fullpath) {
-		char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
-		logerr(MODPREFIX "alloca: %s", estr);
-		return 1;
+	} else if (*name == '/') {
+		fullpath = alloca(len + 1);
+		len = sprintf(fullpath, "%s", root);
+	} else {
+		fullpath = alloca(len + name_len + 2);
+		len = sprintf(fullpath, "%s/%s", root, name);
 	}
-
-	if (name_len) {
-		if (rlen)
-			sprintf(fullpath, "%s/%s", root, name);
-		else
-			sprintf(fullpath, "%s", name);
-	} else
-		sprintf(fullpath, "%s", root);
+	fullpath[len] = '\0';
 
 	debug(ap->logopt, MODPREFIX "calling umount %s", what);
 
--- autofs-5.0.2.orig/modules/mount_ext2.c
+++ autofs-5.0.2/modules/mount_ext2.c
@@ -43,32 +43,22 @@ int mount_mount(struct autofs_point *ap,
 	const char *p, *p1;
 	int err, ro = 0;
 	const char *fsck_prog;
-	int rlen, status, existed = 1;
+	int len, status, existed = 1;
 
 	/* Root offset of multi-mount */
-	if (*name == '/' && name_len == 1) {
-		rlen = strlen(root);
-		name_len = 0;
+	len = strlen(root);
+	if (root[len - 1] == '/') {
+		fullpath = alloca(len);
+		len = snprintf(fullpath, len, "%s", root);
 	/* Direct mount name is absolute path so don't use root */
-	} else if (*name == '/')
-		rlen = 0;
-	else
-		rlen = strlen(root);
-
-	fullpath = alloca(rlen + name_len + 2);
-	if (!fullpath) {
-		char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
-		logerr(MODPREFIX "alloca: %s", estr);
-		return 1;
+	} else if (*name == '/') {
+		fullpath = alloca(len + 1);
+		len = sprintf(fullpath, "%s", root);
+	} else {
+		fullpath = alloca(len + name_len + 2);
+		len = sprintf(fullpath, "%s/%s", root, name);
 	}
-
-	if (name_len) {
-		if (rlen)
-			sprintf(fullpath, "%s/%s", root, name);
-		else
-			sprintf(fullpath, "%s", name);
-	} else
-		sprintf(fullpath, "%s", root);
+	fullpath[len] = '\0';
 
 	debug(ap->logopt, MODPREFIX "calling mkdir_path %s", fullpath);
 
@@ -83,12 +73,6 @@ int mount_mount(struct autofs_point *ap,
 	if (!status)
 		existed = 0;
 
-	if (is_mounted(_PATH_MOUNTED, fullpath, MNTS_REAL)) {
-		error(ap->logopt,
-		      MODPREFIX "warning: %s is already mounted", fullpath);
-		return 0;
-	}
-
 	if (options && options[0]) {
 		for (p = options; (p1 = strchr(p, ',')); p = p1)
 			if (!strncmp(p, "ro", p1 - p) && ++p1 - p == sizeof("ro"))
--- autofs-5.0.2.orig/modules/mount_generic.c
+++ autofs-5.0.2/modules/mount_generic.c
@@ -42,32 +42,22 @@ int mount_mount(struct autofs_point *ap,
 	char *fullpath;
 	char buf[MAX_ERR_BUF];
 	int err;
-	int rlen, status, existed = 1;
+	int len, status, existed = 1;
 
 	/* Root offset of multi-mount */
-	if (*name == '/' && name_len == 1) {
-		rlen = strlen(root);
-		name_len = 0;
+	len = strlen(root);
+	if (root[len - 1] == '/') {
+		fullpath = alloca(len);
+		len = snprintf(fullpath, len, "%s", root);
 	/* Direct mount name is absolute path so don't use root */
-	} else if (*name == '/')
-		rlen = 0;
-	else
-		rlen = strlen(root);
-
-	fullpath = alloca(rlen + name_len + 2);
-	if (!fullpath) {
-		char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
-		logerr(MODPREFIX "alloca: %s", estr);
-		return 1;
+	} else if (*name == '/') {
+		fullpath = alloca(len + 1);
+		len = sprintf(fullpath, "%s", root);
+	} else {
+		fullpath = alloca(len + name_len + 2);
+		len = sprintf(fullpath, "%s/%s", root, name);
 	}
-
-	if (name_len) {
-		if (rlen)
-			sprintf(fullpath, "%s/%s", root, name);
-		else
-			sprintf(fullpath, "%s", name);
-	} else
-		sprintf(fullpath, "%s", root);
+	fullpath[len] = '\0';
 
 	debug(ap->logopt, MODPREFIX "calling mkdir_path %s", fullpath);
 
@@ -82,12 +72,6 @@ int mount_mount(struct autofs_point *ap,
 	if (!status)
 		existed = 0;
 
-	if (is_mounted(_PATH_MOUNTED, fullpath, MNTS_REAL)) {
-		error(ap->logopt,
-		      MODPREFIX "warning: %s is already mounted", fullpath);
-		return 0;
-	}
-
 	if (options && options[0]) {
 		debug(ap->logopt,
 		      MODPREFIX "calling mount -t %s " SLOPPY "-o %s %s %s",
--- autofs-5.0.2.orig/modules/mount_nfs.c
+++ autofs-5.0.2/modules/mount_nfs.c
@@ -64,7 +64,7 @@ int mount_mount(struct autofs_point *ap,
 	struct host *this, *hosts = NULL;
 	unsigned int vers;
 	char *nfsoptions = NULL;
-	int len, rlen, status, err, existed = 1;
+	int len, status, err, existed = 1;
 	int nosymlink = 0;
 	int ro = 0;            /* Set if mount bind should be read-only */
 
@@ -146,30 +146,18 @@ int mount_mount(struct autofs_point *ap,
 	/* Construct and perhaps create mount point directory */
 
 	/* Root offset of multi-mount */
-	if (*name == '/' && name_len == 1) {
-		rlen = strlen(root);
-		name_len = 0;
+	len = strlen(root);
+	if (root[len - 1] == '/') {
+		fullpath = alloca(len);
+		len = snprintf(fullpath, len, "%s", root);
 	/* Direct mount name is absolute path so don't use root */
-	} else if (*name == '/')
-		rlen = 0;
-	else
-		rlen = strlen(root);
-
-	fullpath = alloca(rlen + name_len + 2);
-	if (!fullpath) {
-		char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
-		logerr(MODPREFIX "alloca: %s", estr);
-		free_host_list(&hosts);
-		return 1;
-	}
-
-	if (name_len) {
-		if (rlen)
-			len = sprintf(fullpath, "%s/%s", root, name);
-		else
-			len = sprintf(fullpath, "%s", name);
-	} else
+	} else if (*name == '/') {
+		fullpath = alloca(len + 1);
 		len = sprintf(fullpath, "%s", root);
+	} else {
+		fullpath = alloca(len + name_len + 2);
+		len = sprintf(fullpath, "%s/%s", root, name);
+	}
 	fullpath[len] = '\0';
 
 	debug(ap->logopt, MODPREFIX "calling mkdir_path %s", fullpath);
@@ -189,13 +177,6 @@ int mount_mount(struct autofs_point *ap,
 	while (this) {
 		char *loc, *port_opt = NULL;
 
-		if (is_mounted(_PATH_MOUNTED, fullpath, MNTS_REAL)) {
-			error(ap->logopt,
-			      MODPREFIX
-			      "warning: %s is already mounted", fullpath);
-			break;
-		}
-
 		/*
 		 * If the "port" option is specified, then we don't want
 		 * a bind mount. Use the "port" option if you want to
--- autofs-5.0.2.orig/modules/parse_sun.c
+++ autofs-5.0.2/modules/parse_sun.c
@@ -31,12 +31,18 @@
 #include <sys/vfs.h>
 #include <sys/utsname.h>
 #include <netinet/in.h>
+#include <sys/mount.h>
+#include <linux/fs.h>
 
 #define MODULE_PARSE
 #include "automount.h"
 
 #define MODPREFIX "parse(sun): "
 
+#define MOUNT_MOVE_NONE		0x00
+#define MOUNT_MOVE_AUTOFS	0x01
+#define MOUNT_MOVE_OTHER	0x02
+
 int parse_version = AUTOFS_PARSE_VERSION;	/* Required by protocol */
 
 static struct mount_mod *mount_nfs = NULL;
@@ -67,6 +73,7 @@ static struct parse_context default_cont
 	1			/* Do slashify_colons */
 };
 
+int destroy_logpri_fifo(struct autofs_point *ap);
 static char *concat_options(char *left, char *right);
 
 /* Free all storage associated with this context */
@@ -756,8 +763,10 @@ add_offset_entry(struct autofs_point *ap
 
 	p_len = strlen(path);
 	/* Trailing '/' causes us pain */
-	if (p_len > 1 && path[p_len - 1] == '/')
-		p_len--;
+	if (p_len > 1) {
+		while (p_len > 1 && 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");
@@ -961,53 +970,318 @@ static int parse_mapent(const char *ent,
 	return (p - ent);
 }
 
-static int mount_subtree_offsets(struct autofs_point *ap, struct mapent_cache *mc, struct mapent *me)
+static int move_mount(struct autofs_point *ap,
+		      const char *mm_tmp_root, const char *mm_root,
+		      unsigned int move)
 {
-	struct mapent *mm;
-	char *m_key;
-	int ret, start;
-	char *base, *m_root;
 	char buf[MAX_ERR_BUF];
+	int err;
 
-	mm = me->multi;
+	if (move == MOUNT_MOVE_NONE)
+		return 1;
+
+	err = mkdir_path(mm_root, 0555);
+	if (err < 0 && errno != EEXIST) {
+		error(ap->logopt,
+		      "failed to create move target mount point %s", mm_root);
+		return 0;
+	}
 
-	if (!mm)
+	if (move == MOUNT_MOVE_AUTOFS)
+		err = mount(mm_tmp_root, mm_root, NULL, MS_MOVE, NULL);
+	else
+		err = spawn_mount(ap->logopt,
+				  "--move", mm_tmp_root, mm_root, NULL);
+	if (err) {
+		char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
+		error(ap->logopt,
+		      "failed to move mount from %s to %s: %s",
+		      mm_tmp_root, mm_root, estr);
 		return 0;
+	}
+
+	debug(ap->logopt,
+	      "moved mount tree from %s to %s", mm_tmp_root, mm_root);
+
+	return 1;
+}
+
+static void cleanup_multi_root(struct autofs_point *ap, const char *root,
+					 const char *path, unsigned int move)
+{
+	if (move == MOUNT_MOVE_NONE)
+		return;
+
+	if (move == MOUNT_MOVE_OTHER)
+		spawn_umount(ap->logopt, root, NULL);
+	else {
+		struct autofs_point *submount;
+
+		mounts_mutex_lock(ap);
+		submount = __master_find_submount(ap, path);
+		if (!submount) {
+			mounts_mutex_unlock(ap);
+			return;
+		}
+
+		alarm_delete(submount);
+		st_remove_tasks(submount);
+		st_wait_state(submount, ST_READY);
+
+		submount->parent->submnt_count--;
+		list_del_init(&submount->mounts);
+
+		ioctl(submount->ioctlfd, AUTOFS_IOC_CATATONIC, 0);
+
+		mounts_mutex_unlock(ap);
+
+		if (submount->thid) {
+			pthread_cancel(submount->thid);
+			close_mount_fds(submount);
+			umount(root);
+			destroy_logpri_fifo(submount);
+			master_free_mapent_sources(submount->entry, 1);
+			master_free_mapent(ap->entry);
+		}
+	}
+	return;
+}
 
-	cache_multi_lock(me->parent);
+static void cleanup_multi_triggers(struct autofs_point *ap,
+			    struct mapent *me, const char *root, int start,
+			    const char *base)
+{
+	char path[PATH_MAX + 1];
+	char offset[PATH_MAX + 1];
+	char *poffset = offset;
+	struct mapent *oe;
+	struct list_head *mm_root, *pos;
+	const char o_root[] = "/";
+	const char *mm_base;
 
-	m_key = mm->key;
+	mm_root = &me->multi->multi_list;
 
-	if (*m_key == '/') {
-		m_root = m_key;
-		start = strlen(m_key);
+	if (!base)
+		mm_base = o_root;
+	else
+		mm_base = base;
+
+	pos = NULL;
+
+	/* Make sure "none" of the offsets have an active mount. */
+	while ((poffset = cache_get_offset(mm_base, poffset, start, mm_root, &pos))) {
+		oe = cache_lookup_offset(mm_base, poffset, start, &me->multi_list);
+		/* root offset is a special case */
+		if (!oe || !oe->mapent || (strlen(oe->key) - start) == 1)
+			continue;
+
+		strcpy(path, root);
+		strcat(path, poffset);
+		if (umount(path)) {
+			error(ap->logopt, "error recovering from mount fail");
+			error(ap->logopt, "cannot umount offset %s", path);
+		}
+	}
+
+	return;
+}
+
+static int check_fstype_autofs_option(const char *options)
+{
+	char *tok, *tokbuf;
+	int found;
+
+	/*
+	 * Look for fstype= in options and return true if
+	 * the last occurrence is fstype=autofs.
+	 */
+	found = 0;
+	tokbuf = alloca(strlen(options) + 2);
+	strcpy(tokbuf, options);
+	tok = strtok_r(tokbuf, ",", &tokbuf);
+	if (tok) {
+		do {
+			if (strstr(tok, "fstype=")) {
+				if (strstr(tok, "autofs"))
+					found = 1;
+				else
+					found = 0;
+			}
+		} while ((tok = strtok_r(NULL, ",", &tokbuf)));
+	}
+
+	return found;
+}
+
+static int mount_subtree(struct autofs_point *ap, struct mapent *me,
+			 const char *name, char *loc, char *options, void *ctxt)
+{
+	struct mapent *mm;
+	struct mapent *ro;
+	char t_dir[] = "/tmp/autoXXXXXX";
+	char *mm_root, *mm_base, *mm_key;
+	const char *mm_tmp_root, *target;
+	unsigned int mm_tmp_root_len;
+	int start, ret = 0, rv;
+	unsigned int move;
+
+	rv = 0;
+
+	if (!me || !me->multi) {
+		int loclen = strlen(loc);
+		int namelen = strlen(name);
+		const char *root = ap->path;
+
+		if (!strcmp(ap->path, "/-"))
+			root = name;
+
+		rv = sun_mount(ap, root, name, namelen, loc, loclen, options, ctxt);
+
+		goto done;
+	}
+
+	mm = me->multi;
+	mm_key = mm->key;
+	move = MOUNT_MOVE_NONE;
+
+	if (*mm_key == '/') {
+		mm_root = mm_key;
+		start = strlen(mm_key);
 	} else {
-		start = strlen(ap->path) + strlen(m_key) + 1;
-		m_root = alloca(start + 1);
-		if (!m_root) {
-			char *estr;
-			cache_multi_unlock(me->parent);
-			estr = strerror_r(errno, buf, MAX_ERR_BUF);
-			error(ap->logopt, MODPREFIX "alloca: %s", estr);
-			return -1;
-		}
-		strcpy(m_root, ap->path);
-		strcat(m_root, "/");
-		strcat(m_root, m_key);
-	}
-
-	base = &me->key[start];
-
-	ret = mount_multi_triggers(ap, m_root, me->multi, base);
-	if (ret == -1) {
-		cache_multi_unlock(me->parent);
-		error(ap->logopt, MODPREFIX "failed to mount offset triggers");
-		return -1;
+		start = strlen(ap->path) + strlen(mm_key) + 1;
+		mm_root = alloca(start + 3);
+		strcpy(mm_root, ap->path);
+		strcat(mm_root, "/");
+		strcat(mm_root, mm_key);
 	}
 
-	cache_multi_unlock(me->parent);
+	mm_tmp_root = mkdtemp(t_dir);
+	if (!mm_tmp_root)
+		return 1;
+	mm_tmp_root_len = strlen(mm_tmp_root);
+
+	if (me == me->multi) {
+		/* name = NULL */
+		/* destination = mm_root */
+		target = mm_root;
+		mm_base = "/";
 
-	return ret;
+		/* Mount root offset if it exists */
+		ro = cache_lookup_offset(mm_base, mm_base, strlen(mm_root), &me->multi_list);
+		if (ro) {
+			char *myoptions, *ro_loc, *tmp;
+			int namelen = name ? strlen(name) : 0;
+			const char *root;
+			int ro_len;
+
+			rv = parse_mapent(ro->mapent,
+				options, &myoptions, &ro_loc, ap->logopt);
+			if (!rv) {
+				warn(ap->logopt,
+				      MODPREFIX "failed to parse root offset");
+				cache_delete_offset_list(me->mc, name);
+				rmdir(mm_tmp_root);
+				return 1;
+			}
+			ro_len = strlen(ro_loc);
+
+			move = MOUNT_MOVE_OTHER;
+			if (check_fstype_autofs_option(myoptions))
+				move = MOUNT_MOVE_AUTOFS;
+
+			root = mm_tmp_root;
+			tmp = alloca(mm_tmp_root_len + 1);
+			strcpy(tmp, mm_tmp_root);
+			tmp[mm_tmp_root_len] = '/';
+			tmp[mm_tmp_root_len + 1] = '\0';
+			root = tmp;
+
+			rv = sun_mount(ap, root, name, namelen, ro_loc, ro_len, myoptions, ctxt);
+
+			free(myoptions);
+			free(ro_loc);
+		}
+
+		if (ro && rv == 0) {
+			ret = mount_multi_triggers(ap, me, mm_tmp_root, start, mm_base);
+			if (ret == -1) {
+				error(ap->logopt, MODPREFIX
+					 "failed to mount offset triggers");
+				cleanup_multi_triggers(ap, me, mm_tmp_root, start, mm_base);
+				cleanup_multi_root(ap, mm_tmp_root, mm_root, move);
+				rmdir(mm_tmp_root);
+				return 1;
+			}
+		} else if (rv <= 0) {
+			move = MOUNT_MOVE_NONE;
+			ret = mount_multi_triggers(ap, me, mm_root, start, mm_base);
+			if (ret == -1) {
+				error(ap->logopt, MODPREFIX
+					 "failed to mount offset triggers");
+				cleanup_multi_triggers(ap, me, mm_tmp_root, start, mm_base);
+				rmdir(mm_tmp_root);
+				return 1;
+			}
+		}
+	} else {
+		int loclen = strlen(loc);
+		int namelen = strlen(name);
+
+		move = MOUNT_MOVE_OTHER;
+		if (check_fstype_autofs_option(options))
+			move = MOUNT_MOVE_AUTOFS;
+
+		/* name = mm_root + mm_base */
+		/* destination = mm_root + mm_base = name */
+		target = name;
+		mm_base = &me->key[start];
+
+		rv = sun_mount(ap, mm_tmp_root, name, namelen, loc, loclen, options, ctxt);
+		if (rv == 0) {
+			ret = mount_multi_triggers(ap, me->multi, mm_tmp_root, start, mm_base);
+			if (ret == -1) {
+				error(ap->logopt, MODPREFIX
+					 "failed to mount offset triggers");
+				cleanup_multi_triggers(ap, me, mm_tmp_root, start, mm_base);
+				cleanup_multi_root(ap, mm_tmp_root, mm_root, move);
+				rmdir(mm_tmp_root);
+				return 1;
+			}
+		} else if (rv < 0) {
+			move = MOUNT_MOVE_NONE;
+			ret = mount_multi_triggers(ap, me->multi, mm_root, start, mm_base);
+			if (ret == -1) {
+				error(ap->logopt, MODPREFIX
+					 "failed to mount offset triggers");
+				cleanup_multi_triggers(ap, me, mm_tmp_root, start, mm_base);
+				rmdir(mm_tmp_root);
+				return 1;
+			}
+		}
+	}
+
+	if (!move_mount(ap, mm_tmp_root, target, move)) {
+		cleanup_multi_triggers(ap, me, mm_tmp_root, start, mm_base);
+		cleanup_multi_root(ap, mm_tmp_root, mm_root, move);
+		rmdir(mm_tmp_root);
+		return 1;
+	}
+
+	rmdir(mm_tmp_root);
+
+	/* Mount for base of tree failed */
+	if (rv > 0)
+		return rv;
+
+done:
+	/*
+	 * Convert fail on nonstrict, non-empty multi-mount
+	 * to success
+	 */
+	if (rv < 0 && ret > 0)
+		rv = 0;
+
+	return rv;
 }
 
 /*
@@ -1029,7 +1303,7 @@ int parse_mount(struct autofs_point *ap,
 	char buf[MAX_ERR_BUF];
 	struct map_source *source;
 	struct mapent_cache *mc;
-	struct mapent *me, *ro;
+	struct mapent *me = NULL;
 	char *pmapent, *options;
 	const char *p;
 	int mapent_len, rv = 0;
@@ -1154,7 +1428,7 @@ int parse_mount(struct autofs_point *ap,
 		char *m_root = NULL;
 		int m_root_len;
 		time_t age = time(NULL);
-		int l, ret;
+		int l;
 
 		/* If name starts with "/" it's a direct mount */
 		if (*name == '/') {
@@ -1302,48 +1576,7 @@ int parse_mount(struct autofs_point *ap,
 		 */
 		cache_set_parents(me);
 
-		/* Mount root offset if it exists */
-		ro = cache_lookup_offset("/", "/", strlen(m_root), &me->multi_list);
-		if (ro) {
-			char *myoptions, *loc;
-
-			rv = parse_mapent(ro->mapent,
-				options, &myoptions, &loc, ap->logopt);
-			if (!rv) {
-				warn(ap->logopt,
-				      MODPREFIX "failed to mount root offset");
-				cache_delete_offset_list(mc, name);
-				cache_multi_unlock(me);
-				cache_unlock(mc);
-				free(options);
-				pthread_setcancelstate(cur_state, NULL);
-				return 1;
-			}
-
-			rv = sun_mount(ap, m_root,
-				"/", 1, loc, strlen(loc), myoptions, ctxt);
-
-			free(myoptions);
-			free(loc);
-		}
-
-		ret = mount_multi_triggers(ap, m_root, me, "/");
-		if (ret == -1) {
-			warn(ap->logopt,
-			      MODPREFIX "failed to mount offset triggers");
-			cache_multi_unlock(me);
-			cache_unlock(mc);
-			free(options);
-			pthread_setcancelstate(cur_state, NULL);
-			return 1;
-		}
-
-		/*
-		 * Convert fail on nonstrict, non-empty multi-mount
-		 * to success
-		 */
-		if (rv < 0 && ret > 0)
-			rv = 0;
+		rv = mount_subtree(ap, me, name, NULL, options, ctxt);
 
 		cache_multi_unlock(me);
 		cache_unlock(mc);
@@ -1461,24 +1694,15 @@ mount_it:
 		      MODPREFIX "core of entry: options=%s, loc=%.*s",
 		      options, loclen, loc);
 
-		rv = sun_mount(ap, ap->path, name, name_len, loc, loclen, options, ctxt);
+		cache_readlock(mc);
+		cache_multi_lock(me);
+
+		rv = mount_subtree(ap, me, name, loc, options, ctxt);
 
 		free(loc);
 		free(options);
 
-		/*
-		 * If it's a multi-mount insert the triggers
-		 * These are always direct mount triggers so root = ""
-		 */
-		pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cur_state);
-		cache_readlock(mc);
-		me = cache_lookup_distinct(mc, name);
-		if (me) {
-			int ret = mount_subtree_offsets(ap, mc, me);
-			/* Convert fail on nonstrict, non-empty multi-mount to success */
-			if (rv < 0 && ret > 0)
-				rv = 0;
-		}
+		cache_multi_unlock(me);
 		cache_unlock(mc);
 		pthread_setcancelstate(cur_state, NULL);
 	}

autofs-5.0.3-fix-multi-source-messages.patch:

--- NEW FILE autofs-5.0.3-fix-multi-source-messages.patch ---
autofs-5.0.3 - fix multi source messages

From: Ian Kent <raven at themaw.net>

There are incorrect "key not found" messages seen for master map
entries that have multiple sources (direct mounts).

For example, for the direct mount entries:

/-    auto.one
/-    auto.two

if a mount lookup is done and is not found in auto.one we see a
not found message even though it may be found in auto.two.

This patch moves the "key not found" reporting out to the higher
level lookup and reports status at the end of the lookup.
---

 daemon/lookup.c          |    3 +++
 modules/lookup_file.c    |   11 ++---------
 modules/lookup_ldap.c    |   10 ++--------
 modules/lookup_nisplus.c |   12 +++---------
 modules/lookup_program.c |    2 +-
 modules/lookup_yp.c      |   10 ++--------
 6 files changed, 13 insertions(+), 35 deletions(-)


--- autofs-5.0.2.orig/daemon/lookup.c
+++ autofs-5.0.2/daemon/lookup.c
@@ -903,6 +903,9 @@ int lookup_nss_mount(struct autofs_point
 	send_map_update_request(ap);
 	pthread_cleanup_pop(1);
 
+	if (result == NSS_STATUS_NOTFOUND)
+		error(ap->logopt, "key \"%s\" not found in map.", name);
+
 	return !result;
 }
 
--- autofs-5.0.2.orig/modules/lookup_file.c
+++ autofs-5.0.2/modules/lookup_file.c
@@ -1074,7 +1074,7 @@ int lookup_mount(struct autofs_point *ap
 	me = cache_lookup_distinct(mc, key);
 	if (me && me->status >= time(NULL)) {
 		cache_unlock(mc);
-		return NSS_STATUS_NOTFOUND;
+		return NSS_STATUS_UNAVAIL;
 	}
 	cache_unlock(mc);
 
@@ -1105,11 +1105,6 @@ int lookup_mount(struct autofs_point *ap
 		if (status) {
 			if (status == NSS_STATUS_COMPLETED)
 				return NSS_STATUS_SUCCESS;
-
-			error(ap->logopt,
-			      MODPREFIX "key \"%s\" not found in map",
-			      name);
-
 			return NSS_STATUS_NOTFOUND;
 		}
 	}
@@ -1154,9 +1149,7 @@ int lookup_mount(struct autofs_point *ap
 			}
 			cache_unlock(mc);
 		}
-	} else
-		error(ap->logopt,
-		      MODPREFIX "key \"%s\" not found in map.", name);
+	}
 
 	if (ret)
 		return NSS_STATUS_TRYAGAIN;
--- autofs-5.0.2.orig/modules/lookup_ldap.c
+++ autofs-5.0.2/modules/lookup_ldap.c
@@ -2586,12 +2586,8 @@ int lookup_mount(struct autofs_point *ap
 
 		status = check_map_indirect(ap, lkp_key, strlen(lkp_key), ctxt);
 		free(lkp_key);
-		if (status) {
-			error(ap->logopt,
-			      MODPREFIX "key \"%s\" not found in map",
-			      name);
+		if (status)
 			return status;
-		}
 	}
 
 	cache_readlock(mc);
@@ -2633,9 +2629,7 @@ int lookup_mount(struct autofs_point *ap
 			}
 			cache_unlock(mc);
 		}
-	} else
-		error(ap->logopt,
-		      MODPREFIX "key \"%s\" not found in map", name);
+	}
 
 	if (ret)
 		return NSS_STATUS_TRYAGAIN;
--- autofs-5.0.2.orig/modules/lookup_nisplus.c
+++ autofs-5.0.2/modules/lookup_nisplus.c
@@ -520,12 +520,8 @@ int lookup_mount(struct autofs_point *ap
 		ap->entry->current = source;
 
 		status = check_map_indirect(ap, lkp_key, strlen(lkp_key), ctxt);
-		if (status) {
-			error(ap->logopt,
-			      MODPREFIX "key \"%s\" not found in map",
-			      name);
+		if (status)
 			return status;
-		}
 	}
 
 	cache_readlock(mc);
@@ -566,12 +562,10 @@ int lookup_mount(struct autofs_point *ap
 			}
 			cache_unlock(mc);
 		}
-	} else
-		error(ap->logopt,
-		      MODPREFIX "key \"%s\" not found in map", name);
+	}
 
 	if (ret)
-		return NSS_STATUS_NOTFOUND;
+		return NSS_STATUS_TRYAGAIN;
 
 	return NSS_STATUS_SUCCESS;
 }
--- autofs-5.0.2.orig/modules/lookup_program.c
+++ autofs-5.0.2/modules/lookup_program.c
@@ -390,7 +390,7 @@ out_free:
 			me->status = now + ap->negative_timeout;
 		}
 		cache_unlock(mc);
-		return NSS_STATUS_UNAVAIL;
+		return NSS_STATUS_TRYAGAIN;
 	}
 
 	return NSS_STATUS_SUCCESS;
--- autofs-5.0.2.orig/modules/lookup_yp.c
+++ autofs-5.0.2/modules/lookup_yp.c
@@ -618,12 +618,8 @@ int lookup_mount(struct autofs_point *ap
 
 		status = check_map_indirect(ap, lkp_key, strlen(lkp_key), ctxt);
 		free(lkp_key);
-		if (status) {
-			error(ap->logopt,
-			      MODPREFIX "key \"%s\" not found in map",
-			      name);
+		if (status)
 			return status;
-		}
 	}
 
 	cache_readlock(mc);
@@ -664,9 +660,7 @@ int lookup_mount(struct autofs_point *ap
 			}
 			cache_unlock(mc);
 		}
-	 } else
-		error(ap->logopt,
-		      MODPREFIX "key \"%s\" not found in map", name);
+	 }
 
 	if (ret)
 		return NSS_STATUS_TRYAGAIN;

autofs-5.0.3-fix-nfs4-colon-escape.patch:

--- NEW FILE autofs-5.0.3-fix-nfs4-colon-escape.patch ---
autofs-5.0.3 - fix nfs4 colon escape handling

From: Ian Kent <raven at themaw.net>

When fstype=nfs4 is given for a mount entry that should be bind
mounted because it has a ":" escaped location the colon can be
discarded before the mount module is called. This causes an
incorrect mount fail return since the replicated selection code
expects the colon to be present for parsing.
---

 modules/parse_sun.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)


diff --git a/modules/parse_sun.c b/modules/parse_sun.c
index b548520..333f8a5 100644
--- a/modules/parse_sun.c
+++ b/modules/parse_sun.c
@@ -638,7 +638,7 @@ static int sun_mount(struct autofs_point *ap, const char *root,
 	}
 
 	pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cur_state);
-	if (!strcmp(fstype, "nfs")) {
+	if (!strcmp(fstype, "nfs") || !strcmp(fstype, "nfs4")) {
 		what = alloca(loclen + 1);
 		memcpy(what, loc, loclen);
 		what[loclen] = '\0';

autofs-5.0.3-fix-percent-hack.patch:

--- NEW FILE autofs-5.0.3-fix-percent-hack.patch ---
>From jmoyer at redhat.com Thu Jul 17 10:12:13 2008

From: Ian Kent <raven at themaw.net>

Hi, Ian,

As I mentioned, the encode and decode routines for the % hack were
corrupting heap space.  I put together a patch to fix things as they
stand today.  The comments document the assumptions I made.

I tested this code by compiling a program that only included
these functions and passing them arbitrary input and validating the
reuslts.  I then compiled them into the automounter and verified that
no heap corruption occurred (by running automount -f on a fedora
system where such things are reported).

Now, I don't think that we should ever have to encode the percent
hack.  Shouldn't we just need to decode it, walking through all of the
returned entries until we find an exact match for the key being looked
up?

Comments welcome.

IMK: You're right, but we'll keep it for the moment.

Cheers,
Jeff
---

 modules/lookup_ldap.c |  267 +++++++++++++++++++++++++++++++++++--------------
 1 files changed, 193 insertions(+), 74 deletions(-)


diff --git a/modules/lookup_ldap.c b/modules/lookup_ldap.c
index 7777e90..3990f8c 100644
--- a/modules/lookup_ldap.c
+++ b/modules/lookup_ldap.c
@@ -1512,6 +1512,65 @@ next:
 	return NSS_STATUS_SUCCESS;
 }
 
+static int get_percent_decoded_len(const char *name)
+{
+	int escapes = 0;
+	int escaped = 0;
+	char *tmp = name;
+	int look_for_close = 0;
+
+	while (*tmp) {
+		if (*tmp == '%') {
+			/* assume escapes aren't interpreted inside brackets */
+			if (look_for_close) {
+				tmp++;
+				continue;
+			}
+			/* check for escaped % */
+			if (escaped) {
+				tmp++;
+				escaped = 0;
+				continue;
+			}
+			escapes++;
+			tmp++;
+			if (*tmp == '[') {
+				escapes++;
+				tmp++;
+				look_for_close = 1;
+			} else
+				escaped = 1;
+		} else if (*tmp == ']' && look_for_close) {
+			escaped = 0;
+			escapes++;
+			tmp++;
+			look_for_close = 0;
+		} else {
+			tmp++;
+			escaped = 0;
+		}
+	}
+
+	assert(strlen(name) > escapes);
+	return strlen(name) - escapes;
+}
+
+/*
+ * Try to catch heap corruption if our logic happens to be incorrect.
+ */
+static void validate_string_len(const char *orig, char *start,
+				char *end, unsigned int len)
+{
+	debug(LOGOPT_NONE, MODPREFIX "string %s encoded as %s", orig, start);
+	/* make sure we didn't overflow the allocated space */
+	if (end - start > len + 1) {
+		crit(LOGOPT_ANY, MODPREFIX "orig %s, len %d", orig, len);
+		crit(LOGOPT_ANY, MODPREFIX "en/decoded %s, len %d", start,
+		     end - start);
+	}
+	assert(end-start <= len + 1);
+}
+
 /*
  * Deal with encode and decode of % hack.
  * Return
@@ -1519,131 +1578,191 @@ next:
  * -1 => syntax error or alloc fail.
  * 1 transofrmed value returned.
  */
+/*
+ * Assumptions: %'s must be escaped by %'s.  %'s are not used to escape
+ * anything else except capital letters (so you can't escape a closing
+ * bracket, for example).
+ */
 static int decode_percent_hack(const char *name, char **key)
 {
 	const char *tmp;
 	char *ptr, *new;
+	unsigned int len;
+	int escaped = 0, look_for_close = 0;
 
 	if (!key)
 		return -1;
 
 	*key = NULL;
 
-	tmp = name;
-	while (*tmp && *tmp != '%' && *tmp != '[' && *tmp != ']')
-		tmp++;
-	if (!*tmp)
-		return 0;
+	len = get_percent_decoded_len(name);
+	new = malloc(len + 1);
+	if (!new)
+		return -1;
 
+	ptr = new;
 	tmp = name;
 	while (*tmp) {
 		if (*tmp == '%') {
-			tmp++;
-			if (!*tmp)
-				return -1;
-			if (*tmp != '[')
+			if (escaped) {
+				*ptr++ = *tmp++;
+				if (!look_for_close)
+					escaped = 0;
 				continue;
+			}
 			tmp++;
-			while (*tmp && *tmp != ']') {
-				if (*tmp == '%')
-					tmp++;
+			if (*tmp == '[') {
 				tmp++;
-			}
-			if (!tmp)
-				return -1;
-		}
-		tmp++;
-	}
-
-	new = malloc(strlen(name) + 1);
-	if (!new)
-		return -1;
-
-	ptr = new;
-	tmp = name;
-	while (*tmp) {
-		if (*tmp == '%' || *tmp == '[' || *tmp == ']') {
+				look_for_close = 1;
+				escaped = 1;
+			} else
+				escaped = 1;
+		} else if (*tmp == ']' && look_for_close) {
 			tmp++;
-			if (*tmp && *tmp != '%')
-				continue;
+			look_for_close = 0;
+		} else {
+			escaped = 0;
+			*ptr++ = *tmp++;
 		}
-		*ptr++ = *tmp++;
 	}
 	*ptr = '\0';
-
 	*key = new;
 
+	validate_string_len(name, new, ptr, len);
 	return strlen(new);
 }
 
-static int encode_percent_hack(const char *name, char **key, unsigned int use_class)
+/*
+ * Calculate the length of a string replacing all capital letters with %letter.
+ * For example:
+ * Sale -> %Sale
+ * SALE -> %S%A%L%E
+ */
+static int get_encoded_len_escaping_every_cap(const char *name)
 {
 	const char *tmp;
-	unsigned int len = 0;
-	char *ptr, *new;
+	unsigned int escapes = 0; /* number of % escape characters */
 
-	if (!key)
-		return -1;
+	tmp = name;
+	while (*tmp) {
+		/* We'll need to escape percents */
+		if (*tmp == '%' || isupper(*tmp))
+			escapes++;
+		tmp++;
+	}
 
-	*key = NULL;
+	return strlen(name) + escapes;
+}
+
+/*
+ * Calculate the length of a string replacing sequences (1 or more) of capital
+ * letters with %[letters].  For example:
+ * FOO ->  %[FOO]
+ * Work -> %[W]ork
+ * WorksForMe -> %[W]orks%[F]or%[M]e
+ * aaBBaa -> aa%[BB]aa
+ */
+static int get_encoded_len_escaping_sequences(const char *name)
+{
+	const char *tmp;
+	unsigned int escapes = 0;
 
 	tmp = name;
 	while (*tmp) {
+		/* escape percents */
 		if (*tmp == '%')
-			len++;
+			escapes++;
 		else if (isupper(*tmp)) {
-			tmp++;
-			len++;
-			if (!use_class)
-				len++;
-			else {
-				if (*tmp && isupper(*tmp))
-					len += 2;
-				else
-					return 0;
-				while (*tmp && isupper(*tmp)) {
-					len++;
-					tmp++;
-				}
-			}
+			/* start an escape block %[...] */
+			escapes += 3;  /* %[] */
+			while (*tmp && isupper(*tmp))
+				tmp++;
 			continue;
 		}
-		len++;
 		tmp++;
 	}
-	if (len == strlen(name))
-		return 0;
 
-	new = malloc(len + 1);
-	if (!new)
-		return -1;
+	return strlen(name) + escapes;
+}
+
+static void encode_individual(const char *name, char *new, unsigned int len)
+{
+	const char *tmp;
+	char *ptr;
 
 	ptr = new;
 	tmp = name;
 	while (*tmp) {
-		if (*tmp == '%')
+		if (*tmp == '%' || isupper(*tmp))
 			*ptr++ = '%';
-		else if (isupper(*tmp)) {
-			char next = *tmp++;
+		*ptr++ = *tmp++;
+	}
+	*ptr = '\0';
+	validate_string_len(name, new, ptr, len);
+}
+
+static void encode_sequence(const char *name, char *new, unsigned int len)
+{
+	const char *tmp;
+	char *ptr;
+
+	ptr = new;
+	tmp = name;
+	while (*tmp) {
+		if (*tmp == '%') {
 			*ptr++ = '%';
-			if (*tmp && (!isupper(*tmp) || !use_class))
-				*ptr++ = next;
-			else {
-				*ptr++ = '[';
-				*ptr++ = next;
-				while (*tmp && isupper(*tmp))
-					*ptr++ = *tmp++;
-				*ptr++ = ']';
+			*ptr++ = *tmp++;
+		} else if (isupper(*tmp)) {
+			*ptr++ = '%';
+			*ptr++ = '[';
+			*ptr++ = *tmp++;
+
+			while (*tmp && isupper(*tmp)) {
+				*ptr++ = *tmp;
+				tmp++;
 			}
-			continue;
-		}
-		*ptr++ = *tmp++;
+			*ptr++ = ']';
+		} else
+			*ptr++ = *tmp++;
 	}
 	*ptr = '\0';
+	validate_string_len(name, new, ptr, len);
+}
 
-	*key = new;
+/*
+ * use_class:  1 means encode string as %[CAPITALS], 0 means encode as
+ * %C%A%P%I%T%A%L%S
+ */
+static int encode_percent_hack(const char *name, char **key, unsigned int use_class)
+{
+	unsigned int len = 0;
 
-	return strlen(new);
+	if (!key)
+		return -1;
+
+	if (use_class)
+		len = get_encoded_len_escaping_sequences(name);
+	else
+		len = get_encoded_len_escaping_every_cap(name);
+
+	/* If there is no escaping to be done, return 0 */
+	if (len == strlen(name))
+		return 0;
+
+	*key = malloc(len + 1);
+	if (!*key)
+		return -1;
+
+	if (use_class)
+		encode_sequence(name, *key, len);
+	else
+		encode_individual(name, *key, len);
+
+	if (strlen(*key) != len)
+		crit(LOGOPT_ANY, MODPREFIX "encoded key length mismatch: key "
+		     "%s len %d strlen %d", *key, len, strlen(*key));
+
+	return strlen(*key);
 }
 
 static int do_paged_query(struct ldap_search_params *sp, struct lookup_context *ctxt)

autofs-5.0.3-fix-proximity-other-timeout.patch:

--- NEW FILE autofs-5.0.3-fix-proximity-other-timeout.patch ---
autofs-5.0.3 - fix proximity other rpc ping timeout

From: Ian Kent <raven at themaw.net>

The timeout for the RCP ping for hosts that are on a network other
than the local subnet or network is mistakenly set quite short. This
can lead to unexplained intermittent failures for hosts on remote
networks.
---

 modules/replicated.c |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)


diff --git a/modules/replicated.c b/modules/replicated.c
index efbe6b4..925f641 100644
--- a/modules/replicated.c
+++ b/modules/replicated.c
@@ -552,7 +552,7 @@ static int get_vers_and_cost(unsigned logopt, struct host *host,
 
 	if (host->proximity == PROXIMITY_NET)
 		timeout = RPC_TIMEOUT * 2;
-	else if (host->proximity == PROXIMITY_NET)
+	else if (host->proximity == PROXIMITY_OTHER)
 		timeout = RPC_TIMEOUT * 8;
 
 	rpc_info.host = host->name;
@@ -609,7 +609,7 @@ static int get_supported_ver_and_cost(unsigned logopt, struct host *host,
 
 	if (host->proximity == PROXIMITY_NET)
 		timeout = RPC_TIMEOUT * 2;
-	else if (host->proximity == PROXIMITY_NET)
+	else if (host->proximity == PROXIMITY_OTHER)
 		timeout = RPC_TIMEOUT * 8;
 
 	rpc_info.host = host->name;

autofs-5.0.3-fix-rootless-direct-multi-mount-expire.patch:

--- NEW FILE autofs-5.0.3-fix-rootless-direct-multi-mount-expire.patch ---
autofs-5.0.3 - don't close direct root

From: Ian Kent <raven at themaw.net>

For direct mount multi-mounts with no real mount at their base we
need to leave the file handle open so they will be expired. This
patch corrects the check done at mount completion to do this so
they will be expired.
---

 daemon/direct.c |   13 +++++++++++--
 1 file changed, 11 insertions(+), 2 deletions(-)


--- autofs-5.0.3.orig/daemon/direct.c
+++ autofs-5.0.3/daemon/direct.c
@@ -1311,8 +1311,17 @@ static void *do_mount_direct(void *arg)
 		    !master_find_submount(ap, mt.name)))
 			close_fd = 1;
 		cache_writelock(mt.mc);
-		if (!close_fd && (me = cache_lookup_distinct(mt.mc, mt.name)))
-			me->ioctlfd = mt.ioctlfd;
+		if ((me = cache_lookup_distinct(mt.mc, mt.name))) {
+			/*
+			 * Careful here, we need to leave the file handle open
+			 * for direct mount multi-mounts with no real mount at
+			 * their base so they will be expired.
+			 */
+			if (close_fd && me == me->multi)
+				close_fd = 0;
+			if (!close_fd)
+				me->ioctlfd = mt.ioctlfd;
+		}
 		send_ready(ap->logopt, mt.ioctlfd, mt.wait_queue_token);
 		cache_unlock(mt.mc);
 		if (close_fd)

autofs-5.0.3-library-reload-fix.patch:

--- NEW FILE autofs-5.0.3-library-reload-fix.patch ---
autofs-5.0.3 - library reload fix

From: Ian Kent <raven at themaw.net>

During a map re-read autofs needs to re-open its lookup libraries but
dependent shared libraries can't handle being unloaded and then re-loaded
by the same process. This patch preventis dependent libraries from being
unloaded during this re-open.
---

 daemon/automount.c |    1 -
 daemon/lookup.c    |   21 +++++++++------------
 daemon/state.c     |    3 +++
 include/master.h   |   17 +++--------------
 lib/master.c       |   28 ++++++++++++++++++++++------
 5 files changed, 37 insertions(+), 33 deletions(-)


--- autofs-5.0.3.orig/daemon/automount.c
+++ autofs-5.0.3/daemon/automount.c
@@ -85,7 +85,6 @@ int aquire_flag_file(void);
 void release_flag_file(void);
 static int umount_all(struct autofs_point *ap, int force);
 
-extern pthread_mutex_t master_mutex;
 extern struct master *master_list;
 
 static int do_mkdir(const char *parent, const char *path, mode_t mode)
--- autofs-5.0.3.orig/daemon/lookup.c
+++ autofs-5.0.3/daemon/lookup.c
@@ -267,17 +267,17 @@ static int do_read_map(struct autofs_poi
 	struct lookup_mod *lookup;
 	int status;
 
-	if (!map->lookup) {
-		lookup = open_lookup(map->type, "",
-				map->format, map->argc, map->argv);
-		if (!lookup) {
-			debug(ap->logopt, "lookup module %s failed", map->type);
-			return NSS_STATUS_UNAVAIL;
-		}
-		map->lookup = lookup;
+	lookup = open_lookup(map->type, "", map->format, map->argc, map->argv);
+	if (!lookup) {
+		debug(ap->logopt, "lookup module %s failed", map->type);
+		return NSS_STATUS_UNAVAIL;
 	}
 
-	lookup = map->lookup;
+	master_source_writelock(ap->entry);
+	if (map->lookup)
+		close_lookup(map->lookup);
+	map->lookup = lookup;
+	master_source_unlock(ap->entry);
 
 	/* If we don't need to create directories then there's no use
 	 * reading the map. We just need to test that the map is valid
@@ -463,8 +463,6 @@ int lookup_nss_read_map(struct autofs_po
 	 * point in the master map) do the nss lookup to
 	 * locate the map and read it.
 	 */
-	pthread_cleanup_push(master_source_lock_cleanup, entry);
-	master_source_readlock(entry);
 	if (source)
 		map = source;
 	else
@@ -557,7 +555,6 @@ int lookup_nss_read_map(struct autofs_po
 
 		map = map->next;
 	}
-	pthread_cleanup_pop(1);
 
 	if (!result || at_least_one)
 		return 1;
--- autofs-5.0.3.orig/daemon/state.c
+++ autofs-5.0.3/daemon/state.c
@@ -387,9 +387,12 @@ static void *do_readmap(void *arg)
 
 	info(ap->logopt, "re-reading map for %s", ap->path);
 
+	pthread_cleanup_push(master_mutex_lock_cleanup, NULL);
+	master_mutex_lock();
 	status = lookup_nss_read_map(ap, NULL, now);
 	if (!status)
 		pthread_exit(NULL);
+	pthread_cleanup_pop(1);
 
 	if (ap->type == LKP_INDIRECT) {
 		lookup_prune_cache(ap, now);
--- autofs-5.0.3.orig/include/master.h
+++ autofs-5.0.3/include/master.h
@@ -70,6 +70,9 @@ int master_parse_entry(const char *, uns
 
 /* From master.c master parser utility routines */
 
+void master_mutex_lock(void);
+void master_mutex_unlock(void);
+void master_mutex_lock_cleanup(void *);
 void master_set_default_timeout(void);
 void master_set_default_ghost_mode(void);
 int master_add_autofs_point(struct master_mapent *, time_t, unsigned, unsigned, int);
@@ -108,18 +111,4 @@ extern inline unsigned int master_get_lo
 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
--- autofs-5.0.3.orig/lib/master.c
+++ autofs-5.0.3/lib/master.c
@@ -41,8 +41,28 @@ static struct map_source *
 __master_find_map_source(struct master_mapent *,
 			 const char *, const char *, int, const char **);
 
-pthread_mutex_t master_mutex = PTHREAD_MUTEX_INITIALIZER;
-pthread_mutex_t instance_mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t master_mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t instance_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+void master_mutex_lock(void)
+{
+	int status = pthread_mutex_lock(&master_mutex);
+	if (status)
+		fatal(status);
+}
+
+void master_mutex_unlock(void)
+{
+	int status = pthread_mutex_unlock(&master_mutex);
+	if (status)
+		fatal(status);
+}
+
+void master_mutex_lock_cleanup(void *arg)
+{
+	master_mutex_unlock();
+	return;
+}
 
 int master_add_autofs_point(struct master_mapent *entry,
 		time_t timeout, unsigned logopt, unsigned ghost, int submount) 
@@ -1109,10 +1129,6 @@ int master_mount_mounts(struct master *m
 			continue;
 		}
 
-		master_source_writelock(ap->entry);
-		lookup_close_lookup(ap);
-		master_source_unlock(ap->entry);
-
 		cache_readlock(nc);
 		ne = cache_lookup_distinct(nc, this->path);
 		if (ne && this->age > ne->age) {

autofs-5.0.3-lookup-next-soucre-stale-entry.patch:

--- NEW FILE autofs-5.0.3-lookup-next-soucre-stale-entry.patch ---
autofs-5.0.3 - multi-map doesn't pickup NIS updates automatically

From: Ian Kent <raven at themaw.net>

In a multi-map configuration, autofs doesn't pick up NIS updates
automatically. This is caused by the lookup not checking alternate
sources for the given key (or wildcard) when doing a key lookup.
---

 lib/cache.c              |    2 ++
 modules/lookup_file.c    |   11 ++++++++---
 modules/lookup_ldap.c    |   11 ++++++++---
 modules/lookup_nisplus.c |   11 ++++++++---
 modules/lookup_yp.c      |   11 ++++++++---
 5 files changed, 34 insertions(+), 12 deletions(-)


--- autofs-5.0.2.orig/lib/cache.c
+++ autofs-5.0.2/lib/cache.c
@@ -700,6 +700,8 @@ int cache_update(struct mapent_cache *mc
 	int ret = CHE_OK;
 
 	me = cache_lookup(mc, key);
+	while (me && me->source != ms)
+		me = cache_lookup_key_next(me);
 	if (!me || (*me->key == '*' && *key != '*')) {
 		ret = cache_add(mc, ms, key, mapent, age);
 		if (!ret) {
--- autofs-5.0.2.orig/modules/lookup_file.c
+++ autofs-5.0.2/modules/lookup_file.c
@@ -1116,9 +1116,14 @@ int lookup_mount(struct autofs_point *ap
 
 	cache_readlock(mc);
 	me = cache_lookup(mc, key);
-	/* Stale mapent => check for wildcard */
-	if (me && !me->mapent)
-		me = cache_lookup_distinct(mc, "*");
+	/* Stale mapent => check for entry in alternate source or wildcard */
+	if (me && !me->mapent) {
+		while ((me = cache_lookup_key_next(me)))
+			if (me->source == source)
+				break;
+		if (!me)
+			me = cache_lookup_distinct(mc, "*");
+	}
 	if (me && (me->source == source || *me->key == '/')) {
 		pthread_cleanup_push(cache_lock_cleanup, mc);
 		mapent_len = strlen(me->mapent);
--- autofs-5.0.2.orig/modules/lookup_ldap.c
+++ autofs-5.0.2/modules/lookup_ldap.c
@@ -2596,9 +2596,14 @@ int lookup_mount(struct autofs_point *ap
 
 	cache_readlock(mc);
 	me = cache_lookup(mc, key);
-	/* Stale mapent => check for wildcard */
-	if (me && !me->mapent)
-		me = cache_lookup_distinct(mc, "*");
+	/* Stale mapent => check for entry in alternate source or wildcard */
+	if (me && !me->mapent) {
+		while ((me = cache_lookup_key_next(me)))
+			if (me->source == source)
+				break;
+		if (!me)
+			me = cache_lookup_distinct(mc, "*");
+	}
 	if (me && (me->source == source || *me->key == '/')) {
 		mapent_len = strlen(me->mapent);
 		mapent = alloca(mapent_len + 1);
--- autofs-5.0.2.orig/modules/lookup_nisplus.c
+++ autofs-5.0.2/modules/lookup_nisplus.c
@@ -530,9 +530,14 @@ int lookup_mount(struct autofs_point *ap
 
 	cache_readlock(mc);
 	me = cache_lookup(mc, key);
-	/* Stale mapent => check for wildcard */
-	if (me && !me->mapent)
-		me = cache_lookup_distinct(mc, "*");
+	/* Stale mapent => check for entry in alternate source or wildcard */
+	if (me && !me->mapent) {
+		while ((me = cache_lookup_key_next(me)))
+			if (me->source == source)
+				break;
+		if (!me)
+			me = cache_lookup_distinct(mc, "*");
+	}
 	if (me && (me->source == source || *me->key == '/')) {
 		mapent_len = strlen(me->mapent);
 		mapent = alloca(mapent_len + 1);
--- autofs-5.0.2.orig/modules/lookup_yp.c
+++ autofs-5.0.2/modules/lookup_yp.c
@@ -628,9 +628,14 @@ int lookup_mount(struct autofs_point *ap
 
 	cache_readlock(mc);
 	me = cache_lookup(mc, key);
-	/* Stale mapent => check for wildcard */
-	if (me && !me->mapent)
-		me = cache_lookup_distinct(mc, "*");
+	/* Stale mapent => check for entry in alternate source or wildcard */
+	if (me && !me->mapent) {
+		while ((me = cache_lookup_key_next(me)))
+			if (me->source == source)
+				break;
+		if (!me)
+			me = cache_lookup_distinct(mc, "*");
+	}
 	if (me && (me->source == source || *me->key == '/')) {
 		mapent_len = strlen(me->mapent);
 		mapent = alloca(mapent_len + 1);

autofs-5.0.3-make-handle_mounts-startup-cond-distinct.patch:

--- NEW FILE autofs-5.0.3-make-handle_mounts-startup-cond-distinct.patch ---
autofs-5.0.3 - make handle_mounts startup condition distinct

From: Ian Kent <raven at themaw.net>

When starting a number of mounts we can get contention for the startup
condition used to synchronize the handle_mounts thread completion. This
patch makes the condition used distinct for each thread creation.
---

 daemon/automount.c     |   62 +++++++++++++++++++++++++++++++++++++++++++++----
 include/automount.h    |    4 +++
 lib/master.c           |   29 +++++++++++-----------
 modules/mount_autofs.c |   35 +++++++++++++--------------
 4 files changed, 92 insertions(+), 38 deletions(-)


--- autofs-5.0.2.orig/daemon/automount.c
+++ autofs-5.0.2/daemon/automount.c
@@ -1461,6 +1461,55 @@ static void mutex_operation_wait(pthread
 	return;
 }
 
+int handle_mounts_startup_cond_init(struct startup_cond *suc)
+{
+	int status;
+
+	status = pthread_mutex_init(&suc->mutex, NULL);
+	if (status)
+		return status;
+
+	status = pthread_cond_init(&suc->cond, NULL);
+	if (status) {
+		status = pthread_mutex_destroy(&suc->mutex);
+		if (status)
+			fatal(status);
+		return status;
+	}
+
+	status = pthread_mutex_lock(&suc->mutex);
+	if (status) {
+		status = pthread_mutex_destroy(&suc->mutex);
+		if (status)
+			fatal(status);
+		status = pthread_cond_destroy(&suc->cond);
+		if (status)
+			fatal(status);
+	}
+
+	return 0;
+}
+
+void handle_mounts_startup_cond_destroy(void *arg)
+{
+	struct startup_cond *suc = (struct startup_cond *) arg;
+	int status;
+
+	status = pthread_mutex_unlock(&suc->mutex);
+	if (status)
+		fatal(status);
+
+	status = pthread_mutex_destroy(&suc->mutex);
+	if (status)
+		fatal(status);
+
+	status = pthread_cond_destroy(&suc->cond);
+	if (status)
+		fatal(status);
+
+	return;
+}
+
 static void handle_mounts_cleanup(void *arg)
 {
 	struct autofs_point *ap;
@@ -1512,17 +1561,20 @@ static void handle_mounts_cleanup(void *
 
 void *handle_mounts(void *arg)
 {
+	struct startup_cond *suc;
 	struct autofs_point *ap;
 	int cancel_state, status = 0;
 
-	ap = (struct autofs_point *) arg;
+	suc = (struct startup_cond *) arg;
+
+	ap = suc->ap;
 
-	pthread_cleanup_push(return_start_status, &suc);
+	pthread_cleanup_push(return_start_status, suc);
 	pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cancel_state);
 
 	state_mutex_lock(ap);
 
-	status = pthread_mutex_lock(&suc.mutex);
+	status = pthread_mutex_lock(&suc->mutex);
 	if (status) {
 		logerr("failed to lock startup condition mutex!");
 		fatal(status);
@@ -1530,7 +1582,7 @@ void *handle_mounts(void *arg)
 
 	if (mount_autofs(ap) < 0) {
 		crit(ap->logopt, "mount of %s failed!", ap->path);
-		suc.status = 1;
+		suc->status = 1;
 		state_mutex_unlock(ap);
 		umount_autofs(ap, 1);
 		pthread_setcancelstate(cancel_state, NULL);
@@ -1540,7 +1592,7 @@ void *handle_mounts(void *arg)
 	if (ap->ghost && ap->type != LKP_DIRECT)
 		info(ap->logopt, "ghosting enabled");
 
-	suc.status = 0;
+	suc->status = 0;
 	pthread_cleanup_pop(1);
 
 	/* We often start several automounters at the same time.  Add some
--- autofs-5.0.2.orig/include/automount.h
+++ autofs-5.0.2/include/automount.h
@@ -331,10 +331,14 @@ int ncat_path(char *buf, size_t len,
 struct startup_cond {
 	pthread_mutex_t mutex;
 	pthread_cond_t  cond;
+	struct autofs_point *ap;
 	unsigned int done;
 	unsigned int status;
 };
 
+int handle_mounts_startup_cond_init(struct startup_cond *suc);
+void handle_mounts_startup_cond_destroy(void *arg);
+
 struct master_readmap_cond {
 	pthread_mutex_t mutex;
 	pthread_cond_t  cond;
--- autofs-5.0.2.orig/lib/master.c
+++ autofs-5.0.2/lib/master.c
@@ -997,28 +997,31 @@ next:
 
 static int master_do_mount(struct master_mapent *entry)
 {
+	struct startup_cond suc;
 	struct autofs_point *ap;
 	pthread_t thid;
 	int status;
 
-	status = pthread_mutex_lock(&suc.mutex);
-	if (status)
-		fatal(status);
+	ap = entry->ap;
+
+	if (handle_mounts_startup_cond_init(&suc)) {
+		crit(ap->logopt,
+		     "failed to init startup cond for mount %s", entry->path);
+		return 0;
+	}
 
+	suc.ap = ap;
 	suc.done = 0;
 	suc.status = 0;
 
-	ap = entry->ap;
-
 	debug(ap->logopt, "mounting %s", entry->path);
 
-	if (pthread_create(&thid, &thread_attr, handle_mounts, ap)) {
+	status = pthread_create(&thid, &thread_attr, handle_mounts, &suc);
+	if (status) {
 		crit(ap->logopt,
 		     "failed to create mount handler thread for %s",
 		     entry->path);
-		status = pthread_mutex_unlock(&suc.mutex);
-		if (status)
-			fatal(status);
+		handle_mounts_startup_cond_destroy(&suc);
 		return 0;
 	}
 	entry->thid = thid;
@@ -1031,15 +1034,11 @@ static int master_do_mount(struct master
 
 	if (suc.status) {
 		error(ap->logopt, "failed to startup mount");
-		status = pthread_mutex_unlock(&suc.mutex);
-		if (status)
-			fatal(status);
+		handle_mounts_startup_cond_destroy(&suc);
 		return 0;
 	}
 
-	status = pthread_mutex_unlock(&suc.mutex);
-	if (status)
-		fatal(status);
+	handle_mounts_startup_cond_destroy(&suc);
 
 	return 1;
 }
--- autofs-5.0.2.orig/modules/mount_autofs.c
+++ autofs-5.0.2/modules/mount_autofs.c
@@ -46,6 +46,7 @@ int mount_mount(struct autofs_point *ap,
 		int name_len, const char *what, const char *fstype,
 		const char *c_options, void *context)
 {
+	struct startup_cond suc;
 	pthread_t thid;
 	char *fullpath;
 	const char **argv;
@@ -210,34 +211,34 @@ int mount_mount(struct autofs_point *ap,
 	source->mc = cache_init(entry->ap, source);
 	if (!source->mc) {
 		error(ap->logopt, MODPREFIX "failed to init source cache");
+		master_free_map_source(source, 0);
 		master_free_mapent(entry);
 		return 1;
 	}
 
 	mounts_mutex_lock(ap);
 
-	status = pthread_mutex_lock(&suc.mutex);
-	if (status) {
-		crit(ap->logopt,
-		     MODPREFIX "failed to lock startup condition mutex!");
-		cache_release(source);
+	if (handle_mounts_startup_cond_init(&suc)) {
+		crit(ap->logopt, MODPREFIX
+		     "failed to init startup cond for mount %s", entry->path);
+		mounts_mutex_unlock(ap);
+		master_free_map_source(source, 1);
 		master_free_mapent(entry);
 		return 1;
 	}
 
+	suc.ap = nap;
 	suc.done = 0;
 	suc.status = 0;
 
-	if (pthread_create(&thid, NULL, handle_mounts, nap)) {
+	if (pthread_create(&thid, &thread_attr, handle_mounts, &suc)) {
 		crit(ap->logopt,
 		     MODPREFIX
 		     "failed to create mount handler thread for %s",
 		     fullpath);
+		handle_mounts_startup_cond_destroy(&suc);
 		mounts_mutex_unlock(ap);
-		status = pthread_mutex_unlock(&suc.mutex);
-		if (status)
-			fatal(status);
-		cache_release(source);
+		master_free_map_source(source, 1);
 		master_free_mapent(entry);
 		return 1;
 	}
@@ -246,8 +247,10 @@ int mount_mount(struct autofs_point *ap,
 	while (!suc.done) {
 		status = pthread_cond_wait(&suc.cond, &suc.mutex);
 		if (status) {
+			handle_mounts_startup_cond_destroy(&suc);
 			mounts_mutex_unlock(ap);
-			pthread_mutex_unlock(&suc.mutex);
+			master_free_map_source(source, 1);
+			master_free_mapent(entry);
 			fatal(status);
 		}
 	}
@@ -255,10 +258,9 @@ int mount_mount(struct autofs_point *ap,
 	if (suc.status) {
 		crit(ap->logopt,
 		     MODPREFIX "failed to create submount for %s", fullpath);
+		handle_mounts_startup_cond_destroy(&suc);
 		mounts_mutex_unlock(ap);
-		status = pthread_mutex_unlock(&suc.mutex);
-		if (status)
-			fatal(status);
+		master_free_map_source(source, 1);
 		master_free_mapent(entry);
 		return 1;
 	}
@@ -266,12 +268,9 @@ int mount_mount(struct autofs_point *ap,
 	ap->submnt_count++;
 	list_add(&nap->mounts, &ap->submounts);
 
+	handle_mounts_startup_cond_destroy(&suc);
 	mounts_mutex_unlock(ap);
 
-	status = pthread_mutex_unlock(&suc.mutex);
-	if (status)
-		fatal(status);
-
 	return 0;
 }
 

autofs-5.0.3-map-type-in-map-name-fix.patch:

--- NEW FILE autofs-5.0.3-map-type-in-map-name-fix.patch ---
autofs-5.0.3 - map type in map name fix

From: Ian Kent <raven at themaw.net>

Fix incorrect match of map type as a host name.
Actually the original patch didn't match upstream or RHEL
so this syncs the source with those. It appears the problem
was fixed here some time ago but slightly differently.
---

 lib/master_tok.l |    4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)


--- autofs-5.0.3.orig/lib/master_tok.l
+++ autofs-5.0.3/lib/master_tok.l
@@ -202,7 +202,9 @@ OPTNTOUT	(-n{OPTWS}|-n{OPTWS}={OPTWS}|--
 		}
 	}
 
-	{MTYPE}/({DNSERVERSTR}|{DNATTRSTR}=)? {
+	{MTYPE} |
+	{MTYPE}/{DNSERVERSTR}{DNATTRSTR} |
+	{MTYPE}/{DNATTRSTR}= {
 		tlen = master_leng - 1;
 		if (bptr != buff && isblank(master_text[tlen])) {
 			strncat(buff, master_text, tlen);

autofs-5.0.3-map-type-in-map-name.patch:

--- NEW FILE autofs-5.0.3-map-type-in-map-name.patch ---
---
 lib/master_tok.l |   27 +++++++++++++++++++++------
 1 file changed, 21 insertions(+), 6 deletions(-)

--- autofs-5.0.2.orig/lib/master_tok.l
+++ autofs-5.0.2/lib/master_tok.l
@@ -77,6 +77,7 @@ int my_yyinput(char *, int);
 char buff[1024];
 char *bptr;
 char *optr = buff;
+unsigned int tlen;
 
 %}
 
@@ -190,13 +191,27 @@ OPTNTOUT	(-n{OPTWS}|-n{OPTWS}={OPTWS}|--
 	{OPTWS}\\\n{OPTWS} {}
 
 	{MULTI} {
-		strcpy(master_lval.strtype, master_text);
-		return(MULTITYPE);
+		tlen = master_leng - 1;
+		if (bptr != buff && isblank(master_text[tlen])) {
+			strncat(buff, master_text, tlen);
+			bptr += tlen;
+			yyless(tlen);
+		} else {
+			strcpy(master_lval.strtype, master_text);
+			return(MULTITYPE);
+		}
 	}
 
-	{MTYPE} {
-		strcpy(master_lval.strtype, master_text);
-		return(MAPTYPE);
+	{MTYPE}/({DNSERVERSTR}|{DNATTRSTR}=)? {
+		tlen = master_leng - 1;
+		if (bptr != buff && isblank(master_text[tlen])) {
+			strncat(buff, master_text, tlen);
+			bptr += tlen;
+			yyless(tlen);
+		} else {
+			strcpy(master_lval.strtype, master_text);
+			return(MAPTYPE);
+		}
 	}
 
 	{MULTISEP} { return(DDASH); }
@@ -226,7 +241,7 @@ OPTNTOUT	(-n{OPTWS}|-n{OPTWS}={OPTWS}|--
 		yyless(0);
 	}
 
-	{DNSERVERSTR} {
+	{DNSERVERSTR}{DNATTRSTR} {
 		BEGIN(DNSTR);
 		yyless(0);
 	}

autofs-5.0.3-mount-thread-create-cond-handling-fix.patch:

--- NEW FILE autofs-5.0.3-mount-thread-create-cond-handling-fix.patch ---
autofs-5.0.3 - mount thread create condition handling fix

From: Ian Kent <raven at themaw.net>

Make the mount thread creation condition mutex specific to the
thread being created.
---

 daemon/direct.c   |   31 +++++++++++++++++++++++--------
 daemon/indirect.c |   31 +++++++++++++++++++++++--------
 2 files changed, 46 insertions(+), 16 deletions(-)


--- autofs-5.0.2.orig/daemon/direct.c
+++ autofs-5.0.2/daemon/direct.c
@@ -50,7 +50,6 @@ pthread_key_t key_mnt_direct_params;
 pthread_key_t key_mnt_offset_params;
 pthread_once_t key_mnt_params_once = PTHREAD_ONCE_INIT;
 
-static pthread_mutex_t ma_mutex = PTHREAD_MUTEX_INITIALIZER;
 static pthread_mutex_t ea_mutex = PTHREAD_MUTEX_INITIALIZER;
 
 static void key_mnt_params_destroy(void *arg)
@@ -1218,9 +1217,18 @@ static void mount_send_fail(void *arg)
 	close(mt->ioctlfd);
 }
 
+static void pending_mutex_destroy(void *arg)
+{
+	struct pending_args *mt = (struct pending_args *) arg;
+	int status = pthread_mutex_destroy(&mt->mutex);
+	if (status)
+		fatal(status);
+}
+
 static void mount_mutex_unlock(void *arg)
 {
-	int status = pthread_mutex_unlock(&ma_mutex);
+	struct pending_args *mt = (struct pending_args *) arg;
+	int status = pthread_mutex_unlock(&mt->mutex);
 	if (status)
 		fatal(status);
 }
@@ -1243,7 +1251,7 @@ static void *do_mount_direct(void *arg)
 
 	args = (struct pending_args *) arg;
 
-	status = pthread_mutex_lock(&ma_mutex);
+	status = pthread_mutex_lock(&args->mutex);
 	if (status)
 		fatal(status);
 
@@ -1256,7 +1264,7 @@ static void *do_mount_direct(void *arg)
 	if (status)
 		fatal(status);
 
-	mount_mutex_unlock(NULL);
+	mount_mutex_unlock(args);
 
 	pthread_cleanup_push(mount_send_fail, &mt);
 
@@ -1533,7 +1541,11 @@ int handle_packet_missing_direct(struct 
 	if (status)
 		fatal(status);
 
-	status = pthread_mutex_lock(&ma_mutex);
+	status = pthread_mutex_init(&mt->mutex, NULL);
+	if (status)
+		fatal(status);
+
+	status = pthread_mutex_lock(&mt->mutex);
 	if (status)
 		fatal(status);
 
@@ -1553,8 +1565,9 @@ int handle_packet_missing_direct(struct 
 		send_fail(ap->logopt, ioctlfd, pkt->wait_queue_token);
 		close(ioctlfd);
 		cache_unlock(mc);
-		mount_mutex_unlock(NULL);
+		mount_mutex_unlock(mt);
 		pending_cond_destroy(mt);
+		pending_mutex_destroy(mt);
 		free_pending_args(mt);
 		pthread_setcancelstate(state, NULL);
 		return 1;
@@ -1562,13 +1575,14 @@ int handle_packet_missing_direct(struct 
 
 	cache_unlock(mc);
 	pthread_cleanup_push(free_pending_args, mt);
+	pthread_cleanup_push(pending_mutex_destroy, mt);
 	pthread_cleanup_push(pending_cond_destroy, mt);
-	pthread_cleanup_push(mount_mutex_unlock, NULL);
+	pthread_cleanup_push(mount_mutex_unlock, mt);
 	pthread_setcancelstate(state, NULL);
 
 	mt->signaled = 0;
 	while (!mt->signaled) {
-		status = pthread_cond_wait(&mt->cond, &ma_mutex);
+		status = pthread_cond_wait(&mt->cond, &mt->mutex);
 		if (status)
 			fatal(status);
 	}
@@ -1576,6 +1590,7 @@ int handle_packet_missing_direct(struct 
 	pthread_cleanup_pop(1);
 	pthread_cleanup_pop(1);
 	pthread_cleanup_pop(1);
+	pthread_cleanup_pop(1);
 
 	return 0;
 }
--- autofs-5.0.2.orig/daemon/indirect.c
+++ autofs-5.0.2/daemon/indirect.c
@@ -40,7 +40,6 @@
 
 extern pthread_attr_t thread_attr;
 
-static pthread_mutex_t ma_mutex = PTHREAD_MUTEX_INITIALIZER;
 static pthread_mutex_t ea_mutex = PTHREAD_MUTEX_INITIALIZER;
 
 static int unlink_mount_tree(struct autofs_point *ap, struct mnt_list *mnts)
@@ -651,9 +650,18 @@ static void mount_send_fail(void *arg)
 	send_fail(mt->ap->logopt, mt->ap->ioctlfd, mt->wait_queue_token);
 }
 
+static void pending_mutex_destroy(void *arg)
+{
+	struct pending_args *mt = (struct pending_args *) arg;
+	int status = pthread_mutex_destroy(&mt->mutex);
+	if (status)
+		fatal(status);
+}
+
 static void mount_mutex_unlock(void *arg)
 {
-	int status = pthread_mutex_unlock(&ma_mutex);
+	struct pending_args *mt = (struct pending_args *) arg;
+	int status = pthread_mutex_unlock(&mt->mutex);
 	if (status)
 		fatal(status);
 }
@@ -676,7 +684,7 @@ static void *do_mount_indirect(void *arg
 
 	args = (struct pending_args *) arg;
 
-	status = pthread_mutex_lock(&ma_mutex);
+	status = pthread_mutex_lock(&args->mutex);
 	if (status)
 		fatal(status);
 
@@ -689,7 +697,7 @@ static void *do_mount_indirect(void *arg
 	if (status)
 		fatal(status);
 
-	mount_mutex_unlock(NULL);
+	mount_mutex_unlock(args);
 
 	pthread_cleanup_push(mount_send_fail, &mt);
 
@@ -884,7 +892,11 @@ int handle_packet_missing_indirect(struc
 	if (status)
 		fatal(status);
 
-	status = pthread_mutex_lock(&ma_mutex);
+	status = pthread_mutex_init(&mt->mutex, NULL);
+	if (status)
+		fatal(status);
+
+	status = pthread_mutex_lock(&mt->mutex);
 	if (status)
 		fatal(status);
 
@@ -901,21 +913,23 @@ int handle_packet_missing_indirect(struc
 	if (status) {
 		error(ap->logopt, "expire thread create failed");
 		send_fail(ap->logopt, ap->ioctlfd, pkt->wait_queue_token);
-		mount_mutex_unlock(NULL);
+		mount_mutex_unlock(mt);
 		pending_cond_destroy(mt);
+		pending_mutex_destroy(mt);
 		free_pending_args(mt);
 		pthread_setcancelstate(state, NULL);
 		return 1;
 	}
 
 	pthread_cleanup_push(free_pending_args, mt);
+	pthread_cleanup_push(pending_mutex_destroy, mt);
 	pthread_cleanup_push(pending_cond_destroy, mt);
-	pthread_cleanup_push(mount_mutex_unlock, NULL);
+	pthread_cleanup_push(mount_mutex_unlock, mt);
 	pthread_setcancelstate(state, NULL);
 
 	mt->signaled = 0;
 	while (!mt->signaled) {
-		status = pthread_cond_wait(&mt->cond, &ma_mutex);
+		status = pthread_cond_wait(&mt->cond, &mt->mutex);
 		if (status)
 			fatal(status);
 	}
@@ -923,6 +937,7 @@ int handle_packet_missing_indirect(struc
 	pthread_cleanup_pop(1);
 	pthread_cleanup_pop(1);
 	pthread_cleanup_pop(1);
+	pthread_cleanup_pop(1);
 
 	return 0;
 }

autofs-5.0.3-mtab-as-proc-mounts-fix.patch:

--- NEW FILE autofs-5.0.3-mtab-as-proc-mounts-fix.patch ---
autofs-5.0.3 - check for mtab pointing to /proc/mounts fix

From: Ian Kent <raven at themaw.net>

Fix incorrect initialization in spawn_bind_mount() which
caused bind mounts to not be added to mtab.
---

 daemon/spawn.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)


diff --git a/daemon/spawn.c b/daemon/spawn.c
index 85cf9b8..17f92f4 100644
--- a/daemon/spawn.c
+++ b/daemon/spawn.c
@@ -432,7 +432,7 @@ int spawn_bind_mount(unsigned logopt, ...)
 	char arg_fake[] = "-f";
 	unsigned int options;
 	unsigned int retries = MTAB_LOCK_RETRIES;
-	int update_mtab = 0, ret, printed = 0;
+	int update_mtab = 1, ret, printed = 0;
 	char buf[PATH_MAX];
 
 	/* If we use mount locking we can't validate the location */

autofs-5.0.3-mtab-as-proc-mounts.patch:

--- NEW FILE autofs-5.0.3-mtab-as-proc-mounts.patch ---
autofs-5.0.3 - check for mtab pointing to /proc/mounts

From: Ian Kent <raven at themaw.net>

autofs has problems if /etc/mtab points to /proc/mounts.
This patchs adds a check to see if this is the case. If it is then
autofs uses the mount(8) "-n" option which disables the normal mtab
update error checking.
---

 daemon/spawn.c |   66 +++++++++++++++++++++++++++++++++++++++++++++++++++------
 1 file changed, 60 insertions(+), 6 deletions(-)


--- autofs-5.0.2.orig/daemon/spawn.c
+++ autofs-5.0.2/daemon/spawn.c
@@ -305,11 +305,13 @@ int spawn_mount(unsigned logopt, ...)
 	char **argv, **p;
 	char prog[] = PATH_MOUNT;
 	char arg0[] = PATH_MOUNT;
+	char argn[] = "-n";
 	/* In case we need to use the fake option to mount */
 	char arg_fake[] = "-f";
 	unsigned int options;
 	unsigned int retries = MTAB_LOCK_RETRIES;
-	int ret, printed = 0;
+	int update_mtab = 1, ret, printed = 0;
+	char buf[PATH_MAX];
 
 	/* If we use mount locking we can't validate the location */
 #ifdef ENABLE_MOUNT_LOCKING
@@ -322,6 +324,17 @@ int spawn_mount(unsigned logopt, ...)
 	for (argc = 1; va_arg(arg, char *); argc++);
 	va_end(arg);
 
+	ret = readlink(_PATH_MOUNTED, buf, PATH_MAX);
+	if (ret != -1) {
+		buf[ret] = '\0';
+		if (!strcmp(buf, _PROC_MOUNTS)) {
+			debug(logopt,
+			      "mtab link detected, passing -n to mount");
+			argc++;
+			update_mtab = 0;
+		}
+	}
+
 	/* Alloc 1 extra slot in case we need to use the "-f" option */
 	if (!(argv = alloca(sizeof(char *) * argc + 2)))
 		return -1;
@@ -329,7 +342,12 @@ int spawn_mount(unsigned logopt, ...)
 	argv[0] = arg0;
 
 	va_start(arg, logopt);
-	p = argv + 1;
+	if (update_mtab)
+		p = argv + 1;
+	else {
+		argv[1] = argn;
+		p = argv + 2;
+	}
 	while ((*p = va_arg(arg, char *))) {
 		if (options == SPAWN_OPT_NONE && !strcmp(*p, "-o")) {
 			*(++p) = va_arg(arg, char *);
@@ -409,11 +427,13 @@ int spawn_bind_mount(unsigned logopt, ..
 	char prog[] = PATH_MOUNT;
 	char arg0[] = PATH_MOUNT;
 	char bind[] = "--bind";
+	char argn[] = "-n";
 	/* In case we need to use the fake option to mount */
 	char arg_fake[] = "-f";
 	unsigned int options;
 	unsigned int retries = MTAB_LOCK_RETRIES;
-	int ret, printed = 0;
+	int update_mtab = 0, ret, printed = 0;
+	char buf[PATH_MAX];
 
 	/* If we use mount locking we can't validate the location */
 #ifdef ENABLE_MOUNT_LOCKING
@@ -430,6 +450,17 @@ int spawn_bind_mount(unsigned logopt, ..
 	for (argc = 2; va_arg(arg, char *); argc++);
 	va_end(arg);
 
+	ret = readlink(_PATH_MOUNTED, buf, PATH_MAX);
+	if (ret != -1) {
+		buf[ret] = '\0';
+		if (!strcmp(buf, _PROC_MOUNTS)) {
+			debug(logopt,
+			      "mtab link detected, passing -n to mount");
+			argc++;
+			update_mtab = 0;
+		}
+	}
+
 	if (!(argv = alloca(sizeof(char *) * argc + 2)))
 		return -1;
 
@@ -437,7 +468,12 @@ int spawn_bind_mount(unsigned logopt, ..
 	argv[1] = bind;
 
 	va_start(arg, logopt);
-	p = argv + 2;
+	if (update_mtab)
+		p = argv + 2;
+	else {
+		argv[2] = argn;
+		p = argv + 3;
+	}
 	while ((*p++ = va_arg(arg, char *)));
 	va_end(arg);
 
@@ -499,10 +535,12 @@ int spawn_umount(unsigned logopt, ...)
 	char **argv, **p;
 	char prog[] = PATH_UMOUNT;
 	char arg0[] = PATH_UMOUNT;
+	char argn[] = "-n";
 	unsigned int options;
 	unsigned int retries = MTAB_LOCK_RETRIES;
-	int ret, printed = 0;
+	int update_mtab = 1, ret, printed = 0;
 	unsigned int wait = defaults_get_umount_wait();
+	char buf[PATH_MAX];
 
 #ifdef ENABLE_MOUNT_LOCKING
 	options = SPAWN_OPT_LOCK;
@@ -514,13 +552,29 @@ int spawn_umount(unsigned logopt, ...)
 	for (argc = 1; va_arg(arg, char *); argc++);
 	va_end(arg);
 
+	ret = readlink(_PATH_MOUNTED, buf, PATH_MAX);
+	if (ret != -1) {
+		buf[ret] = '\0';
+		if (!strcmp(buf, _PROC_MOUNTS)) {
+			debug(logopt,
+			      "mtab link detected, passing -n to mount");
+			argc++;
+			update_mtab = 0;
+		}
+	}
+
 	if (!(argv = alloca(sizeof(char *) * argc + 1)))
 		return -1;
 
 	argv[0] = arg0;
 
 	va_start(arg, logopt);
-	p = argv + 1;
+	if (update_mtab)
+		p = argv + 1;
+	else {
+		argv[1] = argn;
+		p = argv + 2;
+	}
 	while ((*p++ = va_arg(arg, char *)));
 	va_end(arg);
 

autofs-5.0.3-nisplus-partial-and-free.patch:

--- NEW FILE autofs-5.0.3-nisplus-partial-and-free.patch ---
autofs-5.0.3 - nisplus partial and free

From: Jeff Bastian <jbastian at redhat.com>

During a nisplus key lookup nis_list() can return NIS_PARTIAL
as well as possibly NIS_NOTFOUND or NIS_S_NOTFOUND when the key
doesn't exist. This patch adds this to the checks and fixes a use
after free of the result struct.
---

 modules/lookup_nisplus.c |   16 ++++++++++------
 1 file changed, 10 insertions(+), 6 deletions(-)


--- autofs-5.0.3.orig/modules/lookup_nisplus.c
+++ autofs-5.0.3/modules/lookup_nisplus.c
@@ -285,13 +285,15 @@ static int lookup_one(struct autofs_poin
 
 	result = nis_list(tablename, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
 	if (result->status != NIS_SUCCESS && result->status != NIS_S_SUCCESS) {
+		nis_error rs = result->status;
 		nis_freeresult(result);
 		pthread_setcancelstate(cur_state, NULL);
-		if (result->status == NIS_NOTFOUND ||
-		    result->status == NIS_S_NOTFOUND)
+		if (rs == NIS_NOTFOUND ||
+		    rs == NIS_S_NOTFOUND ||
+		    rs == NIS_PARTIAL)
 			return CHE_MISSING;
 
-		return -result->status;
+		return -rs;
 	}
 
 	
@@ -338,13 +340,15 @@ static int lookup_wild(struct autofs_poi
 
 	result = nis_list(tablename, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
 	if (result->status != NIS_SUCCESS && result->status != NIS_S_SUCCESS) {
+		nis_error rs = result->status;
 		nis_freeresult(result);
 		pthread_setcancelstate(cur_state, NULL);
-		if (result->status == NIS_NOTFOUND ||
-		    result->status == NIS_S_NOTFOUND)
+		if (rs == NIS_NOTFOUND ||
+		    rs == NIS_S_NOTFOUND ||
+		    rs == NIS_PARTIAL)
 			return CHE_MISSING;
 
-		return -result->status;
+		return -rs;
 	}
 
 	this = NIS_RES_OBJECT(result);

autofs-5.0.3-nss-source-any.patch:

--- NEW FILE autofs-5.0.3-nss-source-any.patch ---
autofs-5.0.3 - ignore nsswitch sources that aren't supported

From: Ian Kent <raven at themaw.net>

Allow any source name in nsswitch and ignore those we don't support.
This has the side affect of also ignoring any action associated with
a source that isn't supported by autofs.
---

 lib/nss_parse.y |   31 ++++++++++++++++---------------
 lib/nss_tok.l   |   22 ++++++++++++----------
 2 files changed, 28 insertions(+), 25 deletions(-)


--- autofs-5.0.2.orig/lib/nss_parse.y
+++ autofs-5.0.2/lib/nss_parse.y
@@ -64,7 +64,6 @@ char strval[128];
 %token <strval> SOURCE
 %token <strval> STATUS
 %token <strval> ACTION
-%token <strval> OTHER
 
 %start file
 
@@ -83,7 +82,9 @@ sources: nss_source
 
 nss_source: SOURCE
 {
-	if (strcmp($1, "winbind"))
+	if (!strcmp($1, "files") || !strcmp($1, "yp") ||
+	    !strcmp($1, "nis") || !strcmp($1, "ldap") ||
+	    !strcmp($1, "nisplus") || !strcmp($1, "hesiod"))
 		src = add_source(nss_list, $1);
 	else
 		nss_ignore($1);
@@ -91,7 +92,9 @@ nss_source: SOURCE
 {
 	enum nsswitch_status a;
 
-	if (strcmp($1, "winbind")) {
+	if (!strcmp($1, "files") || !strcmp($1, "yp") ||
+	    !strcmp($1, "nis") || !strcmp($1, "ldap") ||
+	    !strcmp($1, "nisplus") || !strcmp($1, "hesiod")) {
 		src = add_source(nss_list, $1);
 		for (a = 0; a < NSS_STATUS_MAX; a++) {
 			if (act[a].action != NSS_ACTION_UNKNOWN) {
@@ -101,12 +104,10 @@ nss_source: SOURCE
 		}
 	} else
 		nss_ignore($1);
-} | SOURCE LBRACKET status_exp_list SOURCE { nss_error($4); YYABORT; }
-  | SOURCE LBRACKET status_exp_list OTHER { nss_error($4); YYABORT; }
-  | SOURCE LBRACKET status_exp_list NL { nss_error("no closing bracket"); YYABORT; }
-  | SOURCE LBRACKET OTHER { nss_error($3); YYABORT; }
-  | SOURCE OTHER { nss_error("no opening bracket"); YYABORT; }
-  | error OTHER { nss_error($2); YYABORT; };
+} | SOURCE LBRACKET status_exp_list SOURCE { nss_error("missing close bracket"); YYABORT; }
+  | SOURCE LBRACKET status_exp_list NL { nss_error("missing close bracket"); YYABORT; }
+  | SOURCE LBRACKET SOURCE { nss_error($3); YYABORT; }
+  | error SOURCE { nss_error($2); YYABORT; };
 
 status_exp_list: status_exp
 		| status_exp status_exp_list
@@ -117,17 +118,17 @@ status_exp: STATUS EQUAL ACTION
 } | BANG STATUS EQUAL ACTION
 {
 	set_action(act, $2, $4, 1);
-} | STATUS EQUAL OTHER {nss_error($3); YYABORT; }
-  | STATUS OTHER {nss_error($2); YYABORT; }
-  | BANG STATUS EQUAL OTHER {nss_error($4); YYABORT; }
-  | BANG STATUS OTHER {nss_error($3); YYABORT; }
-  | BANG OTHER {nss_error($2); YYABORT; };
+} | STATUS EQUAL SOURCE {nss_error($3); YYABORT; }
+  | STATUS SOURCE {nss_error($2); YYABORT; }
+  | BANG STATUS EQUAL SOURCE {nss_error($4); YYABORT; }
+  | BANG STATUS SOURCE {nss_error($3); YYABORT; }
+  | BANG SOURCE {nss_error($2); YYABORT; };
 
 %%
 
 static int nss_ignore(const char *s)
 {
-	logmsg("ignored invalid nsswitch config near [ %s ]", s);
+	logmsg("ignored unsupported autofs nsswitch source \"%s\"", s);
 	return(0);
 }
 
--- autofs-5.0.2.orig/lib/nss_tok.l
+++ autofs-5.0.2/lib/nss_tok.l
@@ -62,13 +62,13 @@ extern unsigned int nss_automount_found;
 
 %option nounput
 
-%x AUTOMOUNT
+%x AUTOMOUNT ACTIONSTR
 
 WS		[[:blank:]]+
 
 automount	([Aa][Uu][Tt][Oo][Mm][Oo][Uu][Nn][Tt])
 
-source		files|yp|nis|nisplus|ldap|hesiod|winbind
+source		[[:alnum:]@$%^&*()-+_":;?,<>./'{}~`]+
 
 success		([Ss][Uu][Cc][Cc][Ee][Ss][Ss])
 notfound	([Nn][Oo][Tt][Ff][Oo][Uu][Nn][Dd])
@@ -82,8 +82,6 @@ return		([Rr][Ee][Tt][Uu][Rr][Nn])
 
 action		({continue}|{return})
 
-other		[[:alnum:]@$%^&*()-+_":;?,<>./'{}~`]+
-
 %%
 
 ^{automount}: {
@@ -101,6 +99,14 @@ other		[[:alnum:]@$%^&*()-+_":;?,<>./'{}
 		return SOURCE;
 	}
 
+	"["	{ BEGIN(ACTIONSTR); yyless(0); }
+
+	\n	{ BEGIN(INITIAL); return NL; }
+}
+
+<ACTIONSTR>{
+	{WS}	{ }
+
 	{status} {
 		strcpy(nss_lval.strval, nss_text);
 		return STATUS;
@@ -112,15 +118,11 @@ other		[[:alnum:]@$%^&*()-+_":;?,<>./'{}
 	}
 
 	"["	{ return LBRACKET; }
-	"]"	{ return RBRACKET; }
+	"]"	{ BEGIN(AUTOMOUNT); return RBRACKET; }
 	"="	{ return EQUAL; }
 	"!"	{ return BANG; }
 
-	{other} {
-		strcpy(nss_lval.strval, nss_text);
-		return OTHER;
-	}
-
+	.	{ BEGIN(AUTOMOUNT); yyless(0); }
 	\n	{ BEGIN(INITIAL); return NL; }
 }
 

autofs-5.0.3-override-is-running-check.patch:

--- NEW FILE autofs-5.0.3-override-is-running-check.patch ---
autofs-5.0.3 - add command line option to override is running check

From: Ian Kent <raven at themaw.net>

autofs common usage is to have a single instance of the daemon running
and it checks for this and exits if another instance is found to be
running. But there are situations were people need to run multiple
instances and this patch adds a command line option to overrid the
check. Please note that this doesn't mean that autofs will function
properly and it is the users responsibility to check that the
configuration in use will function properly.
---

 daemon/automount.c |   14 +++++++++++---
 man/automount.8    |   10 ++++++++++
 2 files changed, 21 insertions(+), 3 deletions(-)


--- autofs-5.0.2.orig/daemon/automount.c
+++ autofs-5.0.2/daemon/automount.c
@@ -1694,6 +1694,8 @@ static void usage(void)
 		"			specify global mount options\n"
 		"	-l --set-log-priority priority path [path,...]\n"
 		"			set daemon log verbosity\n"
+		"	-C --dont-check-daemon\n"
+		"			don't check if daemon is already running\n"
 		"	-V --version	print version, build config and exit\n"
 		, program);
 }
@@ -1814,7 +1816,7 @@ int main(int argc, char *argv[])
 {
 	int res, opt, status;
 	int logpri = -1;
-	unsigned ghost, logging;
+	unsigned ghost, logging, daemon_check;
 	unsigned foreground, have_global_options;
 	time_t timeout;
 	time_t age = time(NULL);
@@ -1833,6 +1835,7 @@ int main(int argc, char *argv[])
 		{"global-options", 1, 0, 'O'},
 		{"version", 0, 0, 'V'},
 		{"set-log-priority", 1, 0, 'l'},
+		{"dont-check-daemon", 0, 0, 'C'},
 		{0, 0, 0, 0}
 	};
 
@@ -1851,9 +1854,10 @@ int main(int argc, char *argv[])
 	global_options = NULL;
 	have_global_options = 0;
 	foreground = 0;
+	daemon_check = 1;
 
 	opterr = 0;
-	while ((opt = getopt_long(argc, argv, "+hp:t:vdD:fVrO:l:n:", long_options, NULL)) != EOF) {
+	while ((opt = getopt_long(argc, argv, "+hp:t:vdD:fVrO:l:n:C", long_options, NULL)) != EOF) {
 		switch (opt) {
 		case 'h':
 			usage();
@@ -1922,6 +1926,10 @@ int main(int argc, char *argv[])
 			}
 			break;
 
+		case 'C':
+			daemon_check = 0;
+			break;
+
 		case '?':
 		case ':':
 			printf("%s: Ambiguous or unknown options\n", program);
@@ -1965,7 +1973,7 @@ int main(int argc, char *argv[])
 		exit(exit_code);
 	}
 
-	if (is_automount_running() > 0) {
+	if (daemon_check && is_automount_running() > 0) {
 		fprintf(stderr, "%s: program is already running.\n",
 			program);
 		exit(1);
--- autofs-5.0.2.orig/man/automount.8
+++ autofs-5.0.2/man/automount.8
@@ -81,6 +81,9 @@ be disabled, returning the daemon to ver
 .P
 The \fIpath\fP argument corresponds to the automounted
 path name as specified in the master map.
+.TP
+.I "\-C, \-\-dont-check-daemon"
+Don't check if the daemon is currently running (see NOTES).
 .SH ARGUMENTS
 \fBautomount\fP takes one optional argument, the name of the master map to
 use.
@@ -122,6 +125,13 @@ until they are no longer in use by the p
 If automount managed filesystems are found mounted when autofs is
 started they will be recoverd unless they are no longer present in
 the map in which case they need to umounted manually.
+.P
+If the option to disable the check to see if the daemon is already
+running is used be aware that autofs currently may not function correctly
+for certain types of automount maps. The mounts of the seperate daemons
+might interfere with one another. The implications of running multiple
+daemon instances needs to be checked and tested before we can say this
+is supported.
 .SH "SEE ALSO"
 .BR autofs (5),
 .BR autofs (8),

autofs-5.0.3-refactor-mount-request-vars.patch:

--- NEW FILE autofs-5.0.3-refactor-mount-request-vars.patch ---
autofs-5.0.3 - refactor mount request vars

From: Ian Kent <raven at themaw.net>

There is code duplication between the direct and indirect mount
modules that sets up the variables available to maps. This patch
reorganizes and moves that code to a common location.

Signed-off-by: Ian Kent <raven at themaw.net>
---

 daemon/direct.c      |  131 ----------------
 daemon/indirect.c    |  131 ----------------
 include/automount.h  |   56 ------
 include/mounts.h     |   91 +++++++++++
 include/parse_subs.h |    3 
 lib/mounts.c         |  410 +++++++++++++++++++++++++++++++++++++++++++++------
 lib/parse_subs.c     |  230 ----------------------------
 7 files changed, 458 insertions(+), 594 deletions(-)
 create mode 100644 include/mounts.h


--- autofs-5.0.2.orig/daemon/direct.c
+++ autofs-5.0.2/daemon/direct.c
@@ -35,8 +35,6 @@
 #include <sys/mount.h>
 #include <sys/vfs.h>
 #include <sched.h>
-#include <pwd.h>
-#include <grp.h>
 
 #include "automount.h"
 
@@ -1237,15 +1235,6 @@ static void *do_mount_direct(void *arg)
 {
 	struct pending_args *args, mt;
 	struct autofs_point *ap;
-	struct passwd pw;
-	struct passwd *ppw = &pw;
-	struct passwd **pppw = &ppw;
-	struct group gr;
-	struct group *pgr;
-	struct group **ppgr;
-	char *pw_tmp, *gr_tmp;
-	struct thread_stdenv_vars *tsv;
-	int tmplen, grplen;
 	struct stat st;
 	int status, state;
 
@@ -1291,126 +1280,8 @@ static void *do_mount_direct(void *arg)
 
 	info(ap->logopt, "attempting to mount entry %s", mt.name);
 
-	/*
-	 * Setup thread specific data values for macro
-	 * substution in map entries during the mount.
-	 * Best effort only as it must go ahead.
-	 */
-
-	tsv = malloc(sizeof(struct thread_stdenv_vars));
-	if (!tsv) 
-		goto cont;
-
-	tsv->uid = mt.uid;
-	tsv->gid = mt.gid;
-
-	/* Try to get passwd info */
-
-	tmplen = sysconf(_SC_GETPW_R_SIZE_MAX);
-	if (tmplen < 0) {
-		error(ap->logopt, "failed to get buffer size for getpwuid_r");
-		free(tsv);
-		goto cont;
-	}
-
-	pw_tmp = malloc(tmplen + 1);
-	if (!pw_tmp) {
-		error(ap->logopt, "failed to malloc buffer for getpwuid_r");
-		free(tsv);
-		goto cont;
-	}
-
-	status = getpwuid_r(tsv->uid, ppw, pw_tmp, tmplen, pppw);
-	if (status || !ppw) {
-		error(ap->logopt, "failed to get passwd info from getpwuid_r");
-		free(tsv);
-		free(pw_tmp);
-		goto cont;
-	}
-
-	tsv->user = strdup(pw.pw_name);
-	if (!tsv->user) {
-		error(ap->logopt, "failed to malloc buffer for user");
-		free(tsv);
-		free(pw_tmp);
-		goto cont;
-	}
-
-	tsv->home = strdup(pw.pw_dir);
-	if (!tsv->home) {
-		error(ap->logopt, "failed to malloc buffer for home");
-		free(pw_tmp);
-		free(tsv->user);
-		free(tsv);
-		goto cont;
-	}
-
-	free(pw_tmp);
-
-	/* Try to get group info */
-
-	grplen = sysconf(_SC_GETGR_R_SIZE_MAX);
-	if (tmplen < 0) {
-		error(ap->logopt, "failed to get buffer size for getgrgid_r");
-		free(tsv->user);
-		free(tsv->home);
-		free(tsv);
-		goto cont;
-	}
-
-	gr_tmp = NULL;
-	tmplen = grplen;
-	while (1) {
-		char *tmp = realloc(gr_tmp, tmplen + 1);
-		if (!tmp) {
-			error(ap->logopt, "failed to malloc buffer for getgrgid_r");
-			if (gr_tmp)
-				free(gr_tmp);
-			free(tsv->user);
-			free(tsv->home);
-			free(tsv);
-			goto cont;
-		}
-		gr_tmp = tmp;
-		pgr = &gr;
-		ppgr = &pgr;
-		status = getgrgid_r(tsv->gid, pgr, gr_tmp, tmplen, ppgr);
-		if (status != ERANGE)
-			break;
-		tmplen += grplen;
-	}
-
-	if (status || !pgr) {
-		error(ap->logopt, "failed to get group info from getgrgid_r");
-		free(tsv->user);
-		free(tsv->home);
-		free(tsv);
-		free(gr_tmp);
-		goto cont;
-	}
-
-	tsv->group = strdup(gr.gr_name);
-	if (!tsv->group) {
-		error(ap->logopt, "failed to malloc buffer for group");
-		free(tsv->user);
-		free(tsv->home);
-		free(tsv);
-		free(gr_tmp);
-		goto cont;
-	}
-
-	free(gr_tmp);
-
-	status = pthread_setspecific(key_thread_stdenv_vars, tsv);
-	if (status) {
-		error(ap->logopt, "failed to set stdenv thread var");
-		free(tsv->group);
-		free(tsv->user);
-		free(tsv->home);
-		free(tsv);
-	}
+	set_tsd_user_vars(ap->logopt, mt.uid, mt.gid);
 
-cont:
 	status = lookup_nss_mount(ap, NULL, mt.name, mt.len);
 	/*
 	 * Direct mounts are always a single mount. If it fails there's
--- autofs-5.0.2.orig/daemon/indirect.c
+++ autofs-5.0.2/daemon/indirect.c
@@ -33,8 +33,6 @@
 #include <sys/time.h>
 #include <sys/mount.h>
 #include <sched.h>
-#include <pwd.h>
-#include <grp.h>
 
 #include "automount.h"
 
@@ -672,15 +670,7 @@ static void *do_mount_indirect(void *arg
 	struct autofs_point *ap;
 	char buf[PATH_MAX + 1];
 	struct stat st;
-	struct passwd pw;
-	struct passwd *ppw = &pw;
-	struct passwd **pppw = &ppw;
-	struct group gr;
-	struct group *pgr;
-	struct group **ppgr;
-	char *pw_tmp, *gr_tmp;
-	struct thread_stdenv_vars *tsv;
-	int len, tmplen, grplen, status, state;
+	int len, status, state;
 
 	args = (struct pending_args *) arg;
 
@@ -722,125 +712,8 @@ static void *do_mount_indirect(void *arg
 
 	info(ap->logopt, "attempting to mount entry %s", buf);
 
-	/*
-	 * Setup thread specific data values for macro
-	 * substution in map entries during the mount.
-	 * Best effort only as it must go ahead.
-	 */
-
-	tsv = malloc(sizeof(struct thread_stdenv_vars));
-	if (!tsv) 
-		goto cont;
-
-	tsv->uid = mt.uid;
-	tsv->gid = mt.gid;
-
-	/* Try to get passwd info */
-
-	tmplen = sysconf(_SC_GETPW_R_SIZE_MAX);
-	if (tmplen < 0) {
-		error(ap->logopt, "failed to get buffer size for getpwuid_r");
-		free(tsv);
-		goto cont;
-	}
-
-	pw_tmp = malloc(tmplen + 1);
-	if (!pw_tmp) {
-		error(ap->logopt, "failed to malloc buffer for getpwuid_r");
-		free(tsv);
-		goto cont;
-	}
-
-	status = getpwuid_r(tsv->uid, ppw, pw_tmp, tmplen, pppw);
-	if (status || !ppw) {
-		error(ap->logopt, "failed to get passwd info from getpwuid_r");
-		free(tsv);
-		free(pw_tmp);
-		goto cont;
-	}
-
-	tsv->user = strdup(pw.pw_name);
-	if (!tsv->user) {
-		error(ap->logopt, "failed to malloc buffer for user");
-		free(tsv);
-		free(pw_tmp);
-		goto cont;
-	}
-
-	tsv->home = strdup(pw.pw_dir);
-	if (!tsv->home) {
-		error(ap->logopt, "failed to malloc buffer for home");
-		free(pw_tmp);
-		free(tsv->user);
-		free(tsv);
-		goto cont;
-	}
-
-	free(pw_tmp);
-
-	/* Try to get group info */
-
-	grplen = sysconf(_SC_GETGR_R_SIZE_MAX);
-	if (tmplen < 0) {
-		error(ap->logopt, "failed to get buffer size for getgrgid_r");
-		free(tsv->user);
-		free(tsv->home);
-		free(tsv);
-		goto cont;
-	}
-
-	gr_tmp = NULL;
-	tmplen = grplen;
-	while (1) {
-		char *tmp = realloc(gr_tmp, tmplen + 1);
-		if (!tmp) {
-			error(ap->logopt, "failed to malloc buffer for getgrgid_r");
-			if (gr_tmp)
-				free(gr_tmp);
-			free(tsv->user);
-			free(tsv->home);
-			free(tsv);
-			goto cont;
-		}
-		gr_tmp = tmp;
-		pgr = &gr;
-		ppgr = &pgr;
-		status = getgrgid_r(tsv->gid, pgr, gr_tmp, tmplen, ppgr);
-		if (status != ERANGE)
-			break;
-		tmplen += grplen;
-	}
-
-	if (status || !pgr) {
-		error(ap->logopt, "failed to get group info from getgrgid_r");
-		free(tsv->user);
-		free(tsv->home);
-		free(tsv);
-		free(gr_tmp);
-		goto cont;
-	}
-
-	tsv->group = strdup(gr.gr_name);
-	if (!tsv->group) {
-		error(ap->logopt, "failed to malloc buffer for group");
-		free(tsv->user);
-		free(tsv->home);
-		free(tsv);
-		free(gr_tmp);
-		goto cont;
-	}
+	set_tsd_user_vars(ap->logopt, mt.uid, mt.gid);
 
-	free(gr_tmp);
-
-	status = pthread_setspecific(key_thread_stdenv_vars, tsv);
-	if (status) {
-		error(ap->logopt, "failed to set stdenv thread var");
-		free(tsv->group);
-		free(tsv->user);
-		free(tsv->home);
-		free(tsv);
-	}
-cont:
 	status = lookup_nss_mount(ap, NULL, mt.name, mt.len);
 	pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &state);
 	if (status) {
--- autofs-5.0.2.orig/include/automount.h
+++ autofs-5.0.2/include/automount.h
@@ -28,6 +28,7 @@
 #include "macros.h"
 #include "log.h"
 #include "rpc_subs.h"
+#include "mounts.h"
 #include "parse_subs.h"
 
 #ifdef WITH_DMALLOC
@@ -323,61 +324,6 @@ int cat_path(char *buf, size_t len, cons
 int ncat_path(char *buf, size_t len,
               const char *dir, const char *base, size_t blen);
 
-/* mount table utilities */
-
-#define MNTS_ALL	0x0001
-#define MNTS_REAL	0x0002
-#define MNTS_AUTOFS	0x0004
-
-struct mnt_list {
-	char *path;
-	char *fs_name;
-	char *fs_type;
-	char *opts;
-	pid_t owner;
-	/*
-	 * List operations ie. get_mnt_list.
-	 */
-	struct mnt_list *next;
-	/*
-	 * Tree operations ie. tree_make_tree,
-	 * tree_get_mnt_list etc.
-	 */
-	struct mnt_list *left;
-	struct mnt_list *right;
-	struct list_head self;
-	struct list_head list;
-	struct list_head entries;
-	struct list_head sublist;
-	/*
-	 * Offset mount handling ie. add_ordered_list
-	 * and get_offset.
-	 */
-	struct list_head ordered;
-};
-
-unsigned int query_kproto_ver(void);
-unsigned int get_kver_major(void);
-unsigned int get_kver_minor(void);
-char *make_options_string(char *path, int kernel_pipefd, char *extra);
-char *make_mnt_name_string(char *path);
-struct mnt_list *get_mnt_list(const char *table, const char *path, int include);
-struct mnt_list *reverse_mnt_list(struct mnt_list *list);
-void free_mnt_list(struct mnt_list *list);
-int contained_in_local_fs(const char *path);
-int is_mounted(const char *table, const char *path, unsigned int type);
-int has_fstab_option(const char *opt);
-char *find_mnt_ino(const char *table, dev_t dev, ino_t ino);
-char *get_offset(const char *prefix, char *offset,
-                 struct list_head *head, struct list_head **pos);
-void add_ordered_list(struct mnt_list *ent, struct list_head *head);
-void tree_free_mnt_tree(struct mnt_list *tree);
-struct mnt_list *tree_make_mnt_tree(const char *table, const char *path);
-int tree_get_mnt_list(struct mnt_list *mnts, struct list_head *list, const char *path, int include);
-int tree_get_mnt_sublist(struct mnt_list *mnts, struct list_head *list, const char *path, int include);
-int tree_find_mnt_ents(struct mnt_list *mnts, struct list_head *list, const char *path);
-int tree_is_mounted(struct mnt_list *mnts, const char *path, unsigned int type);
-
 /* Core automount definitions */
 
 #define MNT_DETACH	0x00000002	/* Just detach from the tree */
--- /dev/null
+++ autofs-5.0.2/include/mounts.h
@@ -0,0 +1,91 @@
+/* ----------------------------------------------------------------------- *
+ *
+ *  mounts.h - header file for mount utilities module.
+ *
+ *   Copyright 2008 Red Hat, Inc. All rights reserved.
+ *   Copyright 2004-2006 Ian Kent <raven at themaw.net> - All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139,
+ *   USA; either version 2 of the License, or (at your option) any later
+ *   version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+#ifndef MOUNTS_H
+#define MOUNTS_H
+
+#define AUTOFS_TYPE_ANY		0x0000
+#define AUTOFS_TYPE_INDIRECT	0x0001
+#define AUTOFS_TYPE_DIRECT	0x0002
+#define AUTOFS_TYPE_OFFSET	0x0004
+
+#define MNTS_ALL	0x0001
+#define MNTS_REAL	0x0002
+#define MNTS_AUTOFS	0x0004
+
+#define REMOUNT_SUCCESS		0x0000
+#define REMOUNT_OPEN_FAIL	0x0001
+#define REMOUNT_STAT_FAIL	0x0002
+#define REMOUNT_READ_MAP	0x0004
+
+extern const unsigned int indirect;
+extern const unsigned int direct;
+extern const unsigned int offset;
+
+struct mapent;
+
+struct mnt_list {
+	char *path;
+	char *fs_name;
+	char *fs_type;
+	char *opts;
+	pid_t owner;
+	/*
+	 * List operations ie. get_mnt_list.
+	 */
+	struct mnt_list *next;
+	/*
+	 * Tree operations ie. tree_make_tree,
+	 * tree_get_mnt_list etc.
+	 */
+	struct mnt_list *left;
+	struct mnt_list *right;
+	struct list_head self;
+	struct list_head list;
+	struct list_head entries;
+	struct list_head sublist;
+	/*
+	 * Offset mount handling ie. add_ordered_list
+	 * and get_offset.
+	 */
+	struct list_head ordered;
+};
+
+unsigned int query_kproto_ver(void);
+unsigned int get_kver_major(void);
+unsigned int get_kver_minor(void);
+char *make_options_string(char *path, int kernel_pipefd, const char *extra);
+char *make_mnt_name_string(char *path);
+struct mnt_list *get_mnt_list(const char *table, const char *path, int include);
+struct mnt_list *reverse_mnt_list(struct mnt_list *list);
+void free_mnt_list(struct mnt_list *list);
+int contained_in_local_fs(const char *path);
+int is_mounted(const char *table, const char *path, unsigned int type);
+int has_fstab_option(const char *opt);
+char *get_offset(const char *prefix, char *offset,
+                 struct list_head *head, struct list_head **pos);
+void add_ordered_list(struct mnt_list *ent, struct list_head *head);
+void tree_free_mnt_tree(struct mnt_list *tree);
+struct mnt_list *tree_make_mnt_tree(const char *table, const char *path);
+int tree_get_mnt_list(struct mnt_list *mnts, struct list_head *list, const char *path, int include);
+int tree_get_mnt_sublist(struct mnt_list *mnts, struct list_head *list, const char *path, int include);
+int tree_find_mnt_ents(struct mnt_list *mnts, struct list_head *list, const char *path);
+int tree_is_mounted(struct mnt_list *mnts, const char *path, unsigned int type);
+void set_tsd_user_vars(unsigned int, uid_t, gid_t);
+int umount_ent(struct autofs_point *, const char *);
+int mount_multi_triggers(struct autofs_point *, char *, struct mapent *, const char *);
+int umount_multi_triggers(struct autofs_point *, char *, struct mapent *, const char *);
+
+#endif
--- autofs-5.0.2.orig/include/parse_subs.h
+++ autofs-5.0.2/include/parse_subs.h
@@ -27,8 +27,5 @@ int strmcmp(const char *, const char *, 
 char *dequote(const char *, int, unsigned int);
 int span_space(const char *, unsigned int);
 char *sanitize_path(const char *, int, unsigned int, unsigned int);
-int umount_ent(struct autofs_point *, const char *);
-int mount_multi_triggers(struct autofs_point *, char *, struct mapent *, const char *);
-int umount_multi_triggers(struct autofs_point *, char *, struct mapent *, const char *);
 
 #endif
--- autofs-5.0.2.orig/lib/mounts.c
+++ autofs-5.0.2/lib/mounts.c
@@ -1,6 +1,6 @@
 /* ----------------------------------------------------------------------- *
  *   
- *  mounts.c - module for Linux automount mount table lookup functions
+ *  mounts.c - module for mount utilities.
  *
  *   Copyright 2002-2005 Ian Kent <raven at themaw.net> - All Rights Reserved
  *
@@ -23,12 +23,21 @@
 #include <fcntl.h>
 #include <sys/mount.h>
 #include <stdio.h>
+#include <dirent.h>
+#include <sys/vfs.h>
+#include <pwd.h>
+#include <grp.h>
 
 #include "automount.h"
 
 #define MAX_OPTIONS_LEN		80
 #define MAX_MNT_NAME_LEN	30
 
+const unsigned int indirect = AUTOFS_TYPE_INDIRECT;
+const unsigned int direct = AUTOFS_TYPE_DIRECT;
+const unsigned int offset = AUTOFS_TYPE_OFFSET;
+const unsigned int type_count = 3;
+
 static const char options_template[]       = "fd=%d,pgrp=%u,minproto=5,maxproto=%d";
 static const char options_template_extra[] = "fd=%d,pgrp=%u,minproto=5,maxproto=%d,%s";
 static const char mnt_name_template[]      = "automount(pid%u)";
@@ -119,7 +128,7 @@ unsigned int get_kver_minor(void)
 /*
  * Make common autofs mount options string
  */
-char *make_options_string(char *path, int pipefd, char *extra)
+char *make_options_string(char *path, int pipefd, const char *extra)
 {
 	char *options;
 	int len;
@@ -462,51 +471,6 @@ int has_fstab_option(const char *opt)
 	return ret;
 }
 
-char *find_mnt_ino(const char *table, dev_t dev, ino_t ino)
-{
-	struct mntent mnt_wrk;
-	struct mntent *mnt;
-	char buf[PATH_MAX * 3];
-	char *path = NULL;
-	unsigned long l_dev = (unsigned long) dev;
-	unsigned long l_ino = (unsigned long) ino;
-	FILE *tab;
-
-	tab = setmntent(table, "r");
-	if (!tab) {
-		char *estr = strerror_r(errno, buf, (size_t) PATH_MAX - 1);
-		logerr("setmntent: %s", estr);
-		return 0;
-	}
-
-	while ((mnt = getmntent_r(tab, &mnt_wrk, buf, PATH_MAX * 3))) {
-		char *p_dev, *p_ino;
-		unsigned long m_dev, m_ino;
-
-		if (strcmp(mnt->mnt_type, "autofs"))
-			continue;
-
-		p_dev = strstr(mnt->mnt_opts, "dev=");
-		if (!p_dev)
-			continue;
-		sscanf(p_dev, "dev=%lu", &m_dev);
-		if (m_dev != l_dev)
-			continue;
-
-		p_ino = strstr(mnt->mnt_opts, "ino=");
-		if (!p_ino)
-			continue;
-		sscanf(p_ino, "ino=%lu", &m_ino);
-		if (m_ino == l_ino) {
-			path = strdup(mnt->mnt_dir);
-			break;
-		}
-	}
-	endmntent(tab);
-
-	return path;
-}
-
 char *get_offset(const char *prefix, char *offset,
 		 struct list_head *head, struct list_head **pos)
 {
@@ -982,3 +946,355 @@ int tree_is_mounted(struct mnt_list *mnt
 	return mounted;
 }
 
+void set_tsd_user_vars(unsigned int logopt, uid_t uid, gid_t gid)
+{
+	struct thread_stdenv_vars *tsv;
+	struct passwd pw;
+	struct passwd *ppw = &pw;
+	struct passwd **pppw = &ppw;
+	struct group gr;
+	struct group *pgr;
+	struct group **ppgr;
+	char *pw_tmp, *gr_tmp;
+	int status, tmplen, grplen;
+
+	/*
+	 * Setup thread specific data values for macro
+	 * substution in map entries during the mount.
+	 * Best effort only as it must go ahead.
+	 */
+
+	tsv = malloc(sizeof(struct thread_stdenv_vars));
+	if (!tsv) {
+		error(logopt, "failed alloc tsv storage");
+		return;
+	}
+
+	tsv->uid = uid;
+	tsv->gid = gid;
+
+	/* Try to get passwd info */
+
+	tmplen = sysconf(_SC_GETPW_R_SIZE_MAX);
+	if (tmplen < 0) {
+		error(logopt, "failed to get buffer size for getpwuid_r");
+		goto free_tsv;
+	}
+
+	pw_tmp = malloc(tmplen + 1);
+	if (!pw_tmp) {
+		error(logopt, "failed to malloc buffer for getpwuid_r");
+		goto free_tsv;
+	}
+
+	status = getpwuid_r(uid, ppw, pw_tmp, tmplen, pppw);
+	if (status || !ppw) {
+		error(logopt, "failed to get passwd info from getpwuid_r");
+		free(pw_tmp);
+		goto free_tsv;
+	}
+
+	tsv->user = strdup(pw.pw_name);
+	if (!tsv->user) {
+		error(logopt, "failed to malloc buffer for user");
+		free(pw_tmp);
+		goto free_tsv;
+	}
+
+	tsv->home = strdup(pw.pw_dir);
+	if (!tsv->home) {
+		error(logopt, "failed to malloc buffer for home");
+		free(pw_tmp);
+		goto free_tsv_user;
+	}
+
+	free(pw_tmp);
+
+	/* Try to get group info */
+
+	grplen = sysconf(_SC_GETGR_R_SIZE_MAX);
+	if (tmplen < 0) {
+		error(logopt, "failed to get buffer size for getgrgid_r");
+		goto free_tsv_home;
+	}
+
+	gr_tmp = NULL;
+	tmplen = grplen;
+	while (1) {
+		char *tmp = realloc(gr_tmp, tmplen + 1);
+		if (!tmp) {
+			error(logopt, "failed to malloc buffer for getgrgid_r");
+			if (gr_tmp)
+				free(gr_tmp);
+			goto free_tsv_home;
+		}
+		gr_tmp = tmp;
+		pgr = &gr;
+		ppgr = &pgr;
+		status = getgrgid_r(gid, pgr, gr_tmp, tmplen, ppgr);
+		if (status != ERANGE)
+			break;
+		tmplen += grplen;
+	}
+
+	if (status || !pgr) {
+		error(logopt, "failed to get group info from getgrgid_r");
+		free(gr_tmp);
+		goto free_tsv_home;
+	}
+
+	tsv->group = strdup(gr.gr_name);
+	if (!tsv->group) {
+		error(logopt, "failed to malloc buffer for group");
+		free(gr_tmp);
+		goto free_tsv_home;
+	}
+
+	free(gr_tmp);
+
+	status = pthread_setspecific(key_thread_stdenv_vars, tsv);
+	if (status) {
+		error(logopt, "failed to set stdenv thread var");
+		goto free_tsv_group;
+	}
+
+	return;
+
+free_tsv_group:
+	free(tsv->group);
+free_tsv_home:
+	free(tsv->home);
+free_tsv_user:
+	free(tsv->user);
+free_tsv:
+	free(tsv);
+	return;
+}
+
+int umount_ent(struct autofs_point *ap, const char *path)
+{
+	struct stat st;
+	struct statfs fs;
+	int sav_errno;
+	int status, is_smbfs = 0;
+	int ret, rv = 1;
+
+	ret = statfs(path, &fs);
+	if (ret == -1) {
+		warn(ap->logopt, "could not stat fs of %s", path);
+		is_smbfs = 0;
+	} else {
+		int cifsfs = fs.f_type == (__SWORD_TYPE) CIFS_MAGIC_NUMBER;
+		int smbfs = fs.f_type == (__SWORD_TYPE) SMB_SUPER_MAGIC;
+		is_smbfs = (cifsfs | smbfs) ? 1 : 0;
+	}
+
+	status = lstat(path, &st);
+	sav_errno = errno;
+
+	if (status < 0)
+		warn(ap->logopt, "lstat of %s failed with %d", path, status);
+
+	/*
+	 * lstat failed and we're an smbfs fs returning an error that is not
+	 * EIO or EBADSLT or the lstat failed so it's a bad path. Return
+	 * a fail.
+	 *
+	 * EIO appears to correspond to an smb mount that has gone away
+	 * and EBADSLT relates to CD changer not responding.
+	 */
+	if (!status && (S_ISDIR(st.st_mode) && st.st_dev != ap->dev)) {
+		rv = spawn_umount(ap->logopt, path, NULL);
+	} else if (is_smbfs && (sav_errno == EIO || sav_errno == EBADSLT)) {
+		rv = spawn_umount(ap->logopt, path, NULL);
+	}
+
+	/* 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");
+			return 0;
+		}
+
+		if (ret == 0 && !S_ISDIR(st.st_mode)) {
+			warn(ap->logopt, "mount point is not a directory");
+			return 0;
+		}
+
+		if (ap->state == ST_SHUTDOWN_FORCE) {
+			info(ap->logopt, "forcing umount of %s", path);
+			rv = spawn_umount(ap->logopt, "-l", path, NULL);
+		}
+
+		/*
+		 * Verify that we actually unmounted the thing.  This is a
+		 * belt and suspenders approach to not eating user data.
+		 * We have seen cases where umount succeeds, but there is
+		 * still a file system mounted on the mount point.  How
+		 * this happens has not yet been determined, but we want to
+		 * make sure to return failure here, if that is the case,
+		 * so that we do not try to call rmdir_path on the
+		 * directory.
+		 */
+		if (!rv && is_mounted(_PATH_MOUNTED, path, MNTS_REAL)) {
+			crit(ap->logopt,
+			     "the umount binary reported that %s was "
+			     "unmounted, but there is still something "
+			     "mounted on this path.", path);
+			rv = -1;
+		}
+	}
+
+	return rv;
+}
+
+int mount_multi_triggers(struct autofs_point *ap, char *root, struct mapent *me, const char *base)
+{
+	char path[PATH_MAX + 1];
+	char *offset = path;
+	struct mapent *oe;
+	struct list_head *pos = NULL;
+	unsigned int fs_path_len;
+	unsigned int mounted;
+	int ret, start;
+
+	fs_path_len = strlen(root) + strlen(base);
+	if (fs_path_len > PATH_MAX)
+		return -1;
+
+	strcpy(path, root);
+	strcat(path, base);
+
+	mounted = 0;
+	start = strlen(root);
+	offset = cache_get_offset(base, offset, start, &me->multi_list, &pos);
+	while (offset) {
+		int plen = fs_path_len + strlen(offset);
+
+		if (plen > PATH_MAX) {
+			warn(ap->logopt, "path loo long");
+			goto cont;
+		}
+
+		oe = cache_lookup_offset(base, offset, start, &me->multi_list);
+		if (!oe || !oe->mapent)
+			goto cont;
+
+		debug(ap->logopt, "mount offset %s", oe->key);
+
+		ret = mount_autofs_offset(ap, oe);
+		if (ret >= MOUNT_OFFSET_OK)
+			mounted++;
+		else {
+			if (ret != MOUNT_OFFSET_IGNORE)
+				warn(ap->logopt, "failed to mount offset");
+			else {
+				debug(ap->logopt,
+				      "ignoring \"nohide\" trigger %s",
+				      oe->key);
+				free(oe->mapent);
+				oe->mapent = NULL;
+			}
+		}
+cont:
+		offset = cache_get_offset(base,
+				offset, start, &me->multi_list, &pos);
+	}
+
+	return mounted;
+}
+
+int umount_multi_triggers(struct autofs_point *ap, char *root, struct mapent *me, const char *base)
+{
+	char path[PATH_MAX + 1];
+	char *offset;
+	struct mapent *oe;
+	struct list_head *mm_root, *pos;
+	const char o_root[] = "/";
+	const char *mm_base;
+	int left, start;
+
+	left = 0;
+	start = strlen(root);
+
+	mm_root = &me->multi->multi_list;
+
+	if (!base)
+		mm_base = o_root;
+	else
+		mm_base = base;
+
+	pos = NULL;
+	offset = path;
+
+	/* Make sure "none" of the offsets have an active mount. */
+	while ((offset = cache_get_offset(mm_base, offset, start, mm_root, &pos))) {
+		char *oe_base;
+
+		oe = cache_lookup_offset(mm_base, offset, start, &me->multi_list);
+		/* root offset is a special case */
+		if (!oe || !oe->mapent || (strlen(oe->key) - start) == 1)
+			continue;
+
+		/*
+		 * Check for and umount subtree offsets resulting from
+		 * nonstrict mount fail.
+		 */
+		oe_base = oe->key + strlen(root);
+		left += umount_multi_triggers(ap, root, oe, oe_base);
+
+		if (oe->ioctlfd != -1)
+			left++;
+	}
+
+	if (left)
+		return left;
+
+	pos = NULL;
+	offset = path;
+
+	/* Make sure "none" of the offsets have an active mount. */
+	while ((offset = cache_get_offset(mm_base, offset, start, mm_root, &pos))) {
+		oe = cache_lookup_offset(mm_base, offset, start, &me->multi_list);
+		/* root offset is a special case */
+		if (!oe || !oe->mapent || (strlen(oe->key) - start) == 1)
+			continue;
+
+		debug(ap->logopt, "umount offset %s", oe->key);
+
+		if (umount_autofs_offset(ap, oe)) {
+			warn(ap->logopt, "failed to umount offset");
+			left++;
+		}
+	}
+
+	if (!left && me->multi == me) {
+		struct mapent_cache *mc = me->mc;
+		int status;
+
+		/*
+		 * Special case.
+		 * If we can't umount the root container then we can't
+		 * delete the offsets from the cache and we need to put
+		 * the offset triggers back.
+		 */
+		if (is_mounted(_PATH_MOUNTED, root, MNTS_REAL)) {
+			info(ap->logopt, "unmounting dir = %s", root);
+			if (umount_ent(ap, root)) {
+				if (mount_multi_triggers(ap, root, me, "/") < 0)
+					warn(ap->logopt,
+					     "failed to remount offset triggers");
+				return left++;
+			}
+		}
+
+		/* We're done - clean out the offsets */
+		status = cache_delete_offset_list(mc, me->key);
+		if (status != CHE_OK)
+			warn(ap->logopt, "couldn't delete offset list");
+	}
+
+	return left;
+}
+
--- autofs-5.0.2.orig/lib/parse_subs.c
+++ autofs-5.0.2/lib/parse_subs.c
@@ -18,10 +18,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <ctype.h>
-#include <sys/types.h>
-#include <sys/stat.h>
 #include <unistd.h>
-#include <sys/vfs.h>
 #include "automount.h"
 
 /*
@@ -304,230 +301,3 @@ char *sanitize_path(const char *path, in
 	return s_path;
 }
 
-int umount_ent(struct autofs_point *ap, const char *path)
-{
-	struct stat st;
-	struct statfs fs;
-	int sav_errno;
-	int status, is_smbfs = 0;
-	int ret, rv = 1;
-
-	ret = statfs(path, &fs);
-	if (ret == -1) {
-		warn(ap->logopt, "could not stat fs of %s", path);
-		is_smbfs = 0;
-	} else {
-		int cifsfs = fs.f_type == (__SWORD_TYPE) CIFS_MAGIC_NUMBER;
-		int smbfs = fs.f_type == (__SWORD_TYPE) SMB_SUPER_MAGIC;
-		is_smbfs = (cifsfs | smbfs) ? 1 : 0;
-	}
-
-	status = lstat(path, &st);
-	sav_errno = errno;
-
-	if (status < 0)
-		warn(ap->logopt, "lstat of %s failed with %d", path, status);
-
-	/*
-	 * lstat failed and we're an smbfs fs returning an error that is not
-	 * EIO or EBADSLT or the lstat failed so it's a bad path. Return
-	 * a fail.
-	 *
-	 * EIO appears to correspond to an smb mount that has gone away
-	 * and EBADSLT relates to CD changer not responding.
-	 */
-	if (!status && (S_ISDIR(st.st_mode) && st.st_dev != ap->dev)) {
-		rv = spawn_umount(ap->logopt, path, NULL);
-	} else if (is_smbfs && (sav_errno == EIO || sav_errno == EBADSLT)) {
-		rv = spawn_umount(ap->logopt, path, NULL);
-	}
-
-	/* 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");
-			return 0;
-		}
-
-		if (ret == 0 && !S_ISDIR(st.st_mode)) {
-			warn(ap->logopt, "mount point is not a directory");
-			return 0;
-		}
-
-		if (ap->state == ST_SHUTDOWN_FORCE) {
-			info(ap->logopt, "forcing umount of %s", path);
-			rv = spawn_umount(ap->logopt, "-l", path, NULL);
-		}
-
-		/*
-		 * Verify that we actually unmounted the thing.  This is a
-		 * belt and suspenders approach to not eating user data.
-		 * We have seen cases where umount succeeds, but there is
-		 * still a file system mounted on the mount point.  How
-		 * this happens has not yet been determined, but we want to
-		 * make sure to return failure here, if that is the case,
-		 * so that we do not try to call rmdir_path on the
-		 * directory.
-		 */
-		if (!rv && is_mounted(_PATH_MOUNTED, path, MNTS_REAL)) {
-			crit(ap->logopt,
-			     "the umount binary reported that %s was "
-			     "unmounted, but there is still something "
-			     "mounted on this path.", path);
-			rv = -1;
-		}
-	}
-
-	return rv;
-}
-
-int mount_multi_triggers(struct autofs_point *ap, char *root, struct mapent *me, const char *base)
-{
-	char path[PATH_MAX + 1];
-	char *offset = path;
-	struct mapent *oe;
-	struct list_head *pos = NULL;
-	unsigned int fs_path_len;
-	unsigned int mounted;
-	int ret, start;
-
-	fs_path_len = strlen(root) + strlen(base);
-	if (fs_path_len > PATH_MAX)
-		return -1;
-
-	strcpy(path, root);
-	strcat(path, base);
-
-	mounted = 0;
-	start = strlen(root);
-	offset = cache_get_offset(base, offset, start, &me->multi_list, &pos);
-	while (offset) {
-		int plen = fs_path_len + strlen(offset);
-
-		if (plen > PATH_MAX) {
-			warn(ap->logopt, "path loo long");
-			goto cont;
-		}
-
-		oe = cache_lookup_offset(base, offset, start, &me->multi_list);
-		if (!oe || !oe->mapent)
-			goto cont;
-
-		debug(ap->logopt, "mount offset %s", oe->key);
-
-		ret = mount_autofs_offset(ap, oe);
-		if (ret >= MOUNT_OFFSET_OK)
-			mounted++;
-		else {
-			if (ret != MOUNT_OFFSET_IGNORE)
-				warn(ap->logopt, "failed to mount offset");
-			else {
-				debug(ap->logopt,
-				      "ignoring \"nohide\" trigger %s",
-				      oe->key);
-				free(oe->mapent);
-				oe->mapent = NULL;
-			}
-		}
-cont:
-		offset = cache_get_offset(base,
-				offset, start, &me->multi_list, &pos);
-	}
-
-	return mounted;
-}
-
-int umount_multi_triggers(struct autofs_point *ap, char *root, struct mapent *me, const char *base)
-{
-	char path[PATH_MAX + 1];
-	char *offset;
-	struct mapent *oe;
-	struct list_head *mm_root, *pos;
-	const char o_root[] = "/";
-	const char *mm_base;
-	int left, start;
-
-	left = 0;
-	start = strlen(root);
-
-	mm_root = &me->multi->multi_list;
-
-	if (!base)
-		mm_base = o_root;
-	else
-		mm_base = base;
-
-	pos = NULL;
-	offset = path;
-
-	/* Make sure "none" of the offsets have an active mount. */
-	while ((offset = cache_get_offset(mm_base, offset, start, mm_root, &pos))) {
-		char *oe_base;
-
-		oe = cache_lookup_offset(mm_base, offset, start, &me->multi_list);
-		/* root offset is a special case */
-		if (!oe || !oe->mapent || (strlen(oe->key) - start) == 1)
-			continue;
-
-		/*
-		 * Check for and umount subtree offsets resulting from
-		 * nonstrict mount fail.
-		 */
-		oe_base = oe->key + strlen(root);
-		left += umount_multi_triggers(ap, root, oe, oe_base);
-
-		if (oe->ioctlfd != -1)
-			left++;
-	}
-
-	if (left)
-		return left;
-
-	pos = NULL;
-	offset = path;
-
-	/* Make sure "none" of the offsets have an active mount. */
-	while ((offset = cache_get_offset(mm_base, offset, start, mm_root, &pos))) {
-		oe = cache_lookup_offset(mm_base, offset, start, &me->multi_list);
-		/* root offset is a special case */
-		if (!oe || !oe->mapent || (strlen(oe->key) - start) == 1)
-			continue;
-
-		debug(ap->logopt, "umount offset %s", oe->key);
-
-		if (umount_autofs_offset(ap, oe)) {
-			warn(ap->logopt, "failed to umount offset");
-			left++;
-		}
-	}
-
-	if (!left && me->multi == me) {
-		struct mapent_cache *mc = me->mc;
-		int status;
-
-		/*
-		 * Special case.
-		 * If we can't umount the root container then we can't
-		 * delete the offsets from the cache and we need to put
-		 * the offset triggers back.
-		 */
-		if (is_mounted(_PATH_MOUNTED, root, MNTS_REAL)) {
-			info(ap->logopt, "unmounting dir = %s", root);
-			if (umount_ent(ap, root)) {
-				if (mount_multi_triggers(ap, root, me, "/") < 0)
-					warn(ap->logopt,
-					     "failed to remount offset triggers");
-				return left++;
-			}
-		}
-
-		/* We're done - clean out the offsets */
-		status = cache_delete_offset_list(mc, me->key);
-		if (status != CHE_OK)
-			warn(ap->logopt, "couldn't delete offset list");
-	}
-
-	return left;
-}
-

autofs-5.0.3-remove-redundant-dns-name-lookups.patch:

--- NEW FILE autofs-5.0.3-remove-redundant-dns-name-lookups.patch ---
autofs-5.0.3 - eliminate redundant DNS name lookups

From: Ian Kent <raven at themaw.net>

When autofs tries to lookup a DNS host name where one or more DNS
servers aren't available the mount can take a long time. This is
caused by autofs doing the name lookups more often than it needs
to. This patch removes a number of these redundant name lookups.
---

 include/replicated.h |    1 +
 include/rpc_subs.h   |    4 +++-
 lib/rpc_subs.c       |   22 ++++++++++++++++++++--
 modules/replicated.c |   25 +++++++++++++++++++------
 4 files changed, 43 insertions(+), 9 deletions(-)


--- autofs-5.0.2.orig/include/replicated.h
+++ autofs-5.0.2/include/replicated.h
@@ -52,6 +52,7 @@
 struct host {
 	char *name;
 	char *addr;
+	size_t addr_len;
 	char *path;
 	unsigned int version;
 	unsigned int proximity;
--- autofs-5.0.2.orig/include/rpc_subs.h
+++ autofs-5.0.2/include/rpc_subs.h
@@ -46,6 +46,8 @@
 
 struct conn_info {
 	const char *host;
+	const char *addr;
+	size_t addr_len;
 	unsigned short port;
 	unsigned long program;
 	unsigned long version;
@@ -61,7 +63,7 @@ int rpc_udp_getclient(struct conn_info *
 void rpc_destroy_udp_client(struct conn_info *);
 int rpc_tcp_getclient(struct conn_info *, unsigned int, unsigned int);
 void rpc_destroy_tcp_client(struct conn_info *);
-int rpc_portmap_getclient(struct conn_info *, const char *, const char *, unsigned int);
+int rpc_portmap_getclient(struct conn_info *, const char *, const char *, size_t, const char *, unsigned int);
 unsigned short rpc_portmap_getport(struct conn_info *, struct pmap *);
 int rpc_ping_proto(struct conn_info *);
 int rpc_ping(const char *, long, long, unsigned int);
--- autofs-5.0.2.orig/lib/rpc_subs.c
+++ autofs-5.0.2/lib/rpc_subs.c
@@ -86,6 +86,11 @@ static CLIENT *create_udp_client(struct 
 	memset(&raddr, 0, sizeof(raddr));
 
 	raddr.sin_family = AF_INET;
+	if (info->addr) {
+		memcpy(&raddr.sin_addr.s_addr, info->addr, info->addr_len);
+		goto got_addr;
+	}
+
 	if (inet_aton(info->host, &raddr.sin_addr))
 		goto got_addr;
 
@@ -295,6 +300,11 @@ static CLIENT *create_tcp_client(struct 
 	memset(&addr, 0, sizeof(addr));
 
 	addr.sin_family = AF_INET;
+	if (info->addr) {
+		memcpy(&addr.sin_addr.s_addr, info->addr, info->addr_len);
+		goto got_addr;
+	}
+
 	if (inet_aton(info->host, &addr.sin_addr))
 		goto got_addr;
 
@@ -407,8 +417,8 @@ void rpc_destroy_tcp_client(struct conn_
 }
 
 int rpc_portmap_getclient(struct conn_info *info,
-			  const char *host, const char *proto,
-			  unsigned int option)
+			  const char *host, const char *addr, size_t addr_len,
+			  const char *proto, unsigned int option)
 {
 	struct protoent *pe_proto;
 	CLIENT *client;
@@ -418,6 +428,8 @@ int rpc_portmap_getclient(struct conn_in
 		return 0;
 
 	info->host = host;
+	info->addr = addr;
+	info->addr_len = addr_len;
 	info->program = PMAPPROG;
 	info->port = PMAPPORT;
 	info->version = PMAPVERS;
@@ -462,6 +474,8 @@ unsigned short rpc_portmap_getport(struc
 		client = info->client;
 	else {
 		pmap_info.host = info->host;
+		pmap_info.addr = info->addr;
+		pmap_info.addr_len = info->addr_len;
 		pmap_info.port = PMAPPORT;
 		pmap_info.program = PMAPPROG;
 		pmap_info.version = PMAPVERS;
@@ -589,6 +603,8 @@ static unsigned int __rpc_ping(const cha
 	struct pmap parms;
 
 	info.host = host;
+	info.addr = NULL;
+	info.addr_len = 0;
 	info.program = NFS_PROGRAM;
 	info.version = version;
 	info.send_sz = 0;
@@ -769,6 +785,8 @@ exports rpc_get_exports(const char *host
 	int status;
 
 	info.host = host;
+	info.addr = NULL;
+	info.addr_len = 0;
 	info.program = MOUNTPROG;
 	info.version = MOUNTVERS;
 	info.send_sz = 0;
--- autofs-5.0.2.orig/modules/replicated.c
+++ autofs-5.0.2/modules/replicated.c
@@ -225,7 +225,9 @@ static unsigned int get_proximity(const 
 	return PROXIMITY_OTHER;
 }
 
-static struct host *new_host(const char *name, const char *addr, unsigned int proximity, unsigned int weight)
+static struct host *new_host(const char *name,
+			     const char *addr, size_t addr_len,
+			     unsigned int proximity, unsigned int weight)
 {
 	struct host *new;
 	char *tmp1, *tmp2;
@@ -237,11 +239,12 @@ static struct host *new_host(const char 
 	if (!tmp1)
 		return NULL;
 
-	tmp2 = strdup(addr);
+	tmp2 = malloc(addr_len);
 	if (!tmp2) {
 		free(tmp1);
 		return NULL;
 	}
+	memcpy(tmp2, addr, addr_len);
 
 	new = malloc(sizeof(struct host));
 	if (!new) {
@@ -253,6 +256,7 @@ static struct host *new_host(const char 
 	memset(new, 0, sizeof(struct host));
 
 	new->name = tmp1;
+	new->addr_len = addr_len;
 	new->addr = tmp2;
 	new->proximity = proximity;
 	new->weight = weight;
@@ -437,7 +441,8 @@ static unsigned int get_nfs_info(unsigne
 v3_ver:
 	if (!have_port_opt) {
 		status = rpc_portmap_getclient(pm_info,
-				 host->name, proto, RPC_CLOSE_DEFAULT);
+				host->name, host->addr, host->addr_len,
+				proto, RPC_CLOSE_DEFAULT);
 		if (!status)
 			goto done_ver;
 	}
@@ -551,6 +556,8 @@ static int get_vers_and_cost(unsigned lo
 		timeout = RPC_TIMEOUT * 8;
 
 	rpc_info.host = host->name;
+	rpc_info.addr = host->addr;
+	rpc_info.addr_len = host->addr_len;
 	rpc_info.program = NFS_PROGRAM;
 	rpc_info.timeout.tv_sec = timeout;
 	rpc_info.close_option = RPC_CLOSE_DEFAULT;
@@ -606,6 +613,8 @@ static int get_supported_ver_and_cost(un
 		timeout = RPC_TIMEOUT * 8;
 
 	rpc_info.host = host->name;
+	rpc_info.addr = host->addr;
+	rpc_info.addr_len = host->addr_len;
 	rpc_info.program = NFS_PROGRAM;
 	rpc_info.timeout.tv_sec = timeout;
 	rpc_info.close_option = RPC_CLOSE_DEFAULT;
@@ -652,7 +661,8 @@ static int get_supported_ver_and_cost(un
 			return 0;
 	} else {
 		int ret = rpc_portmap_getclient(&pm_info,
-				 host->name, proto, RPC_CLOSE_DEFAULT);
+				host->name, host->addr, host->addr_len,
+				proto, RPC_CLOSE_DEFAULT);
 		if (!ret)
 			return 0;
 
@@ -868,7 +878,7 @@ static int add_host_addrs(struct host **
 		if (prx == PROXIMITY_ERROR)
 			return 0;
 
-		if (!(new = new_host(host, thost, prx, weight)))
+		if (!(new = new_host(host, thost, sizeof(saddr.sin_addr), prx, weight)))
 			return 0;
 
 		if (!add_host(list, new))
@@ -891,11 +901,14 @@ static int add_host_addrs(struct host **
 	}
 
 	for (haddr = phe->h_addr_list; *haddr; haddr++) {
+		struct in_addr tt;
+
 		prx = get_proximity(*haddr, phe->h_length);
 		if (prx == PROXIMITY_ERROR)
 			return 0;
 
-		if (!(new = new_host(host, *haddr, prx, weight)))
+		memcpy(&tt, *haddr, sizeof(struct in_addr));
+		if (!(new = new_host(host, *haddr, phe->h_length, prx, weight)))
 			return 0;
 
 		if (!add_host(list, new)) {

autofs-5.0.3-submount-shutdown-recovery-12-fix.patch:

--- NEW FILE autofs-5.0.3-submount-shutdown-recovery-12-fix.patch ---
autofs-5.0.3 - submount shutdown recovery fix

From: Ian Kent <raven at themaw.net>

I was sure I fixed this in the final patch but evidently
not.
---

 daemon/direct.c |    2 --
 1 files changed, 0 insertions(+), 2 deletions(-)


diff --git a/daemon/direct.c b/daemon/direct.c
index 34e882b..afb354e 100644
--- a/daemon/direct.c
+++ b/daemon/direct.c
@@ -1129,7 +1129,6 @@ int handle_packet_expire_direct(struct autofs_point *ap, autofs_packet_expire_di
 		 */
 		crit(ap->logopt, "can't find map entry for (%lu,%lu)",
 		    (unsigned long) pkt->dev, (unsigned long) pkt->ino);
-		cache_unlock(mc);
 		master_source_unlock(ap->entry);
 		pthread_setcancelstate(state, NULL);
 		return 1;
@@ -1374,7 +1373,6 @@ int handle_packet_missing_direct(struct autofs_point *ap, autofs_packet_missing_
 		 */
 		logerr("can't find map entry for (%lu,%lu)",
 		    (unsigned long) pkt->dev, (unsigned long) pkt->ino);
-		cache_unlock(mc);
 		master_source_unlock(ap->entry);
 		pthread_setcancelstate(state, NULL);
 		return 1;

autofs-5.0.3-submount-shutdown-recovery-12.patch:

--- NEW FILE autofs-5.0.3-submount-shutdown-recovery-12.patch ---
autofs-5.0.3 - fix submount shutdown handling.

From: Ian Kent <raven at themaw.net>

When using submount maps on a busy system autofs can hang.

This problem comes about because of processes walking into the
submount filesystem when it is in the process of shutting down.
While this race has been fixed for other types of mounts it
still isn't possible to to block processes from walking into
submounts that are expiring so we need to be able to recover
when this happens.

This patch improves the submount shutdown logic and allows
submounts that become busy during shutdown to recover.
---

 daemon/automount.c     |  208 +++++++++++++++++++------------------------
 daemon/direct.c        |   97 ++++++++++++++------
 daemon/indirect.c      |  114 ++++++++++++++++++-----
 daemon/lookup.c        |   11 --
 daemon/state.c         |  235 +++++++++++++++++++++++++++++++++----------------
 include/automount.h    |   17 ---
 include/master.h       |    5 -
 include/state.h        |    9 +
 lib/alarm.c            |   14 --
 lib/master.c           |  182 +++++++------------------------------
 modules/mount_autofs.c |    2 
 11 files changed, 458 insertions(+), 436 deletions(-)


--- autofs-5.0.2.orig/daemon/automount.c
+++ autofs-5.0.2/daemon/automount.c
@@ -369,6 +369,18 @@ int count_mounts(unsigned logopt, const 
 
 static void check_rm_dirs(struct autofs_point *ap, const char *path, int incl)
 {
+	/*
+	 * If we're a submount the kernel can't know we're trying to
+	 * shutdown and so cannot block processes walking into the
+	 * mount point directory. If this is the call to umount_multi()
+	 * made during shutdown (incl == 0) we have to leave any mount
+	 * point directories in place so we can recover if needed. The
+	 * umount itself will clean these directories up for us
+	 * automagically.
+	 */
+	if (!incl && ap->submount)
+		return;
+
 	if ((!ap->ghost) ||
 	    (ap->state == ST_SHUTDOWN_PENDING ||
 	     ap->state == ST_SHUTDOWN_FORCE ||
@@ -390,8 +402,6 @@ static void update_map_cache(struct auto
 	else
 		key = path;
 
-	pthread_cleanup_push(master_source_lock_cleanup, ap->entry);
-	master_source_readlock(ap->entry);
 	map = ap->entry->maps;
 	while (map) {
 		struct mapent *me = NULL;
@@ -413,7 +423,6 @@ static void update_map_cache(struct auto
 
 		map = map->next;
 	}
-	pthread_cleanup_pop(1);
 
 	return;
 }
@@ -918,38 +927,22 @@ static int get_pkt(struct autofs_point *
 		}
 
 		if (fds[1].revents & POLLIN) {
-			enum states next_state, post_state;
+			enum states next_state;
 			size_t read_size = sizeof(next_state);
 			int state_pipe;
 
-			next_state = post_state = ST_INVAL;
+			next_state = ST_INVAL;
 
-			state_mutex_lock(ap);
+			st_mutex_lock();
 
 			state_pipe = ap->state_pipe[0];
 
 			if (fullread(state_pipe, &next_state, read_size)) {
-				state_mutex_unlock(ap);
+				st_mutex_unlock();
 				continue;
 			}
 
-			if (next_state != ST_INVAL && next_state != ap->state) {
-				if (next_state != ST_SHUTDOWN)
-					post_state = next_state;
-				else
-					ap->state = ST_SHUTDOWN;
-			}
-
-			state_mutex_unlock(ap);
-
-			if (post_state != ST_INVAL) {
-				if (post_state == ST_SHUTDOWN_PENDING ||
-				    post_state == ST_SHUTDOWN_FORCE) {
-					alarm_delete(ap);
-					st_remove_tasks(ap);
-				}
-				st_add_task(ap, post_state);
-			}
+			st_mutex_unlock();
 
 			if (next_state == ST_SHUTDOWN)
 				return -1;
@@ -985,11 +978,14 @@ int do_expire(struct autofs_point *ap, c
 
 	info(ap->logopt, "expiring path %s", buf);
 
+	pthread_cleanup_push(master_source_lock_cleanup, ap->entry);
+	master_source_readlock(ap->entry);
 	ret = umount_multi(ap, buf, 1);
 	if (ret == 0)
 		info(ap->logopt, "expired %s", buf);
 	else
 		warn(ap->logopt, "couldn't complete expire of %s", buf);
+	pthread_cleanup_pop(1);
 
 	return ret;
 }
@@ -1069,7 +1065,7 @@ static int mount_autofs(struct autofs_po
 	if (status < 0)
 		return -1;
 
-	ap->state = ST_READY;
+	st_add_task(ap, ST_READY);
 
 	return 0;
 }
@@ -1423,44 +1419,6 @@ static void return_start_status(void *ar
 		fatal(status);
 }
 
-static void mutex_operation_wait(pthread_mutex_t *mutex)
-{
-	int status;
-
-	/*
-	 * Unlock a mutex, but wait for a pending operation
-	 * if one is in progress
-	 */
-	status = pthread_mutex_trylock(mutex);
-	if (status) {
-		if (status == EBUSY) {
-			/* Mutex locked - do we own it */
-			status = pthread_mutex_unlock(mutex);
-			if (status) {
-				if (status != EPERM)
-					fatal(status);
-			} else
-				return;
-
-			status = pthread_mutex_lock(mutex);
-			if (status)
-				fatal(status);
-		} else
-			fatal(status);
-
-		/* Operation complete, release it */
-		status = pthread_mutex_unlock(mutex);
-		if (status)
-			fatal(status);
-	} else {
-		status = pthread_mutex_unlock(mutex);
-		if (status)
-			fatal(status);
-	}
-
-	return;
-}
-
 int handle_mounts_startup_cond_init(struct startup_cond *suc)
 {
 	int status;
@@ -1526,22 +1484,25 @@ static void handle_mounts_cleanup(void *
 	if (!submount && strcmp(ap->path, "/-") && ap->dir_created)
 		clean = 1;
 
-	/* If we have been canceled then we may hold the state mutex. */
-	mutex_operation_wait(&ap->state_mutex);
+	if (submount) {
+		/* We are finishing up */
+		ap->parent->submnt_count--;
+		list_del_init(&ap->mounts);
+	}
 
-	alarm_delete(ap);
-	st_remove_tasks(ap);
+	master_remove_mapent(ap->entry);
+	master_source_unlock(ap->entry);
 
-	umount_autofs(ap, 1);
+	if (submount) {
+		mounts_mutex_unlock(ap->parent);
+		master_source_unlock(ap->parent->entry);
+	}
+	master_mutex_unlock();
 
 	destroy_logpri_fifo(ap);
-	master_signal_submount(ap, MASTER_SUBMNT_JOIN);
-	master_remove_mapent(ap->entry);
 	master_free_mapent_sources(ap->entry, 1);
 	master_free_mapent(ap->entry);
 
-	sched_yield();
-
 	if (clean) {
 		if (rmdir(path) == -1) {
 			char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
@@ -1572,8 +1533,6 @@ void *handle_mounts(void *arg)
 	pthread_cleanup_push(return_start_status, suc);
 	pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cancel_state);
 
-	state_mutex_lock(ap);
-
 	status = pthread_mutex_lock(&suc->mutex);
 	if (status) {
 		logerr("failed to lock startup condition mutex!");
@@ -1583,7 +1542,6 @@ void *handle_mounts(void *arg)
 	if (mount_autofs(ap) < 0) {
 		crit(ap->logopt, "mount of %s failed!", ap->path);
 		suc->status = 1;
-		state_mutex_unlock(ap);
 		umount_autofs(ap, 1);
 		pthread_setcancelstate(cancel_state, NULL);
 		pthread_exit(NULL);
@@ -1600,56 +1558,70 @@ void *handle_mounts(void *arg)
 	if (!ap->submount && ap->exp_timeout)
 		alarm_add(ap, ap->exp_runfreq + rand() % ap->exp_runfreq);
 
-	pthread_cleanup_push(handle_mounts_cleanup, ap);
 	pthread_setcancelstate(cancel_state, NULL);
 
-	state_mutex_unlock(ap);
-
 	while (ap->state != ST_SHUTDOWN) {
 		if (handle_packet(ap)) {
-			int ret, result;
+			int ret, cur_state;
+
+			/*
+			 * If we're a submount we need to ensure our parent
+			 * doesn't try to mount us again until our shutdown
+			 * is complete and that any outstanding mounts are
+			 * completed before we try to shutdown.
+			 */
+			pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cur_state);
+
+			master_mutex_lock();
+
+			if (ap->submount) {
+				master_source_writelock(ap->parent->entry);
+				mounts_mutex_lock(ap->parent);
+			}
+
+			master_source_writelock(ap->entry);
+
+			if (ap->state != ST_SHUTDOWN) {
+				if (!ap->submount)
+					alarm_add(ap, ap->exp_runfreq);
+				/* Return to ST_READY is done immediately */
+				st_add_task(ap, ST_READY);
+				master_source_unlock(ap->entry);
+				if (ap->submount) {
+					mounts_mutex_unlock(ap->parent);
+					master_source_unlock(ap->parent->entry);
+				}
+
+				master_mutex_unlock();
+
+				pthread_setcancelstate(cur_state, NULL);
+				continue;
+			}
+
+			alarm_delete(ap);
+			st_remove_tasks(ap);
+			st_wait_task(ap, ST_ANY, 0);
 
-			state_mutex_lock(ap);
 			/*
 			 * For a direct mount map all mounts have already gone
-			 * by the time we get here.
+			 * by the time we get here and since we only ever
+			 * umount direct mounts at shutdown there is no need
+			 * to check for possible recovery.
 			 */
 			if (ap->type == LKP_DIRECT) {
-				status = 1;
-				state_mutex_unlock(ap);
+				umount_autofs(ap, 1);
 				break;
 			}
 
 			/*
-			 * If the ioctl fails assume the kernel doesn't have
-			 * AUTOFS_IOC_ASKUMOUNT and just continue.
+			 * If umount_autofs returns non-zero it wasn't able
+			 * to complete the umount and has left the mount intact
+			 * so we can continue. This can happen if a lookup
+			 * occurs while we're trying to umount.
 			 */
-			ret = ioctl(ap->ioctlfd, AUTOFS_IOC_ASKUMOUNT, &result);
-			if (ret == -1) {
-				state_mutex_unlock(ap);
+			ret = umount_autofs(ap, 1);
+			if (!ret)
 				break;
-			}
-
-			/* OK to exit */
-			if (ap->state == ST_SHUTDOWN) {
-				if (result) {
-					state_mutex_unlock(ap);
-					break;
-				}
-#ifdef ENABLE_IGNORE_BUSY_MOUNTS
-				/*
-				 * There weren't any active mounts but if the
-				 * filesystem is busy there may be a mount
-				 * request in progress so return to the ready
-				 * state unless a shutdown has been explicitly
-				 * requested.
-				 */
-				if (ap->shutdown) {
-					state_mutex_unlock(ap);
-					break;
-				}
-#endif
-			}
 
 			/* Failed shutdown returns to ready */
 			warn(ap->logopt,
@@ -1657,14 +1629,22 @@ void *handle_mounts(void *arg)
 			     ap->path);
 			if (!ap->submount)
 				alarm_add(ap, ap->exp_runfreq);
-			nextstate(ap->state_pipe[1], ST_READY);
+			/* Return to ST_READY is done immediately */
+			st_add_task(ap, ST_READY);
+			master_source_unlock(ap->entry);
+			if (ap->submount) {
+				mounts_mutex_unlock(ap->parent);
+				master_source_unlock(ap->parent->entry);
+			}
+
+			master_mutex_unlock();
+
+			pthread_setcancelstate(cur_state, NULL);
 
-			state_mutex_unlock(ap);
 		}
 	}
 
-	pthread_cleanup_pop(1);
-	sched_yield();
+	handle_mounts_cleanup(ap);
 
 	return NULL;
 }
--- autofs-5.0.2.orig/daemon/direct.c
+++ autofs-5.0.2/daemon/direct.c
@@ -216,8 +216,6 @@ int umount_autofs_direct(struct autofs_p
 
 	mnts = tree_make_mnt_tree(_PROC_MOUNTS, "/");
 	pthread_cleanup_push(mnts_cleanup, mnts);
-	pthread_cleanup_push(master_source_lock_cleanup, ap->entry);
-	master_source_readlock(ap->entry);
 	nc = ap->entry->master->nc;
 	cache_readlock(nc);
 	pthread_cleanup_push(cache_lock_cleanup, nc);
@@ -244,7 +242,6 @@ int umount_autofs_direct(struct autofs_p
 	}
 	pthread_cleanup_pop(1);
 	pthread_cleanup_pop(1);
-	pthread_cleanup_pop(1);
 
 	return 0;
 }
@@ -572,9 +569,10 @@ int umount_autofs_offset(struct autofs_p
 			return 1;
 		} else if (!status) {
 			if (ap->state != ST_SHUTDOWN_FORCE) {
-				error(ap->logopt,
-				      "ask umount returned busy for %s",
-				      me->key);
+				if (ap->shutdown)
+					error(ap->logopt,
+					     "ask umount returned busy for %s",
+					     me->key);
 				return 1;
 			} else {
 				me->ioctlfd = -1;
@@ -904,7 +902,10 @@ void *expire_proc_direct(void *arg)
 		 * All direct mounts must be present in the map
 		 * entry cache.
 		 */
+		pthread_cleanup_push(master_source_lock_cleanup, ap->entry);
+		master_source_readlock(ap->entry);
 		me = lookup_source_mapent(ap, next->path, LKP_DISTINCT);
+		pthread_cleanup_pop(1);
 		if (!me)
 			continue;
 
@@ -1110,6 +1111,8 @@ int handle_packet_expire_direct(struct a
 	struct pending_args *mt;
 	char buf[MAX_ERR_BUF];
 	pthread_t thid;
+	struct timespec wait;
+	struct timeval now;
 	int status, state;
 
 	pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &state);
@@ -1124,7 +1127,7 @@ int handle_packet_expire_direct(struct a
 	 * and since it got mounted we have to trust that
 	 * there is an entry in the cache.
 	 */
-	master_source_readlock(ap->entry);
+	master_source_writelock(ap->entry);
 	map = ap->entry->maps;
 	while (map) {
 		mc = map->mc;
@@ -1135,7 +1138,6 @@ int handle_packet_expire_direct(struct a
 		cache_unlock(mc);
 		map = map->next;
 	}
-	master_source_unlock(ap->entry);
 
 	if (!me) {
 		/*
@@ -1144,10 +1146,28 @@ int handle_packet_expire_direct(struct a
 		 */
 		crit(ap->logopt, "can't find map entry for (%lu,%lu)",
 		    (unsigned long) pkt->dev, (unsigned long) pkt->ino);
+		cache_unlock(mc);
+		master_source_unlock(ap->entry);
 		pthread_setcancelstate(state, NULL);
 		return 1;
 	}
 
+	/* Can't expire it if it isn't mounted */
+	if (me->ioctlfd == -1) {
+		int ioctlfd = open(me->key, O_RDONLY);
+		if (ioctlfd == -1) {
+			crit(ap->logopt, "can't open ioctlfd for %s",
+			     me->key);
+			pthread_setcancelstate(state, NULL);
+			return 1;
+		}
+		send_ready(ap->logopt, ioctlfd, pkt->wait_queue_token);
+		close(ioctlfd);
+		cache_unlock(mc);
+		master_source_unlock(ap->entry);
+		pthread_setcancelstate(state, NULL);
+		return 0;
+	}
 
 	mt = malloc(sizeof(struct pending_args));
 	if (!mt) {
@@ -1155,6 +1175,7 @@ int handle_packet_expire_direct(struct a
 		error(ap->logopt, "malloc: %s", estr);
 		send_fail(ap->logopt, me->ioctlfd, pkt->wait_queue_token);
 		cache_unlock(mc);
+		master_source_unlock(ap->entry);
 		pthread_setcancelstate(state, NULL);
 		return 1;
 	}
@@ -1184,6 +1205,7 @@ int handle_packet_expire_direct(struct a
 		error(ap->logopt, "expire thread create failed");
 		send_fail(ap->logopt, mt->ioctlfd, pkt->wait_queue_token);
 		cache_unlock(mc);
+		master_source_unlock(ap->entry);
 		expire_mutex_unlock(NULL);
 		pending_cond_destroy(mt);
 		free_pending_args(mt);
@@ -1192,14 +1214,18 @@ int handle_packet_expire_direct(struct a
 	}
 
 	cache_unlock(mc);
+	master_source_unlock(ap->entry);
 
 	pthread_cleanup_push(expire_mutex_unlock, NULL);
 	pthread_setcancelstate(state, NULL);
 
 	mt->signaled = 0;
 	while (!mt->signaled) {
+		gettimeofday(&now, NULL);
+		wait.tv_sec = now.tv_sec + 2;
+		wait.tv_nsec = now.tv_usec * 1000;
 		status = pthread_cond_wait(&mt->cond, &ea_mutex);
-		if (status)
+		if (status && status != ETIMEDOUT)
 			fatal(status);
 	}
 
@@ -1263,6 +1289,9 @@ static void *do_mount_direct(void *arg)
 	if (status == -1) {
 		error(ap->logopt,
 		      "can't stat direct mount trigger %s", mt.name);
+		send_fail(ap->logopt,
+			  mt.ioctlfd, mt.wait_queue_token);
+		close(mt.ioctlfd);
 		pthread_setcancelstate(state, NULL);
 		pthread_exit(NULL);
 	}
@@ -1272,6 +1301,8 @@ static void *do_mount_direct(void *arg)
 		error(ap->logopt,
 		     "direct trigger not valid or already mounted %s",
 		     mt.name);
+		send_ready(ap->logopt, mt.ioctlfd, mt.wait_queue_token);
+		close(mt.ioctlfd);
 		pthread_setcancelstate(state, NULL);
 		pthread_exit(NULL);
 	}
@@ -1290,19 +1321,12 @@ static void *do_mount_direct(void *arg)
 	pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &state);
 	if (status) {
 		struct mapent *me;
-		int real_mount, set_fd;
-		cache_readlock(mt.mc);
+		cache_writelock(mt.mc);
 		me = cache_lookup_distinct(mt.mc, mt.name);
-		real_mount = is_mounted(_PATH_MOUNTED, me->key, MNTS_REAL);
-		set_fd = (real_mount || me->multi == me);
-		cache_unlock(mt.mc);
-		if (set_fd) {
+		if (me)
 			me->ioctlfd = mt.ioctlfd;
-			send_ready(ap->logopt, mt.ioctlfd, mt.wait_queue_token);
-		} else {
-			send_ready(ap->logopt, mt.ioctlfd, mt.wait_queue_token);
-			close(mt.ioctlfd);
-		}
+		send_ready(ap->logopt, mt.ioctlfd, mt.wait_queue_token);
+		cache_unlock(mt.mc);
 		info(ap->logopt, "mounted %s", mt.name);
 	} else {
 		send_fail(ap->logopt, mt.ioctlfd, mt.wait_queue_token);
@@ -1325,11 +1349,21 @@ int handle_packet_missing_direct(struct 
 	struct pending_args *mt;
 	char buf[MAX_ERR_BUF];
 	int status = 0;
+	struct timespec wait;
+	struct timeval now;
 	int ioctlfd, len, cl_flags, state;
 
 	pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &state);
 
-	master_source_readlock(ap->entry);
+	/*
+	 * If our parent is a direct or offset mount that has been
+	 * covered by a mount and another lookup occurs after the
+	 * mount but before the device and inode are set in the
+	 * cache entry we will not be able to find the mapent. So
+	 * we must take the source writelock to ensure the parent
+	 * has mount is complete before we look for the entry.
+	 */
+	master_source_writelock(ap->entry);
 	map = ap->entry->maps;
 	while (map) {
 		/*
@@ -1349,7 +1383,6 @@ int handle_packet_missing_direct(struct 
 		cache_unlock(mc);
 		map = map->next;
 	}
-	master_source_unlock(ap->entry);
 
 	if (!me) {
 		/*
@@ -1358,6 +1391,8 @@ int handle_packet_missing_direct(struct 
 		 */
 		logerr("can't find map entry for (%lu,%lu)",
 		    (unsigned long) pkt->dev, (unsigned long) pkt->ino);
+		cache_unlock(mc);
+		master_source_unlock(ap->entry);
 		pthread_setcancelstate(state, NULL);
 		return 1;
 	}
@@ -1371,6 +1406,7 @@ int handle_packet_missing_direct(struct 
 
 	if (ioctlfd == -1) {
 		cache_unlock(mc);
+		master_source_unlock(ap->entry);
 		pthread_setcancelstate(state, NULL);
 		crit(ap->logopt, "failed to create ioctl fd for %s", me->key);
 		/* TODO:  how do we clear wait q in kernel ?? */
@@ -1386,12 +1422,11 @@ int handle_packet_missing_direct(struct 
 		  (unsigned long) pkt->wait_queue_token, me->key, pkt->pid);
 
 	/* Ignore packet if we're trying to shut down */
-	if (ap->shutdown ||
-	    ap->state == ST_SHUTDOWN_FORCE ||
-	    ap->state == ST_SHUTDOWN) {
+	if (ap->shutdown || ap->state == ST_SHUTDOWN_FORCE) {
 		send_fail(ap->logopt, ioctlfd, pkt->wait_queue_token);
 		close(ioctlfd);
 		cache_unlock(mc);
+		master_source_unlock(ap->entry);
 		pthread_setcancelstate(state, NULL);
 		return 1;
 	}
@@ -1402,6 +1437,7 @@ int handle_packet_missing_direct(struct 
 		send_fail(ap->logopt, ioctlfd, pkt->wait_queue_token);
 		close(ioctlfd);
 		cache_unlock(mc);
+		master_source_unlock(ap->entry);
 		pthread_setcancelstate(state, NULL);
 		return 1;
 	}
@@ -1413,6 +1449,7 @@ int handle_packet_missing_direct(struct 
 		send_fail(ap->logopt, ioctlfd, pkt->wait_queue_token);
 		close(ioctlfd);
 		cache_unlock(mc);
+		master_source_unlock(ap->entry);
 		pthread_setcancelstate(state, NULL);
 		return 1;
 	}
@@ -1447,6 +1484,7 @@ int handle_packet_missing_direct(struct 
 		send_fail(ap->logopt, ioctlfd, pkt->wait_queue_token);
 		close(ioctlfd);
 		cache_unlock(mc);
+		master_source_unlock(ap->entry);
 		mount_mutex_unlock(mt);
 		pending_cond_destroy(mt);
 		pending_mutex_destroy(mt);
@@ -1456,6 +1494,8 @@ int handle_packet_missing_direct(struct 
 	}
 
 	cache_unlock(mc);
+	master_source_unlock(ap->entry);
+
 	pthread_cleanup_push(free_pending_args, mt);
 	pthread_cleanup_push(pending_mutex_destroy, mt);
 	pthread_cleanup_push(pending_cond_destroy, mt);
@@ -1464,8 +1504,11 @@ int handle_packet_missing_direct(struct 
 
 	mt->signaled = 0;
 	while (!mt->signaled) {
-		status = pthread_cond_wait(&mt->cond, &mt->mutex);
-		if (status)
+		gettimeofday(&now, NULL);
+		wait.tv_sec = now.tv_sec + 2;
+		wait.tv_nsec = now.tv_usec * 1000;
+		status = pthread_cond_timedwait(&mt->cond, &mt->mutex, &wait);
+		if (status && status != ETIMEDOUT)
 			fatal(status);
 	}
 
--- autofs-5.0.2.orig/daemon/indirect.c
+++ autofs-5.0.2/daemon/indirect.c
@@ -230,11 +230,8 @@ int mount_autofs_indirect(struct autofs_
 	return 0;
 }
 
-int umount_autofs_indirect(struct autofs_point *ap)
+static void close_mount_fds(struct autofs_point *ap)
 {
-	char buf[MAX_ERR_BUF];
-	int ret, rv, retries;
-
 	/*
 	 * Since submounts look after themselves the parent never knows
 	 * it needs to close the ioctlfd for offset mounts so we have
@@ -244,6 +241,25 @@ int umount_autofs_indirect(struct autofs
 	if (ap->submount)
 		lookup_source_close_ioctlfd(ap->parent, ap->path);
 
+	close(ap->state_pipe[0]);
+	close(ap->state_pipe[1]);
+	ap->state_pipe[0] = -1;
+	ap->state_pipe[1] = -1;
+
+	if (ap->pipefd >= 0)
+		close(ap->pipefd);
+
+	if (ap->kpipefd >= 0)
+		close(ap->kpipefd);
+
+	return;
+}
+
+int umount_autofs_indirect(struct autofs_point *ap)
+{
+	char buf[MAX_ERR_BUF];
+	int ret, rv, retries;
+
 	/* If we are trying to shutdown make sure we can umount */
 	rv = ioctl(ap->ioctlfd, AUTOFS_IOC_ASKUMOUNT, &ret);
 	if (rv == -1) {
@@ -251,24 +267,20 @@ int umount_autofs_indirect(struct autofs
 		logerr("ioctl failed: %s", estr);
 		return 1;
 	} else if (!ret) {
+#if defined(ENABLE_IGNORE_BUSY_MOUNTS) || defined(ENABLE_FORCED_SHUTDOWN)
+		if (!ap->shutdown)
+			return 1;
 		error(ap->logopt, "ask umount returned busy %s", ap->path);
+#else
 		return 1;
+#endif
 	}
 
-	ioctl(ap->ioctlfd, AUTOFS_IOC_CATATONIC, 0);
+	if (ap->shutdown)
+		ioctl(ap->ioctlfd, AUTOFS_IOC_CATATONIC, 0);
+
 	close(ap->ioctlfd);
 	ap->ioctlfd = -1;
-	close(ap->state_pipe[0]);
-	close(ap->state_pipe[1]);
-	ap->state_pipe[0] = -1;
-	ap->state_pipe[1] = -1;
-
-	if (ap->pipefd >= 0)
-		close(ap->pipefd);
-
-	if (ap->kpipefd >= 0)
-		close(ap->kpipefd);
-
 	sched_yield();
 
 	retries = UMOUNT_RETRIES;
@@ -285,24 +297,61 @@ int umount_autofs_indirect(struct autofs
 		case EINVAL:
 			error(ap->logopt,
 			      "mount point %s does not exist", ap->path);
+			close_mount_fds(ap);
 			return 0;
 			break;
 		case EBUSY:
-			error(ap->logopt,
+			debug(ap->logopt,
 			      "mount point %s is in use", ap->path);
-			if (ap->state == ST_SHUTDOWN_FORCE)
+			if (ap->state == ST_SHUTDOWN_FORCE) {
+				close_mount_fds(ap);
 				goto force_umount;
-			else
-				return 0;
+			} else {
+				int cl_flags;
+				/*
+				 * If the umount returns EBUSY there may be
+				 * a mount request in progress so we need to
+				 * recover unless we have been explicitly
+				 * asked to shutdown and configure option
+				 * ENABLE_IGNORE_BUSY_MOUNTS is enabled.
+				 */
+#ifdef ENABLE_IGNORE_BUSY_MOUNTS
+				if (ap->shutdown) {
+					close_mount_fds(ap);
+					return 0;
+				}
+#endif
+				ap->ioctlfd = open(ap->path, O_RDONLY);
+				if (ap->ioctlfd < 0) {
+					warn(ap->logopt,
+					     "could not recover autofs path %s",
+					     ap->path);
+					close_mount_fds(ap);
+					return 0;
+				}
+
+				if ((cl_flags = fcntl(ap->ioctlfd, F_GETFD, 0)) != -1) {
+					cl_flags |= FD_CLOEXEC;
+					fcntl(ap->ioctlfd, F_SETFD, cl_flags);
+				}
+			}
 			break;
 		case ENOTDIR:
 			error(ap->logopt, "mount point is not a directory");
+			close_mount_fds(ap);
 			return 0;
 			break;
 		}
 		return 1;
 	}
 
+	/*
+	 * We have successfully umounted the mount so we now close
+	 * the descriptors. The kernel end of the kernel pipe will
+	 * have been put during the umount super block cleanup.
+	 */
+	close_mount_fds(ap);
+
 force_umount:
 	if (rv != 0) {
 		warn(ap->logopt,
@@ -439,9 +488,12 @@ void *expire_proc_indirect(void *arg)
 		 * Otherwise it's a top level indirect mount (possibly
 		 * with offsets in it) and we use the usual ioctlfd.
 		 */
+		pthread_cleanup_push(master_source_lock_cleanup, ap->entry);
+		master_source_readlock(ap->entry);
 		me = lookup_source_mapent(ap, next->path, LKP_DISTINCT);
 		if (!me && ind_key)
 			me = lookup_source_mapent(ap, ind_key, LKP_NORMAL);
+		pthread_cleanup_pop(1);
 		if (!me)
 			continue;
 
@@ -586,6 +638,8 @@ int handle_packet_expire_indirect(struct
 	struct pending_args *mt;
 	char buf[MAX_ERR_BUF];
 	pthread_t thid;
+	struct timespec wait;
+	struct timeval now;
 	int status, state;
 
 	pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &state);
@@ -632,8 +686,11 @@ int handle_packet_expire_indirect(struct
 
 	mt->signaled = 0;
 	while (!mt->signaled) {
-		status = pthread_cond_wait(&mt->cond, &ea_mutex);
-		if (status)
+		gettimeofday(&now, NULL);
+		wait.tv_sec = now.tv_sec + 2;
+		wait.tv_nsec = now.tv_usec * 1000;
+		status = pthread_cond_timedwait(&mt->cond, &ea_mutex, &wait);
+		if (status && status != ETIMEDOUT)
 			fatal(status);
 	}
 
@@ -735,6 +792,8 @@ int handle_packet_missing_indirect(struc
 	pthread_t thid;
 	char buf[MAX_ERR_BUF];
 	struct pending_args *mt;
+	struct timespec wait;
+	struct timeval now;
 	int status, state;
 
 	pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &state);
@@ -743,9 +802,7 @@ int handle_packet_missing_indirect(struc
 		(unsigned long) pkt->wait_queue_token, pkt->name, pkt->pid);
 
 	/* Ignore packet if we're trying to shut down */
-	if (ap->shutdown ||
-	    ap->state == ST_SHUTDOWN_FORCE ||
-	    ap->state == ST_SHUTDOWN) {
+	if (ap->shutdown || ap->state == ST_SHUTDOWN_FORCE) {
 		send_fail(ap->logopt, ap->ioctlfd, pkt->wait_queue_token);
 		pthread_setcancelstate(state, NULL);
 		return 0;
@@ -802,8 +859,11 @@ int handle_packet_missing_indirect(struc
 
 	mt->signaled = 0;
 	while (!mt->signaled) {
-		status = pthread_cond_wait(&mt->cond, &mt->mutex);
-		if (status)
+		gettimeofday(&now, NULL);
+		wait.tv_sec = now.tv_sec + 2;
+		wait.tv_nsec = now.tv_usec * 1000;
+		status = pthread_cond_timedwait(&mt->cond, &mt->mutex, &wait);
+		if (status && status != ETIMEDOUT)
 			fatal(status);
 	}
 
--- autofs-5.0.2.orig/daemon/lookup.c
+++ autofs-5.0.2/daemon/lookup.c
@@ -935,16 +935,10 @@ void lookup_close_lookup(struct autofs_p
 	if (!map)
 		return;
 
-	/*
-	 * Make sure we don't kill the context if a mount
-	 * request has come in while were shutting down.
-	 */
-	master_source_writelock(ap->entry);
 	while (map) {
 		lookup_close_lookup_instances(map);
 		map = map->next;
 	}
-	master_source_unlock(ap->entry);
 
 	return;
 }
@@ -1122,7 +1116,6 @@ struct mapent *lookup_source_mapent(stru
 	struct mapent_cache *mc;
 	struct mapent *me = NULL;
 
-	master_source_readlock(entry);
 	map = entry->maps;
 	while (map) {
 		mc = map->mc;
@@ -1136,7 +1129,6 @@ struct mapent *lookup_source_mapent(stru
 		cache_unlock(mc);
 		map = map->next;
 	}
-	master_source_unlock(entry);
 
 	return me;
 }
@@ -1149,8 +1141,6 @@ int lookup_source_close_ioctlfd(struct a
 	struct mapent *me;
 	int ret = 0;
 
-	pthread_cleanup_push(master_source_lock_cleanup, entry);
-	master_source_readlock(entry);
 	map = entry->maps;
 	while (map) {
 		mc = map->mc;
@@ -1168,7 +1158,6 @@ int lookup_source_close_ioctlfd(struct a
 		cache_unlock(mc);
 		map = map->next;
 	}
-	pthread_cleanup_pop(1);
 
 	return ret;
 }
--- autofs-5.0.2.orig/daemon/state.c
+++ autofs-5.0.2/daemon/state.c
@@ -37,19 +37,19 @@ static LIST_HEAD(state_queue);
 static void st_set_thid(struct autofs_point *, pthread_t);
 static void st_set_done(struct autofs_point *ap);
 
-#define st_mutex_lock() \
-do { \
-	int status = pthread_mutex_lock(&mutex); \
-	if (status) \
-		fatal(status); \
-} while (0)
-
-#define st_mutex_unlock() \
-do { \
-	int status = pthread_mutex_unlock(&mutex); \
-	if (status) \
-		fatal(status); \
-} while (0)
+void st_mutex_lock(void)
+{
+	int status = pthread_mutex_lock(&mutex);
+	if (status)
+		fatal(status);
+}
+
+void st_mutex_unlock(void)
+{
+	int status = pthread_mutex_unlock(&mutex);
+	if (status)
+		fatal(status);
+}
 
 int do_mount_autofs_direct(struct autofs_point *, struct mnt_list *, struct mapent *);
 
@@ -96,21 +96,19 @@ void expire_cleanup(void *arg)
 	pthread_t thid = pthread_self();
 	struct expire_args *ec;
 	struct autofs_point *ap;
-	int statefd, success;
+	int success;
 	enum states next = ST_INVAL;
 
 	ec = (struct expire_args *) arg;
 	ap = ec->ap;
 	success = ec->status;
 
-	state_mutex_lock(ap);
+	st_mutex_lock();
 
 	debug(ap->logopt,
 	      "got thid %lu path %s stat %d",
 	      (unsigned long) thid, ap->path, success);
 
-	statefd = ap->state_pipe[1];
-
 	/* Check to see if expire process finished */
 	if (thid == ap->exp_thread) {
 		int rv, idle;
@@ -199,11 +197,11 @@ void expire_cleanup(void *arg)
 	}
 
 	if (next != ST_INVAL)
-		nextstate(statefd, next);
+		__st_add_task(ap, next);
 
 	st_set_done(ap);
 
-	state_mutex_unlock(ap);
+	st_mutex_unlock();
 
 	return;
 }
@@ -216,9 +214,6 @@ static unsigned int st_ready(struct auto
 	ap->shutdown = 0;
 	ap->state = ST_READY;
 
-	if (ap->submount)
-		master_signal_submount(ap, MASTER_SUBMNT_CONTINUE);
-
 	return 1;
 }
 
@@ -333,18 +328,18 @@ static void do_readmap_cleanup(void *arg
 	ra = (struct readmap_args *) arg;
 
 	ap = ra->ap;
-	ap->readmap_thread = 0;
 
-	state_mutex_lock(ap);
+	st_mutex_lock();
 
-	nextstate(ap->state_pipe[1], ST_READY);
+	ap->readmap_thread = 0;
+	st_ready(ap);
 	st_set_done(ap);
 
-	state_mutex_unlock(ap);
-
 	if (!ap->submount)
 		alarm_add(ap, ap->exp_runfreq);
 
+	st_mutex_unlock();
+
 	free(ra);
 
 	return;
@@ -499,10 +494,8 @@ static unsigned int st_readmap(struct au
 	ra = malloc(sizeof(struct readmap_args));
 	if (!ra) {
 		error(ap->logopt, "failed to malloc reamap cond struct");
-		state_mutex_lock(ap);
-		nextstate(ap->state_pipe[1], ST_READY);
-		state_mutex_unlock(ap);
 		/* It didn't work: return to ready */
+		st_ready(ap);
 		if (!ap->submount)
 			alarm_add(ap, ap->exp_runfreq);
 		return 0;
@@ -528,10 +521,8 @@ static unsigned int st_readmap(struct au
 		error(ap->logopt, "read map thread create failed");
 		st_readmap_cleanup(ra);
 		free(ra);
-		state_mutex_lock(ap);
-		nextstate(ap->state_pipe[1], ST_READY);
-		state_mutex_unlock(ap);
 		/* It didn't work: return to ready */
+		st_ready(ap);
 		if (!ap->submount)
 			alarm_add(ap, ap->exp_runfreq);
 		return 0;
@@ -570,7 +561,7 @@ static unsigned int st_prepare_shutdown(
 		/* It didn't work: return to ready */
 		if (!ap->submount)
 			alarm_add(ap, ap->exp_runfreq);
-		nextstate(ap->state_pipe[1], ST_READY);
+		st_ready(ap);
 		return 0;
 
 	case EXP_STARTED:
@@ -596,7 +587,7 @@ static unsigned int st_force_shutdown(st
 		/* It didn't work: return to ready */
 		if (!ap->submount)
 			alarm_add(ap, ap->exp_runfreq);
-		nextstate(ap->state_pipe[1], ST_READY);
+		st_ready(ap);
 		return 0;
 
 	case EXP_STARTED:
@@ -605,6 +596,18 @@ static unsigned int st_force_shutdown(st
 	return 0;
 }
 
+static unsigned int st_shutdown(struct autofs_point *ap)
+{
+	debug(ap->logopt, "state %d path %s", ap->state, ap->path);
+
+	assert(ap->state == ST_SHUTDOWN_PENDING || ap->state == ST_SHUTDOWN_FORCE);
+
+	ap->state = ST_SHUTDOWN;
+	nextstate(ap->state_pipe[1], ST_SHUTDOWN);
+
+	return 0;
+}
+
 static unsigned int st_prune(struct autofs_point *ap)
 {
 	debug(ap->logopt, "state %d path %s", ap->state, ap->path);
@@ -617,7 +620,7 @@ static unsigned int st_prune(struct auto
 	case EXP_PARTIAL:
 		if (!ap->submount)
 			alarm_add(ap, ap->exp_runfreq);
-		nextstate(ap->state_pipe[1], ST_READY);
+		st_ready(ap);
 		return 0;
 
 	case EXP_STARTED:
@@ -638,7 +641,7 @@ static unsigned int st_expire(struct aut
 	case EXP_PARTIAL:
 		if (!ap->submount)
 			alarm_add(ap, ap->exp_runfreq);
-		nextstate(ap->state_pipe[1], ST_READY);
+		st_ready(ap);
 		return 0;
 
 	case EXP_STARTED:
@@ -665,43 +668,35 @@ static struct state_queue *st_alloc_task
 	return task;
 }
 
-/* Insert alarm entry on ordered list. */
-int st_add_task(struct autofs_point *ap, enum states state)
+/*
+ * Insert alarm entry on ordered list.
+ * State queue mutex and ap state mutex, in that order, must be held.
+ */
+int __st_add_task(struct autofs_point *ap, enum states state)
 {
 	struct list_head *head;
 	struct list_head *p, *q;
 	struct state_queue *new;
-	enum states ap_state;
 	unsigned int empty = 1;
 	int status;
 
 	/* Task termination marker, poke state machine */
 	if (state == ST_READY) {
-		state_mutex_lock(ap);
 		st_ready(ap);
-		state_mutex_unlock(ap);
-
-		st_mutex_lock();
 
 		signaled = 1;
 		status = pthread_cond_signal(&cond);
 		if (status)
 			fatal(status);
 
-		st_mutex_unlock();
-
 		return 1;
 	}
 
-	state_mutex_lock(ap);
-	ap_state = ap->state;
-	if (ap_state == ST_SHUTDOWN) {
-		state_mutex_unlock(ap);
+	if (ap->state == ST_SHUTDOWN)
 		return 1;
-	}
-	state_mutex_unlock(ap);
 
-	st_mutex_lock();
+	if (state == ST_SHUTDOWN)
+		return st_shutdown(ap);
 
 	head = &state_queue;
 
@@ -718,8 +713,8 @@ int st_add_task(struct autofs_point *ap,
 
 		/* Don't add duplicate tasks */
 		if ((task->state == state && !task->done) ||
-		   (ap_state == ST_SHUTDOWN_PENDING ||
-		    ap_state == ST_SHUTDOWN_FORCE))
+		   (ap->state == ST_SHUTDOWN_PENDING ||
+		    ap->state == ST_SHUTDOWN_FORCE))
 			break;
 
 		/* No pending tasks */
@@ -736,8 +731,8 @@ int st_add_task(struct autofs_point *ap,
 			p_task = list_entry(q, struct state_queue, pending);
 
 			if (p_task->state == state ||
-			   (ap_state == ST_SHUTDOWN_PENDING ||
-			    ap_state == ST_SHUTDOWN_FORCE))
+			   (ap->state == ST_SHUTDOWN_PENDING ||
+			    ap->state == ST_SHUTDOWN_FORCE))
 				goto done;
 		}
 
@@ -760,11 +755,24 @@ done:
 	if (status)
 		fatal(status);
 
+	return 1;
+}
+
+int st_add_task(struct autofs_point *ap, enum states state)
+{
+	int ret;
+
+	st_mutex_lock();
+	ret = __st_add_task(ap, state);
 	st_mutex_unlock();
 
-	return 1;
+	return ret;
 }
 
+/*
+ * Remove state queue tasks for ap.
+ * State queue mutex and ap state mutex, in that order, must be held.
+ */
 void st_remove_tasks(struct autofs_point *ap)
 {
 	struct list_head *head;
@@ -772,14 +780,10 @@ void st_remove_tasks(struct autofs_point
 	struct state_queue *task, *waiting;
 	int status;
 
-	st_mutex_lock();
-
 	head = &state_queue;
 
-	if (list_empty(head)) {
-		st_mutex_unlock();
+	if (list_empty(head))
 		return;
-	}
 
 	p = head->next;
 	while (p != head) {
@@ -816,12 +820,107 @@ void st_remove_tasks(struct autofs_point
 	if (status)
 		fatal(status);
 
+	return;
+}
+
+static int st_task_active(struct autofs_point *ap, enum states state)
+{
+	struct list_head *head;
+	struct list_head *p, *q;
+	struct state_queue *task, *waiting;
+	unsigned int active = 0;
+
+	st_mutex_lock();
+
+	head = &state_queue;
+
+	list_for_each(p, head) {
+		task = list_entry(p, struct state_queue, list);
+
+		if (task->ap != ap)
+			continue;
+
+		if (task->state == state) {
+			active = 1;
+			break;
+		}
+
+		if (state == ST_ANY) {
+			active = 1;
+			break;
+		}
+
+		list_for_each(q, &task->pending) {
+			waiting = list_entry(q, struct state_queue, pending);
+
+			if (waiting->state == state) {
+				active = 1;
+				break;
+			}
+
+			if (state == ST_ANY) {
+				active = 1;
+				break;
+			}
+		}
+	}
+
 	st_mutex_unlock();
 
-	return;
+	return active;
+}
+
+int st_wait_task(struct autofs_point *ap, enum states state, unsigned int seconds)
+{
+	unsigned int wait = 0;
+	unsigned int duration = 0;
+	int ret = 0;
 
+	while (1) {
+		struct timespec t = { 0, 200000000 };
+		struct timespec r;
+
+		while (nanosleep(&t, &r) == -1 && errno == EINTR)
+			memcpy(&t, &r, sizeof(struct timespec));
+
+		if (wait++ == 4) {
+			wait = 0;
+			duration++;
+		}
+
+		if (!st_task_active(ap, state)) {
+			ret = 1;
+			break;
+		}
+
+		if (seconds && duration >= seconds)
+			break;
+	}
+
+	return ret;
 }
 
+int st_wait_state(struct autofs_point *ap, enum states state)
+{
+	while (1) {
+		struct timespec t = { 0, 200000000 };
+		struct timespec r;
+
+		while (nanosleep(&t, &r) == -1 && errno == EINTR)
+			memcpy(&t, &r, sizeof(struct timespec));
+
+		st_mutex_lock();
+		if (ap->state == state) {
+			st_mutex_unlock();
+			return 1;
+		}
+		st_mutex_unlock();
+	}
+
+	return 0;
+}
+
+
 static int run_state_task(struct state_queue *task)
 {
 	struct autofs_point *ap;
@@ -831,8 +930,6 @@ static int run_state_task(struct state_q
 	ap = task->ap;
 	next_state = task->state;
 
-	state_mutex_lock(ap);
-
 	state = ap->state;
 
 	if (next_state != state) {
@@ -862,8 +959,6 @@ static int run_state_task(struct state_q
 		}
 	}
 
-	state_mutex_unlock(ap);
-
 	return ret;
 }
 
@@ -888,8 +983,6 @@ static void st_set_done(struct autofs_po
 	struct list_head *p, *head;
 	struct state_queue *task;
 
-	st_mutex_lock();
-
 	head = &state_queue;
 	list_for_each(p, head) {
 		task = list_entry(p, struct state_queue, list);
@@ -899,8 +992,6 @@ static void st_set_done(struct autofs_po
 		}
 	}
 
-	st_mutex_unlock();
-
 	return;
 }
 
--- autofs-5.0.2.orig/include/automount.h
+++ autofs-5.0.2/include/automount.h
@@ -399,7 +399,6 @@ struct autofs_point {
 	unsigned logopt;		/* Per map logging */
 	pthread_t exp_thread;		/* Thread that is expiring */
 	pthread_t readmap_thread;	/* Thread that is reading maps */
-	pthread_mutex_t state_mutex;	/* Protect state changes */
 	enum states state;		/* Current state */
 	int state_pipe[2];		/* State change router pipe */
 	unsigned dir_created;		/* Directory created for this mount? */
@@ -407,8 +406,6 @@ struct autofs_point {
 					 * host from which to mount */
 	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 shutdown;		/* Shutdown notification */
@@ -446,20 +443,6 @@ int handle_packet_missing_direct(struct 
 void rm_unwanted(unsigned logopt, const char *path, int incl, dev_t dev);
 int count_mounts(unsigned logopt, const char *path, dev_t dev);
 
-#define state_mutex_lock(ap) \
-do { \
-	int _st_lock = pthread_mutex_lock(&ap->state_mutex); \
-	if (_st_lock) \
-		fatal(_st_lock); \
-} while(0)
-
-#define state_mutex_unlock(ap) \
-do{ \
-	int _st_unlock = pthread_mutex_unlock(&ap->state_mutex); \
-	if (_st_unlock) \
-		fatal(_st_unlock); \
-} while (0)
-
 #define mounts_mutex_lock(ap) \
 do { \
 	int _m_lock = pthread_mutex_lock(&ap->mounts_mutex); \
--- autofs-5.0.2.orig/include/master.h
+++ autofs-5.0.2/include/master.h
@@ -20,10 +20,6 @@
 #ifndef MASTER_H
 #define MASTER_H
 
-#define MASTER_SUBMNT_WAIT	0
-#define MASTER_SUBMNT_CONTINUE	1
-#define MASTER_SUBMNT_JOIN	2
-
 struct map_source {
 	char *type;
 	char *format;
@@ -104,7 +100,6 @@ struct master *master_new(const char *, 
 int master_read_master(struct master *, time_t, int);
 int master_submount_list_empty(struct autofs_point *ap);
 int master_notify_submount(struct autofs_point *, const char *path, enum states);
-void master_signal_submount(struct autofs_point *, unsigned int);
 void master_notify_state_change(struct master *, int);
 int master_mount_mounts(struct master *, time_t, int);
 extern inline unsigned int master_get_logopt(void);
--- autofs-5.0.2.orig/include/state.h
+++ autofs-5.0.2/include/state.h
@@ -38,7 +38,8 @@
  *
  */
 enum states {
-	ST_INVAL = -1,
+	ST_ANY = -2,
+	ST_INVAL,
 	ST_INIT,
 	ST_READY,
 	ST_EXPIRE,
@@ -81,12 +82,18 @@ struct readmap_args {
 	time_t now;              /* Time when map is read */
 };
 
+void st_mutex_lock(void);
+void st_mutex_unlock(void);
+
 void expire_cleanup(void *);
 void expire_proc_cleanup(void *);
 void nextstate(int, enum states);
 
 int st_add_task(struct autofs_point *, enum states);
+int __st_add_task(struct autofs_point *, enum states);
 void st_remove_tasks(struct autofs_point *);
+int st_wait_task(struct autofs_point *, enum states, unsigned int);
+int st_wait_state(struct autofs_point *ap, enum states state);
 int st_start_handler(void);
 
 #endif
--- autofs-5.0.2.orig/lib/alarm.c
+++ autofs-5.0.2/lib/alarm.c
@@ -178,7 +178,6 @@ static void *alarm_handler(void *arg)
 	head = &alarms;
 
 	while (1) {
-
 		if (list_empty(head)) {
 			/* No alarms, wait for one to be added */
 			status = pthread_cond_wait(&cond, &mutex);
@@ -211,19 +210,8 @@ static void *alarm_handler(void *arg)
 
 			if (!first->cancel) {
 				struct autofs_point *ap = first->ap;
-				/* 
-				 * We need to unlock the alarm list in case
-				 * some other thread holds the state_mutex
-				 *_lock(ap), and is currently trying to do
-				 * some alarm_* function (i.e if we don't 
-				 * unlock, we might deadlock).
-				 */
 				alarm_unlock(); 
-
-				state_mutex_lock(ap);
-				nextstate(ap->state_pipe[1], ST_EXPIRE);
-				state_mutex_unlock(ap);
-
+				st_add_task(ap, ST_EXPIRE);
 				alarm_lock();
 			}
 			free(first);
--- autofs-5.0.2.orig/lib/master.c
+++ autofs-5.0.2/lib/master.c
@@ -90,41 +90,20 @@ int master_add_autofs_point(struct maste
 	ap->logopt = logopt;
 
 	ap->parent = NULL;
+	ap->thid = 0;
 	ap->submnt_count = 0;
 	ap->submount = submount;
 	INIT_LIST_HEAD(&ap->mounts);
 	INIT_LIST_HEAD(&ap->submounts);
 	ap->shutdown = 0;
 
-	status = pthread_mutex_init(&ap->state_mutex, NULL);
-	if (status) {
-		free(ap->path);
-		free(ap);
-		return 0;
-	}
-
 	status = pthread_mutex_init(&ap->mounts_mutex, NULL);
 	if (status) {
-		status = pthread_mutex_destroy(&ap->state_mutex);
-		if (status)
-			fatal(status);
 		free(ap->path);
 		free(ap);
 		return 0;
 	}
 
-	status = pthread_cond_init(&ap->mounts_cond, NULL);
-	if (status) {
-		status = pthread_mutex_destroy(&ap->mounts_mutex);
-		if (status)
-			fatal(status);
-		status = pthread_mutex_destroy(&ap->state_mutex);
-		if (status)
-			fatal(status);
-		free(ap->path);
-		free(ap);
-		return 0;
-	}
 	entry->ap = ap;
 
 	return 1;
@@ -137,18 +116,10 @@ void master_free_autofs_point(struct aut
 	if (!ap)
 		return;
 
-	status = pthread_mutex_destroy(&ap->state_mutex);
-	if (status)
-		fatal(status);
-
 	status = pthread_mutex_destroy(&ap->mounts_mutex);
 	if (status)
 		fatal(status);
 
-	status = pthread_cond_destroy(&ap->mounts_cond);
-	if (status)
-		fatal(status);
-
 	free(ap->path);
 	free(ap);
 }
@@ -295,11 +266,9 @@ struct map_source *master_find_map_sourc
 {
 	struct map_source *source = NULL;
 
-	master_mutex_lock();
-
+	master_source_readlock(entry);
 	source = __master_find_map_source(entry, type, format, argc, argv);
-
-	master_mutex_unlock();
+	master_source_unlock(entry);
 
 	return source;
 }
@@ -519,13 +488,7 @@ void send_map_update_request(struct auto
 	if (!need_update)
 		return;
 
-	status = pthread_mutex_lock(&ap->state_mutex);
-	if (status)
-		fatal(status);
-	nextstate(ap->state_pipe[1], ST_READMAP);
-	status = pthread_mutex_unlock(&ap->state_mutex);
-	if (status)
-		fatal(status);
+	st_add_task(ap, ST_READMAP);
 
 	return;
 }
@@ -695,17 +658,13 @@ void master_remove_mapent(struct master_
 	if (entry->ap->submount)
 		return;
 
-	master_mutex_lock();
 	if (!list_empty(&entry->list))
 		list_del_init(&entry->list);
-	master_mutex_unlock();
 	return;
 }
 
 void master_free_mapent_sources(struct master_mapent *entry, unsigned int free_cache)
 {
-	master_source_writelock(entry);
-
 	if (entry->maps) {
 		struct map_source *m, *n;
 
@@ -718,8 +677,6 @@ void master_free_mapent_sources(struct m
 		entry->maps = NULL;
 	}
 
-	master_source_unlock(entry);
-
 	return;
 }
 
@@ -827,10 +784,9 @@ int master_submount_list_empty(struct au
 int master_notify_submount(struct autofs_point *ap, const char *path, enum states state)
 {
 	struct list_head *head, *p;
-	struct autofs_point *this;
-	pthread_t thid;
+	struct autofs_point *this = NULL;
 	size_t plen = strlen(path);
-	int status, ret = 1;
+	int ret = 1;
 
 	mounts_mutex_lock(ap);
 
@@ -869,64 +825,30 @@ int master_notify_submount(struct autofs
 
 		/* Now we have a submount to expire */
 
-		state_mutex_lock(this);
+		st_mutex_lock();
 
 		if (this->state == ST_SHUTDOWN) {
-			state_mutex_unlock(this);
+			this = NULL;
+			st_mutex_unlock();
 			break;
 		}
 
-		nextstate(this->state_pipe[1], state);
-
-		state_mutex_unlock(this);
-
-		thid = this->thid;
-		ap->mounts_signaled = MASTER_SUBMNT_WAIT;
-		while (ap->mounts_signaled == MASTER_SUBMNT_WAIT) {
-			status = pthread_cond_wait(&ap->mounts_cond, &ap->mounts_mutex);
-			if (status)
-				fatal(status);
-		}
-
-		if (ap->mounts_signaled == MASTER_SUBMNT_JOIN) {
-			status = pthread_join(thid, NULL);
-			if (status)
-				fatal(status);
-		} else
-			ret = 0;
+		this->shutdown = ap->shutdown;
 
-		break;
-	}
-
-	mounts_mutex_unlock(ap);
+		__st_add_task(this, state);
 
-	return ret;
-}
-
-void master_signal_submount(struct autofs_point *ap, unsigned int join)
-{
-	int status;
-
-	if (!ap->parent || !ap->submount)
-		return;
+		st_mutex_unlock();
+		mounts_mutex_unlock(ap);
 
-	mounts_mutex_lock(ap->parent);
+		st_wait_task(this, state, 0);
 
-	ap->parent->mounts_signaled = join;
+		return ret;
 
-	if (join == MASTER_SUBMNT_JOIN) {
-		/* We are finishing up */
-		ap->parent->submnt_count--;
-		list_del(&ap->mounts);
 	}
 
-	status = pthread_cond_signal(&ap->parent->mounts_cond);
-	if (status)
-		fatal(status);
-
-	mounts_mutex_unlock(ap->parent);
+	mounts_mutex_unlock(ap);
 
-	return;
+	return ret;
 }
 
 void master_notify_state_change(struct master *master, int sig)
@@ -934,7 +856,7 @@ void master_notify_state_change(struct m
 	struct master_mapent *entry;
 	struct autofs_point *ap;
 	struct list_head *p;
-	int state_pipe, cur_state;
+	int cur_state;
 	unsigned int logopt;
 
 	pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cur_state);
@@ -948,13 +870,11 @@ void master_notify_state_change(struct m
 		ap = entry->ap;
 		logopt = ap->logopt;
 
-		state_mutex_lock(ap);
+		st_mutex_lock();
 
 		if (ap->state == ST_SHUTDOWN)
 			goto next;
 
-		state_pipe = ap->state_pipe[1];
-
 		switch (sig) {
 		case SIGTERM:
 		case SIGINT:
@@ -962,7 +882,7 @@ void master_notify_state_change(struct m
 			    ap->state != ST_SHUTDOWN_FORCE) {
 				next = ST_SHUTDOWN_PENDING;
 				ap->shutdown = 1;
-				nextstate(state_pipe, next);
+				__st_add_task(ap, next);
 			}
 			break;
 #ifdef ENABLE_FORCED_SHUTDOWN
@@ -970,14 +890,15 @@ void master_notify_state_change(struct m
 			if (ap->state != ST_SHUTDOWN_FORCE &&
 			    ap->state != ST_SHUTDOWN_PENDING) {
 				next = ST_SHUTDOWN_FORCE;
-				nextstate(state_pipe, next);
+				ap->shutdown = 1;
+				__st_add_task(ap, next);
 			}
 			break;
 #endif
 		case SIGUSR1:
 			assert(ap->state == ST_READY);
 			next = ST_PRUNE;
-			nextstate(state_pipe, next);
+			__st_add_task(ap, next);
 			break;
 		}
 next:
@@ -986,7 +907,7 @@ next:
 			      "sig %d switching %s from %d to %d",
 			      sig, ap->path, ap->state, next);
 
-		state_mutex_unlock(ap);
+		st_mutex_unlock();
 	}
 
 	master_mutex_unlock();
@@ -1024,7 +945,6 @@ static int master_do_mount(struct master
 		handle_mounts_startup_cond_destroy(&suc);
 		return 0;
 	}
-	entry->thid = thid;
 
 	while (!suc.done) {
 		status = pthread_cond_wait(&suc.cond, &suc.mutex);
@@ -1037,45 +957,18 @@ static int master_do_mount(struct master
 		handle_mounts_startup_cond_destroy(&suc);
 		return 0;
 	}
+	entry->thid = thid;
 
 	handle_mounts_startup_cond_destroy(&suc);
 
 	return 1;
 }
 
-static void shutdown_entry(struct master_mapent *entry)
-{
-	int state_pipe;
-	struct autofs_point *ap;
-	struct stat st;
-	int ret;
-
-	ap = entry->ap;
-
-	debug(ap->logopt, "%s", entry->path);
-
-	state_mutex_lock(ap);
-
-	state_pipe = ap->state_pipe[1];
-
-	ret = fstat(state_pipe, &st);
-	if (ret == -1)
-		goto next;
-
-	nextstate(state_pipe, ST_SHUTDOWN_PENDING);
-next:
-	state_mutex_unlock(ap);
-
-	return;
-}
-
 static void check_update_map_sources(struct master_mapent *entry, int readall)
 {
 	struct map_source *source, *last;
-	int state_pipe, map_stale = 0;
 	struct autofs_point *ap;
-	struct stat st;
-	int ret;
+	int map_stale = 0;
 
 	if (readall)
 		map_stale = 1;
@@ -1128,17 +1021,8 @@ static void check_update_map_sources(str
 	master_source_unlock(entry);
 
 	/* The map sources have changed */
-	if (map_stale) {
-		state_mutex_lock(ap);
-
-		state_pipe = entry->ap->state_pipe[1];
-
-		ret = fstat(state_pipe, &st);
-		if (ret != -1)
-			nextstate(state_pipe, ST_READMAP);
-
-		state_mutex_unlock(ap);
-	}
+	if (map_stale)
+		st_add_task(ap, ST_READMAP);
 
 	return;
 }
@@ -1169,17 +1053,19 @@ int master_mount_mounts(struct master *m
 
 		/* A master map entry has gone away */
 		if (this->age < age) {
-			shutdown_entry(this);
+			st_add_task(ap, ST_SHUTDOWN_PENDING);
 			continue;
 		}
 
+		master_source_writelock(ap->entry);
 		lookup_close_lookup(ap);
+		master_source_unlock(ap->entry);
 
 		cache_readlock(nc);
 		ne = cache_lookup_distinct(nc, this->path);
 		if (ne && this->age > ne->age) {
 			cache_unlock(nc);
-			shutdown_entry(this);
+			st_add_task(ap, ST_SHUTDOWN_PENDING);
 			continue;
 		}
 		nested = cache_partial_match(nc, this->path);
@@ -1195,7 +1081,7 @@ int master_mount_mounts(struct master *m
 
 		check_update_map_sources(this, readall);
 
-		state_mutex_lock(ap);
+		st_mutex_lock();
 
 		state_pipe = this->ap->state_pipe[1];
 
@@ -1203,7 +1089,7 @@ int master_mount_mounts(struct master *m
 		ret = fstat(state_pipe, &st);
 		save_errno = errno;
 
-		state_mutex_unlock(ap);
+		st_mutex_unlock();
 
 		if (ret == -1 && save_errno == EBADF)
 			if (!master_do_mount(this)) {
--- autofs-5.0.2.orig/modules/mount_autofs.c
+++ autofs-5.0.2/modules/mount_autofs.c
@@ -242,7 +242,6 @@ int mount_mount(struct autofs_point *ap,
 		master_free_mapent(entry);
 		return 1;
 	}
-	nap->thid = thid;
 
 	while (!suc.done) {
 		status = pthread_cond_wait(&suc.cond, &suc.mutex);
@@ -264,6 +263,7 @@ int mount_mount(struct autofs_point *ap,
 		master_free_mapent(entry);
 		return 1;
 	}
+	nap->thid = thid;
 
 	ap->submnt_count++;
 	list_add(&nap->mounts, &ap->submounts);

autofs-5.0.3-update-replicated-doco.patch:

--- NEW FILE autofs-5.0.3-update-replicated-doco.patch ---
autofs-5.0.3 - update replicated server selection documentation

From: Ian Kent <raven at themaw.net>

Update the replicated server selection README documentation to
reflect the selection rules now used.
---

 README.replicated-server |   51 ++++++++++++++++++++++-------------------------
 1 file changed, 24 insertions(+), 27 deletions(-)


--- autofs-5.0.2.orig/README.replicated-server
+++ autofs-5.0.2/README.replicated-server
@@ -3,48 +3,45 @@ Supported forms for mount paths are:
 Normal single-host (these are unchanged)
 <path> host:/path/path
 
+Single host entries are not probed for a server response.
+
 Multiple replicated hosts, same path:
 <path> host1,host2,hostn:/path/path
 
-This will do an initial RPC call with a .1 second timeout to all hosts to 
-find best match.  If this fails, it will try a 10 second timeout, if this 
-fails it takes the first host.
-
 Multiple hosts, some with same path, some with another
 <path> host1,host2:/blah host3:/some/other/path
 
-Works as expected
-
 Multiple replicated hosts, different (potentially) paths:
 <path> host1:/path/pathA host2:/path/pathB
 
-Same as above with RPC calls..
-
 Mutliple weighted, replicated hosts same path:
-
 <path> host1(5),host2(6),host3(1):/path/path
 
-Will pick lowest weighted host that responds to RPC call.  
-RPC time is not counted, only whether the call got a reply 
-at all.  Initially does a .1 second timeout, if all hosts 
-fail this, moves to 10 second timeout.  If one of the hosts
-is localhost, the automounter will choose that regardless of
-its weight.  (This has been done to remain compatible with
-Sun's automounter)
-
 Multiple weighted, replicated hosts different (potentially) 
 paths:
 <path> host1(3):/path/pathA host2(5):/path/pathB
 
-Same as above with RPC calls/weighting.
-
-Anything else is questionable and unsupported, but these 
-variations will also work:
-<path> host1(3),host:/blah
-
-Unsupported and I don't know why you would use this, but will 
-work.  Weighted host always gets precedence if it responds to RPC
+For these formats a priority ordered list of hosts is created by using
+the following selection rules.
 
-Anything else, I ain't making no promises.
+1) Highest priority in selection is proximity.
+   Proximity, in order of precedence is:
+     - PROXIMITY_LOCAL, host corresponds to a local interface.
+     - PROXIMITY_SUBNET, host is located in a subnet reachable
+       through a local interface.
+     - PROXIMITY_NETWORK, host is located in a network reachable
+       through a local interface.
+     - PROXIMITY_OTHER, host is on a network not directlty
+       reachable through a local interface.
+  
+2) NFS version and protocol is selected by caclculating the largest
+   number of hosts supporting an NFS version and protocol that
+   have the closest proximity. These hosts are added to the list
+   in response time order. Hosts may have a corresponding weight
+   which essentially increases response time and so influences the
+   host order.
+  
+3) Hosts at further proximity that support the selected NFS version
+   and protocol are also added to the list in response time order as
+   in 2 above.
 
-Jason

autofs-5.0.3-use-dev-urandom.patch:

--- NEW FILE autofs-5.0.3-use-dev-urandom.patch ---
autofs-5.0.3 - use /dev/urandom instead of /dev/random

From: Ian Kent <raven at themaw.net>

It has been reported that some headless systems hang when using
/dev/random. It's also been pointed out that /dev/urandom is
sufficient for the needs of autofs.
---

 modules/replicated.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)


--- autofs-5.0.2.orig/modules/replicated.c
+++ autofs-5.0.2/modules/replicated.c
@@ -79,7 +79,7 @@ void seed_random(void)
 	int fd;
 	unsigned int seed;
 
-	fd = open("/dev/random", O_RDONLY);
+	fd = open("/dev/urandom", O_RDONLY);
 	if (fd < 0) {
 		srandom(time(NULL));
 		return;

autofs-5.0.3-wait-submount-expire-complete.patch:

--- NEW FILE autofs-5.0.3-wait-submount-expire-complete.patch ---
autofs-5.0.3 - wait submount expire complete

From: Ian Kent <raven at themaw.net>

When expiring a submount expires away and proceeds to shutdown we
can reach the end of the expire of the parent before the submount
goes away. This can cause an incomplete expire during shutdown in
some cases so, for the case the submount goes to state ST_SHUTDOWN,
we need to wait until the submount either goes away or fails to
shutdown before continuing.
---

 lib/master.c |   23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)


--- autofs-5.0.3.orig/lib/master.c
+++ autofs-5.0.3/lib/master.c
@@ -870,6 +870,29 @@ int master_notify_submount(struct autofs
 
 		st_wait_task(this, state, 0);
 
+		/*
+		 * If our submount gets to state ST_SHUTDOWN we need to
+		 * wait until it goes away or changes to ST_READY.
+		 */
+		mounts_mutex_lock(ap);
+		st_mutex_lock();
+		while ((this = __master_find_submount(ap, path))) {
+			struct timespec t = { 0, 300000000 };
+			struct timespec r;
+
+			if (this->state != ST_SHUTDOWN)
+				break;
+
+			st_mutex_unlock();
+			mounts_mutex_unlock(ap);
+			while (nanosleep(&t, &r) == -1 && errno == EINTR)
+				memcpy(&t, &r, sizeof(struct timespec));
+			mounts_mutex_lock(ap);
+			st_mutex_lock();
+		}
+		st_mutex_unlock();
+		mounts_mutex_unlock(ap);
+
 		return ret;
 
 	}


Index: autofs.spec
===================================================================
RCS file: /cvs/pkgs/rpms/autofs/F-8/autofs.spec,v
retrieving revision 1.239
retrieving revision 1.240
diff -u -r1.239 -r1.240
--- autofs.spec	23 Apr 2008 08:55:35 -0000	1.239
+++ autofs.spec	10 Nov 2008 05:30:26 -0000	1.240
@@ -4,7 +4,7 @@
 Summary: A tool for automatically mounting and unmounting filesystems
 Name: autofs
 Version: 5.0.2
-Release: 29
+Release: 30
 Epoch: 1
 License: GPL
 Group: System Environment/Daemons
@@ -82,6 +82,52 @@
 Patch69: autofs-5.0.3-unlink-mount-return-fix.patch
 Patch70: autofs-5.0.2-init-cb-on-load.patch
 Patch71: autofs-5.0.3-mount-thread-create-cond-handling.patch
+Patch72: autofs-5.0.3-map-type-in-map-name.patch
+Patch73: autofs-5.0.3-check-for-kernel-automount.patch
+Patch74: autofs-5.0.3-nss-source-any.patch
+Patch75: autofs-5.0.3-dont-abuse-ap-ghost-field.patch
+Patch76: autofs-5.0.3-lookup-next-soucre-stale-entry.patch
+Patch77: autofs-5.0.3-remove-redundant-dns-name-lookups.patch
+Patch78: autofs-5.0.3-mount-thread-create-cond-handling-fix.patch
+Patch79: autofs-5.0.3-allow-dir-create-on-nfs-root.patch
+Patch80: autofs-5.0.3-check-direct-path-len.patch
+Patch81: autofs-5.0.3-fix-get-user-info-check.patch
+Patch82: autofs-5.0.3-fix-couple-of-memory-leaks.patch
+Patch83: autofs-5.0.3-override-is-running-check.patch
+Patch84: autofs-5.0.3-dont-use-proc-for-is-running-check.patch
+Patch85: autofs-5.0.3-fix-included-browse-map-not-found.patch
+Patch86: autofs-5.0.3-fix-multi-source-messages.patch
+Patch87: autofs-5.0.3-clear-stale-on-map-read.patch
+Patch88: autofs-5.0.3-fix-proximity-other-timeout.patch
+Patch89: autofs-5.0.3-refactor-mount-request-vars.patch
+Patch90: autofs-5.0.3-make-handle_mounts-startup-cond-distinct.patch
+Patch91: autofs-5.0.3-submount-shutdown-recovery-12.patch
+Patch92: autofs-5.0.3-dont-block-on-expire.patch
+Patch93: autofs-5.0.3-add-umount_wait-parameter.patch
+Patch94: autofs-5.0.3-fix-multi-mount-race.patch
+Patch95: autofs-5.0.3-submount-shutdown-recovery-12-fix.patch
+Patch96: autofs-5.0.3-fix-nfs4-colon-escape.patch
+Patch97: autofs-5.0.3-check-replicated-list-after-probe.patch
+Patch98: autofs-5.0.3-add-replicated-debug-logging.patch
+Patch99: autofs-5.0.3-update-replicated-doco.patch
+Patch100: autofs-5.0.3-use-dev-urandom.patch
+Patch101: autofs-5.0.3-mtab-as-proc-mounts.patch
+Patch102: autofs-5.0.3-fix-ifc-buff-size.patch
+Patch103: autofs-5.0.3-fix-percent-hack.patch
+Patch104: autofs-5.0.3-mtab-as-proc-mounts-fix.patch
+Patch105: autofs-5.0.2-handle-zero-length-nis-key-update.patch
+Patch106: autofs-5.0.3-fix-ifc-buff-size-fix-2.patch
+Patch107: autofs-5.0.3-check-for-kernel-automount-fix.patch
+Patch108: autofs-5.0.3-fix-fd-leak-at-multi-mount-fail.patch
+Patch109: autofs-5.0.3-fix-incorrect-multi-mount-mountpoint.patch
+Patch110: autofs-5.0.3-map-type-in-map-name-fix.patch
+Patch111: autofs-5.0.3-dont-readmap-on-hup-for-new-mount.patch
+Patch112: autofs-5.0.3-nisplus-partial-and-free.patch
+Patch113: autofs-5.0.3-fix-rootless-direct-multi-mount-expire.patch
+Patch114: autofs-5.0.3-wait-submount-expire-complete.patch
+Patch115: autofs-5.0.3-add-missing-uris-list-locking.patch
+Patch116: autofs-5.0.3-library-reload-fix.patch
+Patch117: autofs-5.0.3-expire-thread-create-cond-handling.patch
 Buildroot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
 BuildRequires: autoconf, hesiod-devel, openldap-devel, bison, flex, libxml2-devel, cyrus-sasl-devel, openssl-devel module-init-tools util-linux nfs-utils e2fsprogs
 Conflicts: kernel < 2.6.17
@@ -195,6 +241,52 @@
 %patch69 -p1
 %patch70 -p1
 %patch71 -p1
+%patch72 -p1
+%patch73 -p1
+%patch74 -p1
+%patch75 -p1
+%patch76 -p1
+%patch77 -p1
+%patch78 -p1
+%patch79 -p1
+%patch80 -p1
+%patch81 -p1
+%patch82 -p1
+%patch83 -p1
+%patch84 -p1
+%patch85 -p1
+%patch86 -p1
+%patch87 -p1
+%patch88 -p1
+%patch89 -p1
+%patch90 -p1
+%patch91 -p1
+%patch92 -p1
+%patch93 -p1
+%patch94 -p1
+%patch95 -p1
+%patch96 -p1
+%patch97 -p1
+%patch98 -p1
+%patch99 -p1
+%patch100 -p1
+%patch101 -p1
+%patch102 -p1
+%patch103 -p1
+%patch104 -p1
+%patch105 -p1
+%patch106 -p1
+%patch107 -p1
+%patch108 -p1
+%patch109 -p1
+%patch110 -p1
+%patch111 -p1
+%patch112 -p1
+%patch113 -p1
+%patch114 -p1
+%patch115 -p1
+%patch116 -p1
+%patch117 -p1
 
 %build
 #CFLAGS="$RPM_OPT_FLAGS" ./configure --prefix=/usr --libdir=%{_libdir}
@@ -247,6 +339,55 @@
 %{_libdir}/autofs/
 
 %changelog
+* Mon Nov 10 2008 Ian Kent <ikent at redhat.com> - 5.0.2-30
+- sync. with F-9 bug fixes.
+  - fix lexer ambiguity in match when map type name is included in map name.
+  - check for nohide mounts.
+  - ignore nsswitch sources that aren't supported.
+  - don't abuse the ap->ghost field on NFS mount.
+  - multi-map doesn't pickup NIS updates automatically.
+  - eliminate redundant DNS name lookups.
+  - mount thread create condition handling fix.
+  - allow directory create on NFS root.
+  - check direct mount path length.
+  - fix incorrect in check in get user info.
+  - fix a couple of memory leaks.
+  - don't close file handle for rootless direct mounti-mount at mount.
+  - wait submount expire thread completion when expire successful.
+  - add inadvertantly ommitted server list locking in LDAP module.
+  - add map-type-in-map-name fix patch to sync with upstream and RHEL.
+  - don't readmap on HUP for new mount.
+  - add NIS_PARTIAL to map entry not found check and fix use after free bug.
+  - fix fd leak at multi-mount non-fatal mount fail.
+  - fix incorrect multi-mount mountpoint calcualtion.
+  - add upstream bug fixes
+  - bug fix for mtab check.
+  - bug fix for zero length nis key.
+  - update for ifc buffer handling.
+  - bug fix for kernel automount handling.
+  - add command line option to override is running check.
+  - don't use proc fs for is running check.
+  - fix fail on included browse map not found.
+  - fix incorrect multi source messages.
+  - clear stale flag on map read.
+  - fix proximity other rpc ping timeout.
+  - refactor mount request vars code.
+  - make handle_mounts startup condition distinct.
+  - fix submount shutdown handling.
+  - try not to block on expire.
+  - add configuration paramter UMOUNT_WAIT.
+  - fix multi mount race.
+  - fix nfs4 colon escape handling.
+  - check replicated list after probe.
+  - add replicated server selection debug logging.
+  - update replicated server selection documentation.
+  - use /dev/urandom instead of /dev/random.
+  - check for mtab pointing to /proc/mounts.
+  - fix interface config buffer size.
+  - fix percent hack heap corruption.
+  - fix segv during library re-open.
+  - fix incorrect pthreads condition handling for expire requests.
+
 * Wed Apr 23 2008 Ian Kent <ikent at redhat.com> - 5.0.2-29
 - fix incorrect pthreads condition handling for mount requests.
 




More information about the fedora-extras-commits mailing list