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; }