ctdb-common: Update run_proc api to re-assign stdin
authorAmitay Isaacs <amitay@gmail.com>
Fri, 5 May 2017 16:47:00 +0000 (02:47 +1000)
committerMartin Schwenke <martins@samba.org>
Tue, 30 May 2017 01:58:06 +0000 (03:58 +0200)
This allows to pass data to a child process via stdin.

Signed-off-by: Amitay Isaacs <amitay@gmail.com>
Reviewed-by: Martin Schwenke <martin@meltin.net>
ctdb/common/run_proc.c
ctdb/common/run_proc.h
ctdb/server/ctdb_eventd.c
ctdb/tests/cunit/run_proc_001.sh
ctdb/tests/src/run_proc_test.c

index f9fee80e9072c36db6a986afd58b56df1e0ac043..53862026bd582698b2b38c2ac82ee4a64874f03f 100644 (file)
@@ -67,7 +67,7 @@ static void proc_read_handler(struct tevent_context *ev,
                              void *private_data);
 
 static int proc_start(struct proc_context *proc, struct tevent_context *ev,
-                     const char *path, const char **argv)
+                     const char *path, const char **argv, int stdin_fd)
 {
        int fd[2];
        int ret;
@@ -99,6 +99,13 @@ static int proc_start(struct proc_context *proc, struct tevent_context *ev,
 
                close(fd[1]);
 
+               if (stdin_fd != -1) {
+                       ret = dup2(stdin_fd, STDIN_FILENO);
+                       if (ret == -1) {
+                               exit(64 + errno);
+                       }
+               }
+
                ret = setpgid(0, 0);
                if (ret != 0) {
                        exit(64 + errno);
@@ -382,7 +389,7 @@ struct tevent_req *run_proc_send(TALLOC_CTX *mem_ctx,
                                 struct tevent_context *ev,
                                 struct run_proc_context *run_ctx,
                                 const char *path, const char **argv,
-                                struct timeval timeout)
+                                int stdin_fd, struct timeval timeout)
 {
        struct tevent_req *req;
        struct run_proc_state *state;
@@ -415,7 +422,7 @@ struct tevent_req *run_proc_send(TALLOC_CTX *mem_ctx,
                return tevent_req_post(req, ev);
        }
 
-       ret = proc_start(state->proc, ev, path, argv);
+       ret = proc_start(state->proc, ev, path, argv, stdin_fd);
        if (ret != 0) {
                tevent_req_error(req, ret);
                return tevent_req_post(req, ev);
index 4287347cc64436f02b10bb1fb128e436944a7058..7de0c84f85737a6dd2d039968c3fe967eea5b51d 100644 (file)
@@ -68,6 +68,7 @@ int run_proc_init(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
  * @param[in] run_ctx Run_proc context
  * @param[in] prog The path to the executable
  * @param[in] argv Arguments to the executable
+ * @param[in] stdin_fd Assign stdin_fd as stdin for the process, -1 if not
  * @param[in] timeout How long to wait for execution
  * @return new tevent request, or NULL on failure
  *
@@ -77,7 +78,7 @@ struct tevent_req *run_proc_send(TALLOC_CTX *mem_ctx,
                                 struct tevent_context *ev,
                                 struct run_proc_context *run_ctx,
                                 const char *prog, const char **argv,
-                                struct timeval timeout);
+                                int stdin_fd, struct timeval timeout);
 
 /**
  * @brief Async computation end to run an executable
index 232711ce4e24586bd463f8e478196239a64dfdc4..3542b4fb6f06028f4d833b6514b47592a8081357 100644 (file)
@@ -343,7 +343,7 @@ static struct tevent_req *run_debug_send(TALLOC_CTX *mem_ctx,
                debug_script, argv[1], argv[2]);
 
        subreq = run_proc_send(state, ev, ectx->run_ctx, debug_script, argv,
-                              tevent_timeval_zero());
+                              -1, tevent_timeval_zero());
        if (tevent_req_nomem(subreq, req)) {
                return tevent_req_post(req, ev);
        }
@@ -709,7 +709,7 @@ static struct tevent_req *run_event_run_script(struct tevent_req *req)
                path, state->argv[0], state->argv[1]);
 
        subreq = run_proc_send(state, state->ev, state->ectx->run_ctx,
-                              path, state->argv, state->timeout);
+                              path, state->argv, -1, state->timeout);
 
        talloc_free(path);
 
index e1937a82f2885369cca5b45d5dcc3f782ccf1c3f..b817637e574b6afafd86e6e5141fd2dace08a5d1 100755 (executable)
@@ -6,7 +6,7 @@
 ok <<EOF
 Process exited with error 2
 EOF
-unit_test run_proc_test 0 /a/b/c
+unit_test run_proc_test 0 -1 /a/b/c
 
 # Non-executable path
 prog=$(mktemp --tmpdir="$TEST_VAR_DIR")
@@ -17,7 +17,7 @@ EOF
 ok <<EOF
 Process exited with error 13
 EOF
-unit_test run_proc_test 0 "$prog"
+unit_test run_proc_test 0 -1 "$prog"
 
 # Executable path
 chmod +x "$prog"
@@ -25,7 +25,7 @@ chmod +x "$prog"
 ok <<EOF
 Process exited with error 8
 EOF
-unit_test run_proc_test 0 "$prog"
+unit_test run_proc_test 0 -1 "$prog"
 
 # Capture output
 cat > "$prog" <<EOF
@@ -38,7 +38,7 @@ Process exited with status 0
 Output = (hello
 )
 EOF
-unit_test run_proc_test 0 "$prog"
+unit_test run_proc_test 0 -1 "$prog"
 
 # Specify timeout
 ok <<EOF
@@ -46,7 +46,7 @@ Process exited with status 0
 Output = (hello
 )
 EOF
-unit_test run_proc_test 5 "$prog"
+unit_test run_proc_test 5 -1 "$prog"
 
 # Redirected output
 output=$(mktemp --tmpdir="$TEST_VAR_DIR")
@@ -59,7 +59,7 @@ EOF
 ok <<EOF
 Process exited with status 0
 EOF
-unit_test run_proc_test 0 "$prog"
+unit_test run_proc_test 0 -1 "$prog"
 
 ok <<EOF
 hello
@@ -75,7 +75,7 @@ EOF
 ok <<EOF
 Process exited with status 1
 EOF
-unit_test run_proc_test 0 "$prog"
+unit_test run_proc_test 0 -1 "$prog"
 
 # Exit with signal
 cat > "$prog" <<EOF
@@ -86,7 +86,7 @@ EOF
 ok <<EOF
 Process exited with signal 15
 EOF
-unit_test run_proc_test 0 "$prog"
+unit_test run_proc_test 0 -1 "$prog"
 
 # Exit with timeout
 cat > "$prog" <<EOF
@@ -107,7 +107,7 @@ Child = PID
 Output = (Sleeping for 5 seconds
 )
 EOF
-unit_test run_proc_test 1 "$prog"
+unit_test run_proc_test 1 -1 "$prog"
 
 # No zombie processes
 pidfile=$(mktemp --tmpdir="$TEST_VAR_DIR")
@@ -122,7 +122,7 @@ ok <<EOF
 Process exited with error 62
 Child = PID
 EOF
-unit_test run_proc_test 1 "$prog"
+unit_test run_proc_test 1 -1 "$prog"
 
 result_filter ()
 {
@@ -136,5 +136,23 @@ HEADER
 EOF
 unit_test ps -p "$pid"
 
+# Redirect stdin
+cat > "$prog" <<EOF
+#!/bin/sh
+cat -
+EOF
+
+cat > "$output" <<EOF
+this is sample input
+EOF
+
+ok <<EOF
+Process exited with status 0
+Output = (this is sample input
+)
+EOF
+(unit_test run_proc_test 0 4 "$prog") 4<"$output"
+
 rm -f "$pidfile"
+rm -f "$output"
 rm -f "$prog"
index 6db783d378f881c0264870c712296eacc215e036..7cfb8703e994876d54bbc23518a530f426a6f9cd 100644 (file)
@@ -35,11 +35,12 @@ int main(int argc, const char **argv)
        char *output;
        struct run_proc_result result;
        pid_t pid;
-       int timeout, ret;
+       int timeout, ret, fd;
        bool status;
 
-       if (argc < 3) {
-               fprintf(stderr, "Usage: %s <timeout> <program> <args>\n",
+       if (argc < 4) {
+               fprintf(stderr,
+                       "Usage: %s <timeout> <stdin-fd> <program> <args>\n",
                        argv[0]);
                exit(1);
        }
@@ -63,13 +64,18 @@ int main(int argc, const char **argv)
                tv = tevent_timeval_current_ofs(timeout, 0);
        }
 
+       fd = atoi(argv[2]);
+       if (fd < 0) {
+               fd = -1;
+       }
+
        ret = run_proc_init(mem_ctx, ev, &run_ctx);
        if (ret != 0) {
                fprintf(stderr, "run_proc_init() failed, ret=%d\n", ret);
                exit(1);
        }
 
-       req = run_proc_send(mem_ctx, ev, run_ctx, argv[2], &argv[2], tv);
+       req = run_proc_send(mem_ctx, ev, run_ctx, argv[3], &argv[3], fd, tv);
        if (req == NULL) {
                fprintf(stderr, "run_proc_send() failed\n");
                exit(1);