forked from Bananymous/banan-os
Kernel: add basic support for environment variables
exec functions will search files from PATH
This commit is contained in:
parent
6aff459e1c
commit
064ce568c2
|
@ -27,7 +27,7 @@ namespace Kernel
|
||||||
public:
|
public:
|
||||||
using entry_t = Thread::entry_t;
|
using entry_t = Thread::entry_t;
|
||||||
|
|
||||||
struct userspace_entry_t
|
struct userspace_info_t
|
||||||
{
|
{
|
||||||
uintptr_t entry { 0 };
|
uintptr_t entry { 0 };
|
||||||
int argc { 0 };
|
int argc { 0 };
|
||||||
|
@ -49,7 +49,7 @@ namespace Kernel
|
||||||
|
|
||||||
pid_t pid() const { return m_pid; }
|
pid_t pid() const { return m_pid; }
|
||||||
|
|
||||||
static BAN::ErrorOr<LibELF::ELF*> load_elf_for_exec(BAN::StringView);
|
static BAN::ErrorOr<LibELF::ELF*> load_elf_for_exec(BAN::StringView file_path, const BAN::String& cwd, const BAN::Vector<BAN::StringView>& path_env);
|
||||||
|
|
||||||
BAN::ErrorOr<Process*> fork(uintptr_t rsp, uintptr_t rip);
|
BAN::ErrorOr<Process*> fork(uintptr_t rsp, uintptr_t rip);
|
||||||
BAN::ErrorOr<void> exec(BAN::StringView path, const char* const* argv, const char* const* envp);
|
BAN::ErrorOr<void> 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(); }
|
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:
|
private:
|
||||||
Process(pid_t);
|
Process(pid_t);
|
||||||
|
@ -132,7 +132,7 @@ namespace Kernel
|
||||||
BAN::Vector<BAN::UniqPtr<FixedWidthAllocator>> m_fixed_width_allocators;
|
BAN::Vector<BAN::UniqPtr<FixedWidthAllocator>> m_fixed_width_allocators;
|
||||||
BAN::UniqPtr<GeneralAllocator> m_general_allocator;
|
BAN::UniqPtr<GeneralAllocator> m_general_allocator;
|
||||||
|
|
||||||
userspace_entry_t m_userspace_entry;
|
userspace_info_t m_userspace_info;
|
||||||
ExitStatus m_exit_status;
|
ExitStatus m_exit_status;
|
||||||
|
|
||||||
BAN::UniqPtr<PageTable> m_page_table;
|
BAN::UniqPtr<PageTable> m_page_table;
|
||||||
|
|
|
@ -46,7 +46,7 @@ namespace Kernel
|
||||||
|
|
||||||
BAN::ErrorOr<Process*> Process::create_userspace(BAN::StringView path)
|
BAN::ErrorOr<Process*> 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();
|
auto* process = create_process();
|
||||||
MUST(process->m_working_directory.push_back('/'));
|
MUST(process->m_working_directory.push_back('/'));
|
||||||
|
@ -55,19 +55,28 @@ namespace Kernel
|
||||||
process->load_elf(*elf);
|
process->load_elf(*elf);
|
||||||
|
|
||||||
char** argv = nullptr;
|
char** argv = nullptr;
|
||||||
|
char** envp = nullptr;
|
||||||
{
|
{
|
||||||
PageTableScope _(process->page_table());
|
PageTableScope _(process->page_table());
|
||||||
|
|
||||||
argv = (char**)MUST(process->allocate(sizeof(char**) * 2));
|
argv = (char**)MUST(process->allocate(sizeof(char**) * 2));
|
||||||
argv[0] = (char*)MUST(process->allocate(path.size() + 1));
|
argv[0] = (char*)MUST(process->allocate(path.size() + 1));
|
||||||
memcpy(argv[0], path.data(), path.size());
|
memcpy(argv[0], path.data(), path.size());
|
||||||
argv[0][path.size()] = '\0';
|
argv[0][path.size()] = '\0';
|
||||||
argv[1] = nullptr;
|
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_info.argc = 1;
|
||||||
process->m_userspace_entry.argv = argv;
|
process->m_userspace_info.argv = argv;
|
||||||
process->m_userspace_entry.envp = (char**)0x69696969;
|
process->m_userspace_info.envp = envp;
|
||||||
process->m_userspace_entry.entry = elf->file_header_native().e_entry;
|
process->m_userspace_info.entry = elf->file_header_native().e_entry;
|
||||||
|
|
||||||
delete elf;
|
delete elf;
|
||||||
|
|
||||||
|
@ -155,9 +164,54 @@ namespace Kernel
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<LibELF::ELF*> Process::load_elf_for_exec(BAN::StringView path)
|
BAN::ErrorOr<LibELF::ELF*> Process::load_elf_for_exec(BAN::StringView file_path, const BAN::String& cwd, const BAN::Vector<BAN::StringView>& 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.is_error())
|
||||||
{
|
{
|
||||||
if (elf_or_error.error().get_error_code() == EINVAL)
|
if (elf_or_error.error().get_error_code() == EINVAL)
|
||||||
|
@ -195,7 +249,7 @@ namespace Kernel
|
||||||
|
|
||||||
forked->m_open_files = m_open_files;
|
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)
|
for (auto* mapped_range : m_mapped_ranges)
|
||||||
MUST(forked->m_mapped_ranges.push_back(mapped_range->clone(forked->page_table())));
|
MUST(forked->m_mapped_ranges.push_back(mapped_range->clone(forked->page_table())));
|
||||||
|
@ -219,16 +273,19 @@ namespace Kernel
|
||||||
BAN::ErrorOr<void> Process::exec(BAN::StringView path, const char* const* argv, const char* const* envp)
|
BAN::ErrorOr<void> Process::exec(BAN::StringView path, const char* const* argv, const char* const* envp)
|
||||||
{
|
{
|
||||||
BAN::Vector<BAN::String> str_argv;
|
BAN::Vector<BAN::String> str_argv;
|
||||||
while (argv && *argv)
|
for (int i = 0; argv && argv[i]; i++)
|
||||||
if (str_argv.emplace_back(*argv++).is_error())
|
TRY(str_argv.emplace_back(argv[i]));
|
||||||
return BAN::Error::from_errno(ENOMEM);
|
|
||||||
|
|
||||||
|
BAN::Vector<BAN::StringView> path_env;
|
||||||
BAN::Vector<BAN::String> str_envp;
|
BAN::Vector<BAN::String> str_envp;
|
||||||
while (envp && *envp)
|
for (int i = 0; envp && envp[i]; i++)
|
||||||
if (str_envp.emplace_back(*envp++).is_error())
|
{
|
||||||
return BAN::Error::from_errno(ENOMEM);
|
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);
|
LockGuard lock_guard(m_lock);
|
||||||
|
|
||||||
|
@ -243,7 +300,7 @@ namespace Kernel
|
||||||
|
|
||||||
load_elf(*elf);
|
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;
|
delete elf;
|
||||||
|
|
||||||
|
@ -252,17 +309,27 @@ namespace Kernel
|
||||||
|
|
||||||
{
|
{
|
||||||
PageTableScope _(page_table());
|
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++)
|
for (size_t i = 0; i < str_argv.size(); i++)
|
||||||
{
|
{
|
||||||
m_userspace_entry.argv[i] = (char*)MUST(allocate(str_argv[i].size() + 1));
|
m_userspace_info.argv[i] = (char*)MUST(allocate(str_argv[i].size() + 1));
|
||||||
memcpy(m_userspace_entry.argv[i], str_argv[i].data(), str_argv[i].size());
|
memcpy(m_userspace_info.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][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
|
// NOTE: These must be manually cleared since this function won't return after this point
|
||||||
str_argv.clear();
|
str_argv.clear();
|
||||||
|
|
|
@ -130,8 +130,8 @@ namespace Kernel
|
||||||
static entry_t entry_trampoline(
|
static entry_t entry_trampoline(
|
||||||
[](void*)
|
[](void*)
|
||||||
{
|
{
|
||||||
const auto& entry = Process::current().userspace_entry();
|
const auto& info = Process::current().userspace_info();
|
||||||
thread_userspace_trampoline(Thread::current().rsp(), entry.entry, entry.argc, entry.argv, entry.envp);
|
thread_userspace_trampoline(Thread::current().rsp(), info.entry, info.argc, info.argv, info.envp);
|
||||||
ASSERT_NOT_REACHED();
|
ASSERT_NOT_REACHED();
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
|
@ -206,9 +206,49 @@ int execl(const char* pathname, const char* arg0, ...)
|
||||||
return execv(pathname, argv);
|
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[])
|
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)
|
pid_t fork(void)
|
||||||
|
|
|
@ -43,13 +43,6 @@ int execute_command(BAN::StringView command)
|
||||||
}
|
}
|
||||||
else
|
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();
|
pid_t pid = fork();
|
||||||
if (pid == 0)
|
if (pid == 0)
|
||||||
{
|
{
|
||||||
|
@ -60,7 +53,7 @@ int execute_command(BAN::StringView command)
|
||||||
}
|
}
|
||||||
if (pid == -1)
|
if (pid == -1)
|
||||||
{
|
{
|
||||||
perror("fork()");
|
perror("fork");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
int status;
|
int status;
|
||||||
|
|
Loading…
Reference in New Issue