diff --git a/kernel/src/sys/file.cpp b/kernel/src/sys/file.cpp index f0d8f42f..fbace6c9 100644 --- a/kernel/src/sys/file.cpp +++ b/kernel/src/sys/file.cpp @@ -147,3 +147,22 @@ Result sys_ioctl(Registers*, SyscallArgs args) return descriptor.inode->ioctl(request, arg); } + +Result sys_dup2(Registers*, SyscallArgs args) +{ + int oldfd = (int)args[0]; + int newfd = (int)args[1]; + + Thread* current = Scheduler::current(); + + if (newfd < 0 || newfd >= FD_MAX) return err(EBADF); + + auto descriptor = *TRY(current->resolve_fd(oldfd)); + + if (newfd == oldfd) return (u64)newfd; + + current->fd_table[newfd] = descriptor; + current->fd_table[newfd]->flags &= ~O_CLOEXEC; + + return (u64)newfd; +} diff --git a/libc/include/unistd.h b/libc/include/unistd.h index efa78d3d..c0265ea2 100644 --- a/libc/include/unistd.h +++ b/libc/include/unistd.h @@ -103,6 +103,9 @@ extern "C" /* Duplicate a file descriptor. */ int dup(int fd); + /* Replace a file descriptor with a copy of another one. */ + int dup2(int oldfd, int newfd); + /* Change the current working directory. */ int chdir(const char* path); diff --git a/libc/src/unistd.cpp b/libc/src/unistd.cpp index e5eef964..352e420d 100644 --- a/libc/src/unistd.cpp +++ b/libc/src/unistd.cpp @@ -292,6 +292,12 @@ extern "C" return fcntl(fd, F_DUPFD, 0); } + int dup2(int oldfd, int newfd) + { + long rc = syscall(SYS_dup2, oldfd, newfd); + __errno_return(rc, int); + } + int chdir(const char* path) { long rc = syscall(SYS_chdir, path); diff --git a/libluna/include/luna/Syscall.h b/libluna/include/luna/Syscall.h index 3201dfc9..1075d955 100644 --- a/libluna/include/luna/Syscall.h +++ b/libluna/include/luna/Syscall.h @@ -4,7 +4,7 @@ _e(exit) _e(clock_gettime) _e(mmap) _e(munmap) _e(usleep) _e(openat) _e(close) _e(read) _e(getpid) _e(write) \ _e(lseek) _e(mkdir) _e(execve) _e(mknod) _e(fork) _e(waitpid) _e(getppid) _e(fcntl) _e(getdents) _e(getuid) \ _e(geteuid) _e(getgid) _e(getegid) _e(setuid) _e(setgid) _e(seteuid) _e(setegid) _e(chmod) _e(chown) \ - _e(ioctl) _e(fstatat) _e(chdir) _e(getcwd) _e(unlinkat) _e(uname) _e(sethostname) + _e(ioctl) _e(fstatat) _e(chdir) _e(getcwd) _e(unlinkat) _e(uname) _e(sethostname) _e(dup2) enum Syscalls {