linux_file.c revision 122892
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 122892 2003-11-19 04:12:32Z kan $"); 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/syscallsubr.h> 49#include <sys/sysproto.h> 50#include <sys/tty.h> 51#include <sys/vnode.h> 52 53#include <ufs/ufs/extattr.h> 54#include <ufs/ufs/quota.h> 55#include <ufs/ufs/ufsmount.h> 56 57#include <machine/../linux/linux.h> 58#include <machine/../linux/linux_proto.h> 59#include <compat/linux/linux_util.h> 60 61#ifndef __alpha__ 62int 63linux_creat(struct thread *td, struct linux_creat_args *args) 64{ 65 char *path; 66 int error; 67 68 LCONVPATHEXIST(td, args->path, &path); 69 70#ifdef DEBUG 71 if (ldebug(creat)) 72 printf(ARGS(creat, "%s, %d"), path, args->mode); 73#endif 74 error = kern_open(td, path, UIO_SYSSPACE, O_WRONLY | O_CREAT | O_TRUNC, 75 args->mode); 76 LFREEPATH(path); 77 return (error); 78} 79#endif /*!__alpha__*/ 80 81int 82linux_open(struct thread *td, struct linux_open_args *args) 83{ 84 struct proc *p = td->td_proc; 85 char *path; 86 int bsd_flags, error; 87 88 if (args->flags & LINUX_O_CREAT) 89 LCONVPATHCREAT(td, args->path, &path); 90 else 91 LCONVPATHEXIST(td, args->path, &path); 92 93#ifdef DEBUG 94 if (ldebug(open)) 95 printf(ARGS(open, "%s, 0x%x, 0x%x"), 96 path, args->flags, args->mode); 97#endif 98 bsd_flags = 0; 99 if (args->flags & LINUX_O_RDONLY) 100 bsd_flags |= O_RDONLY; 101 if (args->flags & LINUX_O_WRONLY) 102 bsd_flags |= O_WRONLY; 103 if (args->flags & LINUX_O_RDWR) 104 bsd_flags |= O_RDWR; 105 if (args->flags & LINUX_O_NDELAY) 106 bsd_flags |= O_NONBLOCK; 107 if (args->flags & LINUX_O_APPEND) 108 bsd_flags |= O_APPEND; 109 if (args->flags & LINUX_O_SYNC) 110 bsd_flags |= O_FSYNC; 111 if (args->flags & LINUX_O_NONBLOCK) 112 bsd_flags |= O_NONBLOCK; 113 if (args->flags & LINUX_FASYNC) 114 bsd_flags |= O_ASYNC; 115 if (args->flags & LINUX_O_CREAT) 116 bsd_flags |= O_CREAT; 117 if (args->flags & LINUX_O_TRUNC) 118 bsd_flags |= O_TRUNC; 119 if (args->flags & LINUX_O_EXCL) 120 bsd_flags |= O_EXCL; 121 if (args->flags & LINUX_O_NOCTTY) 122 bsd_flags |= O_NOCTTY; 123 124 error = kern_open(td, path, UIO_SYSSPACE, bsd_flags, args->mode); 125 PROC_LOCK(p); 126 if (!error && !(bsd_flags & O_NOCTTY) && 127 SESS_LEADER(p) && !(p->p_flag & P_CONTROLT)) { 128 struct file *fp; 129 130 PROC_UNLOCK(p); 131 error = fget(td, td->td_retval[0], &fp); 132 if (!error) { 133 if (fp->f_type == DTYPE_VNODE) 134 fo_ioctl(fp, TIOCSCTTY, (caddr_t) 0, td->td_ucred, 135 td); 136 fdrop(fp, td); 137 } 138 } else { 139 PROC_UNLOCK(p); 140#ifdef DEBUG 141 if (ldebug(open)) 142 printf(LMSG("open returns error %d"), error); 143#endif 144 } 145 LFREEPATH(path); 146 return error; 147} 148 149int 150linux_lseek(struct thread *td, struct linux_lseek_args *args) 151{ 152 153 struct lseek_args /* { 154 int fd; 155 int pad; 156 off_t offset; 157 int whence; 158 } */ tmp_args; 159 int error; 160 161#ifdef DEBUG 162 if (ldebug(lseek)) 163 printf(ARGS(lseek, "%d, %ld, %d"), 164 args->fdes, (long)args->off, args->whence); 165#endif 166 tmp_args.fd = args->fdes; 167 tmp_args.offset = (off_t)args->off; 168 tmp_args.whence = args->whence; 169 error = lseek(td, &tmp_args); 170 return error; 171} 172 173#ifndef __alpha__ 174int 175linux_llseek(struct thread *td, struct linux_llseek_args *args) 176{ 177 struct lseek_args bsd_args; 178 int error; 179 off_t off; 180 181#ifdef DEBUG 182 if (ldebug(llseek)) 183 printf(ARGS(llseek, "%d, %d:%d, %d"), 184 args->fd, args->ohigh, args->olow, args->whence); 185#endif 186 off = (args->olow) | (((off_t) args->ohigh) << 32); 187 188 bsd_args.fd = args->fd; 189 bsd_args.offset = off; 190 bsd_args.whence = args->whence; 191 192 if ((error = lseek(td, &bsd_args))) 193 return error; 194 195 if ((error = copyout(td->td_retval, args->res, sizeof (off_t)))) 196 return error; 197 198 td->td_retval[0] = 0; 199 return 0; 200} 201#endif /*!__alpha__*/ 202 203#ifndef __alpha__ 204int 205linux_readdir(struct thread *td, struct linux_readdir_args *args) 206{ 207 struct linux_getdents_args lda; 208 209 lda.fd = args->fd; 210 lda.dent = args->dent; 211 lda.count = 1; 212 return linux_getdents(td, &lda); 213} 214#endif /*!__alpha__*/ 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; 264 265 if ((error = getvnode(td->td_proc->p_fd, args->fd, &fp)) != 0) 266 return (error); 267 268 if ((fp->f_flag & FREAD) == 0) { 269 fdrop(fp, td); 270 return (EBADF); 271 } 272 273 vp = fp->f_vnode; 274 if (vp->v_type != VDIR) { 275 fdrop(fp, td); 276 return (EINVAL); 277 } 278 279 nbytes = args->count; 280 if (nbytes == 1) { 281 /* readdir(2) case. Always struct dirent. */ 282 if (is64bit) { 283 fdrop(fp, td); 284 return (EINVAL); 285 } 286 nbytes = sizeof(linux_dirent); 287 justone = 1; 288 } else 289 justone = 0; 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 fdrop(fp, td); 444 free(buf, M_TEMP); 445 return (error); 446} 447 448int 449linux_getdents(struct thread *td, struct linux_getdents_args *args) 450{ 451 452#ifdef DEBUG 453 if (ldebug(getdents)) 454 printf(ARGS(getdents, "%d, *, %d"), args->fd, args->count); 455#endif 456 457 return (getdents_common(td, (struct linux_getdents64_args*)args, 0)); 458} 459 460int 461linux_getdents64(struct thread *td, struct linux_getdents64_args *args) 462{ 463 464#ifdef DEBUG 465 if (ldebug(getdents64)) 466 printf(ARGS(getdents64, "%d, *, %d"), args->fd, args->count); 467#endif 468 469 return (getdents_common(td, args, 1)); 470} 471 472/* 473 * These exist mainly for hooks for doing /compat/linux translation. 474 */ 475 476int 477linux_access(struct thread *td, struct linux_access_args *args) 478{ 479 char *path; 480 int error; 481 482 LCONVPATHEXIST(td, args->path, &path); 483 484#ifdef DEBUG 485 if (ldebug(access)) 486 printf(ARGS(access, "%s, %d"), path, args->flags); 487#endif 488 error = kern_access(td, path, UIO_SYSSPACE, args->flags); 489 LFREEPATH(path); 490 return (error); 491} 492 493int 494linux_unlink(struct thread *td, struct linux_unlink_args *args) 495{ 496 char *path; 497 int error; 498 499 LCONVPATHEXIST(td, args->path, &path); 500 501#ifdef DEBUG 502 if (ldebug(unlink)) 503 printf(ARGS(unlink, "%s"), path); 504#endif 505 506 error = kern_unlink(td, path, UIO_SYSSPACE); 507 LFREEPATH(path); 508 return (error); 509} 510 511int 512linux_chdir(struct thread *td, struct linux_chdir_args *args) 513{ 514 char *path; 515 int error; 516 517 LCONVPATHEXIST(td, args->path, &path); 518 519#ifdef DEBUG 520 if (ldebug(chdir)) 521 printf(ARGS(chdir, "%s"), path); 522#endif 523 error = kern_chdir(td, path, UIO_SYSSPACE); 524 LFREEPATH(path); 525 return (error); 526} 527 528int 529linux_chmod(struct thread *td, struct linux_chmod_args *args) 530{ 531 char *path; 532 int error; 533 534 LCONVPATHEXIST(td, args->path, &path); 535 536#ifdef DEBUG 537 if (ldebug(chmod)) 538 printf(ARGS(chmod, "%s, %d"), path, args->mode); 539#endif 540 error = kern_chmod(td, path, UIO_SYSSPACE, args->mode); 541 LFREEPATH(path); 542 return (error); 543} 544 545int 546linux_mkdir(struct thread *td, struct linux_mkdir_args *args) 547{ 548 char *path; 549 int error; 550 551 LCONVPATHCREAT(td, args->path, &path); 552 553#ifdef DEBUG 554 if (ldebug(mkdir)) 555 printf(ARGS(mkdir, "%s, %d"), path, args->mode); 556#endif 557 error = kern_mkdir(td, path, UIO_SYSSPACE, args->mode); 558 LFREEPATH(path); 559 return (error); 560} 561 562int 563linux_rmdir(struct thread *td, struct linux_rmdir_args *args) 564{ 565 char *path; 566 int error; 567 568 LCONVPATHEXIST(td, args->path, &path); 569 570#ifdef DEBUG 571 if (ldebug(rmdir)) 572 printf(ARGS(rmdir, "%s"), path); 573#endif 574 error = kern_rmdir(td, path, UIO_SYSSPACE); 575 LFREEPATH(path); 576 return (error); 577} 578 579int 580linux_rename(struct thread *td, struct linux_rename_args *args) 581{ 582 char *from, *to; 583 int error; 584 585 LCONVPATHEXIST(td, args->from, &from); 586 /* Expand LCONVPATHCREATE so that `from' can be freed on errors */ 587 error = linux_emul_convpath(td, args->to, UIO_USERSPACE, &to, 1); 588 if (to == NULL) { 589 LFREEPATH(from); 590 return (error); 591 } 592 593#ifdef DEBUG 594 if (ldebug(rename)) 595 printf(ARGS(rename, "%s, %s"), from, to); 596#endif 597 error = kern_rename(td, from, to, UIO_SYSSPACE); 598 LFREEPATH(from); 599 LFREEPATH(to); 600 return (error); 601} 602 603int 604linux_symlink(struct thread *td, struct linux_symlink_args *args) 605{ 606 char *path, *to; 607 int error; 608 609 LCONVPATHEXIST(td, args->path, &path); 610 /* Expand LCONVPATHCREATE so that `path' can be freed on errors */ 611 error = linux_emul_convpath(td, args->to, UIO_USERSPACE, &to, 1); 612 if (to == NULL) { 613 LFREEPATH(path); 614 return (error); 615 } 616 617#ifdef DEBUG 618 if (ldebug(symlink)) 619 printf(ARGS(symlink, "%s, %s"), path, to); 620#endif 621 error = kern_symlink(td, path, to, UIO_SYSSPACE); 622 LFREEPATH(path); 623 LFREEPATH(to); 624 return (error); 625} 626 627int 628linux_readlink(struct thread *td, struct linux_readlink_args *args) 629{ 630 char *name; 631 int error; 632 633 LCONVPATHEXIST(td, args->name, &name); 634 635#ifdef DEBUG 636 if (ldebug(readlink)) 637 printf(ARGS(readlink, "%s, %p, %d"), name, (void *)args->buf, 638 args->count); 639#endif 640 error = kern_readlink(td, name, UIO_SYSSPACE, args->buf, UIO_USERSPACE, 641 args->count); 642 LFREEPATH(name); 643 return (error); 644} 645 646int 647linux_truncate(struct thread *td, struct linux_truncate_args *args) 648{ 649 char *path; 650 int error; 651 652 LCONVPATHEXIST(td, args->path, &path); 653 654#ifdef DEBUG 655 if (ldebug(truncate)) 656 printf(ARGS(truncate, "%s, %ld"), path, (long)args->length); 657#endif 658 659 error = kern_truncate(td, path, UIO_SYSSPACE, args->length); 660 LFREEPATH(path); 661 return (error); 662} 663 664int 665linux_link(struct thread *td, struct linux_link_args *args) 666{ 667 char *path, *to; 668 int error; 669 670 LCONVPATHEXIST(td, args->path, &path); 671 /* Expand LCONVPATHCREATE so that `path' can be freed on errors */ 672 error = linux_emul_convpath(td, args->to, UIO_USERSPACE, &to, 1); 673 if (to == NULL) { 674 LFREEPATH(path); 675 return (error); 676 } 677 678#ifdef DEBUG 679 if (ldebug(link)) 680 printf(ARGS(link, "%s, %s"), path, to); 681#endif 682 error = kern_link(td, path, to, UIO_SYSSPACE); 683 LFREEPATH(path); 684 LFREEPATH(to); 685 return (error); 686} 687 688#ifndef __alpha__ 689int 690linux_fdatasync(td, uap) 691 struct thread *td; 692 struct linux_fdatasync_args *uap; 693{ 694 struct fsync_args bsd; 695 696 bsd.fd = uap->fd; 697 return fsync(td, &bsd); 698} 699#endif /*!__alpha__*/ 700 701int 702linux_pread(td, uap) 703 struct thread *td; 704 struct linux_pread_args *uap; 705{ 706 struct pread_args bsd; 707 708 bsd.fd = uap->fd; 709 bsd.buf = uap->buf; 710 bsd.nbyte = uap->nbyte; 711 bsd.offset = uap->offset; 712 return pread(td, &bsd); 713} 714 715int 716linux_pwrite(td, uap) 717 struct thread *td; 718 struct linux_pwrite_args *uap; 719{ 720 struct pwrite_args bsd; 721 722 bsd.fd = uap->fd; 723 bsd.buf = uap->buf; 724 bsd.nbyte = uap->nbyte; 725 bsd.offset = uap->offset; 726 return pwrite(td, &bsd); 727} 728 729int 730linux_mount(struct thread *td, struct linux_mount_args *args) 731{ 732 struct ufs_args ufs; 733 char fstypename[MFSNAMELEN]; 734 char mntonname[MNAMELEN], mntfromname[MNAMELEN]; 735 int error; 736 int fsflags; 737 const char *fstype; 738 void *fsdata; 739 740 error = copyinstr(args->filesystemtype, fstypename, MFSNAMELEN - 1, 741 NULL); 742 if (error) 743 return (error); 744 error = copyinstr(args->specialfile, mntfromname, MFSNAMELEN - 1, NULL); 745 if (error) 746 return (error); 747 error = copyinstr(args->dir, mntonname, MFSNAMELEN - 1, NULL); 748 if (error) 749 return (error); 750 751#ifdef DEBUG 752 if (ldebug(mount)) 753 printf(ARGS(mount, "%s, %s, %s"), 754 fstypename, mntfromname, mntonname); 755#endif 756 757 if (strcmp(fstypename, "ext2") == 0) { 758 fstype = "ext2fs"; 759 fsdata = &ufs; 760 ufs.fspec = mntfromname; 761#define DEFAULT_ROOTID -2 762 ufs.export.ex_root = DEFAULT_ROOTID; 763 ufs.export.ex_flags = 764 args->rwflag & LINUX_MS_RDONLY ? MNT_EXRDONLY : 0; 765 } else if (strcmp(fstypename, "proc") == 0) { 766 fstype = "linprocfs"; 767 fsdata = NULL; 768 } else { 769 return (ENODEV); 770 } 771 772 fsflags = 0; 773 774 if ((args->rwflag & 0xffff0000) == 0xc0ed0000) { 775 /* 776 * Linux SYNC flag is not included; the closest equivalent 777 * FreeBSD has is !ASYNC, which is our default. 778 */ 779 if (args->rwflag & LINUX_MS_RDONLY) 780 fsflags |= MNT_RDONLY; 781 if (args->rwflag & LINUX_MS_NOSUID) 782 fsflags |= MNT_NOSUID; 783 if (args->rwflag & LINUX_MS_NODEV) 784 fsflags |= MNT_NODEV; 785 if (args->rwflag & LINUX_MS_NOEXEC) 786 fsflags |= MNT_NOEXEC; 787 if (args->rwflag & LINUX_MS_REMOUNT) 788 fsflags |= MNT_UPDATE; 789 } 790 791 return (vfs_mount(td, fstype, mntonname, fsflags, fsdata)); 792} 793 794int 795linux_oldumount(struct thread *td, struct linux_oldumount_args *args) 796{ 797 struct linux_umount_args args2; 798 799 args2.path = args->path; 800 args2.flags = 0; 801 return (linux_umount(td, &args2)); 802} 803 804int 805linux_umount(struct thread *td, struct linux_umount_args *args) 806{ 807 struct unmount_args bsd; 808 809 bsd.path = args->path; 810 bsd.flags = args->flags; /* XXX correct? */ 811 return (unmount(td, &bsd)); 812} 813 814/* 815 * fcntl family of syscalls 816 */ 817 818struct l_flock { 819 l_short l_type; 820 l_short l_whence; 821 l_off_t l_start; 822 l_off_t l_len; 823 l_pid_t l_pid; 824}; 825 826static void 827linux_to_bsd_flock(struct l_flock *linux_flock, struct flock *bsd_flock) 828{ 829 switch (linux_flock->l_type) { 830 case LINUX_F_RDLCK: 831 bsd_flock->l_type = F_RDLCK; 832 break; 833 case LINUX_F_WRLCK: 834 bsd_flock->l_type = F_WRLCK; 835 break; 836 case LINUX_F_UNLCK: 837 bsd_flock->l_type = F_UNLCK; 838 break; 839 default: 840 bsd_flock->l_type = -1; 841 break; 842 } 843 bsd_flock->l_whence = linux_flock->l_whence; 844 bsd_flock->l_start = (off_t)linux_flock->l_start; 845 bsd_flock->l_len = (off_t)linux_flock->l_len; 846 bsd_flock->l_pid = (pid_t)linux_flock->l_pid; 847} 848 849static void 850bsd_to_linux_flock(struct flock *bsd_flock, struct l_flock *linux_flock) 851{ 852 switch (bsd_flock->l_type) { 853 case F_RDLCK: 854 linux_flock->l_type = LINUX_F_RDLCK; 855 break; 856 case F_WRLCK: 857 linux_flock->l_type = LINUX_F_WRLCK; 858 break; 859 case F_UNLCK: 860 linux_flock->l_type = LINUX_F_UNLCK; 861 break; 862 } 863 linux_flock->l_whence = bsd_flock->l_whence; 864 linux_flock->l_start = (l_off_t)bsd_flock->l_start; 865 linux_flock->l_len = (l_off_t)bsd_flock->l_len; 866 linux_flock->l_pid = (l_pid_t)bsd_flock->l_pid; 867} 868 869#if defined(__i386__) 870struct l_flock64 { 871 l_short l_type; 872 l_short l_whence; 873 l_loff_t l_start; 874 l_loff_t l_len; 875 l_pid_t l_pid; 876}; 877 878static void 879linux_to_bsd_flock64(struct l_flock64 *linux_flock, struct flock *bsd_flock) 880{ 881 switch (linux_flock->l_type) { 882 case LINUX_F_RDLCK: 883 bsd_flock->l_type = F_RDLCK; 884 break; 885 case LINUX_F_WRLCK: 886 bsd_flock->l_type = F_WRLCK; 887 break; 888 case LINUX_F_UNLCK: 889 bsd_flock->l_type = F_UNLCK; 890 break; 891 default: 892 bsd_flock->l_type = -1; 893 break; 894 } 895 bsd_flock->l_whence = linux_flock->l_whence; 896 bsd_flock->l_start = (off_t)linux_flock->l_start; 897 bsd_flock->l_len = (off_t)linux_flock->l_len; 898 bsd_flock->l_pid = (pid_t)linux_flock->l_pid; 899} 900 901static void 902bsd_to_linux_flock64(struct flock *bsd_flock, struct l_flock64 *linux_flock) 903{ 904 switch (bsd_flock->l_type) { 905 case F_RDLCK: 906 linux_flock->l_type = LINUX_F_RDLCK; 907 break; 908 case F_WRLCK: 909 linux_flock->l_type = LINUX_F_WRLCK; 910 break; 911 case F_UNLCK: 912 linux_flock->l_type = LINUX_F_UNLCK; 913 break; 914 } 915 linux_flock->l_whence = bsd_flock->l_whence; 916 linux_flock->l_start = (l_loff_t)bsd_flock->l_start; 917 linux_flock->l_len = (l_loff_t)bsd_flock->l_len; 918 linux_flock->l_pid = (l_pid_t)bsd_flock->l_pid; 919} 920#endif /* __i386__ */ 921 922#if defined(__alpha__) 923#define linux_fcntl64_args linux_fcntl_args 924#endif 925 926static int 927fcntl_common(struct thread *td, struct linux_fcntl64_args *args) 928{ 929 struct l_flock linux_flock; 930 struct flock bsd_flock; 931 struct file *fp; 932 long arg; 933 int error, result; 934 935 switch (args->cmd) { 936 case LINUX_F_DUPFD: 937 return (kern_fcntl(td, args->fd, F_DUPFD, args->arg)); 938 939 case LINUX_F_GETFD: 940 return (kern_fcntl(td, args->fd, F_GETFD, 0)); 941 942 case LINUX_F_SETFD: 943 return (kern_fcntl(td, args->fd, F_SETFD, args->arg)); 944 945 case LINUX_F_GETFL: 946 error = kern_fcntl(td, args->fd, F_GETFL, 0); 947 result = td->td_retval[0]; 948 td->td_retval[0] = 0; 949 if (result & O_RDONLY) 950 td->td_retval[0] |= LINUX_O_RDONLY; 951 if (result & O_WRONLY) 952 td->td_retval[0] |= LINUX_O_WRONLY; 953 if (result & O_RDWR) 954 td->td_retval[0] |= LINUX_O_RDWR; 955 if (result & O_NDELAY) 956 td->td_retval[0] |= LINUX_O_NONBLOCK; 957 if (result & O_APPEND) 958 td->td_retval[0] |= LINUX_O_APPEND; 959 if (result & O_FSYNC) 960 td->td_retval[0] |= LINUX_O_SYNC; 961 if (result & O_ASYNC) 962 td->td_retval[0] |= LINUX_FASYNC; 963 return (error); 964 965 case LINUX_F_SETFL: 966 arg = 0; 967 if (args->arg & LINUX_O_NDELAY) 968 arg |= O_NONBLOCK; 969 if (args->arg & LINUX_O_APPEND) 970 arg |= O_APPEND; 971 if (args->arg & LINUX_O_SYNC) 972 arg |= O_FSYNC; 973 if (args->arg & LINUX_FASYNC) 974 arg |= O_ASYNC; 975 return (kern_fcntl(td, args->fd, F_SETFL, arg)); 976 977 case LINUX_F_GETLK: 978 error = copyin((void *)args->arg, &linux_flock, 979 sizeof(linux_flock)); 980 if (error) 981 return (error); 982 linux_to_bsd_flock(&linux_flock, &bsd_flock); 983 error = kern_fcntl(td, args->fd, F_GETLK, (intptr_t)&bsd_flock); 984 if (error) 985 return (error); 986 bsd_to_linux_flock(&bsd_flock, &linux_flock); 987 return (copyout(&linux_flock, (void *)args->arg, 988 sizeof(linux_flock))); 989 990 case LINUX_F_SETLK: 991 error = copyin((void *)args->arg, &linux_flock, 992 sizeof(linux_flock)); 993 if (error) 994 return (error); 995 linux_to_bsd_flock(&linux_flock, &bsd_flock); 996 return (kern_fcntl(td, args->fd, F_SETLK, 997 (intptr_t)&bsd_flock)); 998 999 case LINUX_F_SETLKW: 1000 error = copyin((void *)args->arg, &linux_flock, 1001 sizeof(linux_flock)); 1002 if (error) 1003 return (error); 1004 linux_to_bsd_flock(&linux_flock, &bsd_flock); 1005 return (kern_fcntl(td, args->fd, F_SETLKW, 1006 (intptr_t)&bsd_flock)); 1007 1008 case LINUX_F_GETOWN: 1009 return (kern_fcntl(td, args->fd, F_GETOWN, 0)); 1010 1011 case LINUX_F_SETOWN: 1012 /* 1013 * XXX some Linux applications depend on F_SETOWN having no 1014 * significant effect for pipes (SIGIO is not delivered for 1015 * pipes under Linux-2.2.35 at least). 1016 */ 1017 error = fget(td, args->fd, &fp); 1018 if (error) 1019 return (error); 1020 if (fp->f_type == DTYPE_PIPE) { 1021 fdrop(fp, td); 1022 return (EINVAL); 1023 } 1024 fdrop(fp, td); 1025 1026 return (kern_fcntl(td, args->fd, F_SETOWN, args->arg)); 1027 } 1028 1029 return (EINVAL); 1030} 1031 1032int 1033linux_fcntl(struct thread *td, struct linux_fcntl_args *args) 1034{ 1035 struct linux_fcntl64_args args64; 1036 1037#ifdef DEBUG 1038 if (ldebug(fcntl)) 1039 printf(ARGS(fcntl, "%d, %08x, *"), args->fd, args->cmd); 1040#endif 1041 1042 args64.fd = args->fd; 1043 args64.cmd = args->cmd; 1044 args64.arg = args->arg; 1045 return (fcntl_common(td, &args64)); 1046} 1047 1048#if defined(__i386__) 1049int 1050linux_fcntl64(struct thread *td, struct linux_fcntl64_args *args) 1051{ 1052 struct l_flock64 linux_flock; 1053 struct flock bsd_flock; 1054 int error; 1055 1056#ifdef DEBUG 1057 if (ldebug(fcntl64)) 1058 printf(ARGS(fcntl64, "%d, %08x, *"), args->fd, args->cmd); 1059#endif 1060 1061 switch (args->cmd) { 1062 case LINUX_F_GETLK64: 1063 error = copyin((void *)args->arg, &linux_flock, 1064 sizeof(linux_flock)); 1065 if (error) 1066 return (error); 1067 linux_to_bsd_flock64(&linux_flock, &bsd_flock); 1068 error = kern_fcntl(td, args->fd, F_GETLK, (intptr_t)&bsd_flock); 1069 if (error) 1070 return (error); 1071 bsd_to_linux_flock64(&bsd_flock, &linux_flock); 1072 return (copyout(&linux_flock, (void *)args->arg, 1073 sizeof(linux_flock))); 1074 1075 case LINUX_F_SETLK64: 1076 error = copyin((void *)args->arg, &linux_flock, 1077 sizeof(linux_flock)); 1078 if (error) 1079 return (error); 1080 linux_to_bsd_flock64(&linux_flock, &bsd_flock); 1081 return (kern_fcntl(td, args->fd, F_SETLK, 1082 (intptr_t)&bsd_flock)); 1083 1084 case LINUX_F_SETLKW64: 1085 error = copyin((void *)args->arg, &linux_flock, 1086 sizeof(linux_flock)); 1087 if (error) 1088 return (error); 1089 linux_to_bsd_flock64(&linux_flock, &bsd_flock); 1090 return (kern_fcntl(td, args->fd, F_SETLKW, 1091 (intptr_t)&bsd_flock)); 1092 } 1093 1094 return (fcntl_common(td, args)); 1095} 1096#endif /* __i386__ */ 1097 1098int 1099linux_chown(struct thread *td, struct linux_chown_args *args) 1100{ 1101 char *path; 1102 int error; 1103 1104 LCONVPATHEXIST(td, args->path, &path); 1105 1106#ifdef DEBUG 1107 if (ldebug(chown)) 1108 printf(ARGS(chown, "%s, %d, %d"), path, args->uid, args->gid); 1109#endif 1110 error = kern_chown(td, path, UIO_SYSSPACE, args->uid, args->gid); 1111 LFREEPATH(path); 1112 return (error); 1113} 1114 1115int 1116linux_lchown(struct thread *td, struct linux_lchown_args *args) 1117{ 1118 char *path; 1119 int error; 1120 1121 LCONVPATHEXIST(td, args->path, &path); 1122 1123#ifdef DEBUG 1124 if (ldebug(lchown)) 1125 printf(ARGS(lchown, "%s, %d, %d"), path, args->uid, args->gid); 1126#endif 1127 error = kern_lchown(td, path, UIO_SYSSPACE, args->uid, args->gid); 1128 LFREEPATH(path); 1129 return (error); 1130} 1131