diff --git a/kernel/include/kernel/Process.h b/kernel/include/kernel/Process.h index 326d24a9..f4f5cab6 100644 --- a/kernel/include/kernel/Process.h +++ b/kernel/include/kernel/Process.h @@ -27,7 +27,7 @@ namespace Kernel public: using entry_t = Thread::entry_t; - struct userspace_entry_t + struct userspace_info_t { uintptr_t entry { 0 }; int argc { 0 }; @@ -49,7 +49,7 @@ namespace Kernel pid_t pid() const { return m_pid; } - static BAN::ErrorOr load_elf_for_exec(BAN::StringView); + static BAN::ErrorOr load_elf_for_exec(BAN::StringView file_path, const BAN::String& cwd, const BAN::Vector& path_env); BAN::ErrorOr fork(uintptr_t rsp, uintptr_t rip); BAN::ErrorOr exec(BAN::StringView path, const char* const* argv, const char* const* envp); @@ -87,7 +87,7 @@ namespace Kernel PageTable& page_table() { return m_page_table ? *m_page_table : PageTable::kernel(); } - const userspace_entry_t& userspace_entry() const { return m_userspace_entry; } + const userspace_info_t& userspace_info() const { return m_userspace_info; } private: Process(pid_t); @@ -132,7 +132,7 @@ namespace Kernel BAN::Vector> m_fixed_width_allocators; BAN::UniqPtr m_general_allocator; - userspace_entry_t m_userspace_entry; + userspace_info_t m_userspace_info; ExitStatus m_exit_status; BAN::UniqPtr m_page_table; diff --git a/kernel/kernel/Process.cpp b/kernel/kernel/Process.cpp index 9529b4c1..b69637a9 100644 --- a/kernel/kernel/Process.cpp +++ b/kernel/kernel/Process.cpp @@ -46,7 +46,7 @@ namespace Kernel BAN::ErrorOr Process::create_userspace(BAN::StringView path) { - auto* elf = TRY(load_elf_for_exec(path)); + auto* elf = TRY(load_elf_for_exec(path, "/"sv, {})); auto* process = create_process(); MUST(process->m_working_directory.push_back('/')); @@ -55,19 +55,28 @@ namespace Kernel process->load_elf(*elf); char** argv = nullptr; + char** envp = nullptr; { PageTableScope _(process->page_table()); + argv = (char**)MUST(process->allocate(sizeof(char**) * 2)); argv[0] = (char*)MUST(process->allocate(path.size() + 1)); memcpy(argv[0], path.data(), path.size()); argv[0][path.size()] = '\0'; argv[1] = nullptr; + + BAN::StringView env1 = "PATH=/bin:/usr/bin"sv; + envp = (char**)MUST(process->allocate(sizeof(char**) * 2)); + envp[0] = (char*)MUST(process->allocate(env1.size() + 1)); + memcpy(envp[0], env1.data(), env1.size()); + envp[0][env1.size()] = '\0'; + envp[1] = nullptr; } - process->m_userspace_entry.argc = 1; - process->m_userspace_entry.argv = argv; - process->m_userspace_entry.envp = (char**)0x69696969; - process->m_userspace_entry.entry = elf->file_header_native().e_entry; + process->m_userspace_info.argc = 1; + process->m_userspace_info.argv = argv; + process->m_userspace_info.envp = envp; + process->m_userspace_info.entry = elf->file_header_native().e_entry; delete elf; @@ -155,9 +164,54 @@ namespace Kernel return {}; } - BAN::ErrorOr Process::load_elf_for_exec(BAN::StringView path) + BAN::ErrorOr Process::load_elf_for_exec(BAN::StringView file_path, const BAN::String& cwd, const BAN::Vector& path_env) { - auto elf_or_error = LibELF::ELF::load_from_file(path); + if (file_path.empty()) + return BAN::Error::from_errno(ENOENT); + + BAN::String absolute_path; + + if (file_path.front() == '/') + { + // We have an absolute path + TRY(absolute_path.append(file_path)); + } + else if (file_path.front() == '.' || file_path.contains('/')) + { + // We have a relative path + TRY(absolute_path.append(cwd)); + TRY(absolute_path.push_back('/')); + TRY(absolute_path.append(file_path)); + } + else + { + // We have neither relative or absolute path, + // search from PATH environment + for (auto path_part : path_env) + { + if (path_part.empty()) + continue; + + if (path_part.front() != '/') + { + TRY(absolute_path.append(cwd)); + TRY(absolute_path.push_back('/')); + } + TRY(absolute_path.append(path_part)); + TRY(absolute_path.push_back('/')); + TRY(absolute_path.append(file_path)); + + if (!VirtualFileSystem::get().file_from_absolute_path(absolute_path, true).is_error()) + break; + + absolute_path.clear(); + } + + if (absolute_path.empty()) + return BAN::Error::from_errno(ENOENT); + } + + auto elf_or_error = LibELF::ELF::load_from_file(absolute_path); if (elf_or_error.is_error()) { if (elf_or_error.error().get_error_code() == EINVAL) @@ -195,7 +249,7 @@ namespace Kernel forked->m_open_files = m_open_files; - forked->m_userspace_entry = m_userspace_entry; + forked->m_userspace_info = m_userspace_info; for (auto* mapped_range : m_mapped_ranges) MUST(forked->m_mapped_ranges.push_back(mapped_range->clone(forked->page_table()))); @@ -219,16 +273,19 @@ namespace Kernel BAN::ErrorOr Process::exec(BAN::StringView path, const char* const* argv, const char* const* envp) { BAN::Vector str_argv; - while (argv && *argv) - if (str_argv.emplace_back(*argv++).is_error()) - return BAN::Error::from_errno(ENOMEM); + for (int i = 0; argv && argv[i]; i++) + TRY(str_argv.emplace_back(argv[i])); + BAN::Vector path_env; BAN::Vector str_envp; - while (envp && *envp) - if (str_envp.emplace_back(*envp++).is_error()) - return BAN::Error::from_errno(ENOMEM); + for (int i = 0; envp && envp[i]; i++) + { + TRY(str_envp.emplace_back(envp[i])); + if (strncmp(envp[i], "PATH=", 5) == 0) + path_env = TRY(BAN::StringView(envp[i]).substring(5).split(':')); + } - auto* elf = TRY(load_elf_for_exec(path)); + auto* elf = TRY(load_elf_for_exec(path, TRY(working_directory()), path_env)); LockGuard lock_guard(m_lock); @@ -243,7 +300,7 @@ namespace Kernel load_elf(*elf); - m_userspace_entry.entry = elf->file_header_native().e_entry; + m_userspace_info.entry = elf->file_header_native().e_entry; delete elf; @@ -252,17 +309,27 @@ namespace Kernel { PageTableScope _(page_table()); - m_userspace_entry.argv = (char**)MUST(allocate(sizeof(char**) * (str_argv.size() + 1))); + + m_userspace_info.argv = (char**)MUST(allocate(sizeof(char**) * (str_argv.size() + 1))); for (size_t i = 0; i < str_argv.size(); i++) { - m_userspace_entry.argv[i] = (char*)MUST(allocate(str_argv[i].size() + 1)); - memcpy(m_userspace_entry.argv[i], str_argv[i].data(), str_argv[i].size()); - m_userspace_entry.argv[i][str_argv[i].size()] = '\0'; + m_userspace_info.argv[i] = (char*)MUST(allocate(str_argv[i].size() + 1)); + memcpy(m_userspace_info.argv[i], str_argv[i].data(), str_argv[i].size()); + m_userspace_info.argv[i][str_argv[i].size()] = '\0'; } - m_userspace_entry.argv[str_argv.size()] = nullptr; + m_userspace_info.argv[str_argv.size()] = nullptr; + + m_userspace_info.envp = (char**)MUST(allocate(sizeof(char**) * (str_envp.size() + 1))); + for (size_t i = 0; i < str_envp.size(); i++) + { + m_userspace_info.envp[i] = (char*)MUST(allocate(str_envp[i].size() + 1)); + memcpy(m_userspace_info.envp[i], str_envp[i].data(), str_envp[i].size()); + m_userspace_info.envp[i][str_envp[i].size()] = '\0'; + } + m_userspace_info.envp[str_envp.size()] = nullptr; } - m_userspace_entry.argc = str_argv.size(); + m_userspace_info.argc = str_argv.size(); // NOTE: These must be manually cleared since this function won't return after this point str_argv.clear(); diff --git a/kernel/kernel/Thread.cpp b/kernel/kernel/Thread.cpp index 8e2d892e..9b76ad1d 100644 --- a/kernel/kernel/Thread.cpp +++ b/kernel/kernel/Thread.cpp @@ -130,8 +130,8 @@ namespace Kernel static entry_t entry_trampoline( [](void*) { - const auto& entry = Process::current().userspace_entry(); - thread_userspace_trampoline(Thread::current().rsp(), entry.entry, entry.argc, entry.argv, entry.envp); + const auto& info = Process::current().userspace_info(); + thread_userspace_trampoline(Thread::current().rsp(), info.entry, info.argc, info.argv, info.envp); ASSERT_NOT_REACHED(); } ); diff --git a/libc/unistd.cpp b/libc/unistd.cpp index 1aa6f9da..d7071841 100644 --- a/libc/unistd.cpp +++ b/libc/unistd.cpp @@ -206,9 +206,49 @@ int execl(const char* pathname, const char* arg0, ...) return execv(pathname, argv); } +int execle(const char* pathname, const char* arg0, ...) +{ + va_list ap; + + int argc = 0; + + if (arg0) + { + va_start(ap, arg0); + argc = 1; + while (va_arg(ap, const char*)) + argc++; + va_end(ap); + } + + char** argv = (char**)malloc(sizeof(char*) * (argc + 1)); + if (argv == nullptr) + { + errno = ENOMEM; + return -1; + } + + char** envp = nullptr; + + va_start(ap, arg0); + argv[0] = (char*)arg0; + for (int i = 1; i < argc; i++) + argv[i] = va_arg(ap, char*); + argv[argc] = nullptr; + envp = va_arg(ap, char**); + va_end(ap); + + return execve(pathname, argv, envp); +} + int execv(const char* pathname, char* const argv[]) { - return syscall(SYS_EXEC, pathname, argv, nullptr); + return execve(pathname, argv, environ); +} + +int execve(const char* pathname, char* const argv[], char* const envp[]) +{ + return syscall(SYS_EXEC, pathname, argv, envp); } pid_t fork(void) diff --git a/userspace/Shell/main.cpp b/userspace/Shell/main.cpp index 17011b7b..67d81114 100644 --- a/userspace/Shell/main.cpp +++ b/userspace/Shell/main.cpp @@ -43,13 +43,6 @@ int execute_command(BAN::StringView command) } else { - struct stat stat_buf; - if (stat(args.front(), &stat_buf) == -1) - { - fprintf(stderr, "command not found: %s\n", args.front()); - return 1; - } - pid_t pid = fork(); if (pid == 0) { @@ -60,7 +53,7 @@ int execute_command(BAN::StringView command) } if (pid == -1) { - perror("fork()"); + perror("fork"); return 1; } int status;