mirror of
https://codeberg.org/dnkl/foot.git
synced 2026-02-05 04:06:08 -05:00
When calling ‘reaper_add()’, the caller can provide a callback. If non-NULL, the reaper will call the callback to handle the actual reaping. If the callback is NULL, or if it returns false, the reaper reaps the child process.
76 lines
1.8 KiB
C
76 lines
1.8 KiB
C
#include "spawn.h"
|
|
|
|
#include <unistd.h>
|
|
#include <errno.h>
|
|
#include <assert.h>
|
|
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <fcntl.h>
|
|
|
|
#define LOG_MODULE "spawn"
|
|
#define LOG_ENABLE_DBG 0
|
|
#include "log.h"
|
|
|
|
bool
|
|
spawn(struct reaper *reaper, const char *cwd, char *const argv[],
|
|
int stdin_fd, int stdout_fd, int stderr_fd)
|
|
{
|
|
int pipe_fds[2] = {-1, -1};
|
|
if (pipe2(pipe_fds, O_CLOEXEC) < 0) {
|
|
LOG_ERRNO("failed to create pipe");
|
|
goto err;
|
|
}
|
|
|
|
pid_t pid = fork();
|
|
if (pid < 0) {
|
|
LOG_ERRNO("failed to fork");
|
|
goto err;
|
|
}
|
|
|
|
if (pid == 0) {
|
|
/* Child */
|
|
close(pipe_fds[0]);
|
|
|
|
if ((stdin_fd >= 0 && (dup2(stdin_fd, STDIN_FILENO) < 0 || close(stdin_fd) < 0)) ||
|
|
(stdout_fd >= 0 && (dup2(stdout_fd, STDOUT_FILENO) < 0 || close(stdout_fd) < 0)) ||
|
|
(stderr_fd >= 0 && (dup2(stderr_fd, STDERR_FILENO) < 0 || close(stderr_fd) < 0)) ||
|
|
(cwd != NULL && chdir(cwd) < 0) ||
|
|
execvp(argv[0], argv) < 0)
|
|
{
|
|
(void)!write(pipe_fds[1], &errno, sizeof(errno));
|
|
_exit(errno);
|
|
}
|
|
assert(false);
|
|
_exit(errno);
|
|
}
|
|
|
|
/* Parent */
|
|
close(pipe_fds[1]);
|
|
|
|
int _errno;
|
|
static_assert(sizeof(_errno) == sizeof(errno), "errno size mismatch");
|
|
|
|
ssize_t ret = read(pipe_fds[0], &_errno, sizeof(_errno));
|
|
close(pipe_fds[0]);
|
|
|
|
if (ret == 0) {
|
|
reaper_add(reaper, pid, NULL, NULL);
|
|
return true;
|
|
} else if (ret < 0) {
|
|
LOG_ERRNO("failed to read from pipe");
|
|
return false;
|
|
} else {
|
|
LOG_ERRNO_P(_errno, "%s: failed to spawn", argv[0]);
|
|
errno = _errno;
|
|
waitpid(pid, NULL, 0);
|
|
return false;
|
|
}
|
|
|
|
err:
|
|
if (pipe_fds[0] != -1)
|
|
close(pipe_fds[0]);
|
|
if (pipe_fds[1] != -1)
|
|
close(pipe_fds[1]);
|
|
return false;
|
|
}
|