summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Shell/Parser.cpp18
-rw-r--r--Shell/Parser.h8
-rw-r--r--Shell/main.cpp306
3 files changed, 179 insertions, 153 deletions
diff --git a/Shell/Parser.cpp b/Shell/Parser.cpp
index dd85237fda..31ce752f9b 100644
--- a/Shell/Parser.cpp
+++ b/Shell/Parser.cpp
@@ -22,6 +22,13 @@ void Parser::commit_subcommand()
m_subcommands.append({ move(m_tokens), move(m_redirections), {} });
}
+void Parser::commit_command()
+{
+ if (m_subcommands.is_empty())
+ return;
+ m_commands.append({ move(m_subcommands) });
+}
+
void Parser::do_pipe()
{
m_redirections.append({ Redirection::Pipe, STDOUT_FILENO });
@@ -38,7 +45,7 @@ void Parser::begin_redirect_write(int fd)
m_redirections.append({ Redirection::FileWrite, fd });
}
-Vector<Subcommand> Parser::parse()
+Vector<Command> Parser::parse()
{
for (int i = 0; i < m_input.length(); ++i) {
char ch = m_input.characters()[i];
@@ -48,6 +55,12 @@ Vector<Subcommand> Parser::parse()
commit_token();
break;
}
+ if (ch == ';') {
+ commit_token();
+ commit_subcommand();
+ commit_command();
+ break;
+ }
if (ch == '|') {
commit_token();
if (m_tokens.is_empty()) {
@@ -140,6 +153,7 @@ Vector<Subcommand> Parser::parse()
}
commit_token();
commit_subcommand();
+ commit_command();
if (!m_subcommands.is_empty()) {
for (auto& redirection : m_subcommands.last().redirections) {
@@ -150,5 +164,5 @@ Vector<Subcommand> Parser::parse()
}
}
- return move(m_subcommands);
+ return move(m_commands);
}
diff --git a/Shell/Parser.h b/Shell/Parser.h
index 294a7ec63a..5008046a00 100644
--- a/Shell/Parser.h
+++ b/Shell/Parser.h
@@ -27,6 +27,10 @@ struct Subcommand {
Vector<Rewiring> rewirings;
};
+struct Command {
+ Vector<Subcommand> subcommands;
+};
+
class Parser {
public:
explicit Parser(const String& input)
@@ -34,11 +38,12 @@ public:
{
}
- Vector<Subcommand> parse();
+ Vector<Command> parse();
private:
void commit_token();
void commit_subcommand();
+ void commit_command();
void do_pipe();
void begin_redirect_read(int fd);
void begin_redirect_write(int fd);
@@ -53,6 +58,7 @@ private:
State m_state { Free };
String m_input;
+ Vector<Command> m_commands;
Vector<Subcommand> m_subcommands;
Vector<String> m_tokens;
Vector<Redirection> m_redirections;
diff --git a/Shell/main.cpp b/Shell/main.cpp
index 150d373618..67b4942e11 100644
--- a/Shell/main.cpp
+++ b/Shell/main.cpp
@@ -20,7 +20,7 @@
#include <termios.h>
#include <unistd.h>
-//#define SH_DEBUG
+#define SH_DEBUG
GlobalState g;
static LineEditor editor;
@@ -320,96 +320,42 @@ static int run_command(const String& cmd)
if (cmd.is_empty())
return 0;
- auto subcommands = Parser(cmd).parse();
+ auto commands = Parser(cmd).parse();
#ifdef SH_DEBUG
- for (int i = 0; i < subcommands.size(); ++i) {
- for (int j = 0; j < i; ++j)
- dbgprintf(" ");
- for (auto& arg : subcommands[i].args) {
- dbgprintf("<%s> ", arg.characters());
- }
- dbgprintf("\n");
- for (auto& redirecton : subcommands[i].redirections) {
+ for (auto& command : commands) {
+ for (int i = 0; i < command.subcommands.size(); ++i) {
for (int j = 0; j < i; ++j)
dbgprintf(" ");
- dbgprintf(" ");
- switch (redirecton.type) {
- case Redirection::Pipe:
- dbgprintf("Pipe\n");
- break;
- case Redirection::FileRead:
- dbgprintf("fd:%d = FileRead: %s\n", redirecton.fd, redirecton.path.characters());
- break;
- case Redirection::FileWrite:
- dbgprintf("fd:%d = FileWrite: %s\n", redirecton.fd, redirecton.path.characters());
- break;
- case Redirection::FileWriteAppend:
- dbgprintf("fd:%d = FileWriteAppend: %s\n", redirecton.fd, redirecton.path.characters());
- break;
- default:
- break;
- }
- }
- }
-#endif
-
- if (subcommands.is_empty())
- return 0;
-
- FileDescriptionCollector fds;
-
- for (int i = 0; i < subcommands.size(); ++i) {
- auto& subcommand = subcommands[i];
- for (auto& redirection : subcommand.redirections) {
- switch (redirection.type) {
- case Redirection::Pipe: {
- int pipefd[2];
- int rc = pipe(pipefd);
- if (rc < 0) {
- perror("pipe");
- return 1;
- }
- subcommand.rewirings.append({ STDOUT_FILENO, pipefd[1] });
- auto& next_command = subcommands[i + 1];
- next_command.rewirings.append({ STDIN_FILENO, pipefd[0] });
- fds.add(pipefd[0]);
- fds.add(pipefd[1]);
- break;
- }
- case Redirection::FileWriteAppend: {
- int fd = open(redirection.path.characters(), O_WRONLY | O_CREAT | O_APPEND, 0666);
- if (fd < 0) {
- perror("open");
- return 1;
- }
- subcommand.rewirings.append({ redirection.fd, fd });
- fds.add(fd);
- break;
+ for (auto& arg : command.subcommands[i].args) {
+ dbgprintf("<%s> ", arg.characters());
}
- case Redirection::FileWrite: {
- int fd = open(redirection.path.characters(), O_WRONLY | O_CREAT | O_TRUNC, 0666);
- if (fd < 0) {
- perror("open");
- return 1;
+ dbgprintf("\n");
+ for (auto& redirecton : command.subcommands[i].redirections) {
+ for (int j = 0; j < i; ++j)
+ dbgprintf(" ");
+ dbgprintf(" ");
+ switch (redirecton.type) {
+ case Redirection::Pipe:
+ dbgprintf("Pipe\n");
+ break;
+ case Redirection::FileRead:
+ dbgprintf("fd:%d = FileRead: %s\n", redirecton.fd, redirecton.path.characters());
+ break;
+ case Redirection::FileWrite:
+ dbgprintf("fd:%d = FileWrite: %s\n", redirecton.fd, redirecton.path.characters());
+ break;
+ case Redirection::FileWriteAppend:
+ dbgprintf("fd:%d = FileWriteAppend: %s\n", redirecton.fd, redirecton.path.characters());
+ break;
+ default:
+ break;
}
- subcommand.rewirings.append({ redirection.fd, fd });
- fds.add(fd);
- break;
- }
- case Redirection::FileRead: {
- int fd = open(redirection.path.characters(), O_RDONLY);
- if (fd < 0) {
- perror("open");
- return 1;
- }
- subcommand.rewirings.append({ redirection.fd, fd });
- fds.add(fd);
- break;
- }
}
}
+ dbgprintf("\n");
}
+#endif
struct termios trm;
tcgetattr(0, &trm);
@@ -419,99 +365,159 @@ static int run_command(const String& cmd)
pid_t pid;
};
- Vector<SpawnedProcess> children;
+ int return_value = 0;
- CommandTimer timer;
+ for (auto& command : commands) {
+ if (command.subcommands.is_empty())
+ continue;
- for (int i = 0; i < subcommands.size(); ++i) {
- auto& subcommand = subcommands[i];
- Vector<String> argv_string = process_arguments(subcommand.args);
- Vector<const char*> argv;
- argv.ensure_capacity(argv_string.size());
- for (const auto& s : argv_string) {
- argv.append(s.characters());
+ FileDescriptionCollector fds;
+
+ for (int i = 0; i < command.subcommands.size(); ++i) {
+ auto& subcommand = command.subcommands[i];
+ for (auto& redirection : subcommand.redirections) {
+ switch (redirection.type) {
+ case Redirection::Pipe: {
+ int pipefd[2];
+ int rc = pipe(pipefd);
+ if (rc < 0) {
+ perror("pipe");
+ return 1;
+ }
+ subcommand.rewirings.append({ STDOUT_FILENO, pipefd[1] });
+ auto& next_command = command.subcommands[i + 1];
+ next_command.rewirings.append({ STDIN_FILENO, pipefd[0] });
+ fds.add(pipefd[0]);
+ fds.add(pipefd[1]);
+ break;
+ }
+ case Redirection::FileWriteAppend: {
+ int fd = open(redirection.path.characters(), O_WRONLY | O_CREAT | O_APPEND, 0666);
+ if (fd < 0) {
+ perror("open");
+ return 1;
+ }
+ subcommand.rewirings.append({ redirection.fd, fd });
+ fds.add(fd);
+ break;
+ }
+ case Redirection::FileWrite: {
+ int fd = open(redirection.path.characters(), O_WRONLY | O_CREAT | O_TRUNC, 0666);
+ if (fd < 0) {
+ perror("open");
+ return 1;
+ }
+ subcommand.rewirings.append({ redirection.fd, fd });
+ fds.add(fd);
+ break;
+ }
+ case Redirection::FileRead: {
+ int fd = open(redirection.path.characters(), O_RDONLY);
+ if (fd < 0) {
+ perror("open");
+ return 1;
+ }
+ subcommand.rewirings.append({ redirection.fd, fd });
+ fds.add(fd);
+ break;
+ }
+ }
+ }
}
- argv.append(nullptr);
+
+ Vector<SpawnedProcess> children;
+
+ CommandTimer timer;
+
+ for (int i = 0; i < command.subcommands.size(); ++i) {
+ auto& subcommand = command.subcommands[i];
+ Vector<String> argv_string = process_arguments(subcommand.args);
+ Vector<const char*> argv;
+ argv.ensure_capacity(argv_string.size());
+ for (const auto& s : argv_string) {
+ argv.append(s.characters());
+ }
+ argv.append(nullptr);
#ifdef SH_DEBUG
- for (auto& arg : argv) {
- dbgprintf("<%s> ", arg);
- }
- dbgprintf("\n");
+ for (auto& arg : argv) {
+ dbgprintf("<%s> ", arg);
+ }
+ dbgprintf("\n");
#endif
- int retval = 0;
- if (handle_builtin(argv.size() - 1, const_cast<char**>(argv.data()), retval))
- return retval;
+ int retval = 0;
+ if (handle_builtin(argv.size() - 1, const_cast<char**>(argv.data()), retval))
+ return retval;
- pid_t child = fork();
- if (!child) {
- setpgid(0, 0);
- tcsetpgrp(0, getpid());
- for (auto& rewiring : subcommand.rewirings) {
+ pid_t child = fork();
+ if (!child) {
+ setpgid(0, 0);
+ tcsetpgrp(0, getpid());
+ for (auto& rewiring : subcommand.rewirings) {
#ifdef SH_DEBUG
- dbgprintf("in %s<%d>, dup2(%d, %d)\n", argv[0], getpid(), redirection.rewire_fd, redirection.fd);
+ dbgprintf("in %s<%d>, dup2(%d, %d)\n", argv[0], getpid(), rewiring.rewire_fd, rewiring.fd);
#endif
- int rc = dup2(rewiring.rewire_fd, rewiring.fd);
- if (rc < 0) {
- perror("dup2");
- return 1;
+ int rc = dup2(rewiring.rewire_fd, rewiring.fd);
+ if (rc < 0) {
+ perror("dup2");
+ return 1;
+ }
}
- }
- fds.collect();
+ fds.collect();
- int rc = execvp(argv[0], const_cast<char* const*>(argv.data()));
- if (rc < 0) {
- if (errno == ENOENT)
- fprintf(stderr, "%s: Command not found.\n", argv[0]);
- else
- fprintf(stderr, "execvp(%s): %s\n", argv[0], strerror(errno));
- exit(1);
+ int rc = execvp(argv[0], const_cast<char* const*>(argv.data()));
+ if (rc < 0) {
+ if (errno == ENOENT)
+ fprintf(stderr, "%s: Command not found.\n", argv[0]);
+ else
+ fprintf(stderr, "execvp(%s): %s\n", argv[0], strerror(errno));
+ exit(1);
+ }
+ ASSERT_NOT_REACHED();
}
- ASSERT_NOT_REACHED();
+ children.append({ argv[0], child });
}
- children.append({ argv[0], child });
- }
#ifdef SH_DEBUG
- dbgprintf("Closing fds in shell process:\n");
+ dbgprintf("Closing fds in shell process:\n");
#endif
- fds.collect();
+ fds.collect();
#ifdef SH_DEBUG
- dbgprintf("Now we gotta wait on children:\n");
- for (auto& child : children)
- dbgprintf(" %d\n", child);
+ dbgprintf("Now we gotta wait on children:\n");
+ for (auto& child : children)
+ dbgprintf(" %d\n", child);
#endif
- int wstatus = 0;
- int return_value = 0;
+ int wstatus = 0;
- for (int i = 0; i < children.size(); ++i) {
- auto& child = children[i];
- do {
- int rc = waitpid(child.pid, &wstatus, WEXITED | WSTOPPED);
- if (rc < 0 && errno != EINTR) {
- if (errno != ECHILD)
- perror("waitpid");
- break;
- }
- if (WIFEXITED(wstatus)) {
- if (WEXITSTATUS(wstatus) != 0)
- dbg() << "Shell: " << child.name << ":" << child.pid << " exited with status " << WEXITSTATUS(wstatus);
- if (i == 0)
- return_value = WEXITSTATUS(wstatus);
- } else if (WIFSTOPPED(wstatus)) {
- printf("Shell: %s(%d) stopped.\n", child.name.characters(), child.pid);
- } else {
- if (WIFSIGNALED(wstatus)) {
- printf("Shell: %s(%d) exited due to signal '%s'\n", child.name.characters(), child.pid, strsignal(WTERMSIG(wstatus)));
+ for (int i = 0; i < children.size(); ++i) {
+ auto& child = children[i];
+ do {
+ int rc = waitpid(child.pid, &wstatus, WEXITED | WSTOPPED);
+ if (rc < 0 && errno != EINTR) {
+ if (errno != ECHILD)
+ perror("waitpid");
+ break;
+ }
+ if (WIFEXITED(wstatus)) {
+ if (WEXITSTATUS(wstatus) != 0)
+ dbg() << "Shell: " << child.name << ":" << child.pid << " exited with status " << WEXITSTATUS(wstatus);
+ if (i == 0)
+ return_value = WEXITSTATUS(wstatus);
+ } else if (WIFSTOPPED(wstatus)) {
+ printf("Shell: %s(%d) stopped.\n", child.name.characters(), child.pid);
} else {
- printf("Shell: %s(%d) exited abnormally\n", child.name.characters(), child.pid);
+ if (WIFSIGNALED(wstatus)) {
+ printf("Shell: %s(%d) exited due to signal '%s'\n", child.name.characters(), child.pid, strsignal(WTERMSIG(wstatus)));
+ } else {
+ printf("Shell: %s(%d) exited abnormally\n", child.name.characters(), child.pid);
+ }
}
- }
- } while (errno == EINTR);
+ } while (errno == EINTR);
+ }
}
// FIXME: Should I really have to tcsetpgrp() after my child has exited?