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
25namespace LIBC_NAMESPACE_DECL {
26namespace internal {
27
28ErrorOr<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
119ErrorOr<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
132ErrorOr<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

source code of libc/src/__support/OSUtil/linux/fcntl.cpp