LibC: implement setenv, unsetenv, putenv

This commit is contained in:
Bananymous 2023-06-05 22:43:26 +03:00
parent 064ce568c2
commit 86f58f60cb
6 changed files with 138 additions and 1 deletions

View File

@ -57,6 +57,8 @@ namespace Kernel
int block_until_exit();
BAN::ErrorOr<pid_t> wait(pid_t pid, int* stat_loc, int options);
BAN::ErrorOr<void> setenvp(char** envp);
BAN::ErrorOr<int> open(BAN::StringView, int);
BAN::ErrorOr<void> close(int fd);
BAN::ErrorOr<size_t> read(int fd, void* buffer, size_t count);

View File

@ -389,6 +389,13 @@ namespace Kernel
return ret;
}
BAN::ErrorOr<void> Process::setenvp(char** envp)
{
LockGuard _(m_lock);
m_userspace_info.envp = envp;
return {};
}
void Process::load_elf(LibELF::ELF& elf)
{
ASSERT(elf.is_native());

View File

@ -136,6 +136,14 @@ namespace Kernel
return 0;
}
long sys_setenvp(char** envp)
{
auto ret = Process::current().setenvp(envp);
if (ret.is_error())
return -ret.error().get_error_code();
return 0;
}
extern "C" long sys_fork_trampoline();
extern "C" long cpp_syscall_handler(int syscall, uintptr_t arg1, uintptr_t arg2, uintptr_t arg3, uintptr_t arg4, uintptr_t arg5)
@ -204,6 +212,9 @@ namespace Kernel
case SYS_STAT:
ret = sys_stat((const char*)arg1, (struct stat*)arg2, (int)arg3);
break;
case SYS_SETENVP:
ret = sys_setenvp((char**)arg1);
break;
default:
Kernel::panic("Unknown syscall {}", syscall);
}

View File

@ -23,6 +23,7 @@ __BEGIN_DECLS
#define SYS_REALLOC 16
#define SYS_WAIT 17
#define SYS_STAT 18
#define SYS_SETENVP 19
__END_DECLS

View File

@ -7,6 +7,8 @@
#include <sys/syscall.h>
#include <unistd.h>
extern "C" char** environ;
extern "C" void _fini();
void abort(void)
@ -54,11 +56,119 @@ int atoi(const char* str)
return negative ? -res : res;
}
char* getenv(const char*)
char* getenv(const char* name)
{
if (environ == nullptr)
return nullptr;
size_t len = strlen(name);
for (int i = 0; environ[i]; i++)
if (strncmp(name, environ[i], len) == 0)
if (environ[i][len] == '=')
return environ[i] + len + 1;
return nullptr;
}
int setenv(const char* name, const char* val, int overwrite)
{
if (name == nullptr || !name[0] || strchr(name, '='))
{
errno = EINVAL;
return -1;
}
if (!overwrite && getenv(name))
return 0;
size_t namelen = strlen(name);
size_t vallen = strlen(val);
char* string = (char*)malloc(namelen + vallen + 2);
memcpy(string, name, namelen);
string[namelen] = '=';
memcpy(string + namelen + 1, val, vallen);
string[namelen + vallen + 1] = '\0';
return putenv(string);
}
int unsetenv(const char* name)
{
if (name == nullptr || !name[0] || strchr(name, '='))
{
errno = EINVAL;
return -1;
}
size_t len = strlen(name);
bool found = false;
for (int i = 0; environ[i]; i++)
{
if (!found && strncmp(environ[i], name, len) == 0 && environ[i][len] == '=')
{
free(environ[i]);
found = true;
}
if (found)
environ[i] = environ[i + 1];
}
return 0;
}
int putenv(char* string)
{
if (string == nullptr || !string[0])
{
errno = EINVAL;
return -1;
}
int cnt = 0;
for (int i = 0; string[i]; i++)
if (string[i] == '=')
cnt++;
if (cnt != 1)
{
errno = EINVAL;
return -1;
}
int namelen = strchr(string, '=') - string;
for (int i = 0; environ[i]; i++)
{
if (strncmp(environ[i], string, namelen + 1) == 0)
{
free(environ[i]);
environ[i] = string;
return 0;
}
}
int env_count = 0;
while (environ[env_count])
env_count++;
char** new_envp = (char**)malloc(sizeof(char*) * (env_count + 2));
if (new_envp == nullptr)
{
errno = ENOMEM;
return -1;
}
for (int i = 0; i < env_count; i++)
new_envp[i] = environ[i];
new_envp[env_count] = string;
new_envp[env_count + 1] = nullptr;
free(environ);
environ = new_envp;
if (syscall(SYS_SETENVP, environ) == -1)
return -1;
return 0;
}
void* malloc(size_t bytes)
{
long res = syscall(SYS_ALLOC, bytes);

View File

@ -157,6 +157,12 @@ long syscall(long syscall, ...)
ret = Kernel::syscall(SYS_STAT, (uintptr_t)path, (uintptr_t)buf, flags);
break;
}
case SYS_SETENVP:
{
char** envp = va_arg(args, char**);
ret = Kernel::syscall(SYS_SETENVP, (uintptr_t)envp);
break;
}
default:
puts("LibC: Unhandeled syscall");
ret = -ENOSYS;