xref: /aosp_15_r20/external/llvm-libc/src/__support/OSUtil/linux/fcntl.cpp (revision 71db0c75aadcf003ffe3238005f61d7618a3fead)
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 
fcntl(int fd,int cmd,void * arg)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