]> Projects (at) Tadryanom (dot) Me - AdrOS.git/commitdiff
posix: add pipe2 and dup3 syscalls
authorTulio A M Mendes <[email protected]>
Tue, 10 Feb 2026 01:37:59 +0000 (22:37 -0300)
committerTulio A M Mendes <[email protected]>
Tue, 10 Feb 2026 01:37:59 +0000 (22:37 -0300)
include/syscall.h
src/kernel/syscall.c
user/init.c

index ebc4794e3b2423c0329e24936b36de425c8d1be5..62464b0e7b56890d5e614e3e69a620923adab879 100644 (file)
@@ -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
index 45acdd211e89f13ad86e48f71dcbecedbdfe7a46..a146fad974c60d6536264e9a6f2576713b019748 100644 (file)
@@ -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;
index 1bb4edfc72616bb402f02f997f7fda38761f5e8f..15fe228d642afb3a8287a61d964227095aca791c 100644 (file)
@@ -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");