diff options
-rw-r--r-- | src/monitor/monitor.c | 41 | ||||
-rw-r--r-- | src/util/server.c | 35 | ||||
-rw-r--r-- | src/util/util.h | 1 |
3 files changed, 73 insertions, 4 deletions
diff --git a/src/monitor/monitor.c b/src/monitor/monitor.c index ea600ba3a..8f1be95af 100644 --- a/src/monitor/monitor.c +++ b/src/monitor/monitor.c @@ -142,6 +142,8 @@ struct mt_ctx { struct sss_domain_info *domains; TALLOC_CTX *service_ctx; /* Memory context for services */ char **services; + int num_services; + int started_services; struct mt_svc *svc_list; struct sbus_connection *sbus_srv; struct config_file_ctx *file_ctx; @@ -151,6 +153,8 @@ struct mt_ctx { bool services_started; struct netlink_ctx *nlctx; struct sss_sigchild_ctx *sigchld_ctx; + bool is_daemon; + pid_t parent_pid; }; static int start_service(struct mt_svc *mt_svc); @@ -422,6 +426,34 @@ static int mark_service_as_started(struct mt_svc *svc) } } + if (svc->type == MT_SVC_SERVICE) { + ctx->started_services++; + } + + if (ctx->started_services == ctx->num_services) { + /* Initialization is complete, terminate parent process if in daemon + * mode. Make sure we send the signal to the right process */ + if (ctx->is_daemon) { + if (ctx->parent_pid <= 1 || ctx->parent_pid != getppid()) { + /* the parent process was already terminated */ + DEBUG(SSSDBG_MINOR_FAILURE, ("Invalid parent pid: %d\n", + ctx->parent_pid)); + goto done; + } + + DEBUG(SSSDBG_TRACE_FUNC, ("SSSD is initialized, " + "terminating parent process\n")); + + errno = 0; + ret = kill(ctx->parent_pid, SIGTERM); + if (ret != 0) { + ret = errno; + DEBUG(SSSDBG_FATAL_FAILURE, ("Unable to terminate parent " + "process [%d]: %s\n", ret, strerror(ret))); + } + } + } + done: return ret; } @@ -783,6 +815,7 @@ int get_monitor_config(struct mt_ctx *ctx) int ret; int timeout_seconds; char *badsrv = NULL; + int i; ret = confdb_get_int(ctx->cdb, ctx, CONFDB_MONITOR_CONF_ENTRY, @@ -813,6 +846,12 @@ int get_monitor_config(struct mt_ctx *ctx) return EINVAL; } + ctx->started_services = 0; + ctx->num_services = 0; + for (i = 0; ctx->services[i] != NULL; i++) { + ctx->num_services++; + } + ctx->domain_ctx = talloc_new(ctx); if(!ctx->domain_ctx) { return ENOMEM; @@ -2460,6 +2499,8 @@ int main(int argc, const char *argv[]) ret = server_setup("sssd", flags, CONFDB_MONITOR_CONF_ENTRY, &main_ctx); if (ret != EOK) return 2; + monitor->is_daemon = !opt_interactive; + monitor->parent_pid = main_ctx->parent_pid; monitor->ev = main_ctx->event_ctx; talloc_steal(main_ctx, monitor); diff --git a/src/util/server.c b/src/util/server.c index 1e8b148d7..41c0d97a5 100644 --- a/src/util/server.c +++ b/src/util/server.c @@ -25,6 +25,7 @@ #define _GNU_SOURCE #include <sys/types.h> +#include <sys/wait.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> @@ -67,18 +68,43 @@ static void close_low_fds(void) #endif } +static void deamon_parent_sigterm(int sig) +{ + _exit(0); +} + /** Become a daemon, discarding the controlling terminal. **/ void become_daemon(bool Fork) { - int ret; + pid_t pid; + int status; + int ret; if (Fork) { - if (fork()) { - _exit(0); - } + pid = fork(); + if (pid != 0) { + /* Terminate parent process on demand so we can hold systemd + * or initd from starting next service until sssd in initialized. + * We use signals directly here because we don't have a tevent + * context yet. */ + CatchSignal(SIGTERM, deamon_parent_sigterm); + + /* or exit when sssd monitor is terminated */ + waitpid(pid, &status, 0); + + /* return error if we didn't exited normally */ + ret = 1; + + if (WIFEXITED(status)) { + /* but return our exit code otherwise */ + ret = WEXITSTATUS(status); + } + + _exit(ret); + } } /* detach from the terminal */ @@ -430,6 +456,7 @@ int server_setup(const char *name, int flags, return ENOMEM; } + ctx->parent_pid = getppid(); ctx->event_ctx = event_ctx; conf_db = talloc_asprintf(ctx, "%s/%s", DB_PATH, CONFDB_FILE); diff --git a/src/util/util.h b/src/util/util.h index 43017aa0d..1bc469282 100644 --- a/src/util/util.h +++ b/src/util/util.h @@ -276,6 +276,7 @@ void sss_log(int priority, const char *format, ...); struct main_context { struct tevent_context *event_ctx; struct confdb_ctx *confdb_ctx; + pid_t parent_pid; }; int die_if_parent_died(void); |