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