diff options
Diffstat (limited to 'src/exec.c')
-rw-r--r-- | src/exec.c | 118 |
1 files changed, 88 insertions, 30 deletions
@@ -1,3 +1,13 @@ +#include <assert.h> +#include <stdlib.h> +#include <signal.h> +#include <sys/wait.h> +#include <string.h> +#include <errno.h> +#include <fcntl.h> + +#include <libdaemon/dlog.h> + #include "exec.h" #include "main.h" @@ -6,13 +16,13 @@ struct process_info { pid_t pid; int killed; - int child_pipe; - process_exit_cb_t *cb; + int stderr_pipe; + process_exit_cb_t cb; void *user; struct process_info *next; char *read_buf; - size_t read_buf_size; + size_t read_buf_len; }; static struct process_info *procs = NULL; @@ -34,19 +44,20 @@ static void *oop_read_cb(oop_source *source, int fd, oop_event event, void *user static void close_child_pipe(struct process_info *p) { assert(p); - + if (p->read_buf_len && p->read_buf) { *(p->read_buf + p->read_buf_len) = 0; daemon_log(LOG_INFO, "child(%lu): %s", (unsigned long) p->pid, p->read_buf); p->read_buf_len = 0; } - if (p->child_pipe >= 0) { + if (p->stderr_pipe >= 0) { assert(event_source && event_source->cancel_fd); - event_source->cancel_fd(event_source, p->child_pipe, OOP_READ, oop_read_cb, p); - close(p->child_pipe); - p->child_pipe = -1; + event_source->cancel_fd(event_source, p->stderr_pipe, OOP_READ); + close(p->stderr_pipe); + p->stderr_pipe = -1; } + } @@ -97,8 +108,8 @@ static void *oop_sigchld_cb(oop_source *source, int sig, void *user) { return OOP_HALT; } - if (!(p = find_process_by_pid(pid))) { - daemon_log(LOG_WARN, "Got SIGCHLD for unknown process, reaping"); + if (!(p = find_process(pid))) { + daemon_log(LOG_WARNING, "Got SIGCHLD for unknown process, reaping"); return OOP_CONTINUE; } @@ -121,7 +132,7 @@ static void *oop_read_cb(oop_source *source, int fd, oop_event event, void *user assert(source && event == OOP_READ); p = (struct process_info*) user; - assert(p && p->child_pipe == fd && fd >= 0); + assert(p && p->stderr_pipe == fd && fd >= 0); if (!p->read_buf) { p->read_buf = malloc(CHILD_BUF_SIZE); @@ -131,7 +142,7 @@ static void *oop_read_cb(oop_source *source, int fd, oop_event event, void *user assert(p->read_buf); start = p->read_buf+p->read_buf_len; - if ((s = read(p->child_pipe, start, CHILD_BUF_SIZE-p->read_buf_len-1)) < 0) { + if ((s = read(fd, start, CHILD_BUF_SIZE-p->read_buf_len-1)) < 0) { daemon_log(LOG_ERR, "Failed to read from child pipe: %s", strerror(errno)); return OOP_HALT; } @@ -165,20 +176,40 @@ static void *oop_read_cb(oop_source *source, int fd, oop_event event, void *user return OOP_CONTINUE; } +static void pipe_close(int fds[]) { + close(fds[0]); + close(fds[1]); +} -pid_t child_process_create(const char *file, char *const argv[], process_exit_cb_t cb, void*user) { +pid_t child_process_create(const char *file, char *const argv[], int *ifd, int *ofd, process_exit_cb_t cb, void *user) { pid_t pid; - int fds[2]; + int stdin_fds[2]; + int stdout_fds[2]; + int stderr_fds[2]; + + if (pipe(stdin_fds) < 0) { + daemon_log(LOG_ERR, "pipe() failed: %s", strerror(errno)); + return -1; + } + + if (pipe(stdout_fds) < 0) { + daemon_log(LOG_ERR, "pipe() failed: %s", strerror(errno)); + pipe_close(stdin_fds); + return -1; + } - if (pipe(fds) < 0) { + if (pipe(stderr_fds) < 0) { daemon_log(LOG_ERR, "pipe() failed: %s", strerror(errno)); + pipe_close(stdin_fds); + pipe_close(stdout_fds); return -1; } if ((pid = fork()) < 0) { daemon_log(LOG_ERR, "fork() failed: %s", strerror(errno)); - close(fds[0]); - close(fds[1]); + pipe_close(stdin_fds); + pipe_close(stdout_fds); + pipe_close(stderr_fds); return -1; } @@ -195,11 +226,23 @@ pid_t child_process_create(const char *file, char *const argv[], process_exit_cb p->next = procs; p->killed = 0; - p->client_pipe = fds[0]; - close(fds[1]); + p->stderr_pipe = stderr_fds[0]; + close(stderr_fds[1]); + + if (ifd) + *ifd = stdout_fds[0]; + else + close(stdout_fds[0]); + close(stdout_fds[1]); + + if (ofd) + *ofd = stdin_fds[1]; + else + close(stdin_fds[1]); + close(stdin_fds[0]); assert(event_source && event_source->on_fd); - event_source->on_fd(event_source, p->client_pipe, oop_read_cb, p); + event_source->on_fd(event_source, p->stderr_pipe, OOP_READ, oop_read_cb, p); procs = p; @@ -207,27 +250,42 @@ pid_t child_process_create(const char *file, char *const argv[], process_exit_cb } else { /* child */ - int fd; - close(fds[0]); + close(stderr_fds[0]); + close(stdout_fds[0]); + close(stdin_fds[1]); + for (fd = 0; fd <= 2; fd++) { - if (fd != fds[1]) + if (fd != stderr_fds[1] && fd != stdout_fds[1] && fd != stdin_fds[0]) close(fd); } - if ((fds[1] != 1 && dup2(fds[1], 1) < 0) || - (fds[1] != 2 && dup2(fds[1], 2) < 0)) { + if ((stdin_fds[0] != 0 && dup2(stdin_fds[0], 0) < 0) || + (stdout_fds[1] != 1 && dup2(stdout_fds[1], 1) < 0) || + (stderr_fds[1] != 2 && dup2(stderr_fds[1], 2) < 0)) { daemon_log(LOG_ERR, "dup2() failed: %s", strerror(errno)); exit(1); } - if (fds[1] != 1 && fds[1] != 2) - close(fds[1]); + if (stdin_fds[0] > 2) close(stdin_fds[0]); + if (stdout_fds[1] > 2) close(stdout_fds[1]); + if (stderr_fds[1] > 2) close(stderr_fds[1]); - if (open("/dev/null", O_RDONLY) != 0) { - daemon_log(LOG_ERR, "open(\"/dev/null\") failed: %s", strerror(errno)); - exit(1); + if (!ifd) { + close(1); + if (open("/dev/null", O_WRONLY) != 1) { + daemon_log(LOG_ERR, "open(\"/dev/null\") failed: %s", strerror(errno)); + exit(1); + } + } + + if (!ofd) { + close(0); + if (open("/dev/null", O_RDONLY) != 0) { + daemon_log(LOG_ERR, "open(\"/dev/null\") failed: %s", strerror(errno)); + exit(1); + } } execv(file, argv); |