diff options
Diffstat (limited to 'libadhocutil/processPipes.cpp')
-rw-r--r-- | libadhocutil/processPipes.cpp | 139 |
1 files changed, 66 insertions, 73 deletions
diff --git a/libadhocutil/processPipes.cpp b/libadhocutil/processPipes.cpp index 0c25045..efdcc88 100644 --- a/libadhocutil/processPipes.cpp +++ b/libadhocutil/processPipes.cpp @@ -5,75 +5,73 @@ #include <sys/resource.h> #include <stdexcept> #include <sys.h> -#include "scopeExit.h" +#include "c++11Helpers.h" -// NOLINTNEXTLINE(modernize-concat-nested-namespaces) -namespace AdHoc { -namespace System { - -using PipePair = std::array<int, 2>; -static -void -pipe(PipePair & pipes, ScopeExit & tidyUp) +namespace AdHoc::System { +ProcessPipes::InitPipe +ProcessPipes::pipeSetup(bool setup, bool swap) { - if (::pipe(pipes.data())) { - throw SystemException("pipe(2) failed", strerror(errno), errno); + if (setup) { + PipePair pair; + if (::pipe(&pair.first)) { + throw SystemException("pipe(2) failed", strerror(errno), errno); + } + if (swap) { + std::swap(pair.first, pair.second); + } + return pair; } - tidyUp.onFailure.emplace_back([pipes] { - close(pipes[0]); - close(pipes[1]); - }); + return {}; } -ProcessPipes::ProcessPipes(const std::vector<std::string> & args, bool i, bool o, bool e) : - in(-1), - out(-1), - error(-1) +void ProcessPipes::closeChild(const InitPipe & pipe) noexcept { - if (args.empty()) { - throw std::invalid_argument("args is empty"); - } - PipePair ipipes { -1, -1 }, opipes { -1, -1 }, epipes { -1, -1 }; - ScopeExit tidyUp; - if (i) { - pipe(ipipes, tidyUp); + if (pipe) { + close(pipe->second); } - if (o) { - pipe(opipes, tidyUp); - } - if (e) { - pipe(epipes, tidyUp); +} + +void ProcessPipes::dupChild(int fd, const InitPipe & pipe) noexcept +{ + if (pipe) { + close(pipe->first); + dup2(pipe->second, fd); } - switch (child = fork()) { - case -1: // fail - throw SystemException("fork(2) failed", strerror(errno), errno); +} + +ProcessPipes::ProcessPipes(const std::vector<std::string> & args, bool i, bool o, bool e) : + ProcessPipes([&args](){ + if (args.empty()) { + throw std::invalid_argument("args is empty"); + } + return args; + }(), pipeSetup(i, true), pipeSetup(o, false), pipeSetup(e, false)) +{ +} + +ProcessPipes::ProcessPipes(const std::vector<std::string> & args, InitPipe && ipp, InitPipe && opp, InitPipe && epp) : + child([]() { + if (pid_t p = fork(); p != -1) { + return p; + } + /// LCOV_EXCL_START (fork won't fail) + throw SystemException("fork(2) failed", strerror(errno), errno); + /// LCOV_EXCL_STOP + }()), + in(ipp ? std::make_optional<FHandle>(ipp->first, &close) : OFHandle()), + out(opp ? std::make_optional<FHandle>(opp->first, &close) : OFHandle()), + error(epp ? std::make_optional<FHandle>(epp->first, &close) : OFHandle()) +{ + switch (child) { default: // parent - if (i) { - close(ipipes[0]); - in = ipipes[1]; - } - if (o) { - close(opipes[1]); - out = opipes[0]; - } - if (e) { - close(epipes[1]); - error = epipes[0]; - } + closeChild(ipp); + closeChild(opp); + closeChild(epp); break; case 0: // in child - if (i) { - close(ipipes[1]); - dup2(ipipes[0], 0); - } - if (o) { - close(opipes[0]); - dup2(opipes[1], 1); - } - if (e) { - close(epipes[0]); - dup2(epipes[1], 2); - } + dupChild(STDIN_FILENO, ipp); + dupChild(STDOUT_FILENO, opp); + dupChild(STDERR_FILENO, epp); closeAllOpenFiles(); std::vector<char *> buf(args.size() + 1); auto w = buf.begin(); @@ -89,35 +87,32 @@ ProcessPipes::ProcessPipes(const std::vector<std::string> & args, bool i, bool o } } -ProcessPipes::~ProcessPipes() +int +ProcessPipes::closeIn() { - if (in >= 0) { - close(in); - } - if (out >= 0) { - close(out); - } - if (error >= 0) { - close(error); + if (in) { + in.reset(); + return 0; } + return EBADF; } int ProcessPipes::fdIn() const noexcept { - return in; + return in ? *in : -1; } int ProcessPipes::fdOut() const noexcept { - return out; + return out ? *out : -1; } int ProcessPipes::fdError() const noexcept { - return error; + return error ? *error : -1; } pid_t @@ -127,7 +122,7 @@ ProcessPipes::pid() const noexcept } void -ProcessPipes::closeAllOpenFiles() +ProcessPipes::closeAllOpenFiles() noexcept { rlimit lim { }; getrlimit(RLIMIT_NOFILE, &lim); @@ -143,7 +138,5 @@ ProcessPipes::closeAllOpenFiles() } } } - -} } |