summaryrefslogtreecommitdiff
path: root/src/basic/process-util.c
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2017-12-29 18:01:37 +0100
committerSven Eden <yamakuzure@gmx.net>2018-05-30 07:49:51 +0200
commitda33559d0bb19673cd487ed8ca8284e6c84971c1 (patch)
tree1201383d1ed38d7568f160dd4c09e93ff8f81742 /src/basic/process-util.c
parent069824bd6c91476242902f7a21d27df11ce18aac (diff)
process-spec: add another flag FORK_WAIT to safe_fork()
This new flag will cause safe_fork() to wait for the forked off child before returning. This allows us to unify a number of cases where we immediately wait on the forked off child, witout running any code in the parent after the fork, and without direct interest in the precise exit status of the process, except recgonizing EXIT_SUCCESS vs everything else.
Diffstat (limited to 'src/basic/process-util.c')
-rw-r--r--src/basic/process-util.c41
1 files changed, 31 insertions, 10 deletions
diff --git a/src/basic/process-util.c b/src/basic/process-util.c
index 7329dccfd..c60ca7516 100644
--- a/src/basic/process-util.c
+++ b/src/basic/process-util.c
@@ -1175,7 +1175,7 @@ int safe_fork_full(
pid_t *ret_pid) {
pid_t original_pid, pid;
- sigset_t saved_ss;
+ sigset_t saved_ss, ss;
bool block_signals;
int prio, r;
@@ -1186,20 +1186,33 @@ int safe_fork_full(
original_pid = getpid_cached();
- block_signals = flags & (FORK_RESET_SIGNALS|FORK_DEATHSIG);
+ if (flags & (FORK_RESET_SIGNALS|FORK_DEATHSIG)) {
- if (block_signals) {
- sigset_t ss;
+ /* We temporarily block all signals, so that the new child has them blocked initially. This way, we can
+ * be sure that SIGTERMs are not lost we might send to the child. */
- /* We temporarily block all signals, so that the new child has them blocked initially. This way, we can be sure
- * that SIGTERMs are not lost we might send to the child. */
if (sigfillset(&ss) < 0)
return log_full_errno(prio, errno, "Failed to reset signal set: %m");
- if (sigprocmask(SIG_SETMASK, &ss, &saved_ss) < 0)
- return log_full_errno(prio, errno, "Failed to reset signal mask: %m");
+ block_signals = true;
+
+ } else if (flags & FORK_WAIT) {
+
+ /* Let's block SIGCHLD at least, so that we can safely watch for the child process */
+
+ if (sigemptyset(&ss) < 0)
+ return log_full_errno(prio, errno, "Failed to clear signal set: %m");
+
+ if (sigaddset(&ss, SIGCHLD) < 0)
+ return log_full_errno(prio, errno, "Failed to add SIGCHLD to signal set: %m");
+
+ block_signals = true;
}
+ if (block_signals)
+ if (sigprocmask(SIG_SETMASK, &ss, &saved_ss) < 0)
+ return log_full_errno(prio, errno, "Failed to set signal mask: %m");
+
pid = fork();
if (pid < 0) {
r = -errno;
@@ -1212,11 +1225,19 @@ int safe_fork_full(
if (pid > 0) {
/* We are in the parent process */
+ log_debug("Successfully forked off '%s' as PID " PID_FMT ".", strna(name), pid);
+
+ if (flags & FORK_WAIT) {
+ r = wait_for_terminate_and_check(name, pid, (flags & FORK_LOG ? WAIT_LOG : 0));
+ if (r < 0)
+ return r;
+ if (r != EXIT_SUCCESS) /* exit status > 0 should be treated as failure, too */
+ return -EPROTO;
+ }
+
if (block_signals) /* undo what we did above */
(void) sigprocmask(SIG_SETMASK, &saved_ss, NULL);
- log_debug("Sucessfully forked off '%s' as PID " PID_FMT ".", strna(name), pid);
-
if (ret_pid)
*ret_pid = pid;