mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 18:27:35 +00:00
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:
parent
d754ac5bcb
commit
85d629103d
2 changed files with 40 additions and 0 deletions
|
@ -527,8 +527,46 @@ int Process::do_exec(String path, Vector<String> arguments, Vector<String> envir
|
||||||
return 0;
|
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)
|
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
|
// The bulk of exec() is done by do_exec(), which ensures that all locals
|
||||||
// are cleaned up by the time we yield-teleport below.
|
// are cleaned up by the time we yield-teleport below.
|
||||||
int rc = do_exec(move(path), move(arguments), move(environment));
|
int rc = do_exec(move(path), move(arguments), move(environment));
|
||||||
|
|
|
@ -310,6 +310,8 @@ private:
|
||||||
int alloc_fd(int first_candidate_fd = 0);
|
int alloc_fd(int first_candidate_fd = 0);
|
||||||
void disown_all_shared_buffers();
|
void disown_all_shared_buffers();
|
||||||
|
|
||||||
|
KResultOr<String> find_shebang_interpreter_for_executable(const String& executable_path);
|
||||||
|
|
||||||
Thread* m_main_thread { nullptr };
|
Thread* m_main_thread { nullptr };
|
||||||
|
|
||||||
RefPtr<PageDirectory> m_page_directory;
|
RefPtr<PageDirectory> m_page_directory;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue