diff --git a/kernel/include/kernel/Process.h b/kernel/include/kernel/Process.h index 42c6ea7354..342215ea1a 100644 --- a/kernel/include/kernel/Process.h +++ b/kernel/include/kernel/Process.h @@ -58,6 +58,9 @@ namespace Kernel BAN::ErrorOr setenvp(char** envp); + BAN::ErrorOr set_pwd(const char* path); + BAN::ErrorOr get_pwd(char* buffer, size_t size); + BAN::ErrorOr set_uid(uid_t); BAN::ErrorOr set_gid(gid_t); BAN::ErrorOr set_euid(uid_t); diff --git a/kernel/kernel/Process.cpp b/kernel/kernel/Process.cpp index cc0a7e2de1..6522a708e6 100644 --- a/kernel/kernel/Process.cpp +++ b/kernel/kernel/Process.cpp @@ -667,6 +667,38 @@ namespace Kernel return {}; } + BAN::ErrorOr Process::set_pwd(const char* path) + { + BAN::String absolute_path; + + { + LockGuard _(m_lock); + absolute_path = TRY(absolute_path_of(path)); + } + + auto file = TRY(VirtualFileSystem::get().file_from_absolute_path(m_credentials, absolute_path, O_SEARCH)); + if (!file.inode->mode().ifdir()) + return BAN::Error::from_errno(ENOTDIR); + + LockGuard _(m_lock); + m_working_directory = BAN::move(file.canonical_path); + + return {}; + } + + BAN::ErrorOr Process::get_pwd(char* buffer, size_t size) + { + LockGuard _(m_lock); + + if (size < m_working_directory.size() + 1) + return BAN::Error::from_errno(ERANGE); + + memcpy(buffer, m_working_directory.data(), m_working_directory.size()); + buffer[m_working_directory.size()] = '\0'; + + return buffer; + } + BAN::ErrorOr Process::working_directory() const { BAN::String result; diff --git a/kernel/kernel/Syscall.cpp b/kernel/kernel/Syscall.cpp index ed63ef84c5..2539bf3e3a 100644 --- a/kernel/kernel/Syscall.cpp +++ b/kernel/kernel/Syscall.cpp @@ -228,6 +228,22 @@ namespace Kernel return Process::current().get_egid(); } + long sys_get_pwd(char* buffer, size_t size) + { + auto ret = Process::current().get_pwd(buffer, size); + if (ret.is_error()) + return -ret.error().get_error_code(); + return (long)ret.value(); + } + + long sys_set_pwd(const char* path) + { + auto ret = Process::current().set_pwd(path); + 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) @@ -335,6 +351,12 @@ namespace Kernel case SYS_GET_EGID: ret = sys_get_egid(); break; + case SYS_GET_PWD: + ret = sys_get_pwd((char*)arg1, (size_t)arg2); + break; + case SYS_SET_PWD: + ret = sys_set_pwd((const char*)arg1); + break; default: dwarnln("Unknown syscall {}", syscall); ret = -ENOSYS; diff --git a/libc/include/sys/syscall.h b/libc/include/sys/syscall.h index 272b312779..e919b16c6e 100644 --- a/libc/include/sys/syscall.h +++ b/libc/include/sys/syscall.h @@ -36,6 +36,8 @@ __BEGIN_DECLS #define SYS_GET_GID 29 #define SYS_GET_EUID 30 #define SYS_GET_EGID 31 +#define SYS_GET_PWD 32 +#define SYS_SET_PWD 33 __END_DECLS diff --git a/libc/unistd.cpp b/libc/unistd.cpp index 54b7f73f31..3ada9dabc6 100644 --- a/libc/unistd.cpp +++ b/libc/unistd.cpp @@ -233,6 +233,19 @@ long syscall(long syscall, ...) ret = Kernel::syscall(SYS_GET_EGID); break; } + case SYS_GET_PWD: + { + char* buffer = va_arg(args, char*); + size_t size = va_arg(args, size_t); + ret = Kernel::syscall(SYS_GET_PWD, (uintptr_t)buffer, size); + break; + } + case SYS_SET_PWD: + { + const char* path = va_arg(args, const char*); + ret = Kernel::syscall(SYS_SET_PWD, (uintptr_t)path); + break; + } default: puts("LibC: Unhandeled syscall"); ret = -ENOSYS; @@ -342,6 +355,26 @@ unsigned int sleep(unsigned int seconds) return syscall(SYS_SLEEP, seconds); } +char* getcwd(char* buf, size_t size) +{ + if (size == 0) + { + errno = EINVAL; + return nullptr; + } + + if ((char*)syscall(SYS_GET_PWD, buf, size) == nullptr) + return nullptr; + + setenv("PWD", buf, 1); + return buf; +} + +int chdir(const char* path) +{ + return syscall(SYS_SET_PWD, path); +} + uid_t getuid(void) { return syscall(SYS_GET_UID);