1
0
mirror of https://github.com/systemd/systemd synced 2025-12-22 17:04:45 +01:00

Compare commits

...

15 Commits

Author SHA1 Message Date
Mike Yuan
65d173a02d core/socket: modernize listen/accept_in_cgroup 2025-12-20 22:56:33 +01:00
Daan De Meyer
6dcc937568
Several follow-ups for recent PRs (#40167) 2025-12-20 22:55:25 +01:00
Mike Yuan
8a10293e5d
shutdown: restore error handling 2025-12-20 21:41:01 +01:00
Mike Yuan
f3c6660b9c
pidref: several follow-ups for pidref_wait_for_terminate_full()
Follow-up for e74b571004661ff39fbcbddfe0cbf36d2fda0046

* Do not reuse si
* Refuse timeout == 0
* Use usec_add()
* Rename ret to ret_si - unlike others this one is not so obvious
2025-12-20 21:41:01 +01:00
Mike Yuan
72ce1046e8
core/exec-invoke: log about name of CPU sched policy
Follow-up for 4dcbfbb1adaeefbf2ed9d78f61a56fbcd0251ead

Also, do not encode errno in log if we know the precise cause,
i.e. unsupported.
2025-12-20 21:40:56 +01:00
Mike Yuan
eb17c37df7
process-util: drop unused sched_priority_is_valid() 2025-12-20 18:38:56 +01:00
Matt Fleming
4dcbfbb1ad process-util: Add support SCHED_EXT scheduling policy
Allow CPUSchedulingPolicy to be set to "ext". SCHED_EXT is a new
scheduling policy in Linux v6.12 that allows processes to be scheduled
using custom BPF schedulers instead of the default in-kernel ones.

Selectively setting the SCHED_EXT policy is useful for systems running
in "partial mode" where not all processes are run using a custom
scheduler.

Fallback to SCHED_OTHER and print an error message for systems where
SCHED_EXT isn't available.
2025-12-20 18:31:55 +01:00
Daan De Meyer
84dcbc3fd2 meson: Deduplicate sources before clang-tidy
Let's make sure we don't define the same clang-tidy
test multiple times by deduplicating sources beforehand.
We end up with the same sources in a few cases because
e.g. we reuse the same fuzz-main.c for each fuzz target.
2025-12-20 17:58:19 +01:00
Daan De Meyer
27de9c391d
sd-event: Don't require blocking SIGCHLD for WEXITED (#39806)
We watch for WEXITED via pidfd instead of signalfd, so no need to insist
on blocking SIGCHLD anymore if we're only watching for WEXITED.

This also removes SIGCHLD blocking tree-wide where it's not required
anymore.
2025-12-20 17:35:47 +01:00
Daan De Meyer
29d1df4b03 tree-wide: Remove unnecessary SIGCHLD blocking
Now that sd-event doesn't insist on blocking
SIGCHLD anymore when watching for process exit,
let's stop blocking SIGCHLD tree-wide where not
required anymore.
2025-12-20 15:50:47 +01:00
Daan De Meyer
fbd276cb86 tree-wide: Use pidref_wait_for_terminate_and_check()
Let's use the pidref variants for waiting and
checking a process everywhere and get rid of the
non pidref variants.
2025-12-20 15:50:47 +01:00
Daan De Meyer
e74b571004 pidref: Add pidref_wait_for_terminate_full()
We can use this to replace wait_for_terminate_with_timeout(). Because
we poll a pidfd, we don't need to block SIGCHLD anymore in umount.c.
2025-12-20 15:49:26 +01:00
Daan De Meyer
9bd833ee6e test-pidref: Migrate to new assertion macros 2025-12-20 15:44:36 +01:00
Daan De Meyer
8c367868ee process-util: Use pidref_wait_for_terminate_and_check in pidref_safe_fork()
Note that we still have to block SIGCHLD so that
we can be certain the process is not reaped before
we get the pidfd to it. safe_fork() and friends are
used in libsystemd where we don't control how the
SIGCHLD signal is configured. Specifically, kernel
autoreaping could be enabled which is why we have
to block SIGCHLD until we get the pidfd so that the
kernel cannot autoreap the process before we get
the pidfd.
2025-12-20 15:44:20 +01:00
Daan De Meyer
a1e5d7f865 sd-event: Clean up SIGCHLD conditions for sd_event_add_child()
First, don't require blocking SIGCHLD for WEXITED. We watch for WEXITED
via pidfd instead of signalfd, so no need to insist on blocking SIGCHLD
anymore if we're only watching for WEXITED.

Second, do a proper check to see if the kernel autoreaping logic is
enabled. That has nothing to do with SIGCHLD being blocked for the current
thread or not. Instead, the kernel autoreaping logic is enabled either if
the disposition is set to SIG_IGN or if the SA_NOCLDWAIT flag is enabled.
2025-12-20 15:27:22 +01:00
102 changed files with 1070 additions and 1027 deletions

4
TODO
View File

@ -576,10 +576,6 @@ Features:
* The bind(AF_UNSPEC) construct (for resetting sockets to their initial state)
should be blocked in many cases because it punches holes in many sandboxes.
* find a nice way to opt-in into auto-masking SIGCHLD on first
sd_event_add_child(), and then get rid of many more explicit sigprocmask()
calls.
* introduce new structure Tpm2CombinedPolicy, that combines the various TPm2
policy bits into one structure, i.e. public key info, pcr masks, pcrlock
stuff, pin and so on. Then pass that around in tpm2_seal() and tpm2_unseal().

View File

@ -10,12 +10,6 @@ int main(int argc, char **argv) {
pid_t pid = fork();
assert(pid >= 0);
/* SIGCHLD signal must be blocked for sd_event_add_child to work */
sigset_t ss;
sigemptyset(&ss);
sigaddset(&ss, SIGCHLD);
sigprocmask(SIG_BLOCK, &ss, NULL);
if (pid == 0) /* child */
sleep(1);

View File

@ -149,11 +149,13 @@
<constant>SD_EVENT_OFF</constant> with
<citerefentry><refentrytitle>sd_event_source_set_enabled</refentrytitle><manvolnum>3</manvolnum></citerefentry>.</para>
<para>The <constant>SIGCHLD</constant> signal must be blocked in all threads before this function is
called (using <citerefentry
project='man-pages'><refentrytitle>sigprocmask</refentrytitle><manvolnum>2</manvolnum></citerefentry> or
<citerefentry
project='man-pages'><refentrytitle>pthread_sigmask</refentrytitle><manvolnum>3</manvolnum></citerefentry>).</para>
<para>The kernel autoreaping logic must be disabled for this function to work as expected (see
<citerefentry project='man-pages'><refentrytitle>signal</refentrytitle><manvolnum>7</manvolnum></citerefentry>).</para>
<para>When watching for <constant>WSTOPPED</constant> or <constant>WCONTINUED</constant>, the
<constant>SIGCHLD</constant> signal must be blocked in all threads before this function is called (using
<citerefentry project='man-pages'><refentrytitle>sigprocmask</refentrytitle><manvolnum>2</manvolnum></citerefentry> or
<citerefentry project='man-pages'><refentrytitle>pthread_sigmask</refentrytitle><manvolnum>3</manvolnum></citerefentry>).</para>
<para>If the second parameter of <function>sd_event_add_child()</function> is passed as
<constant>NULL</constant> no reference to the event source object is returned. In this case, the event
@ -190,7 +192,9 @@
regardless which of <function>sd_event_add_child()</function> and
<function>sd_event_add_child_pidfd()</function> is used for allocating an event source, the watched
process has to be a direct child process of the invoking process. Also in both cases
<constant>SIGCHLD</constant> has to be blocked in the invoking process.</para>
<constant>SIGCHLD</constant> has to be blocked in the invoking process when watching for
<constant>WSTOPPED</constant> or <constant>WCONTINUED</constant> and the kernel autoreaping logic has to
be disabled.</para>
<para><function>sd_event_source_get_child_pid()</function>
retrieves the configured PID of a child process state change event

View File

@ -1326,7 +1326,7 @@ CapabilityBoundingSet=~CAP_B CAP_C</programlisting>
<term><varname>CPUSchedulingPolicy=</varname></term>
<listitem><para>Sets the CPU scheduling policy for executed processes. Takes one of <option>other</option>,
<option>batch</option>, <option>idle</option>, <option>fifo</option> or <option>rr</option>. See
<option>batch</option>, <option>idle</option>, <option>fifo</option>, <option>rr</option> or <option>ext</option>. See
<citerefentry project='man-pages'><refentrytitle>sched_setscheduler</refentrytitle><manvolnum>2</manvolnum></citerefentry> for
details.</para></listitem>
</varlistentry>

View File

@ -2948,7 +2948,18 @@ endif
alias_target('gensources', generated_sources)
clang_tidy = find_program('clang-tidy', required : false)
if meson.version().version_compare('>=1.4.0')
if meson.version().version_compare('>=1.10.0')
uniq = {}
foreach source : sources
if uniq.has_key(source.full_path())
continue
endif
uniq += {source.full_path(): source}
endforeach
sources = uniq.values()
foreach source : sources
if systemd_headers.contains(source)
continue

View File

@ -15,6 +15,7 @@
#include "lock-util.h"
#include "log.h"
#include "path-util.h"
#include "pidref.h"
#include "process-util.h"
#include "string-util.h"
#include "time-util.h"
@ -199,7 +200,6 @@ int lock_generic(int fd, LockType type, int operation) {
}
int lock_generic_with_timeout(int fd, LockType type, int operation, usec_t timeout) {
_cleanup_(sigkill_waitp) pid_t pid = 0;
int r;
assert(fd >= 0);
@ -223,8 +223,8 @@ int lock_generic_with_timeout(int fd, LockType type, int operation, usec_t timeo
return r;
/* If that didn't work, try with a child */
r = safe_fork("(sd-flock)", FORK_RESET_SIGNALS|FORK_DEATHSIG_SIGKILL, &pid);
_cleanup_(pidref_done_sigkill_wait) PidRef pidref = PIDREF_NULL;
r = pidref_safe_fork("(sd-flock)", FORK_RESET_SIGNALS|FORK_DEATHSIG_SIGKILL, &pidref);
if (r < 0)
return log_error_errno(r, "Failed to flock block device in child process: %m");
if (r == 0) {
@ -256,11 +256,11 @@ int lock_generic_with_timeout(int fd, LockType type, int operation, usec_t timeo
}
siginfo_t status;
r = wait_for_terminate(pid, &status);
r = pidref_wait_for_terminate(&pidref, &status);
if (r < 0)
return r;
TAKE_PID(pid);
pidref_done(&pidref);
switch (status.si_code) {

View File

@ -601,25 +601,25 @@ int userns_acquire_self_root(void) {
return userns_acquire(uid_map, gid_map, /* setgroups_deny= */ true);
}
int userns_enter_and_pin(int userns_fd, pid_t *ret_pid) {
int userns_enter_and_pin(int userns_fd, PidRef *ret) {
_cleanup_close_pair_ int pfd[2] = EBADF_PAIR;
_cleanup_(sigkill_waitp) pid_t pid = 0;
_cleanup_(pidref_done_sigkill_wait) PidRef pidref = PIDREF_NULL;
ssize_t n;
char x;
int r;
assert(userns_fd >= 0);
assert(ret_pid);
assert(ret);
if (pipe2(pfd, O_CLOEXEC) < 0)
return -errno;
r = safe_fork_full(
r = pidref_safe_fork_full(
"(sd-pinuserns)",
/* stdio_fds= */ NULL,
(int[]) { pfd[1], userns_fd }, 2,
FORK_CLOSE_ALL_FDS|FORK_DEATHSIG_SIGKILL,
&pid);
&pidref);
if (r < 0)
return r;
if (r == 0) {
@ -652,7 +652,7 @@ int userns_enter_and_pin(int userns_fd, pid_t *ret_pid) {
assert(n == 1);
assert(x == 'x');
*ret_pid = TAKE_PID(pid);
*ret = TAKE_PIDREF(pidref);
return 0;
}
@ -661,22 +661,22 @@ bool userns_supported(void) {
}
int userns_get_base_uid(int userns_fd, uid_t *ret_uid, gid_t *ret_gid) {
_cleanup_(sigkill_waitp) pid_t pid = 0;
_cleanup_(pidref_done_sigkill_wait) PidRef pidref = PIDREF_NULL;
int r;
assert(userns_fd >= 0);
r = userns_enter_and_pin(userns_fd, &pid);
r = userns_enter_and_pin(userns_fd, &pidref);
if (r < 0)
return r;
uid_t uid;
r = uid_map_search_root(pid, UID_RANGE_USERNS_OUTSIDE, &uid);
r = uid_map_search_root(pidref.pid, UID_RANGE_USERNS_OUTSIDE, &uid);
if (r < 0)
return r;
gid_t gid;
r = uid_map_search_root(pid, GID_RANGE_USERNS_OUTSIDE, &gid);
r = uid_map_search_root(pidref.pid, GID_RANGE_USERNS_OUTSIDE, &gid);
if (r < 0)
return r;

View File

@ -82,7 +82,7 @@ int parse_userns_uid_range(const char *s, uid_t *ret_uid_shift, uid_t *ret_uid_r
int userns_acquire_empty(void);
int userns_acquire(const char *uid_map, const char *gid_map, bool setgroups_deny);
int userns_acquire_self_root(void);
int userns_enter_and_pin(int userns_fd, pid_t *ret_pid);
int userns_enter_and_pin(int userns_fd, PidRef *ret);
bool userns_supported(void);
int userns_get_base_uid(int userns_fd, uid_t *ret_uid, gid_t *ret_gid);

View File

@ -1,5 +1,6 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <poll.h>
#include <sys/wait.h>
#include <unistd.h>
@ -8,12 +9,14 @@
#include "fd-util.h"
#include "format-util.h"
#include "hash-funcs.h"
#include "io-util.h"
#include "log.h"
#include "parse-util.h"
#include "pidfd-util.h"
#include "pidref.h"
#include "process-util.h"
#include "siphash24.h"
#include "time-util.h"
int pidref_acquire_pidfd_id(PidRef *pidref) {
int r;
@ -449,9 +452,11 @@ bool pidref_is_self(PidRef *pidref) {
return pidref->fd_id == self_id;
}
int pidref_wait(PidRef *pidref, siginfo_t *ret, int options) {
int pidref_wait_for_terminate_full(PidRef *pidref, usec_t timeout, siginfo_t *ret_si) {
int r;
assert(timeout > 0);
if (!pidref_is_set(pidref))
return -ESRCH;
@ -461,25 +466,37 @@ int pidref_wait(PidRef *pidref, siginfo_t *ret, int options) {
if (pidref->pid == 1 || pidref_is_self(pidref))
return -ECHILD;
siginfo_t si = {};
if (pidref->fd >= 0)
r = RET_NERRNO(waitid(P_PIDFD, pidref->fd, &si, options));
else
r = RET_NERRNO(waitid(P_PID, pidref->pid, &si, options));
if (r < 0)
return r;
if (timeout != USEC_INFINITY && pidref->fd < 0)
return -ENOMEDIUM;
if (ret)
*ret = si;
return 0;
}
int pidref_wait_for_terminate(PidRef *pidref, siginfo_t *ret) {
int r;
usec_t ts = timeout == USEC_INFINITY ? USEC_INFINITY : usec_add(now(CLOCK_MONOTONIC), timeout);
for (;;) {
r = pidref_wait(pidref, ret, WEXITED);
if (ts != USEC_INFINITY) {
usec_t left = usec_sub_unsigned(ts, now(CLOCK_MONOTONIC));
if (left == 0)
return -ETIMEDOUT;
r = fd_wait_for_event(pidref->fd, POLLIN, left);
if (r == 0)
return -ETIMEDOUT;
if (r == -EINTR)
continue;
if (r < 0)
return r;
}
siginfo_t si = {};
if (pidref->fd >= 0)
r = RET_NERRNO(waitid(P_PIDFD, pidref->fd, &si, WEXITED));
else
r = RET_NERRNO(waitid(P_PID, pidref->pid, &si, WEXITED));
if (r >= 0) {
if (ret_si)
*ret_si = si;
return 0;
}
if (r != -EINTR)
return r;
}

View File

@ -96,8 +96,19 @@ int pidref_kill(const PidRef *pidref, int sig);
int pidref_kill_and_sigcont(const PidRef *pidref, int sig);
int pidref_sigqueue(const PidRef *pidref, int sig, int value);
int pidref_wait(PidRef *pidref, siginfo_t *ret, int options);
int pidref_wait_for_terminate(PidRef *pidref, siginfo_t *ret);
int pidref_wait_for_terminate_full(PidRef *pidref, usec_t timeout, siginfo_t *ret_si);
static inline int pidref_wait_for_terminate(PidRef *pidref, siginfo_t *ret_si) {
return pidref_wait_for_terminate_full(pidref, USEC_INFINITY, ret_si);
}
static inline void pidref_done_sigterm_wait(PidRef *pidref) {
if (!pidref_is_set(pidref))
return;
(void) pidref_kill(pidref, SIGTERM);
(void) pidref_wait_for_terminate(pidref, NULL);
pidref_done(pidref);
}
static inline void pidref_done_sigkill_wait(PidRef *pidref) {
if (!pidref_is_set(pidref))
@ -108,6 +119,14 @@ static inline void pidref_done_sigkill_wait(PidRef *pidref) {
pidref_done(pidref);
}
static inline void pidref_done_sigkill_nowait(PidRef *pidref) {
if (!pidref_is_set(pidref))
return;
(void) pidref_kill(pidref, SIGKILL);
pidref_done(pidref);
}
int pidref_verify(const PidRef *pidref);
#define TAKE_PIDREF(p) TAKE_GENERIC((p), PidRef, PIDREF_NULL)

View File

@ -845,13 +845,9 @@ int get_process_umask(pid_t pid, mode_t *ret) {
return parse_mode(m, ret);
}
int wait_for_terminate(pid_t pid, siginfo_t *ret) {
return pidref_wait_for_terminate(&PIDREF_MAKE_FROM_PID(pid), ret);
}
/*
* Return values:
* < 0 : wait_for_terminate() failed to get the state of the
* < 0 : pidref_wait_for_terminate() failed to get the state of the
* process, the process was terminated by a signal, or
* failed for an unknown reason.
* >=0 : The process terminated normally, and its exit code is
@ -908,115 +904,6 @@ int pidref_wait_for_terminate_and_check(const char *name, PidRef *pidref, WaitFl
return -EPROTO;
}
int wait_for_terminate_and_check(const char *name, pid_t pid, WaitFlags flags) {
return pidref_wait_for_terminate_and_check(name, &PIDREF_MAKE_FROM_PID(pid), flags);
}
/*
* Return values:
*
* < 0 : wait_for_terminate_with_timeout() failed to get the state of the process, the process timed out, the process
* was terminated by a signal, or failed for an unknown reason.
*
* >=0 : The process terminated normally with no failures.
*
* Success is indicated by a return value of zero, a timeout is indicated by ETIMEDOUT, and all other child failure
* states are indicated by error is indicated by a non-zero value.
*
* This call assumes SIGCHLD has been blocked already, in particular before the child to wait for has been forked off
* to remain entirely race-free.
*/
int wait_for_terminate_with_timeout(pid_t pid, usec_t timeout) {
sigset_t mask;
int r;
usec_t until;
assert_se(sigemptyset(&mask) == 0);
assert_se(sigaddset(&mask, SIGCHLD) == 0);
/* Drop into a sigtimewait-based timeout. Waiting for the
* pid to exit. */
until = usec_add(now(CLOCK_MONOTONIC), timeout);
for (;;) {
usec_t n;
siginfo_t status = {};
n = now(CLOCK_MONOTONIC);
if (n >= until)
break;
r = RET_NERRNO(sigtimedwait(&mask, NULL, TIMESPEC_STORE(until - n)));
/* Assuming we woke due to the child exiting. */
if (waitid(P_PID, pid, &status, WEXITED|WNOHANG) == 0) {
if (status.si_pid == pid) {
/* This is the correct child. */
if (status.si_code == CLD_EXITED)
return status.si_status == 0 ? 0 : -EPROTO;
else
return -EPROTO;
}
}
/* Not the child, check for errors and proceed appropriately */
if (r < 0) {
switch (r) {
case -EAGAIN:
/* Timed out, child is likely hung. */
return -ETIMEDOUT;
case -EINTR:
/* Received a different signal and should retry */
continue;
default:
/* Return any unexpected errors */
return r;
}
}
}
return -EPROTO;
}
void sigkill_wait(pid_t pid) {
assert(pid > 1);
(void) kill(pid, SIGKILL);
(void) wait_for_terminate(pid, NULL);
}
void sigkill_waitp(pid_t *pid) {
PROTECT_ERRNO;
if (!pid)
return;
if (*pid <= 1)
return;
sigkill_wait(*pid);
}
void sigterm_wait(pid_t pid) {
assert(pid > 1);
(void) kill_and_sigcont(pid, SIGTERM);
(void) wait_for_terminate(pid, NULL);
}
void sigkill_nowait(pid_t pid) {
assert(pid > 1);
(void) kill(pid, SIGKILL);
}
void sigkill_nowaitp(pid_t *pid) {
PROTECT_ERRNO;
if (!pid)
return;
if (*pid <= 1)
return;
sigkill_nowait(*pid);
}
int kill_and_sigcont(pid_t pid, int sig) {
int r;
@ -1343,7 +1230,9 @@ void valgrind_summary_hack(void) {
exit(EXIT_SUCCESS);
else {
log_info("Spawned valgrind helper as PID "PID_FMT".", pid);
(void) wait_for_terminate(pid, NULL);
_cleanup_(pidref_done) PidRef pidref = PIDREF_MAKE_FROM_PID(pid);
(void) pidref_set_pid(&pidref, pid);
(void) pidref_wait_for_terminate(&pidref, NULL);
}
}
#endif
@ -1359,11 +1248,33 @@ bool nice_is_valid(int n) {
}
bool sched_policy_is_valid(int i) {
return IN_SET(i, SCHED_OTHER, SCHED_BATCH, SCHED_IDLE, SCHED_FIFO, SCHED_RR);
return IN_SET(i, SCHED_OTHER, SCHED_BATCH, SCHED_IDLE, SCHED_FIFO, SCHED_RR, SCHED_EXT);
}
bool sched_priority_is_valid(int i) {
return i >= 0 && i <= sched_get_priority_max(SCHED_RR);
bool sched_policy_supported(int policy) {
return sched_get_priority_min(policy) >= 0;
}
/* Wrappers around sched_get_priority_{min,max}() that gracefully handles missing SCHED_EXT support in the kernel */
int sched_get_priority_min_safe(int policy) {
int r;
r = sched_get_priority_min(policy);
if (r >= 0)
return r;
/* Fallback priority */
return 0;
}
int sched_get_priority_max_safe(int policy) {
int r;
r = sched_get_priority_max(policy);
if (r >= 0)
return r;
return 0;
}
/* The cached PID, possible values:
@ -1566,9 +1477,13 @@ int pidref_safe_fork_full(
pidref_transport_fds[1] = safe_close(pidref_transport_fds[1]);
if (pidref_transport_fds[0] >= 0) {
/* Wait for the intermediary child to exit so the caller can be certain the actual child
* process has been reparented by the time this function returns. */
r = wait_for_terminate_and_check(name, pid, FLAGS_SET(flags, FORK_LOG) ? WAIT_LOG : 0);
/* Wait for the intermediary child to exit so the caller can be
* certain the actual child process has been reparented by the time
* this function returns. */
r = pidref_wait_for_terminate_and_check(
name,
&PIDREF_MAKE_FROM_PID(pid),
FLAGS_SET(flags, FORK_LOG) ? WAIT_LOG : 0);
if (r < 0)
return log_full_errno(prio, r, "Failed to wait for intermediary process: %m");
if (r != EXIT_SUCCESS) /* exit status > 0 should be treated as failure, too */
@ -1644,7 +1559,10 @@ int pidref_safe_fork_full(
(void) sigprocmask(SIG_SETMASK, &ss, NULL);
}
r = wait_for_terminate_and_check(name, pid, (flags & FORK_LOG ? WAIT_LOG : 0));
r = pidref_wait_for_terminate_and_check(
name,
&PIDREF_MAKE_FROM_PID(pid),
FLAGS_SET(flags, FORK_LOG) ? WAIT_LOG : 0);
if (r < 0)
return r;
if (r != EXIT_SUCCESS) /* exit status > 0 should be treated as failure, too */
@ -2363,6 +2281,7 @@ static const char* const sched_policy_table[] = {
[SCHED_BATCH] = "batch",
[SCHED_IDLE] = "idle",
[SCHED_FIFO] = "fifo",
[SCHED_EXT] = "ext",
[SCHED_RR] = "rr",
};

View File

@ -60,8 +60,6 @@ static inline bool SIGINFO_CODE_IS_DEAD(int code) {
return IN_SET(code, CLD_EXITED, CLD_KILLED, CLD_DUMPED);
}
int wait_for_terminate(pid_t pid, siginfo_t *ret);
typedef enum WaitFlags {
WAIT_LOG_ABNORMAL = 1 << 0,
WAIT_LOG_NON_ZERO_EXIT_STATUS = 1 << 1,
@ -71,15 +69,6 @@ typedef enum WaitFlags {
} WaitFlags;
int pidref_wait_for_terminate_and_check(const char *name, PidRef *pidref, WaitFlags flags);
int wait_for_terminate_and_check(const char *name, pid_t pid, WaitFlags flags);
int wait_for_terminate_with_timeout(pid_t pid, usec_t timeout);
void sigkill_wait(pid_t pid);
void sigkill_waitp(pid_t *pid);
void sigterm_wait(pid_t pid);
void sigkill_nowait(pid_t pid);
void sigkill_nowaitp(pid_t *pid);
int kill_and_sigcont(pid_t pid, int sig);
@ -139,7 +128,9 @@ int pid_compare_func(const pid_t *a, const pid_t *b);
bool nice_is_valid(int n) _const_;
bool sched_policy_is_valid(int i) _const_;
bool sched_priority_is_valid(int i) _const_;
bool sched_policy_supported(int i);
int sched_get_priority_min_safe(int i);
int sched_get_priority_max_safe(int i);
#define PID_AUTOMATIC ((pid_t) INT_MIN) /* special value indicating "acquire pid from connection peer" */

View File

@ -238,6 +238,15 @@ int signal_is_blocked(int sig) {
return RET_NERRNO(sigismember(&ss, sig));
}
int autoreaping_enabled(void) {
struct sigaction sa;
if (sigaction(SIGCHLD, /* __act= */ NULL, &sa) < 0)
return -errno;
return sa.sa_handler == SIG_IGN || FLAGS_SET(sa.sa_flags, SA_NOCLDWAIT);
}
int pop_pending_signal_internal(int sig, ...) {
sigset_t ss;
va_list ap;

View File

@ -66,6 +66,8 @@ static inline const char* signal_to_string_with_check(int n) {
int signal_is_blocked(int sig);
int autoreaping_enabled(void);
int pop_pending_signal_internal(int sig, ...);
#define pop_pending_signal(...) pop_pending_signal_internal(__VA_ARGS__, -1)

View File

@ -8,6 +8,7 @@
#include "format-util.h"
#include "namespace-util.h"
#include "path-util.h"
#include "pidref.h"
#include "process-util.h"
#include "sort-util.h"
#include "stat-util.h"
@ -286,7 +287,7 @@ int uid_range_load_userns(const char *path, UIDRangeUsernsMode mode, UIDRange **
}
int uid_range_load_userns_by_fd(int userns_fd, UIDRangeUsernsMode mode, UIDRange **ret) {
_cleanup_(sigkill_waitp) pid_t pid = 0;
_cleanup_(pidref_done_sigkill_wait) PidRef pidref = PIDREF_NULL;
int r;
assert(userns_fd >= 0);
@ -294,12 +295,12 @@ int uid_range_load_userns_by_fd(int userns_fd, UIDRangeUsernsMode mode, UIDRange
assert(mode < _UID_RANGE_USERNS_MODE_MAX);
assert(ret);
r = userns_enter_and_pin(userns_fd, &pid);
r = userns_enter_and_pin(userns_fd, &pidref);
if (r < 0)
return r;
const char *p = procfs_file_alloca(
pid,
pidref.pid,
IN_SET(mode, UID_RANGE_USERNS_INSIDE, UID_RANGE_USERNS_OUTSIDE) ? "uid_map" : "gid_map");
return uid_range_load_userns(p, mode, ret);

View File

@ -12,6 +12,7 @@
#include "format-util.h"
#include "log.h"
#include "main.h"
#include "pidref.h"
#include "process-util.h"
#include "raw-clone.h"
#include "rlimit-util.h"
@ -127,8 +128,11 @@ _noreturn_ static void crash(int sig, siginfo_t *siginfo, void *context) {
LOG_MESSAGE_ID(SD_MESSAGE_CRASH_PROCESS_SIGNAL_STR));
}
_cleanup_(pidref_done) PidRef pidref = PIDREF_MAKE_FROM_PID(pid);
(void) pidref_set_pid(&pidref, pid);
/* Order things nicely. */
r = wait_for_terminate(pid, &status);
r = pidref_wait_for_terminate(&pidref, &status);
if (r < 0)
log_struct_errno(LOG_EMERG, r,
LOG_MESSAGE("Caught <%s>, waitpid() failed: %m", signal_to_string(sig)),
@ -181,7 +185,9 @@ _noreturn_ static void crash(int sig, siginfo_t *siginfo, void *context) {
_exit(EXIT_EXCEPTION);
} else {
log_info("Spawned crash shell as PID "PID_FMT".", pid);
(void) wait_for_terminate(pid, NULL);
_cleanup_(pidref_done) PidRef pidref = PIDREF_MAKE_FROM_PID(pid);
(void) pidref_set_pid(&pidref, pid);
(void) pidref_wait_for_terminate(&pidref, NULL);
}
}

View File

@ -3167,7 +3167,7 @@ int bus_exec_context_set_transient_property(
return r;
c->cpu_sched_policy = q;
c->cpu_sched_priority = CLAMP(c->cpu_sched_priority, sched_get_priority_min(q), sched_get_priority_max(q));
c->cpu_sched_priority = CLAMP(c->cpu_sched_priority, sched_get_priority_min_safe(q), sched_get_priority_max_safe(q));
c->cpu_sched_set = true;
unit_write_settingf(u, flags, name, "CPUSchedulingPolicy=%s", s);

View File

@ -2406,7 +2406,7 @@ static int setup_private_users(PrivateUsers private_users, uid_t ouid, gid_t ogi
_cleanup_free_ char *uid_map = NULL, *gid_map = NULL;
_cleanup_close_pair_ int errno_pipe[2] = EBADF_PAIR;
_cleanup_close_ int unshare_ready_fd = -EBADF;
_cleanup_(sigkill_waitp) pid_t pid = 0;
_cleanup_(pidref_done_sigkill_wait) PidRef pidref = PIDREF_NULL;
uint64_t c = 1;
ssize_t n;
int r;
@ -2503,7 +2503,7 @@ static int setup_private_users(PrivateUsers private_users, uid_t ouid, gid_t ogi
if (pipe2(errno_pipe, O_CLOEXEC) < 0)
return -errno;
r = safe_fork("(sd-userns)", FORK_RESET_SIGNALS|FORK_DEATHSIG_SIGKILL, &pid);
r = pidref_safe_fork("(sd-userns)", FORK_RESET_SIGNALS|FORK_DEATHSIG_SIGKILL, &pidref);
if (r < 0)
return r;
if (r == 0) {
@ -2535,9 +2535,10 @@ static int setup_private_users(PrivateUsers private_users, uid_t ouid, gid_t ogi
if (n != 0) /* on success we should have read 0 bytes */
return -EIO;
r = wait_for_terminate_and_check("(sd-userns)", TAKE_PID(pid), 0);
r = pidref_wait_for_terminate_and_check("(sd-userns)", &pidref, 0);
if (r < 0)
return r;
pidref_done(&pidref);
if (r != EXIT_SUCCESS) /* If something strange happened with the child, let's consider this fatal, too */
return -EIO;
@ -2546,7 +2547,7 @@ static int setup_private_users(PrivateUsers private_users, uid_t ouid, gid_t ogi
static int can_mount_proc(void) {
_cleanup_close_pair_ int errno_pipe[2] = EBADF_PAIR;
_cleanup_(sigkill_waitp) pid_t pid = 0;
_cleanup_(pidref_done_sigkill_wait) PidRef pidref = PIDREF_NULL;
ssize_t n;
int r;
@ -2561,8 +2562,10 @@ static int can_mount_proc(void) {
/* Fork a child process into its own mount and PID namespace. Note safe_fork() already remounts / as SLAVE
* with FORK_MOUNTNS_SLAVE. */
r = safe_fork("(sd-proc-check)",
FORK_RESET_SIGNALS|FORK_DEATHSIG_SIGKILL|FORK_NEW_MOUNTNS|FORK_MOUNTNS_SLAVE|FORK_NEW_PIDNS, &pid);
r = pidref_safe_fork(
"(sd-proc-check)",
FORK_RESET_SIGNALS|FORK_DEATHSIG_SIGKILL|FORK_NEW_MOUNTNS|FORK_MOUNTNS_SLAVE|FORK_NEW_PIDNS,
&pidref);
if (r < 0)
return log_debug_errno(r, "Failed to fork child process (sd-proc-check): %m");
if (r == 0) {
@ -2597,9 +2600,10 @@ static int can_mount_proc(void) {
if (n != 0) /* on success we should have read 0 bytes */
return -EIO;
r = wait_for_terminate_and_check("(sd-proc-check)", TAKE_PID(pid), /* flags= */ 0);
r = pidref_wait_for_terminate_and_check("(sd-proc-check)", &pidref, /* flags= */ 0);
if (r < 0)
return log_debug_errno(r, "Failed to wait for (sd-proc-check) child process to terminate: %m");
pidref_done(&pidref);
if (r != EXIT_SUCCESS) /* If something strange happened with the child, let's consider this fatal, too */
return log_debug_errno(SYNTHETIC_ERRNO(EIO), "Child process (sd-proc-check) exited with unexpected exit status '%d'.", r);
@ -5469,9 +5473,16 @@ int exec_invoke(
r = sched_setattr(/* pid= */ 0, &attr, /* flags= */ 0);
if (r < 0) {
if (errno != EINVAL || sched_policy_supported(attr.sched_policy)) {
*exit_status = EXIT_SETSCHEDULER;
return log_error_errno(errno, "Failed to set up CPU scheduling: %m");
}
_cleanup_free_ char *s = NULL;
(void) sched_policy_to_string_alloc(context->cpu_sched_policy, &s);
log_warning_errno(errno, "CPU scheduling policy %s is not supported, proceeding without.", strna(s));
}
}
/*

View File

@ -1539,9 +1539,12 @@ int config_parse_exec_cpu_sched_policy(
return 0;
}
if (!sched_policy_supported(x))
log_syntax(unit, LOG_WARNING, filename, line, x, "Unsupported CPU scheduling policy: %s", rvalue);
c->cpu_sched_policy = x;
/* Moving to or from real-time policy? We need to adjust the priority */
c->cpu_sched_priority = CLAMP(c->cpu_sched_priority, sched_get_priority_min(x), sched_get_priority_max(x));
c->cpu_sched_priority = CLAMP(c->cpu_sched_priority, sched_get_priority_min_safe(x), sched_get_priority_max_safe(x));
c->cpu_sched_set = true;
return 0;

View File

@ -1557,9 +1557,7 @@ static int socket_address_listen_in_cgroup(
const SocketAddress *address,
const char *label) {
_cleanup_(pidref_done) PidRef pid = PIDREF_NULL;
_cleanup_close_pair_ int pair[2] = EBADF_PAIR;
int fd, r;
int r;
assert(s);
assert(address);
@ -1571,11 +1569,11 @@ static int socket_address_listen_in_cgroup(
if (!fork_needed(address, s)) {
/* Shortcut things... */
fd = socket_address_listen_do(s, address, label);
if (fd < 0)
return log_address_error_errno(UNIT(s), address, fd, "Failed to create listening socket (%s): %m");
r = socket_address_listen_do(s, address, label);
if (r < 0)
return log_address_error_errno(UNIT(s), address, r, "Failed to create listening socket (%s): %m");
return fd;
return r;
}
r = unit_setup_exec_runtime(UNIT(s));
@ -1605,6 +1603,10 @@ static int socket_address_listen_in_cgroup(
}
}
_cleanup_(pidref_done) PidRef pid = PIDREF_NULL;
_cleanup_close_pair_ int pair[2] = EBADF_PAIR;
_cleanup_close_ int fd = -EBADF;
if (socketpair(AF_UNIX, SOCK_SEQPACKET|SOCK_CLOEXEC, 0, pair) < 0)
return log_unit_error_errno(UNIT(s), errno, "Failed to create communication channel: %m");
@ -1653,16 +1655,14 @@ static int socket_address_listen_in_cgroup(
fd = receive_one_fd(pair[0], 0);
/* We synchronously wait for the helper, as it shouldn't be slow */
r = wait_for_terminate_and_check("(sd-listen)", pid.pid, WAIT_LOG_ABNORMAL);
if (r < 0) {
safe_close(fd);
r = pidref_wait_for_terminate_and_check("(sd-listen)", &pid, WAIT_LOG_ABNORMAL);
if (r < 0)
return r;
}
if (fd < 0)
return log_address_error_errno(UNIT(s), address, fd, "Failed to receive listening socket (%s): %m");
return fd;
return TAKE_FD(fd);
}
static int socket_open_fds(Socket *orig_s) {
@ -3181,7 +3181,7 @@ static int socket_accept_in_cgroup(Socket *s, SocketPort *p, int fd) {
cfd = receive_one_fd(pair[0], 0);
/* We synchronously wait for the helper, as it shouldn't be slow */
r = wait_for_terminate_and_check("(sd-accept)", pid.pid, WAIT_LOG_ABNORMAL);
r = pidref_wait_for_terminate_and_check("(sd-accept)", &pid, WAIT_LOG_ABNORMAL);
if (r < 0) {
safe_close(cfd);
return r;
@ -3189,7 +3189,7 @@ static int socket_accept_in_cgroup(Socket *s, SocketPort *p, int fd) {
/* If we received no fd, we got EIO here. If this happens with a process exit code of EXIT_SUCCESS
* this is a spurious accept(), let's convert that back to EAGAIN here. */
if (cfd == -EIO)
if (cfd == -EIO && r == EXIT_SUCCESS)
return -EAGAIN;
if (cfd < 0)
return log_unit_error_errno(UNIT(s), cfd, "Failed to receive connection socket: %m");

View File

@ -42,6 +42,7 @@
#include "parse-argument.h"
#include "parse-util.h"
#include "path-util.h"
#include "pidref.h"
#include "pretty-print.h"
#include "process-util.h"
#include "signal-util.h"
@ -1177,7 +1178,6 @@ static int run_debug(int argc, char **argv, void *userdata) {
bool unlink_path = false;
const char *data, *fork_name;
size_t len;
pid_t pid;
int r;
if (!arg_debugger) {
@ -1271,7 +1271,11 @@ static int run_debug(int argc, char **argv, void *userdata) {
fork_name = strjoina("(", debugger_call[0], ")");
r = safe_fork(fork_name, FORK_RESET_SIGNALS|FORK_DEATHSIG_SIGTERM|FORK_CLOSE_ALL_FDS|FORK_RLIMIT_NOFILE_SAFE|FORK_LOG|FORK_FLUSH_STDIO, &pid);
_cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
r = pidref_safe_fork(
fork_name,
FORK_RESET_SIGNALS|FORK_DEATHSIG_SIGTERM|FORK_CLOSE_ALL_FDS|FORK_RLIMIT_NOFILE_SAFE|FORK_LOG|FORK_FLUSH_STDIO,
&pidref);
if (r < 0)
goto finish;
if (r == 0) {
@ -1281,7 +1285,7 @@ static int run_debug(int argc, char **argv, void *userdata) {
_exit(EXIT_FAILURE);
}
r = wait_for_terminate_and_check(debugger_call[0], pid, WAIT_LOG_ABNORMAL);
r = pidref_wait_for_terminate_and_check(debugger_call[0], &pidref, WAIT_LOG_ABNORMAL);
finish:
(void) default_signals(SIGINT, SIGTERM);

View File

@ -19,6 +19,7 @@
#include "pager.h"
#include "parse-argument.h"
#include "path-util.h"
#include "pidref.h"
#include "pretty-print.h"
#include "process-util.h"
#include "stat-util.h"
@ -140,7 +141,6 @@ static int notify_override_unchanged(const char *f) {
static int found_override(const char *top, const char *bottom) {
_cleanup_free_ char *dest = NULL;
pid_t pid;
int r;
assert(top);
@ -165,7 +165,11 @@ static int found_override(const char *top, const char *bottom) {
fflush(stdout);
r = safe_fork("(diff)", FORK_RESET_SIGNALS|FORK_DEATHSIG_SIGTERM|FORK_CLOSE_ALL_FDS|FORK_RLIMIT_NOFILE_SAFE|FORK_LOG, &pid);
_cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
r = pidref_safe_fork(
"(diff)",
FORK_RESET_SIGNALS|FORK_DEATHSIG_SIGTERM|FORK_CLOSE_ALL_FDS|FORK_RLIMIT_NOFILE_SAFE|FORK_LOG,
&pidref);
if (r < 0)
return r;
if (r == 0) {
@ -175,7 +179,7 @@ static int found_override(const char *top, const char *bottom) {
_exit(EXIT_FAILURE);
}
(void) wait_for_terminate_and_check("diff", pid, WAIT_LOG_ABNORMAL);
(void) pidref_wait_for_terminate_and_check("diff", &pidref, WAIT_LOG_ABNORMAL);
putchar('\n');
return r;

View File

@ -23,6 +23,7 @@
#include "fsck-util.h"
#include "main-func.h"
#include "path-util.h"
#include "pidref.h"
#include "proc-cmdline.h"
#include "process-util.h"
#include "socket-util.h"
@ -267,7 +268,6 @@ static int run(int argc, char *argv[]) {
bool root_directory;
struct stat st;
int r, exit_status;
pid_t pid;
log_setup();
@ -366,7 +366,11 @@ static int run(int argc, char *argv[]) {
pipe(progress_pipe) < 0)
return log_error_errno(errno, "pipe(): %m");
r = safe_fork("(fsck)", FORK_RESET_SIGNALS|FORK_DEATHSIG_SIGTERM|FORK_LOG|FORK_RLIMIT_NOFILE_SAFE, &pid);
_cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
r = pidref_safe_fork(
"(fsck)",
FORK_RESET_SIGNALS|FORK_DEATHSIG_SIGTERM|FORK_LOG|FORK_RLIMIT_NOFILE_SAFE,
&pidref);
if (r < 0)
return r;
if (r == 0) {
@ -424,7 +428,7 @@ static int run(int argc, char *argv[]) {
(void) process_progress(TAKE_FD(progress_pipe[0]), console);
}
exit_status = wait_for_terminate_and_check("fsck", pid, WAIT_LOG_ABNORMAL);
exit_status = pidref_wait_for_terminate_and_check("fsck", &pidref, WAIT_LOG_ABNORMAL);
if (exit_status < 0)
return exit_status;
if ((exit_status & ~FSCK_ERROR_CORRECTED) != FSCK_SUCCESS) {

View File

@ -46,6 +46,7 @@
#include "password-quality-util.h"
#include "path-util.h"
#include "percent-util.h"
#include "pidref.h"
#include "pkcs11-util.h"
#include "polkit-agent.h"
#include "pretty-print.h"
@ -2341,7 +2342,6 @@ static int with_home(int argc, char *argv[], void *userdata) {
_cleanup_strv_free_ char **cmdline = NULL;
const char *home;
int r, ret;
pid_t pid;
r = acquire_bus(&bus);
if (r < 0)
@ -2414,7 +2414,11 @@ static int with_home(int argc, char *argv[], void *userdata) {
if (r < 0)
return bus_log_parse_error(r);
r = safe_fork("(with)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_DEATHSIG_SIGTERM|FORK_LOG|FORK_RLIMIT_NOFILE_SAFE|FORK_REOPEN_LOG, &pid);
_cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
r = pidref_safe_fork(
"(with)",
FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_DEATHSIG_SIGTERM|FORK_LOG|FORK_RLIMIT_NOFILE_SAFE|FORK_REOPEN_LOG,
&pidref);
if (r < 0)
return r;
if (r == 0) {
@ -2428,7 +2432,7 @@ static int with_home(int argc, char *argv[], void *userdata) {
_exit(255);
}
ret = wait_for_terminate_and_check(cmdline[0], pid, WAIT_LOG_ABNORMAL);
ret = pidref_wait_for_terminate_and_check(cmdline[0], &pidref, WAIT_LOG_ABNORMAL);
/* Close the fd that pings the home now. */
acquired_fd = safe_close(acquired_fd);

View File

@ -3299,11 +3299,14 @@ int home_wait_for_worker(Home *h) {
log_info("Worker process for home %s is still running while exiting. Waiting for it to finish.", h->user_name);
r = wait_for_terminate_with_timeout(h->worker_pid.pid, 30 * USEC_PER_SEC);
siginfo_t si;
r = pidref_wait_for_terminate_full(&h->worker_pid, 30 * USEC_PER_SEC, &si);
if (r == -ETIMEDOUT)
log_warning_errno(r, "Waiting for worker process for home %s timed out. Ignoring.", h->user_name);
else if (r < 0)
log_warning_errno(r, "Failed to wait for worker process for home %s. Ignoring.", h->user_name);
log_warning_errno(r, "Failed to wait for worker process for home %s, ignoring: %m", h->user_name);
else if (si.si_code != CLD_EXITED || si.si_status != 0)
log_warning("Worker process for home %s failed with non-zero exit status. Ignoring.", h->user_name);
(void) hashmap_remove_value(h->manager->homes_by_worker_pid, &h->worker_pid, h);
pidref_done(&h->worker_pid);

View File

@ -1157,7 +1157,7 @@ static int manager_listen_notify(Manager *m) {
r = notify_socket_prepare_full(
m->event,
SD_EVENT_PRIORITY_NORMAL - 5, /* Make sure we process sd_notify() before SIGCHLD for
SD_EVENT_PRIORITY_NORMAL - 5, /* Make sure we process sd_notify() before child exit for
* any worker, so that we always know the error number
* of a client before it exits. */
on_notify_socket,

View File

@ -12,7 +12,6 @@
#include "log.h"
#include "main-func.h"
#include "service-util.h"
#include "signal-util.h"
static int run(int argc, char *argv[]) {
_cleanup_(manager_freep) Manager *m = NULL;
@ -32,8 +31,6 @@ static int run(int argc, char *argv[]) {
umask(0022);
assert_se(sigprocmask_many(SIG_BLOCK, /* ret_old_mask= */ NULL, SIGCHLD) >= 0);
r = manager_new(&m);
if (r < 0)
return log_error_errno(r, "Could not create manager: %m");

View File

@ -15,6 +15,7 @@
#include "memfd-util.h"
#include "mount-util.h"
#include "path-util.h"
#include "pidref.h"
#include "process-util.h"
#include "stat-util.h"
#include "string-util.h"
@ -75,14 +76,17 @@ int home_setup_cifs(
STRV_FOREACH(pw, h->password) {
_cleanup_close_ int passwd_fd = -EBADF;
pid_t mount_pid;
int exit_status;
passwd_fd = memfd_new_and_seal_string("cifspw", *pw);
if (passwd_fd < 0)
return log_error_errno(passwd_fd, "Failed to create data FD for password: %m");
r = safe_fork("(mount)", FORK_RESET_SIGNALS|FORK_RLIMIT_NOFILE_SAFE|FORK_DEATHSIG_SIGTERM|FORK_LOG|FORK_STDOUT_TO_STDERR, &mount_pid);
_cleanup_(pidref_done) PidRef mount_pidref = PIDREF_NULL;
r = pidref_safe_fork(
"(mount)",
FORK_RESET_SIGNALS|FORK_RLIMIT_NOFILE_SAFE|FORK_DEATHSIG_SIGTERM|FORK_LOG|FORK_STDOUT_TO_STDERR,
&mount_pidref);
if (r < 0)
return r;
if (r == 0) {
@ -108,7 +112,7 @@ int home_setup_cifs(
_exit(EXIT_FAILURE);
}
exit_status = wait_for_terminate_and_check("mount", mount_pid, WAIT_LOG_ABNORMAL|WAIT_LOG_NON_ZERO_EXIT_STATUS);
exit_status = pidref_wait_for_terminate_and_check("mount", &mount_pidref, WAIT_LOG_ABNORMAL|WAIT_LOG_NON_ZERO_EXIT_STATUS);
if (exit_status < 0)
return exit_status;
if (exit_status == EXIT_SUCCESS) {

View File

@ -7,6 +7,7 @@
#include <sys/ioctl.h>
#include <sys/xattr.h>
#include <unistd.h>
#include "pidref.h"
#if HAVE_VALGRIND_MEMCHECK_H
#include <valgrind/memcheck.h>
#endif
@ -227,7 +228,6 @@ static int block_get_size_by_path(const char *path, uint64_t *ret) {
static int run_fsck(const char *node, const char *fstype) {
int r, exit_status;
pid_t fsck_pid;
assert(node);
assert(fstype);
@ -240,9 +240,11 @@ static int run_fsck(const char *node, const char *fstype) {
return 0;
}
r = safe_fork("(fsck)",
_cleanup_(pidref_done) PidRef fsck_pidref = PIDREF_NULL;
r = pidref_safe_fork(
"(fsck)",
FORK_RESET_SIGNALS|FORK_RLIMIT_NOFILE_SAFE|FORK_DEATHSIG_SIGTERM|FORK_LOG|FORK_STDOUT_TO_STDERR|FORK_CLOSE_ALL_FDS,
&fsck_pid);
&fsck_pidref);
if (r < 0)
return r;
if (r == 0) {
@ -253,7 +255,7 @@ static int run_fsck(const char *node, const char *fstype) {
_exit(FSCK_OPERATIONAL_ERROR);
}
exit_status = wait_for_terminate_and_check("fsck", fsck_pid, WAIT_LOG_ABNORMAL);
exit_status = pidref_wait_for_terminate_and_check("fsck", &fsck_pidref, WAIT_LOG_ABNORMAL);
if (exit_status < 0)
return exit_status;
if ((exit_status & ~FSCK_ERROR_CORRECTED) != 0) {
@ -2604,7 +2606,7 @@ static int ext4_offline_resize_fs(
_cleanup_free_ char *size_str = NULL;
bool re_open = false, re_mount = false;
pid_t resize_pid, fsck_pid;
_cleanup_(pidref_done) PidRef resize_pidref = PIDREF_NULL, fsck_pidref = PIDREF_NULL;
int r, exit_status;
assert(setup);
@ -2627,9 +2629,10 @@ static int ext4_offline_resize_fs(
log_info("Temporary unmounting of file system completed.");
/* resize2fs requires that the file system is force checked first, do so. */
r = safe_fork("(e2fsck)",
r = pidref_safe_fork(
"(e2fsck)",
FORK_RESET_SIGNALS|FORK_RLIMIT_NOFILE_SAFE|FORK_DEATHSIG_SIGTERM|FORK_LOG|FORK_STDOUT_TO_STDERR|FORK_CLOSE_ALL_FDS,
&fsck_pid);
&fsck_pidref);
if (r < 0)
return r;
if (r == 0) {
@ -2640,7 +2643,7 @@ static int ext4_offline_resize_fs(
_exit(EXIT_FAILURE);
}
exit_status = wait_for_terminate_and_check("e2fsck", fsck_pid, WAIT_LOG_ABNORMAL);
exit_status = pidref_wait_for_terminate_and_check("e2fsck", &fsck_pidref, WAIT_LOG_ABNORMAL);
if (exit_status < 0)
return exit_status;
if ((exit_status & ~FSCK_ERROR_CORRECTED) != 0) {
@ -2659,9 +2662,10 @@ static int ext4_offline_resize_fs(
return log_oom();
/* Resize the thing */
r = safe_fork("(e2resize)",
r = pidref_safe_fork(
"(e2resize)",
FORK_RESET_SIGNALS|FORK_RLIMIT_NOFILE_SAFE|FORK_DEATHSIG_SIGTERM|FORK_LOG|FORK_WAIT|FORK_STDOUT_TO_STDERR|FORK_CLOSE_ALL_FDS,
&resize_pid);
&resize_pidref);
if (r < 0)
return r;
if (r == 0) {

View File

@ -409,7 +409,7 @@ static int transfer_on_log(sd_event_source *s, int fd, uint32_t revents, void *u
log_error_errno(errno, "Failed to read log message: %m");
if (l <= 0) {
/* EOF/read error. We just close the pipe here, and
* close the watch, waiting for the SIGCHLD to arrive,
* close the watch, waiting for the child to exit,
* before we do anything else. */
t->log_event_source = sd_event_source_unref(t->log_event_source);
return 0;
@ -600,7 +600,7 @@ static int transfer_start(Transfer *t) {
if (r < 0)
return r;
/* Make sure always process logging before SIGCHLD */
/* Make sure always process logging before child exit */
r = sd_event_source_set_priority(t->log_event_source, SD_EVENT_PRIORITY_NORMAL -5);
if (r < 0)
return r;
@ -724,7 +724,7 @@ static int manager_new(RuntimeScope scope, Manager **ret) {
r = notify_socket_prepare(
m->event,
SD_EVENT_PRIORITY_NORMAL - 1, /* Make this processed before SIGCHLD. */
SD_EVENT_PRIORITY_NORMAL - 1, /* Make this processed before child exit. */
manager_on_notify,
m,
&m->notify_socket_path);
@ -2062,8 +2062,6 @@ static int run(int argc, char *argv[]) {
umask(0022);
assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGCHLD) >= 0);
r = manager_new(scope, &m);
if (r < 0)
return log_error_errno(r, "Failed to allocate manager object: %m");

View File

@ -12,6 +12,7 @@
#include "memory-util.h"
#include "os-util.h"
#include "path-util.h"
#include "pidref.h"
#include "process-util.h"
#include "pull-common.h"
#include "pull-job.h"
@ -404,7 +405,7 @@ static int verify_gpg(
_cleanup_close_pair_ int gpg_pipe[2] = EBADF_PAIR;
_cleanup_(rm_rf_physical_and_freep) char *gpg_home = NULL;
char sig_file_path[] = "/tmp/sigXXXXXX";
_cleanup_(sigkill_waitp) pid_t pid = 0;
_cleanup_(pidref_done_sigkill_wait) PidRef pidref = PIDREF_NULL;
int r;
assert(iovec_is_valid(payload));
@ -434,11 +435,12 @@ static int verify_gpg(
goto finish;
}
r = safe_fork_full("(gpg)",
r = pidref_safe_fork_full(
"(gpg)",
(int[]) { gpg_pipe[0], -EBADF, STDERR_FILENO },
NULL, 0,
/* except_fds= */ NULL, /* n_except_fds= */ 0,
FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_DEATHSIG_SIGTERM|FORK_REARRANGE_STDIO|FORK_LOG|FORK_RLIMIT_NOFILE_SAFE,
&pid);
&pidref);
if (r < 0)
return r;
if (r == 0) {
@ -497,9 +499,10 @@ static int verify_gpg(
gpg_pipe[1] = safe_close(gpg_pipe[1]);
r = wait_for_terminate_and_check("gpg", TAKE_PID(pid), WAIT_LOG_ABNORMAL);
r = pidref_wait_for_terminate_and_check("gpg", &pidref, WAIT_LOG_ABNORMAL);
if (r < 0)
goto finish;
pidref_done(&pidref);
if (r != EXIT_SUCCESS)
r = log_error_errno(SYNTHETIC_ERRNO(EBADMSG),
"DOWNLOAD INVALID: Signature verification failed.");

View File

@ -55,3 +55,11 @@ int __clone2(int (*fn)(void *), void *stack_base, size_t stack_size, int flags,
int missing_sched_setattr(pid_t pid, struct sched_attr *attr, unsigned flags);
# define sched_setattr missing_sched_setattr
#endif
/* f0e1a0643a59bf1f922fa209cec86a170b784f3f (6.12),
* defined in sched.h in glibc since glibc-2.41. */
#ifndef SCHED_EXT
# define SCHED_EXT 7
#else
static_assert(SCHED_EXT == 7, "");
#endif

View File

@ -8,6 +8,7 @@
#include "bus-match.h"
#include "constants.h"
#include "list.h"
#include "pidref.h"
#include "runtime-scope.h"
#include "socket-util.h"
@ -271,7 +272,7 @@ typedef struct sd_bus {
unsigned n_memfd_cache;
uint64_t origin_id;
pid_t busexec_pid;
PidRef busexec_pidref;
unsigned iteration_counter;

View File

@ -1163,7 +1163,7 @@ int bus_socket_exec(sd_bus *b) {
assert(b->input_fd < 0);
assert(b->output_fd < 0);
assert(b->exec_path);
assert(b->busexec_pid == 0);
assert(!pidref_is_set(&b->busexec_pidref));
if (DEBUG_LOGGING) {
_cleanup_free_ char *line = NULL;
@ -1181,10 +1181,12 @@ int bus_socket_exec(sd_bus *b) {
if (r < 0)
return -errno;
r = safe_fork_full("(sd-busexec)",
r = pidref_safe_fork_full(
"(sd-busexec)",
(int[]) { s[1], s[1], STDERR_FILENO },
NULL, 0,
FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_REARRANGE_STDIO|FORK_RLIMIT_NOFILE_SAFE, &b->busexec_pid);
FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_REARRANGE_STDIO|FORK_RLIMIT_NOFILE_SAFE,
&b->busexec_pidref);
if (r < 0) {
safe_close_pair(s);
return r;

View File

@ -41,7 +41,6 @@
#include "parse-util.h"
#include "path-util.h"
#include "prioq.h"
#include "process-util.h"
#include "set.h"
#include "string-util.h"
#include "strv.h"
@ -262,6 +261,7 @@ _public_ int sd_bus_new(sd_bus **ret) {
.creds_mask = SD_BUS_CREDS_WELL_KNOWN_NAMES|SD_BUS_CREDS_UNIQUE_NAME,
.accept_fd = true,
.origin_id = origin_id_query(),
.busexec_pidref = PIDREF_NULL,
.n_groups = SIZE_MAX,
.close_on_exit = true,
.ucred = UCRED_INVALID,
@ -1121,13 +1121,6 @@ static int bus_parse_next_address(sd_bus *b) {
return 1;
}
static void bus_kill_exec(sd_bus *bus) {
if (!pid_is_valid(bus->busexec_pid))
return;
sigterm_wait(TAKE_PID(bus->busexec_pid));
}
static int bus_start_address(sd_bus *b) {
int r;
@ -1136,7 +1129,7 @@ static int bus_start_address(sd_bus *b) {
for (;;) {
bus_close_fds(b);
bus_kill_exec(b);
pidref_done_sigterm_wait(&b->busexec_pidref);
/* If you provide multiple different bus-addresses, we
* try all of them in order and use the first one that
@ -1778,7 +1771,7 @@ _public_ void sd_bus_close(sd_bus *bus) {
return;
/* Don't leave ssh hanging around */
bus_kill_exec(bus);
pidref_done_sigterm_wait(&bus->busexec_pidref);
bus_set_state(bus, BUS_CLOSED);
@ -1809,7 +1802,7 @@ _public_ sd_bus* sd_bus_flush_close_unref(sd_bus *bus) {
return NULL;
/* Have to do this before flush() to prevent hang */
bus_kill_exec(bus);
pidref_done_sigterm_wait(&bus->busexec_pidref);
sd_bus_flush(bus);
return sd_bus_close_unref(bus);

View File

@ -1570,6 +1570,33 @@ static int child_exit_callback(sd_event_source *s, const siginfo_t *si, void *us
return sd_event_exit(sd_event_source_get_event(s), PTR_TO_INT(userdata));
}
static int verify_sigchld(int options) {
int r;
if ((options & (WSTOPPED|WCONTINUED)) != 0) {
/* Caller must block SIGCHLD before using us to watch for WSTOPPED or WCONTINUED. */
r = signal_is_blocked(SIGCHLD);
if (r < 0)
return r;
if (r == 0)
return -EBUSY;
}
/* We don't want the Linux autoreaping logic to take effect when we're watching for process exit, so
* check if it is enabled. */
if (options & WEXITED) {
r = autoreaping_enabled();
if (r < 0)
return r;
if (r > 0)
return -EBUSY;
}
return 0;
}
_public_ int sd_event_add_child(
sd_event *e,
sd_event_source **ret,
@ -1592,18 +1619,11 @@ _public_ int sd_event_add_child(
if (!callback)
callback = child_exit_callback;
/* As an optimization we only do these checks on the first child event source created. */
if (e->n_online_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);
r = verify_sigchld(options);
if (r < 0)
return r;
if (r == 0)
return -EBUSY;
}
r = hashmap_ensure_allocated(&e->child_sources, NULL);
@ -1617,8 +1637,8 @@ _public_ int sd_event_add_child(
if (!s)
return -ENOMEM;
/* We always take a pidfd here if we can, even if we wait for anything else than WEXITED, so that we
* pin the PID, and make regular waitid() handling race-free. */
/* We always take a pidfd here, even if we wait for anything else than WEXITED, so that we pin the
* PID, and make regular waitid() handling race-free. */
s->child.pidfd = pidfd_open(pid, 0);
if (s->child.pidfd < 0)
@ -1685,11 +1705,9 @@ _public_ int sd_event_add_child_pidfd(
callback = child_exit_callback;
if (e->n_online_child_sources == 0) {
r = signal_is_blocked(SIGCHLD);
r = verify_sigchld(options);
if (r < 0)
return r;
if (r == 0)
return -EBUSY;
}
r = hashmap_ensure_allocated(&e->child_sources, NULL);

View File

@ -6,12 +6,14 @@
#include "sd-event.h"
#include "alloc-util.h"
#include "event-util.h"
#include "fd-util.h"
#include "fs-util.h"
#include "log.h"
#include "parse-util.h"
#include "path-util.h"
#include "pidfd-util.h"
#include "pidref.h"
#include "process-util.h"
#include "random-util.h"
#include "rm-rf.h"
@ -91,7 +93,7 @@ static int signal_handler(sd_event_source *s, const struct signalfd_siginfo *si,
ASSERT_PTR_EQ(userdata, INT_TO_PTR('e'));
ASSERT_OK(sigprocmask_many(SIG_BLOCK, NULL, SIGCHLD, SIGUSR2));
ASSERT_OK(sigprocmask_many(SIG_BLOCK, NULL, SIGUSR2));
ASSERT_OK_ERRNO(pid = fork());
@ -566,8 +568,6 @@ TEST(pidfd) {
int pidfd;
pid_t pid, pid2;
ASSERT_OK(sigprocmask_many(SIG_BLOCK, NULL, SIGCHLD));
ASSERT_OK_ERRNO(pid = fork());
if (pid == 0)
/* child */
@ -999,8 +999,6 @@ static int child_handler_wnowait(sd_event_source *s, const siginfo_t *si, void *
TEST(child_wnowait) {
_cleanup_(sd_event_unrefp) sd_event *e = NULL;
ASSERT_OK(sigprocmask_many(SIG_BLOCK, NULL, SIGCHLD));
ASSERT_OK(sd_event_default(&e));
/* Fork a subprocess */
@ -1032,8 +1030,6 @@ TEST(child_wnowait) {
TEST(child_pidfd_wnowait) {
_cleanup_(sd_event_unrefp) sd_event *e = NULL;
ASSERT_OK(sigprocmask_many(SIG_BLOCK, NULL, SIGCHLD));
ASSERT_OK(sd_event_default(&e));
/* Fork a subprocess */
@ -1167,4 +1163,31 @@ TEST(defer_fair_scheduling) {
}
}
TEST(child_autoreap_ebusy) {
_cleanup_(sd_event_unrefp) sd_event *e = NULL;
_cleanup_(sd_event_source_unrefp) sd_event_source *s = NULL;
_cleanup_(pidref_done_sigkill_wait) PidRef pidref = PIDREF_NULL;
/* Test that sd_event_add_child() fails with EBUSY when kernel autoreaping is enabled
* by setting SIGCHLD disposition to SIG_IGN */
ASSERT_OK(sd_event_new(&e));
/* First, verify that adding a child source works with default signal disposition */
ASSERT_OK_POSITIVE(pidref_safe_fork("(child-autoreaping-ebusy)", FORK_DEATHSIG_SIGKILL|FORK_FREEZE, &pidref));
ASSERT_OK(event_add_child_pidref(e, &s, &pidref, WEXITED, NULL, NULL));
s = sd_event_source_unref(s);
/* Now set SIGCHLD to SIG_IGN to enable kernel autoreaping */
struct sigaction old_sa, new_sa = {};
new_sa.sa_handler = SIG_IGN;
ASSERT_OK_ERRNO(sigaction(SIGCHLD, &new_sa, &old_sa));
ASSERT_ERROR(event_add_child_pidref(e, &s, &pidref, WEXITED, NULL, NULL), EBUSY);
/* Restore original SIGCHLD disposition */
ASSERT_OK_ERRNO(sigaction(SIGCHLD, &old_sa, NULL));
}
DEFINE_TEST_MAIN(LOG_DEBUG);

View File

@ -26,6 +26,7 @@
#include "mkdir.h"
#include "path-util.h"
#include "pidfd-util.h"
#include "pidref.h"
#include "process-util.h"
#include "socket-util.h"
#include "string-table.h"
@ -149,6 +150,8 @@ static int varlink_new(sd_varlink **ret) {
.allow_fd_passing_input = -1,
.af = -1,
.exec_pidref = PIDREF_NULL,
};
*ret = v;
@ -209,7 +212,7 @@ _public_ int sd_varlink_connect_address(sd_varlink **ret, const char *address) {
_public_ int sd_varlink_connect_exec(sd_varlink **ret, const char *_command, char **_argv) {
_cleanup_close_pair_ int pair[2] = EBADF_PAIR;
_cleanup_(sigkill_waitp) pid_t pid = 0;
_cleanup_(pidref_done_sigkill_wait) PidRef pidref = PIDREF_NULL;
_cleanup_free_ char *command = NULL;
_cleanup_strv_free_ char **argv = NULL;
int r;
@ -239,13 +242,13 @@ _public_ int sd_varlink_connect_exec(sd_varlink **ret, const char *_command, cha
if (r < 0)
return log_debug_errno(r, "Failed to disable O_NONBLOCK for varlink socket: %m");
r = safe_fork_full(
r = pidref_safe_fork_full(
"(sd-vlexec)",
/* stdio_fds= */ NULL,
/* except_fds= */ (int[]) { pair[1] },
/* n_except_fds= */ 1,
FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_DEATHSIG_SIGTERM|FORK_REOPEN_LOG|FORK_LOG|FORK_RLIMIT_NOFILE_SAFE,
&pid);
&pidref);
if (r < 0)
return log_debug_errno(r, "Failed to spawn process: %m");
if (r == 0) {
@ -266,7 +269,7 @@ _public_ int sd_varlink_connect_exec(sd_varlink **ret, const char *_command, cha
_exit(EXIT_FAILURE);
}
xsprintf(spid, PID_FMT, pid);
xsprintf(spid, PID_FMT, pidref.pid);
uint64_t pidfdid;
if (pidfd_get_inode_id_self_cached(&pidfdid) >= 0) {
@ -298,7 +301,7 @@ _public_ int sd_varlink_connect_exec(sd_varlink **ret, const char *_command, cha
v->output_fd = v->input_fd = TAKE_FD(pair[0]);
v->af = AF_UNIX;
v->exec_pid = TAKE_PID(pid);
v->exec_pidref = TAKE_PIDREF(pidref);
varlink_set_state(v, VARLINK_IDLE_CLIENT);
*ret = v;
@ -318,7 +321,7 @@ static int ssh_path(const char **ret) {
static int varlink_connect_ssh_unix(sd_varlink **ret, const char *where) {
_cleanup_close_pair_ int pair[2] = EBADF_PAIR;
_cleanup_(sigkill_waitp) pid_t pid = 0;
_cleanup_(pidref_done_sigkill_wait) PidRef pidref = PIDREF_NULL;
int r;
assert_return(ret, -EINVAL);
@ -356,13 +359,13 @@ static int varlink_connect_ssh_unix(sd_varlink **ret, const char *where) {
if (socketpair(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0, pair) < 0)
return log_debug_errno(errno, "Failed to allocate AF_UNIX socket pair: %m");
r = safe_fork_full(
r = pidref_safe_fork_full(
"(sd-vlssh)",
/* stdio_fds= */ (int[]) { pair[1], pair[1], STDERR_FILENO },
/* except_fds= */ NULL,
/* n_except_fds= */ 0,
FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_DEATHSIG_SIGTERM|FORK_REOPEN_LOG|FORK_LOG|FORK_RLIMIT_NOFILE_SAFE|FORK_REARRANGE_STDIO,
&pid);
&pidref);
if (r < 0)
return log_debug_errno(r, "Failed to spawn process: %m");
if (r == 0) {
@ -382,7 +385,7 @@ static int varlink_connect_ssh_unix(sd_varlink **ret, const char *where) {
v->output_fd = v->input_fd = TAKE_FD(pair[0]);
v->af = AF_UNIX;
v->exec_pid = TAKE_PID(pid);
v->exec_pidref = TAKE_PIDREF(pidref);
varlink_set_state(v, VARLINK_IDLE_CLIENT);
*ret = v;
@ -391,7 +394,7 @@ static int varlink_connect_ssh_unix(sd_varlink **ret, const char *where) {
static int varlink_connect_ssh_exec(sd_varlink **ret, const char *where) {
_cleanup_close_pair_ int input_pipe[2] = EBADF_PAIR, output_pipe[2] = EBADF_PAIR;
_cleanup_(sigkill_waitp) pid_t pid = 0;
_cleanup_(pidref_done_sigkill_wait) PidRef pidref = PIDREF_NULL;
int r;
assert_return(ret, -EINVAL);
@ -440,13 +443,13 @@ static int varlink_connect_ssh_exec(sd_varlink **ret, const char *where) {
if (pipe2(output_pipe, O_CLOEXEC) < 0)
return log_debug_errno(errno, "Failed to allocate output pipe: %m");
r = safe_fork_full(
r = pidref_safe_fork_full(
"(sd-vlssh)",
/* stdio_fds= */ (int[]) { input_pipe[0], output_pipe[1], STDERR_FILENO },
/* except_fds= */ NULL,
/* n_except_fds= */ 0,
FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_DEATHSIG_SIGTERM|FORK_REOPEN_LOG|FORK_LOG|FORK_RLIMIT_NOFILE_SAFE|FORK_REARRANGE_STDIO,
&pid);
&pidref);
if (r < 0)
return log_debug_errno(r, "Failed to spawn process: %m");
if (r == 0) {
@ -475,7 +478,7 @@ static int varlink_connect_ssh_exec(sd_varlink **ret, const char *where) {
v->input_fd = TAKE_FD(output_pipe[0]);
v->output_fd = TAKE_FD(input_pipe[1]);
v->af = AF_UNSPEC;
v->exec_pid = TAKE_PID(pid);
v->exec_pidref = TAKE_PIDREF(pidref);
varlink_set_state(v, VARLINK_IDLE_CLIENT);
*ret = v;
@ -648,10 +651,7 @@ static void varlink_clear(sd_varlink *v) {
v->event = sd_event_unref(v->event);
if (v->exec_pid > 0) {
sigterm_wait(v->exec_pid);
v->exec_pid = 0;
}
pidref_done_sigterm_wait(&v->exec_pidref);
v->peer_pidfd = safe_close(v->peer_pidfd);
}

View File

@ -6,6 +6,7 @@
#include "sd-varlink.h"
#include "list.h"
#include "pidref.h"
#include "sd-forward.h"
typedef enum VarlinkState {
@ -187,7 +188,7 @@ struct sd_varlink {
sd_event_source *quit_event_source;
sd_event_source *defer_event_source;
pid_t exec_pid;
PidRef exec_pidref;
};
typedef struct VarlinkServerSocket VarlinkServerSocket;

View File

@ -20,6 +20,7 @@
#include "main-func.h"
#include "pager.h"
#include "parse-argument.h"
#include "pidref.h"
#include "polkit-agent.h"
#include "pretty-print.h"
#include "process-util.h"
@ -330,7 +331,6 @@ static int run(int argc, char *argv[]) {
_cleanup_strv_free_ char **arguments = NULL;
_cleanup_free_ char *w = NULL;
_cleanup_close_ int fd = -EBADF;
pid_t pid;
/* Ignore SIGINT and allow the forked process to receive it */
(void) ignore_signals(SIGINT);
@ -360,7 +360,8 @@ static int run(int argc, char *argv[]) {
if (!arguments)
return log_oom();
r = safe_fork("(inhibit)", FORK_RESET_SIGNALS|FORK_DEATHSIG_SIGTERM|FORK_CLOSE_ALL_FDS|FORK_RLIMIT_NOFILE_SAFE|FORK_LOG, &pid);
_cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
r = pidref_safe_fork("(inhibit)", FORK_RESET_SIGNALS|FORK_DEATHSIG_SIGTERM|FORK_CLOSE_ALL_FDS|FORK_RLIMIT_NOFILE_SAFE|FORK_LOG, &pidref);
if (r < 0)
return r;
if (r == 0) {
@ -371,7 +372,7 @@ static int run(int argc, char *argv[]) {
_exit(EXIT_FAILURE);
}
return wait_for_terminate_and_check(argv[optind], pid, WAIT_LOG);
return pidref_wait_for_terminate_and_check(argv[optind], &pidref, WAIT_LOG);
}
}

View File

@ -1372,8 +1372,6 @@ static int run(int argc, char *argv[]) {
(void) mkdir_label("/run/systemd/users", 0755);
(void) mkdir_label("/run/systemd/sessions", 0755);
assert_se(sigprocmask_many(SIG_BLOCK, /* ret_old_mask= */ NULL, SIGCHLD) >= 0);
r = manager_new(&m);
if (r < 0)
return log_error_errno(r, "Failed to allocate manager object: %m");

View File

@ -32,7 +32,7 @@ int bus_image_method_remove(
_cleanup_close_pair_ int errno_pipe_fd[2] = EBADF_PAIR;
Image *image = ASSERT_PTR(userdata);
Manager *m = image->userdata;
pid_t child;
_cleanup_(pidref_done_sigkill_wait) PidRef child = PIDREF_NULL;
int r;
assert(message);
@ -62,7 +62,7 @@ int bus_image_method_remove(
if (pipe2(errno_pipe_fd, O_CLOEXEC|O_NONBLOCK) < 0)
return sd_bus_error_set_errnof(error, errno, "Failed to create pipe: %m");
r = safe_fork("(sd-imgrm)", FORK_RESET_SIGNALS, &child);
r = pidref_safe_fork("(sd-imgrm)", FORK_RESET_SIGNALS, &child);
if (r < 0)
return sd_bus_error_set_errnof(error, r, "Failed to fork(): %m");
if (r == 0) {
@ -73,11 +73,11 @@ int bus_image_method_remove(
errno_pipe_fd[1] = safe_close(errno_pipe_fd[1]);
r = operation_new_with_bus_reply(m, /* machine= */ NULL, child, message, errno_pipe_fd[0], /* ret= */ NULL);
if (r < 0) {
sigkill_wait(child);
r = operation_new_with_bus_reply(m, /* machine= */ NULL, &child, message, errno_pipe_fd[0], /* ret= */ NULL);
if (r < 0)
return r;
}
TAKE_PIDREF(child);
errno_pipe_fd[0] = -EBADF;
@ -140,7 +140,7 @@ int bus_image_method_clone(
Manager *m = ASSERT_PTR(image->userdata);
const char *new_name;
int r, read_only;
pid_t child;
_cleanup_(pidref_done_sigkill_wait) PidRef child = PIDREF_NULL;
assert(message);
@ -177,7 +177,7 @@ int bus_image_method_clone(
if (pipe2(errno_pipe_fd, O_CLOEXEC|O_NONBLOCK) < 0)
return sd_bus_error_set_errnof(error, errno, "Failed to create pipe: %m");
r = safe_fork("(sd-imgclone)", FORK_RESET_SIGNALS, &child);
r = pidref_safe_fork("(sd-imgclone)", FORK_RESET_SIGNALS, &child);
if (r < 0)
return sd_bus_error_set_errnof(error, r, "Failed to fork(): %m");
if (r == 0) {
@ -188,11 +188,11 @@ int bus_image_method_clone(
errno_pipe_fd[1] = safe_close(errno_pipe_fd[1]);
r = operation_new_with_bus_reply(m, /* machine= */ NULL, child, message, errno_pipe_fd[0], /* ret= */ NULL);
if (r < 0) {
sigkill_wait(child);
r = operation_new_with_bus_reply(m, /* machine= */ NULL, &child, message, errno_pipe_fd[0], /* ret= */ NULL);
if (r < 0)
return r;
}
TAKE_PIDREF(child);
errno_pipe_fd[0] = -EBADF;

View File

@ -115,7 +115,7 @@ int vl_method_clone_image(sd_varlink *link, sd_json_variant *parameters, sd_varl
_cleanup_close_pair_ int errno_pipe_fd[2] = EBADF_PAIR;
ImageUpdateParameters p = IMAGE_UPDATE_PARAMETERS_NULL;
Image *image;
pid_t child;
_cleanup_(pidref_done_sigkill_wait) PidRef child = PIDREF_NULL;
int r;
assert(link);
@ -156,7 +156,7 @@ int vl_method_clone_image(sd_varlink *link, sd_json_variant *parameters, sd_varl
if (pipe2(errno_pipe_fd, O_CLOEXEC|O_NONBLOCK) < 0)
return log_debug_errno(errno, "Failed to open pipe: %m");
r = safe_fork("(sd-imgclone)", FORK_RESET_SIGNALS, &child);
r = pidref_safe_fork("(sd-imgclone)", FORK_RESET_SIGNALS, &child);
if (r < 0)
return log_debug_errno(r, "Failed to fork: %m");
if (r == 0) {
@ -167,12 +167,11 @@ int vl_method_clone_image(sd_varlink *link, sd_json_variant *parameters, sd_varl
errno_pipe_fd[1] = safe_close(errno_pipe_fd[1]);
r = operation_new_with_varlink_reply(manager, /* machine= */ NULL, child, link, errno_pipe_fd[0], /* ret= */ NULL);
if (r < 0) {
sigkill_wait(child);
r = operation_new_with_varlink_reply(manager, /* machine= */ NULL, &child, link, errno_pipe_fd[0], /* ret= */ NULL);
if (r < 0)
return r;
}
TAKE_PIDREF(child);
TAKE_FD(errno_pipe_fd[0]);
return 1;
}
@ -188,7 +187,7 @@ int vl_method_remove_image(sd_varlink *link, sd_json_variant *parameters, sd_var
_cleanup_close_pair_ int errno_pipe_fd[2] = EBADF_PAIR;
const char *image_name;
Image *image;
pid_t child;
_cleanup_(pidref_done_sigkill_wait) PidRef child = PIDREF_NULL;
int r;
assert(link);
@ -225,7 +224,7 @@ int vl_method_remove_image(sd_varlink *link, sd_json_variant *parameters, sd_var
if (pipe2(errno_pipe_fd, O_CLOEXEC|O_NONBLOCK) < 0)
return log_debug_errno(errno, "Failed to open pipe: %m");
r = safe_fork("(sd-imgrm)", FORK_RESET_SIGNALS, &child);
r = pidref_safe_fork("(sd-imgrm)", FORK_RESET_SIGNALS, &child);
if (r < 0)
return log_debug_errno(r, "Failed to fork: %m");
if (r == 0) {
@ -236,12 +235,11 @@ int vl_method_remove_image(sd_varlink *link, sd_json_variant *parameters, sd_var
errno_pipe_fd[1] = safe_close(errno_pipe_fd[1]);
r = operation_new_with_varlink_reply(manager, /* machine= */ NULL, child, link, errno_pipe_fd[0], /* ret= */ NULL);
if (r < 0) {
sigkill_wait(child);
r = operation_new_with_varlink_reply(manager, /* machine= */ NULL, &child, link, errno_pipe_fd[0], /* ret= */ NULL);
if (r < 0)
return r;
}
TAKE_PIDREF(child);
TAKE_FD(errno_pipe_fd[0]);
return 1;
}

View File

@ -96,7 +96,7 @@ int clean_pool_read_next_entry(FILE *file, char **ret_name, uint64_t *ret_usage)
int image_clean_pool_operation(Manager *manager, ImageCleanPoolMode mode, Operation **ret_operation) {
_cleanup_close_pair_ int errno_pipe_fd[2] = EBADF_PAIR;
_cleanup_close_ int result_fd = -EBADF;
_cleanup_(sigkill_waitp) pid_t child = 0;
_cleanup_(pidref_done_sigkill_wait) PidRef child = PIDREF_NULL;
int r;
assert(manager);
@ -113,7 +113,7 @@ int image_clean_pool_operation(Manager *manager, ImageCleanPoolMode mode, Operat
return log_debug_errno(result_fd, "Failed to open tmpfile: %m");
/* This might be a slow operation, run it asynchronously in a background process */
r = safe_fork("(sd-clean)", FORK_RESET_SIGNALS, &child);
r = pidref_safe_fork("(sd-clean)", FORK_RESET_SIGNALS, &child);
if (r < 0)
return log_debug_errno(r, "Failed to fork(): %m");
if (r == 0) {
@ -183,13 +183,13 @@ int image_clean_pool_operation(Manager *manager, ImageCleanPoolMode mode, Operat
errno_pipe_fd[1] = safe_close(errno_pipe_fd[1]);
/* The clean-up might take a while, hence install a watch on the child and return */
r = operation_new(manager, /* machine= */ NULL, child, errno_pipe_fd[0], ret_operation);
r = operation_new(manager, /* machine= */ NULL, &child, errno_pipe_fd[0], ret_operation);
if (r < 0)
return r;
(*ret_operation)->extra_fd = TAKE_FD(result_fd);
TAKE_FD(errno_pipe_fd[0]);
TAKE_PID(child);
TAKE_PIDREF(child);
return 0;
}

View File

@ -1244,7 +1244,7 @@ int machine_copy_from_to_operation(
// TODO: port to PidRef and donate child rather than destroying it
Operation *operation;
r = operation_new(manager, machine, child.pid, errno_pipe_fd[0], &operation);
r = operation_new(manager, machine, &child, errno_pipe_fd[0], &operation);
if (r < 0)
return r;

View File

@ -366,8 +366,6 @@ static int run(int argc, char *argv[]) {
if (scope == RUNTIME_SCOPE_SYSTEM)
(void) mkdir_label("/run/systemd/machines", 0755);
assert_se(sigprocmask_many(SIG_BLOCK, /* ret_old_mask= */ NULL, SIGCHLD) >= 0);
r = manager_new(scope, &m);
if (r < 0)
return log_error_errno(r, "Failed to allocate manager object: %m");

View File

@ -8,6 +8,7 @@
#include "sd-varlink.h"
#include "alloc-util.h"
#include "event-util.h"
#include "fd-util.h"
#include "format-util.h"
#include "log.h"
@ -45,10 +46,10 @@ static int operation_done(sd_event_source *s, const siginfo_t *si, void *userdat
assert(si);
log_debug("Operation " PID_FMT " is now complete with code=%s status=%i",
o->pid,
o->pidref.pid,
sigchld_code_to_string(si->si_code), si->si_status);
o->pid = 0;
pidref_done(&o->pidref);
r = read_operation_errno(si, o);
if (r < 0)
@ -96,12 +97,12 @@ static int operation_done(sd_event_source *s, const siginfo_t *si, void *userdat
return 0;
}
int operation_new(Manager *manager, Machine *machine, pid_t child, int errno_fd, Operation **ret) {
int operation_new(Manager *manager, Machine *machine, PidRef *child, int errno_fd, Operation **ret) {
Operation *o;
int r;
assert(manager);
assert(child > 1);
assert(pidref_is_set(child));
assert(errno_fd >= 0);
assert(ret);
@ -110,12 +111,12 @@ int operation_new(Manager *manager, Machine *machine, pid_t child, int errno_fd,
return -ENOMEM;
*o = (Operation) {
.pid = child,
.pidref = TAKE_PIDREF(*child),
.errno_fd = errno_fd,
.extra_fd = -EBADF
};
r = sd_event_add_child(manager->event, &o->event_source, child, WEXITED, operation_done, o);
r = event_add_child_pidref(manager->event, &o->event_source, &o->pidref, WEXITED, operation_done, o);
if (r < 0) {
free(o);
return r;
@ -130,7 +131,7 @@ int operation_new(Manager *manager, Machine *machine, pid_t child, int errno_fd,
o->machine = machine;
}
log_debug("Started new operation " PID_FMT ".", child);
log_debug("Started new operation " PID_FMT ".", o->pidref.pid);
/* At this point we took ownership of both the child and the errno file descriptor! */
@ -147,8 +148,7 @@ Operation *operation_free(Operation *o) {
safe_close(o->errno_fd);
safe_close(o->extra_fd);
if (o->pid > 1)
sigkill_wait(o->pid);
pidref_done_sigkill_wait(&o->pidref);
sd_bus_message_unref(o->message);
sd_varlink_unref(o->link);

View File

@ -3,13 +3,14 @@
#include "list.h"
#include "machine-forward.h"
#include "pidref.h"
#define OPERATIONS_MAX 64
typedef struct Operation {
Manager *manager;
Machine *machine;
pid_t pid;
PidRef pidref;
/* only one of these two fields should be set */
sd_varlink *link;
@ -23,7 +24,7 @@ typedef struct Operation {
LIST_FIELDS(Operation, operations_by_machine);
} Operation;
int operation_new(Manager *manager, Machine *machine, pid_t child, int errno_fd, Operation **ret);
int operation_new(Manager *manager, Machine *machine, PidRef *child, int errno_fd, Operation **ret);
Operation *operation_free(Operation *o);
void operation_attach_bus_reply(Operation *op, sd_bus_message *message);
@ -32,7 +33,7 @@ void operation_attach_varlink_reply(Operation *op, sd_varlink *link);
static inline int operation_new_with_bus_reply(
Manager *manager,
Machine *machine,
pid_t child,
PidRef *child,
sd_bus_message *message,
int errno_fd,
Operation **ret) {
@ -55,7 +56,7 @@ static inline int operation_new_with_bus_reply(
static inline int operation_new_with_varlink_reply(
Manager *manager,
Machine *machine,
pid_t child,
PidRef *child,
sd_varlink *link,
int errno_fd,
Operation **ret) {

View File

@ -51,7 +51,7 @@ static int on_worker_exit(sd_event_source *s, const siginfo_t *si, void *userdat
else if (si->si_code == CLD_DUMPED)
log_warning("Worker " PID_FMT " dumped core by signal %s, ignoring.", si->si_pid, signal_to_string(si->si_status));
else
log_warning("Got unexpected exit code via SIGCHLD, ignoring.");
log_warning("Got unexpected exit code from child, ignoring.");
(void) start_workers(m, /* explicit_request= */ false); /* Fill up workers again if we fell below the low watermark */
return 0;

View File

@ -8,7 +8,6 @@
#include "log.h"
#include "main-func.h"
#include "mountfsd-manager.h"
#include "signal-util.h"
static int run(int argc, char *argv[]) {
_unused_ _cleanup_(notify_on_cleanup) const char *notify_stop = NULL;
@ -22,8 +21,6 @@ static int run(int argc, char *argv[]) {
if (argc != 1)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "This program takes no arguments.");
assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGCHLD) >= 0);
r = manager_new(&m);
if (r < 0)
return log_error_errno(r, "Could not create manager: %m");

View File

@ -506,9 +506,10 @@ static int action_fork(char *const *_command) {
_cleanup_free_ char *addr_string = NULL;
r = notify_socket_prepare(
event,
SD_EVENT_PRIORITY_NORMAL - 10, /* If we receive both the sd_notify() message and a
* SIGCHLD always process sd_notify() first, it's the
* more interesting, "positive" information. */
SD_EVENT_PRIORITY_NORMAL - 10, /* If we receive both the sd_notify() message and
* child exit notification, always process sd_notify()
* first, it's the more interesting, "positive"
* information. */
on_notify_socket,
&child,
&addr_string);
@ -541,14 +542,12 @@ static int action_fork(char *const *_command) {
fflush(stdout);
}
BLOCK_SIGNALS(SIGCHLD);
_cleanup_(sd_event_source_disable_unrefp) sd_event_source *child_event_source = NULL;
r = event_add_child_pidref(event, &child_event_source, &child, WEXITED, on_child, /* userdata= */ NULL);
if (r < 0)
return log_error_errno(r, "Failed to allocate child source: %m");
/* Handle SIGCHLD before propagating the other signals below */
/* Handle child exit before propagating the other signals below */
r = sd_event_source_set_priority(child_event_source, SD_EVENT_PRIORITY_NORMAL - 5);
if (r < 0)
return log_error_errno(r, "Failed to change child event source priority: %m");

View File

@ -11,26 +11,28 @@
#include "log.h"
#include "mkdir.h"
#include "nspawn-setuid.h"
#include "pidref.h"
#include "process-util.h"
#include "string-util.h"
#include "strv.h"
#include "user-util.h"
static int spawn_getent(const char *database, const char *key, pid_t *rpid) {
static int spawn_getent(const char *database, const char *key, PidRef *ret) {
int pipe_fds[2], r;
pid_t pid;
assert(database);
assert(key);
assert(rpid);
assert(ret);
if (pipe2(pipe_fds, O_CLOEXEC) < 0)
return log_error_errno(errno, "Failed to allocate pipe: %m");
r = safe_fork_full("(getent)",
_cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
r = pidref_safe_fork_full(
"(getent)",
(int[]) { -EBADF, pipe_fds[1], -EBADF }, NULL, 0,
FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_DEATHSIG_SIGTERM|FORK_REARRANGE_STDIO|FORK_LOG|FORK_RLIMIT_NOFILE_SAFE,
&pid);
&pidref);
if (r < 0) {
safe_close_pair(pipe_fds);
return r;
@ -43,7 +45,7 @@ static int spawn_getent(const char *database, const char *key, pid_t *rpid) {
pipe_fds[1] = safe_close(pipe_fds[1]);
*rpid = pid;
*ret = TAKE_PIDREF(pidref);
return pipe_fds[0];
}
@ -84,7 +86,6 @@ int change_uid_gid(const char *user, bool chown_stdio, char **ret_home) {
unsigned n_gids = 0;
uid_t uid;
gid_t gid;
pid_t pid;
int r;
assert(ret_home);
@ -101,7 +102,8 @@ int change_uid_gid(const char *user, bool chown_stdio, char **ret_home) {
}
/* First, get user credentials */
fd = spawn_getent("passwd", user, &pid);
_cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
fd = spawn_getent("passwd", user, &pidref);
if (fd < 0)
return fd;
@ -116,7 +118,7 @@ int change_uid_gid(const char *user, bool chown_stdio, char **ret_home) {
if (r < 0)
return log_error_errno(r, "Failed to read from getent: %m");
(void) wait_for_terminate_and_check("getent passwd", pid, WAIT_LOG);
(void) pidref_wait_for_terminate_and_check("getent passwd", &pidref, WAIT_LOG);
x = strchr(line, ':');
if (!x)
@ -173,7 +175,8 @@ int change_uid_gid(const char *user, bool chown_stdio, char **ret_home) {
line = mfree(line);
/* Second, get group memberships */
fd = spawn_getent("initgroups", user, &pid);
pidref_done(&pidref);
fd = spawn_getent("initgroups", user, &pidref);
if (fd < 0)
return fd;
@ -188,7 +191,7 @@ int change_uid_gid(const char *user, bool chown_stdio, char **ret_home) {
if (r < 0)
return log_error_errno(r, "Failed to read from getent: %m");
(void) wait_for_terminate_and_check("getent initgroups", pid, WAIT_LOG);
(void) pidref_wait_for_terminate_and_check("getent initgroups", &pidref, WAIT_LOG);
/* Skip over the username and subsequent separator whitespace */
x = line;

View File

@ -2884,7 +2884,7 @@ static int recursive_chown(const char *directory, uid_t shift, uid_t range) {
/*
* Return values:
* < 0 : wait_for_terminate() failed to get the state of the
* < 0 : pidref_wait_for_terminate() failed to get the state of the
* container, the container was terminated by a signal, or
* failed for an unknown reason. No change is made to the
* container argument.

View File

@ -58,7 +58,7 @@ static int on_worker_exit(sd_event_source *s, const siginfo_t *si, void *userdat
else if (si->si_code == CLD_DUMPED)
log_warning("Worker " PID_FMT " dumped core by signal %s, ignoring.", si->si_pid, signal_to_string(si->si_status));
else
log_warning("Got unexpected exit code via SIGCHLD, ignoring.");
log_warning("Got unexpected exit code from child, ignoring.");
(void) start_workers(m, /* explicit_request= */ false); /* Fill up workers again if we fell below the low watermark */
return 0;

View File

@ -9,7 +9,6 @@
#include "log.h"
#include "main-func.h"
#include "nsresourced-manager.h"
#include "signal-util.h"
static int run(int argc, char *argv[]) {
_cleanup_(manager_freep) Manager *m = NULL;
@ -25,8 +24,6 @@ static int run(int argc, char *argv[]) {
if (setenv("SYSTEMD_BYPASS_USERDB", "io.systemd.NamespaceResource", 1) < 0)
return log_error_errno(errno, "Failed to set $SYSTEMD_BYPASS_USERDB: %m");
assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGCHLD) >= 0);
r = manager_new(&m);
if (r < 0)
return log_error_errno(r, "Could not create manager: %m");

View File

@ -541,7 +541,7 @@ static int allocate_now(
}
static int write_userns(int usernsfd, const UserNamespaceInfo *userns_info) {
_cleanup_(sigkill_waitp) pid_t pid = 0;
_cleanup_(pidref_done_sigkill_wait) PidRef pidref = PIDREF_NULL;
_cleanup_close_ int efd = -EBADF;
uint64_t u;
int r;
@ -560,7 +560,7 @@ static int write_userns(int usernsfd, const UserNamespaceInfo *userns_info) {
if (efd < 0)
return log_error_errno(errno, "Failed to allocate eventfd(): %m");
r = safe_fork("(sd-userns)", FORK_RESET_SIGNALS|FORK_DEATHSIG_SIGKILL|FORK_LOG, &pid);
r = pidref_safe_fork("(sd-userns)", FORK_RESET_SIGNALS|FORK_DEATHSIG_SIGKILL|FORK_LOG, &pidref);
if (r < 0)
return r;
if (r == 0) {
@ -590,7 +590,7 @@ static int write_userns(int usernsfd, const UserNamespaceInfo *userns_info) {
_cleanup_free_ char *pmap = NULL;
if (asprintf(&pmap, "/proc/" PID_FMT "/uid_map", pid) < 0)
if (asprintf(&pmap, "/proc/" PID_FMT "/uid_map", pidref.pid) < 0)
return log_oom();
r = write_string_filef(pmap, 0, UID_FMT " " UID_FMT " %" PRIu32 "\n", userns_info->target_uid, userns_info->start_uid, userns_info->size);
@ -598,7 +598,7 @@ static int write_userns(int usernsfd, const UserNamespaceInfo *userns_info) {
return log_error_errno(r, "Failed to write 'uid_map' file of user namespace: %m");
pmap = mfree(pmap);
if (asprintf(&pmap, "/proc/" PID_FMT "/gid_map", pid) < 0)
if (asprintf(&pmap, "/proc/" PID_FMT "/gid_map", pidref.pid) < 0)
return log_oom();
r = write_string_filef(pmap, 0, GID_FMT " " GID_FMT " %" PRIu32 "\n", userns_info->target_gid, userns_info->start_gid, userns_info->size);

View File

@ -11,6 +11,7 @@
#include "log.h"
#include "main-func.h"
#include "namespace-util.h"
#include "pidref.h"
#include "process-util.h"
#include "rm-rf.h"
#include "tmpfile-util.h"
@ -56,7 +57,7 @@ static int run(int argc, char *argv[]) {
_cleanup_(userns_restrict_bpf_freep) struct userns_restrict_bpf *obj = NULL;
_cleanup_close_ int userns_fd = -EBADF, host_fd1 = -EBADF, host_tmpfs = -EBADF, afd = -EBADF, bfd = -EBADF;
_cleanup_(rm_rf_physical_and_freep) char *t = NULL;
_cleanup_(sigkill_waitp) pid_t pid = 0;
_cleanup_(pidref_done_sigkill_wait) PidRef pidref = PIDREF_NULL;
int r;
log_set_max_level(LOG_DEBUG);
@ -100,7 +101,7 @@ static int run(int argc, char *argv[]) {
assert_se(afd >= 0 && bfd >= 0);
r = safe_fork("(test)", FORK_DEATHSIG_SIGKILL, &pid);
r = pidref_safe_fork("(test)", FORK_DEATHSIG_SIGKILL, &pidref);
assert_se(r >= 0);
if (r == 0) {
_cleanup_close_ int private_tmpfs = -EBADF;
@ -178,7 +179,7 @@ static int run(int argc, char *argv[]) {
assert_se(eventfd_write(bfd, 1) >= 0);
assert_se(wait_for_terminate_and_check("(test)", pid, WAIT_LOG) >= 0);
assert_se(pidref_wait_for_terminate_and_check("(test)", &pidref, WAIT_LOG) >= 0);
return 0;
}

View File

@ -36,13 +36,13 @@
#include "mkdir.h"
#include "os-util.h"
#include "path-lookup.h"
#include "pidref.h"
#include "portable.h"
#include "portable-util.h"
#include "process-util.h"
#include "rm-rf.h"
#include "selinux-util.h"
#include "set.h"
#include "signal-util.h"
#include "socket-util.h"
#include "sort-util.h"
#include "string-table.h"
@ -400,7 +400,7 @@ static int portable_extract_by_path(
_cleanup_(dissected_image_unrefp) DissectedImage *m = NULL;
_cleanup_(rmdir_and_freep) char *tmpdir = NULL;
_cleanup_close_pair_ int seq[2] = EBADF_PAIR;
_cleanup_(sigkill_waitp) pid_t child = 0;
_cleanup_(pidref_done_sigkill_wait) PidRef child = PIDREF_NULL;
DissectImageFlags flags =
DISSECT_IMAGE_READ_ONLY |
DISSECT_IMAGE_GENERIC_ROOT |
@ -420,8 +420,6 @@ static int portable_extract_by_path(
/* We now have a loopback block device, let's fork off a child in its own mount namespace, mount it
* there, and extract the metadata we need. The metadata is sent from the child back to us. */
BLOCK_SIGNALS(SIGCHLD);
/* Load some libraries before we fork workers off that want to use them */
(void) dlopen_cryptsetup();
(void) dlopen_libmount();
@ -454,7 +452,7 @@ static int portable_extract_by_path(
if (socketpair(AF_UNIX, SOCK_SEQPACKET|SOCK_CLOEXEC, 0, seq) < 0)
return log_debug_errno(errno, "Failed to allocated SOCK_SEQPACKET socket: %m");
r = safe_fork("(sd-dissect)", FORK_RESET_SIGNALS|FORK_DEATHSIG_SIGTERM|FORK_NEW_MOUNTNS|FORK_MOUNTNS_SLAVE|FORK_LOG, &child);
r = pidref_safe_fork("(sd-dissect)", FORK_RESET_SIGNALS|FORK_DEATHSIG_SIGTERM|FORK_NEW_MOUNTNS|FORK_MOUNTNS_SLAVE|FORK_LOG, &child);
if (r < 0)
return r;
if (r == 0) {
@ -540,10 +538,11 @@ static int portable_extract_by_path(
assert_not_reached();
}
r = wait_for_terminate_and_check("(sd-dissect)", child, 0);
r = pidref_wait_for_terminate_and_check("(sd-dissect)", &child, 0);
if (r < 0)
return r;
child = 0;
TAKE_PIDREF(child);
}
if (!os_release)

View File

@ -488,7 +488,7 @@ int bus_image_common_remove(
sd_bus_error *error) {
_cleanup_close_pair_ int errno_pipe_fd[2] = EBADF_PAIR;
_cleanup_(sigkill_waitp) pid_t child = 0;
_cleanup_(pidref_done_sigkill_wait) PidRef child = PIDREF_NULL;
PortableState state;
int r;
@ -533,7 +533,7 @@ int bus_image_common_remove(
if (pipe2(errno_pipe_fd, O_CLOEXEC|O_NONBLOCK) < 0)
return sd_bus_error_set_errnof(error, errno, "Failed to create pipe: %m");
r = safe_fork("(sd-imgrm)", FORK_RESET_SIGNALS, &child);
r = pidref_safe_fork("(sd-imgrm)", FORK_RESET_SIGNALS, &child);
if (r < 0)
return sd_bus_error_set_errnof(error, r, "Failed to fork(): %m");
if (r == 0) {
@ -550,11 +550,11 @@ int bus_image_common_remove(
errno_pipe_fd[1] = safe_close(errno_pipe_fd[1]);
r = operation_new(m, child, message, errno_pipe_fd[0], NULL);
r = operation_new(m, &child, message, errno_pipe_fd[0], NULL);
if (r < 0)
return r;
child = 0;
TAKE_PIDREF(child);
errno_pipe_fd[0] = -EBADF;
return 1;

View File

@ -7,6 +7,7 @@
#include "sd-event.h"
#include "alloc-util.h"
#include "event-util.h"
#include "fd-util.h"
#include "format-util.h"
#include "log.h"
@ -22,10 +23,10 @@ static int operation_done(sd_event_source *s, const siginfo_t *si, void *userdat
assert(si);
log_debug("Operation " PID_FMT " is now complete with code=%s status=%i",
o->pid,
o->pidref.pid,
sigchld_code_to_string(si->si_code), si->si_status);
o->pid = 0;
pidref_done(&o->pidref);
if (si->si_code != CLD_EXITED) {
r = sd_bus_error_set(&error, SD_BUS_ERROR_FAILED, "Child died abnormally.");
@ -74,12 +75,12 @@ fail:
return 0;
}
int operation_new(Manager *manager, pid_t child, sd_bus_message *message, int errno_fd, Operation **ret) {
int operation_new(Manager *manager, PidRef *child, sd_bus_message *message, int errno_fd, Operation **ret) {
Operation *o;
int r;
assert(manager);
assert(child > 1);
assert(pidref_is_set(child));
assert(message);
assert(errno_fd >= 0);
@ -89,13 +90,13 @@ int operation_new(Manager *manager, pid_t child, sd_bus_message *message, int er
o->extra_fd = -EBADF;
r = sd_event_add_child(manager->event, &o->event_source, child, WEXITED, operation_done, o);
r = event_add_child_pidref(manager->event, &o->event_source, child, WEXITED, operation_done, o);
if (r < 0) {
free(o);
return r;
}
o->pid = child;
o->pidref = TAKE_PIDREF(*child);
o->message = sd_bus_message_ref(message);
o->errno_fd = errno_fd;
@ -103,7 +104,7 @@ int operation_new(Manager *manager, pid_t child, sd_bus_message *message, int er
manager->n_operations++;
o->manager = manager;
log_debug("Started new operation " PID_FMT ".", child);
log_debug("Started new operation " PID_FMT ".", o->pidref.pid);
/* At this point we took ownership of both the child and the errno file descriptor! */
@ -122,8 +123,7 @@ Operation *operation_free(Operation *o) {
safe_close(o->errno_fd);
safe_close(o->extra_fd);
if (o->pid > 1)
sigkill_wait(o->pid);
pidref_done_sigkill_wait(&o->pidref);
sd_bus_message_unref(o->message);

View File

@ -2,13 +2,14 @@
#pragma once
#include "list.h"
#include "pidref.h"
#include "portabled-forward.h"
#define OPERATIONS_MAX 64
typedef struct Operation {
Manager *manager;
pid_t pid;
PidRef pidref;
sd_bus_message *message;
int errno_fd;
int extra_fd;
@ -17,5 +18,5 @@ typedef struct Operation {
LIST_FIELDS(Operation, operations);
} Operation;
int operation_new(Manager *manager, pid_t child, sd_bus_message *message, int errno_fd, Operation **ret);
int operation_new(Manager *manager, PidRef *child, sd_bus_message *message, int errno_fd, Operation **ret);
Operation *operation_free(Operation *o);

View File

@ -143,8 +143,6 @@ static int run(int argc, char *argv[]) {
if (argc != 1)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "This program takes no arguments.");
assert_se(sigprocmask_many(SIG_BLOCK, /* ret_old_mask= */ NULL, SIGCHLD) >= 0);
r = manager_new(&m);
if (r < 0)
return log_error_errno(r, "Failed to allocate manager object: %m");

View File

@ -14,7 +14,6 @@
#include "pretty-print.h"
#include "process-util.h"
#include "ptyfwd.h"
#include "signal-util.h"
#include "string-util.h"
#include "strv.h"
#include "terminal-util.h"
@ -156,8 +155,6 @@ static int run(int argc, char *argv[]) {
log_setup();
assert_se(sigprocmask_many(SIG_BLOCK, /* ret_old_mask= */ NULL, SIGCHLD) >= 0);
r = parse_argv(argc, argv);
if (r <= 0)
return r;

View File

@ -1,19 +1,17 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <signal.h>
#include "ask-password-agent.h"
#include "bus-util.h"
#include "exec-util.h"
#include "log.h"
#include "process-util.h"
#include "pidref.h"
static pid_t agent_pid = 0;
static PidRef agent_pidref = PIDREF_NULL;
int ask_password_agent_open(void) {
int r;
if (agent_pid > 0)
if (pidref_is_set(&agent_pidref))
return 0;
r = shall_fork_agent();
@ -22,7 +20,7 @@ int ask_password_agent_open(void) {
r = fork_agent("(sd-askpwagent)",
NULL, 0,
&agent_pid,
&agent_pidref,
SYSTEMD_TTY_ASK_PASSWORD_AGENT_BINARY_PATH,
"--watch");
if (r < 0)
@ -32,12 +30,8 @@ int ask_password_agent_open(void) {
}
void ask_password_agent_close(void) {
if (agent_pid <= 0)
return;
/* Inform agent that we are done */
sigterm_wait(TAKE_PID(agent_pid));
pidref_done_sigterm_wait(&agent_pidref);
}
int ask_password_agent_open_if_enabled(BusTransport transport, bool ask_password) {

View File

@ -59,11 +59,11 @@
#include "openssl-util.h"
#include "os-util.h"
#include "path-util.h"
#include "pidref.h"
#include "proc-cmdline.h"
#include "process-util.h"
#include "resize-fs.h"
#include "runtime-scope.h"
#include "signal-util.h"
#include "siphash24.h"
#include "stat-util.h"
#include "string-util.h"
@ -2237,7 +2237,6 @@ static int is_loop_device(const char *path) {
static int run_fsck(int node_fd, const char *fstype) {
int r, exit_status;
pid_t pid;
assert(node_fd >= 0);
assert(fstype);
@ -2252,12 +2251,13 @@ static int run_fsck(int node_fd, const char *fstype) {
return 0;
}
r = safe_fork_full(
_cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
r = pidref_safe_fork_full(
"(fsck)",
NULL,
&node_fd, 1, /* Leave the node fd open */
FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_RLIMIT_NOFILE_SAFE|FORK_DEATHSIG_SIGTERM|FORK_REARRANGE_STDIO|FORK_CLOEXEC_OFF,
&pid);
&pidref);
if (r < 0)
return log_debug_errno(r, "Failed to fork off fsck: %m");
if (r == 0) {
@ -2268,7 +2268,7 @@ static int run_fsck(int node_fd, const char *fstype) {
_exit(FSCK_OPERATIONAL_ERROR);
}
exit_status = wait_for_terminate_and_check("fsck", pid, 0);
exit_status = pidref_wait_for_terminate_and_check("fsck", &pidref, 0);
if (exit_status < 0)
return log_debug_errno(exit_status, "Failed to fork off fsck: %m");
@ -4170,15 +4170,13 @@ int dissected_image_acquire_metadata(
_cleanup_strv_free_ char **machine_info = NULL, **os_release = NULL, **initrd_release = NULL, **sysext_release = NULL, **confext_release = NULL;
_cleanup_free_ char *hostname = NULL, *t = NULL;
_cleanup_close_pair_ int error_pipe[2] = EBADF_PAIR;
_cleanup_(sigkill_waitp) pid_t child = 0;
_cleanup_(pidref_done_sigkill_wait) PidRef child = PIDREF_NULL;
sd_id128_t machine_id = SD_ID128_NULL;
unsigned n_meta_initialized = 0;
int fds[2 * _META_MAX], r, v;
int has_init_system = -1;
ssize_t n;
BLOCK_SIGNALS(SIGCHLD);
assert(m);
r = dlopen_libmount();
@ -4203,7 +4201,7 @@ int dissected_image_acquire_metadata(
goto finish;
}
r = safe_fork("(sd-dissect)", FORK_RESET_SIGNALS|FORK_DEATHSIG_SIGTERM, &child);
r = pidref_safe_fork("(sd-dissect)", FORK_RESET_SIGNALS|FORK_DEATHSIG_SIGTERM, &child);
if (r < 0)
goto finish;
if (r == 0) {
@ -4426,11 +4424,12 @@ int dissected_image_acquire_metadata(
}}
}
r = wait_for_terminate_and_check("(sd-dissect)", child, 0);
child = 0;
r = pidref_wait_for_terminate_and_check("(sd-dissect)", &child, 0);
if (r < 0)
goto finish;
TAKE_PIDREF(child);
n = read(error_pipe[0], &v, sizeof(v));
if (n < 0) {
r = -errno;

View File

@ -17,6 +17,7 @@
#include "hashmap.h"
#include "log.h"
#include "path-util.h"
#include "pidref.h"
#include "process-util.h"
#include "serialize.h"
#include "stat-util.h"
@ -28,6 +29,10 @@
#define EXIT_SKIP_REMAINING 77
DEFINE_PRIVATE_HASH_OPS_FULL(pidref_hash_ops_free_free,
PidRef, pidref_hash_func, pidref_compare_func,
pidref_free, char*, free);
/* Put this test here for a lack of better place */
assert_cc(EAGAIN == EWOULDBLOCK);
@ -36,25 +41,25 @@ static int do_spawn(
char *argv[],
int stdout_fd,
bool set_systemd_exec_pid,
pid_t *ret_pid) {
PidRef *ret) {
int r;
assert(path);
assert(ret_pid);
assert(ret);
if (null_or_empty_path(path) > 0) {
log_debug("%s is masked, skipping.", path);
return 0;
}
pid_t pid;
r = safe_fork_full(
_cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
r = pidref_safe_fork_full(
"(exec-inner)",
(const int[]) { STDIN_FILENO, stdout_fd < 0 ? STDOUT_FILENO : stdout_fd, STDERR_FILENO },
/* except_fds= */ NULL, /* n_except_fds= */ 0,
FORK_DEATHSIG_SIGTERM|FORK_LOG|FORK_RLIMIT_NOFILE_SAFE|FORK_REARRANGE_STDIO|FORK_CLOSE_ALL_FDS,
&pid);
&pidref);
if (r < 0)
return r;
if (r == 0) {
@ -78,7 +83,7 @@ static int do_spawn(
_exit(EXIT_FAILURE);
}
*ret_pid = pid;
*ret = TAKE_PIDREF(pidref);
return 1;
}
@ -121,7 +126,6 @@ static int do_execute(
STRV_FOREACH(path, paths) {
_cleanup_free_ char *t = NULL;
_cleanup_close_ int fd = -EBADF;
pid_t pid;
t = path_join(root, *path);
if (!t)
@ -161,19 +165,27 @@ static int do_execute(
"permission bits. Proceeding anyway.", t);
}
r = do_spawn(t, argv, fd, FLAGS_SET(flags, EXEC_DIR_SET_SYSTEMD_EXEC_PID), &pid);
_cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
r = do_spawn(t, argv, fd, FLAGS_SET(flags, EXEC_DIR_SET_SYSTEMD_EXEC_PID), &pidref);
if (r <= 0)
continue;
if (parallel_execution) {
r = hashmap_ensure_put(&pids, &trivial_hash_ops_value_free, PID_TO_PTR(pid), t);
_cleanup_(pidref_freep) PidRef *dup = NULL;
r = pidref_dup(&pidref, &dup);
if (r < 0)
return r;
r = hashmap_ensure_put(&pids, &pidref_hash_ops_free_free, dup, t);
if (r < 0)
return log_oom();
t = NULL;
TAKE_PTR(dup);
TAKE_PTR(t);
} else {
bool skip_remaining = false;
r = wait_for_terminate_and_check(t, pid, WAIT_LOG_ABNORMAL);
r = pidref_wait_for_terminate_and_check(t, &pidref, WAIT_LOG_ABNORMAL);
if (r < 0)
return r;
if (r > 0) {
@ -211,14 +223,12 @@ static int do_execute(
while (!hashmap_isempty(pids)) {
_cleanup_free_ char *t = NULL;
pid_t pid;
void *p;
t = ASSERT_PTR(hashmap_steal_first_key_and_value(pids, &p));
pid = PTR_TO_PID(p);
assert(pid > 0);
_cleanup_(pidref_freep) PidRef *pidref = p;
r = wait_for_terminate_and_check(t, pid, WAIT_LOG);
r = pidref_wait_for_terminate_and_check(t, pidref, WAIT_LOG);
if (r < 0)
return r;
if (!FLAGS_SET(flags, EXEC_DIR_IGNORE_ERRORS) && r > 0)
@ -240,7 +250,6 @@ int execute_strv(
ExecDirFlags flags) {
_cleanup_close_ int fd = -EBADF;
pid_t executor_pid;
int r;
assert(name);
@ -266,7 +275,8 @@ int execute_strv(
const char *process_name = strjoina("(", name, ")");
r = safe_fork(process_name, FORK_RESET_SIGNALS|FORK_DEATHSIG_SIGTERM|FORK_LOG, &executor_pid);
PidRef executor_pidref = PIDREF_NULL;
r = pidref_safe_fork(process_name, FORK_RESET_SIGNALS|FORK_DEATHSIG_SIGTERM|FORK_LOG, &executor_pidref);
if (r < 0)
return r;
if (r == 0) {
@ -274,7 +284,7 @@ int execute_strv(
_exit(r < 0 ? EXIT_FAILURE : r);
}
r = wait_for_terminate_and_check(process_name, executor_pid, 0);
r = pidref_wait_for_terminate_and_check(process_name, &executor_pidref, 0);
if (r < 0)
return r;
if (!FLAGS_SET(flags, EXEC_DIR_IGNORE_ERRORS) && r > 0)
@ -560,19 +570,19 @@ int shall_fork_agent(void) {
return true;
}
int _fork_agent(const char *name, char * const *argv, const int except[], size_t n_except, pid_t *ret_pid) {
int _fork_agent(const char *name, char * const *argv, const int except[], size_t n_except, PidRef *ret) {
int r;
assert(!strv_isempty(argv));
/* Spawns a temporary TTY agent, making sure it goes away when we go away */
r = safe_fork_full(name,
NULL,
(int*) except, /* safe_fork_full only changes except if you pass in FORK_PACK_FDS, which we don't */
n_except,
r = pidref_safe_fork_full(
name,
/* stdio_fds= */ NULL,
(int*) except, n_except, /* safe_fork_full only changes except if you pass in FORK_PACK_FDS, which we don't */
FORK_RESET_SIGNALS|FORK_DEATHSIG_SIGTERM|FORK_CLOSE_ALL_FDS|FORK_REOPEN_LOG|FORK_RLIMIT_NOFILE_SAFE,
ret_pid);
ret);
if (r < 0)
return r;
if (r > 0)

View File

@ -62,5 +62,5 @@ ExecCommandFlags exec_command_flags_from_string(const char *s);
int fexecve_or_execve(int executable_fd, const char *executable, char *const argv[], char *const envp[]);
int shall_fork_agent(void);
int _fork_agent(const char *name, char * const *argv, const int except[], size_t n_except, pid_t *ret_pid);
#define fork_agent(name, except, n_except, ret_pid, ...) _fork_agent(name, STRV_MAKE(__VA_ARGS__), except, n_except, ret_pid)
int _fork_agent(const char *name, char * const *argv, const int except[], size_t n_except, PidRef *ret);
#define fork_agent(name, except, n_except, ret, ...) _fork_agent(name, STRV_MAKE(__VA_ARGS__), except, n_except, ret)

View File

@ -35,7 +35,7 @@ static int on_child_exit(sd_event_source *s, const siginfo_t *si, void *userdata
else if (si->si_code == CLD_DUMPED)
log_debug("Child process " PID_FMT " dumped core by signal %s, ignoring.", si->si_pid, signal_to_string(si->si_status));
else
log_debug("Got unexpected exit code %i via SIGCHLD, ignoring.", si->si_code);
log_debug("Got unexpected exit code %i from child, ignoring.", si->si_code);
/* And let's then fail the whole thing, because regardless what the exit status of the child is
* (i.e. even if successful), if it exits before sending READY=1 something is wrong. */
@ -106,7 +106,7 @@ int fork_notify(char * const *argv, PidRef *ret_pidref) {
_cleanup_free_ char *addr_string = NULL;
r = notify_socket_prepare_full(
event,
SD_EVENT_PRIORITY_NORMAL-10, /* We want the notification message from the child before the SIGCHLD */
SD_EVENT_PRIORITY_NORMAL-10, /* We want the notification message from the child before the child exit */
on_child_notify,
&child,
/* accept_fds= */ false,
@ -124,8 +124,6 @@ int fork_notify(char * const *argv, PidRef *ret_pidref) {
log_debug("Invoking '%s' as child.", strnull(l));
}
BLOCK_SIGNALS(SIGCHLD);
r = pidref_safe_fork_full(
"(fork-notify)",
(const int[3]) { -EBADF, STDOUT_FILENO, STDERR_FILENO },

View File

@ -14,6 +14,7 @@
#include "locale-util.h"
#include "log.h"
#include "pager.h"
#include "pidref.h"
#include "process-util.h"
#include "signal-util.h"
#include "string-util.h"
@ -288,8 +289,10 @@ void pager_close(void) {
stdout_redirected = stderr_redirected = false;
(void) kill(pager_pid, SIGCONT);
(void) wait_for_terminate(TAKE_PID(pager_pid), NULL);
pager_pid = 0;
_cleanup_(pidref_done) PidRef pidref = PIDREF_MAKE_FROM_PID(pager_pid);
(void) pidref_set_pid(&pidref, pager_pid);
(void) pidref_wait_for_terminate(&pidref, NULL);
TAKE_PID(pager_pid);
}
bool pager_have(void) {
@ -299,7 +302,6 @@ bool pager_have(void) {
int show_man_page(const char *desc, bool null_stdio) {
const char *args[4] = { "man", NULL, NULL, NULL };
const char *e = NULL;
pid_t pid;
size_t k;
int r;
@ -319,7 +321,11 @@ int show_man_page(const char *desc, bool null_stdio) {
} else
args[1] = desc;
r = safe_fork("(man)", FORK_RESET_SIGNALS|FORK_DEATHSIG_SIGTERM|(null_stdio ? FORK_REARRANGE_STDIO : 0)|FORK_RLIMIT_NOFILE_SAFE|FORK_LOG, &pid);
_cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
r = pidref_safe_fork(
"(man)",
FORK_RESET_SIGNALS|FORK_DEATHSIG_SIGTERM|(null_stdio ? FORK_REARRANGE_STDIO : 0)|FORK_RLIMIT_NOFILE_SAFE|FORK_LOG|FORK_WAIT,
&pidref);
if (r < 0)
return r;
if (r == 0) {
@ -329,5 +335,5 @@ int show_man_page(const char *desc, bool null_stdio) {
_exit(EXIT_FAILURE);
}
return wait_for_terminate_and_check(NULL, pid, 0);
return pidref_wait_for_terminate_and_check(NULL, &pidref, 0);
}

View File

@ -1,7 +1,6 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <poll.h>
#include <signal.h>
#include <unistd.h>
#include "bus-util.h"
@ -9,19 +8,19 @@
#include "fd-util.h"
#include "io-util.h"
#include "log.h"
#include "pidref.h"
#include "polkit-agent.h"
#include "process-util.h"
#include "stdio-util.h"
#if ENABLE_POLKIT
static pid_t agent_pid = 0;
static PidRef agent_pidref = PIDREF_NULL;
int polkit_agent_open(void) {
_cleanup_close_pair_ int pipe_fd[2] = EBADF_PAIR;
char notify_fd[DECIMAL_STR_MAX(int) + 1];
int r;
if (agent_pid > 0)
if (pidref_is_set(&agent_pidref))
return 0;
/* Clients that run as root don't need to activate/query polkit */
@ -40,7 +39,7 @@ int polkit_agent_open(void) {
r = fork_agent("(polkit-agent)",
&pipe_fd[1],
1,
&agent_pid,
&agent_pidref,
POLKIT_AGENT_BINARY_PATH,
"--notify-fd", notify_fd,
"--fallback");
@ -57,12 +56,8 @@ int polkit_agent_open(void) {
}
void polkit_agent_close(void) {
if (agent_pid <= 0)
return;
/* Inform agent that we are done */
sigterm_wait(TAKE_PID(agent_pid));
pidref_done_sigterm_wait(&agent_pidref);
}
#else

View File

@ -448,7 +448,12 @@ int assert_signal_internal(int *ret_signal) {
return ASSERT_SIGNAL_FORK_CHILD;
}
r = wait_for_terminate(r, &siginfo);
_cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
r = pidref_set_pid(&pidref, r);
if (r < 0)
return r;
r = pidref_wait_for_terminate(&pidref, &siginfo);
if (r < 0)
return r;

View File

@ -228,8 +228,6 @@ int sync_with_progress(int fd) {
_cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
int r;
BLOCK_SIGNALS(SIGCHLD);
/* Due to the possibility of the sync operation hanging, we fork a child process and monitor
* the progress. If the timeout lapses, the assumption is that the particular sync stalled. */
@ -252,12 +250,15 @@ int sync_with_progress(int fd) {
* SYNC_PROGRESS_ATTEMPTS lapse without progress being made,
* we assume that the sync is stalled */
for (unsigned checks = 0; checks < SYNC_PROGRESS_ATTEMPTS; checks++) {
r = wait_for_terminate_with_timeout(pidref.pid, SYNC_TIMEOUT_USEC);
if (r == 0)
siginfo_t si;
r = pidref_wait_for_terminate_full(&pidref, SYNC_TIMEOUT_USEC, &si);
if (r >= 0 && si.si_code == CLD_EXITED && si.si_status == EXIT_SUCCESS)
/* Sync finished without error (sync() call itself does not return an error code) */
return 0;
if (r != -ETIMEDOUT)
return log_error_errno(r, "Failed to sync %s: %m", what);
return log_error_errno(r < 0 ? r : SYNTHETIC_ERRNO(EPROTO),
"Failed to sync %s: %m", what);
/* Reset the check counter if we made some progress */
if (sync_making_progress(&dirty) > 0)

View File

@ -24,9 +24,9 @@
#include "mount-util.h"
#include "mountpoint-util.h"
#include "parse-util.h"
#include "pidref.h"
#include "process-util.h"
#include "random-util.h"
#include "signal-util.h"
#include "stat-util.h"
#include "string-util.h"
#include "umount.h"
@ -250,11 +250,9 @@ static void log_umount_blockers(const char *mnt) {
static int remount_with_timeout(MountPoint *m, bool last_try) {
_cleanup_close_pair_ int pfd[2] = EBADF_PAIR;
_cleanup_(sigkill_nowaitp) pid_t pid = 0;
_cleanup_(pidref_done_sigkill_nowait) PidRef pidref = PIDREF_NULL;
int r;
BLOCK_SIGNALS(SIGCHLD);
assert(m);
r = pipe2(pfd, O_CLOEXEC|O_NONBLOCK);
@ -263,10 +261,10 @@ static int remount_with_timeout(MountPoint *m, bool last_try) {
/* Due to the possibility of a remount operation hanging, we fork a child process and set a
* timeout. If the timeout lapses, the assumption is that the particular remount failed. */
r = safe_fork_full("(sd-remount)",
r = pidref_safe_fork_full("(sd-remount)",
NULL,
pfd, ELEMENTSOF(pfd),
FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_LOG|FORK_REOPEN_LOG, &pid);
FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_LOG|FORK_REOPEN_LOG, &pidref);
if (r < 0)
return r;
if (r == 0) {
@ -287,29 +285,37 @@ static int remount_with_timeout(MountPoint *m, bool last_try) {
pfd[1] = safe_close(pfd[1]);
r = wait_for_terminate_with_timeout(pid, DEFAULT_TIMEOUT_USEC);
siginfo_t si;
r = pidref_wait_for_terminate_full(&pidref, DEFAULT_TIMEOUT_USEC, &si);
if (r == -ETIMEDOUT)
log_error_errno(r, "Remounting '%s' timed out, issuing SIGKILL to PID " PID_FMT ".", m->path, pid);
else if (r == -EPROTO) {
log_error_errno(r, "Remounting '%s' timed out, issuing SIGKILL to PID " PID_FMT ".", m->path, pidref.pid);
else if (r < 0)
log_error_errno(r, "Remounting '%s' failed unexpectedly, couldn't wait for child process " PID_FMT ": %m", m->path, pidref.pid);
else if (si.si_code != CLD_EXITED || si.si_status != 0) {
/* Try to read error code from child */
if (read(pfd[0], &r, sizeof(r)) == sizeof(r))
log_debug_errno(r, "Remounting '%s' failed abnormally, child process " PID_FMT " failed: %m", m->path, pid);
else
r = log_debug_errno(EPROTO, "Remounting '%s' failed abnormally, child process " PID_FMT " aborted or exited non-zero.", m->path, pid);
TAKE_PID(pid); /* child exited (just not as we expected) hence don't kill anymore */
} else if (r < 0)
log_error_errno(r, "Remounting '%s' failed unexpectedly, couldn't wait for child process " PID_FMT ": %m", m->path, pid);
r = read_errno(pfd[0]);
if (r == -EIO)
r = log_debug_errno(
SYNTHETIC_ERRNO(EPROTO),
"Remounting '%s' failed abnormally, child process " PID_FMT " aborted or exited non-zero.",
m->path, pidref.pid);
else if (r < 0)
log_debug_errno(
r,
"Remounting '%s' failed abnormally, child process " PID_FMT " failed: %m",
m->path, pidref.pid);
TAKE_PIDREF(pidref); /* child exited (just not as we expected) hence don't kill anymore */
}
return r;
}
static int umount_with_timeout(MountPoint *m, bool last_try) {
_cleanup_close_pair_ int pfd[2] = EBADF_PAIR;
_cleanup_(sigkill_nowaitp) pid_t pid = 0;
_cleanup_(pidref_done_sigkill_nowait) PidRef pidref = PIDREF_NULL;
int r;
BLOCK_SIGNALS(SIGCHLD);
assert(m);
r = pipe2(pfd, O_CLOEXEC|O_NONBLOCK);
@ -318,10 +324,10 @@ static int umount_with_timeout(MountPoint *m, bool last_try) {
/* Due to the possibility of a umount operation hanging, we fork a child process and set a
* timeout. If the timeout lapses, the assumption is that the particular umount failed. */
r = safe_fork_full("(sd-umount)",
r = pidref_safe_fork_full("(sd-umount)",
NULL,
pfd, ELEMENTSOF(pfd),
FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_LOG|FORK_REOPEN_LOG, &pid);
FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_LOG|FORK_REOPEN_LOG, &pidref);
if (r < 0)
return r;
if (r == 0) {
@ -349,18 +355,28 @@ static int umount_with_timeout(MountPoint *m, bool last_try) {
pfd[1] = safe_close(pfd[1]);
r = wait_for_terminate_with_timeout(pid, DEFAULT_TIMEOUT_USEC);
siginfo_t si;
r = pidref_wait_for_terminate_full(&pidref, DEFAULT_TIMEOUT_USEC, &si);
if (r == -ETIMEDOUT)
log_error_errno(r, "Unmounting '%s' timed out, issuing SIGKILL to PID " PID_FMT ".", m->path, pid);
else if (r == -EPROTO) {
log_error_errno(r, "Unmounting '%s' timed out, issuing SIGKILL to PID " PID_FMT ".", m->path, pidref.pid);
else if (r < 0)
log_error_errno(r, "Unmounting '%s' failed unexpectedly, couldn't wait for child process " PID_FMT ": %m", m->path, pidref.pid);
else if (si.si_code != CLD_EXITED || si.si_status != 0) {
/* Try to read error code from child */
if (read(pfd[0], &r, sizeof(r)) == sizeof(r))
log_debug_errno(r, "Unmounting '%s' failed abnormally, child process " PID_FMT " failed: %m", m->path, pid);
else
r = log_debug_errno(EPROTO, "Unmounting '%s' failed abnormally, child process " PID_FMT " aborted or exited non-zero.", m->path, pid);
TAKE_PID(pid); /* It died, but abnormally, no purpose in killing */
} else if (r < 0)
log_error_errno(r, "Unmounting '%s' failed unexpectedly, couldn't wait for child process " PID_FMT ": %m", m->path, pid);
r = read_errno(pfd[0]);
if (r == -EIO)
r = log_debug_errno(
SYNTHETIC_ERRNO(EPROTO),
"Unmounting '%s' failed abnormally, child process " PID_FMT " aborted or exited non-zero.",
m->path, pidref.pid);
else if (r < 0)
log_debug_errno(
r,
"Unmounting '%s' failed abnormally, child process " PID_FMT " failed: %m",
m->path, pidref.pid);
TAKE_PIDREF(pidref); /* It died, but abnormally, no purpose in killing */
}
return r;
}

View File

@ -16,6 +16,7 @@
#include "initrd-util.h"
#include "log.h"
#include "main-func.h"
#include "pidref.h"
#include "proc-cmdline.h"
#include "process-util.h"
#include "special.h"
@ -66,10 +67,10 @@ static int start_target(sd_bus *bus, const char *target) {
}
static int fork_wait(const char* const cmdline[]) {
pid_t pid;
int r;
r = safe_fork("(sulogin)", FORK_RESET_SIGNALS|FORK_DEATHSIG_SIGTERM|FORK_RLIMIT_NOFILE_SAFE|FORK_LOG, &pid);
_cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
r = pidref_safe_fork("(sulogin)", FORK_RESET_SIGNALS|FORK_DEATHSIG_SIGTERM|FORK_RLIMIT_NOFILE_SAFE|FORK_LOG, &pidref);
if (r < 0)
return r;
if (r == 0) {
@ -79,7 +80,7 @@ static int fork_wait(const char* const cmdline[]) {
_exit(EXIT_FAILURE); /* Operational error */
}
return wait_for_terminate_and_check(cmdline[0], pid, WAIT_LOG_ABNORMAL);
return pidref_wait_for_terminate_and_check(cmdline[0], &pidref, WAIT_LOG_ABNORMAL);
}
static void print_mode(const char* mode) {

View File

@ -48,6 +48,7 @@
#include "parse-argument.h"
#include "parse-util.h"
#include "path-util.h"
#include "pidref.h"
#include "pretty-print.h"
#include "process-util.h"
#include "rm-rf.h"
@ -2139,14 +2140,15 @@ static int merge(ImageClass image_class,
bool no_reload,
int noexec,
Hashmap *images) {
pid_t pid;
int r;
(void) dlopen_cryptsetup();
(void) dlopen_libblkid();
(void) dlopen_libmount();
r = safe_fork("(sd-merge)", FORK_DEATHSIG_SIGTERM|FORK_LOG|FORK_NEW_MOUNTNS, &pid);
_cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
r = pidref_safe_fork("(sd-merge)", FORK_DEATHSIG_SIGTERM|FORK_LOG|FORK_NEW_MOUNTNS, &pidref);
if (r < 0)
return log_error_errno(r, "Failed to fork off child: %m");
if (r == 0) {
@ -2162,7 +2164,7 @@ static int merge(ImageClass image_class,
_exit(r > 0 ? EXIT_SUCCESS : 123); /* 123 means: didn't find any extensions */
}
r = wait_for_terminate_and_check("(sd-merge)", pid, WAIT_LOG_ABNORMAL);
r = pidref_wait_for_terminate_and_check("(sd-merge)", &pidref, WAIT_LOG_ABNORMAL);
if (r < 0)
return r;
if (r == 123) /* exit code 123 means: didn't do anything */

View File

@ -1,6 +1,5 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
@ -9,6 +8,7 @@
#include "log.h"
#include "path-lookup.h"
#include "path-util.h"
#include "pidref.h"
#include "process-util.h"
#include "string-util.h"
#include "strv.h"
@ -56,7 +56,6 @@ int enable_sysv_units(const char *verb, char **args) {
bool found_native = false, found_sysv;
const char *name;
unsigned c = 1;
pid_t pid;
int j;
name = args[f++];
@ -122,7 +121,8 @@ int enable_sysv_units(const char *verb, char **args) {
if (!arg_quiet)
log_info("Executing: %s", l);
j = safe_fork("(sysv-install)", FORK_RESET_SIGNALS|FORK_DEATHSIG_SIGTERM|FORK_RLIMIT_NOFILE_SAFE|FORK_LOG, &pid);
_cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
j = pidref_safe_fork("(sysv-install)", FORK_RESET_SIGNALS|FORK_DEATHSIG_SIGTERM|FORK_RLIMIT_NOFILE_SAFE|FORK_LOG, &pidref);
if (j < 0)
return j;
if (j == 0) {
@ -132,7 +132,7 @@ int enable_sysv_units(const char *verb, char **args) {
_exit(EXIT_FAILURE);
}
j = wait_for_terminate_and_check("sysv-install", pid, WAIT_LOG_ABNORMAL);
j = pidref_wait_for_terminate_and_check("sysv-install", &pidref, WAIT_LOG_ABNORMAL);
if (j < 0)
return j;
if (streq(verb, "is-enabled")) {

View File

@ -21,6 +21,7 @@
#include "gpt.h"
#include "hexdecoct.h"
#include "import-util.h"
#include "pidref.h"
#include "process-util.h"
#include "sort-util.h"
#include "stat-util.h"
@ -274,7 +275,6 @@ static int download_manifest(
_cleanup_close_pair_ int pfd[2] = EBADF_PAIR;
_cleanup_fclose_ FILE *manifest = NULL;
size_t size = 0;
pid_t pid;
int r;
assert(url);
@ -293,11 +293,13 @@ static int download_manifest(
log_info("%s Acquiring manifest file %s%s", glyph(GLYPH_DOWNLOAD),
suffixed_url, glyph(GLYPH_ELLIPSIS));
r = safe_fork_full("(sd-pull)",
_cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
r = pidref_safe_fork_full(
"(sd-pull)",
(int[]) { -EBADF, pfd[1], STDERR_FILENO },
NULL, 0,
FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_DEATHSIG_SIGTERM|FORK_REARRANGE_STDIO|FORK_LOG,
&pid);
&pidref);
if (r < 0)
return r;
if (r == 0) {
@ -337,7 +339,7 @@ static int download_manifest(
manifest = safe_fclose(manifest);
r = wait_for_terminate_and_check("(sd-pull)", pid, WAIT_LOG);
r = pidref_wait_for_terminate_and_check("(sd-pull)", &pidref, WAIT_LOG);
if (r < 0)
return r;
if (r != 0)

View File

@ -23,7 +23,6 @@
#include "path-util.h"
#include "pretty-print.h"
#include "set.h"
#include "signal-util.h"
#include "sort-util.h"
#include "specifier.h"
#include "string-util.h"
@ -1877,9 +1876,6 @@ static int run(int argc, char *argv[]) {
if (r <= 0)
return r;
/* SIGCHLD signal must be blocked for sd_event_add_child to work */
assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGCHLD) >= 0);
return sysupdate_main(argc, argv);
}

View File

@ -1738,7 +1738,7 @@ static int manager_new(Manager **ret) {
r = notify_socket_prepare(
m->event,
SD_EVENT_PRIORITY_NORMAL - 1, /* Make this processed before SIGCHLD. */
SD_EVENT_PRIORITY_NORMAL - 1, /* Make this processed before worker exit. */
manager_on_notify,
m,
&m->notify_socket_path);
@ -2078,9 +2078,6 @@ static int run(int argc, char *argv[]) {
umask(0022);
/* SIGCHLD signal must be blocked for sd_event_add_child to work */
assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGCHLD) >= 0);
r = manager_new(&m);
if (r < 0)
return log_error_errno(r, "Failed to allocate manager object: %m");

View File

@ -59,46 +59,30 @@ static void test_rename_process_now(const char *p, int ret) {
}
static void test_rename_process_one(const char *p, int ret) {
siginfo_t si;
pid_t pid;
int r;
log_info("/* %s(%s) */", __func__, p);
pid = fork();
assert_se(pid >= 0);
r = ASSERT_OK(safe_fork("(rename)", FORK_WAIT|FORK_LOG|FORK_DEATHSIG_SIGKILL, /* ret_pid= */ NULL));
if (pid == 0) {
if (r == 0) {
/* child */
test_rename_process_now(p, ret);
_exit(EXIT_SUCCESS);
}
assert_se(wait_for_terminate(pid, &si) >= 0);
assert_se(si.si_code == CLD_EXITED);
assert_se(si.si_status == EXIT_SUCCESS);
}
TEST(rename_process_invalid) {
assert_se(rename_process(NULL) == -EINVAL);
assert_se(rename_process("") == -EINVAL);
ASSERT_ERROR(rename_process(NULL), EINVAL);
ASSERT_ERROR(rename_process(""), EINVAL);
}
TEST(rename_process_multi) {
pid_t pid;
int r;
pid = fork();
assert_se(pid >= 0);
if (pid > 0) {
siginfo_t si;
assert_se(wait_for_terminate(pid, &si) >= 0);
assert_se(si.si_code == CLD_EXITED);
assert_se(si.si_status == EXIT_SUCCESS);
return;
}
r = ASSERT_OK(safe_fork("(rename)", FORK_WAIT|FORK_LOG|FORK_DEATHSIG_SIGKILL, /* ret_pid= */ NULL));
if (r == 0) {
/* child */
test_rename_process_now("one", 1);
test_rename_process_now("more", 0); /* longer than "one", hence truncated */
@ -106,6 +90,7 @@ TEST(rename_process_multi) {
test_rename_process_now("time!", 0);
test_rename_process_now("0", 1); /* shorter than "one", should fit */
_exit(EXIT_SUCCESS);
}
}
TEST(rename_process) {

View File

@ -18,7 +18,7 @@
TEST(asynchronous_sync) {
_cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
ASSERT_OK(asynchronous_sync(&pidref));
ASSERT_OK(pidref_wait_for_terminate(&pidref, /* ret= */ NULL));
ASSERT_OK(pidref_wait_for_terminate(&pidref, NULL));
}
static void wait_fd_closed(int fd) {

View File

@ -7,6 +7,7 @@
#include "data-fd-util.h"
#include "fd-util.h"
#include "memfd-util.h"
#include "pidref.h"
#include "process-util.h"
#include "tests.h"
@ -33,7 +34,7 @@ static void assert_equal_fd(int fd1, int fd2) {
TEST(copy_data_fd) {
_cleanup_close_ int fd1 = -EBADF, fd2 = -EBADF;
_cleanup_close_pair_ int sfd[2] = EBADF_PAIR;
_cleanup_(sigkill_waitp) pid_t pid = -1;
_cleanup_(pidref_done_sigkill_wait) PidRef pidref = PIDREF_NULL;
int r;
fd1 = open("/etc/fstab", O_RDONLY|O_CLOEXEC);
@ -66,7 +67,7 @@ TEST(copy_data_fd) {
assert_se(socketpair(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0, sfd) >= 0);
r = safe_fork("(sd-pipe)", FORK_RESET_SIGNALS|FORK_DEATHSIG_SIGTERM|FORK_LOG, &pid);
r = pidref_safe_fork("(sd-pipe)", FORK_RESET_SIGNALS|FORK_DEATHSIG_SIGTERM|FORK_LOG, &pidref);
assert_se(r >= 0);
if (r == 0) {

View File

@ -246,18 +246,17 @@ static bool apparmor_restrict_unprivileged_userns(void) {
}
static bool have_userns_privileges(void) {
pid_t pid;
_cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
int r;
if (apparmor_restrict_unprivileged_userns())
return false;
r = safe_fork("(sd-test-check-userns)",
FORK_RESET_SIGNALS |
FORK_CLOSE_ALL_FDS |
FORK_DEATHSIG_SIGKILL,
&pid);
ASSERT_OK(r);
r = ASSERT_OK(pidref_safe_fork(
"(sd-test-check-userns)",
FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_DEATHSIG_SIGKILL,
&pidref));
if (r == 0) {
/* Keep CAP_SYS_ADMIN if we have it to ensure we give an
* accurate result to the caller. Some kernels have a
@ -282,7 +281,7 @@ static bool have_userns_privileges(void) {
* EXIT_SUCCESS => we can use user namespaces
* EXIT_FAILURE => we can NOT use user namespaces
* 2 => some other error occurred */
r = wait_for_terminate_and_check("(sd-test-check-userns)", pid, 0);
r = pidref_wait_for_terminate_and_check("(sd-test-check-userns)", &pidref, 0);
if (!IN_SET(r, EXIT_SUCCESS, EXIT_FAILURE))
log_debug("Failed to check if user namespaces can be used, assuming not.");
@ -681,7 +680,7 @@ static int on_spawn_timeout(sd_event_source *s, uint64_t usec, void *userdata) {
return 1;
}
static int on_spawn_sigchld(sd_event_source *s, const siginfo_t *si, void *userdata) {
static int on_spawn_exit(sd_event_source *s, const siginfo_t *si, void *userdata) {
int ret = -EIO;
ASSERT_NOT_NULL(si);
@ -707,8 +706,6 @@ static int find_libraries(const char *exec, char ***ret) {
ASSERT_NOT_NULL(exec);
ASSERT_NOT_NULL(ret);
ASSERT_OK(sigprocmask_many(SIG_BLOCK, NULL, SIGCHLD));
ASSERT_OK_ERRNO(pipe2(outpipe, O_NONBLOCK|O_CLOEXEC));
ASSERT_OK_ERRNO(pipe2(errpipe, O_NONBLOCK|O_CLOEXEC));
@ -733,8 +730,8 @@ static int find_libraries(const char *exec, char ***ret) {
ASSERT_OK(sd_event_source_set_enabled(stdout_source, SD_EVENT_ONESHOT));
ASSERT_OK(sd_event_add_io(e, &stderr_source, errpipe[0], EPOLLIN, on_spawn_io, NULL));
ASSERT_OK(sd_event_source_set_enabled(stderr_source, SD_EVENT_ONESHOT));
ASSERT_OK(sd_event_add_child(e, &sigchld_source, pid, WEXITED, on_spawn_sigchld, NULL));
/* SIGCHLD should be processed after IO is complete */
ASSERT_OK(sd_event_add_child(e, &sigchld_source, pid, WEXITED, on_spawn_exit, NULL));
/* Child exit should be processed after IO is complete */
ASSERT_OK(sd_event_source_set_priority(sigchld_source, SD_EVENT_PRIORITY_NORMAL + 1));
ASSERT_OK(sd_event_loop(e));

View File

@ -12,6 +12,7 @@
#include "memfd-util.h"
#include "parse-util.h"
#include "path-util.h"
#include "pidref.h"
#include "process-util.h"
#include "random-util.h"
#include "rm-rf.h"
@ -492,7 +493,6 @@ TEST(read_full_file_socket) {
union sockaddr_union sa;
const char *j, *jj;
size_t size;
pid_t pid;
int r;
ASSERT_OK(listener = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0));
@ -513,7 +513,8 @@ TEST(read_full_file_socket) {
/* Bind the *client* socket to some randomized name, to verify that this works correctly. */
ASSERT_OK(asprintf(&clientname, "@%" PRIx64 "/test-bindname", random_u64()));
ASSERT_OK(r = safe_fork("(server)", FORK_DEATHSIG_SIGTERM|FORK_LOG, &pid));
_cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
r = ASSERT_OK(pidref_safe_fork("(server)", FORK_DEATHSIG_SIGTERM|FORK_LOG, &pidref));
if (r == 0) {
union sockaddr_union peer = {};
socklen_t peerlen = sizeof(peer);
@ -540,7 +541,7 @@ TEST(read_full_file_socket) {
ASSERT_EQ(size, strlen(TEST_STR));
ASSERT_STREQ(data, TEST_STR);
ASSERT_OK(wait_for_terminate_and_check("(server)", pid, WAIT_LOG));
ASSERT_OK(pidref_wait_for_terminate_and_check("(server)", &pidref, WAIT_LOG));
#undef TEST_STR
}

View File

@ -12,6 +12,7 @@
#include "fs-util.h"
#include "mkdir.h"
#include "path-util.h"
#include "pidref.h"
#include "process-util.h"
#include "random-util.h"
#include "rm-rf.h"
@ -743,30 +744,29 @@ TEST(xopenat_lock_full) {
_cleanup_(rm_rf_physical_and_freep) char *t = NULL;
_cleanup_close_ int tfd = -EBADF, fd = -EBADF;
siginfo_t si;
int r;
assert_se((tfd = mkdtemp_open(NULL, 0, &t)) >= 0);
ASSERT_OK((tfd = mkdtemp_open(NULL, 0, &t)));
/* Test that we can acquire an exclusive lock on a directory in one process, remove the directory,
* and close the file descriptor and still properly create the directory and acquire the lock in
* another process. */
fd = xopenat_lock_full(tfd, "abc", O_CREAT|O_DIRECTORY|O_CLOEXEC, 0, 0755, LOCK_BSD, LOCK_EX);
assert_se(fd >= 0);
assert_se(faccessat(tfd, "abc", F_OK, 0) >= 0);
assert_se(fd_verify_directory(fd) >= 0);
assert_se(xopenat_lock_full(tfd, "abc", O_DIRECTORY|O_CLOEXEC, 0, 0755, LOCK_BSD, LOCK_EX|LOCK_NB) == -EAGAIN);
fd = ASSERT_OK(xopenat_lock_full(tfd, "abc", O_CREAT|O_DIRECTORY|O_CLOEXEC, 0, 0755, LOCK_BSD, LOCK_EX));
ASSERT_OK_ERRNO(faccessat(tfd, "abc", F_OK, 0));
ASSERT_OK(fd_verify_directory(fd));
ASSERT_ERROR(xopenat_lock_full(tfd, "abc", O_DIRECTORY|O_CLOEXEC, 0, 0755, LOCK_BSD, LOCK_EX|LOCK_NB), EAGAIN);
pid_t pid = fork();
assert_se(pid >= 0);
_cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
r = ASSERT_OK(pidref_safe_fork("(lock)", FORK_DEATHSIG_SIGKILL|FORK_LOG, &pidref));
if (pid == 0) {
if (r == 0) {
safe_close(fd);
fd = xopenat_lock_full(tfd, "abc", O_CREAT|O_DIRECTORY|O_CLOEXEC, 0, 0755, LOCK_BSD, LOCK_EX);
assert_se(fd >= 0);
assert_se(faccessat(tfd, "abc", F_OK, 0) >= 0);
assert_se(fd_verify_directory(fd) >= 0);
assert_se(xopenat_lock_full(tfd, "abc", O_DIRECTORY|O_CLOEXEC, 0, 0755, LOCK_BSD, LOCK_EX|LOCK_NB) == -EAGAIN);
fd = ASSERT_OK(xopenat_lock_full(tfd, "abc", O_CREAT|O_DIRECTORY|O_CLOEXEC, 0, 0755, LOCK_BSD, LOCK_EX));
ASSERT_OK_ERRNO(faccessat(tfd, "abc", F_OK, 0));
ASSERT_OK(fd_verify_directory(fd));
ASSERT_ERROR(xopenat_lock_full(tfd, "abc", O_DIRECTORY|O_CLOEXEC, 0, 0755, LOCK_BSD, LOCK_EX|LOCK_NB), EAGAIN);
_exit(EXIT_SUCCESS);
}
@ -777,16 +777,16 @@ TEST(xopenat_lock_full) {
* for a little and assume that's enough time for the child process to get along far enough. It
* doesn't matter if it doesn't get far enough, in that case we just won't trigger the fallback logic
* in xopenat_lock_full(), but the test will still succeed. */
assert_se(usleep_safe(20 * USEC_PER_MSEC) >= 0);
ASSERT_OK(usleep_safe(20 * USEC_PER_MSEC));
assert_se(unlinkat(tfd, "abc", AT_REMOVEDIR) >= 0);
ASSERT_OK(unlinkat(tfd, "abc", AT_REMOVEDIR));
fd = safe_close(fd);
assert_se(wait_for_terminate(pid, &si) >= 0);
assert_se(si.si_code == CLD_EXITED);
ASSERT_OK(pidref_wait_for_terminate(&pidref, &si));
ASSERT_EQ(si.si_code, CLD_EXITED);
assert_se(xopenat_lock_full(tfd, "abc", 0, 0, 0755, LOCK_POSIX, LOCK_EX) == -EBADF);
assert_se(xopenat_lock_full(tfd, "def", O_DIRECTORY, 0, 0755, LOCK_POSIX, LOCK_EX) == -EBADF);
ASSERT_ERROR(xopenat_lock_full(tfd, "abc", 0, 0, 0755, LOCK_POSIX, LOCK_EX), EBADF);
ASSERT_ERROR(xopenat_lock_full(tfd, "def", O_DIRECTORY, 0, 0755, LOCK_POSIX, LOCK_EX), EBADF);
}
TEST(linkat_replace) {

View File

@ -234,7 +234,6 @@ TEST(real_pressure) {
_exit(EXIT_SUCCESS);
}
assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGCHLD) >= 0);
assert_se(sd_event_add_child(e, &cs, pid, WEXITED, real_pressure_child_callback, NULL) >= 0);
assert_se(sd_event_source_set_child_process_own(cs, true) >= 0);

View File

@ -94,7 +94,7 @@ TEST(tmpdir) {
static void test_shareable_ns(unsigned long nsflag) {
_cleanup_close_pair_ int s[2] = EBADF_PAIR;
bool permission_denied = false;
pid_t pid1, pid2, pid3;
_cleanup_(pidref_done) PidRef pidref1 = PIDREF_NULL, pidref2 = PIDREF_NULL, pidref3 = PIDREF_NULL;
int r, n = 0;
siginfo_t si;
@ -105,51 +105,48 @@ static void test_shareable_ns(unsigned long nsflag) {
ASSERT_OK_ERRNO(socketpair(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0, s));
pid1 = fork();
ASSERT_OK_ERRNO(pid1);
r = ASSERT_OK(pidref_safe_fork("(share-ns-1)", FORK_LOG|FORK_DEATHSIG_SIGKILL, &pidref1));
if (pid1 == 0) {
if (r == 0) {
r = setup_shareable_ns(s, nsflag);
if (!ERRNO_IS_PRIVILEGE(r))
ASSERT_OK(r);
_exit(r >= 0 ? r : EX_NOPERM);
}
pid2 = fork();
ASSERT_OK_ERRNO(pid2);
r = ASSERT_OK(pidref_safe_fork("(share-ns-2)", FORK_LOG|FORK_DEATHSIG_SIGKILL, &pidref2));
if (pid2 == 0) {
if (r == 0) {
r = setup_shareable_ns(s, nsflag);
if (!ERRNO_IS_PRIVILEGE(r))
ASSERT_OK(r);
_exit(r >= 0 ? r : EX_NOPERM);
}
pid3 = fork();
ASSERT_OK_ERRNO(pid3);
r = ASSERT_OK(pidref_safe_fork("(share-ns-3)", FORK_LOG|FORK_DEATHSIG_SIGKILL, &pidref3));
if (pid3 == 0) {
if (r == 0) {
r = setup_shareable_ns(s, nsflag);
if (!ERRNO_IS_PRIVILEGE(r))
ASSERT_OK(r);
_exit(r >= 0 ? r : EX_NOPERM);
}
ASSERT_OK(wait_for_terminate(pid1, &si));
ASSERT_OK(pidref_wait_for_terminate(&pidref1, &si));
ASSERT_EQ(si.si_code, CLD_EXITED);
if (si.si_status == EX_NOPERM)
permission_denied = true;
else
n += si.si_status;
ASSERT_OK(wait_for_terminate(pid2, &si));
ASSERT_OK(pidref_wait_for_terminate(&pidref2, &si));
ASSERT_EQ(si.si_code, CLD_EXITED);
if (si.si_status == EX_NOPERM)
permission_denied = true;
else
n += si.si_status;
ASSERT_OK(wait_for_terminate(pid3, &si));
ASSERT_OK(pidref_wait_for_terminate(&pidref3, &si));
ASSERT_EQ(si.si_code, CLD_EXITED);
if (si.si_status == EX_NOPERM)
permission_denied = true;
@ -203,7 +200,6 @@ TEST(protect_kernel_logs) {
.protect_kernel_logs = true,
.root_directory_fd = -EBADF,
};
pid_t pid;
int r;
if (geteuid() > 0) {
@ -224,10 +220,9 @@ TEST(protect_kernel_logs) {
}
ASSERT_OK(r);
pid = fork();
ASSERT_OK_ERRNO(pid);
r = ASSERT_OK(safe_fork("(protect)", FORK_WAIT|FORK_LOG|FORK_DEATHSIG_SIGKILL, /* ret_pid= */ NULL));
if (pid == 0) {
if (r == 0) {
_cleanup_close_ int fd = -EBADF;
ASSERT_OK_ERRNO(fd = open("/dev/kmsg", O_RDONLY | O_CLOEXEC));
@ -239,8 +234,6 @@ TEST(protect_kernel_logs) {
_exit(EXIT_SUCCESS);
}
ASSERT_OK_EQ(wait_for_terminate_and_check("ns-kernellogs", pid, WAIT_LOG), EXIT_SUCCESS);
}
TEST(idmapping_supported) {
@ -333,7 +326,7 @@ TEST(process_is_owned_by_uid) {
ASSERT_OK_ZERO(process_is_owned_by_uid(&pid, getuid()));
ASSERT_OK(pidref_kill(&pid, SIGKILL));
ASSERT_OK(pidref_wait_for_terminate(&pid, /* ret= */ NULL));
ASSERT_OK(pidref_wait_for_terminate(&pid, NULL));
/* Test a child that runs in a userns as uid 1, but the userns is owned by us */
ASSERT_OK_ERRNO(pipe2(p, O_CLOEXEC));
@ -380,7 +373,7 @@ TEST(process_is_owned_by_uid) {
ASSERT_OK_POSITIVE(process_is_owned_by_uid(&pid, getuid()));
ASSERT_OK(pidref_kill(&pid, SIGKILL));
ASSERT_OK(pidref_wait_for_terminate(&pid, /* ret= */ NULL));
ASSERT_OK(pidref_wait_for_terminate(&pid, NULL));
}
TEST(namespace_get_leader) {

View File

@ -90,8 +90,6 @@ TEST(notify_socket_prepare) {
_cleanup_free_ char *path = NULL;
ASSERT_OK(notify_socket_prepare_full(e, SD_EVENT_PRIORITY_NORMAL - 10, on_recv, &c, true, &path, NULL));
ASSERT_OK(sigprocmask_many(SIG_BLOCK, NULL, SIGCHLD));
ASSERT_OK(r = pidref_safe_fork("(test-notify-recv-child)", FORK_DEATHSIG_SIGTERM|FORK_LOG, &c.pidref));
if (r == 0) {
ASSERT_OK_ERRNO(setenv("NOTIFY_SOCKET", path, /* overwrite= */ true));

View File

@ -464,7 +464,6 @@ TEST(find_executable) {
static void test_find_executable_exec_one(const char *path) {
_cleanup_free_ char *t = NULL;
_cleanup_close_ int fd = -EBADF;
pid_t pid;
int r;
r = find_executable_full(path, NULL, NULL, false, &t, &fd);
@ -476,15 +475,13 @@ static void test_find_executable_exec_one(const char *path) {
if (path_is_absolute(path))
ASSERT_STREQ(t, path);
pid = fork();
assert_se(pid >= 0);
if (pid == 0) {
r = ASSERT_OK(safe_fork("(find-exec)", FORK_LOG|FORK_DEATHSIG_SIGKILL|FORK_WAIT, /* ret_pid= */ NULL));
if (r == 0) {
r = fexecve_or_execve(fd, t, STRV_MAKE(t, "--version"), STRV_MAKE(NULL));
log_error_errno(r, "[f]execve: %m");
_exit(EXIT_FAILURE);
}
assert_se(wait_for_terminate_and_check(t, pid, WAIT_LOG) == 0);
}
TEST(find_executable_exec) {

View File

@ -6,25 +6,26 @@
#include "process-util.h"
#include "stdio-util.h"
#include "tests.h"
#include "time-util.h"
TEST(pidref_is_set) {
assert_se(!pidref_is_set(NULL));
assert_se(!pidref_is_set(&PIDREF_NULL));
assert_se(pidref_is_set(&PIDREF_MAKE_FROM_PID(1)));
ASSERT_FALSE(pidref_is_set(NULL));
ASSERT_FALSE(pidref_is_set(&PIDREF_NULL));
ASSERT_TRUE(pidref_is_set(&PIDREF_MAKE_FROM_PID(1)));
}
TEST(pidref_equal) {
assert_se(pidref_equal(NULL, NULL));
assert_se(pidref_equal(NULL, &PIDREF_NULL));
assert_se(pidref_equal(&PIDREF_NULL, NULL));
assert_se(pidref_equal(&PIDREF_NULL, &PIDREF_NULL));
ASSERT_TRUE(pidref_equal(NULL, NULL));
ASSERT_TRUE(pidref_equal(NULL, &PIDREF_NULL));
ASSERT_TRUE(pidref_equal(&PIDREF_NULL, NULL));
ASSERT_TRUE(pidref_equal(&PIDREF_NULL, &PIDREF_NULL));
assert_se(!pidref_equal(NULL, &PIDREF_MAKE_FROM_PID(1)));
assert_se(!pidref_equal(&PIDREF_MAKE_FROM_PID(1), NULL));
assert_se(!pidref_equal(&PIDREF_NULL, &PIDREF_MAKE_FROM_PID(1)));
assert_se(!pidref_equal(&PIDREF_MAKE_FROM_PID(1), &PIDREF_NULL));
assert_se(pidref_equal(&PIDREF_MAKE_FROM_PID(1), &PIDREF_MAKE_FROM_PID(1)));
assert_se(!pidref_equal(&PIDREF_MAKE_FROM_PID(1), &PIDREF_MAKE_FROM_PID(2)));
ASSERT_FALSE(pidref_equal(NULL, &PIDREF_MAKE_FROM_PID(1)));
ASSERT_FALSE(pidref_equal(&PIDREF_MAKE_FROM_PID(1), NULL));
ASSERT_FALSE(pidref_equal(&PIDREF_NULL, &PIDREF_MAKE_FROM_PID(1)));
ASSERT_FALSE(pidref_equal(&PIDREF_MAKE_FROM_PID(1), &PIDREF_NULL));
ASSERT_TRUE(pidref_equal(&PIDREF_MAKE_FROM_PID(1), &PIDREF_MAKE_FROM_PID(1)));
ASSERT_FALSE(pidref_equal(&PIDREF_MAKE_FROM_PID(1), &PIDREF_MAKE_FROM_PID(2)));
}
TEST(pidref_set_pid) {
@ -34,18 +35,18 @@ TEST(pidref_set_pid) {
r = pidref_set_pid(&pidref, 1);
if (r == -ESRCH)
return (void) log_tests_skipped_errno(r, "PID1 does not exist");
assert_se(r >= 0);
ASSERT_OK(r);
assert_se(pidref_equal(&pidref, &PIDREF_MAKE_FROM_PID(1)));
assert_se(!pidref_equal(&pidref, &PIDREF_MAKE_FROM_PID(2)));
ASSERT_TRUE(pidref_equal(&pidref, &PIDREF_MAKE_FROM_PID(1)));
ASSERT_FALSE(pidref_equal(&pidref, &PIDREF_MAKE_FROM_PID(2)));
}
TEST(pidref_set_self) {
_cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
assert_se(pidref_set_self(&pidref) >= 0);
assert_se(pidref_equal(&pidref, &PIDREF_MAKE_FROM_PID(getpid_cached())));
assert_se(!pidref_equal(&pidref, &PIDREF_MAKE_FROM_PID(getpid_cached()+1)));
ASSERT_OK(pidref_set_self(&pidref));
ASSERT_TRUE(pidref_equal(&pidref, &PIDREF_MAKE_FROM_PID(getpid_cached())));
ASSERT_FALSE(pidref_equal(&pidref, &PIDREF_MAKE_FROM_PID(getpid_cached()+1)));
}
TEST(pidref_set_pidstr) {
@ -53,105 +54,105 @@ TEST(pidref_set_pidstr) {
char buf[DECIMAL_STR_MAX(pid_t)];
xsprintf(buf, PID_FMT, getpid_cached());
assert_se(pidref_set_pidstr(&pidref, buf) >= 0);
assert_se(pidref_equal(&pidref, &PIDREF_MAKE_FROM_PID(getpid_cached())));
assert_se(!pidref_equal(&pidref, &PIDREF_MAKE_FROM_PID(getpid_cached()+1)));
ASSERT_OK(pidref_set_pidstr(&pidref, buf));
ASSERT_TRUE(pidref_equal(&pidref, &PIDREF_MAKE_FROM_PID(getpid_cached())));
ASSERT_FALSE(pidref_equal(&pidref, &PIDREF_MAKE_FROM_PID(getpid_cached()+1)));
}
TEST(pidref_set_pidfd) {
_cleanup_(pidref_done) PidRef a = PIDREF_NULL, b = PIDREF_NULL, c = PIDREF_NULL, d = PIDREF_NULL;
assert_se(pidref_set_self(&a) >= 0);
ASSERT_OK(pidref_set_self(&a));
if (a.fd < 0)
return (void) log_tests_skipped("PIDFD not supported");
assert_se(pidref_set_pidfd(&b, a.fd) >= 0);
assert_se(pidref_equal(&a, &b));
assert_se(pidref_set_pidfd_take(&c, b.fd) >= 0);
ASSERT_OK(pidref_set_pidfd(&b, a.fd));
ASSERT_TRUE(pidref_equal(&a, &b));
ASSERT_OK(pidref_set_pidfd_take(&c, b.fd));
b.fd = -EBADF;
assert_se(pidref_equal(&a, &c));
assert_se(pidref_set_pidfd_consume(&d, TAKE_FD(c.fd)) >= 0);
assert_se(pidref_equal(&a, &d));
ASSERT_TRUE(pidref_equal(&a, &c));
ASSERT_OK(pidref_set_pidfd_consume(&d, TAKE_FD(c.fd)));
ASSERT_TRUE(pidref_equal(&a, &d));
}
TEST(pidref_is_self) {
_cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
assert_se(pidref_set_self(&pidref) >= 0);
assert_se(pidref_is_self(&pidref));
ASSERT_OK(pidref_set_self(&pidref));
ASSERT_TRUE(pidref_is_self(&pidref));
assert_se(!pidref_is_self(NULL));
assert_se(!pidref_is_self(&PIDREF_NULL));
assert_se(pidref_is_self(&PIDREF_MAKE_FROM_PID(getpid_cached())));
assert_se(!pidref_is_self(&PIDREF_MAKE_FROM_PID(getpid_cached()+1)));
ASSERT_FALSE(pidref_is_self(NULL));
ASSERT_FALSE(pidref_is_self(&PIDREF_NULL));
ASSERT_TRUE(pidref_is_self(&PIDREF_MAKE_FROM_PID(getpid_cached())));
ASSERT_FALSE(pidref_is_self(&PIDREF_MAKE_FROM_PID(getpid_cached()+1)));
}
TEST(pidref_copy) {
_cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
int r;
assert_se(pidref_copy(NULL, &pidref) >= 0);
assert_se(!pidref_is_set(&pidref));
ASSERT_OK(pidref_copy(NULL, &pidref));
ASSERT_FALSE(pidref_is_set(&pidref));
assert_se(pidref_copy(&PIDREF_NULL, &pidref) >= 0);
assert_se(!pidref_is_set(&pidref));
ASSERT_OK(pidref_copy(&PIDREF_NULL, &pidref));
ASSERT_FALSE(pidref_is_set(&pidref));
assert_se(pidref_copy(&PIDREF_MAKE_FROM_PID(getpid_cached()), &pidref) >= 0);
assert_se(pidref_is_self(&pidref));
ASSERT_OK(pidref_copy(&PIDREF_MAKE_FROM_PID(getpid_cached()), &pidref));
ASSERT_TRUE(pidref_is_self(&pidref));
pidref_done(&pidref);
r = pidref_copy(&PIDREF_MAKE_FROM_PID(1), &pidref);
if (r == -ESRCH)
return (void) log_tests_skipped_errno(r, "PID1 does not exist");
assert_se(r >= 0);
assert_se(pidref_equal(&pidref, &PIDREF_MAKE_FROM_PID(1)));
ASSERT_OK(r);
ASSERT_TRUE(pidref_equal(&pidref, &PIDREF_MAKE_FROM_PID(1)));
}
TEST(pidref_dup) {
_cleanup_(pidref_freep) PidRef *pidref = NULL;
int r;
assert_se(pidref_dup(NULL, &pidref) >= 0);
assert_se(pidref);
assert_se(!pidref_is_set(pidref));
ASSERT_OK(pidref_dup(NULL, &pidref));
ASSERT_NOT_NULL(pidref);
ASSERT_FALSE(pidref_is_set(pidref));
pidref = pidref_free(pidref);
assert_se(pidref_dup(&PIDREF_NULL, &pidref) >= 0);
assert_se(pidref);
assert_se(!pidref_is_set(pidref));
ASSERT_OK(pidref_dup(&PIDREF_NULL, &pidref));
ASSERT_NOT_NULL(pidref);
ASSERT_FALSE(pidref_is_set(pidref));
pidref = pidref_free(pidref);
assert_se(pidref_dup(&PIDREF_MAKE_FROM_PID(getpid_cached()), &pidref) >= 0);
assert_se(pidref_is_self(pidref));
ASSERT_OK(pidref_dup(&PIDREF_MAKE_FROM_PID(getpid_cached()), &pidref));
ASSERT_TRUE(pidref_is_self(pidref));
pidref = pidref_free(pidref);
r = pidref_dup(&PIDREF_MAKE_FROM_PID(1), &pidref);
if (r == -ESRCH)
return (void) log_tests_skipped_errno(r, "PID1 does not exist");
assert_se(r >= 0);
assert_se(pidref_equal(pidref, &PIDREF_MAKE_FROM_PID(1)));
ASSERT_OK(r);
ASSERT_TRUE(pidref_equal(pidref, &PIDREF_MAKE_FROM_PID(1)));
}
TEST(pidref_new_from_pid) {
_cleanup_(pidref_freep) PidRef *pidref = NULL;
int r;
assert_se(pidref_new_from_pid(-1, &pidref) == -ESRCH);
assert_se(!pidref);
ASSERT_ERROR(pidref_new_from_pid(-1, &pidref), ESRCH);
ASSERT_NULL(pidref);
assert_se(pidref_new_from_pid(0, &pidref) >= 0);
assert_se(pidref_is_self(pidref));
ASSERT_OK(pidref_new_from_pid(0, &pidref));
ASSERT_TRUE(pidref_is_self(pidref));
pidref = pidref_free(pidref);
assert_se(pidref_new_from_pid(getpid_cached(), &pidref) >= 0);
assert_se(pidref_is_self(pidref));
ASSERT_OK(pidref_new_from_pid(getpid_cached(), &pidref));
ASSERT_TRUE(pidref_is_self(pidref));
pidref = pidref_free(pidref);
r = pidref_new_from_pid(1, &pidref);
if (r == -ESRCH)
return (void) log_tests_skipped_errno(r, "PID1 does not exist");
assert_se(r >= 0);
assert_se(pidref_equal(pidref, &PIDREF_MAKE_FROM_PID(1)));
ASSERT_OK(r);
ASSERT_TRUE(pidref_equal(pidref, &PIDREF_MAKE_FROM_PID(1)));
}
TEST(pidref_kill) {
@ -160,9 +161,9 @@ TEST(pidref_kill) {
ASSERT_OK_POSITIVE(pidref_safe_fork("(test-pidref-kill)", FORK_DEATHSIG_SIGKILL|FORK_FREEZE, &pidref));
assert_se(pidref_kill(&pidref, SIGKILL) >= 0);
assert_se(pidref_wait_for_terminate(&pidref, &si) >= 0);
assert_se(si.si_signo == SIGCHLD);
ASSERT_OK(pidref_kill(&pidref, SIGKILL));
ASSERT_OK(pidref_wait_for_terminate(&pidref, &si));
ASSERT_EQ(si.si_signo, SIGCHLD);
}
TEST(pidref_kill_and_sigcont) {
@ -171,9 +172,9 @@ TEST(pidref_kill_and_sigcont) {
ASSERT_OK_POSITIVE(pidref_safe_fork("(test-pidref-kill-and-sigcont)", FORK_DEATHSIG_SIGTERM|FORK_FREEZE, &pidref));
assert_se(pidref_kill_and_sigcont(&pidref, SIGTERM) >= 0);
assert_se(pidref_wait_for_terminate(&pidref, &si) >= 0);
assert_se(si.si_signo == SIGCHLD);
ASSERT_OK(pidref_kill_and_sigcont(&pidref, SIGTERM));
ASSERT_OK(pidref_wait_for_terminate(&pidref, &si));
ASSERT_EQ(si.si_signo, SIGCHLD);
}
TEST(pidref_sigqueue) {
@ -182,9 +183,9 @@ TEST(pidref_sigqueue) {
ASSERT_OK_POSITIVE(pidref_safe_fork("(test-pidref-sigqueue)", FORK_DEATHSIG_SIGTERM|FORK_FREEZE, &pidref));
assert_se(pidref_sigqueue(&pidref, SIGTERM, 42) >= 0);
assert_se(pidref_wait_for_terminate(&pidref, &si) >= 0);
assert_se(si.si_signo == SIGCHLD);
ASSERT_OK(pidref_sigqueue(&pidref, SIGTERM, 42));
ASSERT_OK(pidref_wait_for_terminate(&pidref, &si));
ASSERT_EQ(si.si_signo, SIGCHLD);
}
TEST(pidref_done_sigkill_wait) {
@ -195,39 +196,41 @@ TEST(pidref_done_sigkill_wait) {
TEST(pidref_verify) {
_cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
int r;
assert_se(pidref_verify(NULL) == -ESRCH);
assert_se(pidref_verify(&PIDREF_NULL) == -ESRCH);
ASSERT_ERROR(pidref_verify(NULL), ESRCH);
ASSERT_ERROR(pidref_verify(&PIDREF_NULL), ESRCH);
assert_se(pidref_verify(&PIDREF_MAKE_FROM_PID(1)) == 1);
assert_se(pidref_verify(&PIDREF_MAKE_FROM_PID(getpid_cached())) == 0);
ASSERT_OK_POSITIVE(pidref_verify(&PIDREF_MAKE_FROM_PID(1)));
ASSERT_OK_ZERO(pidref_verify(&PIDREF_MAKE_FROM_PID(getpid_cached())));
assert_se(pidref_set_self(&pidref) >= 0);
assert_se(pidref_verify(&pidref) == (pidref.fd >= 0));
ASSERT_OK(pidref_set_self(&pidref));
ASSERT_OK(r = pidref_verify(&pidref));
ASSERT_EQ(r, (pidref.fd >= 0));
}
TEST(pidref_is_automatic) {
assert_se(!pidref_is_automatic(NULL));
assert_se(!pidref_is_automatic(&PIDREF_NULL));
assert_se(!pidref_is_automatic(&PIDREF_MAKE_FROM_PID(1)));
assert_se(!pidref_is_automatic(&PIDREF_MAKE_FROM_PID(getpid_cached())));
assert_se(pidref_is_automatic(&PIDREF_AUTOMATIC));
ASSERT_FALSE(pidref_is_automatic(NULL));
ASSERT_FALSE(pidref_is_automatic(&PIDREF_NULL));
ASSERT_FALSE(pidref_is_automatic(&PIDREF_MAKE_FROM_PID(1)));
ASSERT_FALSE(pidref_is_automatic(&PIDREF_MAKE_FROM_PID(getpid_cached())));
ASSERT_TRUE(pidref_is_automatic(&PIDREF_AUTOMATIC));
assert_se(!pid_is_automatic(0));
assert_se(!pid_is_automatic(1));
assert_se(!pid_is_automatic(getpid_cached()));
assert_se(pid_is_automatic(PID_AUTOMATIC));
ASSERT_FALSE(pid_is_automatic(0));
ASSERT_FALSE(pid_is_automatic(1));
ASSERT_FALSE(pid_is_automatic(getpid_cached()));
ASSERT_TRUE(pid_is_automatic(PID_AUTOMATIC));
assert_se(!pidref_is_set(&PIDREF_AUTOMATIC));
assert_se(!pid_is_valid(PID_AUTOMATIC));
ASSERT_FALSE(pidref_is_set(&PIDREF_AUTOMATIC));
ASSERT_FALSE(pid_is_valid(PID_AUTOMATIC));
}
TEST(pidref_is_remote) {
assert_se(!pidref_is_remote(NULL));
assert_se(!pidref_is_remote(&PIDREF_NULL));
assert_se(!pidref_is_remote(&PIDREF_MAKE_FROM_PID(1)));
assert_se(!pidref_is_remote(&PIDREF_MAKE_FROM_PID(getpid_cached())));
assert_se(!pidref_is_remote(&PIDREF_AUTOMATIC));
ASSERT_FALSE(pidref_is_remote(NULL));
ASSERT_FALSE(pidref_is_remote(&PIDREF_NULL));
ASSERT_FALSE(pidref_is_remote(&PIDREF_MAKE_FROM_PID(1)));
ASSERT_FALSE(pidref_is_remote(&PIDREF_MAKE_FROM_PID(getpid_cached())));
ASSERT_FALSE(pidref_is_remote(&PIDREF_AUTOMATIC));
PidRef p = {
.pid = 1,
@ -235,13 +238,31 @@ TEST(pidref_is_remote) {
.fd_id = 4711,
};
assert_se(pidref_is_set(&p));
assert_se(pidref_is_remote(&p));
assert_se(!pidref_is_automatic(&p));
assert_se(pidref_kill(&p, SIGTERM) == -EREMOTE);
assert_se(pidref_kill_and_sigcont(&p, SIGTERM) == -EREMOTE);
assert_se(pidref_wait_for_terminate(&p, /* ret= */ NULL) == -EREMOTE);
assert_se(pidref_verify(&p) == -EREMOTE);
ASSERT_TRUE(pidref_is_set(&p));
ASSERT_TRUE(pidref_is_remote(&p));
ASSERT_FALSE(pidref_is_automatic(&p));
ASSERT_ERROR(pidref_kill(&p, SIGTERM), EREMOTE);
ASSERT_ERROR(pidref_kill_and_sigcont(&p, SIGTERM), EREMOTE);
ASSERT_ERROR(pidref_wait_for_terminate(&p, NULL), EREMOTE);
ASSERT_ERROR(pidref_verify(&p), EREMOTE);
}
TEST(pidref_wait_for_terminate_timeout) {
_cleanup_(pidref_done_sigkill_wait) PidRef pidref = PIDREF_NULL;
siginfo_t si;
/* Test successful termination within timeout */
ASSERT_OK(pidref_safe_fork("(test-pidref-wait-timeout)", FORK_DEATHSIG_SIGKILL|FORK_FREEZE, &pidref));
assert_se(pidref_kill(&pidref, SIGKILL) >= 0);
ASSERT_OK(pidref_wait_for_terminate_full(&pidref, 5 * USEC_PER_SEC, &si));
ASSERT_EQ(si.si_signo, SIGCHLD);
pidref_done(&pidref);
/* Test timeout when process doesn't terminate */
ASSERT_OK(pidref_safe_fork("(test-pidref-wait-timeout-expired)", FORK_DEATHSIG_SIGKILL|FORK_FREEZE, &pidref));
ASSERT_ERROR(pidref_wait_for_terminate_full(&pidref, 100 * USEC_PER_MSEC, NULL), ETIMEDOUT);
}
DEFINE_TEST_MAIN(LOG_DEBUG);

View File

@ -263,7 +263,6 @@ TEST(pid_get_cmdline_harder) {
_cleanup_close_ int fd = -EBADF;
_cleanup_free_ char *line = NULL;
_cleanup_strv_free_ char **args = NULL;
pid_t pid;
int r;
if (geteuid() != 0) {
@ -286,20 +285,8 @@ TEST(pid_get_cmdline_harder) {
}
#endif
pid = fork();
if (pid > 0) {
siginfo_t si;
(void) wait_for_terminate(pid, &si);
ASSERT_EQ(si.si_code, CLD_EXITED);
ASSERT_OK_ZERO(si.si_status);
return;
}
ASSERT_OK_ZERO(pid);
r = ASSERT_OK(safe_fork("(cmdline)", FORK_WAIT|FORK_LOG|FORK_DEATHSIG_SIGKILL, /* ret_pid= */ NULL));
if (r == 0) {
r = detach_mount_namespace();
if (r < 0) {
log_warning_errno(r, "detach mount namespace failed: %m");
@ -572,11 +559,12 @@ TEST(pid_get_cmdline_harder) {
safe_close(fd);
_exit(EXIT_SUCCESS);
}
}
TEST(getpid_cached) {
siginfo_t si;
pid_t a, b, c, d, e, f, child;
pid_t a, b, c, d, e, f;
int r;
a = getpid();
b = getpid_cached();
@ -585,10 +573,9 @@ TEST(getpid_cached) {
ASSERT_EQ(a, b);
ASSERT_EQ(a, c);
child = fork();
ASSERT_OK_ERRNO(child);
r = ASSERT_OK(safe_fork("(getpid)", FORK_WAIT|FORK_LOG|FORK_DEATHSIG_SIGKILL, /* ret_pid= */ NULL));
if (child == 0) {
if (r == 0) {
/* In child */
a = getpid();
b = getpid_cached();
@ -606,10 +593,6 @@ TEST(getpid_cached) {
ASSERT_EQ(a, d);
ASSERT_EQ(a, e);
ASSERT_EQ(a, f);
ASSERT_OK(wait_for_terminate(child, &si));
ASSERT_EQ(si.si_status, 0);
ASSERT_EQ(si.si_code, CLD_EXITED);
}
TEST(getpid_measure) {
@ -641,8 +624,6 @@ TEST(safe_fork) {
pid_t pid;
int r;
BLOCK_SIGNALS(SIGCHLD);
r = safe_fork("(test-child)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_DEATHSIG_SIGTERM|FORK_REARRANGE_STDIO|FORK_REOPEN_LOG, &pid);
ASSERT_OK(r);
@ -653,11 +634,14 @@ TEST(safe_fork) {
_exit(88);
}
ASSERT_OK(wait_for_terminate(pid, &status));
_cleanup_(pidref_done) PidRef child = PIDREF_NULL;
ASSERT_OK(pidref_set_pid(&child, pid));
ASSERT_OK(pidref_wait_for_terminate(&child, &status));
ASSERT_EQ(status.si_code, CLD_EXITED);
ASSERT_EQ(status.si_status, 88);
_cleanup_(pidref_done) PidRef child = PIDREF_NULL;
pidref_done(&child);
r = pidref_safe_fork("(test-child)", FORK_DETACH, &child);
if (r == 0) {
/* Don't freeze so this doesn't linger around forever in case something goes wrong. */

View File

@ -13,7 +13,7 @@
int main(int argc, char *argv[]) {
_cleanup_(rm_rf_physical_and_freep) char *runtime_dir = NULL;
_cleanup_(manager_freep) Manager *m = NULL;
Unit *idle_ok, *idle_bad, *rr_ok, *rr_bad, *rr_sched;
Unit *idle_ok, *idle_bad, *rr_ok, *rr_bad, *rr_sched, *ext_ok;
Service *ser;
int r;
@ -76,5 +76,11 @@ int main(int argc, char *argv[]) {
assert_se(ser->exec_context.cpu_sched_policy == SCHED_RR);
assert_se(ser->exec_context.cpu_sched_priority == 99);
/* load ext ok */
assert_se(manager_load_startable_unit_or_warn(m, "sched_ext_ok.service", NULL, &ext_ok) >= 0);
ser = SERVICE(ext_ok);
assert_se(ser->exec_context.cpu_sched_policy == SCHED_EXT);
assert_se(ser->exec_context.cpu_sched_priority == 0);
return EXIT_SUCCESS;
}

View File

@ -143,7 +143,7 @@ static int run(int argc, char *argv[]) {
assert_se(event = udev_event_new(dev, NULL, EVENT_TEST_RULE_RUNNER));
assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, SIGHUP, SIGCHLD) >= 0);
assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, SIGHUP) >= 0);
/* do what devtmpfs usually provides us */
if (sd_device_get_devname(dev, &devname) >= 0) {

View File

@ -7,7 +7,6 @@
#include "alloc-util.h"
#include "mountpoint-util.h"
#include "path-util.h"
#include "signal-util.h"
#include "string-util.h"
#include "strv.h"
#include "tests.h"
@ -104,8 +103,6 @@ int main(int argc, char *argv[]) {
test_setup_logging(LOG_DEBUG);
assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGCHLD) >= 0);
test_event_spawn_cat(true, SIZE_MAX);
test_event_spawn_cat(false, SIZE_MAX);
test_event_spawn_cat(true, 5);

View File

@ -390,7 +390,7 @@ void manager_revert(Manager *manager) {
manager_kill_workers(manager, SIGTERM);
}
static int on_sigchld(sd_event_source *s, const siginfo_t *si, void *userdata) {
static int on_worker_exit(sd_event_source *s, const siginfo_t *si, void *userdata) {
_cleanup_(worker_freep) Worker *worker = ASSERT_PTR(userdata);
sd_device *dev = worker->event ? ASSERT_PTR(worker->event->dev) : NULL;
@ -452,11 +452,11 @@ static int worker_new(Worker **ret, Manager *manager, sd_device_monitor *worker_
if (r < 0)
return r;
r = event_add_child_pidref(manager->event, &worker->child_event_source, &worker->pidref, WEXITED, on_sigchld, worker);
r = event_add_child_pidref(manager->event, &worker->child_event_source, &worker->pidref, WEXITED, on_worker_exit, worker);
if (r < 0)
return r;
r = sd_event_source_set_priority(worker->child_event_source, EVENT_PRIORITY_WORKER_SIGCHLD);
r = sd_event_source_set_priority(worker->child_event_source, EVENT_PRIORITY_WORKER_EXIT);
if (r < 0)
return r;
@ -1363,9 +1363,6 @@ static int manager_setup_event(Manager *manager) {
assert(manager);
/* block SIGCHLD for listening child events. */
assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGCHLD) >= 0);
r = sd_event_default(&e);
if (r < 0)
return log_error_errno(r, "Failed to allocate event loop: %m");

View File

@ -17,13 +17,13 @@
/* This must have a higher priority than the worker notification, to make IN_IGNORED event received earlier
* than notifications about requests of adding/removing inotify watches. */
#define EVENT_PRIORITY_INOTIFY_WATCH (SD_EVENT_PRIORITY_NORMAL - 4)
/* This must have a higher priority than the worker SIGCHLD event, to make notifications about completions of
* processing events received before SIGCHLD. */
/* This must have a higher priority than the worker exit event, to make notifications about completions of
* processing events received before exit. */
#define EVENT_PRIORITY_WORKER_NOTIFY (SD_EVENT_PRIORITY_NORMAL - 3)
/* This should have a higher priority than timer events about killing long running worker processes or idle
* worker processes. */
#define EVENT_PRIORITY_WORKER_SIGCHLD (SD_EVENT_PRIORITY_NORMAL - 2)
/* As said in the above, this should have a lower proority than the SIGCHLD event source. */
#define EVENT_PRIORITY_WORKER_EXIT (SD_EVENT_PRIORITY_NORMAL - 2)
/* As said in the above, this should have a lower proority than the exit event source. */
#define EVENT_PRIORITY_WORKER_TIMER (SD_EVENT_PRIORITY_NORMAL - 1)
/* This should have a lower priority than most event sources, but let's process earlier than varlink and the
* legacy control socket. */

View File

@ -146,7 +146,7 @@ static int on_spawn_timeout_warning(sd_event_source *s, uint64_t usec, void *use
return 1;
}
static int on_spawn_sigchld(sd_event_source *s, const siginfo_t *si, void *userdata) {
static int on_spawn_exit(sd_event_source *s, const siginfo_t *si, void *userdata) {
Spawn *spawn = ASSERT_PTR(userdata);
int ret = -EIO;
@ -175,7 +175,7 @@ static int on_spawn_sigchld(sd_event_source *s, const siginfo_t *si, void *userd
static int spawn_wait(Spawn *spawn) {
_cleanup_(sd_event_unrefp) sd_event *e = NULL;
_cleanup_(sd_event_source_disable_unrefp) sd_event_source *sigchld_source = NULL;
_cleanup_(sd_event_source_disable_unrefp) sd_event_source *child_source = NULL;
_cleanup_(sd_event_source_disable_unrefp) sd_event_source *stdout_source = NULL;
_cleanup_(sd_event_source_disable_unrefp) sd_event_source *stderr_source = NULL;
int r;
@ -214,11 +214,12 @@ static int spawn_wait(Spawn *spawn) {
return log_device_debug_errno(spawn->device, r, "Failed to create stderr event source: %m");
}
r = event_add_child_pidref(e, &sigchld_source, &spawn->pidref, WEXITED, on_spawn_sigchld, spawn);
r = event_add_child_pidref(e, &child_source, &spawn->pidref, WEXITED, on_spawn_exit, spawn);
if (r < 0)
return log_device_debug_errno(spawn->device, r, "Failed to create sigchild event source: %m");
/* SIGCHLD should be processed after IO is complete */
r = sd_event_source_set_priority(sigchld_source, SD_EVENT_PRIORITY_NORMAL + 1);
/* Child exit should be processed after IO is complete */
r = sd_event_source_set_priority(child_source, SD_EVENT_PRIORITY_NORMAL + 1);
if (r < 0)
return log_device_debug_errno(spawn->device, r, "Failed to set priority to sigchild event source: %m");

View File

@ -48,7 +48,7 @@ static int on_worker_exit(sd_event_source *s, const siginfo_t *si, void *userdat
else if (si->si_code == CLD_DUMPED)
log_warning("Worker " PID_FMT " dumped core by signal %s, ignoring.", si->si_pid, signal_to_string(si->si_status));
else
log_warning("Can't handle SIGCHLD of this type");
log_warning("Can't handle exit code of this type");
(void) start_workers(m, /* explicit_request= */ false); /* Fill up workers again if we fell below the low watermark */
return 0;

View File

@ -8,7 +8,6 @@
#include "daemon-util.h"
#include "log.h"
#include "main-func.h"
#include "signal-util.h"
#include "userdbd-manager.h"
/* This service offers two Varlink services, both implementing io.systemd.UserDatabase:
@ -39,8 +38,6 @@ static int run(int argc, char *argv[]) {
if (setenv("SYSTEMD_BYPASS_USERDB", "io.systemd.NameServiceSwitch:io.systemd.Multiplexer:io.systemd.DropIn", 1) < 0)
return log_error_errno(errno, "Failed to set $SYSTEMD_BYPASS_USERDB: %m");
assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGCHLD) >= 0);
r = manager_new(&m);
if (r < 0)
return log_error_errno(r, "Could not create manager: %m");

View File

@ -23,6 +23,7 @@
#include "locale-util.h"
#include "log.h"
#include "main-func.h"
#include "pidref.h"
#include "proc-cmdline.h"
#include "process-util.h"
#include "stdio-util.h"
@ -255,7 +256,6 @@ assert_cc(STRLEN(SYSTEMD_DEFAULT_KEYMAP) > 0);
static int keyboard_load_and_wait(const char *vc, Context *c, bool utf8) {
const char* args[8];
unsigned i = 0;
pid_t pid;
int r;
assert(vc);
@ -286,7 +286,8 @@ static int keyboard_load_and_wait(const char *vc, Context *c, bool utf8) {
log_debug("Executing \"%s\"...", strnull(cmd));
}
r = safe_fork("(loadkeys)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_RLIMIT_NOFILE_SAFE|FORK_LOG, &pid);
_cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
r = pidref_safe_fork("(loadkeys)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_RLIMIT_NOFILE_SAFE|FORK_LOG, &pidref);
if (r < 0)
return r;
if (r == 0) {
@ -294,13 +295,12 @@ static int keyboard_load_and_wait(const char *vc, Context *c, bool utf8) {
_exit(EXIT_FAILURE);
}
return wait_for_terminate_and_check(KBD_LOADKEYS, pid, WAIT_LOG);
return pidref_wait_for_terminate_and_check(KBD_LOADKEYS, &pidref, WAIT_LOG);
}
static int font_load_and_wait(const char *vc, Context *c) {
const char* args[9];
unsigned i = 0;
pid_t pid;
int r;
assert(vc);
@ -337,7 +337,8 @@ static int font_load_and_wait(const char *vc, Context *c) {
log_debug("Executing \"%s\"...", strnull(cmd));
}
r = safe_fork("(setfont)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_RLIMIT_NOFILE_SAFE|FORK_LOG, &pid);
_cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
r = pidref_safe_fork("(setfont)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_RLIMIT_NOFILE_SAFE|FORK_LOG, &pidref);
if (r < 0)
return r;
if (r == 0) {
@ -348,7 +349,7 @@ static int font_load_and_wait(const char *vc, Context *c) {
/* setfont returns EX_OSERR when ioctl(KDFONTOP/PIO_FONTX/PIO_FONTX) fails. This might mean various
* things, but in particular lack of a graphical console. Let's be generous and not treat this as an
* error. */
r = wait_for_terminate_and_check(KBD_SETFONT, pid, WAIT_LOG_ABNORMAL);
r = pidref_wait_for_terminate_and_check(KBD_SETFONT, &pidref, WAIT_LOG_ABNORMAL);
if (r == EX_OSERR)
log_notice(KBD_SETFONT " failed with a \"system error\" (EX_OSERR), ignoring.");
else if (r >= 0 && r != EXIT_SUCCESS)

Some files were not shown because too many files have changed in this diff Show More