From 9131134704d3494c743887f1ed0ccc912e246357 Mon Sep 17 00:00:00 2001 From: Karol Baraniecki Date: Sun, 27 Oct 2019 10:42:07 +0100 Subject: [PATCH] Kernel: Support passing arguments in shebangged scripts Add the ability to both pass arguments to scripts with shebangs (./script argument1 argument2) and to specify them in the shebang line (#!/usr/local/bin/bash -x -e) Fixes #585 --- Kernel/Process.cpp | 40 +++++++++++++++++++++++++++++++++------- Kernel/Process.h | 2 +- 2 files changed, 34 insertions(+), 8 deletions(-) diff --git a/Kernel/Process.cpp b/Kernel/Process.cpp index 13157de840..77b4e83021 100644 --- a/Kernel/Process.cpp +++ b/Kernel/Process.cpp @@ -550,7 +550,7 @@ int Process::do_exec(String path, Vector arguments, Vector envir return 0; } -KResultOr Process::find_shebang_interpreter_for_executable(const String& executable_path) +KResultOr> 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 @@ -569,16 +569,34 @@ KResultOr Process::find_shebang_interpreter_for_executable(const String& char first_page[PAGE_SIZE]; int nread = description->read((u8*)&first_page, sizeof(first_page)); - int interpreter_length = 0; + int word_start = 2; + int word_length = 0; if (nread > 2 && first_page[0] == '#' && first_page[1] == '!') { + Vector interpreter_words; + for (int i = 2; i < nread; ++i) { if (first_page[i] == '\n') { - interpreter_length = i - 2; break; } + + if (first_page[i] != ' ') { + ++word_length; + } + + if (first_page[i] == ' ') { + if (word_length > 0) { + interpreter_words.append(String(&first_page[word_start], word_length)); + } + word_length = 0; + word_start = i + 1; + } } - if (interpreter_length > 0) - return String(&first_page[2], interpreter_length); + + if (word_length > 0) + interpreter_words.append(String(&first_page[word_start], word_length)); + + if (!interpreter_words.is_empty()) + return interpreter_words; } return KResult(-ENOEXEC); @@ -587,8 +605,16 @@ KResultOr Process::find_shebang_interpreter_for_executable(const String& int Process::exec(String path, Vector arguments, Vector environment) { auto result = find_shebang_interpreter_for_executable(path); - if (!result.is_error()) - return exec(result.value(), { result.value(), path }, move(environment)); + if (!result.is_error()) { + Vector new_arguments(result.value()); + + new_arguments.append(path); + + arguments.remove(0); + new_arguments.append(move(arguments)); + + return exec(result.value().first(), move(new_arguments), 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. diff --git a/Kernel/Process.h b/Kernel/Process.h index 0fb4d2a73f..9be94c58d4 100644 --- a/Kernel/Process.h +++ b/Kernel/Process.h @@ -318,7 +318,7 @@ private: int alloc_fd(int first_candidate_fd = 0); void disown_all_shared_buffers(); - KResultOr find_shebang_interpreter_for_executable(const String& executable_path); + KResultOr> find_shebang_interpreter_for_executable(const String& executable_path); Thread* m_main_thread { nullptr };