autofs-5.0.9 - wait for master map available at start From: Ian Kent 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; }