On 10/30/2012 01:51 PM, Jakub Hrozek wrote:
On Fri, Oct 26, 2012 at 01:10:38PM +0200, Pavel Březina wrote:
On 10/22/2012 01:49 PM, Pavel Březina wrote:
On 10/19/2012 02:20 PM, Simo Sorce wrote:
On Fri, 2012-10-19 at 09:52 +0200, Pavel Březina wrote:
On 10/18/2012 08:43 PM, Stephen Gallagher wrote:
On 10/18/2012 09:50 AM, Jakub Hrozek wrote:
On Thu, Oct 18, 2012 at 11:28:10AM +0200, Pavel Březina wrote:
On 10/18/2012 11:15 AM, Pavel Březina wrote:
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.

Oops, I forgot to amend the patch with latest changes. The final
patch is attached.

I haven't really had time to read the patch too carefully yet, but my
first thought was to always try to use tevent signals if you need
signals at all.

Yes, I went through a lot of effort a little over a year ago to get the
monitor properly using tevent signals instead of managing its own
directly. Please do not add manual handlers.

Nack.

Hi guys,
I just want to make sure that we are on the same page here before I
start modifying it to tevent.

I am not mixing tevent signals with posix signals. There is no existing
tevent context available and there will never be (unless I create it).

I just need to catch SIGTERM in original process (that forks and become
monitor), so that monitor can signal the original process to quit. Or
wait for the monitor to exit (in case of error etc.) if the signal
doesn't come.

Using tevent for this case seems like using a sledgehammer to crack a
nut.

Pavel if this is before we create the tevent event context than it is ok
to directly handle signals, however put a comment there taht says so.
example: /* We use signals directly here because we don't have a tevent
context yet */

Simo.


Very well. New patch is attached.

Hi,
I'm sending new patch set.

[PATCH 1/2] exit original process after sssd is initialized
...unchanged.

[PATCH 2/2] create pid file immediately after fork again
We realized that sysv and systemd does not use pid file existence
as a notification of finished initialization. Therefore, we create
the pid file immediately after we fork to become daemon.


Positive testing went fine. So far I only have one remark for the code --
is there a reason to keep the parent pid around at all? Why not simply
call getppid()?

Also, starting the service doesn't work if any provider is
misconfigured, it seems that the parent never exits. I tested by simply
putting an invalid ldap URI (ldap=someserver instead of
ldap://someserver).

I'm sending another set of patches after our offline discussion.


From b05e8829822e94f9bc96bfd586aa099114cd1a12 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrez...@redhat.com>
Date: Thu, 1 Nov 2012 13:20:43 +0100
Subject: [PATCH 1/3] make monitor_quit() usable outside signal handler

---
 src/monitor/monitor.c | 40 ++++++++++++++++++++++++++--------------
 1 file changed, 26 insertions(+), 14 deletions(-)

diff --git a/src/monitor/monitor.c b/src/monitor/monitor.c
index eef2fc7066c78c7994e05ea1579b483754ccc2d1..413bac953dd8570eba352525e8f4835e62812fdc 100644
--- a/src/monitor/monitor.c
+++ b/src/monitor/monitor.c
@@ -1257,14 +1257,8 @@ static int monitor_cleanup(void)
     return EOK;
 }
 
