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