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();
 | 
			
		||||
		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);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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());
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -23,6 +23,7 @@ __BEGIN_DECLS
 | 
			
		|||
#define SYS_REALLOC 16
 | 
			
		||||
#define SYS_WAIT 17
 | 
			
		||||
#define SYS_STAT 18
 | 
			
		||||
#define SYS_SETENVP 19
 | 
			
		||||
 | 
			
		||||
__END_DECLS
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										112
									
								
								libc/stdlib.cpp
								
								
								
								
							
							
						
						
									
										112
									
								
								libc/stdlib.cpp
								
								
								
								
							| 
						 | 
				
			
			@ -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);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue