xref: /freebsd/contrib/llvm-project/libc/src/__support/OSUtil/linux/fcntl.cpp (revision bb722a7d0f1642bff6487f943ad0427799a6e5bf)
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/errno_macros.h"
12 #include "hdr/fcntl_macros.h"
13 #include "hdr/types/mode_t.h"
14 #include "hdr/types/off_t.h"
15 #include "hdr/types/struct_f_owner_ex.h"
16 #include "hdr/types/struct_flock.h"
17 #include "hdr/types/struct_flock64.h"
18 #include "src/__support/OSUtil/syscall.h" // For internal syscall function.
19 #include "src/__support/common.h"
20 #include "src/__support/error_or.h"
21 #include "src/__support/macros/config.h"
22 
23 #include <sys/syscall.h> // For syscall numbers.
24 
25 namespace LIBC_NAMESPACE_DECL {
26 namespace internal {
27 
fcntl(int fd,int cmd,void * arg)28 ErrorOr<int> fcntl(int fd, int cmd, void *arg) {
29 #if SYS_fcntl
30   constexpr auto FCNTL_SYSCALL_ID = SYS_fcntl;
31 #elif defined(SYS_fcntl64)
32   constexpr auto FCNTL_SYSCALL_ID = SYS_fcntl64;
33 #else
34 #error "fcntl and fcntl64 syscalls not available."
35 #endif
36 
37   switch (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     int ret =
49         LIBC_NAMESPACE::syscall_impl<int>(FCNTL_SYSCALL_ID, fd, cmd, &flk64);
50     if (ret < 0)
51       return Error(-ret);
52     return ret;
53   }
54   case F_OFD_GETLK:
55   case F_OFD_SETLK: {
56     struct flock *flk = reinterpret_cast<struct flock *>(arg);
57     // convert the struct to a flock64
58     struct flock64 flk64;
59     flk64.l_type = flk->l_type;
60     flk64.l_whence = flk->l_whence;
61     flk64.l_start = flk->l_start;
62     flk64.l_len = flk->l_len;
63     flk64.l_pid = flk->l_pid;
64     // create a syscall
65     int ret =
66         LIBC_NAMESPACE::syscall_impl<int>(FCNTL_SYSCALL_ID, fd, cmd, &flk64);
67     // On failure, return
68     if (ret < 0)
69       return Error(-1);
70     // Check for overflow, i.e. the offsets are not the same when cast
71     // to off_t from off64_t.
72     if (static_cast<off_t>(flk64.l_len) != flk64.l_len ||
73         static_cast<off_t>(flk64.l_start) != flk64.l_start)
74       return Error(EOVERFLOW);
75 
76     // Now copy back into flk, in case flk64 got modified
77     flk->l_type = flk64.l_type;
78     flk->l_whence = flk64.l_whence;
79     flk->l_start = static_cast<decltype(flk->l_start)>(flk64.l_start);
80     flk->l_len = static_cast<decltype(flk->l_len)>(flk64.l_len);
81     flk->l_pid = flk64.l_pid;
82     return ret;
83   }
84   case F_GETOWN: {
85     struct f_owner_ex fex;
86     int ret = LIBC_NAMESPACE::syscall_impl<int>(FCNTL_SYSCALL_ID, fd,
87                                                 F_GETOWN_EX, &fex);
88     if (ret < 0)
89       return Error(-ret);
90     return fex.type == F_OWNER_PGRP ? -fex.pid : fex.pid;
91   }
92 #ifdef SYS_fcntl64
93   case F_GETLK: {
94     if constexpr (FCNTL_SYSCALL_ID == SYS_fcntl64)
95       cmd = F_GETLK64;
96     break;
97   }
98   case F_SETLK: {
99     if constexpr (FCNTL_SYSCALL_ID == SYS_fcntl64)
100       cmd = F_SETLK64;
101     break;
102   }
103   case F_SETLKW: {
104     if constexpr (FCNTL_SYSCALL_ID == SYS_fcntl64)
105       cmd = F_SETLKW64;
106     break;
107   }
108 #endif
109   }
110 
111   // default, but may use rewritten cmd from above.
112   int ret = LIBC_NAMESPACE::syscall_impl<int>(FCNTL_SYSCALL_ID, fd, cmd,
113                                               reinterpret_cast<void *>(arg));
114   if (ret < 0)
115     return Error(-ret);
116   return ret;
117 }
118 
open(const char * path,int flags,mode_t mode_flags)119 ErrorOr<int> open(const char *path, int flags, mode_t mode_flags) {
120 #ifdef SYS_open
121   int fd = LIBC_NAMESPACE::syscall_impl<int>(SYS_open, path, flags, mode_flags);
122 #else
123   int fd = LIBC_NAMESPACE::syscall_impl<int>(SYS_openat, AT_FDCWD, path, flags,
124                                              mode_flags);
125 #endif
126   if (fd < 0)
127     return Error(-fd);
128 
129   return fd;
130 }
131 
close(int fd)132 ErrorOr<int> close(int fd) {
133   int ret = LIBC_NAMESPACE::syscall_impl<int>(SYS_close, fd);
134 
135   if (ret < 0)
136     return Error(-ret);
137 
138   return ret;
139 }
140 
141 } // namespace internal
142 } // namespace LIBC_NAMESPACE_DECL
143