Kernel: Implement shebang executables ("#!/bin/sh")

This patch makes it possible to *run* text files that start with the
characters "#!" followed by an interpreter.

I've tested this with both the Serenity built-in shell and the Bash
shell, and it works as expected. :^)
This commit is contained in:
Andreas Kling 2019-09-15 11:47:21 +02:00
parent d754ac5bcb
commit 85d629103d
Notes: sideshowbarker 2024-07-19 12:06:26 +09:00
2 changed files with 40 additions and 0 deletions

View file

@ -527,8 +527,46 @@ int Process::do_exec(String path, Vector<String> arguments, Vector<String> envir
return 0;
}
KResultOr<String> Process::find_shebang_interpreter_for_executable(const String& executable_path)
{
// FIXME: It's a bit sad that we'll open the executable twice (in case there's no shebang)
// Maybe we can find a way to plumb this opened FileDescription to the rest of the
// exec implementation..
auto result = VFS::the().open(executable_path, 0, 0, current_directory());
if (result.is_error())
return result.error();
auto description = result.value();
auto metadata = description->metadata();
if (!metadata.may_execute(m_euid, m_gids))
return KResult(-EACCES);
if (metadata.size < 3)
return KResult(-ENOEXEC);
char first_page[PAGE_SIZE];
int nread = description->read((u8*)&first_page, sizeof(first_page));
int interpreter_length = 0;
if (nread > 2 && first_page[0] == '#' && first_page[1] == '!') {
for (int i = 2; i < nread; ++i) {
if (first_page[i] == '\n') {
interpreter_length = i - 2;
break;
}
}
if (interpreter_length > 0)
return String(&first_page[2], interpreter_length);
}
return KResult(-ENOEXEC);
}
int Process::exec(String path, Vector<String> arguments, Vector<String> environment)
{
auto result = find_shebang_interpreter_for_executable(path);
if (!result.is_error())
return exec(result.value(), { result.value(), path }, move(environment));
// The bulk of exec() is done by do_exec(), which ensures that all locals
// are cleaned up by the time we yield-teleport below.
int rc = do_exec(move(path), move(arguments), move(environment));

View file

@ -310,6 +310,8 @@ private:
int alloc_fd(int first_candidate_fd = 0);
void disown_all_shared_buffers();
KResultOr<String> find_shebang_interpreter_for_executable(const String& executable_path);
Thread* m_main_thread { nullptr };
RefPtr<PageDirectory> m_page_directory;