From: Tulio A M Mendes Date: Tue, 10 Feb 2026 01:37:59 +0000 (-0300) Subject: posix: add pipe2 and dup3 syscalls X-Git-Url: https://projects.tadryanom.me/?a=commitdiff_plain;h=f5d047987a14d719628b83ea4f561dbace3f5ded;p=AdrOS.git posix: add pipe2 and dup3 syscalls --- diff --git a/include/syscall.h b/include/syscall.h index ebc4794..62464b0 100644 --- a/include/syscall.h +++ b/include/syscall.h @@ -23,6 +23,7 @@ enum { SYSCALL_DUP = 12, SYSCALL_DUP2 = 13, SYSCALL_PIPE = 14, + SYSCALL_PIPE2 = 34, SYSCALL_EXECVE = 15, SYSCALL_FORK = 16, SYSCALL_GETPPID = 17, @@ -47,6 +48,7 @@ enum { SYSCALL_CHDIR = 32, SYSCALL_GETCWD = 33, + SYSCALL_DUP3 = 35, }; #endif diff --git a/src/kernel/syscall.c b/src/kernel/syscall.c index 45acdd2..a146fad 100644 --- a/src/kernel/syscall.c +++ b/src/kernel/syscall.c @@ -388,10 +388,8 @@ static int pipe_node_create(struct pipe_state* ps, int is_read_end, fs_node_t** return 0; } -static int syscall_pipe_impl(int* user_fds) { - if (!user_fds) return -EFAULT; - if (user_range_ok(user_fds, sizeof(int) * 2) == 0) return -EFAULT; - +static int pipe_create_kfds(int kfds[2]) { + if (!kfds) return -EINVAL; struct pipe_state* ps = (struct pipe_state*)kmalloc(sizeof(*ps)); if (!ps) return -ENOMEM; memset(ps, 0, sizeof(*ps)); @@ -445,12 +443,46 @@ static int syscall_pipe_impl(int* user_fds) { return -EMFILE; } - int kfds[2]; kfds[0] = rfd; kfds[1] = wfd; + return 0; +} + +static int syscall_pipe_impl(int* user_fds) { + if (!user_fds) return -EFAULT; + if (user_range_ok(user_fds, sizeof(int) * 2) == 0) return -EFAULT; + + int kfds[2]; + int rc = pipe_create_kfds(kfds); + if (rc < 0) return rc; + if (copy_to_user(user_fds, kfds, sizeof(kfds)) < 0) { - (void)fd_close(rfd); - (void)fd_close(wfd); + (void)fd_close(kfds[0]); + (void)fd_close(kfds[1]); + return -EFAULT; + } + return 0; +} + +static int syscall_pipe2_impl(int* user_fds, uint32_t flags) { + if (!user_fds) return -EFAULT; + if (user_range_ok(user_fds, sizeof(int) * 2) == 0) return -EFAULT; + + int kfds[2]; + int rc = pipe_create_kfds(kfds); + if (rc < 0) return rc; + if (!current_process) return -ECHILD; + + if (kfds[0] >= 0 && kfds[0] < PROCESS_MAX_FILES && current_process->files[kfds[0]]) { + current_process->files[kfds[0]]->flags = flags; + } + if (kfds[1] >= 0 && kfds[1] < PROCESS_MAX_FILES && current_process->files[kfds[1]]) { + current_process->files[kfds[1]]->flags = flags; + } + + if (copy_to_user(user_fds, kfds, sizeof(kfds)) < 0) { + (void)fd_close(kfds[0]); + (void)fd_close(kfds[1]); return -EFAULT; } @@ -692,6 +724,23 @@ static int syscall_dup2_impl(int oldfd, int newfd) { return newfd; } +static int syscall_dup3_impl(int oldfd, int newfd, uint32_t flags) { + // Minimal: accept only flags==0 for now. + if (flags != 0) return -EINVAL; + if (newfd < 0 || newfd >= PROCESS_MAX_FILES) return -EBADF; + if (oldfd == newfd) return -EINVAL; + struct file* f = fd_get(oldfd); + if (!f) return -EBADF; + + if (current_process && current_process->files[newfd]) { + (void)fd_close(newfd); + } + + f->refcount++; + current_process->files[newfd] = f; + return newfd; +} + static int syscall_stat_impl(const char* user_path, struct stat* user_st) { if (!user_path || !user_st) return -EFAULT; if (user_range_ok(user_st, sizeof(*user_st)) == 0) return -EFAULT; @@ -1350,12 +1399,27 @@ static void syscall_handler(struct registers* regs) { return; } + if (syscall_no == SYSCALL_DUP3) { + int oldfd = (int)regs->ebx; + int newfd = (int)regs->ecx; + uint32_t flags = (uint32_t)regs->edx; + regs->eax = (uint32_t)syscall_dup3_impl(oldfd, newfd, flags); + return; + } + if (syscall_no == SYSCALL_PIPE) { int* user_fds = (int*)regs->ebx; regs->eax = (uint32_t)syscall_pipe_impl(user_fds); return; } + if (syscall_no == SYSCALL_PIPE2) { + int* user_fds = (int*)regs->ebx; + uint32_t flags = (uint32_t)regs->ecx; + regs->eax = (uint32_t)syscall_pipe2_impl(user_fds, flags); + return; + } + if (syscall_no == SYSCALL_EXECVE) { const char* path = (const char*)regs->ebx; const char* const* argv = (const char* const*)regs->ecx; diff --git a/user/init.c b/user/init.c index 1bb4edf..15fe228 100644 --- a/user/init.c +++ b/user/init.c @@ -48,6 +48,7 @@ enum { SYSCALL_DUP = 12, SYSCALL_DUP2 = 13, SYSCALL_PIPE = 14, + SYSCALL_PIPE2 = 34, SYSCALL_EXECVE = 15, SYSCALL_FORK = 16, SYSCALL_GETPPID = 17, @@ -72,6 +73,7 @@ enum { SYSCALL_CHDIR = 32, SYSCALL_GETCWD = 33, + SYSCALL_DUP3 = 35, }; enum { @@ -136,6 +138,7 @@ enum { enum { EAGAIN = 11, + EINVAL = 22, }; #define S_IFMT 0170000 @@ -159,6 +162,17 @@ static int sys_write(int fd, const void* buf, uint32_t len) { return __syscall_fix(ret); } +static int sys_pipe2(int fds[2], uint32_t flags) { + int ret; + __asm__ volatile( + "int $0x80" + : "=a"(ret) + : "a"(SYSCALL_PIPE2), "b"(fds), "c"(flags) + : "memory" + ); + return __syscall_fix(ret); +} + static int sys_chdir(const char* path) { int ret; __asm__ volatile( @@ -461,6 +475,17 @@ static int sys_dup2(int oldfd, int newfd) { return __syscall_fix(ret); } +static int sys_dup3(int oldfd, int newfd, uint32_t flags) { + int ret; + __asm__ volatile( + "int $0x80" + : "=a"(ret) + : "a"(SYSCALL_DUP3), "b"(oldfd), "c"(newfd), "d"(flags) + : "memory" + ); + return __syscall_fix(ret); +} + static int sys_waitpid(int pid, int* status, uint32_t options) { int ret; __asm__ volatile( @@ -1821,6 +1846,36 @@ void _start(void) { (uint32_t)(sizeof("[init] O_NONBLOCK OK\n") - 1)); } + // B6b: pipe2 + dup3 smoke + { + int fds[2]; + if (sys_pipe2(fds, O_NONBLOCK) < 0) { + sys_write(1, "[init] pipe2 failed\n", + (uint32_t)(sizeof("[init] pipe2 failed\n") - 1)); + sys_exit(1); + } + + char b; + int r = sys_read(fds[0], &b, 1); + if (r != -1 || errno != EAGAIN) { + sys_write(1, "[init] pipe2 nonblock read expected EAGAIN\n", + (uint32_t)(sizeof("[init] pipe2 nonblock read expected EAGAIN\n") - 1)); + sys_exit(1); + } + + int d = sys_dup3(fds[0], fds[0], 0); + if (d != -1 || errno != EINVAL) { + sys_write(1, "[init] dup3 samefd expected EINVAL\n", + (uint32_t)(sizeof("[init] dup3 samefd expected EINVAL\n") - 1)); + sys_exit(1); + } + + (void)sys_close(fds[0]); + (void)sys_close(fds[1]); + sys_write(1, "[init] pipe2/dup3 OK\n", + (uint32_t)(sizeof("[init] pipe2/dup3 OK\n") - 1)); + } + // B7: chdir/getcwd smoke + relative paths { int r = sys_mkdir("/disk/cwd");