summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnotherTest <ali.mpfard@gmail.com>2020-08-14 22:30:48 +0430
committerAndreas Kling <kling@serenityos.org>2020-08-15 20:48:17 +0200
commitc589625418e444164b6732ac9f4e1908a9bdbc5c (patch)
tree1d0671db2ead01637c2651e414037b7d72a9057c
parent0dac7af6c500f224741dd76027efd2003a5e675a (diff)
downloadserenity-c589625418e444164b6732ac9f4e1908a9bdbc5c.zip
Shell: Allow redirections and pipes on builtins
Fixes #3072.
-rw-r--r--Shell/Builtin.cpp34
-rw-r--r--Shell/Execution.h17
-rw-r--r--Shell/Forward.h1
-rw-r--r--Shell/Shell.cpp8
-rw-r--r--Shell/Shell.h2
-rw-r--r--Shell/main.cpp32
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;