From 09d2516c263e5d1458c4948c4b92cb925aede51d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
Date: Thu, 18 Oct 2012 10:16:06 +0200
Subject: [PATCH] exit original process after sssd is initialized

https://fedorahosted.org/sssd/ticket/1357

Neither systemd or our init script use pid file as a notification
that sssd is finished initializing. They will continue starting up
next service right after the original process is terminated.
---
 src/monitor/monitor.c |   19 +++++++++++++++++++
 src/util/server.c     |   37 ++++++++++++++++++++++++++++++++-----
 src/util/util.h       |    1 +
 3 files changed, 52 insertions(+), 5 deletions(-)

diff --git a/src/monitor/monitor.c b/src/monitor/monitor.c
index a5653999e7531e27556693f88d1d988cc6c24a59..a9949bbf964544c254656c4fbf5f2353b3f54ae7 100644
--- a/src/monitor/monitor.c
+++ b/src/monitor/monitor.c
@@ -157,6 +157,8 @@ struct mt_ctx {
     const char *conf_path;
     struct sss_sigchild_ctx *sigchld_ctx;
     bool pid_file_created;
+    bool is_daemon;
+    pid_t parent_pid;
 };
 
 static int start_service(struct mt_svc *mt_svc);
@@ -449,6 +451,21 @@ static int mark_service_as_started(struct mt_svc *svc)
         }
 
         ctx->pid_file_created = true;
+
+        /* initialization is complete, terminate parent process
+         * if in daemon mode */
+        if (ctx->is_daemon && ctx->parent_pid > 0) {
+            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:
@@ -2627,6 +2644,8 @@ int main(int argc, const char *argv[])
     ret = server_setup(MONITOR_NAME, flags, monitor->conf_path, &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 f3f1b201bc751a4017b1e974c3a734cca415a097..11992a4fcc5624fd774d534b652ee92ef91a20e1 100644
--- a/src/util/server.c
+++ b/src/util/server.c
@@ -24,6 +24,7 @@
 */
 
 #include <sys/types.h>
+#include <sys/wait.h>
 #include <sys/stat.h>
 #include <fcntl.h>
 #include <unistd.h>
@@ -67,20 +68,44 @@ 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)
+void become_daemon(bool Fork, pid_t *ppid)
 {
-        int ret;
+    pid_t pid;
+    int status;
+    int ret;
 
 	if (Fork) {
-		if (fork()) {
-			_exit(0);
+	    pid = fork();
+		if (pid != 0) {
+		    *ppid = 0;
+
+		    /* terminate parent process on demand so we can hold systemd
+		     * or initd from starting next service until sssd in initialized */
+		    CatchSignal(SIGTERM, deamon_parent_sigterm);
+
+		    /* or exit when sssd monitor is terminated */
+		    waitpid(pid, &status, 0);
+
+		    ret = 0;
+		    if (WIFEXITED(status)) {
+		        ret = WEXITSTATUS(status);
+		    }
+
+			_exit(ret);
 		}
 	}
 
+	*ppid = getppid();
+
     /* detach from the terminal */
 	setsid();
 
@@ -369,6 +394,7 @@ int server_setup(const char *name, int flags,
     bool dm;
     struct tevent_signal *tes;
     struct logrotate_ctx *lctx;
+    pid_t parent_pid = 0;
 
     debug_prg_name = strdup(name);
     if (!debug_prg_name) {
@@ -385,7 +411,7 @@ int server_setup(const char *name, int flags,
 
     if (flags & FLAGS_DAEMON) {
         DEBUG(3,("Becoming a daemon.\n"));
-        become_daemon(true);
+        become_daemon(true, &parent_pid);
     }
 
     if (flags & FLAGS_PID_FILE) {
@@ -430,6 +456,7 @@ int server_setup(const char *name, int flags,
         return ENOMEM;
     }
 
+    ctx->parent_pid = parent_pid;
     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 a96f519ad959b8706f31c5cf7e4204c77e39b737..268cffccd633d54ef82805c0ebb77673c06a0360 100644
--- a/src/util/util.h
+++ b/src/util/util.h
@@ -358,6 +358,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);
-- 
1.7.6.5

