xref: /llvm-project/libc/src/__support/OSUtil/linux/fcntl.cpp (revision c80b799e90c6279ced025c44b9177c6e5f0f2ada)
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