From eca20e92daf402cbcc3f57c240da8eec5050e0fc Mon Sep 17 00:00:00 2001 From: Peter Elliott Date: Sat, 3 Apr 2021 13:57:31 -0600 Subject: [PATCH] Userland: Add support for -S to env command - Refactor env to use Core::ArgsParser - create symlink from /bin/env to /usr/bin/env for compatiability --- Base/usr/bin/env | 1 + Userland/Utilities/env.cpp | 60 +++++++++++++++++++++++++------------- 2 files changed, 40 insertions(+), 21 deletions(-) create mode 120000 Base/usr/bin/env diff --git a/Base/usr/bin/env b/Base/usr/bin/env new file mode 120000 index 00000000000..24234ae18e9 --- /dev/null +++ b/Base/usr/bin/env @@ -0,0 +1 @@ +/bin/env \ No newline at end of file diff --git a/Userland/Utilities/env.cpp b/Userland/Utilities/env.cpp index 630ff817494..8f9332bd91c 100644 --- a/Userland/Utilities/env.cpp +++ b/Userland/Utilities/env.cpp @@ -24,6 +24,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include #include #include #include @@ -36,40 +37,57 @@ int main(int argc, char** argv) return 1; } - const char* filename = nullptr; + bool ignore_env = false; + const char* split_string = nullptr; + Vector values; - for (int idx = 1; idx < argc; ++idx) { - if (idx == 1) { - if (StringView { argv[idx] } == "-i" || StringView { argv[idx] } == "--ignore-environment") { - clearenv(); - continue; - } - } - if (StringView { argv[idx] }.contains('=')) { - putenv(argv[idx]); + Core::ArgsParser args_parser; + args_parser.add_option(ignore_env, "Start with an empty environment", "ignore-environment", 'i'); + args_parser.add_option(split_string, "Process and split S into separate arguments; used to pass multiple arguments on shebang lines", "split-string", 'S', "S"); + + args_parser.add_positional_argument(values, "Environment and commands", "env/command", Core::ArgsParser::Required::No); + args_parser.parse(argc, argv); + + if (ignore_env) + clearenv(); + + size_t argv_start; + for (argv_start = 0; argv_start < values.size(); ++argv_start) { + if (StringView { values[argv_start] }.contains('=')) { + putenv(const_cast(values[argv_start])); } else { - filename = argv[idx]; - argv += idx; break; } } - if (filename == nullptr) { + Vector split_string_storage; + Vector new_argv; + if (split_string) { + for (auto view : StringView(split_string).split_view(' ')) { + split_string_storage.append(view); + } + for (auto& str : split_string_storage) { + new_argv.append(str.characters()); + } + } + + for (size_t i = argv_start; i < values.size(); ++i) { + new_argv.append(values[i]); + } + + if (new_argv.size() == 0) { for (auto entry = environ; *entry != nullptr; ++entry) printf("%s\n", *entry); return 0; } - String filepath = Core::find_executable_in_path(filename); + new_argv.append(nullptr); - if (filepath.is_null()) { - warnln("no {} in path", filename); - return 1; - } + const char* executable = new_argv[0]; + char* const* new_argv_ptr = const_cast(&new_argv[0]); - execv(filepath.characters(), argv); - - perror("execv"); + execvp(executable, new_argv_ptr); + perror("execvp"); return 1; }