-static void monitor_quit(struct tevent_context *ev,
-                         struct tevent_signal *se,
-                         int signum,
-                         int count,
-                         void *siginfo,
-                         void *private_data)
+static void monitor_quit(struct mt_ctx *mt_ctx, int ret)
 {
-    struct mt_ctx *mt_ctx = talloc_get_type(private_data, struct mt_ctx);
     struct mt_svc *svc;
     pid_t pid;
     int status;
@@ -1272,10 +1266,7 @@ static void monitor_quit(struct tevent_context *ev,
     int kret;
     bool killed;
 
-    DEBUG(8, ("Received shutdown command\n"));
-
-    DEBUG(0, ("Monitor received %s: terminating children\n",
-              strsignal(signum)));
+    DEBUG(SSSDBG_FATAL_FAILURE, ("Shutting down with: %d\n", ret));
 
     /* Kill all of our known children manually */
     DLIST_FOR_EACH(svc, mt_ctx->svc_list) {
@@ -1350,7 +1341,24 @@ static void monitor_quit(struct tevent_context *ev,
 
     monitor_cleanup();
 
-    exit(0);
+    exit(ret);
+}
+
+static void monitor_quit_signal(struct tevent_context *ev,
+                                struct tevent_signal *se,
+                                int signum,
+                                int count,
+                                void *siginfo,
+                                void *private_data)
+{
+    struct mt_ctx *mt_ctx = talloc_get_type(private_data, struct mt_ctx);
+
+    DEBUG(8, ("Received shutdown command\n"));
+
+    DEBUG(0, ("Monitor received %s: terminating children\n",
+              strsignal(signum)));
+
+    monitor_quit(mt_ctx, 0);
 }
 
 static void signal_res_init(struct mt_ctx *monitor)
@@ -2026,14 +2034,14 @@ int monitor_process_init(struct mt_ctx *ctx,
     /* Set up an event handler for a SIGINT */
     BlockSignals(false, SIGINT);
     tes = tevent_add_signal(ctx->ev, ctx, SIGINT, 0,
-                            monitor_quit, ctx);
+                            monitor_quit_signal, ctx);
     if (tes == NULL) {
         return EIO;
     }
 
     /* Set up an event handler for a SIGTERM */
     tes = tevent_add_signal(ctx->ev, ctx, SIGTERM, 0,
-                            monitor_quit, ctx);
+                            monitor_quit_signal, ctx);
     if (tes == NULL) {
         return EIO;
     }
@@ -2412,6 +2420,7 @@ static void service_startup_handler(struct tevent_context *ev,
 static void mt_svc_exit_handler(int pid, int wait_status, void *pvt)
 {
     struct mt_svc *svc = talloc_get_type(pvt, struct mt_svc);
+    struct mt_ctx *mt_ctx = svc->mt_ctx;
     time_t now = time(NULL);
 
     if WIFEXITED(wait_status) {
@@ -2442,6 +2451,9 @@ static void mt_svc_exit_handler(int pid, int wait_status, void *pvt)
         DEBUG(SSSDBG_FATAL_FAILURE,
               ("Process [%s], definitely stopped!\n", svc->name));
         talloc_free(svc);
+
+        /* exit with error */
+        monitor_quit(mt_ctx, 1);
         return;
     }
 
-- 
1.7.11.7

From 4b16e8a887712d390e4d86bcb9ddbc0003c6e16f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrez...@redhat.com>
Date: Thu, 18 Oct 2012 10:16:06 +0200
Subject: [PATCH 2/3] 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 (not daemonized) sssd process
is terminated.

If any of the responders fail to start, we will never terminate
the original process via signal and "service sssd start" will hang.
Thus we take this as an error and terminate the daemon with
a non-zero value. This will also terminate the original process
and init script or systemd will print failure.
---
 src/monitor/monitor.c | 26 +++++++++++++++++++++++++
 src/util/server.c     | 54 ++++++++++++++++++++++++++++++++++++++++-----------
 src/util/util.h       |  1 +
 3 files changed, 70 insertions(+), 11 deletions(-)

diff --git a/src/monitor/monitor.c b/src/monitor/monitor.c
index 413bac953dd8570eba352525e8f4835e62812fdc..8dd96cd7e6f7eba98460269efd1630bc441075c3 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,28 @@ 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. Make sure we send the signal to the right process */
+        if (ctx->is_daemon && ctx->parent_pid > 0
+                && ctx->parent_pid == getppid()) {
+            if (ctx->parent_pid <= 0 || ctx->parent_pid != getppid()) {
+                /* the parent process was already terminated */
+                DEBUG(SSSDBG_MINOR_FAILURE, ("Invalid parent pid\n"));
+                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:
@@ -2647,6 +2671,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..63f646b496155d5eef37e971ef28aca3791c2e9c 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,22 +68,51 @@ 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);
-		}
-	}
+    if (Fork) {
+        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.
+             * 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);
+        }
+    }
+
+    *ppid = getppid();
 
     /* detach from the terminal */
-	setsid();
+    setsid();
 
         /* chdir to / to be sure we're not on a remote filesystem */
         errno = 0;
@@ -93,8 +123,8 @@ void become_daemon(bool Fork)
             return;
         }
 
