Initial project import
This commit is contained in:
commit
23f2d29e32
11957 files changed
+1754577
No files matched your search
@@ -0,0 +1,178 @@
|
||||
// v_os_execute_set_cloexec marks an fd as close-on-exec. When multiple threads
|
||||
// each call os.execute, every pipe() they create is briefly visible to all of
|
||||
// them; without FD_CLOEXEC, one thread's spawned child can inherit another
|
||||
// thread's pipe write end, keeping that pipe open after the intended writer
|
||||
// exits. The reader then never observes EOF and the captured output ends up
|
||||
// empty (seen on macOS arm64 in CI). Setting CLOEXEC closes the fd
|
||||
// automatically across exec, which fixes the race for both fork/execvp and
|
||||
// posix_spawn paths.
|
||||
static void v_os_execute_set_cloexec(int fd) {
|
||||
int flags = fcntl(fd, F_GETFD, 0);
|
||||
if (flags >= 0) {
|
||||
fcntl(fd, F_SETFD, flags | FD_CLOEXEC);
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(__ANDROID__) && (!defined(__ANDROID_API__) || __ANDROID_API__ < 28)
|
||||
// Android API levels below 28 do not provide posix_spawn(). Fall back to
|
||||
// fork()/execvp() with a pipe; this is what popen() does internally and
|
||||
// is sufficient for capturing the merged stdout+stderr of a shell command.
|
||||
static int v_os_execute_capture_start(const char *cmd, int *child_pid, int *read_fd) {
|
||||
int pipefd[2];
|
||||
if (pipe(pipefd) != 0) {
|
||||
return -1;
|
||||
}
|
||||
v_os_execute_set_cloexec(pipefd[0]);
|
||||
v_os_execute_set_cloexec(pipefd[1]);
|
||||
pid_t pid = fork();
|
||||
if (pid < 0) {
|
||||
close(pipefd[0]);
|
||||
close(pipefd[1]);
|
||||
return -1;
|
||||
}
|
||||
if (pid == 0) {
|
||||
// child: redirect stdout+stderr to the pipe, then exec the shell.
|
||||
// dup2 clears FD_CLOEXEC on the destination, so STDOUT/STDERR stay
|
||||
// open across exec while the original pipe fds are auto-closed.
|
||||
dup2(pipefd[1], STDOUT_FILENO);
|
||||
dup2(pipefd[1], STDERR_FILENO);
|
||||
close(pipefd[0]);
|
||||
close(pipefd[1]);
|
||||
execlp("sh", "sh", "-c", cmd, (char *)NULL);
|
||||
_exit(127);
|
||||
}
|
||||
close(pipefd[1]);
|
||||
*child_pid = (int)pid;
|
||||
*read_fd = pipefd[0];
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int v_os_exec_capture_start(char *const argv[], int *child_pid, int *read_fd) {
|
||||
if (argv == NULL || argv[0] == NULL) {
|
||||
return -1;
|
||||
}
|
||||
int pipefd[2];
|
||||
if (pipe(pipefd) != 0) {
|
||||
return -1;
|
||||
}
|
||||
v_os_execute_set_cloexec(pipefd[0]);
|
||||
v_os_execute_set_cloexec(pipefd[1]);
|
||||
pid_t pid = fork();
|
||||
if (pid < 0) {
|
||||
close(pipefd[0]);
|
||||
close(pipefd[1]);
|
||||
return -1;
|
||||
}
|
||||
if (pid == 0) {
|
||||
dup2(pipefd[1], STDOUT_FILENO);
|
||||
dup2(pipefd[1], STDERR_FILENO);
|
||||
close(pipefd[0]);
|
||||
close(pipefd[1]);
|
||||
execvp(argv[0], argv);
|
||||
_exit(127);
|
||||
}
|
||||
close(pipefd[1]);
|
||||
*child_pid = (int)pid;
|
||||
*read_fd = pipefd[0];
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
// Use opaque void* declarations for posix_spawn instead of #include <spawn.h>.
|
||||
// Including <spawn.h> transitively pulls in <features.h>/<sys/cdefs.h>, which
|
||||
// breaks under musl-gcc on the Ubuntu docker image where <sys/cdefs.h> is not
|
||||
// on the include path. The 128-byte buffer is comfortably larger than the
|
||||
// real posix_spawn_file_actions_t on glibc (~80 bytes) and musl (~40 bytes);
|
||||
// posix_spawn_file_actions_init() initializes the buffer, so its true layout
|
||||
// is not needed here. We pass NULL for posix_spawnattr_t, so it is not
|
||||
// declared. Calling these via void* is ABI-compatible: pointer parameters
|
||||
// are passed identically regardless of pointee type.
|
||||
typedef struct { unsigned char _opaque[128]; } v_posix_spawn_file_actions_t;
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
extern int posix_spawn(pid_t *, const char *, const void *, const void *, char *const [], char *const []);
|
||||
extern int posix_spawnp(pid_t *, const char *, const void *, const void *, char *const [], char *const []);
|
||||
extern int posix_spawn_file_actions_init(void *);
|
||||
extern int posix_spawn_file_actions_destroy(void *);
|
||||
extern int posix_spawn_file_actions_adddup2(void *, int, int);
|
||||
extern int posix_spawn_file_actions_addclose(void *, int);
|
||||
|
||||
extern char **environ;
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
static int v_os_execute_capture_start(const char *cmd, int *child_pid, int *read_fd) {
|
||||
int pipefd[2];
|
||||
if (pipe(pipefd) != 0) {
|
||||
return -1;
|
||||
}
|
||||
v_os_execute_set_cloexec(pipefd[0]);
|
||||
v_os_execute_set_cloexec(pipefd[1]);
|
||||
v_posix_spawn_file_actions_t actions;
|
||||
if (posix_spawn_file_actions_init(&actions) != 0) {
|
||||
close(pipefd[0]);
|
||||
close(pipefd[1]);
|
||||
return -1;
|
||||
}
|
||||
int err = 0;
|
||||
if ((err = posix_spawn_file_actions_adddup2(&actions, pipefd[1], STDOUT_FILENO)) != 0
|
||||
|| (err = posix_spawn_file_actions_adddup2(&actions, pipefd[1], STDERR_FILENO)) != 0
|
||||
|| (err = posix_spawn_file_actions_addclose(&actions, pipefd[0])) != 0
|
||||
|| (err = posix_spawn_file_actions_addclose(&actions, pipefd[1])) != 0) {
|
||||
posix_spawn_file_actions_destroy(&actions);
|
||||
close(pipefd[0]);
|
||||
close(pipefd[1]);
|
||||
return -1;
|
||||
}
|
||||
char *const argv[] = {(char *)"/bin/sh", (char *)"-c", (char *)cmd, NULL};
|
||||
err = posix_spawn(child_pid, "/bin/sh", &actions, NULL, argv, environ);
|
||||
posix_spawn_file_actions_destroy(&actions);
|
||||
if (err != 0) {
|
||||
close(pipefd[0]);
|
||||
close(pipefd[1]);
|
||||
return -1;
|
||||
}
|
||||
close(pipefd[1]);
|
||||
*read_fd = pipefd[0];
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int v_os_exec_capture_start(char *const argv[], int *child_pid, int *read_fd) {
|
||||
if (argv == NULL || argv[0] == NULL) {
|
||||
return -1;
|
||||
}
|
||||
int pipefd[2];
|
||||
if (pipe(pipefd) != 0) {
|
||||
return -1;
|
||||
}
|
||||
v_os_execute_set_cloexec(pipefd[0]);
|
||||
v_os_execute_set_cloexec(pipefd[1]);
|
||||
v_posix_spawn_file_actions_t actions;
|
||||
if (posix_spawn_file_actions_init(&actions) != 0) {
|
||||
close(pipefd[0]);
|
||||
close(pipefd[1]);
|
||||
return -1;
|
||||
}
|
||||
int err = 0;
|
||||
if ((err = posix_spawn_file_actions_adddup2(&actions, pipefd[1], STDOUT_FILENO)) != 0
|
||||
|| (err = posix_spawn_file_actions_adddup2(&actions, pipefd[1], STDERR_FILENO)) != 0
|
||||
|| (err = posix_spawn_file_actions_addclose(&actions, pipefd[0])) != 0
|
||||
|| (err = posix_spawn_file_actions_addclose(&actions, pipefd[1])) != 0) {
|
||||
posix_spawn_file_actions_destroy(&actions);
|
||||
close(pipefd[0]);
|
||||
close(pipefd[1]);
|
||||
return -1;
|
||||
}
|
||||
err = posix_spawnp(child_pid, argv[0], &actions, NULL, argv, environ);
|
||||
posix_spawn_file_actions_destroy(&actions);
|
||||
if (err != 0) {
|
||||
close(pipefd[0]);
|
||||
close(pipefd[1]);
|
||||
return -1;
|
||||
}
|
||||
close(pipefd[1]);
|
||||
*read_fd = pipefd[0];
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
Reference in new issue
Block a user