diff --git a/kernel/include/kernel/Process.h b/kernel/include/kernel/Process.h index 99e1b66d..738d78de 100644 --- a/kernel/include/kernel/Process.h +++ b/kernel/include/kernel/Process.h @@ -85,6 +85,7 @@ namespace Kernel BAN::ErrorOr sys_creat(BAN::StringView name, mode_t); BAN::ErrorOr sys_pipe(int fildes[2]); + BAN::ErrorOr sys_dup2(int fildes, int fildes2); BAN::ErrorOr sys_seek(int fd, off_t offset, int whence); BAN::ErrorOr sys_tell(int fd); diff --git a/kernel/kernel/Process.cpp b/kernel/kernel/Process.cpp index 0eede365..cca4e63b 100644 --- a/kernel/kernel/Process.cpp +++ b/kernel/kernel/Process.cpp @@ -135,8 +135,13 @@ namespace Kernel } m_threads.clear(); - for (auto& open_fd : m_open_files) - open_fd.inode = nullptr; + + for (int fd = 0; fd < (int)m_open_files.size(); fd++) + { + if (validate_fd(fd).is_error()) + continue; + (void)sys_close(fd); + } // NOTE: We must unmap ranges while the page table is still alive for (auto* range : m_mapped_ranges) @@ -624,6 +629,34 @@ namespace Kernel return 0; } + BAN::ErrorOr Process::sys_dup2(int fildes, int fildes2) + { + // FIXME: m_open_files should be BAN::Array, OPEN_MAX> for accurate dup2 + + if (fildes2 < 0 || fildes2 >= 100) + return BAN::Error::from_errno(EBADF); + + LockGuard _(m_lock); + + TRY(validate_fd(fildes)); + if (fildes == fildes2) + return fildes; + + if (m_open_files.size() <= (size_t)fildes2) + TRY(m_open_files.resize(fildes2 + 1)); + + if (!validate_fd(fildes2).is_error()) + TRY(sys_close(fildes2)); + + m_open_files[fildes2] = m_open_files[fildes]; + m_open_files[fildes2].flags &= ~O_CLOEXEC; + + if (m_open_files[fildes].flags & O_WRONLY && m_open_files[fildes].inode->is_pipe()) + ((Pipe*)m_open_files[fildes].inode.ptr())->clone_writing(); + + return fildes; + } + BAN::ErrorOr Process::sys_seek(int fd, off_t offset, int whence) { LockGuard _(m_lock); diff --git a/kernel/kernel/Syscall.cpp b/kernel/kernel/Syscall.cpp index bfedb0ed..c475829f 100644 --- a/kernel/kernel/Syscall.cpp +++ b/kernel/kernel/Syscall.cpp @@ -135,6 +135,9 @@ namespace Kernel case SYS_PIPE: ret = Process::current().sys_pipe((int*)arg1); break; + case SYS_DUP2: + ret = Process::current().sys_dup2((int)arg1, (int)arg2); + break; default: dwarnln("Unknown syscall {}", syscall); break; diff --git a/libc/include/sys/syscall.h b/libc/include/sys/syscall.h index 6b2545a6..32be089e 100644 --- a/libc/include/sys/syscall.h +++ b/libc/include/sys/syscall.h @@ -40,6 +40,7 @@ __BEGIN_DECLS #define SYS_SET_PWD 33 #define SYS_CLOCK_GETTIME 34 #define SYS_PIPE 35 +#define SYS_DUP2 36 __END_DECLS diff --git a/libc/unistd.cpp b/libc/unistd.cpp index ff7a4ff0..9da86fe5 100644 --- a/libc/unistd.cpp +++ b/libc/unistd.cpp @@ -257,6 +257,13 @@ long syscall(long syscall, ...) ret = Kernel::syscall(SYS_PIPE, (uintptr_t)fildes); break; } + case SYS_DUP2: + { + int fildes = va_arg(args, int); + int fildes2 = va_arg(args, int); + ret = Kernel::syscall(SYS_DUP2, fildes, fildes2); + break; + } default: puts("LibC: Unhandeled syscall"); ret = -ENOSYS; @@ -289,6 +296,11 @@ ssize_t write(int fildes, const void* buf, size_t nbyte) return syscall(SYS_WRITE, fildes, buf, nbyte); } +int dup2(int fildes, int fildes2) +{ + return syscall(SYS_DUP2, fildes, fildes2); +} + int execl(const char* pathname, const char* arg0, ...) { if (arg0 == nullptr)