linux_file.c revision 162201
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 162201 2006-09-10 13:47:56Z netchild $"); 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/mac.h> 44#include <sys/malloc.h> 45#include <sys/mount.h> 46#include <sys/mutex.h> 47#include <sys/proc.h> 48#include <sys/stat.h> 49#include <sys/syscallsubr.h> 50#include <sys/sysproto.h> 51#include <sys/tty.h> 52#include <sys/vnode.h> 53 54#include <ufs/ufs/extattr.h> 55#include <ufs/ufs/quota.h> 56#include <ufs/ufs/ufsmount.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_util.h> 66 67int 68linux_creat(struct thread *td, struct linux_creat_args *args) 69{ 70 char *path; 71 int error; 72 73 LCONVPATHEXIST(td, args->path, &path); 74 75#ifdef DEBUG 76 if (ldebug(creat)) 77 printf(ARGS(creat, "%s, %d"), path, args->mode); 78#endif 79 error = kern_open(td, path, UIO_SYSSPACE, O_WRONLY | O_CREAT | O_TRUNC, 80 args->mode); 81 LFREEPATH(path); 82 return (error); 83} 84 85int 86linux_open(struct thread *td, struct linux_open_args *args) 87{ 88 struct proc *p = td->td_proc; 89 char *path; 90 int bsd_flags, error; 91 92 if (args->flags & LINUX_O_CREAT) 93 LCONVPATHCREAT(td, args->path, &path); 94 else 95 LCONVPATHEXIST(td, args->path, &path); 96 97#ifdef DEBUG 98 if (ldebug(open)) 99 printf(ARGS(open, "%s, 0x%x, 0x%x"), 100 path, args->flags, args->mode); 101#endif 102 bsd_flags = 0; 103 if (args->flags & LINUX_O_RDONLY) 104 bsd_flags |= O_RDONLY; 105 if (args->flags & LINUX_O_WRONLY) 106 bsd_flags |= O_WRONLY; 107 if (args->flags & LINUX_O_RDWR) 108 bsd_flags |= O_RDWR; 109 if (args->flags & LINUX_O_NDELAY) 110 bsd_flags |= O_NONBLOCK; 111 if (args->flags & LINUX_O_APPEND) 112 bsd_flags |= O_APPEND; 113 if (args->flags & LINUX_O_SYNC) 114 bsd_flags |= O_FSYNC; 115 if (args->flags & LINUX_O_NONBLOCK) 116 bsd_flags |= O_NONBLOCK; 117 if (args->flags & LINUX_FASYNC) 118 bsd_flags |= O_ASYNC; 119 if (args->flags & LINUX_O_CREAT) 120 bsd_flags |= O_CREAT; 121 if (args->flags & LINUX_O_TRUNC) 122 bsd_flags |= O_TRUNC; 123 if (args->flags & LINUX_O_EXCL) 124 bsd_flags |= O_EXCL; 125 if (args->flags & LINUX_O_NOCTTY) 126 bsd_flags |= O_NOCTTY; 127 128 error = kern_open(td, path, UIO_SYSSPACE, bsd_flags, args->mode); 129 PROC_LOCK(p); 130 if (!error && !(bsd_flags & O_NOCTTY) && 131 SESS_LEADER(p) && !(p->p_flag & P_CONTROLT)) { 132 struct file *fp; 133 134 PROC_UNLOCK(p); 135 error = fget(td, td->td_retval[0], &fp); 136 if (!error) { 137 if (fp->f_type == DTYPE_VNODE) 138 fo_ioctl(fp, TIOCSCTTY, (caddr_t) 0, td->td_ucred, 139 td); 140 fdrop(fp, td); 141 } 142 } else { 143 PROC_UNLOCK(p); 144#ifdef DEBUG 145 if (ldebug(open)) 146 printf(LMSG("open returns error %d"), error); 147#endif 148 } 149 LFREEPATH(path); 150 return error; 151} 152 153int 154linux_lseek(struct thread *td, struct linux_lseek_args *args) 155{ 156 157 struct lseek_args /* { 158 int fd; 159 int pad; 160 off_t offset; 161 int whence; 162 } */ tmp_args; 163 int error; 164 165#ifdef DEBUG 166 if (ldebug(lseek)) 167 printf(ARGS(lseek, "%d, %ld, %d"), 168 args->fdes, (long)args->off, args->whence); 169#endif 170 tmp_args.fd = args->fdes; 171 tmp_args.offset = (off_t)args->off; 172 tmp_args.whence = args->whence; 173 error = lseek(td, &tmp_args); 174 return error; 175} 176 177int 178linux_llseek(struct thread *td, struct linux_llseek_args *args) 179{ 180 struct lseek_args bsd_args; 181 int error; 182 off_t off; 183 184#ifdef DEBUG 185 if (ldebug(llseek)) 186 printf(ARGS(llseek, "%d, %d:%d, %d"), 187 args->fd, args->ohigh, args->olow, args->whence); 188#endif 189 off = (args->olow) | (((off_t) args->ohigh) << 32); 190 191 bsd_args.fd = args->fd; 192 bsd_args.offset = off; 193 bsd_args.whence = args->whence; 194 195 if ((error = lseek(td, &bsd_args))) 196 return error; 197 198 if ((error = copyout(td->td_retval, args->res, sizeof (off_t)))) 199 return error; 200 201 td->td_retval[0] = 0; 202 return 0; 203} 204 205int 206linux_readdir(struct thread *td, struct linux_readdir_args *args) 207{ 208 struct linux_getdents_args lda; 209 210 lda.fd = args->fd; 211 lda.dent = args->dent; 212 lda.count = 1; 213 return linux_getdents(td, &lda); 214} 215 216/* 217 * Note that linux_getdents(2) and linux_getdents64(2) have the same 218 * arguments. They only differ in the definition of struct dirent they 219 * operate on. We use this to common the code, with the exception of 220 * accessing struct dirent. Note that linux_readdir(2) is implemented 221 * by means of linux_getdents(2). In this case we never operate on 222 * struct dirent64 and thus don't need to handle it... 223 */ 224 225struct l_dirent { 226 l_long d_ino; 227 l_off_t d_off; 228 l_ushort d_reclen; 229 char d_name[LINUX_NAME_MAX + 1]; 230}; 231 232struct l_dirent64 { 233 uint64_t d_ino; 234 int64_t d_off; 235 l_ushort d_reclen; 236 u_char d_type; 237 char d_name[LINUX_NAME_MAX + 1]; 238}; 239 240#define LINUX_RECLEN(de,namlen) \ 241 ALIGN((((char *)&(de)->d_name - (char *)de) + (namlen) + 1)) 242 243#define LINUX_DIRBLKSIZ 512 244 245static int 246getdents_common(struct thread *td, struct linux_getdents64_args *args, 247 int is64bit) 248{ 249 struct dirent *bdp; 250 struct vnode *vp; 251 caddr_t inp, buf; /* BSD-format */ 252 int len, reclen; /* BSD-format */ 253 caddr_t outp; /* Linux-format */ 254 int resid, linuxreclen=0; /* Linux-format */ 255 struct file *fp; 256 struct uio auio; 257 struct iovec aiov; 258 off_t off; 259 struct l_dirent linux_dirent; 260 struct l_dirent64 linux_dirent64; 261 int buflen, error, eofflag, nbytes, justone; 262 u_long *cookies = NULL, *cookiep; 263 int ncookies, vfslocked; 264 265 nbytes = args->count; 266 if (nbytes == 1) { 267 /* readdir(2) case. Always struct dirent. */ 268 if (is64bit) 269 return (EINVAL); 270 nbytes = sizeof(linux_dirent); 271 justone = 1; 272 } else 273 justone = 0; 274 275 if ((error = getvnode(td->td_proc->p_fd, args->fd, &fp)) != 0) 276 return (error); 277 278 if ((fp->f_flag & FREAD) == 0) { 279 fdrop(fp, td); 280 return (EBADF); 281 } 282 283 vp = fp->f_vnode; 284 vfslocked = VFS_LOCK_GIANT(vp->v_mount); 285 if (vp->v_type != VDIR) { 286 VFS_UNLOCK_GIANT(vfslocked); 287 fdrop(fp, td); 288 return (EINVAL); 289 } 290 291 off = fp->f_offset; 292 293 buflen = max(LINUX_DIRBLKSIZ, nbytes); 294 buflen = min(buflen, MAXBSIZE); 295 buf = malloc(buflen, M_TEMP, M_WAITOK); 296 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td); 297 298again: 299 aiov.iov_base = buf; 300 aiov.iov_len = buflen; 301 auio.uio_iov = &aiov; 302 auio.uio_iovcnt = 1; 303 auio.uio_rw = UIO_READ; 304 auio.uio_segflg = UIO_SYSSPACE; 305 auio.uio_td = td; 306 auio.uio_resid = buflen; 307 auio.uio_offset = off; 308 309 if (cookies) { 310 free(cookies, M_TEMP); 311 cookies = NULL; 312 } 313 314#ifdef MAC 315 /* 316 * Do directory search MAC check using non-cached credentials. 317 */ 318 if ((error = mac_check_vnode_readdir(td->td_ucred, vp))) 319 goto out; 320#endif /* MAC */ 321 if ((error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, &ncookies, 322 &cookies))) 323 goto out; 324 325 inp = buf; 326 outp = (caddr_t)args->dirent; 327 resid = nbytes; 328 if ((len = buflen - auio.uio_resid) <= 0) 329 goto eof; 330 331 cookiep = cookies; 332 333 if (cookies) { 334 /* 335 * When using cookies, the vfs has the option of reading from 336 * a different offset than that supplied (UFS truncates the 337 * offset to a block boundary to make sure that it never reads 338 * partway through a directory entry, even if the directory 339 * has been compacted). 340 */ 341 while (len > 0 && ncookies > 0 && *cookiep <= off) { 342 bdp = (struct dirent *) inp; 343 len -= bdp->d_reclen; 344 inp += bdp->d_reclen; 345 cookiep++; 346 ncookies--; 347 } 348 } 349 350 while (len > 0) { 351 if (cookiep && ncookies == 0) 352 break; 353 bdp = (struct dirent *) inp; 354 reclen = bdp->d_reclen; 355 if (reclen & 3) { 356 error = EFAULT; 357 goto out; 358 } 359 360 if (bdp->d_fileno == 0) { 361 inp += reclen; 362 if (cookiep) { 363 off = *cookiep++; 364 ncookies--; 365 } else 366 off += reclen; 367 368 len -= reclen; 369 continue; 370 } 371 372 linuxreclen = (is64bit) 373 ? LINUX_RECLEN(&linux_dirent64, bdp->d_namlen) 374 : LINUX_RECLEN(&linux_dirent, bdp->d_namlen); 375 376 if (reclen > len || resid < linuxreclen) { 377 outp++; 378 break; 379 } 380 381 if (justone) { 382 /* readdir(2) case. */ 383 linux_dirent.d_ino = (l_long)bdp->d_fileno; 384 linux_dirent.d_off = (l_off_t)linuxreclen; 385 linux_dirent.d_reclen = (l_ushort)bdp->d_namlen; 386 strcpy(linux_dirent.d_name, bdp->d_name); 387 error = copyout(&linux_dirent, outp, linuxreclen); 388 } else { 389 if (is64bit) { 390 linux_dirent64.d_ino = bdp->d_fileno; 391 linux_dirent64.d_off = (cookiep) 392 ? (l_off_t)*cookiep 393 : (l_off_t)(off + reclen); 394 linux_dirent64.d_reclen = 395 (l_ushort)linuxreclen; 396 linux_dirent64.d_type = bdp->d_type; 397 strcpy(linux_dirent64.d_name, bdp->d_name); 398 error = copyout(&linux_dirent64, outp, 399 linuxreclen); 400 } else { 401 linux_dirent.d_ino = bdp->d_fileno; 402 linux_dirent.d_off = (cookiep) 403 ? (l_off_t)*cookiep 404 : (l_off_t)(off + reclen); 405 linux_dirent.d_reclen = (l_ushort)linuxreclen; 406 strcpy(linux_dirent.d_name, bdp->d_name); 407 error = copyout(&linux_dirent, outp, 408 linuxreclen); 409 } 410 } 411 if (error) 412 goto out; 413 414 inp += reclen; 415 if (cookiep) { 416 off = *cookiep++; 417 ncookies--; 418 } else 419 off += reclen; 420 421 outp += linuxreclen; 422 resid -= linuxreclen; 423 len -= reclen; 424 if (justone) 425 break; 426 } 427 428 if (outp == (caddr_t)args->dirent) 429 goto again; 430 431 fp->f_offset = off; 432 if (justone) 433 nbytes = resid + linuxreclen; 434 435eof: 436 td->td_retval[0] = nbytes - resid; 437 438out: 439 if (cookies) 440 free(cookies, M_TEMP); 441 442 VOP_UNLOCK(vp, 0, td); 443 VFS_UNLOCK_GIANT(vfslocked); 444 fdrop(fp, td); 445 free(buf, M_TEMP); 446 return (error); 447} 448 449int 450linux_getdents(struct thread *td, struct linux_getdents_args *args) 451{ 452 453#ifdef DEBUG 454 if (ldebug(getdents)) 455 printf(ARGS(getdents, "%d, *, %d"), args->fd, args->count); 456#endif 457 458 return (getdents_common(td, (struct linux_getdents64_args*)args, 0)); 459} 460 461int 462linux_getdents64(struct thread *td, struct linux_getdents64_args *args) 463{ 464 465#ifdef DEBUG 466 if (ldebug(getdents64)) 467 printf(ARGS(getdents64, "%d, *, %d"), args->fd, args->count); 468#endif 469 470 return (getdents_common(td, args, 1)); 471} 472 473/* 474 * These exist mainly for hooks for doing /compat/linux translation. 475 */ 476 477int 478linux_access(struct thread *td, struct linux_access_args *args) 479{ 480 char *path; 481 int error; 482 483 LCONVPATHEXIST(td, args->path, &path); 484 485#ifdef DEBUG 486 if (ldebug(access)) 487 printf(ARGS(access, "%s, %d"), path, args->flags); 488#endif 489 error = kern_access(td, path, UIO_SYSSPACE, args->flags); 490 LFREEPATH(path); 491 return (error); 492} 493 494int 495linux_unlink(struct thread *td, struct linux_unlink_args *args) 496{ 497 char *path; 498 int error; 499 struct stat st; 500 501 LCONVPATHEXIST(td, args->path, &path); 502 503#ifdef DEBUG 504 if (ldebug(unlink)) 505 printf(ARGS(unlink, "%s"), path); 506#endif 507 508 error = kern_unlink(td, path, UIO_SYSSPACE); 509 if (error == EPERM) 510 /* Introduce POSIX noncompliant behaviour of Linux */ 511 if (kern_stat(td, path, UIO_SYSSPACE, &st) == 0) 512 if (S_ISDIR(st.st_mode)) 513 error = EISDIR; 514 LFREEPATH(path); 515 return (error); 516} 517 518int 519linux_chdir(struct thread *td, struct linux_chdir_args *args) 520{ 521 char *path; 522 int error; 523 524 LCONVPATHEXIST(td, args->path, &path); 525 526#ifdef DEBUG 527 if (ldebug(chdir)) 528 printf(ARGS(chdir, "%s"), path); 529#endif 530 error = kern_chdir(td, path, UIO_SYSSPACE); 531 LFREEPATH(path); 532 return (error); 533} 534 535int 536linux_chmod(struct thread *td, struct linux_chmod_args *args) 537{ 538 char *path; 539 int error; 540 541 LCONVPATHEXIST(td, args->path, &path); 542 543#ifdef DEBUG 544 if (ldebug(chmod)) 545 printf(ARGS(chmod, "%s, %d"), path, args->mode); 546#endif 547 error = kern_chmod(td, path, UIO_SYSSPACE, args->mode); 548 LFREEPATH(path); 549 return (error); 550} 551 552int 553linux_mkdir(struct thread *td, struct linux_mkdir_args *args) 554{ 555 char *path; 556 int error; 557 558 LCONVPATHCREAT(td, args->path, &path); 559 560#ifdef DEBUG 561 if (ldebug(mkdir)) 562 printf(ARGS(mkdir, "%s, %d"), path, args->mode); 563#endif 564 error = kern_mkdir(td, path, UIO_SYSSPACE, args->mode); 565 LFREEPATH(path); 566 return (error); 567} 568 569int 570linux_rmdir(struct thread *td, struct linux_rmdir_args *args) 571{ 572 char *path; 573 int error; 574 575 LCONVPATHEXIST(td, args->path, &path); 576 577#ifdef DEBUG 578 if (ldebug(rmdir)) 579 printf(ARGS(rmdir, "%s"), path); 580#endif 581 error = kern_rmdir(td, path, UIO_SYSSPACE); 582 LFREEPATH(path); 583 return (error); 584} 585 586int 587linux_rename(struct thread *td, struct linux_rename_args *args) 588{ 589 char *from, *to; 590 int error; 591 592 LCONVPATHEXIST(td, args->from, &from); 593 /* Expand LCONVPATHCREATE so that `from' can be freed on errors */ 594 error = linux_emul_convpath(td, args->to, UIO_USERSPACE, &to, 1); 595 if (to == NULL) { 596 LFREEPATH(from); 597 return (error); 598 } 599 600#ifdef DEBUG 601 if (ldebug(rename)) 602 printf(ARGS(rename, "%s, %s"), from, to); 603#endif 604 error = kern_rename(td, from, to, UIO_SYSSPACE); 605 LFREEPATH(from); 606 LFREEPATH(to); 607 return (error); 608} 609 610int 611linux_symlink(struct thread *td, struct linux_symlink_args *args) 612{ 613 char *path, *to; 614 int error; 615 616 LCONVPATHEXIST(td, args->path, &path); 617 /* Expand LCONVPATHCREATE so that `path' can be freed on errors */ 618 error = linux_emul_convpath(td, args->to, UIO_USERSPACE, &to, 1); 619 if (to == NULL) { 620 LFREEPATH(path); 621 return (error); 622 } 623 624#ifdef DEBUG 625 if (ldebug(symlink)) 626 printf(ARGS(symlink, "%s, %s"), path, to); 627#endif 628 error = kern_symlink(td, path, to, UIO_SYSSPACE); 629 LFREEPATH(path); 630 LFREEPATH(to); 631 return (error); 632} 633 634int 635linux_readlink(struct thread *td, struct linux_readlink_args *args) 636{ 637 char *name; 638 int error; 639 640 LCONVPATHEXIST(td, args->name, &name); 641 642#ifdef DEBUG 643 if (ldebug(readlink)) 644 printf(ARGS(readlink, "%s, %p, %d"), name, (void *)args->buf, 645 args->count); 646#endif 647 error = kern_readlink(td, name, UIO_SYSSPACE, args->buf, UIO_USERSPACE, 648 args->count); 649 LFREEPATH(name); 650 return (error); 651} 652 653int 654linux_truncate(struct thread *td, struct linux_truncate_args *args) 655{ 656 char *path; 657 int error; 658 659 LCONVPATHEXIST(td, args->path, &path); 660 661#ifdef DEBUG 662 if (ldebug(truncate)) 663 printf(ARGS(truncate, "%s, %ld"), path, (long)args->length); 664#endif 665 666 error = kern_truncate(td, path, UIO_SYSSPACE, args->length); 667 LFREEPATH(path); 668 return (error); 669} 670 671int 672linux_ftruncate(struct thread *td, struct linux_ftruncate_args *args) 673{ 674 struct ftruncate_args /* { 675 int fd; 676 int pad; 677 off_t length; 678 } */ nuap; 679 680 nuap.fd = args->fd; 681 nuap.pad = 0; 682 nuap.length = args->length; 683 return (ftruncate(td, &nuap)); 684} 685 686int 687linux_link(struct thread *td, struct linux_link_args *args) 688{ 689 char *path, *to; 690 int error; 691 692 LCONVPATHEXIST(td, args->path, &path); 693 /* Expand LCONVPATHCREATE so that `path' can be freed on errors */ 694 error = linux_emul_convpath(td, args->to, UIO_USERSPACE, &to, 1); 695 if (to == NULL) { 696 LFREEPATH(path); 697 return (error); 698 } 699 700#ifdef DEBUG 701 if (ldebug(link)) 702 printf(ARGS(link, "%s, %s"), path, to); 703#endif 704 error = kern_link(td, path, to, UIO_SYSSPACE); 705 LFREEPATH(path); 706 LFREEPATH(to); 707 return (error); 708} 709 710int 711linux_fdatasync(td, uap) 712 struct thread *td; 713 struct linux_fdatasync_args *uap; 714{ 715 struct fsync_args bsd; 716 717 bsd.fd = uap->fd; 718 return fsync(td, &bsd); 719} 720 721int 722linux_pread(td, uap) 723 struct thread *td; 724 struct linux_pread_args *uap; 725{ 726 struct pread_args bsd; 727 728 bsd.fd = uap->fd; 729 bsd.buf = uap->buf; 730 bsd.nbyte = uap->nbyte; 731 bsd.offset = uap->offset; 732 return pread(td, &bsd); 733} 734 735int 736linux_pwrite(td, uap) 737 struct thread *td; 738 struct linux_pwrite_args *uap; 739{ 740 struct pwrite_args bsd; 741 742 bsd.fd = uap->fd; 743 bsd.buf = uap->buf; 744 bsd.nbyte = uap->nbyte; 745 bsd.offset = uap->offset; 746 return pwrite(td, &bsd); 747} 748 749int 750linux_mount(struct thread *td, struct linux_mount_args *args) 751{ 752 struct ufs_args ufs; 753 char fstypename[MFSNAMELEN]; 754 char mntonname[MNAMELEN], mntfromname[MNAMELEN]; 755 int error; 756 int fsflags; 757 void *fsdata; 758 759 error = copyinstr(args->filesystemtype, fstypename, MFSNAMELEN - 1, 760 NULL); 761 if (error) 762 return (error); 763 error = copyinstr(args->specialfile, mntfromname, MNAMELEN - 1, NULL); 764 if (error) 765 return (error); 766 error = copyinstr(args->dir, mntonname, MNAMELEN - 1, NULL); 767 if (error) 768 return (error); 769 770#ifdef DEBUG 771 if (ldebug(mount)) 772 printf(ARGS(mount, "%s, %s, %s"), 773 fstypename, mntfromname, mntonname); 774#endif 775 776 if (strcmp(fstypename, "ext2") == 0) { 777 strcpy(fstypename, "ext2fs"); 778 fsdata = &ufs; 779 ufs.fspec = mntfromname; 780#define DEFAULT_ROOTID -2 781 ufs.export.ex_root = DEFAULT_ROOTID; 782 ufs.export.ex_flags = 783 args->rwflag & LINUX_MS_RDONLY ? MNT_EXRDONLY : 0; 784 } else if (strcmp(fstypename, "proc") == 0) { 785 strcpy(fstypename, "linprocfs"); 786 fsdata = NULL; 787 } else { 788 return (ENODEV); 789 } 790 791 fsflags = 0; 792 793 if ((args->rwflag & 0xffff0000) == 0xc0ed0000) { 794 /* 795 * Linux SYNC flag is not included; the closest equivalent 796 * FreeBSD has is !ASYNC, which is our default. 797 */ 798 if (args->rwflag & LINUX_MS_RDONLY) 799 fsflags |= MNT_RDONLY; 800 if (args->rwflag & LINUX_MS_NOSUID) 801 fsflags |= MNT_NOSUID; 802 if (args->rwflag & LINUX_MS_NOEXEC) 803 fsflags |= MNT_NOEXEC; 804 if (args->rwflag & LINUX_MS_REMOUNT) 805 fsflags |= MNT_UPDATE; 806 } 807 808 if (strcmp(fstypename, "linprocfs") == 0) { 809 error = kernel_vmount(fsflags, 810 "fstype", fstypename, 811 "fspath", mntonname, 812 NULL); 813 } else 814 error = EOPNOTSUPP; 815 return (error); 816} 817 818int 819linux_oldumount(struct thread *td, struct linux_oldumount_args *args) 820{ 821 struct linux_umount_args args2; 822 823 args2.path = args->path; 824 args2.flags = 0; 825 return (linux_umount(td, &args2)); 826} 827 828int 829linux_umount(struct thread *td, struct linux_umount_args *args) 830{ 831 struct unmount_args bsd; 832 833 bsd.path = args->path; 834 bsd.flags = args->flags; /* XXX correct? */ 835 return (unmount(td, &bsd)); 836} 837 838/* 839 * fcntl family of syscalls 840 */ 841 842struct l_flock { 843 l_short l_type; 844 l_short l_whence; 845 l_off_t l_start; 846 l_off_t l_len; 847 l_pid_t l_pid; 848} 849#if defined(__amd64__) && defined(COMPAT_LINUX32) 850__packed 851#endif 852; 853 854static void 855linux_to_bsd_flock(struct l_flock *linux_flock, struct flock *bsd_flock) 856{ 857 switch (linux_flock->l_type) { 858 case LINUX_F_RDLCK: 859 bsd_flock->l_type = F_RDLCK; 860 break; 861 case LINUX_F_WRLCK: 862 bsd_flock->l_type = F_WRLCK; 863 break; 864 case LINUX_F_UNLCK: 865 bsd_flock->l_type = F_UNLCK; 866 break; 867 default: 868 bsd_flock->l_type = -1; 869 break; 870 } 871 bsd_flock->l_whence = linux_flock->l_whence; 872 bsd_flock->l_start = (off_t)linux_flock->l_start; 873 bsd_flock->l_len = (off_t)linux_flock->l_len; 874 bsd_flock->l_pid = (pid_t)linux_flock->l_pid; 875} 876 877static void 878bsd_to_linux_flock(struct flock *bsd_flock, struct l_flock *linux_flock) 879{ 880 switch (bsd_flock->l_type) { 881 case F_RDLCK: 882 linux_flock->l_type = LINUX_F_RDLCK; 883 break; 884 case F_WRLCK: 885 linux_flock->l_type = LINUX_F_WRLCK; 886 break; 887 case F_UNLCK: 888 linux_flock->l_type = LINUX_F_UNLCK; 889 break; 890 } 891 linux_flock->l_whence = bsd_flock->l_whence; 892 linux_flock->l_start = (l_off_t)bsd_flock->l_start; 893 linux_flock->l_len = (l_off_t)bsd_flock->l_len; 894 linux_flock->l_pid = (l_pid_t)bsd_flock->l_pid; 895} 896 897#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) 898struct l_flock64 { 899 l_short l_type; 900 l_short l_whence; 901 l_loff_t l_start; 902 l_loff_t l_len; 903 l_pid_t l_pid; 904} 905#if defined(__amd64__) && defined(COMPAT_LINUX32) 906__packed 907#endif 908; 909 910static void 911linux_to_bsd_flock64(struct l_flock64 *linux_flock, struct flock *bsd_flock) 912{ 913 switch (linux_flock->l_type) { 914 case LINUX_F_RDLCK: 915 bsd_flock->l_type = F_RDLCK; 916 break; 917 case LINUX_F_WRLCK: 918 bsd_flock->l_type = F_WRLCK; 919 break; 920 case LINUX_F_UNLCK: 921 bsd_flock->l_type = F_UNLCK; 922 break; 923 default: 924 bsd_flock->l_type = -1; 925 break; 926 } 927 bsd_flock->l_whence = linux_flock->l_whence; 928 bsd_flock->l_start = (off_t)linux_flock->l_start; 929 bsd_flock->l_len = (off_t)linux_flock->l_len; 930 bsd_flock->l_pid = (pid_t)linux_flock->l_pid; 931} 932 933static void 934bsd_to_linux_flock64(struct flock *bsd_flock, struct l_flock64 *linux_flock) 935{ 936 switch (bsd_flock->l_type) { 937 case F_RDLCK: 938 linux_flock->l_type = LINUX_F_RDLCK; 939 break; 940 case F_WRLCK: 941 linux_flock->l_type = LINUX_F_WRLCK; 942 break; 943 case F_UNLCK: 944 linux_flock->l_type = LINUX_F_UNLCK; 945 break; 946 } 947 linux_flock->l_whence = bsd_flock->l_whence; 948 linux_flock->l_start = (l_loff_t)bsd_flock->l_start; 949 linux_flock->l_len = (l_loff_t)bsd_flock->l_len; 950 linux_flock->l_pid = (l_pid_t)bsd_flock->l_pid; 951} 952#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ 953 954static int 955fcntl_common(struct thread *td, struct linux_fcntl64_args *args) 956{ 957 struct l_flock linux_flock; 958 struct flock bsd_flock; 959 struct file *fp; 960 long arg; 961 int error, result; 962 963 switch (args->cmd) { 964 case LINUX_F_DUPFD: 965 return (kern_fcntl(td, args->fd, F_DUPFD, args->arg)); 966 967 case LINUX_F_GETFD: 968 return (kern_fcntl(td, args->fd, F_GETFD, 0)); 969 970 case LINUX_F_SETFD: 971 return (kern_fcntl(td, args->fd, F_SETFD, args->arg)); 972 973 case LINUX_F_GETFL: 974 error = kern_fcntl(td, args->fd, F_GETFL, 0); 975 result = td->td_retval[0]; 976 td->td_retval[0] = 0; 977 if (result & O_RDONLY) 978 td->td_retval[0] |= LINUX_O_RDONLY; 979 if (result & O_WRONLY) 980 td->td_retval[0] |= LINUX_O_WRONLY; 981 if (result & O_RDWR) 982 td->td_retval[0] |= LINUX_O_RDWR; 983 if (result & O_NDELAY) 984 td->td_retval[0] |= LINUX_O_NONBLOCK; 985 if (result & O_APPEND) 986 td->td_retval[0] |= LINUX_O_APPEND; 987 if (result & O_FSYNC) 988 td->td_retval[0] |= LINUX_O_SYNC; 989 if (result & O_ASYNC) 990 td->td_retval[0] |= LINUX_FASYNC; 991#ifdef LINUX_O_NOFOLLOW 992 if (result & O_NOFOLLOW) 993 td->td_retval[0] |= LINUX_O_NOFOLLOW; 994#endif 995#ifdef LINUX_O_DIRECT 996 if (result & O_DIRECT) 997 td->td_retval[0] |= LINUX_O_DIRECT; 998#endif 999 return (error); 1000 1001 case LINUX_F_SETFL: 1002 arg = 0; 1003 if (args->arg & LINUX_O_NDELAY) 1004 arg |= O_NONBLOCK; 1005 if (args->arg & LINUX_O_APPEND) 1006 arg |= O_APPEND; 1007 if (args->arg & LINUX_O_SYNC) 1008 arg |= O_FSYNC; 1009 if (args->arg & LINUX_FASYNC) 1010 arg |= O_ASYNC; 1011#ifdef LINUX_O_NOFOLLOW 1012 if (args->arg & LINUX_O_NOFOLLOW) 1013 arg |= O_NOFOLLOW; 1014#endif 1015#ifdef LINUX_O_DIRECT 1016 if (args->arg & LINUX_O_DIRECT) 1017 arg |= O_DIRECT; 1018#endif 1019 return (kern_fcntl(td, args->fd, F_SETFL, arg)); 1020 1021 case LINUX_F_GETLK: 1022 error = copyin((void *)args->arg, &linux_flock, 1023 sizeof(linux_flock)); 1024 if (error) 1025 return (error); 1026 linux_to_bsd_flock(&linux_flock, &bsd_flock); 1027 error = kern_fcntl(td, args->fd, F_GETLK, (intptr_t)&bsd_flock); 1028 if (error) 1029 return (error); 1030 bsd_to_linux_flock(&bsd_flock, &linux_flock); 1031 return (copyout(&linux_flock, (void *)args->arg, 1032 sizeof(linux_flock))); 1033 1034 case LINUX_F_SETLK: 1035 error = copyin((void *)args->arg, &linux_flock, 1036 sizeof(linux_flock)); 1037 if (error) 1038 return (error); 1039 linux_to_bsd_flock(&linux_flock, &bsd_flock); 1040 return (kern_fcntl(td, args->fd, F_SETLK, 1041 (intptr_t)&bsd_flock)); 1042 1043 case LINUX_F_SETLKW: 1044 error = copyin((void *)args->arg, &linux_flock, 1045 sizeof(linux_flock)); 1046 if (error) 1047 return (error); 1048 linux_to_bsd_flock(&linux_flock, &bsd_flock); 1049 return (kern_fcntl(td, args->fd, F_SETLKW, 1050 (intptr_t)&bsd_flock)); 1051 1052 case LINUX_F_GETOWN: 1053 return (kern_fcntl(td, args->fd, F_GETOWN, 0)); 1054 1055 case LINUX_F_SETOWN: 1056 /* 1057 * XXX some Linux applications depend on F_SETOWN having no 1058 * significant effect for pipes (SIGIO is not delivered for 1059 * pipes under Linux-2.2.35 at least). 1060 */ 1061 error = fget(td, args->fd, &fp); 1062 if (error) 1063 return (error); 1064 if (fp->f_type == DTYPE_PIPE) { 1065 fdrop(fp, td); 1066 return (EINVAL); 1067 } 1068 fdrop(fp, td); 1069 1070 return (kern_fcntl(td, args->fd, F_SETOWN, args->arg)); 1071 } 1072 1073 return (EINVAL); 1074} 1075 1076int 1077linux_fcntl(struct thread *td, struct linux_fcntl_args *args) 1078{ 1079 struct linux_fcntl64_args args64; 1080 1081#ifdef DEBUG 1082 if (ldebug(fcntl)) 1083 printf(ARGS(fcntl, "%d, %08x, *"), args->fd, args->cmd); 1084#endif 1085 1086 args64.fd = args->fd; 1087 args64.cmd = args->cmd; 1088 args64.arg = args->arg; 1089 return (fcntl_common(td, &args64)); 1090} 1091 1092#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) 1093int 1094linux_fcntl64(struct thread *td, struct linux_fcntl64_args *args) 1095{ 1096 struct l_flock64 linux_flock; 1097 struct flock bsd_flock; 1098 int error; 1099 1100#ifdef DEBUG 1101 if (ldebug(fcntl64)) 1102 printf(ARGS(fcntl64, "%d, %08x, *"), args->fd, args->cmd); 1103#endif 1104 1105 switch (args->cmd) { 1106 case LINUX_F_GETLK64: 1107 error = copyin((void *)args->arg, &linux_flock, 1108 sizeof(linux_flock)); 1109 if (error) 1110 return (error); 1111 linux_to_bsd_flock64(&linux_flock, &bsd_flock); 1112 error = kern_fcntl(td, args->fd, F_GETLK, (intptr_t)&bsd_flock); 1113 if (error) 1114 return (error); 1115 bsd_to_linux_flock64(&bsd_flock, &linux_flock); 1116 return (copyout(&linux_flock, (void *)args->arg, 1117 sizeof(linux_flock))); 1118 1119 case LINUX_F_SETLK64: 1120 error = copyin((void *)args->arg, &linux_flock, 1121 sizeof(linux_flock)); 1122 if (error) 1123 return (error); 1124 linux_to_bsd_flock64(&linux_flock, &bsd_flock); 1125 return (kern_fcntl(td, args->fd, F_SETLK, 1126 (intptr_t)&bsd_flock)); 1127 1128 case LINUX_F_SETLKW64: 1129 error = copyin((void *)args->arg, &linux_flock, 1130 sizeof(linux_flock)); 1131 if (error) 1132 return (error); 1133 linux_to_bsd_flock64(&linux_flock, &bsd_flock); 1134 return (kern_fcntl(td, args->fd, F_SETLKW, 1135 (intptr_t)&bsd_flock)); 1136 } 1137 1138 return (fcntl_common(td, args)); 1139} 1140#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ 1141 1142int 1143linux_chown(struct thread *td, struct linux_chown_args *args) 1144{ 1145 char *path; 1146 int error; 1147 1148 LCONVPATHEXIST(td, args->path, &path); 1149 1150#ifdef DEBUG 1151 if (ldebug(chown)) 1152 printf(ARGS(chown, "%s, %d, %d"), path, args->uid, args->gid); 1153#endif 1154 error = kern_chown(td, path, UIO_SYSSPACE, args->uid, args->gid); 1155 LFREEPATH(path); 1156 return (error); 1157} 1158 1159int 1160linux_lchown(struct thread *td, struct linux_lchown_args *args) 1161{ 1162 char *path; 1163 int error; 1164 1165 LCONVPATHEXIST(td, args->path, &path); 1166 1167#ifdef DEBUG 1168 if (ldebug(lchown)) 1169 printf(ARGS(lchown, "%s, %d, %d"), path, args->uid, args->gid); 1170#endif 1171 error = kern_lchown(td, path, UIO_SYSSPACE, args->uid, args->gid); 1172 LFREEPATH(path); 1173 return (error); 1174} 1175