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