summaryrefslogtreecommitdiffstats
path: root/src/exec.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/exec.c')
-rw-r--r--src/exec.c118
1 files changed, 88 insertions, 30 deletions
diff --git a/src/exec.c b/src/exec.c
index d9d8e49..728c574 100644
--- a/src/exec.c
+++ b/src/exec.c
@@ -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);