lib: Make async_sock includable on its own
[kai/samba.git] / lib / util / util_runcmd.c
index 50a3db7f7281c334ff72101f6d55b4dd6cf57404..cc274c21d54c3a76423818a59ed66a1a2f954709 100644 (file)
 #include "includes.h"
 #include "system/filesys.h"
 #include <tevent.h>
-#include <tevent_unix.h>
+#include "../lib/util/tevent_unix.h"
 
 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,9 +73,8 @@ 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;
-       int ret;
        va_list ap;
 
        req = tevent_req_create(mem_ctx, &state,
@@ -101,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) {
@@ -108,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);
        }
@@ -116,10 +126,18 @@ 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);
+
+               smb_set_close_on_exec(state->fd_stdin);
+               smb_set_close_on_exec(state->fd_stdout);
+               smb_set_close_on_exec(state->fd_stderr);
 
                talloc_set_destructor(state, samba_runcmd_state_destructor);
 
@@ -129,8 +147,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);
@@ -141,11 +160,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);
                }
@@ -156,6 +187,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);
@@ -165,10 +197,14 @@ 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);
 
+       close(p1[1]);
+       close(p2[1]);
+       close(p3[0]);
+
        argv = str_list_copy(state, discard_const_p(const char *, argv0));
        if (!argv) {
                fprintf(stderr, "Out of memory in child\n");
@@ -187,7 +223,7 @@ struct tevent_req *samba_runcmd_send(TALLOC_CTX *mem_ctx,
        }
        va_end(ap);
 
-       ret = execvp(state->arg0, argv);
+       (void)execvp(state->arg0, argv);
        fprintf(stderr, "Failed to exec child - %s\n", strerror(errno));
        _exit(255);
        return NULL;
@@ -212,9 +248,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)) {