10b24b470SXu Zhang //===-- Implementation of internal fcntl ----------------------------------===// 20b24b470SXu Zhang // 30b24b470SXu Zhang // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b24b470SXu Zhang // See https://llvm.org/LICENSE.txt for license information. 50b24b470SXu Zhang // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b24b470SXu Zhang // 70b24b470SXu Zhang //===----------------------------------------------------------------------===// 80b24b470SXu Zhang 90b24b470SXu Zhang #include "src/__support/OSUtil/fcntl.h" 100b24b470SXu Zhang 110b24b470SXu Zhang #include "hdr/fcntl_macros.h" 125aed6d67SMichael Jones #include "hdr/types/off_t.h" 130b24b470SXu Zhang #include "hdr/types/struct_f_owner_ex.h" 140b24b470SXu Zhang #include "hdr/types/struct_flock.h" 150b24b470SXu Zhang #include "hdr/types/struct_flock64.h" 160b24b470SXu Zhang #include "src/__support/OSUtil/syscall.h" // For internal syscall function. 170b24b470SXu Zhang #include "src/__support/common.h" 185ff3ff33SPetr Hosek #include "src/__support/macros/config.h" 190b24b470SXu Zhang #include "src/errno/libc_errno.h" 200b24b470SXu Zhang 210b24b470SXu Zhang #include <stdarg.h> 220b24b470SXu Zhang #include <sys/syscall.h> // For syscall numbers. 230b24b470SXu Zhang 245ff3ff33SPetr Hosek namespace LIBC_NAMESPACE_DECL { 255ff3ff33SPetr Hosek namespace internal { 260b24b470SXu Zhang 270b24b470SXu Zhang int fcntl(int fd, int cmd, void *arg) { 284f77677cSMikhail R. Gadelha #if SYS_fcntl 294f77677cSMikhail R. Gadelha constexpr auto FCNTL_SYSCALL_ID = SYS_fcntl; 304f77677cSMikhail R. Gadelha #elif defined(SYS_fcntl64) 314f77677cSMikhail R. Gadelha constexpr auto FCNTL_SYSCALL_ID = SYS_fcntl64; 324f77677cSMikhail R. Gadelha #else 334f77677cSMikhail R. Gadelha #error "fcntl and fcntl64 syscalls not available." 344f77677cSMikhail R. Gadelha #endif 354f77677cSMikhail R. Gadelha 36*c80b799eSMikhail R. Gadelha int new_cmd = cmd; 37*c80b799eSMikhail R. Gadelha switch (new_cmd) { 380b24b470SXu Zhang case F_OFD_SETLKW: { 390b24b470SXu Zhang struct flock *flk = reinterpret_cast<struct flock *>(arg); 400b24b470SXu Zhang // convert the struct to a flock64 410b24b470SXu Zhang struct flock64 flk64; 420b24b470SXu Zhang flk64.l_type = flk->l_type; 430b24b470SXu Zhang flk64.l_whence = flk->l_whence; 440b24b470SXu Zhang flk64.l_start = flk->l_start; 450b24b470SXu Zhang flk64.l_len = flk->l_len; 460b24b470SXu Zhang flk64.l_pid = flk->l_pid; 470b24b470SXu Zhang // create a syscall 48*c80b799eSMikhail R. Gadelha return LIBC_NAMESPACE::syscall_impl<int>(FCNTL_SYSCALL_ID, fd, new_cmd, 49*c80b799eSMikhail R. Gadelha &flk64); 500b24b470SXu Zhang } 510b24b470SXu Zhang case F_OFD_GETLK: 520b24b470SXu Zhang case F_OFD_SETLK: { 530b24b470SXu Zhang struct flock *flk = reinterpret_cast<struct flock *>(arg); 540b24b470SXu Zhang // convert the struct to a flock64 550b24b470SXu Zhang struct flock64 flk64; 560b24b470SXu Zhang flk64.l_type = flk->l_type; 570b24b470SXu Zhang flk64.l_whence = flk->l_whence; 580b24b470SXu Zhang flk64.l_start = flk->l_start; 590b24b470SXu Zhang flk64.l_len = flk->l_len; 600b24b470SXu Zhang flk64.l_pid = flk->l_pid; 610b24b470SXu Zhang // create a syscall 62*c80b799eSMikhail R. Gadelha int retVal = LIBC_NAMESPACE::syscall_impl<int>(FCNTL_SYSCALL_ID, fd, 63*c80b799eSMikhail R. Gadelha new_cmd, &flk64); 640b24b470SXu Zhang // On failure, return 650b24b470SXu Zhang if (retVal == -1) 660b24b470SXu Zhang return -1; 670b24b470SXu Zhang // Check for overflow, i.e. the offsets are not the same when cast 680b24b470SXu Zhang // to off_t from off64_t. 690b24b470SXu Zhang if (static_cast<off_t>(flk64.l_len) != flk64.l_len || 700b24b470SXu Zhang static_cast<off_t>(flk64.l_start) != flk64.l_start) { 710b24b470SXu Zhang libc_errno = EOVERFLOW; 720b24b470SXu Zhang return -1; 730b24b470SXu Zhang } 740b24b470SXu Zhang // Now copy back into flk, in case flk64 got modified 750b24b470SXu Zhang flk->l_type = flk64.l_type; 760b24b470SXu Zhang flk->l_whence = flk64.l_whence; 77fad2ad70SNick Desaulniers (paternity leave) flk->l_start = static_cast<decltype(flk->l_start)>(flk64.l_start); 78fad2ad70SNick Desaulniers (paternity leave) flk->l_len = static_cast<decltype(flk->l_len)>(flk64.l_len); 790b24b470SXu Zhang flk->l_pid = flk64.l_pid; 800b24b470SXu Zhang return retVal; 810b24b470SXu Zhang } 820b24b470SXu Zhang case F_GETOWN: { 830b24b470SXu Zhang struct f_owner_ex fex; 844f77677cSMikhail R. Gadelha int ret = LIBC_NAMESPACE::syscall_impl<int>(FCNTL_SYSCALL_ID, fd, 854f77677cSMikhail R. Gadelha F_GETOWN_EX, &fex); 867c4fc9ccSXu Zhang if (ret >= 0) 870b24b470SXu Zhang return fex.type == F_OWNER_PGRP ? -fex.pid : fex.pid; 887c4fc9ccSXu Zhang libc_errno = -ret; 890b24b470SXu Zhang return -1; 900b24b470SXu Zhang } 91cda5b2b4SMikhail R. Gadelha #ifdef SYS_fcntl64 92cda5b2b4SMikhail R. Gadelha case F_GETLK: { 93cda5b2b4SMikhail R. Gadelha if constexpr (FCNTL_SYSCALL_ID == SYS_fcntl64) 94*c80b799eSMikhail R. Gadelha new_cmd = F_GETLK64; 95cda5b2b4SMikhail R. Gadelha break; 96cda5b2b4SMikhail R. Gadelha } 97cda5b2b4SMikhail R. Gadelha case F_SETLK: { 98cda5b2b4SMikhail R. Gadelha if constexpr (FCNTL_SYSCALL_ID == SYS_fcntl64) 99*c80b799eSMikhail R. Gadelha new_cmd = F_SETLK64; 100cda5b2b4SMikhail R. Gadelha break; 101cda5b2b4SMikhail R. Gadelha } 102cda5b2b4SMikhail R. Gadelha case F_SETLKW: { 103cda5b2b4SMikhail R. Gadelha if constexpr (FCNTL_SYSCALL_ID == SYS_fcntl64) 104*c80b799eSMikhail R. Gadelha new_cmd = F_SETLKW64; 105cda5b2b4SMikhail R. Gadelha break; 106cda5b2b4SMikhail R. Gadelha } 107cda5b2b4SMikhail R. Gadelha #endif 108cda5b2b4SMikhail R. Gadelha } 109*c80b799eSMikhail R. Gadelha int retVal = LIBC_NAMESPACE::syscall_impl<int>(FCNTL_SYSCALL_ID, fd, new_cmd, 110cda5b2b4SMikhail R. Gadelha reinterpret_cast<void *>(arg)); 1110b24b470SXu Zhang if (retVal >= 0) { 1120b24b470SXu Zhang return retVal; 1130b24b470SXu Zhang } 1140b24b470SXu Zhang libc_errno = -retVal; 1150b24b470SXu Zhang return -1; 1160b24b470SXu Zhang } 1170b24b470SXu Zhang 1185ff3ff33SPetr Hosek } // namespace internal 1195ff3ff33SPetr Hosek } // namespace LIBC_NAMESPACE_DECL 120