18989aa00SSiva Chandra Reddy //===-- Linux implementation of dup2 --------------------------------------===// 28989aa00SSiva Chandra Reddy // 38989aa00SSiva Chandra Reddy // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 48989aa00SSiva Chandra Reddy // See https://llvm.org/LICENSE.txt for license information. 58989aa00SSiva Chandra Reddy // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 68989aa00SSiva Chandra Reddy // 78989aa00SSiva Chandra Reddy //===----------------------------------------------------------------------===// 88989aa00SSiva Chandra Reddy 98989aa00SSiva Chandra Reddy #include "src/unistd/dup2.h" 108989aa00SSiva Chandra Reddy 118989aa00SSiva Chandra Reddy #include "src/__support/OSUtil/syscall.h" // For internal syscall function. 128989aa00SSiva Chandra Reddy #include "src/__support/common.h" 138989aa00SSiva Chandra Reddy 14*abc49cc1SJob Henandez Lara #include "hdr/fcntl_macros.h" 155ff3ff33SPetr Hosek #include "src/__support/macros/config.h" 16803437dbSMichael Jones #include "src/errno/libc_errno.h" 178989aa00SSiva Chandra Reddy #include <sys/syscall.h> // For syscall numbers. 188989aa00SSiva Chandra Reddy 195ff3ff33SPetr Hosek namespace LIBC_NAMESPACE_DECL { 208989aa00SSiva Chandra Reddy 218989aa00SSiva Chandra Reddy LLVM_LIBC_FUNCTION(int, dup2, (int oldfd, int newfd)) { 228989aa00SSiva Chandra Reddy #ifdef SYS_dup2 238989aa00SSiva Chandra Reddy // If dup2 syscall is available, we make use of directly. 24b6bc9d72SGuillaume Chatelet int ret = LIBC_NAMESPACE::syscall_impl<int>(SYS_dup2, oldfd, newfd); 258989aa00SSiva Chandra Reddy #elif defined(SYS_dup3) 268989aa00SSiva Chandra Reddy // If dup2 syscall is not available, we try using the dup3 syscall. However, 278989aa00SSiva Chandra Reddy // dup3 fails if oldfd is the same as newfd. So, we handle that case 288989aa00SSiva Chandra Reddy // separately before making the dup3 syscall. 298989aa00SSiva Chandra Reddy if (oldfd == newfd) { 308989aa00SSiva Chandra Reddy // Check if oldfd is actually a valid file descriptor. 31c9783d2bSMikhail R. Gadelha #if SYS_fcntl 32b6bc9d72SGuillaume Chatelet int ret = LIBC_NAMESPACE::syscall_impl<int>(SYS_fcntl, oldfd, F_GETFD); 33c9783d2bSMikhail R. Gadelha #elif defined(SYS_fcntl64) 34c9783d2bSMikhail R. Gadelha // Same as fcntl but can handle large offsets 35b6bc9d72SGuillaume Chatelet int ret = LIBC_NAMESPACE::syscall_impl<int>(SYS_fcntl64, oldfd, F_GETFD); 36c9783d2bSMikhail R. Gadelha #else 37c9783d2bSMikhail R. Gadelha #error "SYS_fcntl and SYS_fcntl64 syscalls not available." 38c9783d2bSMikhail R. Gadelha #endif 398989aa00SSiva Chandra Reddy if (ret >= 0) 408989aa00SSiva Chandra Reddy return oldfd; 41204587a3SSiva Chandra Reddy libc_errno = -ret; 428989aa00SSiva Chandra Reddy return -1; 438989aa00SSiva Chandra Reddy } 44b6bc9d72SGuillaume Chatelet int ret = LIBC_NAMESPACE::syscall_impl<int>(SYS_dup3, oldfd, newfd, 0); 458989aa00SSiva Chandra Reddy #else 465b22df99SMikhail R. Gadelha #error "dup2 and dup3 syscalls not available." 478989aa00SSiva Chandra Reddy #endif 488989aa00SSiva Chandra Reddy if (ret < 0) { 49204587a3SSiva Chandra Reddy libc_errno = -ret; 508989aa00SSiva Chandra Reddy return -1; 518989aa00SSiva Chandra Reddy } 528989aa00SSiva Chandra Reddy return ret; 538989aa00SSiva Chandra Reddy } 548989aa00SSiva Chandra Reddy 555ff3ff33SPetr Hosek } // namespace LIBC_NAMESPACE_DECL 56