Blob Blame History Raw
autofs-5.1.2 - 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.

Signed-off-by: Ian Kent <raven@themaw.net>
---
 CHANGELOG                |    1 
 daemon/automount.c       |   81 +++++++++++++++++++++++++++++++++++++++++------
 daemon/lookup.c          |    8 ++++
 lib/master.c             |    3 +
 modules/lookup_file.c    |    6 +++
 modules/lookup_nisplus.c |   14 +++++---
 modules/lookup_yp.c      |   13 +++++--
 7 files changed, 108 insertions(+), 18 deletions(-)

--- autofs-5.0.7.orig/CHANGELOG
+++ autofs-5.0.7/CHANGELOG
@@ -206,6 +206,7 @@
 - add configuration option to use fqdn in mounts.
 - fix use-after-free in st_queue_handler().
 - add config option to supress not found log message.
+- wait for master map available at start.
 
 25/07/2012 autofs-5.0.7
 =======================
--- autofs-5.0.7.orig/daemon/automount.c
+++ autofs-5.0.7/daemon/automount.c
@@ -1379,9 +1379,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;
 
@@ -1470,7 +1471,7 @@ static void *statemachine(void *arg)
 			break;
 
 		case SIGHUP:
-			do_hup_signal(master_list, time(NULL));
+			do_hup_signal(master_list);
 			break;
 
 		default:
@@ -2031,12 +2032,56 @@ static void remove_empty_args(char **arg
 	*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;
@@ -2429,14 +2474,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);
 	}
 
 	/*
@@ -2449,6 +2496,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);
 
--- autofs-5.0.7.orig/daemon/lookup.c
+++ autofs-5.0.7/daemon/lookup.c
@@ -241,6 +241,7 @@ int lookup_nss_read_master(struct master
 	}
 
 	/* First one gets it */
+	result = NSS_STATUS_UNKNOWN;
 	head = &nsslist;
 	list_for_each(p, head) {
 		struct nss_source *this;
@@ -248,6 +249,13 @@ int lookup_nss_read_master(struct master
 
 		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) &&
+		    strncmp(this->source, "sss", 3))
+			continue;
+
 		debug(logopt,
 		      "reading master %s %s", this->source, master->name);
 
--- autofs-5.0.7.orig/lib/master.c
+++ autofs-5.0.7/lib/master.c
@@ -922,7 +922,10 @@ int master_read_master(struct master *ma
 		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);
 	}
 
--- autofs-5.0.7.orig/modules/lookup_file.c
+++ autofs-5.0.7/modules/lookup_file.c
@@ -506,6 +506,12 @@ int lookup_read_master(struct master *ma
 				     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;
--- autofs-5.0.7.orig/modules/lookup_nisplus.c
+++ autofs-5.0.7/modules/lookup_nisplus.c
@@ -149,19 +149,25 @@ int lookup_read_master(struct master *ma
 		char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
 		logerr(MODPREFIX "malloc: %s", estr);
 		pthread_setcancelstate(cur_state, NULL);
-		return NSS_STATUS_UNAVAIL;
+		return NSS_STATUS_UNKNOWN;
 	}
 	sprintf(tablename, "%s.org_dir.%s", ctxt->mapname, ctxt->domainname);
 
 	/* check that the table exists */
 	result = nis_lookup(tablename, FOLLOW_PATH | FOLLOW_LINKS);
 	if (result->status != NIS_SUCCESS && result->status != NIS_S_SUCCESS) {
+		int status = result->status;
 		nis_freeresult(result);
-		crit(logopt,
-		     MODPREFIX "couldn't locate nis+ table %s", ctxt->mapname);
 		free(tablename);
 		pthread_setcancelstate(cur_state, NULL);
-		return NSS_STATUS_NOTFOUND;
+		if (status == NIS_UNAVAIL || status == NIS_FAIL)
+			return NSS_STATUS_UNAVAIL;
+		else {
+			crit(logopt,
+			     MODPREFIX "couldn't locate nis+ table %s",
+			     ctxt->mapname);
+			return NSS_STATUS_NOTFOUND;
+		}
 	}
 
 	sprintf(tablename, "[],%s.org_dir.%s", ctxt->mapname, ctxt->domainname);
--- autofs-5.0.7.orig/modules/lookup_yp.c
+++ autofs-5.0.7/modules/lookup_yp.c
@@ -282,9 +282,9 @@ int lookup_read_master(struct master *ma
 	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);
 
@@ -308,19 +308,24 @@ int lookup_read_master(struct master *ma
 			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;
 }