diff options
author | AnotherTest <ali.mpfard@gmail.com> | 2020-08-14 22:30:48 +0430 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2020-08-15 20:48:17 +0200 |
commit | c589625418e444164b6732ac9f4e1908a9bdbc5c (patch) | |
tree | 1d0671db2ead01637c2651e414037b7d72a9057c | |
parent | 0dac7af6c500f224741dd76027efd2003a5e675a (diff) | |
download | serenity-c589625418e444164b6732ac9f4e1908a9bdbc5c.zip |
Shell: Allow redirections and pipes on builtins
Fixes #3072.
-rw-r--r-- | Shell/Builtin.cpp | 34 | ||||
-rw-r--r-- | Shell/Execution.h | 17 | ||||
-rw-r--r-- | Shell/Forward.h | 1 | ||||
-rw-r--r-- | Shell/Shell.cpp | 8 | ||||
-rw-r--r-- | Shell/Shell.h | 2 | ||||
-rw-r--r-- | Shell/main.cpp | 32 |
6 files changed, 81 insertions, 13 deletions
diff --git a/Shell/Builtin.cpp b/Shell/Builtin.cpp index cc5658ebdd..129af8e008 100644 --- a/Shell/Builtin.cpp +++ b/Shell/Builtin.cpp @@ -757,23 +757,41 @@ int Shell::builtin_unset(int argc, const char** argv) return 0; } -bool Shell::run_builtin(int argc, const char** argv, int& retval) +bool Shell::run_builtin(const AST::Command& command, const NonnullRefPtrVector<AST::Rewiring>& rewirings, int& retval) { - if (argc == 0) + if (command.argv.is_empty()) return false; - StringView name { argv[0] }; + if (!has_builtin(command.argv.first())) + return false; + + Vector<const char*> argv; + for (auto& arg : command.argv) + argv.append(arg.characters()); + + argv.append(nullptr); + + StringView name = command.argv.first(); + + SavedFileDescriptors fds { rewirings }; -#define __ENUMERATE_SHELL_BUILTIN(builtin) \ - if (name == #builtin) { \ - retval = builtin_##builtin(argc, argv); \ - return true; \ + for (auto& rewiring : rewirings) { + int rc = dup2(rewiring.dest_fd, rewiring.source_fd); + if (rc < 0) { + perror("dup2(run)"); + return false; + } + } + +#define __ENUMERATE_SHELL_BUILTIN(builtin) \ + if (name == #builtin) { \ + retval = builtin_##builtin(argv.size() - 1, argv.data()); \ + return true; \ } ENUMERATE_SHELL_BUILTINS(); #undef __ENUMERATE_SHELL_BUILTIN - return false; } diff --git a/Shell/Execution.h b/Shell/Execution.h index bf45c76418..7e407df281 100644 --- a/Shell/Execution.h +++ b/Shell/Execution.h @@ -26,7 +26,9 @@ #pragma once +#include "Forward.h" #include <AK/Forward.h> +#include <AK/NonnullRefPtrVector.h> #include <AK/String.h> #include <AK/Vector.h> #include <LibCore/ElapsedTimer.h> @@ -42,3 +44,18 @@ public: private: Vector<int, 32> m_fds; }; + +class SavedFileDescriptors { +public: + SavedFileDescriptors(const NonnullRefPtrVector<AST::Rewiring>&); + ~SavedFileDescriptors(); + +private: + struct SavedFileDescriptor { + int original { -1 }; + int saved { -1 }; + }; + + Vector<SavedFileDescriptor> m_saves; + FileDescriptionCollector m_collector; +}; diff --git a/Shell/Forward.h b/Shell/Forward.h index 94d5cf7eda..5cf82ce2f0 100644 --- a/Shell/Forward.h +++ b/Shell/Forward.h @@ -33,5 +33,6 @@ class Node; class Value; class SyntaxError; class Pipeline; +class Rewiring; } diff --git a/Shell/Shell.cpp b/Shell/Shell.cpp index b9d621f16c..33b16074bb 100644 --- a/Shell/Shell.cpp +++ b/Shell/Shell.cpp @@ -500,6 +500,10 @@ RefPtr<Job> Shell::run_command(const AST::Command& command) return nullptr; } + int retval = 0; + if (run_builtin(command, rewirings, retval)) + return nullptr; + Vector<const char*> argv; Vector<String> copy_argv = command.argv; argv.ensure_capacity(command.argv.size() + 1); @@ -509,10 +513,6 @@ RefPtr<Job> Shell::run_command(const AST::Command& command) argv.append(nullptr); - int retval = 0; - if (run_builtin(argv.size() - 1, argv.data(), retval)) - return nullptr; - int sync_pipe[2]; if (pipe(sync_pipe) < 0) { perror("pipe"); diff --git a/Shell/Shell.h b/Shell/Shell.h index 3c03b585f5..90469303af 100644 --- a/Shell/Shell.h +++ b/Shell/Shell.h @@ -78,7 +78,7 @@ public: RefPtr<Job> run_command(const AST::Command&); NonnullRefPtrVector<Job> run_commands(Vector<AST::Command>&); bool run_file(const String&, bool explicitly_invoked = true); - bool run_builtin(int argc, const char** argv, int& retval); + bool run_builtin(const AST::Command&, const NonnullRefPtrVector<AST::Rewiring>&, int& retval); bool has_builtin(const StringView&) const; void block_on_job(RefPtr<Job>); String prompt() const; diff --git a/Shell/main.cpp b/Shell/main.cpp index 80ef3aa22d..b50c250ef5 100644 --- a/Shell/main.cpp +++ b/Shell/main.cpp @@ -56,6 +56,38 @@ void FileDescriptionCollector::add(int fd) m_fds.append(fd); } +SavedFileDescriptors::SavedFileDescriptors(const NonnullRefPtrVector<AST::Rewiring>& intended_rewirings) +{ + for (auto& rewiring : intended_rewirings) { + int new_fd = dup(rewiring.source_fd); + if (new_fd < 0) { + if (errno != EBADF) + perror("dup"); + // The fd that will be overwritten isn't open right now, + // it will be cleaned up by the exec()-side collector + // and we have nothing to do here, so just ignore this error. + continue; + } + + auto flags = fcntl(new_fd, F_GETFL); + auto rc = fcntl(new_fd, F_SETFL, flags | FD_CLOEXEC); + ASSERT(rc == 0); + + m_saves.append({ rewiring.source_fd, new_fd }); + m_collector.add(new_fd); + } +} + +SavedFileDescriptors::~SavedFileDescriptors() +{ + for (auto& save : m_saves) { + if (dup2(save.saved, save.original) < 0) { + perror("dup2(~SavedFileDescriptors)"); + continue; + } + } +} + int main(int argc, char** argv) { Core::EventLoop loop; |