chiark / gitweb /
process-spec: add another flag FORK_WAIT to safe_fork()
authorLennart Poettering <lennart@poettering.net>
Fri, 29 Dec 2017 17:01:37 +0000 (18:01 +0100)
committerSven Eden <yamakuzure@gmx.net>
Wed, 30 May 2018 05:49:51 +0000 (07:49 +0200)
This new flag will cause safe_fork() to wait for the forked off child
before returning. This allows us to unify a number of cases where we
immediately wait on the forked off child, witout running any code in the
parent after the fork, and without direct interest in the precise exit
status of the process, except recgonizing EXIT_SUCCESS vs everything
else.

src/basic/exec-util.c
src/basic/process-util.c
src/basic/process-util.h
src/basic/time-util.c

index f3182d3064e3fadec56d83a0356b68761e4bb909..e195bf98558a8fd02bb16e9dd1100fb42222156c 100644 (file)
@@ -193,10 +193,9 @@ int execute_directories(
                 void* const callback_args[_STDOUT_CONSUME_MAX],
                 char *argv[]) {
 
-        pid_t executor_pid;
-        char *name;
         char **dirs = (char**) directories;
         _cleanup_close_ int fd = -1;
+        char *name;
         int r;
 
         assert(!strv_isempty(dirs));
@@ -219,7 +218,7 @@ int execute_directories(
          * them to finish. Optionally a timeout is applied. If a file with the same name
          * exists in more than one directory, the earliest one wins. */
 
-        r = safe_fork("(sd-executor)", FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_LOG, &executor_pid);
+        r = safe_fork("(sd-executor)", FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_LOG|FORK_WAIT, NULL);
         if (r < 0)
                 return r;
         if (r == 0) {
@@ -227,12 +226,6 @@ int execute_directories(
                 _exit(r < 0 ? EXIT_FAILURE : EXIT_SUCCESS);
         }
 
-        r = wait_for_terminate_and_check(name, executor_pid, WAIT_LOG);
-        if (r < 0)
-                return r;
-        if (r > 0) /* non-zero return code from child */
-                return -EREMOTEIO;
-
         if (!callbacks)
                 return 0;
 
index 7329dccfdcf753eb0e85d14d270a639ef5aca55e..c60ca7516c2aad42697aee6fb254d0e9f0131f99 100644 (file)
@@ -1175,7 +1175,7 @@ int safe_fork_full(
                 pid_t *ret_pid) {
 
         pid_t original_pid, pid;
-        sigset_t saved_ss;
+        sigset_t saved_ss, ss;
         bool block_signals;
         int prio, r;
 
@@ -1186,20 +1186,33 @@ int safe_fork_full(
 
         original_pid = getpid_cached();
 
-        block_signals = flags & (FORK_RESET_SIGNALS|FORK_DEATHSIG);
+        if (flags & (FORK_RESET_SIGNALS|FORK_DEATHSIG)) {
 
-        if (block_signals) {
-                sigset_t ss;
+                /* We temporarily block all signals, so that the new child has them blocked initially. This way, we can
+                 * be sure that SIGTERMs are not lost we might send to the child. */
 
-                /* We temporarily block all signals, so that the new child has them blocked initially. This way, we can be sure
-                 * that SIGTERMs are not lost we might send to the child. */
                 if (sigfillset(&ss) < 0)
                         return log_full_errno(prio, errno, "Failed to reset signal set: %m");
 
-                if (sigprocmask(SIG_SETMASK, &ss, &saved_ss) < 0)
-                        return log_full_errno(prio, errno, "Failed to reset signal mask: %m");
+                block_signals = true;
+
+        } else if (flags & FORK_WAIT) {
+
+                /* Let's block SIGCHLD at least, so that we can safely watch for the child process */
+
+                if (sigemptyset(&ss) < 0)
+                        return log_full_errno(prio, errno, "Failed to clear signal set: %m");
+
+                if (sigaddset(&ss, SIGCHLD) < 0)
+                        return log_full_errno(prio, errno, "Failed to add SIGCHLD to signal set: %m");
+
+                block_signals = true;
         }
 
+        if (block_signals)
+                if (sigprocmask(SIG_SETMASK, &ss, &saved_ss) < 0)
+                        return log_full_errno(prio, errno, "Failed to set signal mask: %m");
+
         pid = fork();
         if (pid < 0) {
                 r = -errno;
@@ -1212,11 +1225,19 @@ int safe_fork_full(
         if (pid > 0) {
                 /* We are in the parent process */
 
+                log_debug("Successfully forked off '%s' as PID " PID_FMT ".", strna(name), pid);
+
+                if (flags & FORK_WAIT) {
+                        r = wait_for_terminate_and_check(name, pid, (flags & FORK_LOG ? WAIT_LOG : 0));
+                        if (r < 0)
+                                return r;
+                        if (r != EXIT_SUCCESS) /* exit status > 0 should be treated as failure, too */
+                                return -EPROTO;
+                }
+
                 if (block_signals) /* undo what we did above */
                         (void) sigprocmask(SIG_SETMASK, &saved_ss, NULL);
 
-                log_debug("Sucessfully forked off '%s' as PID " PID_FMT ".", strna(name), pid);
-
                 if (ret_pid)
                         *ret_pid = pid;
 
index d38de5711ed1cd07bf2304c751c1864f7324fbde..f52f95ac1dad59e2659f5d48130a6a9e13b23c3a 100644 (file)
@@ -181,6 +181,7 @@ typedef enum ForkFlags {
         FORK_NULL_STDIO    = 1U << 3,
         FORK_REOPEN_LOG    = 1U << 4,
         FORK_LOG           = 1U << 5,
+        FORK_WAIT          = 1U << 6,
 } ForkFlags;
 
 int safe_fork_full(const char *name, const int except_fds[], size_t n_except_fds, ForkFlags flags, pid_t *ret_pid);
index a6bff575cfa92887a8b8bd3dec8684be62563b47..98324c2346b6d079c438f8556d8e62351d9fbcd3 100644 (file)
@@ -899,7 +899,6 @@ typedef struct ParseTimestampResult {
 int parse_timestamp(const char *t, usec_t *usec) {
         char *last_space, *tz = NULL;
         ParseTimestampResult *shared, tmp;
-        pid_t pid;
         int r;
 
         last_space = strrchr(t, ' ');
@@ -913,7 +912,7 @@ int parse_timestamp(const char *t, usec_t *usec) {
         if (shared == MAP_FAILED)
                 return negative_errno();
 
-        r = safe_fork("(sd-timestamp)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_DEATHSIG, &pid);
+        r = safe_fork("(sd-timestamp)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_DEATHSIG|FORK_WAIT, NULL);
         if (r < 0) {
                 (void) munmap(shared, sizeof *shared);
                 return r;
@@ -941,12 +940,6 @@ int parse_timestamp(const char *t, usec_t *usec) {
                 _exit(EXIT_SUCCESS);
         }
 
-        r = wait_for_terminate(pid, NULL);
-        if (r < 0) {
-                (void) munmap(shared, sizeof *shared);
-                return r;
-        }
-
         tmp = *shared;
         if (munmap(shared, sizeof *shared) != 0)
                 return negative_errno();