From: Lennart Poettering Date: Wed, 30 Oct 2019 16:41:15 +0000 (+0100) Subject: sd-event: refuse sd_event_add_child() if SIGCHLD is not blocked X-Git-Tag: v245-rc1~315^2~5 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=ee880b37c1522346a6a641bb5d532e94511df86f;p=thirdparty%2Fsystemd.git sd-event: refuse sd_event_add_child() if SIGCHLD is not blocked 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. --- diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c index bb3c542b7cf..8d4a20e420f 100644 --- a/src/libsystemd/sd-event/sd-event.c +++ b/src/libsystemd/sd-event/sd-event.c @@ -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;