1 /*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 // We need 32-bit functions here. Suppress unconditional use of 64-bit offsets.
18 // Functions with 64-bit offsets are still available when used with "64" suffix.
19 //
20 // Note: this is actually only needed for host build since Android build system
21 // insists on defining _FILE_OFFSET_BITS=64 for host-host binaries.
22 //
23 // _FILE_OFFSET_BITS is NOT defined when we are building target-host binaries.
24 #ifdef _FILE_OFFSET_BITS
25 #undef _FILE_OFFSET_BITS
26 #endif
27
28 #include "berberis/kernel_api/fcntl_emulation.h"
29
30 #include <fcntl.h>
31 #include <sys/file.h>
32
33 #include <cerrno>
34
35 #include "berberis/base/checks.h"
36 #include "berberis/base/tracing.h"
37 #include "berberis/kernel_api/open_emulation.h"
38
39 static_assert(F_DUPFD == 0);
40 static_assert(F_GETFD == 1);
41 static_assert(F_SETFD == 2);
42 static_assert(F_GETFL == 3);
43 static_assert(F_SETFL == 4);
44 static_assert(F_SETOWN == 8);
45 static_assert(F_GETOWN == 9);
46 static_assert(F_SETSIG == 10);
47 static_assert(F_GETSIG == 11);
48 static_assert(F_SETOWN_EX == 15);
49 static_assert(F_GETOWN_EX == 16);
50 static_assert(F_OWNER_TID == 0);
51 static_assert(F_OWNER_PID == 1);
52 static_assert(F_OWNER_PGRP == 2);
53 static_assert(F_RDLCK == 0);
54 static_assert(F_WRLCK == 1);
55 static_assert(F_UNLCK == 2);
56 #ifdef F_EXLCK
57 static_assert(F_EXLCK == 4);
58 #endif
59 #ifdef F_SHLCK
60 static_assert(F_SHLCK == 8);
61 #endif
62 static_assert(F_SETLEASE == 1024);
63 static_assert(F_GETLEASE == 1025);
64 static_assert(F_NOTIFY == 1026);
65
66 #if !defined(ANDROID_HOST_MUSL)
67 static_assert(F_GETLK == 5);
68 static_assert(F_SETLK == 6);
69 static_assert(F_SETLKW == 7);
70 #endif
71
72 #define GUEST_F_GETLK 5
73 #define GUEST_F_SETLK 6
74 #define GUEST_F_SETLKW 7
75
76 #if defined(ANDROID_HOST_MUSL)
77 // Musl only has a 64-bit flock that it uses for flock and flock64.
78
79 struct Guest_flock {
80 int16_t l_type;
81 int16_t l_whence;
82 int32_t l_start;
83 int32_t l_len;
84 int32_t l_pid;
85 };
86
ConvertGuestFlockToHostFlock64(const Guest_flock * guest,struct flock64 * host)87 const struct flock64* ConvertGuestFlockToHostFlock64(const Guest_flock* guest,
88 struct flock64* host) {
89 if (!guest) {
90 return nullptr;
91 }
92 *host = {guest->l_type, guest->l_whence, guest->l_start, guest->l_len, guest->l_pid};
93 return host;
94 }
95
ConvertHostFlock64ToGuestFlock(const struct flock64 * host,Guest_flock * guest)96 void ConvertHostFlock64ToGuestFlock(const struct flock64* host, Guest_flock* guest) {
97 CHECK_NE(guest, nullptr);
98 CHECK_LE(host->l_start, INT32_MAX);
99 CHECK_GE(host->l_start, INT32_MIN);
100 CHECK_LE(host->l_len, INT32_MAX);
101 CHECK_GE(host->l_len, INT32_MIN);
102 *guest = {host->l_type,
103 host->l_whence,
104 static_cast<int32_t>(host->l_start),
105 static_cast<int32_t>(host->l_len),
106 host->l_pid};
107 }
108 #endif
109
110 namespace berberis {
111
GuestFcntl(int fd,int cmd,long arg_3)112 int GuestFcntl(int fd, int cmd, long arg_3) {
113 // TODO(b/346604197): Enable on arm64 once guest_os_primitives is ported.
114 #ifdef __aarch64__
115 UNUSED(fd, cmd, arg_3);
116 TRACE("unimplemented GuestFcntl");
117 errno = ENOSYS;
118 return -1;
119 #else
120 auto [processed, result] = GuestFcntlArch(fd, cmd, arg_3);
121 if (processed) {
122 return result;
123 }
124
125 switch (cmd) {
126 case F_GETFD:
127 case F_GETOWN:
128 case F_GETSIG:
129 case F_GETLEASE:
130 return fcntl(fd, cmd);
131 case F_GETFL: {
132 auto result = fcntl(fd, cmd);
133 if (result < 0) {
134 return result;
135 }
136 return ToGuestOpenFlags(result);
137 }
138 case F_DUPFD:
139 case F_DUPFD_CLOEXEC:
140 case F_SETFD:
141 case F_SETOWN:
142 case F_SETSIG:
143 case F_SETLEASE:
144 case F_NOTIFY:
145 case F_GETOWN_EX:
146 case F_SETOWN_EX:
147 #if defined(F_ADD_SEALS)
148 case F_ADD_SEALS:
149 #endif
150 #if defined(F_GET_SEALS)
151 case F_GET_SEALS:
152 #endif
153 case GUEST_F_SETLK:
154 case GUEST_F_SETLKW:
155 case GUEST_F_GETLK:
156 #if defined(ANDROID_HOST_MUSL)
157 {
158 // Musl only has a 64-bit flock for both flock and flock64, translate flock calls to flock64.
159 Guest_flock* guest_flock = reinterpret_cast<Guest_flock*>(arg_3);
160 struct flock64 host_flock64;
161 // In case of GETLK input flock describes region
162 // to check, thus conversion is also required.
163 auto result = fcntl(fd,
164 cmd + F_SETLK - GUEST_F_SETLK,
165 ConvertGuestFlockToHostFlock64(guest_flock, &host_flock64));
166 if (result == 0 && cmd == GUEST_F_GETLK) {
167 // Output contains the result of lock check.
168 ConvertHostFlock64ToGuestFlock(&host_flock64, guest_flock);
169 }
170 return result;
171 }
172 #else
173 // struct flock compatibility is checked above.
174 return fcntl(fd, cmd, arg_3);
175 #endif
176 case F_SETFL:
177 return fcntl(fd, cmd, ToHostOpenFlags(arg_3));
178 default:
179 TRACE("Unknown fcntl command: %d", cmd);
180 errno = ENOSYS;
181 return -1;
182 }
183 #endif
184 }
185
186 } // namespace berberis
187