summaryrefslogtreecommitdiffstats
path: root/src/xspawn.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/xspawn.c')
-rw-r--r--src/xspawn.c67
1 files changed, 37 insertions, 30 deletions
diff --git a/src/xspawn.c b/src/xspawn.c
index 065fbae..33e5a4a 100644
--- a/src/xspawn.c
+++ b/src/xspawn.c
@@ -1,13 +1,15 @@
// Copyright © Tavian Barnes <tavianator@tavianator.com>
// SPDX-License-Identifier: 0BSD
+#include "prelude.h"
#include "xspawn.h"
#include "alloc.h"
#include "bfstd.h"
-#include "config.h"
+#include "diag.h"
#include "list.h"
#include <errno.h>
#include <fcntl.h>
+#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <sys/resource.h>
@@ -209,10 +211,10 @@ int bfs_spawn_adddup2(struct bfs_spawn *ctx, int oldfd, int newfd) {
* PATH ..., using the working directory of the child process after all
* file_actions have been performed.
*
- * but macOS resolves the PATH *before* file_actions (because there
+ * but macOS and NetBSD resolve the PATH *before* file_actions (because there
* posix_spawn() is its own syscall).
*/
-#define BFS_POSIX_SPAWNP_AFTER_FCHDIR !__APPLE__
+#define BFS_POSIX_SPAWNP_AFTER_FCHDIR !(__APPLE__ || __NetBSD__)
int bfs_spawn_addfchdir(struct bfs_spawn *ctx, int fd) {
struct bfs_spawn_action *action = bfs_spawn_action(BFS_SPAWN_FCHDIR);
@@ -220,29 +222,15 @@ int bfs_spawn_addfchdir(struct bfs_spawn *ctx, int fd) {
return -1;
}
-#ifndef BFS_HAS_POSIX_SPAWN_FCHDIR
-# define BFS_HAS_POSIX_SPAWN_FCHDIR __NetBSD_Prereq__(10, 0, 0)
-#endif
-
-#ifndef BFS_HAS_POSIX_SPAWN_FCHDIR_NP
-# if __GLIBC__
-# define BFS_HAS_POSIX_SPAWN_FCHDIR_NP __GLIBC_PREREQ(2, 29)
-# elif __ANDROID__
-# define BFS_HAS_POSIX_SPAWN_FCHDIR_NP (__ANDROID_API__ >= 34)
-# else
-# define BFS_HAS_POSIX_SPAWN_FCHDIR_NP (__linux__ || __FreeBSD__ || __APPLE__)
-# endif
-#endif
-
-#if BFS_HAS_POSIX_SPAWN_FCHDIR
-# define BFS_POSIX_SPAWN_FCHDIR posix_spawn_file_actions_addfchdir
-#elif BFS_HAS_POSIX_SPAWN_FCHDIR_NP
-# define BFS_POSIX_SPAWN_FCHDIR posix_spawn_file_actions_addfchdir_np
+#if BFS_HAS_POSIX_SPAWN_ADDFCHDIR
+# define BFS_POSIX_SPAWN_ADDFCHDIR posix_spawn_file_actions_addfchdir
+#elif BFS_HAS_POSIX_SPAWN_ADDFCHDIR_NP
+# define BFS_POSIX_SPAWN_ADDFCHDIR posix_spawn_file_actions_addfchdir_np
#endif
#if _POSIX_SPAWN > 0 && defined(BFS_POSIX_SPAWN_FCHDIR)
if (ctx->flags & BFS_SPAWN_USE_POSIX) {
- errno = BFS_POSIX_SPAWN_FCHDIR(&ctx->actions, fd);
+ errno = BFS_POSIX_SPAWN_ADDFCHDIR(&ctx->actions, fd);
if (errno != 0) {
free(action);
return -1;
@@ -604,30 +592,49 @@ static pid_t bfs_fork_spawn(struct bfs_resolver *res, const struct bfs_spawn *ct
return -1;
}
+ // Block signals before fork() so handlers don't run in the child
+ sigset_t new_mask;
+ if (sigfillset(&new_mask) != 0) {
+ goto fail;
+ }
+ sigset_t old_mask;
+ errno = pthread_sigmask(SIG_BLOCK, &new_mask, &old_mask);
+ if (errno != 0) {
+ goto fail;
+ }
+
pid_t pid = fork();
- if (pid < 0) {
- close_quietly(pipefd[1]);
- close_quietly(pipefd[0]);
- return -1;
- } else if (pid == 0) {
+ if (pid == 0) {
// Child
bfs_spawn_exec(res, ctx, argv, envp, pipefd);
}
- // Parent
+ // Restore the original signal mask
+ int ret = pthread_sigmask(SIG_SETMASK, &old_mask, NULL);
+ bfs_everify(ret == 0, "pthread_sigmask()");
+
+ if (pid < 0) {
+ // fork() failed
+ goto fail;
+ }
+
xclose(pipefd[1]);
int error;
ssize_t nbytes = xread(pipefd[0], &error, sizeof(error));
xclose(pipefd[0]);
if (nbytes == sizeof(error)) {
- int wstatus;
- xwaitpid(pid, &wstatus, 0);
+ xwaitpid(pid, NULL, 0);
errno = error;
return -1;
}
return pid;
+
+fail:
+ close_quietly(pipefd[1]);
+ close_quietly(pipefd[0]);
+ return -1;
}
/** Call the right bfs_spawn() implementation. */