1 //===-- Implementation of internal fcntl ----------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "src/__support/OSUtil/fcntl.h" 10 11 #include "hdr/fcntl_macros.h" 12 #include "hdr/types/off_t.h" 13 #include "hdr/types/struct_f_owner_ex.h" 14 #include "hdr/types/struct_flock.h" 15 #include "hdr/types/struct_flock64.h" 16 #include "src/__support/OSUtil/syscall.h" // For internal syscall function. 17 #include "src/__support/common.h" 18 #include "src/__support/macros/config.h" 19 #include "src/errno/libc_errno.h" 20 21 #include <stdarg.h> 22 #include <sys/syscall.h> // For syscall numbers. 23 24 namespace LIBC_NAMESPACE_DECL { 25 namespace internal { 26 27 int fcntl(int fd, int cmd, void *arg) { 28 #if SYS_fcntl 29 constexpr auto FCNTL_SYSCALL_ID = SYS_fcntl; 30 #elif defined(SYS_fcntl64) 31 constexpr auto FCNTL_SYSCALL_ID = SYS_fcntl64; 32 #else 33 #error "fcntl and fcntl64 syscalls not available." 34 #endif 35 36 int new_cmd = cmd; 37 switch (new_cmd) { 38 case F_OFD_SETLKW: { 39 struct flock *flk = reinterpret_cast<struct flock *>(arg); 40 // convert the struct to a flock64 41 struct flock64 flk64; 42 flk64.l_type = flk->l_type; 43 flk64.l_whence = flk->l_whence; 44 flk64.l_start = flk->l_start; 45 flk64.l_len = flk->l_len; 46 flk64.l_pid = flk->l_pid; 47 // create a syscall 48 return LIBC_NAMESPACE::syscall_impl<int>(FCNTL_SYSCALL_ID, fd, new_cmd, 49 &flk64); 50 } 51 case F_OFD_GETLK: 52 case F_OFD_SETLK: { 53 struct flock *flk = reinterpret_cast<struct flock *>(arg); 54 // convert the struct to a flock64 55 struct flock64 flk64; 56 flk64.l_type = flk->l_type; 57 flk64.l_whence = flk->l_whence; 58 flk64.l_start = flk->l_start; 59 flk64.l_len = flk->l_len; 60 flk64.l_pid = flk->l_pid; 61 // create a syscall 62 int retVal = LIBC_NAMESPACE::syscall_impl<int>(FCNTL_SYSCALL_ID, fd, 63 new_cmd, &flk64); 64 // On failure, return 65 if (retVal == -1) 66 return -1; 67 // Check for overflow, i.e. the offsets are not the same when cast 68 // to off_t from off64_t. 69 if (static_cast<off_t>(flk64.l_len) != flk64.l_len || 70 static_cast<off_t>(flk64.l_start) != flk64.l_start) { 71 libc_errno = EOVERFLOW; 72 return -1; 73 } 74 // Now copy back into flk, in case flk64 got modified 75 flk->l_type = flk64.l_type; 76 flk->l_whence = flk64.l_whence; 77 flk->l_start = static_cast<decltype(flk->l_start)>(flk64.l_start); 78 flk->l_len = static_cast<decltype(flk->l_len)>(flk64.l_len); 79 flk->l_pid = flk64.l_pid; 80 return retVal; 81 } 82 case F_GETOWN: { 83 struct f_owner_ex fex; 84 int ret = LIBC_NAMESPACE::syscall_impl<int>(FCNTL_SYSCALL_ID, fd, 85 F_GETOWN_EX, &fex); 86 if (ret >= 0) 87 return fex.type == F_OWNER_PGRP ? -fex.pid : fex.pid; 88 libc_errno = -ret; 89 return -1; 90 } 91 #ifdef SYS_fcntl64 92 case F_GETLK: { 93 if constexpr (FCNTL_SYSCALL_ID == SYS_fcntl64) 94 new_cmd = F_GETLK64; 95 break; 96 } 97 case F_SETLK: { 98 if constexpr (FCNTL_SYSCALL_ID == SYS_fcntl64) 99 new_cmd = F_SETLK64; 100 break; 101 } 102 case F_SETLKW: { 103 if constexpr (FCNTL_SYSCALL_ID == SYS_fcntl64) 104 new_cmd = F_SETLKW64; 105 break; 106 } 107 #endif 108 } 109 int retVal = LIBC_NAMESPACE::syscall_impl<int>(FCNTL_SYSCALL_ID, fd, new_cmd, 110 reinterpret_cast<void *>(arg)); 111 if (retVal >= 0) { 112 return retVal; 113 } 114 libc_errno = -retVal; 115 return -1; 116 } 117 118 } // namespace internal 119 } // namespace LIBC_NAMESPACE_DECL 120