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