]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
sd-event: refuse sd_event_add_child() if SIGCHLD is not blocked
authorLennart Poettering <lennart@poettering.net>
Wed, 30 Oct 2019 16:41:15 +0000 (17:41 +0100)
committerLennart Poettering <lennart@poettering.net>
Wed, 4 Dec 2019 09:35:27 +0000 (10:35 +0100)
We already refuse sd_event_add_signal() if the specified signal is not
blocked, let's do this also for sd_event_add_child(), since we might
need signalfd() to implement this, and this means the signal needs to be
blocked.

src/libsystemd/sd-event/sd-event.c

index bb3c542b7cf40f6421179aecb20baeecd4793603..8d4a20e420fbbef43bffc6ef448d5bb376bafbae 100644 (file)
@@ -1239,6 +1239,20 @@ _public_ int sd_event_add_child(
         assert_return(e->state != SD_EVENT_FINISHED, -ESTALE);
         assert_return(!event_pid_changed(e), -ECHILD);
 
+        if (e->n_enabled_child_sources == 0) {
+                /* Caller must block SIGCHLD before using us to watch children, even if pidfd is available,
+                 * for compatibility with pre-pidfd and because we don't want the reap the child processes
+                 * ourselves, i.e. call waitid(), and don't want Linux' default internal logic for that to
+                 * take effect.
+                 *
+                 * (As an optimization we only do this check on the first child event source created.) */
+                r = signal_is_blocked(SIGCHLD);
+                if (r < 0)
+                        return r;
+                if (r == 0)
+                        return -EBUSY;
+        }
+
         r = hashmap_ensure_allocated(&e->child_sources, NULL);
         if (r < 0)
                 return r;
@@ -1326,6 +1340,14 @@ _public_ int sd_event_add_child_pidfd(
         assert_return(e->state != SD_EVENT_FINISHED, -ESTALE);
         assert_return(!event_pid_changed(e), -ECHILD);
 
+        if (e->n_enabled_child_sources == 0) {
+                r = signal_is_blocked(SIGCHLD);
+                if (r < 0)
+                        return r;
+                if (r == 0)
+                        return -EBUSY;
+        }
+
         r = hashmap_ensure_allocated(&e->child_sources, NULL);
         if (r < 0)
                 return r;