autofs-5.0.9 - wait for master map available at start

From: Ian Kent <raven@themaw.net>

If the network map source isn't available at start the master map
can't be read. In this case we should wait until it is available
so we can get a startup map.
---
 CHANGELOG             |    1 +
 daemon/automount.c    |   81 +++++++++++++++++++++++++++++++++++++++++++------
 daemon/lookup.c       |    7 ++++
 lib/master.c          |    3 ++
 modules/lookup_file.c |    6 ++++
 modules/lookup_yp.c   |   13 +++++---
 6 files changed, 97 insertions(+), 14 deletions(-)

diff --git a/CHANGELOG b/CHANGELOG
index 68afc32..a995dda 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -3,6 +3,7 @@
 - fix mistake in assignment.
 - check for non existent negative entries in lookup_ghost().
 - fix reset flex scan buffer on init.
+- wait for master map available at start.
 
 28/03/2014 autofs-5.0.9
 =======================
diff --git a/daemon/automount.c b/daemon/automount.c
index 0dd6477..3c76c6b 100644
--- a/daemon/automount.c
+++ b/daemon/automount.c
@@ -1284,9 +1284,10 @@ static void *do_read_master(void *arg)
 	return NULL;
 }
 
-static int do_hup_signal(struct master *master, time_t age)
+static int do_hup_signal(struct master *master)
 {
 	unsigned int logopt = master->logopt;
+	time_t age = time(NULL);
 	pthread_t thid;
 	int status;
 
@@ -1375,7 +1376,7 @@ static void *statemachine(void *arg)
 			break;
 
 		case SIGHUP:
-			do_hup_signal(master_list, time(NULL));
+			do_hup_signal(master_list);
 			break;
 
 		default:
@@ -1912,12 +1913,56 @@ static void remove_empty_args(char **argv, int *argc)
 	*argc = j;
 }
 
+static int do_master_read_master(struct master *master, int wait)
+{
+	sigset_t signalset;
+	/* Wait must be at least 1 second */
+	unsigned int retry_wait = 2;
+	unsigned int elapsed = 0;
+	int max_wait = wait;
+	int ret = 0;
+	time_t age;
+
+	sigemptyset(&signalset);
+	sigaddset(&signalset, SIGTERM);
+	sigaddset(&signalset, SIGINT);
+	sigaddset(&signalset, SIGHUP);
+	sigprocmask(SIG_UNBLOCK, &signalset, NULL);
+
+	while (1) {
+		struct timespec t = { retry_wait, 0 };
+
+		age = time(NULL);
+		if (master_read_master(master, age, 0)) {
+			ret = 1;
+			break;
+		}
+
+		if (nanosleep(&t, NULL) == -1)
+			break;
+
+		if (max_wait > 0) {
+			elapsed += retry_wait;
+			if (elapsed >= max_wait) {
+				logmsg("problem reading master map, "
+					"maximum wait exceeded");
+				break;
+			}
+		}
+	}
+
+	sigprocmask(SIG_BLOCK, &signalset, NULL);
+
+	return ret;
+}
+
 int main(int argc, char *argv[])
 {
 	int res, opt, status;
 	int logpri = -1;
 	unsigned ghost, logging, daemon_check;
 	unsigned dumpmaps, foreground, have_global_options;
+	unsigned master_read;
 	time_t timeout;
 	time_t age = time(NULL);
 	struct rlimit rlim;
@@ -2310,14 +2355,16 @@ int main(int argc, char *argv[])
 		dh_tirpc = dlopen("libtirpc.so.1", RTLD_NOW);
 #endif
 
-	if (!master_read_master(master_list, age, 0)) {
-		master_kill(master_list);
-		*pst_stat = 3;
-		res = write(start_pipefd[1], pst_stat, sizeof(*pst_stat));
-		close(start_pipefd[1]);
-		release_flag_file();
-		macro_free_global_table();
-		exit(3);
+	master_read = master_read_master(master_list, age, 0);
+	if (!master_read) {
+		if (foreground)
+			logerr("%s: failed to read master map, "
+			       "will retry!",
+			       program);
+		else
+			logerr("%s: failed to read master map, "
+			       "will retry in background!",
+			       program);
 	}
 
 	/*
@@ -2330,6 +2377,20 @@ int main(int argc, char *argv[])
 	res = write(start_pipefd[1], pst_stat, sizeof(*pst_stat));
 	close(start_pipefd[1]);
 
+	if (!master_read) {
+		/*
+		 * Read master map, waiting until it is available, unless
+		 * a signal is received, in which case exit returning an
+		 * error.
+		 */
+		if (!do_master_read_master(master_list, -1)) {
+			logerr("%s: failed to read master map!", program);
+			master_kill(master_list);
+			release_flag_file();
+			exit(3);
+		}
+	}
+
 	state_mach_thid = pthread_self();
 	statemachine(NULL);
 
diff --git a/daemon/lookup.c b/daemon/lookup.c
index 3665fca..7d7da1c 100644
--- a/daemon/lookup.c
+++ b/daemon/lookup.c
@@ -247,6 +247,7 @@ int lookup_nss_read_master(struct master *master, time_t age)
 	}
 
 	/* First one gets it */
