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