diff --git a/Shell/Parser.cpp b/Shell/Parser.cpp index 0c1d17eebb..97d3faba81 100644 --- a/Shell/Parser.cpp +++ b/Shell/Parser.cpp @@ -49,11 +49,11 @@ void Parser::commit_subcommand() m_subcommands.append({ move(m_tokens), move(m_redirections), {} }); } -void Parser::commit_command() +void Parser::commit_command(Attributes attributes) { if (m_subcommands.is_empty()) return; - m_commands.append({ move(m_subcommands) }); + m_commands.append({ move(m_subcommands), attributes }); } void Parser::do_pipe() @@ -109,6 +109,31 @@ Vector Parser::parse() commit_command(); break; } + if (ch == '&') { + commit_token(Token::Special); + + if (i + 1 >= m_input.length()) { + in_background:; + // Nothing interesting past this token, commit with InBackground + commit_subcommand(); + commit_command(Attributes::InBackground); + break; + } + + ch = m_input.characters()[++i]; + ++m_position; + + if (ch == '&') { + // This is '&&', commit with ShortCircuit + commit_subcommand(); + commit_command(Attributes::ShortCircuitOnFailure); + break; + } + + --i; + --m_position; + goto in_background; + } if (ch == '|') { commit_token(Token::Special); if (m_tokens.is_empty()) { diff --git a/Shell/Parser.h b/Shell/Parser.h index 65f3ef44f7..b0b7792170 100644 --- a/Shell/Parser.h +++ b/Shell/Parser.h @@ -45,6 +45,12 @@ struct Token { Type type; }; +enum Attributes { + None = 0x0, + ShortCircuitOnFailure = 0x1, + InBackground = 0x2, +}; + struct Redirection { enum Type { Pipe, @@ -71,6 +77,7 @@ struct Subcommand { struct Command { Vector subcommands; + Attributes attributes; }; class Parser { @@ -89,7 +96,7 @@ private: }; void commit_token(Token::Type, AllowEmptyToken = AllowEmptyToken::No); void commit_subcommand(); - void commit_command(); + void commit_command(Attributes = None); void do_pipe(); void begin_redirect_read(int fd); void begin_redirect_write(int fd); diff --git a/Shell/Shell.cpp b/Shell/Shell.cpp index 61368e3197..350447ca6e 100644 --- a/Shell/Shell.cpp +++ b/Shell/Shell.cpp @@ -1052,8 +1052,7 @@ IterationDecision Shell::wait_for_pid(const Shell::SpawnedProcess& process, bool if (WEXITSTATUS(wstatus) != 0) dbg() << "Shell: " << process.name << ":" << process.pid << " exited with status " << WEXITSTATUS(wstatus); - if (is_first_command_in_chain) - return_value = WEXITSTATUS(wstatus); + return_value = WEXITSTATUS(wstatus); if (job) { auto* mutable_job = const_cast(job); @@ -1128,6 +1127,7 @@ ExitCodeOrContinuationRequest Shell::run_command(const StringView& cmd) break; } } + dbgprintf("\n"); for (auto& redirecton : command.subcommands[i].redirections) { for (size_t j = 0; j < i; ++j) @@ -1151,6 +1151,13 @@ ExitCodeOrContinuationRequest Shell::run_command(const StringView& cmd) } } } + if (auto attributes = command.attributes) { + dbgprintf("\n "); + if (attributes & Attributes::InBackground) + dbgprintf("InBackground "); + if (attributes & Attributes::ShortCircuitOnFailure) + dbgprintf("ShortCircuitOnFailure "); + } dbgprintf("\n"); } #endif @@ -1159,8 +1166,20 @@ ExitCodeOrContinuationRequest Shell::run_command(const StringView& cmd) tcgetattr(0, &trm); int return_value = 0; + bool fail_short_circuits = false; for (auto& command : commands) { + if (fail_short_circuits) { + if (command.attributes & Attributes::ShortCircuitOnFailure) + continue; + + // Do not fail any command after this one, as we've reached the end of a short-circuit chain, + // e.g. foo && bar && baz ; foobar + // ^ we reached this command. + fail_short_circuits = false; + continue; + } + if (command.subcommands.is_empty()) continue; @@ -1306,6 +1325,14 @@ ExitCodeOrContinuationRequest Shell::run_command(const StringView& cmd) dbgprintf(" %d (%s)\n", child.pid, child.name.characters()); #endif + if (command.attributes & Attributes::InBackground) { + // Set the jobs as running in background and continue without waiting. + for (auto& child : children) + const_cast(jobs.get(child.pid).value())->set_running_in_background(true); + + continue; + } + for (size_t i = 0; i < children.size(); ++i) { auto& child = children[i]; dbg() << "Now waiting for " << child.name << " (" << child.pid << ")"; @@ -1314,6 +1341,12 @@ ExitCodeOrContinuationRequest Shell::run_command(const StringView& cmd) break; } while (errno == EINTR); } + + if (command.attributes & Attributes::ShortCircuitOnFailure) { + if (return_value != 0) { + fail_short_circuits = true; + } + } } last_return_code = return_value;