diff options
author | Andrew Tridgell <tridge@samba.org> | 2011-11-30 14:07:51 +1100 |
---|---|---|
committer | Andrew Bartlett <abartlet@samba.org> | 2011-12-22 12:26:08 +0100 |
commit | 81c564798c84a39c92c2c33d57151a9064940152 (patch) | |
tree | cc46fcc28ba3269475eecc45ef87d650959d49db /lib/util/util_runcmd.c | |
parent | 711c18c2301d1bea35cac1144080a94e6b89be27 (diff) | |
download | samba-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.c | 53 |
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)) { |