Home | History | Annotate | Download | only in arch-mips
      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 
     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  */
     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 
    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 
    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  */
    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