|
@@ -63,6 +63,9 @@ namespace snel { |
|
|
Child::~Child () { |
|
|
Child::~Child () { |
|
|
for (int i=0 ; i<3 ; ++i) |
|
|
for (int i=0 ; i<3 ; ++i) |
|
|
restore_std_if(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) { |
|
|
void Child::redirect_std_if(std::string fn, fd_t std_fd) { |
|
@@ -89,26 +92,36 @@ namespace snel { |
|
|
} |
|
|
} |
|
|
Child& Child::make_arguments () { |
|
|
Child& Child::make_arguments () { |
|
|
bool in{false}, out{false}, err{false}; |
|
|
bool in{false}, out{false}, err{false}; |
|
|
|
|
|
bool CanRedirectIn = (pipe_.from) ? true : false; |
|
|
|
|
|
bool CanRedirectOut = (!pipe_.to) ? true : false; |
|
|
|
|
|
|
|
|
for (auto& t: command) { |
|
|
for (auto& t: command) { |
|
|
if (t == "" || t== " ") continue; // skip crap |
|
|
|
|
|
|
|
|
if (t == "" || t== " " || t=="|") continue; // skip crap |
|
|
|
|
|
|
|
|
if (t == "&&") logic = LogicOp::AND; |
|
|
if (t == "&&") logic = LogicOp::AND; |
|
|
else if (t == "||") logic = LogicOp::OR; |
|
|
else if (t == "||") logic = LogicOp::OR; |
|
|
// one pass redirection parsing |
|
|
// 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) |
|
|
// two pass redirection parsing (if redirection came in 2 arguments) |
|
|
else if (t == "<") in = true; |
|
|
else if (t == "<") in = true; |
|
|
else if (t == "1>" || t == ">") out = true; |
|
|
else if (t == "1>" || t == ">") out = true; |
|
|
else if (t == "2>") err = true; |
|
|
else if (t == "2>") err = true; |
|
|
else if (in) { |
|
|
else if (in) { |
|
|
filenames[STDIN_] = t; in = false; |
|
|
|
|
|
|
|
|
if (CanRedirectIn) |
|
|
|
|
|
filenames[STDIN_] = t; |
|
|
|
|
|
in = false; |
|
|
} |
|
|
} |
|
|
else if (out) { |
|
|
else if (out) { |
|
|
filenames[STDOUT_] = t; out = false; |
|
|
|
|
|
|
|
|
if (CanRedirectOut) |
|
|
|
|
|
filenames[STDOUT_] = t; |
|
|
|
|
|
out = false; |
|
|
} |
|
|
} |
|
|
else if (err) { |
|
|
else if (err) { |
|
|
filenames[STDERR_] = t; err = false; |
|
|
filenames[STDERR_] = t; err = false; |
|
@@ -119,24 +132,45 @@ namespace snel { |
|
|
return *this; |
|
|
return *this; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
bool Child::execute() { |
|
|
|
|
|
|
|
|
bool Child::execute(const Child* previous) { |
|
|
bool stop = {false}; |
|
|
bool stop = {false}; |
|
|
|
|
|
|
|
|
|
|
|
// Check parent redirection |
|
|
redirect_std_if (filenames[STDIN_], STDIN_); |
|
|
redirect_std_if (filenames[STDIN_], STDIN_); |
|
|
redirect_std_if (filenames[STDOUT_], STDOUT_); |
|
|
redirect_std_if (filenames[STDOUT_], STDOUT_); |
|
|
redirect_std_if (filenames[STDERR_], STDERR_); |
|
|
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(); |
|
|
pid_t pid = fork(); |
|
|
if (pid < 0) { |
|
|
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 |
|
|
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()); |
|
|
execvp(arguments.front(), arguments.data()); |
|
|
// error if we got here |
|
|
// error if we got here |
|
|
std::cout << "Can not invoke: " << arguments.front() << std::endl; |
|
|
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 |
|
|
else { // parent |
|
|
|
|
|
if (pipe_.to) close (pipe_.fd[1]); |
|
|
|
|
|
else if (pipe_.from) close (previous->pipe().fd[0]); |
|
|
|
|
|
|
|
|
int exit_status; |
|
|
int exit_status; |
|
|
waitpid(pid, &exit_status, 0); // wait child process to finish |
|
|
waitpid(pid, &exit_status, 0); // wait child process to finish |
|
|
restore_std_if (STDIN_); |
|
|
restore_std_if (STDIN_); |
|
@@ -171,31 +205,42 @@ namespace snel { |
|
|
tokens.clear(); // make a new token vector for command |
|
|
tokens.clear(); // make a new token vector for command |
|
|
split (s, tokens, ' '); |
|
|
split (s, tokens, ' '); |
|
|
|
|
|
|
|
|
seq_.emplace_back(std::vector<Child>{}); // make a new child for command |
|
|
|
|
|
|
|
|
seq_.emplace_back(std::vector<Child>{}); // make a new child for command |
|
|
// check tokens inside command |
|
|
// check tokens inside command |
|
|
|
|
|
bool from = false; |
|
|
for (auto& t: tokens) { |
|
|
for (auto& t: tokens) { |
|
|
if (is_pipe(t)) { |
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
command.push_back(t); // get current token |
|
|
command.push_back(t); // get current token |
|
|
if (is_seperator(t)) { |
|
|
if (is_seperator(t)) { |
|
|
// construct a child with what we have so far and clear command |
|
|
// construct a child with what we have so far and clear command |
|
|
seq_.back().emplace_back(command); |
|
|
seq_.back().emplace_back(command); |
|
|
command.clear(); |
|
|
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 |
|
|
seq_.back().emplace_back(command); // construct the child with tokens |
|
|
|
|
|
if (from) |
|
|
|
|
|
seq_.back().back().pipe().from = from; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
return *this; |
|
|
return *this; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
Sequencer& Sequencer::execute() { |
|
|
Sequencer& Sequencer::execute() { |
|
|
for (auto& batch : seq_) |
|
|
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; |
|
|
break; |
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
seq_.clear(); |
|
|
seq_.clear(); |
|
|
return *this; |
|
|
return *this; |
|
|
} |
|
|
} |
|
|