1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-24 01:15:07 +00:00

Shell: Parse and correctly evaluate 'command &' and 'command &&'

This commit adds the InBackground and ShortCircuitOnFailure attributes
to commands, which respectively cause the command to be run in the
background, and abort the command chain with exit status != 0.
This commit is contained in:
AnotherTest 2020-05-24 23:00:46 +04:30 committed by Andreas Kling
parent 143be7234f
commit c23c354779
3 changed files with 70 additions and 5 deletions

View file

@ -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*>(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<Job*>(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;