-	/* Close fd's 0,1,2. Needed if started by rsh */
-	close_low_fds();
+    /* Close fd's 0,1,2. Needed if started by rsh */
+    close_low_fds();
 }
 
 int pidfile(const char *path, const char *name)
@@ -369,6 +399,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 +416,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 +461,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 df57a3dec4b6d42bb1e4b5e70c109317a4aff31f..554f86d61815d7087ed8f6ad4215813b0b08016b 100644
--- a/src/util/util.h
+++ b/src/util/util.h
@@ -363,6 +363,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.11.7

From 99c4a968889c4ee6d0f3015b160152da8c733960 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrez...@redhat.com>
Date: Fri, 26 Oct 2012 12:46:48 +0200
Subject: [PATCH 3/3] create pid file immediately after fork again

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

We realized that sysv and systemd does not use pid file existence
as a notification of finished initialization. Therefore, we create
the pid file immediately after we fork to become daemon.
---
 src/monitor/monitor.c | 29 ++++-------------------------
 1 file changed, 4 insertions(+), 25 deletions(-)

diff --git a/src/monitor/monitor.c b/src/monitor/monitor.c
index 8dd96cd7e6f7eba98460269efd1630bc441075c3..b90e69af13ee21b74ec735037483507e3de21457 100644
--- a/src/monitor/monitor.c
+++ b/src/monitor/monitor.c
@@ -156,7 +156,6 @@ struct mt_ctx {
     struct netlink_ctx *nlctx;
     const char *conf_path;
     struct sss_sigchild_ctx *sigchld_ctx;
-    bool pid_file_created;
     bool is_daemon;
     pid_t parent_pid;
 };
@@ -438,20 +437,7 @@ static int mark_service_as_started(struct mt_svc *svc)
         ctx->started_services++;
     }
 
-    /* create the pid file if all services are alive */
-    if (!ctx->pid_file_created && ctx->started_services == ctx->num_services) {
-        DEBUG(SSSDBG_TRACE_FUNC, ("All services have successfully started, "
-                                  "creating pid file\n"));
-        ret = pidfile(PID_PATH, MONITOR_NAME);
-        if (ret != EOK) {
-            DEBUG(SSSDBG_FATAL_FAILURE,
-                  ("Error creating pidfile: %s/%s.pid! (%d [%s])\n",
-                   PID_PATH, MONITOR_NAME, ret, strerror(ret)));
-            kill(getpid(), SIGTERM);
-        }
-
-        ctx->pid_file_created = true;
-
+    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 && ctx->parent_pid > 0
@@ -1473,7 +1459,6 @@ static errno_t load_configuration(TALLOC_CTX *mem_ctx,
         return ENOMEM;
     }
 
-    ctx->pid_file_created = false;
     talloc_set_destructor((TALLOC_CTX *)ctx, monitor_ctx_destructor);
 
     cdb_file = talloc_asprintf(ctx, "%s/%s", DB_PATH, CONFDB_FILE);
@@ -2592,6 +2577,9 @@ int main(int argc, const char *argv[])
         return 6;
     }
 
+    /* we want a pid file check */
+    flags |= FLAGS_PID_FILE;
+
     /* Open before server_setup() does to have logging
      * during configuration checking */
     if (debug_to_file) {
@@ -2635,15 +2623,6 @@ int main(int argc, const char *argv[])
                 "netgroup nsswitch maps.");
     }
 
-    /* Check if the SSSD is already running */
-    ret = check_file(SSSD_PIDFILE_PATH, 0, 0, 0600, CHECK_REG, NULL, false);
-    if (ret == EOK) {
-        DEBUG(SSSDBG_FATAL_FAILURE,
-              ("pidfile exists at %s\n", SSSD_PIDFILE_PATH));
-        ERROR("SSSD is already running\n");
-        return 2;
-    }
-
     /* Parse config file, fail if cannot be done */
     ret = load_configuration(tmp_ctx, config_file, &monitor);
     if (ret != EOK) {
-- 
1.7.11.7

_______________________________________________
sssd-devel mailing list
sssd-devel@lists.fedorahosted.org
https://lists.fedorahosted.org/mailman/listinfo/sssd-devel

Reply via email to