aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2015-07-23 14:47:09 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2015-07-23 14:47:09 +0200
commite2d759fce9ff5e5886064ec693af54fe598773ff (patch)
tree2ecc81af9347fdf5b60182536dabdf24e9fd9546
parent9565dd32bbd68d2fada2fbe2ece4b778b43e6bb0 (diff)
Add support for process redirection to existing fd, piping
-rw-r--r--butl/process44
-rw-r--r--butl/process.cxx64
2 files changed, 70 insertions, 38 deletions
diff --git a/butl/process b/butl/process
index 52aad41..cf18acd 100644
--- a/butl/process
+++ b/butl/process
@@ -28,18 +28,36 @@ namespace butl
struct process
{
- // Start another process using the specified command line. Connect the
- // newly created process' stdin to out_fd. Also if connect_* are true,
- // connect the created process' stdout and stderr to in_*fd. Throw
- // process_error if anything goes wrong.
+ // Start another process using the specified command line. The default
+ // values to the in, out and err arguments indicate that the child
+ // process should inherit the parent process stdin, stdout, and stderr,
+ // respectively. If -1 is passed instead, then the corresponding child
+ // process descriptor is connected (via a pipe) to out_fd for stdin,
+ // in_ofd for stdout, and in_efd for stderr (see data members below).
+ //
+ // Instead of passing -1 or the default value, you can also pass your
+ // own descriptors. Note, however, that in this case they are not
+ // closed by the parent. So you should do this yourself, if required.
+ // For example, to redirect the child process stdout to stderr, you
+ // can do:
+ //
+ // process p (..., 0, 2);
//
- // Note that some of the exceptions (e.g., if exec() failed) can be
- // thrown in the child version of us.
+ // Throw process_error if anything goes wrong. Note that some of the
+ // exceptions (e.g., if exec() failed) can be thrown in the child
+ // version of us.
//
- process (char const* args[],
- bool connect_stdin = false,
- bool connect_stderr = false,
- bool connect_stdout = false);
+ process (char const* args[], int in = 0, int out = 1, int err = 2);
+
+ // The "piping" constructor, for example:
+ //
+ // process lhs (..., 0, -1); // Redirect stdout to a pipe.
+ // process rhs (..., lhs); // Redirect stdin to lhs's pipe.
+ //
+ // rhs.wait (); // Wait for last first.
+ // lhs.wait ();
+ //
+ process (char const* args[], process& in, int out = 1, int err = 2);
// Wait for the process to terminate. Return true if the process
// terminated normally and with the zero exit status. Throw
@@ -50,6 +68,9 @@ namespace butl
~process () {if (id != 0) wait ();}
+ process (const process&) = delete;
+ process& operator= (const process&) = delete;
+
#ifndef _WIN32
typedef pid_t id_type;
#else
@@ -57,9 +78,10 @@ namespace butl
#endif
id_type id;
+
int out_fd; // Write to this fd to send to the new process' stdin.
- int in_efd; // Read from this fd to receive from the new process' stderr.
int in_ofd; // Read from this fd to receive from the new process' stdout.
+ int in_efd; // Read from this fd to receive from the new process' stderr.
};
}
diff --git a/butl/process.cxx b/butl/process.cxx
index 35ca26d..a456217 100644
--- a/butl/process.cxx
+++ b/butl/process.cxx
@@ -16,6 +16,8 @@
# include <fcntl.h> // _O_TEXT
#endif
+#include <cassert>
+
using namespace std;
namespace butl
@@ -23,15 +25,15 @@ namespace butl
#ifndef _WIN32
process::
- process (char const* args[], bool in, bool err, bool out)
+ process (char const* args[], int in, int out, int err)
{
- int out_fd[2];
- int in_efd[2];
- int in_ofd[2];
+ int out_fd[2] = {in, 0};
+ int in_ofd[2] = {0, out};
+ int in_efd[2] = {0, err};
- if ((in && pipe (out_fd) == -1) ||
- (err && pipe (in_efd) == -1) ||
- (out && pipe (in_ofd) == -1))
+ if ((in == -1 && pipe (out_fd) == -1) ||
+ (out == -1 && pipe (in_ofd) == -1) ||
+ (err == -1 && pipe (in_efd) == -1))
throw process_error (errno, false);
id = fork ();
@@ -44,31 +46,31 @@ namespace butl
// Child. If requested, close the write end of the pipe and duplicate
// the read end to stdin. Then close the original read end descriptor.
//
- if (in)
+ if (in != STDIN_FILENO)
{
- if (close (out_fd[1]) == -1 ||
- dup2 (out_fd[0], STDIN_FILENO) == -1 ||
- close (out_fd[0]) == -1)
+ if ((in == -1 && close (out_fd[1]) == -1) ||
+ dup2 (out_fd[0], STDIN_FILENO) == -1 ||
+ (in == -1 && close (out_fd[0]) == -1))
throw process_error (errno, true);
}
- // Do the same for the stderr if requested.
+ // Do the same for the stdout if requested.
//
- if (err)
+ if (out != STDOUT_FILENO)
{
- if (close (in_efd[0]) == -1 ||
- dup2 (in_efd[1], STDERR_FILENO) == -1 ||
- close (in_efd[1]) == -1)
+ if ((out == -1 && close (in_ofd[0]) == -1) ||
+ dup2 (in_ofd[1], STDOUT_FILENO) == -1 ||
+ (out == -1 && close (in_ofd[1]) == -1))
throw process_error (errno, true);
}
- // Do the same for the stdout if requested.
+ // Do the same for the stderr if requested.
//
- if (out)
+ if (err != STDERR_FILENO)
{
- if (close (in_ofd[0]) == -1 ||
- dup2 (in_ofd[1], STDOUT_FILENO) == -1 ||
- close (in_ofd[1]) == -1)
+ if ((err == -1 && close (in_efd[0]) == -1) ||
+ dup2 (in_efd[1], STDERR_FILENO) == -1 ||
+ (err == -1 && close (in_efd[1]) == -1))
throw process_error (errno, true);
}
@@ -79,15 +81,23 @@ namespace butl
{
// Parent. Close the other ends of the pipes.
//
- if ((in && close (out_fd[0]) == -1) ||
- (err && close (in_efd[1]) == -1) ||
- (out && close (in_ofd[1]) == -1))
+ if ((in == -1 && close (out_fd[0]) == -1) ||
+ (out == -1 && close (in_ofd[1]) == -1) ||
+ (err == -1 && close (in_efd[1]) == -1))
throw process_error (errno, false);
}
- this->out_fd = in ? out_fd[1] : 0;
- this->in_efd = err ? in_efd[0] : 0;
- this->in_ofd = out ? in_ofd[0] : 0;
+ this->out_fd = in == -1 ? out_fd[1] : -1;
+ this->in_ofd = out == -1 ? in_ofd[0] : -1;
+ this->in_efd = err == -1 ? in_efd[0] : -1;
+ }
+
+ process::
+ process (char const* args[], process& in, int out, int err)
+ : process (args, in.in_ofd, out, err)
+ {
+ assert (in.in_ofd != -1); // Should be a pipe.
+ close (in.in_ofd); // Close it on our side.
}
bool process::