2022-10-10 18:21:39 +00:00
|
|
|
#define MODULE "stdio"
|
|
|
|
|
2022-09-29 17:17:43 +00:00
|
|
|
#include "interrupts/Context.h"
|
|
|
|
#include "io/Serial.h"
|
2022-10-10 18:21:39 +00:00
|
|
|
#include "log/Log.h"
|
2022-10-13 20:13:04 +00:00
|
|
|
#include "memory/VMM.h"
|
2022-10-01 12:27:45 +00:00
|
|
|
#include "render/TextRenderer.h"
|
2022-10-19 15:41:23 +00:00
|
|
|
#include "std/errno.h"
|
2022-10-13 20:13:04 +00:00
|
|
|
#include "std/stdlib.h"
|
|
|
|
#include "sys/Syscall.h"
|
2022-10-19 15:13:16 +00:00
|
|
|
#include "sys/UserMemory.h"
|
2022-10-10 18:21:39 +00:00
|
|
|
#include "thread/Scheduler.h"
|
|
|
|
#include "thread/Task.h"
|
|
|
|
|
2022-10-11 19:06:12 +00:00
|
|
|
#define OPEN_READ 1
|
|
|
|
#define OPEN_WRITE 2
|
2022-10-21 19:51:03 +00:00
|
|
|
#define OPEN_NONBLOCK 4
|
2022-10-22 08:28:02 +00:00
|
|
|
#define OPEN_CLOEXEC 8
|
2022-10-11 19:06:12 +00:00
|
|
|
|
2022-10-12 13:28:52 +00:00
|
|
|
#define SEEK_SET 0
|
|
|
|
#define SEEK_CUR 1
|
|
|
|
#define SEEK_END 2
|
|
|
|
|
2022-10-21 16:34:31 +00:00
|
|
|
#define FCNTL_DUPFD 0
|
|
|
|
#define FCNTL_ISTTY 1
|
2022-10-15 08:56:06 +00:00
|
|
|
|
2022-10-17 15:01:22 +00:00
|
|
|
void sys_fcntl(Context* context, int fd, int command, uintptr_t arg)
|
2022-10-15 08:56:06 +00:00
|
|
|
{
|
|
|
|
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];
|
2022-10-21 16:34:31 +00:00
|
|
|
if (command == FCNTL_DUPFD)
|
2022-10-15 08:56:06 +00:00
|
|
|
{
|
2022-10-17 15:01:22 +00:00
|
|
|
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);
|
2022-10-15 08:56:06 +00:00
|
|
|
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;
|
|
|
|
}
|
2022-10-21 16:34:31 +00:00
|
|
|
else if (command == FCNTL_ISTTY)
|
|
|
|
{
|
|
|
|
VFS::Node* node = file.node();
|
|
|
|
if (node->tty) { context->rax = 1; }
|
|
|
|
else
|
|
|
|
context->rax = -ENOTTY;
|
|
|
|
return;
|
|
|
|
}
|
2022-10-15 08:56:06 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
context->rax = -EINVAL;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-10-12 13:28:52 +00:00
|
|
|
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;
|
|
|
|
}
|
2022-10-15 08:56:06 +00:00
|
|
|
Descriptor& file = current_task->files[fd];
|
2022-10-12 13:28:52 +00:00
|
|
|
long new_offset;
|
|
|
|
if (whence == SEEK_SET) new_offset = offset;
|
|
|
|
else if (whence == SEEK_CUR)
|
2022-10-15 08:56:06 +00:00
|
|
|
new_offset = offset + file.offset();
|
2022-10-12 13:28:52 +00:00
|
|
|
else if (whence == SEEK_END)
|
2022-10-15 08:56:06 +00:00
|
|
|
new_offset = file.length() + offset;
|
2022-10-12 13:28:52 +00:00
|
|
|
else
|
|
|
|
__builtin_unreachable();
|
|
|
|
if (new_offset < 0)
|
|
|
|
{
|
|
|
|
context->rax = -EINVAL; // FIXME: Is this the right error?
|
|
|
|
return;
|
|
|
|
}
|
2022-10-15 08:56:06 +00:00
|
|
|
if (new_offset == file.offset())
|
|
|
|
{
|
|
|
|
context->rax = new_offset;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
int result = file.seek(new_offset);
|
2022-10-12 13:28:52 +00:00
|
|
|
if (result < 0)
|
|
|
|
{
|
|
|
|
context->rax = result;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
context->rax = new_offset;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-10-11 19:06:12 +00:00
|
|
|
void sys_write(Context* context, int fd, size_t size, const char* addr)
|
2022-09-29 17:17:43 +00:00
|
|
|
{
|
2022-10-11 19:06:12 +00:00
|
|
|
if (!addr)
|
|
|
|
{
|
2022-10-12 17:25:35 +00:00
|
|
|
context->rax = -EFAULT;
|
2022-10-11 19:06:12 +00:00
|
|
|
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;
|
|
|
|
}
|
2022-10-15 08:56:06 +00:00
|
|
|
Descriptor& file = current_task->files[fd];
|
|
|
|
if (!file.can_write())
|
2022-10-11 19:06:12 +00:00
|
|
|
{
|
|
|
|
context->rax = -EBADF;
|
|
|
|
return;
|
|
|
|
}
|
2022-10-15 08:56:06 +00:00
|
|
|
ssize_t result = file.write(size, (const char*)VMM::get_physical((uint64_t)addr));
|
2022-10-11 19:06:12 +00:00
|
|
|
context->rax = (size_t)result;
|
|
|
|
return;
|
2022-10-10 18:21:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void sys_open(Context* context, const char* filename, int flags)
|
|
|
|
{
|
|
|
|
Task* current_task = Scheduler::current_task();
|
2022-10-15 08:56:06 +00:00
|
|
|
int fd = current_task->alloc_fd();
|
|
|
|
if (fd < 0)
|
2022-10-10 18:21:39 +00:00
|
|
|
{
|
|
|
|
context->rax = -EMFILE;
|
|
|
|
return;
|
|
|
|
}
|
2022-10-11 19:06:12 +00:00
|
|
|
|
2022-10-21 19:51:03 +00:00
|
|
|
char* kfilename = strdup_from_user(filename);
|
|
|
|
if (!kfilename)
|
2022-10-13 20:13:04 +00:00
|
|
|
{
|
|
|
|
context->rax = -EFAULT;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-10-21 19:51:03 +00:00
|
|
|
VFS::Node* node = VFS::resolve_path(kfilename);
|
2022-10-10 18:21:39 +00:00
|
|
|
if (!node)
|
|
|
|
{
|
2022-10-21 19:51:03 +00:00
|
|
|
kfree(kfilename);
|
2022-10-10 18:21:39 +00:00
|
|
|
context->rax = -ENOENT;
|
|
|
|
return;
|
|
|
|
}
|
2022-10-11 19:06:12 +00:00
|
|
|
|
|
|
|
bool can_read = (flags & OPEN_READ) > 0;
|
|
|
|
bool can_write = (flags & OPEN_WRITE) > 0;
|
|
|
|
if (!can_read && !can_write)
|
|
|
|
{
|
2022-10-21 19:51:03 +00:00
|
|
|
kfree(kfilename);
|
2022-10-11 19:06:12 +00:00
|
|
|
context->rax = -EINVAL;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-10-21 19:51:03 +00:00
|
|
|
bool able_to_block = (flags & OPEN_NONBLOCK) == 0;
|
2022-10-22 08:28:02 +00:00
|
|
|
bool close_on_exec = (flags & OPEN_CLOEXEC) > 0;
|
2022-10-21 19:51:03 +00:00
|
|
|
|
|
|
|
kdbgln("open(): opening %s %s, allocated file descriptor %d", kfilename,
|
2022-10-11 19:06:12 +00:00
|
|
|
(can_read && can_write) ? "rw"
|
|
|
|
: can_read ? "r-"
|
|
|
|
: "-w",
|
|
|
|
fd);
|
|
|
|
|
2022-10-21 19:51:03 +00:00
|
|
|
kfree(kfilename);
|
2022-10-22 08:28:02 +00:00
|
|
|
current_task->files[fd].open(node, can_read, can_write, able_to_block, close_on_exec);
|
2022-10-10 18:21:39 +00:00
|
|
|
context->rax = fd;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
void sys_read(Context* context, int fd, size_t size, char* buffer)
|
|
|
|
{
|
|
|
|
if (!buffer)
|
|
|
|
{
|
2022-10-12 17:25:35 +00:00
|
|
|
context->rax = -EFAULT;
|
2022-10-10 18:21:39 +00:00
|
|
|
return;
|
|
|
|
}
|
2022-10-11 15:10:44 +00:00
|
|
|
if (fd >= TASK_MAX_FDS || fd < 0)
|
2022-10-10 18:21:39 +00:00
|
|
|
{
|
|
|
|
context->rax = -EBADF;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
Task* current_task = Scheduler::current_task();
|
2022-10-11 15:10:44 +00:00
|
|
|
if (!current_task->files[fd].is_open() || !current_task->files[fd].can_read())
|
2022-10-10 18:21:39 +00:00
|
|
|
{
|
|
|
|
context->rax = -EBADF;
|
|
|
|
return;
|
|
|
|
}
|
2022-10-21 19:26:19 +00:00
|
|
|
if (VFS::would_block(current_task->files[fd].node()))
|
|
|
|
{
|
2022-10-21 19:51:03 +00:00
|
|
|
if (!current_task->files[fd].able_to_block())
|
|
|
|
{
|
|
|
|
context->rax = -EAGAIN;
|
|
|
|
return;
|
|
|
|
}
|
2022-10-21 19:26:19 +00:00
|
|
|
current_task->state = current_task->Blocking;
|
|
|
|
current_task->blocking_read_info.fd = fd;
|
|
|
|
current_task->blocking_read_info.buf = (char*)VMM::get_physical((uint64_t)buffer); // FIXME: Handle errors.
|
|
|
|
current_task->blocking_read_info.size = size;
|
|
|
|
return Scheduler::task_yield(context);
|
|
|
|
}
|
2022-10-22 08:28:02 +00:00
|
|
|
ssize_t result = current_task->files[fd].read(
|
|
|
|
size, (char*)VMM::get_physical((uint64_t)buffer)); // FIXME: Handle errors, and big buffers which may not be
|
|
|
|
// across continuous physical pages.
|
2022-10-10 18:21:39 +00:00
|
|
|
context->rax = (size_t)result;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
void sys_close(Context* context, int fd)
|
|
|
|
{
|
2022-10-11 15:10:44 +00:00
|
|
|
if (fd >= TASK_MAX_FDS || fd < 0)
|
2022-10-10 18:21:39 +00:00
|
|
|
{
|
|
|
|
context->rax = -EBADF;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
Task* current_task = Scheduler::current_task();
|
|
|
|
if (!current_task->files[fd].is_open())
|
|
|
|
{
|
|
|
|
context->rax = -EBADF;
|
|
|
|
return;
|
|
|
|
}
|
2022-10-11 15:19:03 +00:00
|
|
|
kdbgln("close(): releasing file descriptor %d", fd);
|
2022-10-10 18:21:39 +00:00
|
|
|
current_task->files[fd].close();
|
|
|
|
context->rax = 0;
|
|
|
|
return;
|
2022-10-16 15:22:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void sys_mkdir(Context* context, const char* filename)
|
|
|
|
{
|
2022-10-19 15:13:16 +00:00
|
|
|
char* kfilename = strdup_from_user(filename);
|
2022-10-16 15:22:12 +00:00
|
|
|
if (!kfilename)
|
|
|
|
{
|
|
|
|
context->rax = -EFAULT;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
int rc = VFS::mkdir(kfilename);
|
|
|
|
|
|
|
|
kfree(kfilename);
|
|
|
|
|
|
|
|
context->rax = rc;
|
2022-10-20 17:03:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void sys_access(Context* context, const char* path, int) // FIXME: Use the amode argument.
|
|
|
|
{
|
|
|
|
char* kpath = strdup_from_user(path);
|
|
|
|
if (!VFS::exists(kpath)) { context->rax = -ENOENT; }
|
|
|
|
else
|
|
|
|
context->rax = 0;
|
|
|
|
kfree(kpath);
|
2022-09-29 17:17:43 +00:00
|
|
|
}
|