From 8671686e8072041a4a5cb1fcd7dcf93ab86b1e88 Mon Sep 17 00:00:00 2001 From: Christos Houtouridis Date: Thu, 14 Feb 2019 16:53:18 +0200 Subject: [PATCH] pipes: ... in progress ... --- src/sequencer.cpp | 83 ++++++++++++++++++++++++++++++++++++----------- src/sequencer.h | 16 ++++++--- 2 files changed, 75 insertions(+), 24 deletions(-) diff --git a/src/sequencer.cpp b/src/sequencer.cpp index c219263..5291155 100755 --- a/src/sequencer.cpp +++ b/src/sequencer.cpp @@ -63,6 +63,9 @@ namespace snel { Child::~Child () { for (int i=0 ; i<3 ; ++i) restore_std_if(i); + // close any leaked pipes +// if (pipe_.fd[0] != -1) close(pipe_.fd[0]); +// if (pipe_.fd[1] != -1) close(pipe_.fd[1]); } void Child::redirect_std_if(std::string fn, fd_t std_fd) { @@ -89,26 +92,36 @@ namespace snel { } Child& Child::make_arguments () { bool in{false}, out{false}, err{false}; + bool CanRedirectIn = (pipe_.from) ? true : false; + bool CanRedirectOut = (!pipe_.to) ? true : false; for (auto& t: command) { - if (t == "" || t== " ") continue; // skip crap + if (t == "" || t== " " || t=="|") continue; // skip crap if (t == "&&") logic = LogicOp::AND; else if (t == "||") logic = LogicOp::OR; // one pass redirection parsing - else if (!t.compare(0, 1, "<")) filenames[STDIN_] = t.substr(1); - else if (!t.compare(0, 1, ">")) filenames[STDOUT_] = t.substr(1); - else if (!t.compare(0, 2, "1>")) filenames[STDOUT_] = t.substr(2); - else if (!t.compare(0, 2, "2>")) filenames[STDERR_] = t.substr(2); + else if (CanRedirectIn && !t.compare(0, 1, "<")) + filenames[STDIN_] = t.substr(1); + else if (CanRedirectOut&& !t.compare(0, 1, ">")) + filenames[STDOUT_] = t.substr(1); + else if (CanRedirectOut&& !t.compare(0, 2, "1>")) + filenames[STDOUT_] = t.substr(2); + else if (!t.compare(0, 2, "2>")) + filenames[STDERR_] = t.substr(2); // two pass redirection parsing (if redirection came in 2 arguments) else if (t == "<") in = true; else if (t == "1>" || t == ">") out = true; else if (t == "2>") err = true; else if (in) { - filenames[STDIN_] = t; in = false; + if (CanRedirectIn) + filenames[STDIN_] = t; + in = false; } else if (out) { - filenames[STDOUT_] = t; out = false; + if (CanRedirectOut) + filenames[STDOUT_] = t; + out = false; } else if (err) { filenames[STDERR_] = t; err = false; @@ -119,24 +132,45 @@ namespace snel { return *this; } - bool Child::execute() { + bool Child::execute(const Child* previous) { bool stop = {false}; + // Check parent redirection redirect_std_if (filenames[STDIN_], STDIN_); redirect_std_if (filenames[STDOUT_], STDOUT_); redirect_std_if (filenames[STDERR_], STDERR_); + + // Check parent pipe control + if (pipe_.to) { + if((::pipe (pipe_.fd)) == -1) + throw Error("Child: Can not create pipe"); + } pid_t pid = fork(); if (pid < 0) { - throw Error("Child::execute(): Can not create child process"); + throw Error("Child: Can not create child process"); } else if (pid == 0) { // child - + // Some extra pipe checking while we still have our data + if (pipe_.to) { // transmitting child + close(pipe_.fd[0]); // close the read end + if ((dup2(pipe_.fd[1], STDOUT_)) == -1) // redirect output + throw Error("Child pipe[to]: Can not redirect through pipe"); + } + else if ((previous!= nullptr) && pipe_.from) { // receiveing child + std::cout << "from[0]=" << previous->pipe().fd[0] << " from[1]=" << previous->pipe().fd[1]<< std::endl; + close (previous->pipe().fd[1]); // close the write end + if ((dup2(previous->pipe().fd[0], STDIN_)) == -1) // redirect input + throw Error("Child pipe[from]: Can not redirect through pipe"); + } execvp(arguments.front(), arguments.data()); // error if we got here std::cout << "Can not invoke: " << arguments.front() << std::endl; - throw Error("Child::execute(): Can not run child process"); + throw Error("Child: Can not run child process"); } else { // parent + if (pipe_.to) close (pipe_.fd[1]); + else if (pipe_.from) close (previous->pipe().fd[0]); + int exit_status; waitpid(pid, &exit_status, 0); // wait child process to finish restore_std_if (STDIN_); @@ -171,31 +205,42 @@ namespace snel { tokens.clear(); // make a new token vector for command split (s, tokens, ' '); - seq_.emplace_back(std::vector{}); // make a new child for command + seq_.emplace_back(std::vector{}); // make a new child for command // check tokens inside command + bool from = false; for (auto& t: tokens) { - if (is_pipe(t)) { - - } - command.push_back(t); // get current token if (is_seperator(t)) { // construct a child with what we have so far and clear command seq_.back().emplace_back(command); command.clear(); + if (from) { + seq_.back().back().pipe().from = from; + from = false; + } + + if (is_pipe(t)) { + seq_.back().back().pipe().to = true; + from = true; + } } } seq_.back().emplace_back(command); // construct the child with tokens + if (from) + seq_.back().back().pipe().from = from; } - return *this; } Sequencer& Sequencer::execute() { for (auto& batch : seq_) - for (auto& command: batch) - if (command.make_arguments().execute()) + for (auto it = batch.begin() ; it != batch.end(); ++it) { + Child& command = *it; + Child p = (it != batch.begin()) ? std::prev(it) : Child{}; + if (command.make_arguments().execute(p)) break; + + } seq_.clear(); return *this; } diff --git a/src/sequencer.h b/src/sequencer.h index a84f830..2f38352 100755 --- a/src/sequencer.h +++ b/src/sequencer.h @@ -59,6 +59,12 @@ namespace snel { }; + struct Pipe { + fd_t fd[2] {-1, -1}; + bool from {false}; + bool to {false}; + }; + class Child { public: enum class LogicOp { NONE=0, OR, AND }; @@ -69,10 +75,11 @@ namespace snel { ~Child (); Child () noexcept = default; Child (const command_t& c) : command{c} { } - Child (command_t&& c) : command{std::move(c)} { } + Child (command_t&& c) : command{std::move(c)} { } Child& make_arguments (); - bool execute (); + bool execute (const Child* previous); + Pipe& pipe() { return pipe_; } private: void redirect_std_if(std::string fn, fd_t std_fd); void restore_std_if(fd_t std_fd); @@ -84,10 +91,9 @@ namespace snel { fd_t sstd [3] = {-1, -1, -1}; std::string filenames[3] = {"", "", ""}; LogicOp logic {LogicOp::NONE}; - bool pipe {false}; + Pipe pipe_; }; - class Sequencer { public: Sequencer& parse (const std::string& input); @@ -95,7 +101,7 @@ namespace snel { private: bool is_seperator (std::string& s) { - return (s == "&&" || s == "||") ? true : false; + return (s == "&&" || s == "||" || s == "|") ? true : false; } bool is_pipe (std::string& s) { return (s == "|") ? true : false;