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/kernel_api/open_emulation.h"
37 #include "berberis/kernel_api/tracing.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 auto [processed, result] = GuestFcntlArch(fd, cmd, arg_3);
114 if (processed) {
115 return result;
116 }
117
118 switch (cmd) {
119 case F_GETFD:
120 case F_GETOWN:
121 case F_GETSIG:
122 case F_GETLEASE:
123 return fcntl(fd, cmd);
124 case F_GETFL: {
125 auto result = fcntl(fd, cmd);
126 if (result < 0) {
127 return result;
128 }
129 return ToGuestOpenFlags(result);
130 }
131 case F_DUPFD:
132 case F_DUPFD_CLOEXEC:
133 case F_SETFD:
134 case F_SETOWN:
135 case F_SETSIG:
136 case F_SETLEASE:
137 case F_NOTIFY:
138 case F_GETOWN_EX:
139 case F_SETOWN_EX:
140 #if defined(F_ADD_SEALS)
141 case F_ADD_SEALS:
142 #endif
143 #if defined(F_GET_SEALS)
144 case F_GET_SEALS:
145 #endif
146 case GUEST_F_SETLK:
147 case GUEST_F_SETLKW:
148 case GUEST_F_GETLK:
149 #if defined(ANDROID_HOST_MUSL)
150 {
151 // Musl only has a 64-bit flock for both flock and flock64, translate flock calls to flock64.
152 Guest_flock* guest_flock = reinterpret_cast<Guest_flock*>(arg_3);
153 struct flock64 host_flock64;
154 // In case of GETLK input flock describes region
155 // to check, thus conversion is also required.
156 auto result = fcntl(fd,
157 cmd + F_SETLK - GUEST_F_SETLK,
158 ConvertGuestFlockToHostFlock64(guest_flock, &host_flock64));
159 if (result == 0 && cmd == GUEST_F_GETLK) {
160 // Output contains the result of lock check.
161 ConvertHostFlock64ToGuestFlock(&host_flock64, guest_flock);
162 }
163 return result;
164 }
165 #else
166 // struct flock compatibility is checked above.
167 return fcntl(fd, cmd, arg_3);
168 #endif
169 case F_SETFL:
170 return fcntl(fd, cmd, ToHostOpenFlags(arg_3));
171 default:
172 KAPI_TRACE("Unknown fcntl command: %d", cmd);
173 errno = ENOSYS;
174 return -1;
175 }
176 }
177
178 } // namespace berberis
179