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));
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;
}
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;
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;
SYSCALL_DUP = 12,
SYSCALL_DUP2 = 13,
SYSCALL_PIPE = 14,
+ SYSCALL_PIPE2 = 34,
SYSCALL_EXECVE = 15,
SYSCALL_FORK = 16,
SYSCALL_GETPPID = 17,
SYSCALL_CHDIR = 32,
SYSCALL_GETCWD = 33,
+ SYSCALL_DUP3 = 35,
};
enum {
enum {
EAGAIN = 11,
+ EINVAL = 22,
};
#define S_IFMT 0170000
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(
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(
(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");