1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 1994-1995 Søren Schmidt 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 #include <sys/cdefs.h> 30 __FBSDID("$FreeBSD$"); 31 32 #include "opt_compat.h" 33 34 #include <sys/param.h> 35 #include <sys/systm.h> 36 #include <sys/capsicum.h> 37 #include <sys/conf.h> 38 #include <sys/dirent.h> 39 #include <sys/fcntl.h> 40 #include <sys/file.h> 41 #include <sys/filedesc.h> 42 #include <sys/lock.h> 43 #include <sys/malloc.h> 44 #include <sys/mount.h> 45 #include <sys/mutex.h> 46 #include <sys/namei.h> 47 #include <sys/proc.h> 48 #include <sys/stat.h> 49 #include <sys/sx.h> 50 #include <sys/syscallsubr.h> 51 #include <sys/sysproto.h> 52 #include <sys/tty.h> 53 #include <sys/unistd.h> 54 #include <sys/vnode.h> 55 56 #ifdef COMPAT_LINUX32 57 #include <machine/../linux32/linux.h> 58 #include <machine/../linux32/linux32_proto.h> 59 #else 60 #include <machine/../linux/linux.h> 61 #include <machine/../linux/linux_proto.h> 62 #endif 63 #include <compat/linux/linux_misc.h> 64 #include <compat/linux/linux_util.h> 65 #include <compat/linux/linux_file.h> 66 67 static int linux_common_open(struct thread *, int, char *, int, int); 68 static int linux_getdents_error(struct thread *, int, int); 69 70 71 #ifdef LINUX_LEGACY_SYSCALLS 72 int 73 linux_creat(struct thread *td, struct linux_creat_args *args) 74 { 75 char *path; 76 int error; 77 78 LCONVPATHEXIST(td, args->path, &path); 79 #ifdef DEBUG 80 if (ldebug(creat)) 81 printf(ARGS(creat, "%s, %d"), path, args->mode); 82 #endif 83 error = kern_openat(td, AT_FDCWD, path, UIO_SYSSPACE, 84 O_WRONLY | O_CREAT | O_TRUNC, args->mode); 85 LFREEPATH(path); 86 return (error); 87 } 88 #endif 89 90 static int 91 linux_common_open(struct thread *td, int dirfd, char *path, int l_flags, int mode) 92 { 93 struct proc *p = td->td_proc; 94 struct file *fp; 95 int fd; 96 int bsd_flags, error; 97 98 bsd_flags = 0; 99 switch (l_flags & LINUX_O_ACCMODE) { 100 case LINUX_O_WRONLY: 101 bsd_flags |= O_WRONLY; 102 break; 103 case LINUX_O_RDWR: 104 bsd_flags |= O_RDWR; 105 break; 106 default: 107 bsd_flags |= O_RDONLY; 108 } 109 if (l_flags & LINUX_O_NDELAY) 110 bsd_flags |= O_NONBLOCK; 111 if (l_flags & LINUX_O_APPEND) 112 bsd_flags |= O_APPEND; 113 if (l_flags & LINUX_O_SYNC) 114 bsd_flags |= O_FSYNC; 115 if (l_flags & LINUX_O_NONBLOCK) 116 bsd_flags |= O_NONBLOCK; 117 if (l_flags & LINUX_FASYNC) 118 bsd_flags |= O_ASYNC; 119 if (l_flags & LINUX_O_CREAT) 120 bsd_flags |= O_CREAT; 121 if (l_flags & LINUX_O_TRUNC) 122 bsd_flags |= O_TRUNC; 123 if (l_flags & LINUX_O_EXCL) 124 bsd_flags |= O_EXCL; 125 if (l_flags & LINUX_O_NOCTTY) 126 bsd_flags |= O_NOCTTY; 127 if (l_flags & LINUX_O_DIRECT) 128 bsd_flags |= O_DIRECT; 129 if (l_flags & LINUX_O_NOFOLLOW) 130 bsd_flags |= O_NOFOLLOW; 131 if (l_flags & LINUX_O_DIRECTORY) 132 bsd_flags |= O_DIRECTORY; 133 /* XXX LINUX_O_NOATIME: unable to be easily implemented. */ 134 135 error = kern_openat(td, dirfd, path, UIO_SYSSPACE, bsd_flags, mode); 136 if (error != 0) 137 goto done; 138 if (bsd_flags & O_NOCTTY) 139 goto done; 140 141 /* 142 * XXX In between kern_openat() and fget(), another process 143 * having the same filedesc could use that fd without 144 * checking below. 145 */ 146 fd = td->td_retval[0]; 147 if (fget(td, fd, &cap_ioctl_rights, &fp) == 0) { 148 if (fp->f_type != DTYPE_VNODE) { 149 fdrop(fp, td); 150 goto done; 151 } 152 sx_slock(&proctree_lock); 153 PROC_LOCK(p); 154 if (SESS_LEADER(p) && !(p->p_flag & P_CONTROLT)) { 155 PROC_UNLOCK(p); 156 sx_sunlock(&proctree_lock); 157 /* XXXPJD: Verify if TIOCSCTTY is allowed. */ 158 (void) fo_ioctl(fp, TIOCSCTTY, (caddr_t) 0, 159 td->td_ucred, td); 160 } else { 161 PROC_UNLOCK(p); 162 sx_sunlock(&proctree_lock); 163 } 164 fdrop(fp, td); 165 } 166 167 done: 168 #ifdef DEBUG 169 #ifdef LINUX_LEGACY_SYSCALLS 170 if (ldebug(open)) 171 #else 172 if (ldebug(openat)) 173 #endif 174 printf(LMSG("open returns error %d"), error); 175 #endif 176 LFREEPATH(path); 177 return (error); 178 } 179 180 int 181 linux_openat(struct thread *td, struct linux_openat_args *args) 182 { 183 char *path; 184 int dfd; 185 186 dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd; 187 if (args->flags & LINUX_O_CREAT) 188 LCONVPATH_AT(td, args->filename, &path, 1, dfd); 189 else 190 LCONVPATH_AT(td, args->filename, &path, 0, dfd); 191 #ifdef DEBUG 192 if (ldebug(openat)) 193 printf(ARGS(openat, "%i, %s, 0x%x, 0x%x"), args->dfd, 194 path, args->flags, args->mode); 195 #endif 196 return (linux_common_open(td, dfd, path, args->flags, args->mode)); 197 } 198 199 #ifdef LINUX_LEGACY_SYSCALLS 200 int 201 linux_open(struct thread *td, struct linux_open_args *args) 202 { 203 char *path; 204 205 if (args->flags & LINUX_O_CREAT) 206 LCONVPATHCREAT(td, args->path, &path); 207 else 208 LCONVPATHEXIST(td, args->path, &path); 209 #ifdef DEBUG 210 if (ldebug(open)) 211 printf(ARGS(open, "%s, 0x%x, 0x%x"), 212 path, args->flags, args->mode); 213 #endif 214 return (linux_common_open(td, AT_FDCWD, path, args->flags, args->mode)); 215 } 216 #endif 217 218 int 219 linux_lseek(struct thread *td, struct linux_lseek_args *args) 220 { 221 222 #ifdef DEBUG 223 if (ldebug(lseek)) 224 printf(ARGS(lseek, "%d, %ld, %d"), 225 args->fdes, (long)args->off, args->whence); 226 #endif 227 return (kern_lseek(td, args->fdes, args->off, args->whence)); 228 } 229 230 #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) 231 int 232 linux_llseek(struct thread *td, struct linux_llseek_args *args) 233 { 234 int error; 235 off_t off; 236 237 #ifdef DEBUG 238 if (ldebug(llseek)) 239 printf(ARGS(llseek, "%d, %d:%d, %d"), 240 args->fd, args->ohigh, args->olow, args->whence); 241 #endif 242 off = (args->olow) | (((off_t) args->ohigh) << 32); 243 244 error = kern_lseek(td, args->fd, off, args->whence); 245 if (error != 0) 246 return (error); 247 248 error = copyout(td->td_retval, args->res, sizeof(off_t)); 249 if (error != 0) 250 return (error); 251 252 td->td_retval[0] = 0; 253 return (0); 254 } 255 #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ 256 257 /* 258 * Note that linux_getdents(2) and linux_getdents64(2) have the same 259 * arguments. They only differ in the definition of struct dirent they 260 * operate on. 261 * Note that linux_readdir(2) is a special case of linux_getdents(2) 262 * where count is always equals 1, meaning that the buffer is one 263 * dirent-structure in size and that the code can't handle more anyway. 264 * Note that linux_readdir(2) can't be implemented by means of linux_getdents(2) 265 * as in case when the *dent buffer size is equal to 1 linux_getdents(2) will 266 * trash user stack. 267 */ 268 269 static int 270 linux_getdents_error(struct thread *td, int fd, int err) 271 { 272 struct vnode *vp; 273 struct file *fp; 274 int error; 275 276 /* Linux return ENOTDIR in case when fd is not a directory. */ 277 error = getvnode(td, fd, &cap_read_rights, &fp); 278 if (error != 0) 279 return (error); 280 vp = fp->f_vnode; 281 if (vp->v_type != VDIR) { 282 fdrop(fp, td); 283 return (ENOTDIR); 284 } 285 fdrop(fp, td); 286 return (err); 287 } 288 289 struct l_dirent { 290 l_ulong d_ino; 291 l_off_t d_off; 292 l_ushort d_reclen; 293 char d_name[LINUX_NAME_MAX + 1]; 294 }; 295 296 struct l_dirent64 { 297 uint64_t d_ino; 298 int64_t d_off; 299 l_ushort d_reclen; 300 u_char d_type; 301 char d_name[LINUX_NAME_MAX + 1]; 302 }; 303 304 /* 305 * Linux uses the last byte in the dirent buffer to store d_type, 306 * at least glibc-2.7 requires it. That is why l_dirent is padded with 2 bytes. 307 */ 308 #define LINUX_RECLEN(namlen) \ 309 roundup(offsetof(struct l_dirent, d_name) + (namlen) + 2, sizeof(l_ulong)) 310 311 #define LINUX_RECLEN64(namlen) \ 312 roundup(offsetof(struct l_dirent64, d_name) + (namlen) + 1, \ 313 sizeof(uint64_t)) 314 315 #ifdef LINUX_LEGACY_SYSCALLS 316 int 317 linux_getdents(struct thread *td, struct linux_getdents_args *args) 318 { 319 struct dirent *bdp; 320 caddr_t inp, buf; /* BSD-format */ 321 int len, reclen; /* BSD-format */ 322 caddr_t outp; /* Linux-format */ 323 int resid, linuxreclen; /* Linux-format */ 324 caddr_t lbuf; /* Linux-format */ 325 off_t base; 326 struct l_dirent *linux_dirent; 327 int buflen, error; 328 size_t retval; 329 330 #ifdef DEBUG 331 if (ldebug(getdents)) 332 printf(ARGS(getdents, "%d, *, %d"), args->fd, args->count); 333 #endif 334 buflen = min(args->count, MAXBSIZE); 335 buf = malloc(buflen, M_TEMP, M_WAITOK); 336 337 error = kern_getdirentries(td, args->fd, buf, buflen, 338 &base, NULL, UIO_SYSSPACE); 339 if (error != 0) { 340 error = linux_getdents_error(td, args->fd, error); 341 goto out1; 342 } 343 344 lbuf = malloc(LINUX_RECLEN(LINUX_NAME_MAX), M_TEMP, M_WAITOK | M_ZERO); 345 346 len = td->td_retval[0]; 347 inp = buf; 348 outp = (caddr_t)args->dent; 349 resid = args->count; 350 retval = 0; 351 352 while (len > 0) { 353 bdp = (struct dirent *) inp; 354 reclen = bdp->d_reclen; 355 linuxreclen = LINUX_RECLEN(bdp->d_namlen); 356 /* 357 * No more space in the user supplied dirent buffer. 358 * Return EINVAL. 359 */ 360 if (resid < linuxreclen) { 361 error = EINVAL; 362 goto out; 363 } 364 365 linux_dirent = (struct l_dirent*)lbuf; 366 linux_dirent->d_ino = bdp->d_fileno; 367 linux_dirent->d_off = base + reclen; 368 linux_dirent->d_reclen = linuxreclen; 369 /* 370 * Copy d_type to last byte of l_dirent buffer 371 */ 372 lbuf[linuxreclen - 1] = bdp->d_type; 373 strlcpy(linux_dirent->d_name, bdp->d_name, 374 linuxreclen - offsetof(struct l_dirent, d_name)-1); 375 error = copyout(linux_dirent, outp, linuxreclen); 376 if (error != 0) 377 goto out; 378 379 inp += reclen; 380 base += reclen; 381 len -= reclen; 382 383 retval += linuxreclen; 384 outp += linuxreclen; 385 resid -= linuxreclen; 386 } 387 td->td_retval[0] = retval; 388 389 out: 390 free(lbuf, M_TEMP); 391 out1: 392 free(buf, M_TEMP); 393 return (error); 394 } 395 #endif 396 397 int 398 linux_getdents64(struct thread *td, struct linux_getdents64_args *args) 399 { 400 struct dirent *bdp; 401 caddr_t inp, buf; /* BSD-format */ 402 int len, reclen; /* BSD-format */ 403 caddr_t outp; /* Linux-format */ 404 int resid, linuxreclen; /* Linux-format */ 405 caddr_t lbuf; /* Linux-format */ 406 off_t base; 407 struct l_dirent64 *linux_dirent64; 408 int buflen, error; 409 size_t retval; 410 411 #ifdef DEBUG 412 if (ldebug(getdents64)) 413 uprintf(ARGS(getdents64, "%d, *, %d"), args->fd, args->count); 414 #endif 415 buflen = min(args->count, MAXBSIZE); 416 buf = malloc(buflen, M_TEMP, M_WAITOK); 417 418 error = kern_getdirentries(td, args->fd, buf, buflen, 419 &base, NULL, UIO_SYSSPACE); 420 if (error != 0) { 421 error = linux_getdents_error(td, args->fd, error); 422 goto out1; 423 } 424 425 lbuf = malloc(LINUX_RECLEN64(LINUX_NAME_MAX), M_TEMP, M_WAITOK | M_ZERO); 426 427 len = td->td_retval[0]; 428 inp = buf; 429 outp = (caddr_t)args->dirent; 430 resid = args->count; 431 retval = 0; 432 433 while (len > 0) { 434 bdp = (struct dirent *) inp; 435 reclen = bdp->d_reclen; 436 linuxreclen = LINUX_RECLEN64(bdp->d_namlen); 437 /* 438 * No more space in the user supplied dirent buffer. 439 * Return EINVAL. 440 */ 441 if (resid < linuxreclen) { 442 error = EINVAL; 443 goto out; 444 } 445 446 linux_dirent64 = (struct l_dirent64*)lbuf; 447 linux_dirent64->d_ino = bdp->d_fileno; 448 linux_dirent64->d_off = base + reclen; 449 linux_dirent64->d_reclen = linuxreclen; 450 linux_dirent64->d_type = bdp->d_type; 451 strlcpy(linux_dirent64->d_name, bdp->d_name, 452 linuxreclen - offsetof(struct l_dirent64, d_name)); 453 error = copyout(linux_dirent64, outp, linuxreclen); 454 if (error != 0) 455 goto out; 456 457 inp += reclen; 458 base += reclen; 459 len -= reclen; 460 461 retval += linuxreclen; 462 outp += linuxreclen; 463 resid -= linuxreclen; 464 } 465 td->td_retval[0] = retval; 466 467 out: 468 free(lbuf, M_TEMP); 469 out1: 470 free(buf, M_TEMP); 471 return (error); 472 } 473 474 #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) 475 int 476 linux_readdir(struct thread *td, struct linux_readdir_args *args) 477 { 478 struct dirent *bdp; 479 caddr_t buf; /* BSD-format */ 480 int linuxreclen; /* Linux-format */ 481 caddr_t lbuf; /* Linux-format */ 482 off_t base; 483 struct l_dirent *linux_dirent; 484 int buflen, error; 485 486 #ifdef DEBUG 487 if (ldebug(readdir)) 488 printf(ARGS(readdir, "%d, *"), args->fd); 489 #endif 490 buflen = LINUX_RECLEN(LINUX_NAME_MAX); 491 buf = malloc(buflen, M_TEMP, M_WAITOK); 492 493 error = kern_getdirentries(td, args->fd, buf, buflen, 494 &base, NULL, UIO_SYSSPACE); 495 if (error != 0) { 496 error = linux_getdents_error(td, args->fd, error); 497 goto out; 498 } 499 if (td->td_retval[0] == 0) 500 goto out; 501 502 lbuf = malloc(LINUX_RECLEN(LINUX_NAME_MAX), M_TEMP, M_WAITOK | M_ZERO); 503 504 bdp = (struct dirent *) buf; 505 linuxreclen = LINUX_RECLEN(bdp->d_namlen); 506 507 linux_dirent = (struct l_dirent*)lbuf; 508 linux_dirent->d_ino = bdp->d_fileno; 509 linux_dirent->d_off = linuxreclen; 510 linux_dirent->d_reclen = bdp->d_namlen; 511 strlcpy(linux_dirent->d_name, bdp->d_name, 512 linuxreclen - offsetof(struct l_dirent, d_name)); 513 error = copyout(linux_dirent, args->dent, linuxreclen); 514 if (error == 0) 515 td->td_retval[0] = linuxreclen; 516 517 free(lbuf, M_TEMP); 518 out: 519 free(buf, M_TEMP); 520 return (error); 521 } 522 #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ 523 524 525 /* 526 * These exist mainly for hooks for doing /compat/linux translation. 527 */ 528 529 #ifdef LINUX_LEGACY_SYSCALLS 530 int 531 linux_access(struct thread *td, struct linux_access_args *args) 532 { 533 char *path; 534 int error; 535 536 /* Linux convention. */ 537 if (args->amode & ~(F_OK | X_OK | W_OK | R_OK)) 538 return (EINVAL); 539 540 LCONVPATHEXIST(td, args->path, &path); 541 542 #ifdef DEBUG 543 if (ldebug(access)) 544 printf(ARGS(access, "%s, %d"), path, args->amode); 545 #endif 546 error = kern_accessat(td, AT_FDCWD, path, UIO_SYSSPACE, 0, 547 args->amode); 548 LFREEPATH(path); 549 550 return (error); 551 } 552 #endif 553 554 int 555 linux_faccessat(struct thread *td, struct linux_faccessat_args *args) 556 { 557 char *path; 558 int error, dfd; 559 560 /* Linux convention. */ 561 if (args->amode & ~(F_OK | X_OK | W_OK | R_OK)) 562 return (EINVAL); 563 564 dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd; 565 LCONVPATHEXIST_AT(td, args->filename, &path, dfd); 566 567 #ifdef DEBUG 568 if (ldebug(faccessat)) 569 printf(ARGS(access, "%s, %d"), path, args->amode); 570 #endif 571 572 error = kern_accessat(td, dfd, path, UIO_SYSSPACE, 0, args->amode); 573 LFREEPATH(path); 574 575 return (error); 576 } 577 578 #ifdef LINUX_LEGACY_SYSCALLS 579 int 580 linux_unlink(struct thread *td, struct linux_unlink_args *args) 581 { 582 char *path; 583 int error; 584 struct stat st; 585 586 LCONVPATHEXIST(td, args->path, &path); 587 588 #ifdef DEBUG 589 if (ldebug(unlink)) 590 printf(ARGS(unlink, "%s"), path); 591 #endif 592 593 error = kern_unlinkat(td, AT_FDCWD, path, UIO_SYSSPACE, 0, 0); 594 if (error == EPERM) { 595 /* Introduce POSIX noncompliant behaviour of Linux */ 596 if (kern_statat(td, 0, AT_FDCWD, path, UIO_SYSSPACE, &st, 597 NULL) == 0) { 598 if (S_ISDIR(st.st_mode)) 599 error = EISDIR; 600 } 601 } 602 LFREEPATH(path); 603 return (error); 604 } 605 #endif 606 607 int 608 linux_unlinkat(struct thread *td, struct linux_unlinkat_args *args) 609 { 610 char *path; 611 int error, dfd; 612 struct stat st; 613 614 if (args->flag & ~LINUX_AT_REMOVEDIR) 615 return (EINVAL); 616 617 dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd; 618 LCONVPATHEXIST_AT(td, args->pathname, &path, dfd); 619 620 #ifdef DEBUG 621 if (ldebug(unlinkat)) 622 printf(ARGS(unlinkat, "%s"), path); 623 #endif 624 625 if (args->flag & LINUX_AT_REMOVEDIR) 626 error = kern_rmdirat(td, dfd, path, UIO_SYSSPACE, 0); 627 else 628 error = kern_unlinkat(td, dfd, path, UIO_SYSSPACE, 0, 0); 629 if (error == EPERM && !(args->flag & LINUX_AT_REMOVEDIR)) { 630 /* Introduce POSIX noncompliant behaviour of Linux */ 631 if (kern_statat(td, AT_SYMLINK_NOFOLLOW, dfd, path, 632 UIO_SYSSPACE, &st, NULL) == 0 && S_ISDIR(st.st_mode)) 633 error = EISDIR; 634 } 635 LFREEPATH(path); 636 return (error); 637 } 638 int 639 linux_chdir(struct thread *td, struct linux_chdir_args *args) 640 { 641 char *path; 642 int error; 643 644 LCONVPATHEXIST(td, args->path, &path); 645 646 #ifdef DEBUG 647 if (ldebug(chdir)) 648 printf(ARGS(chdir, "%s"), path); 649 #endif 650 error = kern_chdir(td, path, UIO_SYSSPACE); 651 LFREEPATH(path); 652 return (error); 653 } 654 655 #ifdef LINUX_LEGACY_SYSCALLS 656 int 657 linux_chmod(struct thread *td, struct linux_chmod_args *args) 658 { 659 char *path; 660 int error; 661 662 LCONVPATHEXIST(td, args->path, &path); 663 664 #ifdef DEBUG 665 if (ldebug(chmod)) 666 printf(ARGS(chmod, "%s, %d"), path, args->mode); 667 #endif 668 error = kern_fchmodat(td, AT_FDCWD, path, UIO_SYSSPACE, 669 args->mode, 0); 670 LFREEPATH(path); 671 return (error); 672 } 673 #endif 674 675 int 676 linux_fchmodat(struct thread *td, struct linux_fchmodat_args *args) 677 { 678 char *path; 679 int error, dfd; 680 681 dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd; 682 LCONVPATHEXIST_AT(td, args->filename, &path, dfd); 683 684 #ifdef DEBUG 685 if (ldebug(fchmodat)) 686 printf(ARGS(fchmodat, "%s, %d"), path, args->mode); 687 #endif 688 689 error = kern_fchmodat(td, dfd, path, UIO_SYSSPACE, args->mode, 0); 690 LFREEPATH(path); 691 return (error); 692 } 693 694 #ifdef LINUX_LEGACY_SYSCALLS 695 int 696 linux_mkdir(struct thread *td, struct linux_mkdir_args *args) 697 { 698 char *path; 699 int error; 700 701 LCONVPATHCREAT(td, args->path, &path); 702 703 #ifdef DEBUG 704 if (ldebug(mkdir)) 705 printf(ARGS(mkdir, "%s, %d"), path, args->mode); 706 #endif 707 error = kern_mkdirat(td, AT_FDCWD, path, UIO_SYSSPACE, args->mode); 708 LFREEPATH(path); 709 return (error); 710 } 711 #endif 712 713 int 714 linux_mkdirat(struct thread *td, struct linux_mkdirat_args *args) 715 { 716 char *path; 717 int error, dfd; 718 719 dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd; 720 LCONVPATHCREAT_AT(td, args->pathname, &path, dfd); 721 722 #ifdef DEBUG 723 if (ldebug(mkdirat)) 724 printf(ARGS(mkdirat, "%s, %d"), path, args->mode); 725 #endif 726 error = kern_mkdirat(td, dfd, path, UIO_SYSSPACE, args->mode); 727 LFREEPATH(path); 728 return (error); 729 } 730 731 #ifdef LINUX_LEGACY_SYSCALLS 732 int 733 linux_rmdir(struct thread *td, struct linux_rmdir_args *args) 734 { 735 char *path; 736 int error; 737 738 LCONVPATHEXIST(td, args->path, &path); 739 740 #ifdef DEBUG 741 if (ldebug(rmdir)) 742 printf(ARGS(rmdir, "%s"), path); 743 #endif 744 error = kern_rmdirat(td, AT_FDCWD, path, UIO_SYSSPACE, 0); 745 LFREEPATH(path); 746 return (error); 747 } 748 749 int 750 linux_rename(struct thread *td, struct linux_rename_args *args) 751 { 752 char *from, *to; 753 int error; 754 755 LCONVPATHEXIST(td, args->from, &from); 756 /* Expand LCONVPATHCREATE so that `from' can be freed on errors */ 757 error = linux_emul_convpath(td, args->to, UIO_USERSPACE, &to, 1, AT_FDCWD); 758 if (to == NULL) { 759 LFREEPATH(from); 760 return (error); 761 } 762 763 #ifdef DEBUG 764 if (ldebug(rename)) 765 printf(ARGS(rename, "%s, %s"), from, to); 766 #endif 767 error = kern_renameat(td, AT_FDCWD, from, AT_FDCWD, to, UIO_SYSSPACE); 768 LFREEPATH(from); 769 LFREEPATH(to); 770 return (error); 771 } 772 #endif 773 774 int 775 linux_renameat(struct thread *td, struct linux_renameat_args *args) 776 { 777 char *from, *to; 778 int error, olddfd, newdfd; 779 780 olddfd = (args->olddfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->olddfd; 781 newdfd = (args->newdfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->newdfd; 782 LCONVPATHEXIST_AT(td, args->oldname, &from, olddfd); 783 /* Expand LCONVPATHCREATE so that `from' can be freed on errors */ 784 error = linux_emul_convpath(td, args->newname, UIO_USERSPACE, &to, 1, newdfd); 785 if (to == NULL) { 786 LFREEPATH(from); 787 return (error); 788 } 789 790 #ifdef DEBUG 791 if (ldebug(renameat)) 792 printf(ARGS(renameat, "%s, %s"), from, to); 793 #endif 794 error = kern_renameat(td, olddfd, from, newdfd, to, UIO_SYSSPACE); 795 LFREEPATH(from); 796 LFREEPATH(to); 797 return (error); 798 } 799 800 #ifdef LINUX_LEGACY_SYSCALLS 801 int 802 linux_symlink(struct thread *td, struct linux_symlink_args *args) 803 { 804 char *path, *to; 805 int error; 806 807 LCONVPATHEXIST(td, args->path, &path); 808 /* Expand LCONVPATHCREATE so that `path' can be freed on errors */ 809 error = linux_emul_convpath(td, args->to, UIO_USERSPACE, &to, 1, AT_FDCWD); 810 if (to == NULL) { 811 LFREEPATH(path); 812 return (error); 813 } 814 815 #ifdef DEBUG 816 if (ldebug(symlink)) 817 printf(ARGS(symlink, "%s, %s"), path, to); 818 #endif 819 error = kern_symlinkat(td, path, AT_FDCWD, to, UIO_SYSSPACE); 820 LFREEPATH(path); 821 LFREEPATH(to); 822 return (error); 823 } 824 #endif 825 826 int 827 linux_symlinkat(struct thread *td, struct linux_symlinkat_args *args) 828 { 829 char *path, *to; 830 int error, dfd; 831 832 dfd = (args->newdfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->newdfd; 833 LCONVPATHEXIST(td, args->oldname, &path); 834 /* Expand LCONVPATHCREATE so that `path' can be freed on errors */ 835 error = linux_emul_convpath(td, args->newname, UIO_USERSPACE, &to, 1, dfd); 836 if (to == NULL) { 837 LFREEPATH(path); 838 return (error); 839 } 840 841 #ifdef DEBUG 842 if (ldebug(symlinkat)) 843 printf(ARGS(symlinkat, "%s, %s"), path, to); 844 #endif 845 846 error = kern_symlinkat(td, path, dfd, to, UIO_SYSSPACE); 847 LFREEPATH(path); 848 LFREEPATH(to); 849 return (error); 850 } 851 852 #ifdef LINUX_LEGACY_SYSCALLS 853 int 854 linux_readlink(struct thread *td, struct linux_readlink_args *args) 855 { 856 char *name; 857 int error; 858 859 LCONVPATHEXIST(td, args->name, &name); 860 861 #ifdef DEBUG 862 if (ldebug(readlink)) 863 printf(ARGS(readlink, "%s, %p, %d"), name, (void *)args->buf, 864 args->count); 865 #endif 866 error = kern_readlinkat(td, AT_FDCWD, name, UIO_SYSSPACE, 867 args->buf, UIO_USERSPACE, args->count); 868 LFREEPATH(name); 869 return (error); 870 } 871 #endif 872 873 int 874 linux_readlinkat(struct thread *td, struct linux_readlinkat_args *args) 875 { 876 char *name; 877 int error, dfd; 878 879 dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd; 880 LCONVPATHEXIST_AT(td, args->path, &name, dfd); 881 882 #ifdef DEBUG 883 if (ldebug(readlinkat)) 884 printf(ARGS(readlinkat, "%s, %p, %d"), name, (void *)args->buf, 885 args->bufsiz); 886 #endif 887 888 error = kern_readlinkat(td, dfd, name, UIO_SYSSPACE, args->buf, 889 UIO_USERSPACE, args->bufsiz); 890 LFREEPATH(name); 891 return (error); 892 } 893 894 int 895 linux_truncate(struct thread *td, struct linux_truncate_args *args) 896 { 897 char *path; 898 int error; 899 900 LCONVPATHEXIST(td, args->path, &path); 901 902 #ifdef DEBUG 903 if (ldebug(truncate)) 904 printf(ARGS(truncate, "%s, %ld"), path, (long)args->length); 905 #endif 906 907 error = kern_truncate(td, path, UIO_SYSSPACE, args->length); 908 LFREEPATH(path); 909 return (error); 910 } 911 912 #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) 913 int 914 linux_truncate64(struct thread *td, struct linux_truncate64_args *args) 915 { 916 char *path; 917 int error; 918 919 LCONVPATHEXIST(td, args->path, &path); 920 921 #ifdef DEBUG 922 if (ldebug(truncate64)) 923 printf(ARGS(truncate64, "%s, %jd"), path, args->length); 924 #endif 925 926 error = kern_truncate(td, path, UIO_SYSSPACE, args->length); 927 LFREEPATH(path); 928 return (error); 929 } 930 #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ 931 932 int 933 linux_ftruncate(struct thread *td, struct linux_ftruncate_args *args) 934 { 935 936 return (kern_ftruncate(td, args->fd, args->length)); 937 } 938 939 #ifdef LINUX_LEGACY_SYSCALLS 940 int 941 linux_link(struct thread *td, struct linux_link_args *args) 942 { 943 char *path, *to; 944 int error; 945 946 LCONVPATHEXIST(td, args->path, &path); 947 /* Expand LCONVPATHCREATE so that `path' can be freed on errors */ 948 error = linux_emul_convpath(td, args->to, UIO_USERSPACE, &to, 1, AT_FDCWD); 949 if (to == NULL) { 950 LFREEPATH(path); 951 return (error); 952 } 953 954 #ifdef DEBUG 955 if (ldebug(link)) 956 printf(ARGS(link, "%s, %s"), path, to); 957 #endif 958 error = kern_linkat(td, AT_FDCWD, AT_FDCWD, path, to, UIO_SYSSPACE, 959 FOLLOW); 960 LFREEPATH(path); 961 LFREEPATH(to); 962 return (error); 963 } 964 #endif 965 966 int 967 linux_linkat(struct thread *td, struct linux_linkat_args *args) 968 { 969 char *path, *to; 970 int error, olddfd, newdfd, follow; 971 972 if (args->flag & ~LINUX_AT_SYMLINK_FOLLOW) 973 return (EINVAL); 974 975 olddfd = (args->olddfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->olddfd; 976 newdfd = (args->newdfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->newdfd; 977 LCONVPATHEXIST_AT(td, args->oldname, &path, olddfd); 978 /* Expand LCONVPATHCREATE so that `path' can be freed on errors */ 979 error = linux_emul_convpath(td, args->newname, UIO_USERSPACE, &to, 1, newdfd); 980 if (to == NULL) { 981 LFREEPATH(path); 982 return (error); 983 } 984 985 #ifdef DEBUG 986 if (ldebug(linkat)) 987 printf(ARGS(linkat, "%i, %s, %i, %s, %i"), args->olddfd, path, 988 args->newdfd, to, args->flag); 989 #endif 990 991 follow = (args->flag & LINUX_AT_SYMLINK_FOLLOW) == 0 ? NOFOLLOW : 992 FOLLOW; 993 error = kern_linkat(td, olddfd, newdfd, path, to, UIO_SYSSPACE, follow); 994 LFREEPATH(path); 995 LFREEPATH(to); 996 return (error); 997 } 998 999 int 1000 linux_fdatasync(td, uap) 1001 struct thread *td; 1002 struct linux_fdatasync_args *uap; 1003 { 1004 1005 return (kern_fsync(td, uap->fd, false)); 1006 } 1007 1008 int 1009 linux_pread(struct thread *td, struct linux_pread_args *uap) 1010 { 1011 struct vnode *vp; 1012 int error; 1013 1014 error = kern_pread(td, uap->fd, uap->buf, uap->nbyte, uap->offset); 1015 if (error == 0) { 1016 /* This seems to violate POSIX but Linux does it. */ 1017 error = fgetvp(td, uap->fd, &cap_pread_rights, &vp); 1018 if (error != 0) 1019 return (error); 1020 if (vp->v_type == VDIR) { 1021 vrele(vp); 1022 return (EISDIR); 1023 } 1024 vrele(vp); 1025 } 1026 return (error); 1027 } 1028 1029 int 1030 linux_pwrite(struct thread *td, struct linux_pwrite_args *uap) 1031 { 1032 1033 return (kern_pwrite(td, uap->fd, uap->buf, uap->nbyte, uap->offset)); 1034 } 1035 1036 int 1037 linux_preadv(struct thread *td, struct linux_preadv_args *uap) 1038 { 1039 struct uio *auio; 1040 int error; 1041 off_t offset; 1042 1043 /* 1044 * According http://man7.org/linux/man-pages/man2/preadv.2.html#NOTES 1045 * pos_l and pos_h, respectively, contain the 1046 * low order and high order 32 bits of offset. 1047 */ 1048 offset = (((off_t)uap->pos_h << (sizeof(offset) * 4)) << 1049 (sizeof(offset) * 4)) | uap->pos_l; 1050 if (offset < 0) 1051 return (EINVAL); 1052 #ifdef COMPAT_LINUX32 1053 error = linux32_copyinuio(PTRIN(uap->vec), uap->vlen, &auio); 1054 #else 1055 error = copyinuio(uap->vec, uap->vlen, &auio); 1056 #endif 1057 if (error != 0) 1058 return (error); 1059 error = kern_preadv(td, uap->fd, auio, offset); 1060 free(auio, M_IOV); 1061 return (error); 1062 } 1063 1064 int 1065 linux_pwritev(struct thread *td, struct linux_pwritev_args *uap) 1066 { 1067 struct uio *auio; 1068 int error; 1069 off_t offset; 1070 1071 /* 1072 * According http://man7.org/linux/man-pages/man2/pwritev.2.html#NOTES 1073 * pos_l and pos_h, respectively, contain the 1074 * low order and high order 32 bits of offset. 1075 */ 1076 offset = (((off_t)uap->pos_h << (sizeof(offset) * 4)) << 1077 (sizeof(offset) * 4)) | uap->pos_l; 1078 if (offset < 0) 1079 return (EINVAL); 1080 #ifdef COMPAT_LINUX32 1081 error = linux32_copyinuio(PTRIN(uap->vec), uap->vlen, &auio); 1082 #else 1083 error = copyinuio(uap->vec, uap->vlen, &auio); 1084 #endif 1085 if (error != 0) 1086 return (error); 1087 error = kern_pwritev(td, uap->fd, auio, offset); 1088 free(auio, M_IOV); 1089 return (error); 1090 } 1091 1092 int 1093 linux_mount(struct thread *td, struct linux_mount_args *args) 1094 { 1095 char fstypename[MFSNAMELEN]; 1096 char *mntonname, *mntfromname; 1097 int error, fsflags; 1098 1099 mntonname = malloc(MNAMELEN, M_TEMP, M_WAITOK); 1100 mntfromname = malloc(MNAMELEN, M_TEMP, M_WAITOK); 1101 error = copyinstr(args->filesystemtype, fstypename, MFSNAMELEN - 1, 1102 NULL); 1103 if (error != 0) 1104 goto out; 1105 error = copyinstr(args->specialfile, mntfromname, MNAMELEN - 1, NULL); 1106 if (error != 0) 1107 goto out; 1108 error = copyinstr(args->dir, mntonname, MNAMELEN - 1, NULL); 1109 if (error != 0) 1110 goto out; 1111 1112 #ifdef DEBUG 1113 if (ldebug(mount)) 1114 printf(ARGS(mount, "%s, %s, %s"), 1115 fstypename, mntfromname, mntonname); 1116 #endif 1117 1118 if (strcmp(fstypename, "ext2") == 0) { 1119 strcpy(fstypename, "ext2fs"); 1120 } else if (strcmp(fstypename, "proc") == 0) { 1121 strcpy(fstypename, "linprocfs"); 1122 } else if (strcmp(fstypename, "vfat") == 0) { 1123 strcpy(fstypename, "msdosfs"); 1124 } 1125 1126 fsflags = 0; 1127 1128 if ((args->rwflag & 0xffff0000) == 0xc0ed0000) { 1129 /* 1130 * Linux SYNC flag is not included; the closest equivalent 1131 * FreeBSD has is !ASYNC, which is our default. 1132 */ 1133 if (args->rwflag & LINUX_MS_RDONLY) 1134 fsflags |= MNT_RDONLY; 1135 if (args->rwflag & LINUX_MS_NOSUID) 1136 fsflags |= MNT_NOSUID; 1137 if (args->rwflag & LINUX_MS_NOEXEC) 1138 fsflags |= MNT_NOEXEC; 1139 if (args->rwflag & LINUX_MS_REMOUNT) 1140 fsflags |= MNT_UPDATE; 1141 } 1142 1143 error = kernel_vmount(fsflags, 1144 "fstype", fstypename, 1145 "fspath", mntonname, 1146 "from", mntfromname, 1147 NULL); 1148 out: 1149 free(mntonname, M_TEMP); 1150 free(mntfromname, M_TEMP); 1151 return (error); 1152 } 1153 1154 #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) 1155 int 1156 linux_oldumount(struct thread *td, struct linux_oldumount_args *args) 1157 { 1158 struct linux_umount_args args2; 1159 1160 args2.path = args->path; 1161 args2.flags = 0; 1162 return (linux_umount(td, &args2)); 1163 } 1164 #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ 1165 1166 #ifdef LINUX_LEGACY_SYSCALLS 1167 int 1168 linux_umount(struct thread *td, struct linux_umount_args *args) 1169 { 1170 struct unmount_args bsd; 1171 1172 bsd.path = args->path; 1173 bsd.flags = args->flags; /* XXX correct? */ 1174 return (sys_unmount(td, &bsd)); 1175 } 1176 #endif 1177 1178 /* 1179 * fcntl family of syscalls 1180 */ 1181 1182 struct l_flock { 1183 l_short l_type; 1184 l_short l_whence; 1185 l_off_t l_start; 1186 l_off_t l_len; 1187 l_pid_t l_pid; 1188 } 1189 #if defined(__amd64__) && defined(COMPAT_LINUX32) 1190 __packed 1191 #endif 1192 ; 1193 1194 static void 1195 linux_to_bsd_flock(struct l_flock *linux_flock, struct flock *bsd_flock) 1196 { 1197 switch (linux_flock->l_type) { 1198 case LINUX_F_RDLCK: 1199 bsd_flock->l_type = F_RDLCK; 1200 break; 1201 case LINUX_F_WRLCK: 1202 bsd_flock->l_type = F_WRLCK; 1203 break; 1204 case LINUX_F_UNLCK: 1205 bsd_flock->l_type = F_UNLCK; 1206 break; 1207 default: 1208 bsd_flock->l_type = -1; 1209 break; 1210 } 1211 bsd_flock->l_whence = linux_flock->l_whence; 1212 bsd_flock->l_start = (off_t)linux_flock->l_start; 1213 bsd_flock->l_len = (off_t)linux_flock->l_len; 1214 bsd_flock->l_pid = (pid_t)linux_flock->l_pid; 1215 bsd_flock->l_sysid = 0; 1216 } 1217 1218 static void 1219 bsd_to_linux_flock(struct flock *bsd_flock, struct l_flock *linux_flock) 1220 { 1221 switch (bsd_flock->l_type) { 1222 case F_RDLCK: 1223 linux_flock->l_type = LINUX_F_RDLCK; 1224 break; 1225 case F_WRLCK: 1226 linux_flock->l_type = LINUX_F_WRLCK; 1227 break; 1228 case F_UNLCK: 1229 linux_flock->l_type = LINUX_F_UNLCK; 1230 break; 1231 } 1232 linux_flock->l_whence = bsd_flock->l_whence; 1233 linux_flock->l_start = (l_off_t)bsd_flock->l_start; 1234 linux_flock->l_len = (l_off_t)bsd_flock->l_len; 1235 linux_flock->l_pid = (l_pid_t)bsd_flock->l_pid; 1236 } 1237 1238 #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) 1239 struct l_flock64 { 1240 l_short l_type; 1241 l_short l_whence; 1242 l_loff_t l_start; 1243 l_loff_t l_len; 1244 l_pid_t l_pid; 1245 } 1246 #if defined(__amd64__) && defined(COMPAT_LINUX32) 1247 __packed 1248 #endif 1249 ; 1250 1251 static void 1252 linux_to_bsd_flock64(struct l_flock64 *linux_flock, struct flock *bsd_flock) 1253 { 1254 switch (linux_flock->l_type) { 1255 case LINUX_F_RDLCK: 1256 bsd_flock->l_type = F_RDLCK; 1257 break; 1258 case LINUX_F_WRLCK: 1259 bsd_flock->l_type = F_WRLCK; 1260 break; 1261 case LINUX_F_UNLCK: 1262 bsd_flock->l_type = F_UNLCK; 1263 break; 1264 default: 1265 bsd_flock->l_type = -1; 1266 break; 1267 } 1268 bsd_flock->l_whence = linux_flock->l_whence; 1269 bsd_flock->l_start = (off_t)linux_flock->l_start; 1270 bsd_flock->l_len = (off_t)linux_flock->l_len; 1271 bsd_flock->l_pid = (pid_t)linux_flock->l_pid; 1272 bsd_flock->l_sysid = 0; 1273 } 1274 1275 static void 1276 bsd_to_linux_flock64(struct flock *bsd_flock, struct l_flock64 *linux_flock) 1277 { 1278 switch (bsd_flock->l_type) { 1279 case F_RDLCK: 1280 linux_flock->l_type = LINUX_F_RDLCK; 1281 break; 1282 case F_WRLCK: 1283 linux_flock->l_type = LINUX_F_WRLCK; 1284 break; 1285 case F_UNLCK: 1286 linux_flock->l_type = LINUX_F_UNLCK; 1287 break; 1288 } 1289 linux_flock->l_whence = bsd_flock->l_whence; 1290 linux_flock->l_start = (l_loff_t)bsd_flock->l_start; 1291 linux_flock->l_len = (l_loff_t)bsd_flock->l_len; 1292 linux_flock->l_pid = (l_pid_t)bsd_flock->l_pid; 1293 } 1294 #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ 1295 1296 static int 1297 fcntl_common(struct thread *td, struct linux_fcntl_args *args) 1298 { 1299 struct l_flock linux_flock; 1300 struct flock bsd_flock; 1301 struct file *fp; 1302 long arg; 1303 int error, result; 1304 1305 switch (args->cmd) { 1306 case LINUX_F_DUPFD: 1307 return (kern_fcntl(td, args->fd, F_DUPFD, args->arg)); 1308 1309 case LINUX_F_GETFD: 1310 return (kern_fcntl(td, args->fd, F_GETFD, 0)); 1311 1312 case LINUX_F_SETFD: 1313 return (kern_fcntl(td, args->fd, F_SETFD, args->arg)); 1314 1315 case LINUX_F_GETFL: 1316 error = kern_fcntl(td, args->fd, F_GETFL, 0); 1317 result = td->td_retval[0]; 1318 td->td_retval[0] = 0; 1319 if (result & O_RDONLY) 1320 td->td_retval[0] |= LINUX_O_RDONLY; 1321 if (result & O_WRONLY) 1322 td->td_retval[0] |= LINUX_O_WRONLY; 1323 if (result & O_RDWR) 1324 td->td_retval[0] |= LINUX_O_RDWR; 1325 if (result & O_NDELAY) 1326 td->td_retval[0] |= LINUX_O_NONBLOCK; 1327 if (result & O_APPEND) 1328 td->td_retval[0] |= LINUX_O_APPEND; 1329 if (result & O_FSYNC) 1330 td->td_retval[0] |= LINUX_O_SYNC; 1331 if (result & O_ASYNC) 1332 td->td_retval[0] |= LINUX_FASYNC; 1333 #ifdef LINUX_O_NOFOLLOW 1334 if (result & O_NOFOLLOW) 1335 td->td_retval[0] |= LINUX_O_NOFOLLOW; 1336 #endif 1337 #ifdef LINUX_O_DIRECT 1338 if (result & O_DIRECT) 1339 td->td_retval[0] |= LINUX_O_DIRECT; 1340 #endif 1341 return (error); 1342 1343 case LINUX_F_SETFL: 1344 arg = 0; 1345 if (args->arg & LINUX_O_NDELAY) 1346 arg |= O_NONBLOCK; 1347 if (args->arg & LINUX_O_APPEND) 1348 arg |= O_APPEND; 1349 if (args->arg & LINUX_O_SYNC) 1350 arg |= O_FSYNC; 1351 if (args->arg & LINUX_FASYNC) 1352 arg |= O_ASYNC; 1353 #ifdef LINUX_O_NOFOLLOW 1354 if (args->arg & LINUX_O_NOFOLLOW) 1355 arg |= O_NOFOLLOW; 1356 #endif 1357 #ifdef LINUX_O_DIRECT 1358 if (args->arg & LINUX_O_DIRECT) 1359 arg |= O_DIRECT; 1360 #endif 1361 return (kern_fcntl(td, args->fd, F_SETFL, arg)); 1362 1363 case LINUX_F_GETLK: 1364 error = copyin((void *)args->arg, &linux_flock, 1365 sizeof(linux_flock)); 1366 if (error) 1367 return (error); 1368 linux_to_bsd_flock(&linux_flock, &bsd_flock); 1369 error = kern_fcntl(td, args->fd, F_GETLK, (intptr_t)&bsd_flock); 1370 if (error) 1371 return (error); 1372 bsd_to_linux_flock(&bsd_flock, &linux_flock); 1373 return (copyout(&linux_flock, (void *)args->arg, 1374 sizeof(linux_flock))); 1375 1376 case LINUX_F_SETLK: 1377 error = copyin((void *)args->arg, &linux_flock, 1378 sizeof(linux_flock)); 1379 if (error) 1380 return (error); 1381 linux_to_bsd_flock(&linux_flock, &bsd_flock); 1382 return (kern_fcntl(td, args->fd, F_SETLK, 1383 (intptr_t)&bsd_flock)); 1384 1385 case LINUX_F_SETLKW: 1386 error = copyin((void *)args->arg, &linux_flock, 1387 sizeof(linux_flock)); 1388 if (error) 1389 return (error); 1390 linux_to_bsd_flock(&linux_flock, &bsd_flock); 1391 return (kern_fcntl(td, args->fd, F_SETLKW, 1392 (intptr_t)&bsd_flock)); 1393 1394 case LINUX_F_GETOWN: 1395 return (kern_fcntl(td, args->fd, F_GETOWN, 0)); 1396 1397 case LINUX_F_SETOWN: 1398 /* 1399 * XXX some Linux applications depend on F_SETOWN having no 1400 * significant effect for pipes (SIGIO is not delivered for 1401 * pipes under Linux-2.2.35 at least). 1402 */ 1403 error = fget(td, args->fd, 1404 &cap_fcntl_rights, &fp); 1405 if (error) 1406 return (error); 1407 if (fp->f_type == DTYPE_PIPE) { 1408 fdrop(fp, td); 1409 return (EINVAL); 1410 } 1411 fdrop(fp, td); 1412 1413 return (kern_fcntl(td, args->fd, F_SETOWN, args->arg)); 1414 1415 case LINUX_F_DUPFD_CLOEXEC: 1416 return (kern_fcntl(td, args->fd, F_DUPFD_CLOEXEC, args->arg)); 1417 } 1418 1419 return (EINVAL); 1420 } 1421 1422 int 1423 linux_fcntl(struct thread *td, struct linux_fcntl_args *args) 1424 { 1425 1426 #ifdef DEBUG 1427 if (ldebug(fcntl)) 1428 printf(ARGS(fcntl, "%d, %08x, *"), args->fd, args->cmd); 1429 #endif 1430 1431 return (fcntl_common(td, args)); 1432 } 1433 1434 #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) 1435 int 1436 linux_fcntl64(struct thread *td, struct linux_fcntl64_args *args) 1437 { 1438 struct l_flock64 linux_flock; 1439 struct flock bsd_flock; 1440 struct linux_fcntl_args fcntl_args; 1441 int error; 1442 1443 #ifdef DEBUG 1444 if (ldebug(fcntl64)) 1445 printf(ARGS(fcntl64, "%d, %08x, *"), args->fd, args->cmd); 1446 #endif 1447 1448 switch (args->cmd) { 1449 case LINUX_F_GETLK64: 1450 error = copyin((void *)args->arg, &linux_flock, 1451 sizeof(linux_flock)); 1452 if (error) 1453 return (error); 1454 linux_to_bsd_flock64(&linux_flock, &bsd_flock); 1455 error = kern_fcntl(td, args->fd, F_GETLK, (intptr_t)&bsd_flock); 1456 if (error) 1457 return (error); 1458 bsd_to_linux_flock64(&bsd_flock, &linux_flock); 1459 return (copyout(&linux_flock, (void *)args->arg, 1460 sizeof(linux_flock))); 1461 1462 case LINUX_F_SETLK64: 1463 error = copyin((void *)args->arg, &linux_flock, 1464 sizeof(linux_flock)); 1465 if (error) 1466 return (error); 1467 linux_to_bsd_flock64(&linux_flock, &bsd_flock); 1468 return (kern_fcntl(td, args->fd, F_SETLK, 1469 (intptr_t)&bsd_flock)); 1470 1471 case LINUX_F_SETLKW64: 1472 error = copyin((void *)args->arg, &linux_flock, 1473 sizeof(linux_flock)); 1474 if (error) 1475 return (error); 1476 linux_to_bsd_flock64(&linux_flock, &bsd_flock); 1477 return (kern_fcntl(td, args->fd, F_SETLKW, 1478 (intptr_t)&bsd_flock)); 1479 } 1480 1481 fcntl_args.fd = args->fd; 1482 fcntl_args.cmd = args->cmd; 1483 fcntl_args.arg = args->arg; 1484 return (fcntl_common(td, &fcntl_args)); 1485 } 1486 #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ 1487 1488 #ifdef LINUX_LEGACY_SYSCALLS 1489 int 1490 linux_chown(struct thread *td, struct linux_chown_args *args) 1491 { 1492 char *path; 1493 int error; 1494 1495 LCONVPATHEXIST(td, args->path, &path); 1496 1497 #ifdef DEBUG 1498 if (ldebug(chown)) 1499 printf(ARGS(chown, "%s, %d, %d"), path, args->uid, args->gid); 1500 #endif 1501 error = kern_fchownat(td, AT_FDCWD, path, UIO_SYSSPACE, args->uid, 1502 args->gid, 0); 1503 LFREEPATH(path); 1504 return (error); 1505 } 1506 #endif 1507 1508 int 1509 linux_fchownat(struct thread *td, struct linux_fchownat_args *args) 1510 { 1511 char *path; 1512 int error, dfd, flag; 1513 1514 if (args->flag & ~LINUX_AT_SYMLINK_NOFOLLOW) 1515 return (EINVAL); 1516 1517 dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd; 1518 LCONVPATHEXIST_AT(td, args->filename, &path, dfd); 1519 1520 #ifdef DEBUG 1521 if (ldebug(fchownat)) 1522 printf(ARGS(fchownat, "%s, %d, %d"), path, args->uid, args->gid); 1523 #endif 1524 1525 flag = (args->flag & LINUX_AT_SYMLINK_NOFOLLOW) == 0 ? 0 : 1526 AT_SYMLINK_NOFOLLOW; 1527 error = kern_fchownat(td, dfd, path, UIO_SYSSPACE, args->uid, args->gid, 1528 flag); 1529 LFREEPATH(path); 1530 return (error); 1531 } 1532 1533 #ifdef LINUX_LEGACY_SYSCALLS 1534 int 1535 linux_lchown(struct thread *td, struct linux_lchown_args *args) 1536 { 1537 char *path; 1538 int error; 1539 1540 LCONVPATHEXIST(td, args->path, &path); 1541 1542 #ifdef DEBUG 1543 if (ldebug(lchown)) 1544 printf(ARGS(lchown, "%s, %d, %d"), path, args->uid, args->gid); 1545 #endif 1546 error = kern_fchownat(td, AT_FDCWD, path, UIO_SYSSPACE, args->uid, 1547 args->gid, AT_SYMLINK_NOFOLLOW); 1548 LFREEPATH(path); 1549 return (error); 1550 } 1551 #endif 1552 1553 static int 1554 convert_fadvice(int advice) 1555 { 1556 switch (advice) { 1557 case LINUX_POSIX_FADV_NORMAL: 1558 return (POSIX_FADV_NORMAL); 1559 case LINUX_POSIX_FADV_RANDOM: 1560 return (POSIX_FADV_RANDOM); 1561 case LINUX_POSIX_FADV_SEQUENTIAL: 1562 return (POSIX_FADV_SEQUENTIAL); 1563 case LINUX_POSIX_FADV_WILLNEED: 1564 return (POSIX_FADV_WILLNEED); 1565 case LINUX_POSIX_FADV_DONTNEED: 1566 return (POSIX_FADV_DONTNEED); 1567 case LINUX_POSIX_FADV_NOREUSE: 1568 return (POSIX_FADV_NOREUSE); 1569 default: 1570 return (-1); 1571 } 1572 } 1573 1574 int 1575 linux_fadvise64(struct thread *td, struct linux_fadvise64_args *args) 1576 { 1577 int advice; 1578 1579 advice = convert_fadvice(args->advice); 1580 if (advice == -1) 1581 return (EINVAL); 1582 return (kern_posix_fadvise(td, args->fd, args->offset, args->len, 1583 advice)); 1584 } 1585 1586 #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) 1587 int 1588 linux_fadvise64_64(struct thread *td, struct linux_fadvise64_64_args *args) 1589 { 1590 int advice; 1591 1592 advice = convert_fadvice(args->advice); 1593 if (advice == -1) 1594 return (EINVAL); 1595 return (kern_posix_fadvise(td, args->fd, args->offset, args->len, 1596 advice)); 1597 } 1598 #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ 1599 1600 #ifdef LINUX_LEGACY_SYSCALLS 1601 int 1602 linux_pipe(struct thread *td, struct linux_pipe_args *args) 1603 { 1604 int fildes[2]; 1605 int error; 1606 1607 #ifdef DEBUG 1608 if (ldebug(pipe)) 1609 printf(ARGS(pipe, "*")); 1610 #endif 1611 1612 error = kern_pipe(td, fildes, 0, NULL, NULL); 1613 if (error != 0) 1614 return (error); 1615 1616 error = copyout(fildes, args->pipefds, sizeof(fildes)); 1617 if (error != 0) { 1618 (void)kern_close(td, fildes[0]); 1619 (void)kern_close(td, fildes[1]); 1620 } 1621 1622 return (error); 1623 } 1624 #endif 1625 1626 int 1627 linux_pipe2(struct thread *td, struct linux_pipe2_args *args) 1628 { 1629 int fildes[2]; 1630 int error, flags; 1631 1632 #ifdef DEBUG 1633 if (ldebug(pipe2)) 1634 printf(ARGS(pipe2, "*, %d"), args->flags); 1635 #endif 1636 1637 if ((args->flags & ~(LINUX_O_NONBLOCK | LINUX_O_CLOEXEC)) != 0) 1638 return (EINVAL); 1639 1640 flags = 0; 1641 if ((args->flags & LINUX_O_NONBLOCK) != 0) 1642 flags |= O_NONBLOCK; 1643 if ((args->flags & LINUX_O_CLOEXEC) != 0) 1644 flags |= O_CLOEXEC; 1645 error = kern_pipe(td, fildes, flags, NULL, NULL); 1646 if (error != 0) 1647 return (error); 1648 1649 error = copyout(fildes, args->pipefds, sizeof(fildes)); 1650 if (error != 0) { 1651 (void)kern_close(td, fildes[0]); 1652 (void)kern_close(td, fildes[1]); 1653 } 1654 1655 return (error); 1656 } 1657 1658 int 1659 linux_dup3(struct thread *td, struct linux_dup3_args *args) 1660 { 1661 int cmd; 1662 intptr_t newfd; 1663 1664 if (args->oldfd == args->newfd) 1665 return (EINVAL); 1666 if ((args->flags & ~LINUX_O_CLOEXEC) != 0) 1667 return (EINVAL); 1668 if (args->flags & LINUX_O_CLOEXEC) 1669 cmd = F_DUP2FD_CLOEXEC; 1670 else 1671 cmd = F_DUP2FD; 1672 1673 newfd = args->newfd; 1674 return (kern_fcntl(td, args->oldfd, cmd, newfd)); 1675 } 1676 1677 int 1678 linux_fallocate(struct thread *td, struct linux_fallocate_args *args) 1679 { 1680 1681 /* 1682 * We emulate only posix_fallocate system call for which 1683 * mode should be 0. 1684 */ 1685 if (args->mode != 0) 1686 return (ENOSYS); 1687 1688 return (kern_posix_fallocate(td, args->fd, args->offset, 1689 args->len)); 1690 } 1691