linux_file.c revision 178439
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: head/sys/compat/linux/linux_file.c 178439 2008-04-23 15:56:33Z rdivacky $"); 31 32#include "opt_compat.h" 33#include "opt_mac.h" 34 35#include <sys/param.h> 36#include <sys/systm.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#include <ufs/ufs/extattr.h> 59#include <ufs/ufs/quota.h> 60#include <ufs/ufs/ufsmount.h> 61 62#ifdef COMPAT_LINUX32 63#include <machine/../linux32/linux.h> 64#include <machine/../linux32/linux32_proto.h> 65#else 66#include <machine/../linux/linux.h> 67#include <machine/../linux/linux_proto.h> 68#endif 69#include <compat/linux/linux_util.h> 70#include <compat/linux/linux_file.h> 71 72int 73linux_creat(struct thread *td, struct linux_creat_args *args) 74{ 75 char *path; 76 int error; 77 78 LCONVPATHEXIST(td, args->path, &path); 79 80#ifdef DEBUG 81 if (ldebug(creat)) 82 printf(ARGS(creat, "%s, %d"), path, args->mode); 83#endif 84 error = kern_open(td, path, UIO_SYSSPACE, O_WRONLY | O_CREAT | O_TRUNC, 85 args->mode); 86 LFREEPATH(path); 87 return (error); 88} 89 90 91static int 92linux_common_open(struct thread *td, int dirfd, char *path, int l_flags, int mode) 93{ 94 struct proc *p = td->td_proc; 95 struct file *fp; 96 int fd; 97 int bsd_flags, error; 98 99 bsd_flags = 0; 100 switch (l_flags & LINUX_O_ACCMODE) { 101 case LINUX_O_WRONLY: 102 bsd_flags |= O_WRONLY; 103 break; 104 case LINUX_O_RDWR: 105 bsd_flags |= O_RDWR; 106 break; 107 default: 108 bsd_flags |= O_RDONLY; 109 } 110 if (l_flags & LINUX_O_NDELAY) 111 bsd_flags |= O_NONBLOCK; 112 if (l_flags & LINUX_O_APPEND) 113 bsd_flags |= O_APPEND; 114 if (l_flags & LINUX_O_SYNC) 115 bsd_flags |= O_FSYNC; 116 if (l_flags & LINUX_O_NONBLOCK) 117 bsd_flags |= O_NONBLOCK; 118 if (l_flags & LINUX_FASYNC) 119 bsd_flags |= O_ASYNC; 120 if (l_flags & LINUX_O_CREAT) 121 bsd_flags |= O_CREAT; 122 if (l_flags & LINUX_O_TRUNC) 123 bsd_flags |= O_TRUNC; 124 if (l_flags & LINUX_O_EXCL) 125 bsd_flags |= O_EXCL; 126 if (l_flags & LINUX_O_NOCTTY) 127 bsd_flags |= O_NOCTTY; 128 if (l_flags & LINUX_O_DIRECT) 129 bsd_flags |= O_DIRECT; 130 if (l_flags & LINUX_O_NOFOLLOW) 131 bsd_flags |= O_NOFOLLOW; 132 /* XXX LINUX_O_NOATIME: unable to be easily implemented. */ 133 134 error = kern_openat(td, dirfd, path, UIO_SYSSPACE, bsd_flags, mode); 135 136 if (!error) { 137 fd = td->td_retval[0]; 138 /* 139 * XXX In between kern_open() and fget(), another process 140 * having the same filedesc could use that fd without 141 * checking below. 142 */ 143 error = fget(td, fd, &fp); 144 if (!error) { 145 sx_slock(&proctree_lock); 146 PROC_LOCK(p); 147 if (!(bsd_flags & O_NOCTTY) && 148 SESS_LEADER(p) && !(p->p_flag & P_CONTROLT)) { 149 PROC_UNLOCK(p); 150 sx_unlock(&proctree_lock); 151 if (fp->f_type == DTYPE_VNODE) 152 (void) fo_ioctl(fp, TIOCSCTTY, (caddr_t) 0, 153 td->td_ucred, td); 154 } else { 155 PROC_UNLOCK(p); 156 sx_sunlock(&proctree_lock); 157 } 158 if (l_flags & LINUX_O_DIRECTORY) { 159 if (fp->f_type != DTYPE_VNODE || 160 fp->f_vnode->v_type != VDIR) { 161 error = ENOTDIR; 162 } 163 } 164 fdrop(fp, td); 165 /* 166 * XXX as above, fdrop()/kern_close() pair is racy. 167 */ 168 if (error) 169 kern_close(td, fd); 170 } 171 } 172 173#ifdef DEBUG 174 if (ldebug(open)) 175 printf(LMSG("open returns error %d"), error); 176#endif 177 LFREEPATH(path); 178 return (error); 179} 180 181int 182linux_openat(struct thread *td, struct linux_openat_args *args) 183{ 184 char *path; 185 int dfd; 186 187 dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd; 188 if (args->flags & LINUX_O_CREAT) 189 LCONVPATH_AT(td, args->filename, &path, 1, dfd); 190 else 191 LCONVPATH_AT(td, args->filename, &path, 0, dfd); 192#ifdef DEBUG 193 if (ldebug(openat)) 194 printf(ARGS(openat, "%i, %s, 0x%x, 0x%x"), args->dfd, 195 path, args->flags, args->mode); 196#endif 197 return (linux_common_open(td, dfd, path, args->flags, args->mode)); 198} 199 200int 201linux_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 210#ifdef DEBUG 211 if (ldebug(open)) 212 printf(ARGS(open, "%s, 0x%x, 0x%x"), 213 path, args->flags, args->mode); 214#endif 215 216 return (linux_common_open(td, AT_FDCWD, path, args->flags, args->mode)); 217} 218 219int 220linux_lseek(struct thread *td, struct linux_lseek_args *args) 221{ 222 223 struct lseek_args /* { 224 int fd; 225 int pad; 226 off_t offset; 227 int whence; 228 } */ tmp_args; 229 int error; 230 231#ifdef DEBUG 232 if (ldebug(lseek)) 233 printf(ARGS(lseek, "%d, %ld, %d"), 234 args->fdes, (long)args->off, args->whence); 235#endif 236 tmp_args.fd = args->fdes; 237 tmp_args.offset = (off_t)args->off; 238 tmp_args.whence = args->whence; 239 error = lseek(td, &tmp_args); 240 return error; 241} 242 243int 244linux_llseek(struct thread *td, struct linux_llseek_args *args) 245{ 246 struct lseek_args bsd_args; 247 int error; 248 off_t off; 249 250#ifdef DEBUG 251 if (ldebug(llseek)) 252 printf(ARGS(llseek, "%d, %d:%d, %d"), 253 args->fd, args->ohigh, args->olow, args->whence); 254#endif 255 off = (args->olow) | (((off_t) args->ohigh) << 32); 256 257 bsd_args.fd = args->fd; 258 bsd_args.offset = off; 259 bsd_args.whence = args->whence; 260 261 if ((error = lseek(td, &bsd_args))) 262 return error; 263 264 if ((error = copyout(td->td_retval, args->res, sizeof (off_t)))) 265 return error; 266 267 td->td_retval[0] = 0; 268 return 0; 269} 270 271int 272linux_readdir(struct thread *td, struct linux_readdir_args *args) 273{ 274 struct linux_getdents_args lda; 275 276 lda.fd = args->fd; 277 lda.dent = args->dent; 278 lda.count = 1; 279 return linux_getdents(td, &lda); 280} 281 282/* 283 * Note that linux_getdents(2) and linux_getdents64(2) have the same 284 * arguments. They only differ in the definition of struct dirent they 285 * operate on. We use this to common the code, with the exception of 286 * accessing struct dirent. Note that linux_readdir(2) is implemented 287 * by means of linux_getdents(2). In this case we never operate on 288 * struct dirent64 and thus don't need to handle it... 289 */ 290 291struct l_dirent { 292 l_long d_ino; 293 l_off_t d_off; 294 l_ushort d_reclen; 295 char d_name[LINUX_NAME_MAX + 1]; 296}; 297 298struct l_dirent64 { 299 uint64_t d_ino; 300 int64_t d_off; 301 l_ushort d_reclen; 302 u_char d_type; 303 char d_name[LINUX_NAME_MAX + 1]; 304}; 305 306#define LINUX_RECLEN(de,namlen) \ 307 ALIGN((((char *)&(de)->d_name - (char *)de) + (namlen) + 1)) 308 309#define LINUX_DIRBLKSIZ 512 310 311static int 312getdents_common(struct thread *td, struct linux_getdents64_args *args, 313 int is64bit) 314{ 315 struct dirent *bdp; 316 struct vnode *vp; 317 caddr_t inp, buf; /* BSD-format */ 318 int len, reclen; /* BSD-format */ 319 caddr_t outp; /* Linux-format */ 320 int resid, linuxreclen=0; /* Linux-format */ 321 struct file *fp; 322 struct uio auio; 323 struct iovec aiov; 324 off_t off; 325 struct l_dirent linux_dirent; 326 struct l_dirent64 linux_dirent64; 327 int buflen, error, eofflag, nbytes, justone; 328 u_long *cookies = NULL, *cookiep; 329 int ncookies, vfslocked; 330 331 nbytes = args->count; 332 if (nbytes == 1) { 333 /* readdir(2) case. Always struct dirent. */ 334 if (is64bit) 335 return (EINVAL); 336 nbytes = sizeof(linux_dirent); 337 justone = 1; 338 } else 339 justone = 0; 340 341 if ((error = getvnode(td->td_proc->p_fd, args->fd, &fp)) != 0) 342 return (error); 343 344 if ((fp->f_flag & FREAD) == 0) { 345 fdrop(fp, td); 346 return (EBADF); 347 } 348 349 vp = fp->f_vnode; 350 vfslocked = VFS_LOCK_GIANT(vp->v_mount); 351 if (vp->v_type != VDIR) { 352 VFS_UNLOCK_GIANT(vfslocked); 353 fdrop(fp, td); 354 return (EINVAL); 355 } 356 357 off = fp->f_offset; 358 359 buflen = max(LINUX_DIRBLKSIZ, nbytes); 360 buflen = min(buflen, MAXBSIZE); 361 buf = malloc(buflen, M_TEMP, M_WAITOK); 362 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 363 364again: 365 aiov.iov_base = buf; 366 aiov.iov_len = buflen; 367 auio.uio_iov = &aiov; 368 auio.uio_iovcnt = 1; 369 auio.uio_rw = UIO_READ; 370 auio.uio_segflg = UIO_SYSSPACE; 371 auio.uio_td = td; 372 auio.uio_resid = buflen; 373 auio.uio_offset = off; 374 375 if (cookies) { 376 free(cookies, M_TEMP); 377 cookies = NULL; 378 } 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_RECLEN(&linux_dirent64, bdp->d_namlen) 440 : LINUX_RECLEN(&linux_dirent, 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.d_ino = (l_long)bdp->d_fileno; 450 linux_dirent.d_off = (l_off_t)linuxreclen; 451 linux_dirent.d_reclen = (l_ushort)bdp->d_namlen; 452 strcpy(linux_dirent.d_name, bdp->d_name); 453 error = copyout(&linux_dirent, outp, linuxreclen); 454 } else { 455 if (is64bit) { 456 linux_dirent64.d_ino = bdp->d_fileno; 457 linux_dirent64.d_off = (cookiep) 458 ? (l_off_t)*cookiep 459 : (l_off_t)(off + reclen); 460 linux_dirent64.d_reclen = 461 (l_ushort)linuxreclen; 462 linux_dirent64.d_type = bdp->d_type; 463 strcpy(linux_dirent64.d_name, bdp->d_name); 464 error = copyout(&linux_dirent64, outp, 465 linuxreclen); 466 } else { 467 linux_dirent.d_ino = bdp->d_fileno; 468 linux_dirent.d_off = (cookiep) 469 ? (l_off_t)*cookiep 470 : (l_off_t)(off + reclen); 471 linux_dirent.d_reclen = (l_ushort)linuxreclen; 472 strcpy(linux_dirent.d_name, bdp->d_name); 473 error = copyout(&linux_dirent, outp, 474 linuxreclen); 475 } 476 } 477 if (error) 478 goto out; 479 480 inp += reclen; 481 if (cookiep) { 482 off = *cookiep++; 483 ncookies--; 484 } else 485 off += reclen; 486 487 outp += linuxreclen; 488 resid -= linuxreclen; 489 len -= reclen; 490 if (justone) 491 break; 492 } 493 494 if (outp == (caddr_t)args->dirent) 495 goto again; 496 497 fp->f_offset = off; 498 if (justone) 499 nbytes = resid + linuxreclen; 500 501eof: 502 td->td_retval[0] = nbytes - resid; 503 504out: 505 if (cookies) 506 free(cookies, M_TEMP); 507 508 VOP_UNLOCK(vp, 0); 509 VFS_UNLOCK_GIANT(vfslocked); 510 fdrop(fp, td); 511 free(buf, M_TEMP); 512 return (error); 513} 514 515int 516linux_getdents(struct thread *td, struct linux_getdents_args *args) 517{ 518 519#ifdef DEBUG 520 if (ldebug(getdents)) 521 printf(ARGS(getdents, "%d, *, %d"), args->fd, args->count); 522#endif 523 524 return (getdents_common(td, (struct linux_getdents64_args*)args, 0)); 525} 526 527int 528linux_getdents64(struct thread *td, struct linux_getdents64_args *args) 529{ 530 531#ifdef DEBUG 532 if (ldebug(getdents64)) 533 printf(ARGS(getdents64, "%d, *, %d"), args->fd, args->count); 534#endif 535 536 return (getdents_common(td, args, 1)); 537} 538 539/* 540 * These exist mainly for hooks for doing /compat/linux translation. 541 */ 542 543int 544linux_access(struct thread *td, struct linux_access_args *args) 545{ 546 char *path; 547 int error; 548 549 /* linux convention */ 550 if (args->flags & ~(F_OK | X_OK | W_OK | R_OK)) 551 return (EINVAL); 552 553 LCONVPATHEXIST(td, args->path, &path); 554 555#ifdef DEBUG 556 if (ldebug(access)) 557 printf(ARGS(access, "%s, %d"), path, args->flags); 558#endif 559 error = kern_access(td, path, UIO_SYSSPACE, args->flags); 560 LFREEPATH(path); 561 562 return (error); 563} 564 565int 566linux_faccessat(struct thread *td, struct linux_faccessat_args *args) 567{ 568 char *path; 569 int error, dfd; 570 571 /* linux convention */ 572 if (args->mode & ~(F_OK | X_OK | W_OK | R_OK)) 573 return (EINVAL); 574 575 dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd; 576 LCONVPATHEXIST_AT(td, args->filename, &path, dfd); 577 578#ifdef DEBUG 579 if (ldebug(access)) 580 printf(ARGS(access, "%s, %d"), path, args->mode); 581#endif 582 583 error = kern_accessat(td, dfd, path, UIO_SYSSPACE, 0 /* XXX */, 584 args->mode); 585 LFREEPATH(path); 586 587 return (error); 588} 589 590int 591linux_unlink(struct thread *td, struct linux_unlink_args *args) 592{ 593 char *path; 594 int error; 595 struct stat st; 596 597 LCONVPATHEXIST(td, args->path, &path); 598 599#ifdef DEBUG 600 if (ldebug(unlink)) 601 printf(ARGS(unlink, "%s"), path); 602#endif 603 604 error = kern_unlink(td, path, UIO_SYSSPACE); 605 if (error == EPERM) 606 /* Introduce POSIX noncompliant behaviour of Linux */ 607 if (kern_stat(td, path, UIO_SYSSPACE, &st) == 0) 608 if (S_ISDIR(st.st_mode)) 609 error = EISDIR; 610 LFREEPATH(path); 611 return (error); 612} 613 614int 615linux_unlinkat(struct thread *td, struct linux_unlinkat_args *args) 616{ 617 char *path; 618 int error, dfd; 619 struct stat st; 620 621 if (args->flag & ~LINUX_AT_REMOVEDIR) 622 return (EINVAL); 623 624 dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd; 625 LCONVPATHEXIST_AT(td, args->pathname, &path, dfd); 626 627#ifdef DEBUG 628 if (ldebug(unlinkat)) 629 printf(ARGS(unlinkat, "%s"), path); 630#endif 631 632 if (args->flag & LINUX_AT_REMOVEDIR) 633 error = kern_rmdirat(td, dfd, path, UIO_SYSSPACE); 634 else 635 error = kern_unlinkat(td, dfd, path, UIO_SYSSPACE); 636 if (error == EPERM && !(args->flag & LINUX_AT_REMOVEDIR)) { 637 /* Introduce POSIX noncompliant behaviour of Linux */ 638 if (kern_statat(td, AT_SYMLINK_NOFOLLOW, dfd, path, 639 UIO_SYSSPACE, &st) == 0 && S_ISDIR(st.st_mode)) 640 error = EISDIR; 641 } 642 LFREEPATH(path); 643 return (error); 644} 645int 646linux_chdir(struct thread *td, struct linux_chdir_args *args) 647{ 648 char *path; 649 int error; 650 651 LCONVPATHEXIST(td, args->path, &path); 652 653#ifdef DEBUG 654 if (ldebug(chdir)) 655 printf(ARGS(chdir, "%s"), path); 656#endif 657 error = kern_chdir(td, path, UIO_SYSSPACE); 658 LFREEPATH(path); 659 return (error); 660} 661 662int 663linux_chmod(struct thread *td, struct linux_chmod_args *args) 664{ 665 char *path; 666 int error; 667 668 LCONVPATHEXIST(td, args->path, &path); 669 670#ifdef DEBUG 671 if (ldebug(chmod)) 672 printf(ARGS(chmod, "%s, %d"), path, args->mode); 673#endif 674 error = kern_chmod(td, path, UIO_SYSSPACE, args->mode); 675 LFREEPATH(path); 676 return (error); 677} 678 679int 680linux_fchmodat(struct thread *td, struct linux_fchmodat_args *args) 681{ 682 char *path; 683 int error, dfd; 684 685 dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd; 686 LCONVPATHEXIST_AT(td, args->filename, &path, dfd); 687 688#ifdef DEBUG 689 if (ldebug(fchmodat)) 690 printf(ARGS(fchmodat, "%s, %d"), path, args->mode); 691#endif 692 693 error = kern_fchmodat(td, dfd, path, UIO_SYSSPACE, args->mode, 0); 694 LFREEPATH(path); 695 return (error); 696} 697 698int 699linux_mkdir(struct thread *td, struct linux_mkdir_args *args) 700{ 701 char *path; 702 int error; 703 704 LCONVPATHCREAT(td, args->path, &path); 705 706#ifdef DEBUG 707 if (ldebug(mkdir)) 708 printf(ARGS(mkdir, "%s, %d"), path, args->mode); 709#endif 710 error = kern_mkdir(td, path, UIO_SYSSPACE, args->mode); 711 LFREEPATH(path); 712 return (error); 713} 714 715int 716linux_mkdirat(struct thread *td, struct linux_mkdirat_args *args) 717{ 718 char *path; 719 int error, dfd; 720 721 dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd; 722 LCONVPATHCREAT_AT(td, args->pathname, &path, dfd); 723 724#ifdef DEBUG 725 if (ldebug(mkdirat)) 726 printf(ARGS(mkdirat, "%s, %d"), path, args->mode); 727#endif 728 error = kern_mkdirat(td, dfd, path, UIO_SYSSPACE, args->mode); 729 LFREEPATH(path); 730 return (error); 731} 732 733int 734linux_rmdir(struct thread *td, struct linux_rmdir_args *args) 735{ 736 char *path; 737 int error; 738 739 LCONVPATHEXIST(td, args->path, &path); 740 741#ifdef DEBUG 742 if (ldebug(rmdir)) 743 printf(ARGS(rmdir, "%s"), path); 744#endif 745 error = kern_rmdir(td, path, UIO_SYSSPACE); 746 LFREEPATH(path); 747 return (error); 748} 749 750int 751linux_rename(struct thread *td, struct linux_rename_args *args) 752{ 753 char *from, *to; 754 int error; 755 756 LCONVPATHEXIST(td, args->from, &from); 757 /* Expand LCONVPATHCREATE so that `from' can be freed on errors */ 758 error = linux_emul_convpath(td, args->to, UIO_USERSPACE, &to, 1, AT_FDCWD); 759 if (to == NULL) { 760 LFREEPATH(from); 761 return (error); 762 } 763 764#ifdef DEBUG 765 if (ldebug(rename)) 766 printf(ARGS(rename, "%s, %s"), from, to); 767#endif 768 error = kern_rename(td, from, to, UIO_SYSSPACE); 769 LFREEPATH(from); 770 LFREEPATH(to); 771 return (error); 772} 773 774int 775linux_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 800int 801linux_symlink(struct thread *td, struct linux_symlink_args *args) 802{ 803 char *path, *to; 804 int error; 805 806 LCONVPATHEXIST(td, args->path, &path); 807 /* Expand LCONVPATHCREATE so that `path' can be freed on errors */ 808 error = linux_emul_convpath(td, args->to, UIO_USERSPACE, &to, 1, AT_FDCWD); 809 if (to == NULL) { 810 LFREEPATH(path); 811 return (error); 812 } 813 814#ifdef DEBUG 815 if (ldebug(symlink)) 816 printf(ARGS(symlink, "%s, %s"), path, to); 817#endif 818 error = kern_symlink(td, path, to, UIO_SYSSPACE); 819 LFREEPATH(path); 820 LFREEPATH(to); 821 return (error); 822} 823 824int 825linux_symlinkat(struct thread *td, struct linux_symlinkat_args *args) 826{ 827 char *path, *to; 828 int error, dfd; 829 830 dfd = (args->newdfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->newdfd; 831 LCONVPATHEXIST_AT(td, args->oldname, &path, dfd); 832 /* Expand LCONVPATHCREATE so that `path' can be freed on errors */ 833 error = linux_emul_convpath(td, args->newname, UIO_USERSPACE, &to, 1, dfd); 834 if (to == NULL) { 835 LFREEPATH(path); 836 return (error); 837 } 838 839#ifdef DEBUG 840 if (ldebug(symlinkat)) 841 printf(ARGS(symlinkat, "%s, %s"), path, to); 842#endif 843 844 error = kern_symlinkat(td, path, dfd, to, UIO_SYSSPACE); 845 LFREEPATH(path); 846 LFREEPATH(to); 847 return (error); 848} 849 850int 851linux_readlink(struct thread *td, struct linux_readlink_args *args) 852{ 853 char *name; 854 int error; 855 856 LCONVPATHEXIST(td, args->name, &name); 857 858#ifdef DEBUG 859 if (ldebug(readlink)) 860 printf(ARGS(readlink, "%s, %p, %d"), name, (void *)args->buf, 861 args->count); 862#endif 863 error = kern_readlink(td, name, UIO_SYSSPACE, args->buf, UIO_USERSPACE, 864 args->count); 865 LFREEPATH(name); 866 return (error); 867} 868 869int 870linux_readlinkat(struct thread *td, struct linux_readlinkat_args *args) 871{ 872 char *name; 873 int error, dfd; 874 875 dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd; 876 LCONVPATHEXIST_AT(td, args->path, &name, dfd); 877 878#ifdef DEBUG 879 if (ldebug(readlinkat)) 880 printf(ARGS(readlinkat, "%s, %p, %d"), name, (void *)args->buf, 881 args->bufsiz); 882#endif 883 884 error = kern_readlinkat(td, dfd, name, UIO_SYSSPACE, args->buf, 885 UIO_USERSPACE, args->bufsiz); 886 LFREEPATH(name); 887 return (error); 888} 889 890int 891linux_truncate(struct thread *td, struct linux_truncate_args *args) 892{ 893 char *path; 894 int error; 895 896 LCONVPATHEXIST(td, args->path, &path); 897 898#ifdef DEBUG 899 if (ldebug(truncate)) 900 printf(ARGS(truncate, "%s, %ld"), path, (long)args->length); 901#endif 902 903 error = kern_truncate(td, path, UIO_SYSSPACE, args->length); 904 LFREEPATH(path); 905 return (error); 906} 907 908int 909linux_truncate64(struct thread *td, struct linux_truncate64_args *args) 910{ 911 char *path; 912 int error; 913 914 LCONVPATHEXIST(td, args->path, &path); 915 916#ifdef DEBUG 917 if (ldebug(truncate64)) 918 printf(ARGS(truncate64, "%s, %jd"), path, args->length); 919#endif 920 921 error = kern_truncate(td, path, UIO_SYSSPACE, args->length); 922 LFREEPATH(path); 923 return (error); 924} 925int 926linux_ftruncate(struct thread *td, struct linux_ftruncate_args *args) 927{ 928 struct ftruncate_args /* { 929 int fd; 930 int pad; 931 off_t length; 932 } */ nuap; 933 934 nuap.fd = args->fd; 935 nuap.length = args->length; 936 return (ftruncate(td, &nuap)); 937} 938 939int 940linux_link(struct thread *td, struct linux_link_args *args) 941{ 942 char *path, *to; 943 int error; 944 945 LCONVPATHEXIST(td, args->path, &path); 946 /* Expand LCONVPATHCREATE so that `path' can be freed on errors */ 947 error = linux_emul_convpath(td, args->to, UIO_USERSPACE, &to, 1, AT_FDCWD); 948 if (to == NULL) { 949 LFREEPATH(path); 950 return (error); 951 } 952 953#ifdef DEBUG 954 if (ldebug(link)) 955 printf(ARGS(link, "%s, %s"), path, to); 956#endif 957 error = kern_link(td, path, to, UIO_SYSSPACE); 958 LFREEPATH(path); 959 LFREEPATH(to); 960 return (error); 961} 962 963int 964linux_linkat(struct thread *td, struct linux_linkat_args *args) 965{ 966 char *path, *to; 967 int error, olddfd, newdfd; 968 969 /* 970 * They really introduced flags argument which is forbidden to 971 * use. 972 */ 973 if (args->flags != 0) 974 return (EINVAL); 975 976 olddfd = (args->olddfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->olddfd; 977 newdfd = (args->newdfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->newdfd; 978 LCONVPATHEXIST_AT(td, args->oldname, &path, olddfd); 979 /* Expand LCONVPATHCREATE so that `path' can be freed on errors */ 980 error = linux_emul_convpath(td, args->newname, UIO_USERSPACE, &to, 1, newdfd); 981 if (to == NULL) { 982 LFREEPATH(path); 983 return (error); 984 } 985 986#ifdef DEBUG 987 if (ldebug(linkat)) 988 printf(ARGS(linkat, "%i, %s, %i, %s, %i"), args->olddfd, path, 989 args->newdfd, to, args->flags); 990#endif 991 992 error = kern_linkat(td, olddfd, newdfd, path, to, UIO_SYSSPACE, FOLLOW); 993 LFREEPATH(path); 994 LFREEPATH(to); 995 return (error); 996} 997 998int 999linux_fdatasync(td, uap) 1000 struct thread *td; 1001 struct linux_fdatasync_args *uap; 1002{ 1003 struct fsync_args bsd; 1004 1005 bsd.fd = uap->fd; 1006 return fsync(td, &bsd); 1007} 1008 1009int 1010linux_pread(td, uap) 1011 struct thread *td; 1012 struct linux_pread_args *uap; 1013{ 1014 struct pread_args bsd; 1015 struct vnode *vp; 1016 int error; 1017 1018 bsd.fd = uap->fd; 1019 bsd.buf = uap->buf; 1020 bsd.nbyte = uap->nbyte; 1021 bsd.offset = uap->offset; 1022 1023 error = pread(td, &bsd); 1024 1025 if (error == 0) { 1026 /* This seems to violate POSIX but linux does it */ 1027 if ((error = fgetvp(td, uap->fd, &vp)) != 0) 1028 return (error); 1029 if (vp->v_type == VDIR) { 1030 vrele(vp); 1031 return (EISDIR); 1032 } 1033 vrele(vp); 1034 } 1035 1036 return (error); 1037} 1038 1039int 1040linux_pwrite(td, uap) 1041 struct thread *td; 1042 struct linux_pwrite_args *uap; 1043{ 1044 struct pwrite_args bsd; 1045 1046 bsd.fd = uap->fd; 1047 bsd.buf = uap->buf; 1048 bsd.nbyte = uap->nbyte; 1049 bsd.offset = uap->offset; 1050 return pwrite(td, &bsd); 1051} 1052 1053int 1054linux_mount(struct thread *td, struct linux_mount_args *args) 1055{ 1056 struct ufs_args ufs; 1057 char fstypename[MFSNAMELEN]; 1058 char mntonname[MNAMELEN], mntfromname[MNAMELEN]; 1059 int error; 1060 int fsflags; 1061 void *fsdata; 1062 1063 error = copyinstr(args->filesystemtype, fstypename, MFSNAMELEN - 1, 1064 NULL); 1065 if (error) 1066 return (error); 1067 error = copyinstr(args->specialfile, mntfromname, MNAMELEN - 1, NULL); 1068 if (error) 1069 return (error); 1070 error = copyinstr(args->dir, mntonname, MNAMELEN - 1, NULL); 1071 if (error) 1072 return (error); 1073 1074#ifdef DEBUG 1075 if (ldebug(mount)) 1076 printf(ARGS(mount, "%s, %s, %s"), 1077 fstypename, mntfromname, mntonname); 1078#endif 1079 1080 if (strcmp(fstypename, "ext2") == 0) { 1081 strcpy(fstypename, "ext2fs"); 1082 fsdata = &ufs; 1083 ufs.fspec = mntfromname; 1084#define DEFAULT_ROOTID -2 1085 ufs.export.ex_root = DEFAULT_ROOTID; 1086 ufs.export.ex_flags = 1087 args->rwflag & LINUX_MS_RDONLY ? MNT_EXRDONLY : 0; 1088 } else if (strcmp(fstypename, "proc") == 0) { 1089 strcpy(fstypename, "linprocfs"); 1090 fsdata = NULL; 1091 } else { 1092 return (ENODEV); 1093 } 1094 1095 fsflags = 0; 1096 1097 if ((args->rwflag & 0xffff0000) == 0xc0ed0000) { 1098 /* 1099 * Linux SYNC flag is not included; the closest equivalent 1100 * FreeBSD has is !ASYNC, which is our default. 1101 */ 1102 if (args->rwflag & LINUX_MS_RDONLY) 1103 fsflags |= MNT_RDONLY; 1104 if (args->rwflag & LINUX_MS_NOSUID) 1105 fsflags |= MNT_NOSUID; 1106 if (args->rwflag & LINUX_MS_NOEXEC) 1107 fsflags |= MNT_NOEXEC; 1108 if (args->rwflag & LINUX_MS_REMOUNT) 1109 fsflags |= MNT_UPDATE; 1110 } 1111 1112 if (strcmp(fstypename, "linprocfs") == 0) { 1113 error = kernel_vmount(fsflags, 1114 "fstype", fstypename, 1115 "fspath", mntonname, 1116 NULL); 1117 } else 1118 error = EOPNOTSUPP; 1119 return (error); 1120} 1121 1122int 1123linux_oldumount(struct thread *td, struct linux_oldumount_args *args) 1124{ 1125 struct linux_umount_args args2; 1126 1127 args2.path = args->path; 1128 args2.flags = 0; 1129 return (linux_umount(td, &args2)); 1130} 1131 1132int 1133linux_umount(struct thread *td, struct linux_umount_args *args) 1134{ 1135 struct unmount_args bsd; 1136 1137 bsd.path = args->path; 1138 bsd.flags = args->flags; /* XXX correct? */ 1139 return (unmount(td, &bsd)); 1140} 1141 1142/* 1143 * fcntl family of syscalls 1144 */ 1145 1146struct l_flock { 1147 l_short l_type; 1148 l_short l_whence; 1149 l_off_t l_start; 1150 l_off_t l_len; 1151 l_pid_t l_pid; 1152} 1153#if defined(__amd64__) && defined(COMPAT_LINUX32) 1154__packed 1155#endif 1156; 1157 1158static void 1159linux_to_bsd_flock(struct l_flock *linux_flock, struct flock *bsd_flock) 1160{ 1161 switch (linux_flock->l_type) { 1162 case LINUX_F_RDLCK: 1163 bsd_flock->l_type = F_RDLCK; 1164 break; 1165 case LINUX_F_WRLCK: 1166 bsd_flock->l_type = F_WRLCK; 1167 break; 1168 case LINUX_F_UNLCK: 1169 bsd_flock->l_type = F_UNLCK; 1170 break; 1171 default: 1172 bsd_flock->l_type = -1; 1173 break; 1174 } 1175 bsd_flock->l_whence = linux_flock->l_whence; 1176 bsd_flock->l_start = (off_t)linux_flock->l_start; 1177 bsd_flock->l_len = (off_t)linux_flock->l_len; 1178 bsd_flock->l_pid = (pid_t)linux_flock->l_pid; 1179 bsd_flock->l_sysid = 0; 1180} 1181 1182static void 1183bsd_to_linux_flock(struct flock *bsd_flock, struct l_flock *linux_flock) 1184{ 1185 switch (bsd_flock->l_type) { 1186 case F_RDLCK: 1187 linux_flock->l_type = LINUX_F_RDLCK; 1188 break; 1189 case F_WRLCK: 1190 linux_flock->l_type = LINUX_F_WRLCK; 1191 break; 1192 case F_UNLCK: 1193 linux_flock->l_type = LINUX_F_UNLCK; 1194 break; 1195 } 1196 linux_flock->l_whence = bsd_flock->l_whence; 1197 linux_flock->l_start = (l_off_t)bsd_flock->l_start; 1198 linux_flock->l_len = (l_off_t)bsd_flock->l_len; 1199 linux_flock->l_pid = (l_pid_t)bsd_flock->l_pid; 1200} 1201 1202#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) 1203struct l_flock64 { 1204 l_short l_type; 1205 l_short l_whence; 1206 l_loff_t l_start; 1207 l_loff_t l_len; 1208 l_pid_t l_pid; 1209} 1210#if defined(__amd64__) && defined(COMPAT_LINUX32) 1211__packed 1212#endif 1213; 1214 1215static void 1216linux_to_bsd_flock64(struct l_flock64 *linux_flock, struct flock *bsd_flock) 1217{ 1218 switch (linux_flock->l_type) { 1219 case LINUX_F_RDLCK: 1220 bsd_flock->l_type = F_RDLCK; 1221 break; 1222 case LINUX_F_WRLCK: 1223 bsd_flock->l_type = F_WRLCK; 1224 break; 1225 case LINUX_F_UNLCK: 1226 bsd_flock->l_type = F_UNLCK; 1227 break; 1228 default: 1229 bsd_flock->l_type = -1; 1230 break; 1231 } 1232 bsd_flock->l_whence = linux_flock->l_whence; 1233 bsd_flock->l_start = (off_t)linux_flock->l_start; 1234 bsd_flock->l_len = (off_t)linux_flock->l_len; 1235 bsd_flock->l_pid = (pid_t)linux_flock->l_pid; 1236 bsd_flock->l_sysid = 0; 1237} 1238 1239static void 1240bsd_to_linux_flock64(struct flock *bsd_flock, struct l_flock64 *linux_flock) 1241{ 1242 switch (bsd_flock->l_type) { 1243 case F_RDLCK: 1244 linux_flock->l_type = LINUX_F_RDLCK; 1245 break; 1246 case F_WRLCK: 1247 linux_flock->l_type = LINUX_F_WRLCK; 1248 break; 1249 case F_UNLCK: 1250 linux_flock->l_type = LINUX_F_UNLCK; 1251 break; 1252 } 1253 linux_flock->l_whence = bsd_flock->l_whence; 1254 linux_flock->l_start = (l_loff_t)bsd_flock->l_start; 1255 linux_flock->l_len = (l_loff_t)bsd_flock->l_len; 1256 linux_flock->l_pid = (l_pid_t)bsd_flock->l_pid; 1257} 1258#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ 1259 1260static int 1261fcntl_common(struct thread *td, struct linux_fcntl64_args *args) 1262{ 1263 struct l_flock linux_flock; 1264 struct flock bsd_flock; 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, &fp); 1368 if (error) 1369 return (error); 1370 if (fp->f_type == DTYPE_PIPE) { 1371 fdrop(fp, td); 1372 return (EINVAL); 1373 } 1374 fdrop(fp, td); 1375 1376 return (kern_fcntl(td, args->fd, F_SETOWN, args->arg)); 1377 } 1378 1379 return (EINVAL); 1380} 1381 1382int 1383linux_fcntl(struct thread *td, struct linux_fcntl_args *args) 1384{ 1385 struct linux_fcntl64_args args64; 1386 1387#ifdef DEBUG 1388 if (ldebug(fcntl)) 1389 printf(ARGS(fcntl, "%d, %08x, *"), args->fd, args->cmd); 1390#endif 1391 1392 args64.fd = args->fd; 1393 args64.cmd = args->cmd; 1394 args64.arg = args->arg; 1395 return (fcntl_common(td, &args64)); 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 int error; 1405 1406#ifdef DEBUG 1407 if (ldebug(fcntl64)) 1408 printf(ARGS(fcntl64, "%d, %08x, *"), args->fd, args->cmd); 1409#endif 1410 1411 switch (args->cmd) { 1412 case LINUX_F_GETLK64: 1413 error = copyin((void *)args->arg, &linux_flock, 1414 sizeof(linux_flock)); 1415 if (error) 1416 return (error); 1417 linux_to_bsd_flock64(&linux_flock, &bsd_flock); 1418 error = kern_fcntl(td, args->fd, F_GETLK, (intptr_t)&bsd_flock); 1419 if (error) 1420 return (error); 1421 bsd_to_linux_flock64(&bsd_flock, &linux_flock); 1422 return (copyout(&linux_flock, (void *)args->arg, 1423 sizeof(linux_flock))); 1424 1425 case LINUX_F_SETLK64: 1426 error = copyin((void *)args->arg, &linux_flock, 1427 sizeof(linux_flock)); 1428 if (error) 1429 return (error); 1430 linux_to_bsd_flock64(&linux_flock, &bsd_flock); 1431 return (kern_fcntl(td, args->fd, F_SETLK, 1432 (intptr_t)&bsd_flock)); 1433 1434 case LINUX_F_SETLKW64: 1435 error = copyin((void *)args->arg, &linux_flock, 1436 sizeof(linux_flock)); 1437 if (error) 1438 return (error); 1439 linux_to_bsd_flock64(&linux_flock, &bsd_flock); 1440 return (kern_fcntl(td, args->fd, F_SETLKW, 1441 (intptr_t)&bsd_flock)); 1442 } 1443 1444 return (fcntl_common(td, args)); 1445} 1446#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ 1447 1448int 1449linux_chown(struct thread *td, struct linux_chown_args *args) 1450{ 1451 char *path; 1452 int error; 1453 1454 LCONVPATHEXIST(td, args->path, &path); 1455 1456#ifdef DEBUG 1457 if (ldebug(chown)) 1458 printf(ARGS(chown, "%s, %d, %d"), path, args->uid, args->gid); 1459#endif 1460 error = kern_chown(td, path, UIO_SYSSPACE, args->uid, args->gid); 1461 LFREEPATH(path); 1462 return (error); 1463} 1464 1465int 1466linux_fchownat(struct thread *td, struct linux_fchownat_args *args) 1467{ 1468 char *path; 1469 int error, dfd, follow; 1470 1471 if (args->flag & ~LINUX_AT_SYMLINK_NOFOLLOW) 1472 return (EINVAL); 1473 1474 dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd; 1475 LCONVPATHEXIST_AT(td, args->filename, &path, dfd); 1476 1477#ifdef DEBUG 1478 if (ldebug(fchownat)) 1479 printf(ARGS(fchownat, "%s, %d, %d"), path, args->uid, args->gid); 1480#endif 1481 1482 follow = (args->flag & LINUX_AT_SYMLINK_NOFOLLOW) == 0 ? 0 : 1483 AT_SYMLINK_NOFOLLOW; 1484 error = kern_fchownat(td, dfd, path, UIO_SYSSPACE, args->uid, args->gid, 1485 follow); 1486 LFREEPATH(path); 1487 return (error); 1488} 1489 1490int 1491linux_lchown(struct thread *td, struct linux_lchown_args *args) 1492{ 1493 char *path; 1494 int error; 1495 1496 LCONVPATHEXIST(td, args->path, &path); 1497 1498#ifdef DEBUG 1499 if (ldebug(lchown)) 1500 printf(ARGS(lchown, "%s, %d, %d"), path, args->uid, args->gid); 1501#endif 1502 error = kern_lchown(td, path, UIO_SYSSPACE, args->uid, args->gid); 1503 LFREEPATH(path); 1504 return (error); 1505} 1506