/* See LICENSE file for copyright and license details. */ #include "common.h" #ifndef TEST int libexec_spawn(pid_t *out, struct libexec_command *cmd, int (*after_fork)(struct libexec_command *cmd, int new_fd, void *user), void *user, struct libexec_document **docsp, size_t *ndocsp, int doc_fd_flags) { int fds[2], error, new_fd; size_t i; ssize_t r; if (!docsp || !ndocsp || !out || !cmd) { errno = EINVAL; return -1; } *out = -1; if (pipe2(fds, O_CLOEXEC)) return -1; new_fd = fds[1]; for (i = 0; i < cmd->nplumings; i++) if (cmd->plumings[i].fd >= new_fd) new_fd = cmd->plumings[i].fd + 1; if (new_fd != fds[1]) { new_fd = fcntl(fds[1], F_DUPFD_CLOEXEC, new_fd); if (new_fd == -1) goto fail; fds[1] = new_fd; } if (libexec_get_documents(cmd, docsp, ndocsp, doc_fd_flags)) goto fail; *out = fork(); switch (*out) { case -1: goto fail; case 0: close(fds[0]); if (after_fork) if ((*after_fork)(cmd, fds[1], user)) goto child_fail; libexec_exec(cmd); child_fail: error = errno; write_again: r = write(fds[1], &error, sizeof(error)); if (r <= 0) { if (errno == EINTR) goto write_again; abort(); } _exit(1); default: close(fds[1]); read_again: r = read(fds[0], &error, sizeof(error)); if (r < 0) { if (errno == EINTR) goto read_again; } else if (r == 0) { return 0; } else if ((size_t)r >= sizeof(error)) { errno = error; } return -1; } fail: error = errno; close(fds[0]); close(fds[1]); errno = error; return -1; } #else LIBEXEC_CONST__ int main(void) {return 0;} /* TODO test */ #endif