diff --git a/DevTools/UserspaceEmulator/Emulator.cpp b/DevTools/UserspaceEmulator/Emulator.cpp index ee972804a9..3878f2854c 100644 --- a/DevTools/UserspaceEmulator/Emulator.cpp +++ b/DevTools/UserspaceEmulator/Emulator.cpp @@ -253,6 +253,8 @@ u32 Emulator::virt_syscall(u32 function, u32 arg1, u32 arg2, u32 arg3) switch (function) { case SC_chdir: return virt$chdir(arg1, arg2); + case SC_dup2: + return virt$dup2(arg1, arg2); case SC_access: return virt$access(arg1, arg2, arg3); case SC_waitid: @@ -1348,4 +1350,9 @@ int Emulator::virt$chdir(FlatPtr path, size_t path_length) return syscall(SC_chdir, host_path.data(), host_path.size()); } +int Emulator::virt$dup2(int old_fd, int new_fd) +{ + return syscall(SC_dup2, old_fd, new_fd); +} + } diff --git a/DevTools/UserspaceEmulator/Emulator.h b/DevTools/UserspaceEmulator/Emulator.h index 34956d3a50..0709b93bd8 100644 --- a/DevTools/UserspaceEmulator/Emulator.h +++ b/DevTools/UserspaceEmulator/Emulator.h @@ -138,6 +138,7 @@ private: ssize_t virt$getrandom(FlatPtr buffer, size_t buffer_size, unsigned int flags); int virt$sleep(unsigned); int virt$chdir(FlatPtr, size_t); + int virt$dup2(int, int); int virt$getpgrp(); int virt$getpgid(pid_t); int virt$setpgid(pid_t pid, pid_t pgid); diff --git a/Kernel/API/Syscall.h b/Kernel/API/Syscall.h index 4581d0c204..a882df0a35 100644 --- a/Kernel/API/Syscall.h +++ b/Kernel/API/Syscall.h @@ -86,6 +86,7 @@ namespace Kernel { S(getpgrp) \ S(fork) \ S(execve) \ + S(dup2) \ S(sigaction) \ S(umask) \ S(getgroups) \ diff --git a/Kernel/CMakeLists.txt b/Kernel/CMakeLists.txt index 9743e146b2..3382edf454 100644 --- a/Kernel/CMakeLists.txt +++ b/Kernel/CMakeLists.txt @@ -100,6 +100,7 @@ set(KERNEL_SOURCES Syscalls/clock.cpp Syscalls/debug.cpp Syscalls/disown.cpp + Syscalls/dup2.cpp Syscalls/execve.cpp Syscalls/exit.cpp Syscalls/fcntl.cpp diff --git a/Kernel/Process.h b/Kernel/Process.h index 40f60ae9ec..73dd12c762 100644 --- a/Kernel/Process.h +++ b/Kernel/Process.h @@ -258,6 +258,7 @@ public: int sys$ptsname(int fd, Userspace, size_t); pid_t sys$fork(RegisterState&); int sys$execve(Userspace); + int sys$dup2(int old_fd, int new_fd); int sys$sigaction(int signum, const sigaction* act, sigaction* old_act); int sys$sigprocmask(int how, Userspace set, Userspace old_set); int sys$sigpending(Userspace); diff --git a/Kernel/Syscalls/dup2.cpp b/Kernel/Syscalls/dup2.cpp new file mode 100644 index 0000000000..7e46f10e31 --- /dev/null +++ b/Kernel/Syscalls/dup2.cpp @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2018-2020, Andreas Kling + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include + +namespace Kernel { + +int Process::sys$dup2(int old_fd, int new_fd) +{ + REQUIRE_PROMISE(stdio); + auto description = file_description(old_fd); + if (!description) + return -EBADF; + if (old_fd == new_fd) + return 0; + if (new_fd < 0 || new_fd >= m_max_open_file_descriptors) + return -EINVAL; + m_fds[new_fd].set(*description); + return new_fd; +} + +} diff --git a/Libraries/LibC/unistd.cpp b/Libraries/LibC/unistd.cpp index 385aacff46..74299af907 100644 --- a/Libraries/LibC/unistd.cpp +++ b/Libraries/LibC/unistd.cpp @@ -415,20 +415,8 @@ int dup(int old_fd) int dup2(int old_fd, int new_fd) { - if (new_fd < 0) { - errno = EBADF; - return -1; - } - - if (old_fd == new_fd) - return old_fd; - - // Validate `old_fd` so we don't close `new_fd` and then fail the `F_DUPFD`. - if (fcntl(old_fd, F_GETFL) < 0) - return -1; - - close(new_fd); - return fcntl(old_fd, F_DUPFD, new_fd); + int rc = syscall(SC_dup2, old_fd, new_fd); + __RETURN_WITH_ERRNO(rc, rc, -1); } int setgroups(size_t size, const gid_t* list)