summaryrefslogtreecommitdiff
path: root/lib/util/util_runcmd.c
diff options
context:
space:
mode:
authorAndrew Tridgell <tridge@samba.org>2011-11-30 14:07:51 +1100
committerAndrew Bartlett <abartlet@samba.org>2011-12-22 12:26:08 +0100
commit81c564798c84a39c92c2c33d57151a9064940152 (patch)
treecc46fcc28ba3269475eecc45ef87d650959d49db /lib/util/util_runcmd.c
parent711c18c2301d1bea35cac1144080a94e6b89be27 (diff)
downloadsamba-81c564798c84a39c92c2c33d57151a9064940152.tar.gz
runcmd: use a pipe for stdin to child processes
this allows child processes to detect the exit of the parent by looking for EOF on stdin
Diffstat (limited to 'lib/util/util_runcmd.c')
-rw-r--r--lib/util/util_runcmd.c53
1 files changed, 46 insertions, 7 deletions
diff --git a/lib/util/util_runcmd.c b/lib/util/util_runcmd.c
index cfe0034a32f..8a475ef301d 100644
--- a/lib/util/util_runcmd.c
+++ b/lib/util/util_runcmd.c
@@ -33,9 +33,10 @@
struct samba_runcmd_state {
int stdout_log_level;
int stderr_log_level;
+ struct tevent_fd *fde_stdin;
struct tevent_fd *fde_stdout;
struct tevent_fd *fde_stderr;
- int fd_stdout, fd_stderr;
+ int fd_stdin, fd_stdout, fd_stderr;
char *arg0;
pid_t pid;
char buf[1024];
@@ -72,7 +73,7 @@ struct tevent_req *samba_runcmd_send(TALLOC_CTX *mem_ctx,
{
struct tevent_req *req;
struct samba_runcmd_state *state;
- int p1[2], p2[2];
+ int p1[2], p2[2], p3[2];
char **argv;
va_list ap;
@@ -100,6 +101,14 @@ struct tevent_req *samba_runcmd_send(TALLOC_CTX *mem_ctx,
tevent_req_error(req, errno);
return tevent_req_post(req, ev);
}
+ if (pipe(p3) != 0) {
+ close(p1[0]);
+ close(p1[1]);
+ close(p2[0]);
+ close(p2[1]);
+ tevent_req_error(req, errno);
+ return tevent_req_post(req, ev);
+ }
state->pid = fork();
if (state->pid == (pid_t)-1) {
@@ -107,6 +116,8 @@ struct tevent_req *samba_runcmd_send(TALLOC_CTX *mem_ctx,
close(p1[1]);
close(p2[0]);
close(p2[1]);
+ close(p3[0]);
+ close(p3[1]);
tevent_req_error(req, errno);
return tevent_req_post(req, ev);
}
@@ -115,10 +126,14 @@ struct tevent_req *samba_runcmd_send(TALLOC_CTX *mem_ctx,
/* the parent */
close(p1[1]);
close(p2[1]);
+ close(p3[0]);
state->fd_stdout = p1[0];
state->fd_stderr = p2[0];
+ state->fd_stdin = p3[1];
+
set_blocking(state->fd_stdout, false);
set_blocking(state->fd_stderr, false);
+ set_blocking(state->fd_stdin, false);
talloc_set_destructor(state, samba_runcmd_state_destructor);
@@ -128,8 +143,9 @@ struct tevent_req *samba_runcmd_send(TALLOC_CTX *mem_ctx,
samba_runcmd_io_handler,
req);
if (tevent_req_nomem(state->fde_stdout, req)) {
- close(p1[0]);
- close(p2[0]);
+ close(state->fd_stdout);
+ close(state->fd_stderr);
+ close(state->fd_stdin);
return tevent_req_post(req, ev);
}
tevent_fd_set_auto_close(state->fde_stdout);
@@ -140,11 +156,23 @@ struct tevent_req *samba_runcmd_send(TALLOC_CTX *mem_ctx,
samba_runcmd_io_handler,
req);
if (tevent_req_nomem(state->fde_stdout, req)) {
- close(p2[0]);
+ close(state->fd_stderr);
+ close(state->fd_stdin);
return tevent_req_post(req, ev);
}
tevent_fd_set_auto_close(state->fde_stderr);
+ state->fde_stdin = tevent_add_fd(ev, state,
+ state->fd_stdin,
+ 0,
+ samba_runcmd_io_handler,
+ req);
+ if (tevent_req_nomem(state->fde_stdin, req)) {
+ close(state->fd_stdin);
+ return tevent_req_post(req, ev);
+ }
+ tevent_fd_set_auto_close(state->fde_stdin);
+
if (!timeval_is_zero(&endtime)) {
tevent_req_set_endtime(req, ev, endtime);
}
@@ -155,6 +183,7 @@ struct tevent_req *samba_runcmd_send(TALLOC_CTX *mem_ctx,
/* the child */
close(p1[0]);
close(p2[0]);
+ close(p3[1]);
close(0);
close(1);
close(2);
@@ -164,7 +193,7 @@ struct tevent_req *samba_runcmd_send(TALLOC_CTX *mem_ctx,
tevent_re_initialise(ev);
/* setup for logging to go to the parents debug log */
- open("/dev/null", O_RDONLY); /* for stdin */
+ dup2(p3[0], 0);
dup2(p1[1], 1);
dup2(p2[1], 2);
@@ -211,9 +240,19 @@ static void samba_runcmd_io_handler(struct tevent_context *ev,
if (fde == state->fde_stdout) {
level = state->stdout_log_level;
fd = state->fd_stdout;
- } else {
+ } else if (fde == state->fde_stderr) {
level = state->stderr_log_level;
fd = state->fd_stderr;
+ } else if (fde == state->fde_stdin) {
+ char c;
+ if (read(state->fd_stdin, &c, 1) != 1) {
+ /* the child has closed its stdin */
+ talloc_free(fde);
+ state->fde_stdin = NULL;
+ return;
+ }
+ } else {
+ return;
}
if (!(flags & TEVENT_FD_READ)) {