aboutsummaryrefslogtreecommitdiff
path: root/butl/process.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'butl/process.cxx')
-rw-r--r--butl/process.cxx104
1 files changed, 69 insertions, 35 deletions
diff --git a/butl/process.cxx b/butl/process.cxx
index 1a795ea..4b834fb 100644
--- a/butl/process.cxx
+++ b/butl/process.cxx
@@ -25,6 +25,8 @@
#include <cassert>
+#include <butl/fdstream> // fdnull(), fdclose()
+
using namespace std;
namespace butl
@@ -56,16 +58,13 @@ namespace butl
{
if (fd_ != -1)
{
-#ifndef _WIN32
- int r (close (fd_));
-#else
- int r (_close (fd_));
-#endif
+ bool r (fdclose (fd_));
+
// The valid file descriptor that has no IO operations being
// performed on it should close successfully, unless something is
// severely damaged.
//
- assert (r != -1);
+ assert (r);
}
fd_ = fd;
@@ -98,14 +97,31 @@ namespace butl
p[1].reset (pd[1]);
};
+ auto create_null = [&fail](auto_fd& n)
+ {
+ int fd (fdnull ());
+ if (fd == -1)
+ fail (false);
+
+ n.reset (fd);
+ };
+
+ // If we are asked to open null (-2) then open "half-pipe".
+ //
if (in == -1)
create_pipe (out_fd);
+ else if (in == -2)
+ create_null (out_fd[0]);
if (out == -1)
create_pipe (in_ofd);
+ else if (out == -2)
+ create_null (in_ofd[1]);
if (err == -1)
create_pipe (in_efd);
+ else if (err == -2)
+ create_null (in_efd[1]);
handle = fork ();
@@ -116,16 +132,16 @@ namespace butl
{
// Child.
//
- // Duplicate the user-supplied (fd != -1) or the created pipe descriptor
+ // Duplicate the user-supplied (fd > -1) or the created pipe descriptor
// to the standard stream descriptor (read end for STDIN_FILENO, write
// end otherwise). Close the the pipe afterwards.
//
auto duplicate = [&fail](int sd, int fd, pipe& pd)
{
- if (fd == -1)
+ if (fd == -1 || fd == -2)
fd = pd[sd == STDIN_FILENO ? 0 : 1].get ();
- assert (fd != -1);
+ assert (fd > -1);
if (dup2 (fd, sd) == -1)
fail (true);
@@ -385,14 +401,55 @@ namespace butl
fail ();
};
+ // Resolve file descriptor to HANDLE and make sure it is inherited. Note
+ // that the handle is closed either when CloseHandle() is called for it or
+ // when _close() is called for the associated file descriptor. Make sure
+ // that either the original file descriptor or the resulted HANDLE is
+ // closed but not both of them.
+ //
+ auto get_osfhandle = [&fail](int fd) -> HANDLE
+ {
+ HANDLE h (reinterpret_cast<HANDLE> (_get_osfhandle (fd)));
+ if (h == INVALID_HANDLE_VALUE)
+ fail ("unable to obtain file handle");
+
+ // SetHandleInformation() fails for standard handles. We assume they are
+ // inherited by default.
+ //
+ if (fd != STDIN_FILENO && fd != STDOUT_FILENO && fd != STDERR_FILENO)
+ {
+ if (!SetHandleInformation (
+ h, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT))
+ fail ();
+ }
+
+ return h;
+ };
+
+ auto create_null = [&get_osfhandle, &fail](auto_handle& n)
+ {
+ auto_fd fd (fdnull ());
+ if (fd.get () == -1)
+ fail ();
+
+ n.reset (get_osfhandle (fd.get ()));
+ fd.release (); // Not to close the handle twice.
+ };
+
if (in == -1)
create_pipe (out_h, 1);
+ else if (in == -2)
+ create_null (out_h[0]);
if (out == -1)
create_pipe (in_oh, 0);
+ else if (out == -2)
+ create_null (in_oh[1]);
if (err == -1)
create_pipe (in_eh, 0);
+ else if (err == -2)
+ create_null (in_eh[1]);
// Create the process.
//
@@ -447,42 +504,19 @@ namespace butl
si.cb = sizeof (STARTUPINFO);
si.dwFlags |= STARTF_USESTDHANDLES;
- // Resolve file descriptor to HANDLE and make sure it is inherited. Note
- // that the handle is closed when _close() is called for the associated
- // file descriptor.
- //
- auto get_osfhandle = [&fail](int fd) -> HANDLE
- {
- HANDLE h (reinterpret_cast<HANDLE> (_get_osfhandle (fd)));
- if (h == INVALID_HANDLE_VALUE)
- fail ("unable to obtain file handle");
-
- // SetHandleInformation() fails for standard handles. We assume they are
- // inherited by default.
- //
- if (fd != STDIN_FILENO && fd != STDOUT_FILENO && fd != STDERR_FILENO)
- {
- if (!SetHandleInformation (
- h, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT))
- fail ();
- }
-
- return h;
- };
-
- si.hStdInput = in == -1
+ si.hStdInput = in == -1 || in == -2
? out_h[0].get ()
: in == STDIN_FILENO
? GetStdHandle (STD_INPUT_HANDLE)
: get_osfhandle (in);
- si.hStdOutput = out == -1
+ si.hStdOutput = out == -1 || out == -2
? in_oh[1].get ()
: out == STDOUT_FILENO
? GetStdHandle (STD_OUTPUT_HANDLE)
: get_osfhandle (out);
- si.hStdError = err == -1
+ si.hStdError = err == -1 || err == -2
? in_eh[1].get ()
: err == STDERR_FILENO
? GetStdHandle (STD_ERROR_HANDLE)