void* const callback_args[_STDOUT_CONSUME_MAX],
char *argv[]) {
- pid_t executor_pid;
- char *name;
char **dirs = (char**) directories;
_cleanup_close_ int fd = -1;
+ char *name;
int r;
assert(!strv_isempty(dirs));
* 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. */
- r = safe_fork("(sd-executor)", FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_LOG, &executor_pid);
+ r = safe_fork("(sd-executor)", FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_LOG|FORK_WAIT, NULL);
if (r < 0)
return r;
if (r == 0) {
_exit(r < 0 ? EXIT_FAILURE : EXIT_SUCCESS);
}
- r = wait_for_terminate_and_check(name, executor_pid, WAIT_LOG);
- if (r < 0)
- return r;
- if (r > 0) /* non-zero return code from child */
- return -EREMOTEIO;
-
if (!callbacks)
return 0;
pid_t *ret_pid) {
pid_t original_pid, pid;
- sigset_t saved_ss;
+ sigset_t saved_ss, ss;
bool block_signals;
int prio, r;
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;
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;
int parse_timestamp(const char *t, usec_t *usec) {
char *last_space, *tz = NULL;
ParseTimestampResult *shared, tmp;
- pid_t pid;
int r;
last_space = strrchr(t, ' ');
if (shared == MAP_FAILED)
return negative_errno();
- r = safe_fork("(sd-timestamp)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_DEATHSIG, &pid);
+ r = safe_fork("(sd-timestamp)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_DEATHSIG|FORK_WAIT, NULL);
if (r < 0) {
(void) munmap(shared, sizeof *shared);
return r;
_exit(EXIT_SUCCESS);
}
- r = wait_for_terminate(pid, NULL);
- if (r < 0) {
- (void) munmap(shared, sizeof *shared);
- return r;
- }
-
tmp = *shared;
if (munmap(shared, sizeof *shared) != 0)
return negative_errno();