summaryrefslogtreecommitdiff
path: root/libadhocutil/processPipes.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'libadhocutil/processPipes.cpp')
-rw-r--r--libadhocutil/processPipes.cpp138
1 files changed, 138 insertions, 0 deletions
diff --git a/libadhocutil/processPipes.cpp b/libadhocutil/processPipes.cpp
new file mode 100644
index 0000000..55050ae
--- /dev/null
+++ b/libadhocutil/processPipes.cpp
@@ -0,0 +1,138 @@
+#include "processPipes.h"
+#include <unistd.h>
+#include <poll.h>
+#include <string.h>
+#include <sys/resource.h>
+#include <stdexcept>
+
+ProcessPipes::ProcessPipes(const std::vector<std::string> & args, bool i, bool o, bool e) :
+ in(-1),
+ out(-1),
+ error(-1)
+{
+ int ipipes[2], opipes[2], epipes[2];
+ if (i) {
+ if (pipe(ipipes)) {
+ throw std::runtime_error("Failed to create stdin pipe");
+ }
+ }
+ if (o) {
+ if (pipe(opipes)) {
+ if (i) {
+ close(ipipes[0]);
+ close(ipipes[1]);
+ }
+ throw std::runtime_error("Failed to create stdout pipe");
+ }
+ }
+ if (e) {
+ if (pipe(epipes)) {
+ if (i) {
+ close(ipipes[0]);
+ close(ipipes[1]);
+ }
+ if (o) {
+ close(opipes[0]);
+ close(opipes[1]);
+ }
+ throw std::runtime_error("Failed to create stderr pipe");
+ }
+ }
+ switch (child = fork()) {
+ case -1: // fail
+ if (i) {
+ close(ipipes[0]);
+ close(ipipes[1]);
+ }
+ if (o) {
+ close(opipes[0]);
+ close(opipes[1]);
+ }
+ if (e) {
+ close(epipes[0]);
+ close(epipes[1]);
+ }
+ throw std::runtime_error("Failed to fork");
+ 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];
+ }
+ break;
+ case 0: // in child
+ rlimit lim;
+ getrlimit(RLIMIT_NOFILE, &lim);
+ 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);
+ }
+ std::vector<struct pollfd> fds;
+ fds.reserve(lim.rlim_max);
+ for (int n = 3; n < (int)lim.rlim_max; n += 1) {
+ fds.push_back({n, 0, 0});
+ }
+ poll(&fds.front(), fds.size(), 0);
+ for(const auto & pfd : fds) {
+ if (!(pfd.revents & POLLNVAL)) {
+ close(pfd.fd);
+ }
+ }
+ char * buf[100];
+ char ** w = &buf[0];
+ for (const auto & p : args) {
+ *w++ = strdup(p.c_str());
+ }
+ *w = NULL;
+ execv(buf[0], buf);
+ abort();
+ break;
+ }
+}
+
+ProcessPipes::~ProcessPipes()
+{
+ if (in) close(in);
+ if (out) close(out);
+ if (error) close(error);
+}
+
+int
+ProcessPipes::fdIn() const
+{
+ return in;
+}
+
+int
+ProcessPipes::fdOut() const
+{
+ return out;
+}
+
+int
+ProcessPipes::fdError() const
+{
+ return error;
+}
+
+pid_t
+ProcessPipes::pid() const
+{
+ return child;
+}
+