#define MODULE "stdio" #include "errno.h" #include "interrupts/Context.h" #include "io/Serial.h" #include "log/Log.h" #include "memory/VMM.h" #include "render/TextRenderer.h" #include "std/stdlib.h" #include "sys/Syscall.h" #include "sys/UserMemory.h" #include "thread/Scheduler.h" #include "thread/Task.h" #define OPEN_READ 1 #define OPEN_WRITE 2 #define SEEK_SET 0 #define SEEK_CUR 1 #define SEEK_END 2 #define FNCTL_DUPFD 0 void sys_fcntl(Context* context, int fd, int command, uintptr_t arg) { if (fd >= TASK_MAX_FDS || fd < 0) { context->rax = -EBADF; return; } Task* current_task = Scheduler::current_task(); if (!current_task->files[fd].is_open()) { context->rax = -EBADF; return; } Descriptor& file = current_task->files[fd]; if (command == FNCTL_DUPFD) { if ((int)arg < 0 || (int)arg >= TASK_MAX_FDS) { context->rax = -EINVAL; return; } int dupfd = current_task->alloc_fd_greater_than_or_equal((int)arg); if (dupfd < 0) { context->rax = -EMFILE; return; } current_task->files[dupfd] = file; context->rax = dupfd; kdbgln("fcntl(F_DUPFD): duplicated fd %d, result is %d", fd, dupfd); return; } else { context->rax = -EINVAL; return; } } void sys_seek(Context* context, int fd, long offset, int whence) { if (whence < SEEK_SET || whence > SEEK_END) { context->rax = -EINVAL; return; } if (fd >= TASK_MAX_FDS || fd < 0) { context->rax = -EBADF; return; } Task* current_task = Scheduler::current_task(); if (!current_task->files[fd].is_open()) { context->rax = -EBADF; return; } Descriptor& file = current_task->files[fd]; long new_offset; if (whence == SEEK_SET) new_offset = offset; else if (whence == SEEK_CUR) new_offset = offset + file.offset(); else if (whence == SEEK_END) new_offset = file.length() + offset; else __builtin_unreachable(); if (new_offset < 0) { context->rax = -EINVAL; // FIXME: Is this the right error? return; } if (new_offset == file.offset()) { context->rax = new_offset; return; } int result = file.seek(new_offset); if (result < 0) { context->rax = result; return; } context->rax = new_offset; return; } void sys_write(Context* context, int fd, size_t size, const char* addr) { if (!addr) { context->rax = -EFAULT; return; } if (fd >= TASK_MAX_FDS || fd < 0) { context->rax = -EBADF; return; } Task* current_task = Scheduler::current_task(); if (!current_task->files[fd].is_open()) { context->rax = -EBADF; return; } Descriptor& file = current_task->files[fd]; if (!file.can_write()) { context->rax = -EBADF; return; } ssize_t result = file.write(size, (const char*)VMM::get_physical((uint64_t)addr)); context->rax = (size_t)result; return; } void sys_open(Context* context, const char* filename, int flags) { Task* current_task = Scheduler::current_task(); int fd = current_task->alloc_fd(); if (fd < 0) { context->rax = -EMFILE; return; } char* kernel_filename = strdup_from_user(filename); if (!kernel_filename) { context->rax = -EFAULT; return; } VFS::Node* node = VFS::resolve_path(kernel_filename); if (!node) { kfree(kernel_filename); context->rax = -ENOENT; return; } bool can_read = (flags & OPEN_READ) > 0; bool can_write = (flags & OPEN_WRITE) > 0; if (!can_read && !can_write) { kfree(kernel_filename); context->rax = -EINVAL; return; } kdbgln("open(): opening %s %s, allocated file descriptor %d", kernel_filename, (can_read && can_write) ? "rw" : can_read ? "r-" : "-w", fd); kfree(kernel_filename); current_task->files[fd].open(node, can_read, can_write); context->rax = fd; return; } void sys_read(Context* context, int fd, size_t size, char* buffer) { if (!buffer) { context->rax = -EFAULT; return; } if (fd >= TASK_MAX_FDS || fd < 0) { context->rax = -EBADF; return; } Task* current_task = Scheduler::current_task(); if (!current_task->files[fd].is_open() || !current_task->files[fd].can_read()) { context->rax = -EBADF; return; } ssize_t result = current_task->files[fd].read(size, (char*)VMM::get_physical((uint64_t)buffer)); context->rax = (size_t)result; return; } void sys_close(Context* context, int fd) { if (fd >= TASK_MAX_FDS || fd < 0) { context->rax = -EBADF; return; } Task* current_task = Scheduler::current_task(); if (!current_task->files[fd].is_open()) { context->rax = -EBADF; return; } kdbgln("close(): releasing file descriptor %d", fd); current_task->files[fd].close(); context->rax = 0; return; } void sys_mkdir(Context* context, const char* filename) { char* kfilename = strdup_from_user(filename); if (!kfilename) { context->rax = -EFAULT; return; } int rc = VFS::mkdir(kfilename); kfree(kfilename); context->rax = rc; }