kernel+libc+apps: Add support for environment variables

This commit is contained in:
apio 2023-04-07 15:03:38 +02:00
parent 3ef484b3f3
commit 3a28771520
Signed by: asleepymoon
GPG Key ID: B8A7D06E42258954
13 changed files with 85 additions and 9 deletions

View File

@ -8,6 +8,7 @@ endfunction()
luna_app(init.cpp init) luna_app(init.cpp init)
luna_app(sh.cpp sh) luna_app(sh.cpp sh)
luna_app(env.cpp env)
luna_app(cat.cpp cat) luna_app(cat.cpp cat)
target_link_libraries(cat PRIVATE os) target_link_libraries(cat PRIVATE os)

9
apps/env.cpp Normal file
View File

@ -0,0 +1,9 @@
#include <stdio.h>
extern char** environ;
int main()
{
char** env = environ;
while (*env) { puts(*(env++)); }
}

View File

@ -43,7 +43,8 @@ int main()
if (ret == 0) if (ret == 0)
{ {
char* argv[] = { "/bin/sh", NULL }; char* argv[] = { "/bin/sh", NULL };
execv(argv[0], argv); char* envp[] = { "PATH=/bin:/sbin", NULL };
execve(argv[0], argv, envp);
perror("execv"); perror("execv");
return 1; return 1;
} }

View File

