1 /* 2 * stat related system call shims and definitions 3 * 4 * Copyright (c) 2013 Stacey D. Son 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, see <http://www.gnu.org/licenses/>. 18 */ 19 20 #ifndef BSD_USER_FREEBSD_OS_STAT_H 21 #define BSD_USER_FREEBSD_OS_STAT_H 22 23 int freebsd11_stat(const char *path, struct freebsd11_stat *stat); 24 __sym_compat(stat, freebsd11_stat, FBSD_1.0); 25 int freebsd11_lstat(const char *path, struct freebsd11_stat *stat); 26 __sym_compat(lstat, freebsd11_lstat, FBSD_1.0); 27 int freebsd11_fstat(int fd, struct freebsd11_stat *stat); 28 __sym_compat(fstat, freebsd11_fstat, FBSD_1.0); 29 int freebsd11_fstatat(int fd, const char *path, struct freebsd11_stat *stat, 30 int flag); 31 __sym_compat(fstatat, freebsd11_fstatat, FBSD_1.1); 32 33 int freebsd11_fhstat(const fhandle_t *fhandle, struct freebsd11_stat *stat); 34 __sym_compat(fhstat, freebsd11_fhstat, FBSD_1.0); 35 int freebsd11_getfsstat(struct freebsd11_statfs *buf, long bufsize, int mode); 36 __sym_compat(getfsstat, freebsd11_getfsstat, FBSD_1.0); 37 int freebsd11_fhstatfs(const fhandle_t *fhandle, struct freebsd11_statfs * buf); 38 __sym_compat(fhstatfs, freebsd11_fhstatfs, FBSD_1.0); 39 int freebsd11_statfs(const char *path, struct freebsd11_statfs *buf); 40 __sym_compat(statfs, freebsd11_statfs, FBSD_1.0); 41 int freebsd11_fstatfs(int fd, struct freebsd11_statfs *buf); 42 __sym_compat(fstatfs, freebsd11_fstatfs, FBSD_1.0); 43 44 ssize_t freebsd11_getdirentries(int fd, char *buf, size_t nbytes, off_t *basep); 45 __sym_compat(getdirentries, freebsd11_getdirentries, FBSD_1.0); 46 ssize_t freebsd11_getdents(int fd, char *buf, size_t nbytes); 47 __sym_compat(getdents, freebsd11_getdents, FBSD_1.0); 48 49 /* undocumented nstat system calls */ 50 int freebsd11_nstat(const char *path, struct freebsd11_stat *sb); 51 __sym_compat(nstat, freebsd11_nstat, FBSD_1.0); 52 int freebsd11_nlstat(const char *path, struct freebsd11_stat *sb); 53 __sym_compat(nlstat, freebsd11_nlstat, FBSD_1.0); 54 int freebsd11_nfstat(int fd, struct freebsd11_stat *sb); 55 __sym_compat(nfstat, freebsd11_nfstat, FBSD_1.0); 56 57 /* stat(2) */ 58 static inline abi_long do_freebsd11_stat(abi_long arg1, abi_long arg2) 59 { 60 abi_long ret; 61 void *p; 62 struct freebsd11_stat st; 63 64 LOCK_PATH(p, arg1); 65 ret = get_errno(freebsd11_stat(path(p), &st)); 66 UNLOCK_PATH(p, arg1); 67 if (!is_error(ret)) { 68 ret = h2t_freebsd11_stat(arg2, &st); 69 } 70 return ret; 71 } 72 73 /* lstat(2) */ 74 static inline abi_long do_freebsd11_lstat(abi_long arg1, abi_long arg2) 75 { 76 abi_long ret; 77 void *p; 78 struct freebsd11_stat st; 79 80 LOCK_PATH(p, arg1); 81 ret = get_errno(freebsd11_lstat(path(p), &st)); 82 UNLOCK_PATH(p, arg1); 83 if (!is_error(ret)) { 84 ret = h2t_freebsd11_stat(arg2, &st); 85 } 86 return ret; 87 } 88 89 /* fstat(2) */ 90 static inline abi_long do_freebsd11_fstat(abi_long arg1, abi_long arg2) 91 { 92 abi_long ret; 93 struct freebsd11_stat st; 94 95 ret = get_errno(freebsd11_fstat(arg1, &st)); 96 if (!is_error(ret)) { 97 ret = h2t_freebsd11_stat(arg2, &st); 98 } 99 return ret; 100 } 101 102 /* fstat(2) */ 103 static inline abi_long do_freebsd_fstat(abi_long arg1, abi_long arg2) 104 { 105 abi_long ret; 106 struct stat st; 107 108 ret = get_errno(fstat(arg1, &st)); 109 if (!is_error(ret)) { 110 ret = h2t_freebsd_stat(arg2, &st); 111 } 112 return ret; 113 } 114 115 /* fstatat(2) */ 116 static inline abi_long do_freebsd11_fstatat(abi_long arg1, abi_long arg2, 117 abi_long arg3, abi_long arg4) 118 { 119 abi_long ret; 120 void *p; 121 struct freebsd11_stat st; 122 123 LOCK_PATH(p, arg2); 124 ret = get_errno(freebsd11_fstatat(arg1, p, &st, arg4)); 125 UNLOCK_PATH(p, arg2); 126 if (!is_error(ret) && arg3) { 127 ret = h2t_freebsd11_stat(arg3, &st); 128 } 129 return ret; 130 } 131 132 /* fstatat(2) */ 133 static inline abi_long do_freebsd_fstatat(abi_long arg1, abi_long arg2, 134 abi_long arg3, abi_long arg4) 135 { 136 abi_long ret; 137 void *p; 138 struct stat st; 139 140 LOCK_PATH(p, arg2); 141 ret = get_errno(fstatat(arg1, p, &st, arg4)); 142 UNLOCK_PATH(p, arg2); 143 if (!is_error(ret) && arg3) { 144 ret = h2t_freebsd_stat(arg3, &st); 145 } 146 return ret; 147 } 148 149 /* undocummented nstat(char *path, struct nstat *ub) syscall */ 150 static abi_long do_freebsd11_nstat(abi_long arg1, abi_long arg2) 151 { 152 abi_long ret; 153 void *p; 154 struct freebsd11_stat st; 155 156 LOCK_PATH(p, arg1); 157 ret = get_errno(freebsd11_nstat(path(p), &st)); 158 UNLOCK_PATH(p, arg1); 159 if (!is_error(ret)) { 160 ret = h2t_freebsd11_nstat(arg2, &st); 161 } 162 return ret; 163 } 164 165 /* undocummented nfstat(int fd, struct nstat *sb) syscall */ 166 static abi_long do_freebsd11_nfstat(abi_long arg1, abi_long arg2) 167 { 168 abi_long ret; 169 struct freebsd11_stat st; 170 171 ret = get_errno(freebsd11_nfstat(arg1, &st)); 172 if (!is_error(ret)) { 173 ret = h2t_freebsd11_nstat(arg2, &st); 174 } 175 return ret; 176 } 177 178 /* undocummented nlstat(char *path, struct nstat *ub) syscall */ 179 static abi_long do_freebsd11_nlstat(abi_long arg1, abi_long arg2) 180 { 181 abi_long ret; 182 void *p; 183 struct freebsd11_stat st; 184 185 LOCK_PATH(p, arg1); 186 ret = get_errno(freebsd11_nlstat(path(p), &st)); 187 UNLOCK_PATH(p, arg1); 188 if (!is_error(ret)) { 189 ret = h2t_freebsd11_nstat(arg2, &st); 190 } 191 return ret; 192 } 193 194 /* getfh(2) */ 195 static abi_long do_freebsd_getfh(abi_long arg1, abi_long arg2) 196 { 197 abi_long ret; 198 void *p; 199 fhandle_t host_fh; 200 201 LOCK_PATH(p, arg1); 202 ret = get_errno(getfh(path(p), &host_fh)); 203 UNLOCK_PATH(p, arg1); 204 if (is_error(ret)) { 205 return ret; 206 } 207 return h2t_freebsd_fhandle(arg2, &host_fh); 208 } 209 210 /* lgetfh(2) */ 211 static inline abi_long do_freebsd_lgetfh(abi_long arg1, abi_long arg2) 212 { 213 abi_long ret; 214 void *p; 215 fhandle_t host_fh; 216 217 LOCK_PATH(p, arg1); 218 ret = get_errno(lgetfh(path(p), &host_fh)); 219 UNLOCK_PATH(p, arg1); 220 if (is_error(ret)) { 221 return ret; 222 } 223 return h2t_freebsd_fhandle(arg2, &host_fh); 224 } 225 226 /* fhopen(2) */ 227 static inline abi_long do_freebsd_fhopen(abi_long arg1, abi_long arg2) 228 { 229 abi_long ret; 230 fhandle_t host_fh; 231 232 ret = t2h_freebsd_fhandle(&host_fh, arg1); 233 if (is_error(ret)) { 234 return ret; 235 } 236 237 return get_errno(fhopen(&host_fh, arg2)); 238 } 239 240 /* fhstat(2) */ 241 static inline abi_long do_freebsd11_fhstat(abi_long arg1, abi_long arg2) 242 { 243 abi_long ret; 244 fhandle_t host_fh; 245 struct freebsd11_stat host_sb; 246 247 ret = t2h_freebsd_fhandle(&host_fh, arg1); 248 if (is_error(ret)) { 249 return ret; 250 } 251 ret = get_errno(freebsd11_fhstat(&host_fh, &host_sb)); 252 if (is_error(ret)) { 253 return ret; 254 } 255 return h2t_freebsd11_stat(arg2, &host_sb); 256 } 257 258 /* fhstat(2) */ 259 static inline abi_long do_freebsd_fhstat(abi_long arg1, abi_long arg2) 260 { 261 abi_long ret; 262 fhandle_t host_fh; 263 struct stat host_sb; 264 265 ret = t2h_freebsd_fhandle(&host_fh, arg1); 266 if (is_error(ret)) { 267 return ret; 268 } 269 ret = get_errno(fhstat(&host_fh, &host_sb)); 270 if (is_error(ret)) { 271 return ret; 272 } 273 return h2t_freebsd_stat(arg2, &host_sb); 274 } 275 276 /* fhstatfs(2) */ 277 static inline abi_long do_freebsd11_fhstatfs(abi_ulong target_fhp_addr, 278 abi_ulong target_stfs_addr) 279 { 280 abi_long ret; 281 fhandle_t host_fh; 282 struct freebsd11_statfs host_stfs; 283 284 ret = t2h_freebsd_fhandle(&host_fh, target_fhp_addr); 285 if (is_error(ret)) { 286 return ret; 287 } 288 ret = get_errno(freebsd11_fhstatfs(&host_fh, &host_stfs)); 289 if (is_error(ret)) { 290 return ret; 291 } 292 return h2t_freebsd11_statfs(target_stfs_addr, &host_stfs); 293 } 294 295 /* fhstatfs(2) */ 296 static inline abi_long do_freebsd_fhstatfs(abi_ulong target_fhp_addr, 297 abi_ulong target_stfs_addr) 298 { 299 abi_long ret; 300 fhandle_t host_fh; 301 struct statfs host_stfs; 302 303 ret = t2h_freebsd_fhandle(&host_fh, target_fhp_addr); 304 if (is_error(ret)) { 305 return ret; 306 } 307 ret = get_errno(fhstatfs(&host_fh, &host_stfs)); 308 if (is_error(ret)) { 309 return ret; 310 } 311 return h2t_freebsd_statfs(target_stfs_addr, &host_stfs); 312 } 313 314 /* statfs(2) */ 315 static inline abi_long do_freebsd11_statfs(abi_long arg1, abi_long arg2) 316 { 317 abi_long ret; 318 void *p; 319 struct freebsd11_statfs host_stfs; 320 321 LOCK_PATH(p, arg1); 322 ret = get_errno(freebsd11_statfs(path(p), &host_stfs)); 323 UNLOCK_PATH(p, arg1); 324 if (is_error(ret)) { 325 return ret; 326 } 327 328 return h2t_freebsd11_statfs(arg2, &host_stfs); 329 } 330 331 /* statfs(2) */ 332 static inline abi_long do_freebsd_statfs(abi_long arg1, abi_long arg2) 333 { 334 abi_long ret; 335 void *p; 336 struct statfs host_stfs; 337 338 LOCK_PATH(p, arg1); 339 ret = get_errno(statfs(path(p), &host_stfs)); 340 UNLOCK_PATH(p, arg1); 341 if (is_error(ret)) { 342 return ret; 343 } 344 345 return h2t_freebsd_statfs(arg2, &host_stfs); 346 } 347 348 /* fstatfs(2) */ 349 static inline abi_long do_freebsd11_fstatfs(abi_long fd, abi_ulong target_addr) 350 { 351 abi_long ret; 352 struct freebsd11_statfs host_stfs; 353 354 ret = get_errno(freebsd11_fstatfs(fd, &host_stfs)); 355 if (is_error(ret)) { 356 return ret; 357 } 358 359 return h2t_freebsd11_statfs(target_addr, &host_stfs); 360 } 361 362 /* fstatfs(2) */ 363 static inline abi_long do_freebsd_fstatfs(abi_long fd, abi_ulong target_addr) 364 { 365 abi_long ret; 366 struct statfs host_stfs; 367 368 ret = get_errno(fstatfs(fd, &host_stfs)); 369 if (is_error(ret)) { 370 return ret; 371 } 372 373 return h2t_freebsd_statfs(target_addr, &host_stfs); 374 } 375 376 /* getfsstat(2) */ 377 static inline abi_long do_freebsd11_getfsstat(abi_ulong target_addr, 378 abi_long bufsize, abi_long flags) 379 { 380 abi_long ret; 381 struct freebsd11_statfs *host_stfs; 382 int count; 383 long host_bufsize; 384 385 count = bufsize / sizeof(struct target_freebsd11_statfs); 386 387 /* if user buffer is NULL then return number of mounted FS's */ 388 if (target_addr == 0 || count == 0) { 389 return get_errno(freebsd11_getfsstat(NULL, 0, flags)); 390 } 391 392 /* XXX check count to be reasonable */ 393 host_bufsize = sizeof(struct freebsd11_statfs) * count; 394 host_stfs = alloca(host_bufsize); 395 if (!host_stfs) { 396 return -TARGET_EINVAL; 397 } 398 399 ret = count = get_errno(freebsd11_getfsstat(host_stfs, host_bufsize, flags)); 400 if (is_error(ret)) { 401 return ret; 402 } 403 404 while (count--) { 405 if (h2t_freebsd11_statfs((target_addr + 406 (count * sizeof(struct target_freebsd11_statfs))), 407 &host_stfs[count])) { 408 return -TARGET_EFAULT; 409 } 410 } 411 return ret; 412 } 413 414 /* getfsstat(2) */ 415 static inline abi_long do_freebsd_getfsstat(abi_ulong target_addr, 416 abi_long bufsize, abi_long flags) 417 { 418 abi_long ret; 419 struct statfs *host_stfs; 420 int count; 421 long host_bufsize; 422 423 count = bufsize / sizeof(struct target_statfs); 424 425 /* if user buffer is NULL then return number of mounted FS's */ 426 if (target_addr == 0 || count == 0) { 427 return get_errno(freebsd11_getfsstat(NULL, 0, flags)); 428 } 429 430 /* XXX check count to be reasonable */ 431 host_bufsize = sizeof(struct statfs) * count; 432 host_stfs = alloca(host_bufsize); 433 if (!host_stfs) { 434 return -TARGET_EINVAL; 435 } 436 437 ret = count = get_errno(getfsstat(host_stfs, host_bufsize, flags)); 438 if (is_error(ret)) { 439 return ret; 440 } 441 442 while (count--) { 443 if (h2t_freebsd_statfs((target_addr + 444 (count * sizeof(struct target_statfs))), 445 &host_stfs[count])) { 446 return -TARGET_EFAULT; 447 } 448 } 449 return ret; 450 } 451 452 /* getdents(2) */ 453 static inline abi_long do_freebsd11_getdents(abi_long arg1, 454 abi_ulong arg2, abi_long nbytes) 455 { 456 abi_long ret; 457 struct freebsd11_dirent *dirp; 458 459 dirp = lock_user(VERIFY_WRITE, arg2, nbytes, 0); 460 if (dirp == NULL) { 461 return -TARGET_EFAULT; 462 } 463 ret = get_errno(freebsd11_getdents(arg1, (char *)dirp, nbytes)); 464 if (!is_error(ret)) { 465 struct freebsd11_dirent *de; 466 int len = ret; 467 int reclen; 468 469 de = dirp; 470 while (len > 0) { 471 reclen = de->d_reclen; 472 if (reclen > len) { 473 return -TARGET_EFAULT; 474 } 475 de->d_reclen = tswap16(reclen); 476 de->d_fileno = tswap32(de->d_fileno); 477 len -= reclen; 478 } 479 } 480 return ret; 481 } 482 483 /* getdirecentries(2) */ 484 static inline abi_long do_freebsd11_getdirentries(abi_long arg1, 485 abi_ulong arg2, abi_long nbytes, abi_ulong arg4) 486 { 487 abi_long ret; 488 struct freebsd11_dirent *dirp; 489 long basep; 490 491 dirp = lock_user(VERIFY_WRITE, arg2, nbytes, 0); 492 if (dirp == NULL) { 493 return -TARGET_EFAULT; 494 } 495 ret = get_errno(freebsd11_getdirentries(arg1, (char *)dirp, nbytes, &basep)); 496 if (!is_error(ret)) { 497 struct freebsd11_dirent *de; 498 int len = ret; 499 int reclen; 500 501 de = dirp; 502 while (len > 0) { 503 reclen = de->d_reclen; 504 if (reclen > len) { 505 return -TARGET_EFAULT; 506 } 507 de->d_reclen = tswap16(reclen); 508 de->d_fileno = tswap32(de->d_fileno); 509 len -= reclen; 510 de = (struct freebsd11_dirent *)((void *)de + reclen); 511 } 512 } 513 unlock_user(dirp, arg2, ret); 514 if (arg4) { 515 if (put_user(basep, arg4, abi_ulong)) { 516 return -TARGET_EFAULT; 517 } 518 } 519 return ret; 520 } 521 522 /* getdirecentries(2) */ 523 static inline abi_long do_freebsd_getdirentries(abi_long arg1, 524 abi_ulong arg2, abi_long nbytes, abi_ulong arg4) 525 { 526 abi_long ret; 527 struct dirent *dirp; 528 long basep; 529 530 dirp = lock_user(VERIFY_WRITE, arg2, nbytes, 0); 531 if (dirp == NULL) { 532 return -TARGET_EFAULT; 533 } 534 ret = get_errno(getdirentries(arg1, (char *)dirp, nbytes, &basep)); 535 if (!is_error(ret)) { 536 struct dirent *de; 537 int len = ret; 538 int reclen; 539 540 de = dirp; 541 while (len > 0) { 542 reclen = de->d_reclen; 543 if (reclen > len) { 544 return -TARGET_EFAULT; 545 } 546 de->d_fileno = tswap64(de->d_fileno); 547 de->d_off = tswap64(de->d_off); 548 de->d_reclen = tswap16(de->d_reclen); 549 de->d_namlen = tswap16(de->d_namlen); 550 len -= reclen; 551 de = (struct dirent *)((void *)de + reclen); 552 } 553 } 554 unlock_user(dirp, arg2, ret); 555 if (arg4) { 556 if (put_user(basep, arg4, abi_ulong)) { 557 return -TARGET_EFAULT; 558 } 559 } 560 return ret; 561 } 562 563 /* fcntl(2) */ 564 static inline abi_long do_freebsd_fcntl(abi_long arg1, abi_long arg2, 565 abi_ulong arg3) 566 { 567 abi_long ret; 568 int host_cmd; 569 struct flock fl; 570 struct target_freebsd_flock *target_fl; 571 572 host_cmd = target_to_host_fcntl_cmd(arg2); 573 if (host_cmd < 0) { 574 return host_cmd; 575 } 576 switch (arg2) { 577 case TARGET_F_GETLK: 578 if (!lock_user_struct(VERIFY_READ, target_fl, arg3, 1)) { 579 return -TARGET_EFAULT; 580 } 581 __get_user(fl.l_type, &target_fl->l_type); 582 __get_user(fl.l_whence, &target_fl->l_whence); 583 __get_user(fl.l_start, &target_fl->l_start); 584 __get_user(fl.l_len, &target_fl->l_len); 585 __get_user(fl.l_pid, &target_fl->l_pid); 586 __get_user(fl.l_sysid, &target_fl->l_sysid); 587 unlock_user_struct(target_fl, arg3, 0); 588 ret = get_errno(safe_fcntl(arg1, host_cmd, &fl)); 589 if (!is_error(ret)) { 590 if (!lock_user_struct(VERIFY_WRITE, target_fl, arg3, 0)) { 591 return -TARGET_EFAULT; 592 } 593 __put_user(fl.l_type, &target_fl->l_type); 594 __put_user(fl.l_whence, &target_fl->l_whence); 595 __put_user(fl.l_start, &target_fl->l_start); 596 __put_user(fl.l_len, &target_fl->l_len); 597 __put_user(fl.l_pid, &target_fl->l_pid); 598 __put_user(fl.l_sysid, &target_fl->l_sysid); 599 unlock_user_struct(target_fl, arg3, 1); 600 } 601 break; 602 603 case TARGET_F_SETLK: 604 case TARGET_F_SETLKW: 605 if (!lock_user_struct(VERIFY_READ, target_fl, arg3, 1)) { 606 return -TARGET_EFAULT; 607 } 608 __get_user(fl.l_type, &target_fl->l_type); 609 __get_user(fl.l_whence, &target_fl->l_whence); 610 __get_user(fl.l_start, &target_fl->l_start); 611 __get_user(fl.l_len, &target_fl->l_len); 612 __get_user(fl.l_pid, &target_fl->l_pid); 613 __get_user(fl.l_sysid, &target_fl->l_sysid); 614 unlock_user_struct(target_fl, arg3, 0); 615 ret = get_errno(safe_fcntl(arg1, host_cmd, &fl)); 616 break; 617 618 case TARGET_F_DUPFD: 619 case TARGET_F_DUP2FD: 620 case TARGET_F_GETOWN: 621 case TARGET_F_SETOWN: 622 case TARGET_F_GETFD: 623 case TARGET_F_SETFD: 624 case TARGET_F_GETFL: 625 case TARGET_F_SETFL: 626 case TARGET_F_READAHEAD: 627 case TARGET_F_RDAHEAD: 628 case TARGET_F_ADD_SEALS: 629 case TARGET_F_GET_SEALS: 630 default: 631 ret = get_errno(safe_fcntl(arg1, host_cmd, arg3)); 632 break; 633 } 634 return ret; 635 } 636 637 #if defined(__FreeBSD_version) && __FreeBSD_version >= 1300080 638 extern int __realpathat(int fd, const char *path, char *buf, size_t size, 639 int flags); 640 /* https://svnweb.freebsd.org/base?view=revision&revision=358172 */ 641 /* no man page */ 642 static inline abi_long do_freebsd_realpathat(abi_long arg1, abi_long arg2, 643 abi_long arg3, abi_long arg4, abi_long arg5) 644 { 645 abi_long ret; 646 void *p, *b; 647 648 LOCK_PATH(p, arg2); 649 b = lock_user(VERIFY_WRITE, arg3, arg4, 0); 650 if (b == NULL) { 651 UNLOCK_PATH(p, arg2); 652 return -TARGET_EFAULT; 653 } 654 655 ret = get_errno(__realpathat(arg1, p, b, arg4, arg5)); 656 UNLOCK_PATH(p, arg2); 657 unlock_user(b, arg3, ret); 658 659 return ret; 660 } 661 #endif 662 663 #endif /* BSD_USER_FREEBSD_OS_STAT_H */ 664