runcmd: use a pipe for stdin to child processes
authorAndrew Tridgell <tridge@samba.org>
Wed, 30 Nov 2011 03:07:51 +0000 (14:07 +1100)
committerAndrew Bartlett <abartlet@samba.org>
Thu, 22 Dec 2011 11:26:08 +0000 (12:26 +0100)
this allows child processes to detect the exit of the parent by
looking for EOF on stdin

lib/util/util_runcmd.c

index cfe0034a32f240fd36aa5cb1b1aea6990476d883..8a475ef301d01dad1feb54c4bb6c518e3b00d106 100644 (file)
 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)) {