• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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