LibC: implement setenv, unsetenv, putenv
This commit is contained in:
		
							parent
							
								
									55ea5c5488
								
							
						
					
					
						commit
						24993f6020
					
				|  | @ -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