1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-28 22:25:07 +00:00

Shell: Allow redirections and pipes on builtins

Fixes #3072.
This commit is contained in:
AnotherTest 2020-08-14 22:30:48 +04:30 committed by Andreas Kling
parent 0dac7af6c5
commit c589625418
6 changed files with 81 additions and 13 deletions

View file

@ -757,23 +757,41 @@ int Shell::builtin_unset(int argc, const char** argv)
return 0; 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; return false;
StringView name { argv[0] }; if (!has_builtin(command.argv.first()))
return false;
#define __ENUMERATE_SHELL_BUILTIN(builtin) \ Vector<const char*> argv;
if (name == #builtin) { \ for (auto& arg : command.argv)
retval = builtin_##builtin(argc, argv); \ argv.append(arg.characters());
return true; \
argv.append(nullptr);
StringView name = command.argv.first();
SavedFileDescriptors fds { rewirings };
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(); ENUMERATE_SHELL_BUILTINS();
#undef __ENUMERATE_SHELL_BUILTIN #undef __ENUMERATE_SHELL_BUILTIN
return false; return false;
} }

View file

@ -26,7 +26,9 @@
#pragma once #pragma once
#include "Forward.h"
#include <AK/Forward.h> #include <AK/Forward.h>
#include <AK/NonnullRefPtrVector.h>
#include <AK/String.h> #include <AK/String.h>
#include <AK/Vector.h> #include <AK/Vector.h>
#include <LibCore/ElapsedTimer.h> #include <LibCore/ElapsedTimer.h>
@ -42,3 +44,18 @@ public:
private: private:
Vector<int, 32> m_fds; 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;
};

View file

@ -33,5 +33,6 @@ class Node;
class Value; class Value;
class SyntaxError; class SyntaxError;
class Pipeline; class Pipeline;
class Rewiring;
} }

View file

@ -500,6 +500,10 @@ RefPtr<Job> Shell::run_command(const AST::Command& command)
return nullptr; return nullptr;
} }
int retval = 0;
if (run_builtin(command, rewirings, retval))
return nullptr;
Vector<const char*> argv; Vector<const char*> argv;
Vector<String> copy_argv = command.argv; Vector<String> copy_argv = command.argv;
argv.ensure_capacity(command.argv.size() + 1); argv.ensure_capacity(command.argv.size() + 1);
@ -509,10 +513,6 @@ RefPtr<Job> Shell::run_command(const AST::Command& command)
argv.append(nullptr); argv.append(nullptr);
int retval = 0;
if (run_builtin(argv.size() - 1, argv.data(), retval))
return nullptr;
int sync_pipe[2]; int sync_pipe[2];
if (pipe(sync_pipe) < 0) { if (pipe(sync_pipe) < 0) {
perror("pipe"); perror("pipe");

View file

@ -78,7 +78,7 @@ public:
RefPtr<Job> run_command(const AST::Command&); RefPtr<Job> run_command(const AST::Command&);
NonnullRefPtrVector<Job> run_commands(Vector<AST::Command>&); NonnullRefPtrVector<Job> run_commands(Vector<AST::Command>&);
bool run_file(const String&, bool explicitly_invoked = true); 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; bool has_builtin(const StringView&) const;
void block_on_job(RefPtr<Job>); void block_on_job(RefPtr<Job>);
String prompt() const; String prompt() const;

View file

@ -56,6 +56,38 @@ void FileDescriptionCollector::add(int fd)
m_fds.append(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) int main(int argc, char** argv)
{ {
Core::EventLoop loop; Core::EventLoop loop;