@ -31,12 +31,13 @@ static Result<Vector<String>> copy_string_vector_from_userspace(u64 address)
return result; return result;
} }
Result<u64> sys_exec(Registers* regs, SyscallArgs args) Result<u64> sys_execve(Registers* regs, SyscallArgs args)
{ {
auto path = TRY(MemoryManager::strdup_from_user(args[0])); auto path = TRY(MemoryManager::strdup_from_user(args[0]));
auto argv = TRY(copy_string_vector_from_userspace(args[1])); auto argv = TRY(copy_string_vector_from_userspace(args[1]));
auto envp = TRY(copy_string_vector_from_userspace(args[2]));
// FIXME: Make sure argv is not too big. // FIXME: Make sure argv & envp are not too big.
auto inode = TRY(VFS::resolve_path(path.chars())); auto inode = TRY(VFS::resolve_path(path.chars()));
@ -56,6 +57,11 @@ Result<u64> sys_exec(Registers* regs, SyscallArgs args)
u64 user_argv = TRY(image->push_string_vector_on_stack(argv)); u64 user_argv = TRY(image->push_string_vector_on_stack(argv));
usize user_argc = argv.size(); usize user_argc = argv.size();
kdbgln("exec: copying envp to image memory (envc = %zu)", envp.size());
u64 user_envp = TRY(image->push_string_vector_on_stack(envp));
usize user_envc = envp.size();
// From now on, nothing should fail. // From now on, nothing should fail.
kinfoln("exec: image load ok, will now replace existing process image"); kinfoln("exec: image load ok, will now replace existing process image");
@ -77,7 +83,7 @@ Result<u64> sys_exec(Registers* regs, SyscallArgs args)
MMU::switch_page_directory(current->directory); MMU::switch_page_directory(current->directory);
current->set_arguments(user_argc, user_argv, 0, 0); current->set_arguments(user_argc, user_argv, user_envc, user_envp);
memcpy(regs, &current->regs, sizeof(*regs)); memcpy(regs, &current->regs, sizeof(*regs));

View File

@ -115,13 +115,22 @@ namespace Scheduler
thread->name = name; thread->name = name;
thread->parent_id = 0; thread->parent_id = 0;
Vector<String> args;
auto name_string = TRY(String::from_cstring(name));
TRY(args.try_append(move(name_string)));
Vector<String> env;
auto guard = make_scope_guard([&] { delete thread; }); auto guard = make_scope_guard([&] { delete thread; });
auto image = TRY(ThreadImage::try_load_from_elf(inode)); auto image = TRY(ThreadImage::try_load_from_elf(inode));
u64 argv = TRY(image->push_string_vector_on_stack(args));
u64 envp = TRY(image->push_string_vector_on_stack(env));
guard.deactivate(); guard.deactivate();
image->apply(thread); image->apply(thread);
thread->set_arguments(args.size(), argv, env.size(), envp);
kinfoln("Created userspace thread: id %lu with ip %#.16lx and sp %#.16lx (ksp %#lx)", thread->id, thread->ip(), kinfoln("Created userspace thread: id %lu with ip %#.16lx and sp %#.16lx (ksp %#lx)", thread->id, thread->ip(),
thread->sp(), thread->kernel_stack.top()); thread->sp(), thread->kernel_stack.top());

View File

@ -15,6 +15,7 @@ set(SOURCES
src/init.cpp src/init.cpp
src/dirent.cpp src/dirent.cpp
src/setjmp.cpp src/setjmp.cpp
src/env.cpp
src/sys/stat.cpp src/sys/stat.cpp
src/sys/mman.cpp src/sys/mman.cpp
src/sys/wait.cpp src/sys/wait.cpp

View File

@ -102,7 +102,8 @@ extern "C"
int system(const char*); int system(const char*);
char* getenv(const char*); /* Get the value of an environment variable. */
char* getenv(const char* key);
void qsort(void*, size_t, size_t, int (*)(const void*, const void*)); void qsort(void*, size_t, size_t, int (*)(const void*, const void*));
void* bsearch(const void*, const void*, size_t, size_t, int (*)(const void*, const void*)); void* bsearch(const void*, const void*, size_t, size_t, int (*)(const void*, const void*));

View File

@ -34,7 +34,9 @@ extern "C"
/* Replace the current process with another one. On success, does not return. */ /* Replace the current process with another one. On success, does not return. */
int execl(const char* path, const char* arg, ...); int execl(const char* path, const char* arg, ...);
int execve(const char*, char* const*, char* const*); /* Replace the current process with another one. On success, does not return. */
int execve(const char* path, char* const* argv, char* const* envp);
int execvp(const char*, char* const*); int execvp(const char*, char* const*);
/* Call the operating system kernel for a specific service. */ /* Call the operating system kernel for a specific service. */

View File

@ -12,12 +12,14 @@ _start:
pushq %rsi pushq %rsi
pushq %rdi pushq %rdi
pushq %rcx
call libc_init call libc_init
# Run the global constructors. # Run the global constructors.
call _init call _init
popq %rdx
popq %rdi popq %rdi
popq %rsi popq %rsi

31
libc/src/env.cpp Normal file
View File

@ -0,0 +1,31 @@
#include <string.h>
extern "C"
{
char** environ = nullptr;
char* getenv(const char* key)
{
char** env = environ;
size_t len = strlen(key);
while (*env)
{
// Retrieve an environment variable from environ.
char* var = *(env++);
// Check for an equals sign, else we just skip this one.
char* delim = strchr(var, '=');
if (!delim) continue;
// Get the length of this variable's key (the part before the equals sign)
size_t key_length = strcspn(var, "=");
if (len != key_length) continue;
// If the keys match, we found it! Return the value (which is just after the equals sign)
if (!memcmp(key, var, key_length)) { return delim + 1; }
}
return nullptr;
}
}

View File

@ -1,10 +1,16 @@
#include <luna/Ignore.h>
#include <stdio.h> #include <stdio.h>
#include <unistd.h> #include <unistd.h>
extern char** environ;
extern "C" extern "C"
{ {
void libc_init() void libc_init(int argc, char** argv, int envc, char** envp)
{ {
ignore(argc, argv, envc);
environ = envp;
stdin = fdopen(STDIN_FILENO, "r"); stdin = fdopen(STDIN_FILENO, "r");
stdout = fdopen(STDOUT_FILENO, "w"); stdout = fdopen(STDOUT_FILENO, "w");
stderr = fdopen(STDERR_FILENO, "w"); stderr = fdopen(STDERR_FILENO, "w");

View File

@ -9,6 +9,8 @@
extern "C" long arch_invoke_syscall(long, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t); extern "C" long arch_invoke_syscall(long, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t);
extern char** environ;
extern "C" extern "C"
{ {
pid_t fork(void) pid_t fork(void)
@ -29,7 +31,12 @@ extern "C"
int execv(const char* path, char* const* argv) int execv(const char* path, char* const* argv)
{ {
long rc = syscall(SYS_exec, path, argv); return execve(path, argv, environ);
}
int execve(const char* path, char* const* argv, char* const* envp)
{
long rc = syscall(SYS_execve, path, argv, envp);
__errno_return(rc, int); __errno_return(rc, int);
} }

View File

@ -2,7 +2,7 @@
#define enumerate_syscalls(_e) \ #define enumerate_syscalls(_e) \
_e(exit) _e(clock_gettime) _e(mmap) _e(munmap) _e(usleep) _e(open) _e(close) _e(read) _e(getpid) _e(write) \ _e(exit) _e(clock_gettime) _e(mmap) _e(munmap) _e(usleep) _e(open) _e(close) _e(read) _e(getpid) _e(write) \
_e(lseek) _e(mkdir) _e(exec) _e(mknod) _e(fork) _e(waitpid) _e(getppid) _e(fcntl) _e(getdents) _e(lseek) _e(mkdir) _e(execve) _e(mknod) _e(fork) _e(waitpid) _e(getppid) _e(fcntl) _e(getdents)
enum Syscalls enum Syscalls
{ {