forked from Bananymous/banan-os
LibC: implement setenv, unsetenv, putenv
This commit is contained in:
parent
064ce568c2
commit
86f58f60cb
|
@ -57,6 +57,8 @@ namespace Kernel
|
||||||
int block_until_exit();
|
int block_until_exit();
|
||||||
BAN::ErrorOr<pid_t> wait(pid_t pid, int* stat_loc, int options);
|
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<int> open(BAN::StringView, int);
|
||||||
BAN::ErrorOr<void> close(int fd);
|
BAN::ErrorOr<void> close(int fd);
|
||||||
BAN::ErrorOr<size_t> read(int fd, void* buffer, size_t count);
|
BAN::ErrorOr<size_t> read(int fd, void* buffer, size_t count);
|
||||||
|
|
|
@ -389,6 +389,13 @@ namespace Kernel
|
||||||
return ret;
|
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)
|
void Process::load_elf(LibELF::ELF& elf)
|
||||||
{
|
{
|
||||||
ASSERT(elf.is_native());
|
ASSERT(elf.is_native());
|
||||||
|
|
|
@ -136,6 +136,14 @@ namespace Kernel
|
||||||
return 0;
|
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 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)
|
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:
|
case SYS_STAT:
|
||||||
ret = sys_stat((const char*)arg1, (struct stat*)arg2, (int)arg3);
|
ret = sys_stat((const char*)arg1, (struct stat*)arg2, (int)arg3);
|
||||||
break;
|
break;
|
||||||
|
case SYS_SETENVP:
|
||||||
|
ret = sys_setenvp((char**)arg1);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
Kernel::panic("Unknown syscall {}", syscall);
|
Kernel::panic("Unknown syscall {}", syscall);
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,7 @@ __BEGIN_DECLS
|
||||||
#define SYS_REALLOC 16
|
#define SYS_REALLOC 16
|
||||||
#define SYS_WAIT 17
|
#define SYS_WAIT 17
|
||||||
#define SYS_STAT 18
|
#define SYS_STAT 18
|
||||||
|
#define SYS_SETENVP 19
|
||||||
|
|
||||||
__END_DECLS
|
__END_DECLS
|
||||||
|
|
||||||
|
|
112
libc/stdlib.cpp
112
libc/stdlib.cpp
|
@ -7,6 +7,8 @@
|
||||||
#include <sys/syscall.h>
|
#include <sys/syscall.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
|
extern "C" char** environ;
|
||||||
|
|
||||||
extern "C" void _fini();
|
extern "C" void _fini();
|
||||||
|
|
||||||
void abort(void)
|
void abort(void)
|
||||||
|
@ -54,11 +56,119 @@ int atoi(const char* str)
|
||||||
return negative ? -res : res;
|
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;
|
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)
|
void* malloc(size_t bytes)
|
||||||
{
|
{
|
||||||
long res = syscall(SYS_ALLOC, bytes);
|
long res = syscall(SYS_ALLOC, bytes);
|
||||||
|
|
|
@ -157,6 +157,12 @@ long syscall(long syscall, ...)
|
||||||
ret = Kernel::syscall(SYS_STAT, (uintptr_t)path, (uintptr_t)buf, flags);
|
ret = Kernel::syscall(SYS_STAT, (uintptr_t)path, (uintptr_t)buf, flags);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case SYS_SETENVP:
|
||||||
|
{
|
||||||
|
char** envp = va_arg(args, char**);
|
||||||
|
ret = Kernel::syscall(SYS_SETENVP, (uintptr_t)envp);
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
puts("LibC: Unhandeled syscall");
|
puts("LibC: Unhandeled syscall");
|
||||||
ret = -ENOSYS;
|
ret = -ENOSYS;
|
||||||
|
|
Loading…
Reference in New Issue