static int fork_and_exec_process(const char* child, char** argv, char **env, int fd) {
_cleanup_free_ char *joined = NULL;
- pid_t parent_pid, child_pid;
+ pid_t child_pid;
+ int r;
joined = strv_join(argv, " ");
if (!joined)
return log_oom();
- parent_pid = getpid_cached();
-
- child_pid = fork();
- if (child_pid < 0)
- return log_error_errno(errno, "Failed to fork: %m");
-
- /* In the child */
- if (child_pid == 0) {
-
- (void) reset_all_signal_handlers();
- (void) reset_signal_mask();
-
- /* Make sure the child goes away when the parent dies */
- if (prctl(PR_SET_PDEATHSIG, SIGTERM) < 0)
- _exit(EXIT_FAILURE);
-
- /* Check whether our parent died before we were able
- * to set the death signal */
- if (getppid() != parent_pid)
- _exit(EXIT_SUCCESS);
-
+ r = safe_fork("(activate)", FORK_RESET_SIGNALS|FORK_DEATHSIG, &child_pid);
+ if (r < 0)
+ return log_error_errno(r, "Failed to fork: %m");
+ if (r == 0) {
+ /* In the child */
exec_process(child, argv, env, fd, 1);
_exit(EXIT_FAILURE);
}
- log_info("Spawned %s (%s) as PID %d", child, joined, child_pid);
+ log_info("Spawned %s (%s) as PID " PID_FMT ".", child, joined, child_pid);
return 0;
}
}
int asynchronous_sync(void) {
- pid_t pid;
+ int r;
/* This forks off an invocation of fork() as a child process, in order to initiate synchronization to
* disk. Note that we implement this as helper process rather than thread as we don't want the sync() to hang our
* original process ever, and a thread would do that as the process can't exit with threads hanging in blocking
* syscalls. */
- log_debug("Spawning new process for sync");
-
- pid = fork();
- if (pid < 0)
- return -errno;
-
- if (pid == 0) {
+ r = safe_fork("(sd-sync)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS, NULL);
+ if (r < 0)
+ return r;
+ if (r == 0) {
/* Child process */
-
- (void) rename_process("(sd-sync)");
-
- (void) reset_all_signal_handlers();
- (void) reset_signal_mask();
-
- (void) close_all_fds(NULL, 0);
-
(void) sync();
_exit(EXIT_SUCCESS);
}
} SpecNextResult;
int calendar_spec_next_usec(const CalendarSpec *spec, usec_t usec, usec_t *next) {
+ SpecNextResult *shared, tmp;
pid_t pid;
- SpecNextResult *shared;
- SpecNextResult tmp;
int r;
if (isempty(spec->timezone))
if (shared == MAP_FAILED)
return negative_errno();
- pid = fork();
-
- if (pid == -1) {
- int fork_errno = errno;
+ r = safe_fork("(sd-calendar)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_DEATHSIG, &pid);
+ if (r < 0) {
(void) munmap(shared, sizeof *shared);
- return -fork_errno;
+ return r;
}
-
- if (pid == 0) {
+ if (r == 0) {
if (setenv("TZ", spec->timezone, 1) != 0) {
shared->return_value = negative_errno();
_exit(EXIT_FAILURE);
static int do_spawn(const char *path, char *argv[], int stdout_fd, pid_t *pid) {
pid_t _pid;
+ int r;
if (null_or_empty_path(path)) {
log_debug("%s is empty (a mask).", path);
return 0;
}
- _pid = fork();
- if (_pid < 0)
- return log_error_errno(errno, "Failed to fork: %m");
- if (_pid == 0) {
+ r = safe_fork("(direxec)", FORK_DEATHSIG, &_pid);
+ if (r < 0)
+ return log_error_errno(r, "Failed to fork: %m");
+ if (r == 0) {
char *_argv[2];
- assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0);
-
if (stdout_fd >= 0) {
/* If the fd happens to be in the right place, go along with that */
if (stdout_fd != STDOUT_FILENO &&
* If callbacks is nonnull, execution is serial. Otherwise, we default to parallel.
*/
- (void) reset_all_signal_handlers();
- (void) reset_signal_mask();
-
- assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0);
-
r = conf_files_list_strv(&paths, NULL, NULL, CONF_FILES_EXECUTABLE, (const char* const*) directories);
if (r < 0)
return r;
* them to finish. Optionally a timeout is applied. If a file with the same name
* exists in more than one directory, the earliest one wins. */
- executor_pid = fork();
- if (executor_pid < 0)
- return log_error_errno(errno, "Failed to fork: %m");
-
- if (executor_pid == 0) {
+ r = safe_fork("(sd-executor)", FORK_RESET_SIGNALS|FORK_DEATHSIG, &executor_pid);
+ if (r < 0)
+ return log_error_errno(r, "Failed to fork: %m");
+ if (r == 0) {
r = do_execute(dirs, timeout, callbacks, callback_args, fd, argv);
_exit(r < 0 ? EXIT_FAILURE : EXIT_SUCCESS);
}
#include "stat-util.h"
#include "string-table.h"
#include "string-util.h"
+#include "terminal-util.h"
#include "user-util.h"
#include "util.h"
return -EPERM;
}
+int safe_fork_full(
+ const char *name,
+ const int except_fds[],
+ size_t n_except_fds,
+ ForkFlags flags,
+ pid_t *ret_pid) {
+
+ pid_t original_pid, pid;
+ sigset_t saved_ss;
+ bool block_signals;
+ int r;
+
+ /* A wrapper around fork(), that does a couple of important initializations in addition to mere forking. Always
+ * returns the child's PID in *ret_pid. Returns == 0 in the child, and > 0 in the parent. */
+
+ original_pid = getpid_cached();
+
+ block_signals = 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. */
+ if (sigfillset(&ss) < 0)
+ return log_debug_errno(errno, "Failed to reset signal set: %m");
+
+ if (sigprocmask(SIG_SETMASK, &ss, &saved_ss) < 0)
+ return log_debug_errno(errno, "Failed to reset signal mask: %m");
+ }
+
+ pid = fork();
+ if (pid < 0) {
+ r = -errno;
+
+ if (block_signals) /* undo what we did above */
+ (void) sigprocmask(SIG_SETMASK, &saved_ss, NULL);
+
+ return log_debug_errno(r, "Failed to fork: %m");
+ }
+ if (pid > 0) {
+ /* We are in the parent process */
+
+ 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;
+
+ return 1;
+ }
+
+ /* We are in the child process */
+
+ if (flags & FORK_REOPEN_LOG) {
+ /* Close the logs if requested, before we log anything. And make sure we reopen it if needed. */
+ log_close();
+ log_set_open_when_needed(true);
+ }
+
+ if (name) {
+ r = rename_process(name);
+ if (r < 0)
+ log_debug_errno(r, "Failed to rename process, ignoring: %m");
+ }
+
+ if (flags & FORK_DEATHSIG)
+ if (prctl(PR_SET_PDEATHSIG, SIGTERM) < 0) {
+ log_debug_errno(errno, "Failed to set death signal: %m");
+ _exit(EXIT_FAILURE);
+ }
+
+ if (flags & FORK_RESET_SIGNALS) {
+ r = reset_all_signal_handlers();
+ if (r < 0) {
+ log_debug_errno(r, "Failed to reset signal handlers: %m");
+ _exit(EXIT_FAILURE);
+ }
+
+ /* This implicitly undoes the signal mask stuff we did before the fork()ing above */
+ r = reset_signal_mask();
+ if (r < 0) {
+ log_debug_errno(r, "Failed to reset signal mask: %m");
+ _exit(EXIT_FAILURE);
+ }
+ } else if (block_signals) { /* undo what we did above */
+ if (sigprocmask(SIG_SETMASK, &saved_ss, NULL) < 0) {
+ log_debug_errno(errno, "Failed to restore signal mask: %m");
+ _exit(EXIT_FAILURE);
+ }
+ }
+
+ if (flags & FORK_DEATHSIG) {
+ /* Let's see if the parent PID is still the one we started from? If not, then the parent
+ * already died by the time we set PR_SET_PDEATHSIG, hence let's emulate the effect */
+
+ if (getppid() != original_pid) {
+ log_debug("Parent died early, raising SIGTERM.");
+ (void) raise(SIGTERM);
+ _exit(EXIT_FAILURE);
+ }
+ }
+
+ if (flags & FORK_CLOSE_ALL_FDS) {
+ /* Close the logs here in case it got reopened above, as close_all_fds() would close them for us */
+ log_close();
+
+ r = close_all_fds(except_fds, n_except_fds);
+ if (r < 0) {
+ log_debug_errno(r, "Failed to close all file descriptors: %m");
+ _exit(EXIT_FAILURE);
+ }
+ }
+
+ /* When we were asked to reopen the logs, do so again now */
+ if (flags & FORK_REOPEN_LOG) {
+ log_open();
+ log_set_open_when_needed(false);
+ }
+
+ if (flags & FORK_NULL_STDIO) {
+ r = make_null_stdio();
+ if (r < 0) {
+ log_debug_errno(r, "Failed to connect stdin/stdout to /dev/null: %m");
+ _exit(EXIT_FAILURE);
+ }
+ }
+
+ if (ret_pid)
+ *ret_pid = getpid_cached();
+
+ return 0;
+}
+
static const char *const ioprio_class_table[] = {
[IOPRIO_CLASS_NONE] = "none",
[IOPRIO_CLASS_RT] = "realtime",
pid_t getpid_cached(void);
int must_be_root(void);
+
+typedef enum ForkFlags {
+ FORK_RESET_SIGNALS = 1U << 0,
+ FORK_CLOSE_ALL_FDS = 1U << 1,
+ FORK_DEATHSIG = 1U << 2,
+ FORK_NULL_STDIO = 1U << 3,
+ FORK_REOPEN_LOG = 1U << 4,
+} ForkFlags;
+
+int safe_fork_full(const char *name, const int except_fds[], size_t n_except_fds, ForkFlags flags, pid_t *ret_pid);
+
+static inline int safe_fork(const char *name, ForkFlags flags, pid_t *ret_pid) {
+ return safe_fork_full(name, NULL, 0, flags, ret_pid);
+}
if (socketpair(AF_UNIX, SOCK_DGRAM, 0, pair) < 0)
return -errno;
- child = fork();
- if (child < 0)
- return -errno;
-
- if (child == 0) {
+ r = safe_fork("(sd-openpt)", FORK_RESET_SIGNALS|FORK_DEATHSIG, &child);
+ if (r < 0)
+ return r;
+ if (r == 0) {
int master;
pair[0] = safe_close(pair[0]);
if (socketpair(AF_UNIX, SOCK_DGRAM, 0, pair) < 0)
return -errno;
- child = fork();
- if (child < 0)
- return -errno;
-
- if (child == 0) {
+ r = safe_fork("(sd-terminal)", FORK_RESET_SIGNALS|FORK_DEATHSIG, &child);
+ if (r < 0)
+ return r;
+ if (r == 0) {
int master;
pair[0] = safe_close(pair[0]);
int parse_timestamp(const char *t, usec_t *usec) {
char *last_space, *tz = NULL;
ParseTimestampResult *shared, tmp;
- int r;
pid_t pid;
+ int r;
last_space = strrchr(t, ' ');
if (last_space != NULL && timezone_is_valid(last_space + 1))
if (shared == MAP_FAILED)
return negative_errno();
- pid = fork();
-
- if (pid == -1) {
- int fork_errno = errno;
+ r = safe_fork("(sd-timestamp)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_DEATHSIG, &pid);
+ if (r < 0) {
(void) munmap(shared, sizeof *shared);
- return -fork_errno;
+ return r;
}
-
- if (pid == 0) {
+ if (r == 0) {
bool with_tz = true;
if (setenv("TZ", tz, 1) != 0) {
int fork_agent(pid_t *pid, const int except[], unsigned n_except, const char *path, ...) {
bool stdout_is_tty, stderr_is_tty;
- pid_t parent_pid, agent_pid;
- sigset_t ss, saved_ss;
+ pid_t agent_pid;
unsigned n, i;
va_list ap;
char **l;
+ int r;
assert(pid);
assert(path);
/* Spawns a temporary TTY agent, making sure it goes away when
* we go away */
- parent_pid = getpid_cached();
-
- /* First 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 agent. */
- assert_se(sigfillset(&ss) >= 0);
- assert_se(sigprocmask(SIG_SETMASK, &ss, &saved_ss) >= 0);
-
- agent_pid = fork();
- if (agent_pid < 0) {
- assert_se(sigprocmask(SIG_SETMASK, &saved_ss, NULL) >= 0);
- return -errno;
- }
-
- if (agent_pid != 0) {
- assert_se(sigprocmask(SIG_SETMASK, &saved_ss, NULL) >= 0);
- *pid = agent_pid;
+ r = safe_fork_full("(sd-agent)", except, n_except, FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_CLOSE_ALL_FDS, &agent_pid);
+ if (r < 0)
+ return r;
+ if (r > 0)
return 0;
- }
- /* In the child:
- *
- * Make sure the agent goes away when the parent dies */
- if (prctl(PR_SET_PDEATHSIG, SIGTERM) < 0)
- _exit(EXIT_FAILURE);
-
- /* Make sure we actually can kill the agent, if we need to, in
- * case somebody invoked us from a shell script that trapped
- * SIGTERM or so... */
- (void) reset_all_signal_handlers();
- (void) reset_signal_mask();
-
- /* Check whether our parent died before we were able
- * to set the death signal and unblock the signals */
- if (getppid() != parent_pid)
- _exit(EXIT_SUCCESS);
-
- /* Don't leak fds to the agent */
- close_all_fds(except, n_except);
+ /* In the child: */
stdout_is_tty = isatty(STDOUT_FILENO);
stderr_is_tty = isatty(STDERR_FILENO);
parent_pid = getpid_cached();
- pam_pid = fork();
- if (pam_pid < 0) {
- r = -errno;
+ r = safe_fork("(sd-pam)", 0, &pam_pid);
+ if (r < 0)
goto fail;
- }
-
- if (pam_pid == 0) {
+ if (r == 0) {
int sig, ret = EXIT_PAM;
/* The child's job is to reset the PAM session on
* termination */
barrier_set_role(&barrier, BARRIER_CHILD);
- /* This string must fit in 10 chars (i.e. the length
- * of "/sbin/init"), to look pretty in /bin/ps */
- rename_process("(sd-pam)");
-
- /* Make sure we don't keep open the passed fds in this
- child. We assume that otherwise only those fds are
- open here that have been opened by PAM. */
- close_many(fds, n_fds);
+ /* Make sure we don't keep open the passed fds in this child. We assume that otherwise only those fds
+ * are open here that have been opened by PAM. */
+ (void) close_many(fds, n_fds);
/* Drop privileges - we don't need any to pam_close_session
* and this will make PR_SET_PDEATHSIG work in most cases.
if (pipe2(errno_pipe, O_CLOEXEC) < 0)
return -errno;
- pid = fork();
- if (pid < 0)
- return -errno;
-
- if (pid == 0) {
+ r = safe_fork("(sd-userns)", FORK_RESET_SIGNALS|FORK_DEATHSIG, &pid);
+ if (r < 0)
+ return r;
+ if (r == 0) {
_cleanup_close_ int fd = -1;
const char *a;
pid_t ppid;
/* Due to the possiblity of the sync operation hanging, we fork
* a child process and monitor the progress. If the timeout
* lapses, the assumption is that that particular sync stalled. */
- pid = fork();
- if (pid < 0) {
- log_error_errno(errno, "Failed to fork: %m");
+ r = safe_fork("(sd-sync)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS, &pid);
+ if (r < 0) {
+ log_error_errno(r, "Failed to fork: %m");
return;
}
-
- if (pid == 0) {
+ if (r == 0) {
/* Start the sync operation here in the child */
sync();
_exit(EXIT_SUCCESS);
log_info("Rebooting with kexec.");
- pid = fork();
- if (pid < 0)
- log_error_errno(errno, "Failed to fork: %m");
- else if (pid == 0) {
+ r = safe_fork("(sd-kexec)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS, &pid);
+ if (r < 0)
+ log_error_errno(r, "Failed to fork: %m");
+ if (r == 0) {
const char * const args[] = {
KEXEC, "-e", NULL
execv(args[0], (char * const *) args);
_exit(EXIT_FAILURE);
- } else
- wait_for_terminate_and_warn("kexec", pid, true);
+ }
+
+ (void) wait_for_terminate_and_warn("kexec", pid, true);
}
cmd = RB_AUTOBOOT;
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");
- r = unit_fork_helper_process(UNIT(s), &pid);
+ r = unit_fork_helper_process(UNIT(s), "(sd-listen)", &pid);
if (r < 0)
return log_unit_error_errno(UNIT(s), r, "Failed to fork off listener stub process: %m");
if (r == 0) {
/* We have to resolve the user names out-of-process, hence
* let's fork here. It's messy, but well, what can we do? */
- r = unit_fork_helper_process(UNIT(s), &pid);
+ r = unit_fork_helper_process(UNIT(s), "(sd-chown)", &pid);
if (r < 0)
return r;
if (r == 0) {
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");
- r = unit_fork_helper_process(UNIT(s), &pid);
+ r = unit_fork_helper_process(UNIT(s), "(sd-accept)", &pid);
if (r < 0)
return log_unit_error_errno(UNIT(s), r, "Failed to fork off accept stub process: %m");
if (r == 0) {
* fork a child process and set a timeout. If the timeout
* lapses, the assumption is that that particular remount
* failed. */
- pid = fork();
- if (pid < 0)
- return log_error_errno(errno, "Failed to fork: %m");
-
- if (pid == 0) {
+ r = safe_fork("(sd-remount)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS, &pid);
+ if (r < 0)
+ return log_error_errno(r, "Failed to fork: %m");
+ if (r == 0) {
log_info("Remounting '%s' read-only in with options '%s'.", m->path, options);
/* Start the mount operation here in the child */
* fork a child process and set a timeout. If the timeout
* lapses, the assumption is that that particular umount
* failed. */
- pid = fork();
- if (pid < 0)
- return log_error_errno(errno, "Failed to fork: %m");
-
- if (pid == 0) {
+ r = safe_fork("(sd-umount)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS, &pid);
+ if (r < 0)
+ return log_error_errno(r, "Failed to fork: %m");
+ if (r == 0) {
log_info("Unmounting '%s'.", m->path);
/* Start the mount operation here in the child Using MNT_FORCE
#include <errno.h>
#include <stdlib.h>
#include <string.h>
+#include <sys/prctl.h>
#include <sys/stat.h>
#include <unistd.h>
SET_FLAG(p->flags, EXEC_CGROUP_DELEGATE, UNIT_CGROUP_BOOL(u, delegate));
}
-int unit_fork_helper_process(Unit *u, pid_t *ret) {
- pid_t pid;
+int unit_fork_helper_process(Unit *u, const char *name, pid_t *ret) {
int r;
assert(u);
(void) unit_realize_cgroup(u);
- pid = fork();
- if (pid < 0)
- return -errno;
-
- if (pid == 0) {
+ r = safe_fork(name, FORK_REOPEN_LOG, ret);
+ if (r != 0)
+ return r;
- (void) default_signals(SIGNALS_CRASH_HANDLER, SIGNALS_IGNORE, -1);
- (void) ignore_signals(SIGPIPE, -1);
+ (void) default_signals(SIGNALS_CRASH_HANDLER, SIGNALS_IGNORE, -1);
+ (void) ignore_signals(SIGPIPE, -1);
- log_close();
- log_open();
+ (void) prctl(PR_SET_PDEATHSIG, SIGTERM);
- if (u->cgroup_path) {
- r = cg_attach_everywhere(u->manager->cgroup_supported, u->cgroup_path, 0, NULL, NULL);
- if (r < 0) {
- log_unit_error_errno(u, r, "Failed to join unit cgroup %s: %m", u->cgroup_path);
- _exit(EXIT_CGROUP);
- }
+ if (u->cgroup_path) {
+ r = cg_attach_everywhere(u->manager->cgroup_supported, u->cgroup_path, 0, NULL, NULL);
+ if (r < 0) {
+ log_unit_error_errno(u, r, "Failed to join unit cgroup %s: %m", u->cgroup_path);
+ _exit(EXIT_CGROUP);
}
-
- *ret = getpid_cached();
- return 0;
}
- *ret = pid;
- return 1;
+ return 0;
}
static void unit_update_dependency_mask(Unit *u, UnitDependency d, Unit *other, UnitDependencyInfo di) {
void unit_set_exec_params(Unit *s, ExecParameters *p);
-int unit_fork_helper_process(Unit *u, pid_t *ret);
+int unit_fork_helper_process(Unit *u, const char *name, pid_t *ret);
void unit_remove_dependencies(Unit *u, UnitDependencyMask mask);
/* Don't interfere with gdb and its handling of SIGINT. */
(void) ignore_signals(SIGINT, -1);
- pid = fork();
- if (pid < 0) {
- r = log_error_errno(errno, "Failed to fork(): %m");
+ r = safe_fork("(gdb)", FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_CLOSE_ALL_FDS, &pid);
+ if (r < 0) {
+ log_error_errno(r, "Failed to fork(): %m");
goto finish;
}
- if (pid == 0) {
- (void) reset_all_signal_handlers();
- (void) reset_signal_mask();
-
+ if (r == 0) {
execlp("gdb", "gdb", exe, path, NULL);
-
log_error_errno(errno, "Failed to invoke gdb: %m");
_exit(1);
}
static int found_override(const char *top, const char *bottom) {
_cleanup_free_ char *dest = NULL;
- int k;
pid_t pid;
+ int r;
assert(top);
assert(bottom);
if (null_or_empty_path(top) > 0)
return notify_override_masked(top, bottom);
- k = readlink_malloc(top, &dest);
- if (k >= 0) {
+ r = readlink_malloc(top, &dest);
+ if (r >= 0) {
if (equivalent(dest, bottom) > 0)
return notify_override_equivalent(top, bottom);
else
return notify_override_redirected(top, bottom);
}
- k = notify_override_overridden(top, bottom);
+ r = notify_override_overridden(top, bottom);
if (!arg_diff)
- return k;
+ return r;
putchar('\n');
fflush(stdout);
- pid = fork();
- if (pid < 0)
- return log_error_errno(errno, "Failed to fork off diff: %m");
- else if (pid == 0) {
-
- (void) reset_all_signal_handlers();
- (void) reset_signal_mask();
- assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0);
-
+ r = safe_fork("(diff)", FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_CLOSE_ALL_FDS, &pid);
+ if (r < 0)
+ return log_error_errno(pid, "Failed to fork off diff: %m");
+ if (r == 0) {
execlp("diff", "diff", "-us", "--", bottom, top, NULL);
log_error_errno(errno, "Failed to execute diff: %m");
_exit(EXIT_FAILURE);
wait_for_terminate_and_warn("diff", pid, false);
putchar('\n');
- return k;
+ return r;
}
static int enumerate_dir_d(
}
}
- pid = fork();
- if (pid < 0) {
- r = log_error_errno(errno, "fork(): %m");
+ r = safe_fork("(fsck)", FORK_RESET_SIGNALS|FORK_DEATHSIG, &pid);
+ if (r < 0) {
+ log_error_errno(r, "fork(): %m");
goto finish;
}
- if (pid == 0) {
+ if (r == 0) {
char dash_c[STRLEN("-C") + DECIMAL_STR_MAX(int) + 1];
int progress_socket = -1;
const char *cmdline[9];
/* Child */
- (void) reset_all_signal_handlers();
- (void) reset_signal_mask();
- assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0);
-
/* Close the reading side of the progress pipe */
progress_pipe[0] = safe_close(progress_pipe[0]);
if (pipe2(pipefd, O_CLOEXEC) < 0)
return log_error_errno(errno, "Failed to create pipe for tar: %m");
- pid = fork();
- if (pid < 0)
- return log_error_errno(errno, "Failed to fork off tar: %m");
-
- if (pid == 0) {
+ r = safe_fork("(tar)", FORK_RESET_SIGNALS|FORK_DEATHSIG, &pid);
+ if (r < 0)
+ return log_error_errno(r, "Failed to fork off tar: %m");
+ if (r == 0) {
int null_fd;
uint64_t retain =
(1ULL << CAP_CHOWN) |
/* Child */
- (void) reset_all_signal_handlers();
- (void) reset_signal_mask();
- assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0);
-
pipefd[1] = safe_close(pipefd[1]);
r = move_fd(pipefd[0], STDIN_FILENO, false);
if (pipe2(pipefd, O_CLOEXEC) < 0)
return log_error_errno(errno, "Failed to create pipe for tar: %m");
- pid = fork();
- if (pid < 0)
- return log_error_errno(errno, "Failed to fork off tar: %m");
-
- if (pid == 0) {
+ r = safe_fork("(tar)", FORK_RESET_SIGNALS|FORK_DEATHSIG, &pid);
+ if (r < 0)
+ return log_error_errno(r, "Failed to fork off tar: %m");
+ if (r == 0) {
int null_fd;
uint64_t retain = (1ULL << CAP_DAC_OVERRIDE);
/* Child */
- (void) reset_all_signal_handlers();
- (void) reset_signal_mask();
- assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0);
-
pipefd[0] = safe_close(pipefd[0]);
r = move_fd(pipefd[1], STDOUT_FILENO, false);
if (pipe2(pipefd, O_CLOEXEC) < 0)
return -errno;
- t->pid = fork();
- if (t->pid < 0)
- return -errno;
- if (t->pid == 0) {
+ r = safe_fork("(sd-transfer)", FORK_RESET_SIGNALS|FORK_DEATHSIG, &t->pid);
+ if (r < 0)
+ return r;
+ if (r == 0) {
const char *cmd[] = {
NULL, /* systemd-import, systemd-export or systemd-pull */
NULL, /* tar, raw */
/* Child */
- (void) reset_all_signal_handlers();
- (void) reset_signal_mask();
- assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0);
-
pipefd[0] = safe_close(pipefd[0]);
if (dup2(pipefd[1], STDERR_FILENO) != STDERR_FILENO) {
gpg_home_created = true;
- pid = fork();
- if (pid < 0)
- return log_error_errno(errno, "Failed to fork off gpg: %m");
- if (pid == 0) {
+ r = safe_fork("(gpg)", FORK_RESET_SIGNALS|FORK_DEATHSIG, &pid);
+ if (r < 0)
+ return log_error_errno(r, "Failed to fork off gpg: %m");
+ if (r == 0) {
const char *cmd[] = {
"gpg",
"--no-options",
/* Child */
- (void) reset_all_signal_handlers();
- (void) reset_signal_mask();
- assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0);
-
gpg_pipe[1] = safe_close(gpg_pipe[1]);
r = move_fd(gpg_pipe[0], STDIN_FILENO, false);
**********************************************************************/
static int spawn_child(const char* child, char** argv) {
- int fd[2];
- pid_t parent_pid, child_pid;
- int r;
+ pid_t child_pid;
+ int fd[2], r;
if (pipe(fd) < 0)
return log_error_errno(errno, "Failed to create pager pipe: %m");
- parent_pid = getpid_cached();
-
- child_pid = fork();
- if (child_pid < 0) {
- r = log_error_errno(errno, "Failed to fork: %m");
+ r = safe_fork("(remote)", FORK_RESET_SIGNALS|FORK_DEATHSIG, &child_pid);
+ if (r < 0) {
safe_close_pair(fd);
- return r;
+ return log_error_errno(r, "Failed to fork: %m");
}
/* In the child */
- if (child_pid == 0) {
-
- (void) reset_all_signal_handlers();
- (void) reset_signal_mask();
+ if (r == 0) {
r = dup2(fd[1], STDOUT_FILENO);
if (r < 0) {
safe_close_pair(fd);
- /* Make sure the child goes away when the parent dies */
- if (prctl(PR_SET_PDEATHSIG, SIGTERM) < 0)
- _exit(EXIT_FAILURE);
-
- /* Check whether our parent died before we were able
- * to set the death signal */
- if (getppid() != parent_pid)
- _exit(EXIT_SUCCESS);
-
execvp(child, argv);
log_error_errno(errno, "Failed to exec child %s: %m", child);
_exit(EXIT_FAILURE);
if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, pair) < 0)
return -errno;
- child = fork();
- if (child < 0)
- return -errno;
-
- if (child == 0) {
+ r = safe_fork("(sd-buscntr)", FORK_RESET_SIGNALS|FORK_DEATHSIG, &child);
+ if (r < 0)
+ return r;
+ if (r == 0) {
pid_t grandchild;
pair[0] = safe_close(pair[0]);
* comes from a process from within the container, and
* not outside of it */
- grandchild = fork();
- if (grandchild < 0)
+ r = safe_fork("(sd-buscntr2)", FORK_RESET_SIGNALS|FORK_DEATHSIG, &grandchild);
+ if (r < 0)
_exit(EXIT_FAILURE);
-
- if (grandchild == 0) {
+ if (r == 0) {
r = connect(b->input_fd, &b->sockaddr.sa, b->sockaddr_size);
if (r < 0) {
if (r < 0)
return -errno;
- pid = fork();
- if (pid < 0) {
+ r = safe_fork_full("(sd-busexec)", s+1, 1, FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS, &pid);
+ if (r < 0) {
safe_close_pair(s);
- return -errno;
+ return r;
}
- if (pid == 0) {
+ if (r == 0) {
/* Child */
- (void) reset_all_signal_handlers();
- (void) reset_signal_mask();
-
- close_all_fds(s+1, 1);
-
assert_se(dup3(s[1], STDIN_FILENO, 0) == STDIN_FILENO);
assert_se(dup3(s[1], STDOUT_FILENO, 0) == STDOUT_FILENO);
return EXIT_FAILURE;
}
- pid = fork();
- if (pid < 0) {
- log_error_errno(errno, "Failed to fork: %m");
+ r = safe_fork("(inhibit)", FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_CLOSE_ALL_FDS, &pid);
+ if (r < 0) {
+ log_error_errno(r, "Failed to fork: %m");
return EXIT_FAILURE;
}
-
- if (pid == 0) {
+ if (r == 0) {
/* Child */
-
- (void) reset_all_signal_handlers();
- (void) reset_signal_mask();
-
- close_all_fds(NULL, 0);
-
execvp(argv[optind], argv + optind);
log_error_errno(errno, "Failed to execute %s: %m", argv[optind]);
_exit(EXIT_FAILURE);
if (pipe2(errno_pipe_fd, O_CLOEXEC|O_NONBLOCK) < 0)
return sd_bus_error_set_errnof(error, errno, "Failed to create pipe: %m");
- child = fork();
- if (child < 0)
- return sd_bus_error_set_errnof(error, errno, "Failed to fork(): %m");
- if (child == 0) {
+ r = 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) {
errno_pipe_fd[0] = safe_close(errno_pipe_fd[0]);
r = image_remove(image);
if (pipe2(errno_pipe_fd, O_CLOEXEC|O_NONBLOCK) < 0)
return sd_bus_error_set_errnof(error, errno, "Failed to create pipe: %m");
- child = fork();
- if (child < 0)
- return sd_bus_error_set_errnof(error, errno, "Failed to fork(): %m");
- if (child == 0) {
+ r = safe_fork("(imgclone)", FORK_RESET_SIGNALS, &child);
+ if (r < 0)
+ return sd_bus_error_set_errnof(error, r, "Failed to fork(): %m");
+ if (r == 0) {
errno_pipe_fd[0] = safe_close(errno_pipe_fd[0]);
r = image_clone(image, new_name, read_only);
if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, pair) < 0)
return -errno;
- child = fork();
- if (child < 0)
- return sd_bus_error_set_errnof(error, errno, "Failed to fork(): %m");
-
- if (child == 0) {
+ r = safe_fork("(sd-addr)", FORK_RESET_SIGNALS|FORK_DEATHSIG, &child);
+ if (r < 0)
+ return sd_bus_error_set_errnof(error, r, "Failed to fork(): %m");
+ if (r == 0) {
_cleanup_free_ struct local_address *addresses = NULL;
struct local_address *a;
int i, n;
if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, pair) < 0)
return -errno;
- child = fork();
- if (child < 0)
- return sd_bus_error_set_errnof(error, errno, "Failed to fork(): %m");
-
- if (child == 0) {
+ r = safe_fork("(sd-osrel)", FORK_RESET_SIGNALS|FORK_DEATHSIG, &child);
+ if (r < 0)
+ return sd_bus_error_set_errnof(error, r, "Failed to fork(): %m");
+ if (r == 0) {
int fd = -1;
pair[0] = safe_close(pair[0]);
goto finish;
}
- child = fork();
- if (child < 0) {
- r = sd_bus_error_set_errnof(error, errno, "Failed to fork(): %m");
+ r = safe_fork("(sd-bindmnt)", FORK_RESET_SIGNALS, &child);
+ if (r < 0) {
+ sd_bus_error_set_errnof(error, r, "Failed to fork(): %m");
goto finish;
}
-
- if (child == 0) {
+ if (r == 0) {
const char *mount_inside;
int mntfd;
const char *q;
if (pipe2(errno_pipe_fd, O_CLOEXEC|O_NONBLOCK) < 0)
return sd_bus_error_set_errnof(error, errno, "Failed to create pipe: %m");
- child = fork();
- if (child < 0)
- return sd_bus_error_set_errnof(error, errno, "Failed to fork(): %m");
-
- if (child == 0) {
+ r = safe_fork("(sd-copy)", FORK_RESET_SIGNALS, &child);
+ if (r < 0)
+ return sd_bus_error_set_errnof(error, r, "Failed to fork(): %m");
+ if (r == 0) {
int containerfd;
const char *q;
int mntfd;
if (socketpair(AF_UNIX, SOCK_DGRAM, 0, pair) < 0)
return -errno;
- child = fork();
- if (child < 0)
- return sd_bus_error_set_errnof(error, errno, "Failed to fork(): %m");
-
- if (child == 0) {
+ r = safe_fork("(sd-openroot)", FORK_RESET_SIGNALS|FORK_DEATHSIG, &child);
+ if (r < 0)
+ return sd_bus_error_set_errnof(error, r, "Failed to fork(): %m");
+ if (r == 0) {
_cleanup_close_ int dfd = -1;
pair[0] = safe_close(pair[0]);
return -errno;
/* This might be a slow operation, run it asynchronously in a background process */
- child = fork();
- if (child < 0)
- return sd_bus_error_set_errnof(error, errno, "Failed to fork(): %m");
-
- if (child == 0) {
+ r = safe_fork("(sd-clean)", FORK_RESET_SIGNALS, &child);
+ if (r < 0)
+ return sd_bus_error_set_errnof(error, r, "Failed to fork(): %m");
+ if (r == 0) {
_cleanup_(image_hashmap_freep) Hashmap *images = NULL;
bool success = true;
Image *image;
#include "util.h"
static int spawn_getent(const char *database, const char *key, pid_t *rpid) {
- int pipe_fds[2];
+ int pipe_fds[2], r;
pid_t pid;
assert(database);
if (pipe2(pipe_fds, O_CLOEXEC) < 0)
return log_error_errno(errno, "Failed to allocate pipe: %m");
- pid = fork();
- if (pid < 0)
- return log_error_errno(errno, "Failed to fork getent child: %m");
- else if (pid == 0) {
+ r = safe_fork("(getent)", FORK_RESET_SIGNALS|FORK_DEATHSIG, &pid);
+ if (r < 0)
+ return log_error_errno(r, "Failed to fork getent child: %m");
+ if (r == 0) {
int nullfd;
char *empty_env = NULL;
if (nullfd > 2)
safe_close(nullfd);
- (void) reset_all_signal_handlers();
- (void) reset_signal_mask();
close_all_fds(NULL, 0);
execle("/usr/bin/getent", "getent", database, key, NULL, &empty_env);
sd_id128_to_string(uuid, new_environment + sizeof(new_environment) - SD_ID128_STRING_MAX);
reset_environ(new_environment, sizeof(new_environment));
- rename_process("STUBINIT");
+ (void) rename_process("(sd-stubinit)");
assert_se(sigemptyset(&waitmask) >= 0);
assert_se(sigset_add_many(&waitmask,
static int makefs(const char *type, const char *device) {
const char *mkfs;
pid_t pid;
+ int r;
if (streq(type, "swap"))
mkfs = "/sbin/mkswap";
if (access(mkfs, X_OK) != 0)
return log_error_errno(errno, "%s is not executable: %m", mkfs);
- pid = fork();
- if (pid < 0)
- return log_error_errno(errno, "fork(): %m");
-
- if (pid == 0) {
+ r = safe_fork("(fsck)", FORK_RESET_SIGNALS|FORK_DEATHSIG, &pid);
+ if (r < 0)
+ return log_error_errno(r, "fork(): %m");
+ if (r == 0) {
const char *cmdline[3] = { mkfs, device, NULL };
/* Child */
- (void) reset_all_signal_handlers();
- (void) reset_signal_mask();
- assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0);
-
execv(cmdline[0], (char**) cmdline);
_exit(EXIT_FAILURE);
}
return EXIT_SUCCESS;
}
- pid = fork();
- if (pid < 0) {
- r = log_error_errno(errno, "fork(): %m");
+ r = safe_fork("(quotacheck)", FORK_RESET_SIGNALS|FORK_DEATHSIG, &pid);
+ if (r < 0) {
+ log_error_errno(r, "fork(): %m");
goto finish;
}
- if (pid == 0) {
+ if (r == 0) {
/* Child */
- (void) reset_all_signal_handlers();
- (void) reset_signal_mask();
- assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0);
-
execv(cmdline[0], (char**) cmdline);
_exit(1); /* Operational error */
}
log_debug("Remounting %s", me->mnt_dir);
- pid = fork();
- if (pid < 0) {
- r = log_error_errno(errno, "Failed to fork: %m");
+ r = safe_fork("(remount)", FORK_RESET_SIGNALS|FORK_DEATHSIG, &pid);
+ if (r < 0) {
+ log_error_errno(r, "Failed to fork: %m");
goto finish;
}
-
- if (pid == 0) {
+ if (r == 0) {
/* Child */
- (void) reset_all_signal_handlers();
- (void) reset_signal_mask();
- (void) prctl(PR_SET_PDEATHSIG, SIGTERM);
-
execv(MOUNT_PATH, STRV_MAKE(MOUNT_PATH, me->mnt_dir, "-o", "remount"));
log_error_errno(errno, "Failed to execute " MOUNT_PATH ": %m");
if (socketpair(AF_UNIX, SOCK_DGRAM, 0, pair) < 0)
return -errno;
- child = fork();
- if (child < 0)
- return -errno;
-
- if (child == 0) {
+ r = safe_fork("(sd-bootid)", FORK_RESET_SIGNALS|FORK_DEATHSIG, &child);
+ if (r < 0)
+ return r;
+ if (r == 0) {
int fd;
pair[0] = safe_close(pair[0]);
goto fail;
}
- pid = fork();
- if (pid < 0) {
- r = sd_bus_error_set_errnof(error, errno, "Failed to fork mkfs.btrfs: %m");
+ r = safe_fork("(mkfs)", FORK_RESET_SIGNALS|FORK_DEATHSIG, &pid);
+ if (r < 0) {
+ sd_bus_error_set_errnof(error, r, "Failed to fork mkfs.btrfs: %m");
goto fail;
}
-
- if (pid == 0) {
+ if (r == 0) {
/* Child */
- (void) reset_all_signal_handlers();
- (void) reset_signal_mask();
- assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0);
-
fd = safe_close(fd);
execlp("mkfs.btrfs", "-Lvar-lib-machines", tmp, NULL);
int pager_open(bool no_pager, bool jump_to_end) {
_cleanup_close_pair_ int fd[2] = { -1, -1 };
const char *pager;
- pid_t parent_pid;
+ int r;
if (no_pager)
return 0;
if (pipe2(fd, O_CLOEXEC) < 0)
return log_error_errno(errno, "Failed to create pager pipe: %m");
- parent_pid = getpid_cached();
-
- pager_pid = fork();
- if (pager_pid < 0)
- return log_error_errno(errno, "Failed to fork pager: %m");
-
- /* In the child start the pager */
- if (pager_pid == 0) {
+ r = safe_fork("(pager)", FORK_RESET_SIGNALS|FORK_DEATHSIG, &pager_pid);
+ if (r < 0)
+ return log_error_errno(r, "Failed to fork pager: %m");
+ if (r == 0) {
const char* less_opts, *less_charset;
- (void) reset_all_signal_handlers();
- (void) reset_signal_mask();
+ /* In the child start the pager */
(void) dup2(fd[0], STDIN_FILENO);
safe_close_pair(fd);
setenv("LESSCHARSET", less_charset, 1) < 0)
_exit(EXIT_FAILURE);
- /* Make sure the pager goes away when the parent dies */
- if (prctl(PR_SET_PDEATHSIG, SIGTERM) < 0)
- _exit(EXIT_FAILURE);
-
- /* Check whether our parent died before we were able
- * to set the death signal */
- if (getppid() != parent_pid)
- _exit(EXIT_SUCCESS);
-
if (pager) {
execlp(pager, pager, NULL);
execl("/bin/sh", "sh", "-c", pager, NULL);
} else
args[1] = desc;
- pid = fork();
- if (pid < 0)
- return log_error_errno(errno, "Failed to fork: %m");
-
- if (pid == 0) {
+ r = safe_fork("(man)", FORK_RESET_SIGNALS|FORK_DEATHSIG|(null_stdio ? FORK_NULL_STDIO : 0), &pid);
+ if (r < 0)
+ return log_error_errno(r, "Failed to fork: %m");
+ if (r == 0) {
/* Child */
-
- (void) reset_all_signal_handlers();
- (void) reset_signal_mask();
-
- if (null_stdio) {
- r = make_null_stdio();
- if (r < 0) {
- log_error_errno(r, "Failed to kill stdio: %m");
- _exit(EXIT_FAILURE);
- }
- }
-
execvp(args[0], (char**) args);
log_error_errno(errno, "Failed to execute man: %m");
_exit(EXIT_FAILURE);
static int fork_wait(const char* const cmdline[]) {
pid_t pid;
+ int r;
- pid = fork();
- if (pid < 0)
- return log_error_errno(errno, "fork(): %m");
- if (pid == 0) {
-
+ r = safe_fork("(sulogin)", FORK_RESET_SIGNALS|FORK_DEATHSIG, &pid);
+ if (r < 0)
+ return log_error_errno(r, "fork(): %m");
+ if (r == 0) {
/* Child */
-
- (void) reset_all_signal_handlers();
- (void) reset_signal_mask();
- assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0);
-
execv(cmdline[0], (char**) cmdline);
log_error_errno(errno, "Failed to execute %s: %m", cmdline[0]);
_exit(EXIT_FAILURE); /* Operational error */
if (arg_dry_run)
return 0;
- pid = fork();
- if (pid < 0)
- return log_error_errno(errno, "Failed to fork: %m");
- else if (pid == 0) {
+ r = safe_fork("(kexec)", FORK_RESET_SIGNALS|FORK_DEATHSIG, &pid);
+ if (r < 0)
+ return log_error_errno(r, "Failed to fork: %m");
+ if (r == 0) {
const char* const args[] = {
KEXEC,
NULL };
/* Child */
-
- (void) reset_all_signal_handlers();
- (void) reset_signal_mask();
- assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0);
-
execv(args[0], (char * const *) args);
_exit(EXIT_FAILURE);
- } else
- return wait_for_terminate_and_warn("kexec", pid, true);
+ }
+
+ return wait_for_terminate_and_warn("kexec", pid, true);
}
static int set_exit_code(uint8_t code) {
if (!arg_quiet)
log_info("Executing: %s", l);
- pid = fork();
- if (pid < 0)
- return log_error_errno(errno, "Failed to fork: %m");
- else if (pid == 0) {
+ j = safe_fork("(sysv)", FORK_RESET_SIGNALS|FORK_DEATHSIG, &pid);
+ if (j < 0)
+ return log_error_errno(j, "Failed to fork: %m");
+ if (j == 0) {
/* Child */
-
- (void) reset_all_signal_handlers();
- (void) reset_signal_mask();
-
execv(argv[0], (char**) argv);
log_error_errno(errno, "Failed to execute %s: %m", argv[0]);
_exit(EXIT_FAILURE);
assert(paths);
- pid = fork();
- if (pid < 0)
- return log_error_errno(errno, "Failed to fork: %m");
-
- if (pid == 0) {
+ r = safe_fork("(editor)", FORK_RESET_SIGNALS|FORK_DEATHSIG, &pid);
+ if (r < 0)
+ return log_error_errno(r, "Failed to fork: %m");
+ if (r == 0) {
const char **args;
char *editor, **editor_args = NULL;
char **tmp_path, **original_path, *p;
unsigned n_editor_args = 0, i = 1;
size_t argc;
- (void) reset_all_signal_handlers();
- (void) reset_signal_mask();
-
argc = strv_length(paths)/2 + 1;
/* SYSTEMD_EDITOR takes precedence over EDITOR which takes precedence over VISUAL
#include "macro.h"
#include "parse-util.h"
#include "process-util.h"
+#include "signal-util.h"
#include "stdio-util.h"
#include "string-util.h"
#include "terminal-util.h"
log_info("getpid_cached(): %llu/s\n", (unsigned long long) (MEASURE_ITERATIONS*USEC_PER_SEC/q));
}
+static void test_safe_fork(void) {
+ siginfo_t status;
+ pid_t pid;
+ int r;
+
+ BLOCK_SIGNALS(SIGCHLD);
+
+ r = safe_fork("(test-child)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_DEATHSIG|FORK_NULL_STDIO|FORK_REOPEN_LOG, &pid);
+ assert_se(r >= 0);
+
+ if (r == 0) {
+ /* child */
+ usleep(100 * USEC_PER_MSEC);
+
+ _exit(88);
+ }
+
+ assert_se(wait_for_terminate(pid, &status) >= 0);
+ assert_se(status.si_code == CLD_EXITED);
+ assert_se(status.si_status == 88);
+}
+
int main(int argc, char *argv[]) {
log_set_max_level(LOG_DEBUG);
test_rename_process();
test_getpid_cached();
test_getpid_measure();
+ test_safe_fork();
return 0;
}
* If one of the tasks does handle a password, the remaining tasks
* will be terminated.
*/
-static int ask_on_this_console(const char *tty, pid_t *pid, int argc, char *argv[]) {
+static int ask_on_this_console(const char *tty, pid_t *ret_pid, int argc, char *argv[]) {
struct sigaction sig = {
.sa_handler = nop_signal_handler,
.sa_flags = SA_NOCLDSTOP | SA_RESTART,
};
+ pid_t pid;
+ int r;
assert_se(sigprocmask_many(SIG_UNBLOCK, NULL, SIGHUP, SIGCHLD, -1) >= 0);
sig.sa_handler = SIG_DFL;
assert_se(sigaction(SIGHUP, &sig, NULL) >= 0);
- *pid = fork();
- if (*pid < 0)
- return log_error_errno(errno, "Failed to fork process: %m");
-
- if (*pid == 0) {
+ r = safe_fork("(sd-passwd)", FORK_RESET_SIGNALS, &pid);
+ if (r < 0)
+ return log_error_errno(r, "Failed to fork process: %m");
+ if (r == 0) {
int ac;
assert_se(prctl(PR_SET_PDEATHSIG, SIGHUP) >= 0);
- reset_signal_mask();
- reset_all_signal_handlers();
-
for (ac = 0; ac < argc; ac++) {
if (streq(argv[ac], "--console")) {
argv[ac] = strjoina("--console=", tty);
execv(SYSTEMD_TTY_ASK_PASSWORD_AGENT_BINARY_PATH, argv);
_exit(EXIT_FAILURE);
}
+
+ *ret_pid = pid;
return 0;
}
}
}
- pid = fork();
- switch(pid) {
- case 0:
- {
+ err = safe_fork("(spawn)", FORK_RESET_SIGNALS, &pid);
+ if (err < 0) {
+ log_error_errno(err, "fork of '%s' failed: %m", cmd);
+ goto out;
+ }
+ if (err == 0) {
char arg[UTIL_PATH_SIZE];
char *argv[128];
char program[UTIL_PATH_SIZE];
_exit(2);
}
- case -1:
- log_error_errno(errno, "fork of '%s' failed: %m", cmd);
- err = -1;
- goto out;
- default:
- /* parent closed child's ends of pipes */
- outpipe[WRITE_END] = safe_close(outpipe[WRITE_END]);
- errpipe[WRITE_END] = safe_close(errpipe[WRITE_END]);
- spawn_read(event,
- timeout_usec,
- cmd,
- outpipe[READ_END], errpipe[READ_END],
- result, ressize);
+ /* parent closed child's ends of pipes */
+ outpipe[WRITE_END] = safe_close(outpipe[WRITE_END]);
+ errpipe[WRITE_END] = safe_close(errpipe[WRITE_END]);
- err = spawn_wait(event, timeout_usec, timeout_warn_usec, cmd, pid, accept_failure);
- }
+ spawn_read(event,
+ timeout_usec,
+ cmd,
+ outpipe[READ_END], errpipe[READ_END],
+ result, ressize);
+
+ err = spawn_wait(event, timeout_usec, timeout_warn_usec, cmd, pid, accept_failure);
out:
if (outpipe[READ_END] >= 0)
const char *args[8];
unsigned i = 0;
pid_t pid;
+ int r;
/* An empty map means kernel map */
if (isempty(map))
log_debug("Executing \"%s\"...",
strnull((cmd = strv_join((char**) args, " "))));
- pid = fork();
- if (pid < 0)
- return log_error_errno(errno, "Failed to fork: %m");
- else if (pid == 0) {
-
- (void) reset_all_signal_handlers();
- (void) reset_signal_mask();
-
+ r = safe_fork("(loadkeys)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS, &pid);
+ if (r < 0)
+ return log_error_errno(r, "Failed to fork: %m");
+ if (r == 0) {
execv(args[0], (char **) args);
_exit(EXIT_FAILURE);
}
const char *args[9];
unsigned i = 0;
pid_t pid;
+ int r;
/* Any part can be set independently */
if (isempty(font) && isempty(map) && isempty(unimap))
log_debug("Executing \"%s\"...",
strnull((cmd = strv_join((char**) args, " "))));
- pid = fork();
- if (pid < 0)
- return log_error_errno(errno, "Failed to fork: %m");
- else if (pid == 0) {
-
- (void) reset_all_signal_handlers();
- (void) reset_signal_mask();
-
+ r = safe_fork("(setfont)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS, &pid);
+ if (r < 0)
+ return log_error_errno(r, "Failed to fork: %m");
+ if (r == 0) {
execv(args[0], (char **) args);
_exit(EXIT_FAILURE);
}