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