+	result = NSS_STATUS_UNKNOWN;
 	head = &nsslist;
 	list_for_each(p, head) {
 		struct nss_source *this;
@@ -254,6 +255,12 @@ int lookup_nss_read_master(struct master *master, time_t age)
 
 		this = list_entry(p, struct nss_source, list);
 
+		if (strncmp(this->source, "files", 5) &&
+		    strncmp(this->source, "nis", 3) &&
+		    strncmp(this->source, "nisplus", 7) &&
+		    strncmp(this->source, "ldap", 4))
+			continue;
+
 		debug(logopt,
 		      "reading master %s %s", this->source, master->name);
 
diff --git a/lib/master.c b/lib/master.c
index ce6320e..32bc868 100644
--- a/lib/master.c
+++ b/lib/master.c
@@ -865,7 +865,10 @@ int master_read_master(struct master *master, time_t age, int readall)
 		master_mount_mounts(master, age, readall);
 	else {
 		master->read_fail = 0;
+		/* HUP signal sets readall == 1 only */
 		if (!readall)
+			return 0;
+		else
 			master_mount_mounts(master, age, readall);
 	}
 
diff --git a/modules/lookup_file.c b/modules/lookup_file.c
index 512e3ef..ea0df27 100644
--- a/modules/lookup_file.c
+++ b/modules/lookup_file.c
@@ -454,6 +454,12 @@ int lookup_read_master(struct master *master, time_t age, void *context)
 				     MODPREFIX
 				     "failed to read included master map %s",
 				     master->name);
+				/*
+				 * If we're starting up wee need the whole
+				 * master map initially, so tell the upper
+				 * layer to retry.
+				 */
+				master->read_fail = 1;
 			}
 			master->depth--;
 			master->recurse = 0;
diff --git a/modules/lookup_yp.c b/modules/lookup_yp.c
index ba97ccc..eb5b2db 100644
--- a/modules/lookup_yp.c
+++ b/modules/lookup_yp.c
@@ -214,9 +214,9 @@ int lookup_read_master(struct master *master, time_t age, void *context)
 	char *mapname;
 	int err;
 
-	mapname = alloca(strlen(ctxt->mapname) + 1);
+	mapname = malloc(strlen(ctxt->mapname) + 1);
 	if (!mapname)
-		return 0;
+		return NSS_STATUS_UNKNOWN;
 
 	strcpy(mapname, ctxt->mapname);
 
@@ -240,19 +240,24 @@ int lookup_read_master(struct master *master, time_t age, void *context)
 			err = yp_all((char *) ctxt->domainname, mapname, &ypcb);
 		}
 
-		if (err == YPERR_SUCCESS)
+		if (err == YPERR_SUCCESS) {
+			free(mapname);
 			return NSS_STATUS_SUCCESS;
+		}
 
 		info(logopt,
 		     MODPREFIX "read of master map %s failed: %s",
 		     mapname, yperr_string(err));
 
-		if (err == YPERR_PMAP || err == YPERR_YPSERV)
+		free(mapname);
+
+		if (err == YPERR_YPSERV || err == YPERR_DOMAIN)
 			return NSS_STATUS_UNAVAIL;
 
 		return NSS_STATUS_NOTFOUND;
 	}
 
+	free(mapname);
 	return NSS_STATUS_SUCCESS;
 }
 
