1 /*
2 * Copyright 2012, 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 #include <portability.h>
18 #include <fcntl.h>
19 #include <errno.h>
20 #include <stdarg.h>
21 #include <stdlib.h>
22 #include <stdio.h>
23 #include <errno.h>
24 #include <errno_portable.h>
25 #include <portability.h>
26 #include <fcntl_portable.h>
27 #include <filefd_portable.h>
28
29 #include <portability.h>
30
31 #if F_GETLK_PORTABLE==F_GETLK
32 #error Bad build environment
33 #endif
34
35 #define PORTABLE_TAG "fcntl_portable"
36 #include <log_portable.h>
37
map_portable_cmd_to_name(int cmd)38 static char *map_portable_cmd_to_name(int cmd)
39 {
40 char *name;
41
42 switch(cmd) {
43 case F_DUPFD_PORTABLE: name = "F_DUPFD_PORTABLE"; break; /* 0 */
44 case F_GETFD_PORTABLE: name = "F_GETFD_PORTABLE"; break; /* 1 */
45 case F_SETFD_PORTABLE: name = "F_SETFD_PORTABLE"; break; /* 2 */
46 case F_GETFL_PORTABLE: name = "F_GETFL_PORTABLE"; break; /* 3 */
47 case F_SETFL_PORTABLE: name = "F_SETFL_PORTABLE"; break; /* 4 */
48 case F_GETLK_PORTABLE: name = "F_GETLK_PORTABLE"; break; /* 5 */
49 case F_SETLK_PORTABLE: name = "F_SETLK_PORTABLE"; break; /* 6 */
50 case F_SETLKW_PORTABLE: name = "F_SETLKW_PORTABLE"; break; /* 7 */
51 case F_SETOWN_PORTABLE: name = "F_SETOWN_PORTABLE"; break; /* 8 */
52 case F_GETOWN_PORTABLE: name = "F_GETOWN_PORTABLE"; break; /* 9 */
53 case F_SETSIG_PORTABLE: name = "F_SETSIG_PORTABLE"; break; /* 10 */
54 case F_GETSIG_PORTABLE: name = "F_GETSIG_PORTABLE"; break; /* 11 */
55 case F_GETLK64_PORTABLE: name = "F_GETLK64_PORTABLE"; break; /* 12 */
56 case F_SETLK64_PORTABLE: name = "F_SETLK64_PORTABLE"; break; /* 13 */
57 case F_SETLKW64_PORTABLE: name = "F_SETLKW64_PORTABLE"; break; /* 14 */
58 case F_SETLEASE_PORTABLE: name = "F_SETLEASE_PORTABLE"; break; /* 1024 */
59 case F_GETLEASE_PORTABLE: name = "F_GETLEASE_PORTABLE"; break; /* 1025 */
60 case F_NOTIFY_PORTABLE: name = "F_NOTIFY_PORTABLE"; break; /* 1026 */
61 case F_CANCELLK_PORTABLE: name = "F_CANCELLK_PORTABLE"; break; /* 1029 */
62 case F_DUPFD_CLOEXEC_PORTABLE: name = "F_DUPFD_CLOEXEC_PORTABLE"; break; /* 1030 */
63 default: name = "<UNKNOWN>"; break;
64 }
65 return name;
66 }
67
68
69 /*
70 * Maps a fcntl portable cmd to a native command.
71 */
fcntl_cmd_pton(int portable_cmd)72 static int fcntl_cmd_pton(int portable_cmd)
73 {
74 int native_cmd;
75 char *error_msg = NULL;
76
77 switch(portable_cmd) {
78 case F_DUPFD_PORTABLE: /* 0 --> 0 */
79 native_cmd = F_DUPFD;
80 break;
81
82 case F_GETFD_PORTABLE: /* 1 --> 1 */
83 native_cmd = F_GETFD;
84 break;
85
86 case F_SETFD_PORTABLE: /* 2 --> 2 */
87 native_cmd = F_SETFD;
88 break;
89
90 case F_GETFL_PORTABLE: /* 3 --> 3 */
91 native_cmd = F_GETFL;
92 break;
93
94 case F_SETFL_PORTABLE: /* 4 --> 4 */
95 native_cmd = F_SETFL;
96 break;
97
98 case F_GETLK_PORTABLE: /* 5 --> 14 */
99 native_cmd = F_GETLK;
100 break;
101
102 case F_SETLK_PORTABLE: /* 6 --> 6 */
103 native_cmd = F_SETLK;
104 break;
105
106 case F_SETLKW_PORTABLE: /* 7 --> 7 */
107 native_cmd = F_SETLKW;
108 break;
109
110 case F_SETOWN_PORTABLE: /* 8 --> 24 */
111 native_cmd = F_SETOWN;
112 break;
113
114 case F_GETOWN_PORTABLE: /* 9 --> 23 */
115 native_cmd = F_GETOWN;
116 break;
117
118 case F_SETSIG_PORTABLE: /* 10 --> 10 */
119 native_cmd = F_SETSIG;
120 break;
121
122 case F_GETSIG_PORTABLE: /* 11 --> 11 */
123 native_cmd = F_GETSIG;
124 break;
125
126 case F_GETLK64_PORTABLE: /* 12 --> 33 */
127 native_cmd = F_GETLK64;
128 break;
129
130 case F_SETLK64_PORTABLE: /* 13 --> 34 */
131 native_cmd = F_SETLK64;
132 break;
133
134 case F_SETLKW64_PORTABLE: /* 14 --> 35 */
135 native_cmd = F_SETLKW64;
136 break;
137
138 case F_SETLEASE_PORTABLE: /* 1024 --> 1024 */
139 native_cmd = F_SETLEASE;
140 break;
141
142 case F_GETLEASE_PORTABLE: /* 1025 --> 1025 */
143 native_cmd = F_GETLEASE;
144 break;
145
146 case F_NOTIFY_PORTABLE: /* 1026 --> 1026 */
147 native_cmd = F_NOTIFY;
148 break;
149
150 case F_CANCELLK_PORTABLE: /* 1029 --> void */
151 error_msg = "Case F_CANCELLK_PORTABLE: Not supported by MIPS. ";
152 native_cmd = portable_cmd;
153 break;
154
155 case F_DUPFD_CLOEXEC_PORTABLE: /* 1030 --> VOID; Not currently used by Bionic */
156 error_msg = "Case F_DUPFD_CLOEXEC_PORTABLE: Not supported by MIPS. ";
157 native_cmd = portable_cmd;
158 break;
159
160 default:
161 error_msg = "Case Default: Command Not Supported. ";
162 native_cmd = portable_cmd;
163 break;
164 }
165
166 done:
167 if (error_msg != NULL) {
168 ALOGE("%s(portable_cmd:%d:0x%x): %sreturn(native_cmd:%d:0x%x);", __func__,
169 portable_cmd, portable_cmd, error_msg, native_cmd, native_cmd);
170 } else {
171 ALOGV("%s(portable_cmd:%d:0x%x): return(native_cmd:%d:0x%x);", __func__,
172 portable_cmd, portable_cmd, native_cmd, native_cmd);
173 }
174 return native_cmd;
175 }
176
177
fcntl_flags_pton(int flags)178 static int fcntl_flags_pton(int flags)
179 {
180 int mipsflags = flags & O_ACCMODE_PORTABLE;
181
182 if (flags & O_CREAT_PORTABLE)
183 mipsflags |= O_CREAT;
184 if (flags & O_EXCL_PORTABLE)
185 mipsflags |= O_EXCL;
186 if (flags & O_NOCTTY_PORTABLE)
187 mipsflags |= O_NOCTTY;
188 if (flags & O_TRUNC_PORTABLE)
189 mipsflags |= O_TRUNC;
190 if (flags & O_APPEND_PORTABLE)
191 mipsflags |= O_APPEND;
192 if (flags & O_NONBLOCK_PORTABLE)
193 mipsflags |= O_NONBLOCK;
194 if (flags & O_SYNC_PORTABLE)
195 mipsflags |= O_SYNC;
196 if (flags & FASYNC_PORTABLE)
197 mipsflags |= FASYNC;
198 if (flags & O_DIRECT_PORTABLE)
199 mipsflags |= O_DIRECT;
200 if (flags & O_LARGEFILE_PORTABLE)
201 mipsflags |= O_LARGEFILE;
202 if (flags & O_DIRECTORY_PORTABLE)
203 mipsflags |= O_DIRECTORY;
204 if (flags & O_NOFOLLOW_PORTABLE)
205 mipsflags |= O_NOFOLLOW;
206 if (flags & O_NOATIME_PORTABLE)
207 mipsflags |= O_NOATIME;
208 if (flags & O_NDELAY_PORTABLE)
209 mipsflags |= O_NDELAY;
210
211 ALOGV("%s(flags:0x%x): return(mipsflags:0x%x);", __func__,
212 flags, mipsflags);
213
214 return mipsflags;
215 }
216
fcntl_flags_ntop(int flags)217 static int fcntl_flags_ntop(int flags)
218 {
219 int portableflags = flags & O_ACCMODE_PORTABLE;
220
221 if (flags & O_CREAT)
222 portableflags |= O_CREAT_PORTABLE;
223 if (flags & O_EXCL)
224 portableflags |= O_EXCL_PORTABLE;
225 if (flags & O_NOCTTY)
226 portableflags |= O_NOCTTY_PORTABLE;
227 if (flags & O_TRUNC)
228 portableflags |= O_TRUNC_PORTABLE;
229 if (flags & O_APPEND)
230 portableflags |= O_APPEND_PORTABLE;
231 if (flags & O_NONBLOCK)
232 portableflags |= O_NONBLOCK_PORTABLE;
233 if (flags & O_SYNC)
234 portableflags |= O_SYNC_PORTABLE;
235 if (flags & FASYNC)
236 portableflags |= FASYNC_PORTABLE;
237 if (flags & O_DIRECT)
238 portableflags |= O_DIRECT_PORTABLE;
239 if (flags & O_LARGEFILE)
240 portableflags |= O_LARGEFILE_PORTABLE;
241 if (flags & O_DIRECTORY)
242 portableflags |= O_DIRECTORY_PORTABLE;
243 if (flags & O_NOFOLLOW)
244 portableflags |= O_NOFOLLOW_PORTABLE;
245 if (flags & O_NOATIME)
246 portableflags |= O_NOATIME_PORTABLE;
247 if (flags & O_NDELAY)
248 portableflags |= O_NDELAY_PORTABLE;
249
250 ALOGV("%s(flags:0x%x): return(portableflags:0x%x);", __func__,
251 flags, portableflags);
252
253 return portableflags;
254 }
255
256 extern int __fcntl64(int, int, void *);
257
258 /*
259 * For 32 bit flocks we are converting a portable/ARM struct flock to a MIPS struct flock:
260 *
261 * MIPS: ARM:
262 * struct flock { struct flock_portable {
263 * short l_type; short l_type;
264 *
265 * short l_whence; short l_whence;
266 * off_t l_start; loff_t l_start;
267 * off_t l_len; loff_t l_len;
268 * long l_sysid;
269 *
270 * __kernel_pid_t l_pid; pid_t l_pid;
271 * long pad[4];
272 * }; }
273 *
274 * which have identically sized structure members:
275 *
276 * For a 64 bit flocks we only have to deal with
277 * a four byte padding in the ARM/Portable structure:
278 *
279 * MIPS: ARM:
280 * struct flock64 { struct flock64_portable {
281 * short l_type; short l_type;
282 * short l_whence; short l_whence;
283 * unsigned char __padding[4]; <---- NOTE
284 * loff_t l_start; loff_t l_start;
285 * loff_t l_len; loff_t l_len;
286 * pid_t l_pid; pid_t l_pid;
287 * } }
288 */
WRAP(fcntl)289 int WRAP(fcntl)(int fd, int portable_cmd, ...)
290 {
291 int flags;
292 va_list ap;
293 void *arg;
294 int mips_cmd;
295 int result = 0;
296 struct flock flock; /* Native MIPS structure */
297 struct flock64 flock64; /* Native MIPS structure */
298 char *portable_cmd_name = map_portable_cmd_to_name(portable_cmd);
299 struct flock_portable *flock_portable = NULL;
300 struct flock64_portable *flock64_portable = NULL;
301
302 ALOGV(" ");
303 ALOGV("%s(fd:%d, portable_cmd:%d:'%s', ...) {", __func__,
304 fd, portable_cmd,
305 portable_cmd_name);
306
307
308 va_start(ap, portable_cmd);
309 arg = va_arg(ap, void *);
310 va_end(ap);
311
312 mips_cmd = fcntl_cmd_pton(portable_cmd);
313 switch(mips_cmd) {
314 case F_GETLK:
315 case F_SETLK:
316 case F_SETLKW:
317 flock_portable = (struct flock_portable *) arg;
318
319 if (invalid_pointer(flock_portable)) {
320 ALOGE("%s: flock_portable:%p == {NULL||-1}", __func__, flock_portable);
321 *REAL(__errno)() = EFAULT;
322 result = -1;
323 goto done;
324 }
325
326 /*
327 * Lock type and Whence are the same for all ARCHs
328 * (F_RDLCK:0, F_WRLCK:1, F_UNLCK:2)
329 * (SEEK_SET:0, SEEK_CUR:1, SEEK_END:2)
330 */
331 flock.l_type = flock_portable->l_type;
332 flock.l_whence = flock_portable->l_whence;
333 flock.l_start = (off_t) flock_portable->l_start;
334 flock.l_len = (off_t) flock_portable->l_len;
335 flock.l_sysid = 0L;
336 flock.l_pid = flock_portable->l_pid; /* Perhaps 0 would be better */
337
338 result = __fcntl64(fd, mips_cmd, (void *) &flock);
339
340 flock_portable->l_type = flock.l_type;
341 flock_portable->l_whence = flock.l_whence;
342 flock_portable->l_start = flock.l_start;
343 flock_portable->l_len = flock.l_len;
344 flock_portable->l_pid = flock.l_pid;
345 break;
346
347 case F_GETLK64:
348 case F_SETLK64:
349 case F_SETLKW64:
350 flock64_portable = (struct flock64_portable *) arg;
351
352 if (invalid_pointer(flock_portable)) {
353 ALOGE("%s: flock_portable:%p == {NULL||-1}", __func__, flock_portable);
354 *REAL(__errno)() = EFAULT;
355 result = -1;
356 goto done;
357 }
358
359 /*
360 * Lock type and Whence are the same for all ARCHs
361 * (F_RDLCK:0, F_WRLCK:1, F_UNLCK:2)
362 * (SEEK_SET:0, SEEK_CUR:1, SEEK_END:2)
363 */
364 flock64.l_type = flock64_portable->l_type;
365 flock64.l_whence = flock64_portable->l_whence;
366 flock64.l_start = (off_t) flock64_portable->l_start;
367 flock64.l_len = (off_t) flock64_portable->l_len;
368 flock64.l_pid = flock64_portable->l_pid; /* Perhaps 0 would be better */
369
370 result = __fcntl64(fd, mips_cmd, (void *) &flock);
371
372 flock64_portable->l_type = flock64.l_type;
373 flock64_portable->l_whence = flock64.l_whence;
374 flock64_portable->l_start = flock64.l_start;
375 flock64_portable->l_len = flock64.l_len;
376 flock64_portable->l_pid = flock64.l_pid;
377 break;
378
379 case F_SETFL:
380 flags = fcntl_flags_pton((int)arg);
381 result = __fcntl64(fd, mips_cmd, (void *)flags);
382 break;
383
384 case F_GETFL:
385 result = __fcntl64(fd, mips_cmd, arg);
386 if (result != -1)
387 result = fcntl_flags_ntop(result);
388 break;
389
390 case F_DUPFD:
391 case F_GETFD:
392 case F_SETFD:
393 case F_SETOWN:
394 case F_GETOWN:
395 case F_SETSIG:
396 case F_GETSIG:
397 case F_SETLEASE:
398 case F_GETLEASE:
399 case F_NOTIFY:
400 ALOGV("%s: Calling __fcntl64(fd:%d, mips_cmd:0x%x, arg:%p);", __func__,
401 fd, mips_cmd, arg);
402
403 result = __fcntl64(fd, mips_cmd, arg);
404
405 if (result < 0) {
406 ALOGV("%s: result = %d = __fcntl64(fd:%d, mips_cmd:0x%x, arg:%p);", __func__,
407 result, fd, mips_cmd, arg);
408 } else {
409 if (mips_cmd == F_SETFD) {
410 /*
411 * File descriptor flag bits got set or cleared.
412 */
413 flags = (int)arg;
414 if (flags & FD_CLOEXEC) {
415 filefd_CLOEXEC_enabled(fd);
416 } else {
417 filefd_CLOEXEC_disabled(fd);
418 }
419 }
420 }
421 break;
422
423 default:
424 /*
425 * This is likely a rare situation, abort() would hang fcntl13 LTP test.
426 */
427 ALOGE("%s: mips_cmd:%d doesn't appear to be supported;", __func__,
428 mips_cmd);
429
430 ALOGV("%s: Assume it doesn't need to be mapped!", __func__);
431
432 result = __fcntl64(fd, mips_cmd, arg);
433 }
434
435 done:
436 ALOGV("%s: return(result:%d); }", __func__, result);
437 return result;
438 }
439
440