svr4_fcntl.c revision 172930
1/*- 2 * Copyright (c) 1998 Mark Newton 3 * Copyright (c) 1994, 1997 Christos Zoulas. 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 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. All advertising materials mentioning features or use of this software 15 * must display the following acknowledgement: 16 * This product includes software developed by Christos Zoulas. 17 * 4. The name of the author may not be used to endorse or promote products 18 * derived from this software without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 23 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 29 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32#include <sys/cdefs.h> 33__FBSDID("$FreeBSD: head/sys/compat/svr4/svr4_fcntl.c 172930 2007-10-24 19:04:04Z rwatson $"); 34 35#include "opt_mac.h" 36 37#include <sys/param.h> 38#include <sys/systm.h> 39#include <sys/file.h> 40#include <sys/filedesc.h> 41/*#include <sys/ioctl.h>*/ 42#include <sys/lock.h> 43#include <sys/malloc.h> 44#include <sys/mount.h> 45#include <sys/mutex.h> 46#include <sys/namei.h> 47#include <sys/priv.h> 48#include <sys/proc.h> 49#include <sys/stat.h> 50#include <sys/syscallsubr.h> 51#include <sys/unistd.h> 52#include <sys/vnode.h> 53 54#include <sys/sysproto.h> 55 56#include <compat/svr4/svr4.h> 57#include <compat/svr4/svr4_types.h> 58#include <compat/svr4/svr4_signal.h> 59#include <compat/svr4/svr4_proto.h> 60#include <compat/svr4/svr4_util.h> 61#include <compat/svr4/svr4_fcntl.h> 62 63#include <security/mac/mac_framework.h> 64 65static int svr4_to_bsd_flags(int); 66static u_long svr4_to_bsd_cmd(u_long); 67static int fd_revoke(struct thread *, int); 68static int fd_truncate(struct thread *, int, struct flock *); 69static int bsd_to_svr4_flags(int); 70static void bsd_to_svr4_flock(struct flock *, struct svr4_flock *); 71static void svr4_to_bsd_flock(struct svr4_flock *, struct flock *); 72static void bsd_to_svr4_flock64(struct flock *, struct svr4_flock64 *); 73static void svr4_to_bsd_flock64(struct svr4_flock64 *, struct flock *); 74 75static u_long 76svr4_to_bsd_cmd(cmd) 77 u_long cmd; 78{ 79 switch (cmd) { 80 case SVR4_F_DUPFD: 81 return F_DUPFD; 82 case SVR4_F_GETFD: 83 return F_GETFD; 84 case SVR4_F_SETFD: 85 return F_SETFD; 86 case SVR4_F_GETFL: 87 return F_GETFL; 88 case SVR4_F_SETFL: 89 return F_SETFL; 90 case SVR4_F_GETLK: 91 return F_GETLK; 92 case SVR4_F_SETLK: 93 return F_SETLK; 94 case SVR4_F_SETLKW: 95 return F_SETLKW; 96 default: 97 return -1; 98 } 99} 100 101static int 102svr4_to_bsd_flags(l) 103 int l; 104{ 105 int r = 0; 106 r |= (l & SVR4_O_RDONLY) ? O_RDONLY : 0; 107 r |= (l & SVR4_O_WRONLY) ? O_WRONLY : 0; 108 r |= (l & SVR4_O_RDWR) ? O_RDWR : 0; 109 r |= (l & SVR4_O_NDELAY) ? O_NONBLOCK : 0; 110 r |= (l & SVR4_O_APPEND) ? O_APPEND : 0; 111 r |= (l & SVR4_O_SYNC) ? O_FSYNC : 0; 112 r |= (l & SVR4_O_NONBLOCK) ? O_NONBLOCK : 0; 113 r |= (l & SVR4_O_PRIV) ? O_EXLOCK : 0; 114 r |= (l & SVR4_O_CREAT) ? O_CREAT : 0; 115 r |= (l & SVR4_O_TRUNC) ? O_TRUNC : 0; 116 r |= (l & SVR4_O_EXCL) ? O_EXCL : 0; 117 r |= (l & SVR4_O_NOCTTY) ? O_NOCTTY : 0; 118 return r; 119} 120 121static int 122bsd_to_svr4_flags(l) 123 int l; 124{ 125 int r = 0; 126 r |= (l & O_RDONLY) ? SVR4_O_RDONLY : 0; 127 r |= (l & O_WRONLY) ? SVR4_O_WRONLY : 0; 128 r |= (l & O_RDWR) ? SVR4_O_RDWR : 0; 129 r |= (l & O_NDELAY) ? SVR4_O_NONBLOCK : 0; 130 r |= (l & O_APPEND) ? SVR4_O_APPEND : 0; 131 r |= (l & O_FSYNC) ? SVR4_O_SYNC : 0; 132 r |= (l & O_NONBLOCK) ? SVR4_O_NONBLOCK : 0; 133 r |= (l & O_EXLOCK) ? SVR4_O_PRIV : 0; 134 r |= (l & O_CREAT) ? SVR4_O_CREAT : 0; 135 r |= (l & O_TRUNC) ? SVR4_O_TRUNC : 0; 136 r |= (l & O_EXCL) ? SVR4_O_EXCL : 0; 137 r |= (l & O_NOCTTY) ? SVR4_O_NOCTTY : 0; 138 return r; 139} 140 141 142static void 143bsd_to_svr4_flock(iflp, oflp) 144 struct flock *iflp; 145 struct svr4_flock *oflp; 146{ 147 switch (iflp->l_type) { 148 case F_RDLCK: 149 oflp->l_type = SVR4_F_RDLCK; 150 break; 151 case F_WRLCK: 152 oflp->l_type = SVR4_F_WRLCK; 153 break; 154 case F_UNLCK: 155 oflp->l_type = SVR4_F_UNLCK; 156 break; 157 default: 158 oflp->l_type = -1; 159 break; 160 } 161 162 oflp->l_whence = (short) iflp->l_whence; 163 oflp->l_start = (svr4_off_t) iflp->l_start; 164 oflp->l_len = (svr4_off_t) iflp->l_len; 165 oflp->l_sysid = 0; 166 oflp->l_pid = (svr4_pid_t) iflp->l_pid; 167} 168 169 170static void 171svr4_to_bsd_flock(iflp, oflp) 172 struct svr4_flock *iflp; 173 struct flock *oflp; 174{ 175 switch (iflp->l_type) { 176 case SVR4_F_RDLCK: 177 oflp->l_type = F_RDLCK; 178 break; 179 case SVR4_F_WRLCK: 180 oflp->l_type = F_WRLCK; 181 break; 182 case SVR4_F_UNLCK: 183 oflp->l_type = F_UNLCK; 184 break; 185 default: 186 oflp->l_type = -1; 187 break; 188 } 189 190 oflp->l_whence = iflp->l_whence; 191 oflp->l_start = (off_t) iflp->l_start; 192 oflp->l_len = (off_t) iflp->l_len; 193 oflp->l_pid = (pid_t) iflp->l_pid; 194 195} 196 197static void 198bsd_to_svr4_flock64(iflp, oflp) 199 struct flock *iflp; 200 struct svr4_flock64 *oflp; 201{ 202 switch (iflp->l_type) { 203 case F_RDLCK: 204 oflp->l_type = SVR4_F_RDLCK; 205 break; 206 case F_WRLCK: 207 oflp->l_type = SVR4_F_WRLCK; 208 break; 209 case F_UNLCK: 210 oflp->l_type = SVR4_F_UNLCK; 211 break; 212 default: 213 oflp->l_type = -1; 214 break; 215 } 216 217 oflp->l_whence = (short) iflp->l_whence; 218 oflp->l_start = (svr4_off64_t) iflp->l_start; 219 oflp->l_len = (svr4_off64_t) iflp->l_len; 220 oflp->l_sysid = 0; 221 oflp->l_pid = (svr4_pid_t) iflp->l_pid; 222} 223 224 225static void 226svr4_to_bsd_flock64(iflp, oflp) 227 struct svr4_flock64 *iflp; 228 struct flock *oflp; 229{ 230 switch (iflp->l_type) { 231 case SVR4_F_RDLCK: 232 oflp->l_type = F_RDLCK; 233 break; 234 case SVR4_F_WRLCK: 235 oflp->l_type = F_WRLCK; 236 break; 237 case SVR4_F_UNLCK: 238 oflp->l_type = F_UNLCK; 239 break; 240 default: 241 oflp->l_type = -1; 242 break; 243 } 244 245 oflp->l_whence = iflp->l_whence; 246 oflp->l_start = (off_t) iflp->l_start; 247 oflp->l_len = (off_t) iflp->l_len; 248 oflp->l_pid = (pid_t) iflp->l_pid; 249 250} 251 252 253static int 254fd_revoke(td, fd) 255 struct thread *td; 256 int fd; 257{ 258 struct vnode *vp; 259 struct mount *mp; 260 struct vattr vattr; 261 int error, *retval; 262 263 retval = td->td_retval; 264 if ((error = fgetvp(td, fd, &vp)) != 0) 265 return (error); 266 267 if (vp->v_type != VCHR && vp->v_type != VBLK) { 268 error = EINVAL; 269 goto out; 270 } 271 272#ifdef MAC 273 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td); 274 error = mac_vnode_check_revoke(td->td_ucred, vp); 275 VOP_UNLOCK(vp, 0, td); 276 if (error) 277 goto out; 278#endif 279 280 if ((error = VOP_GETATTR(vp, &vattr, td->td_ucred, td)) != 0) 281 goto out; 282 283 if (td->td_ucred->cr_uid != vattr.va_uid && 284 (error = priv_check(td, PRIV_VFS_ADMIN)) != 0) 285 goto out; 286 287 if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0) 288 goto out; 289 if (vcount(vp) > 1) 290 VOP_REVOKE(vp, REVOKEALL); 291 vn_finished_write(mp); 292out: 293 vrele(vp); 294 return error; 295} 296 297 298static int 299fd_truncate(td, fd, flp) 300 struct thread *td; 301 int fd; 302 struct flock *flp; 303{ 304 off_t start, length; 305 struct file *fp; 306 struct vnode *vp; 307 struct vattr vattr; 308 int error, *retval; 309 struct ftruncate_args ft; 310 311 retval = td->td_retval; 312 313 /* 314 * We only support truncating the file. 315 */ 316 if ((error = fget(td, fd, &fp)) != 0) 317 return (error); 318 319 vp = fp->f_vnode; 320 321 if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO) { 322 fdrop(fp, td); 323 return ESPIPE; 324 } 325 326 if ((error = VOP_GETATTR(vp, &vattr, td->td_ucred, td)) != 0) { 327 fdrop(fp, td); 328 return error; 329 } 330 331 length = vattr.va_size; 332 333 switch (flp->l_whence) { 334 case SEEK_CUR: 335 start = fp->f_offset + flp->l_start; 336 break; 337 338 case SEEK_END: 339 start = flp->l_start + length; 340 break; 341 342 case SEEK_SET: 343 start = flp->l_start; 344 break; 345 346 default: 347 fdrop(fp, td); 348 return EINVAL; 349 } 350 351 if (start + flp->l_len < length) { 352 /* We don't support free'ing in the middle of the file */ 353 fdrop(fp, td); 354 return EINVAL; 355 } 356 357 ft.fd = fd; 358 ft.length = start; 359 360 error = ftruncate(td, &ft); 361 362 fdrop(fp, td); 363 return (error); 364} 365 366int 367svr4_sys_open(td, uap) 368 register struct thread *td; 369 struct svr4_sys_open_args *uap; 370{ 371 struct proc *p = td->td_proc; 372 char *newpath; 373 int bsd_flags, error, retval; 374 375 CHECKALTEXIST(td, uap->path, &newpath); 376 377 bsd_flags = svr4_to_bsd_flags(uap->flags); 378 error = kern_open(td, newpath, UIO_SYSSPACE, bsd_flags, uap->mode); 379 free(newpath, M_TEMP); 380 381 if (error) { 382 /* uprintf("svr4_open(%s, 0x%0x, 0%o): %d\n", uap->path, 383 uap->flags, uap->mode, error);*/ 384 return error; 385 } 386 387 retval = td->td_retval[0]; 388 389 PROC_LOCK(p); 390 if (!(bsd_flags & O_NOCTTY) && SESS_LEADER(p) && 391 !(p->p_flag & P_CONTROLT)) { 392#if defined(NOTYET) 393 struct file *fp; 394 395 error = fget(td, retval, &fp); 396 PROC_UNLOCK(p); 397 /* 398 * we may have lost a race the above open() and 399 * another thread issuing a close() 400 */ 401 if (error) 402 return (EBADF); /* XXX: correct errno? */ 403 /* ignore any error, just give it a try */ 404 if (fp->f_type == DTYPE_VNODE) 405 fo_ioctl(fp, TIOCSCTTY, (caddr_t) 0, td->td_ucred, 406 td); 407 fdrop(fp, td); 408 } else { 409 PROC_UNLOCK(p); 410 } 411#else 412 } 413 PROC_UNLOCK(p); 414#endif 415 return error; 416} 417 418int 419svr4_sys_open64(td, uap) 420 register struct thread *td; 421 struct svr4_sys_open64_args *uap; 422{ 423 return svr4_sys_open(td, (struct svr4_sys_open_args *)uap); 424} 425 426int 427svr4_sys_creat(td, uap) 428 register struct thread *td; 429 struct svr4_sys_creat_args *uap; 430{ 431 char *newpath; 432 int error; 433 434 CHECKALTEXIST(td, uap->path, &newpath); 435 436 error = kern_open(td, newpath, UIO_SYSSPACE, O_WRONLY | O_CREAT | 437 O_TRUNC, uap->mode); 438 free(newpath, M_TEMP); 439 return (error); 440} 441 442int 443svr4_sys_creat64(td, uap) 444 register struct thread *td; 445 struct svr4_sys_creat64_args *uap; 446{ 447 return svr4_sys_creat(td, (struct svr4_sys_creat_args *)uap); 448} 449 450int 451svr4_sys_llseek(td, uap) 452 register struct thread *td; 453 struct svr4_sys_llseek_args *uap; 454{ 455 struct lseek_args ap; 456 457 ap.fd = uap->fd; 458 459#if BYTE_ORDER == BIG_ENDIAN 460 ap.offset = (((u_int64_t) uap->offset1) << 32) | 461 uap->offset2; 462#else 463 ap.offset = (((u_int64_t) uap->offset2) << 32) | 464 uap->offset1; 465#endif 466 ap.whence = uap->whence; 467 468 return lseek(td, &ap); 469} 470 471int 472svr4_sys_access(td, uap) 473 register struct thread *td; 474 struct svr4_sys_access_args *uap; 475{ 476 char *newpath; 477 int error; 478 479 CHECKALTEXIST(td, uap->path, &newpath); 480 error = kern_access(td, newpath, UIO_SYSSPACE, uap->flags); 481 free(newpath, M_TEMP); 482 return (error); 483} 484 485#if defined(NOTYET) 486int 487svr4_sys_pread(td, uap) 488 register struct thread *td; 489 struct svr4_sys_pread_args *uap; 490{ 491 struct pread_args pra; 492 493 /* 494 * Just translate the args structure and call the NetBSD 495 * pread(2) system call (offset type is 64-bit in NetBSD). 496 */ 497 pra.fd = uap->fd; 498 pra.buf = uap->buf; 499 pra.nbyte = uap->nbyte; 500 pra.offset = uap->off; 501 502 return pread(td, &pra); 503} 504#endif 505 506#if defined(NOTYET) 507int 508svr4_sys_pread64(td, v, retval) 509 register struct thread *td; 510 void *v; 511 register_t *retval; 512{ 513 514 struct svr4_sys_pread64_args *uap = v; 515 struct sys_pread_args pra; 516 517 /* 518 * Just translate the args structure and call the NetBSD 519 * pread(2) system call (offset type is 64-bit in NetBSD). 520 */ 521 pra.fd = uap->fd; 522 pra.buf = uap->buf; 523 pra.nbyte = uap->nbyte; 524 pra.offset = uap->off; 525 526 return (sys_pread(td, &pra, retval)); 527} 528#endif /* NOTYET */ 529 530#if defined(NOTYET) 531int 532svr4_sys_pwrite(td, uap) 533 register struct thread *td; 534 struct svr4_sys_pwrite_args *uap; 535{ 536 struct pwrite_args pwa; 537 538 /* 539 * Just translate the args structure and call the NetBSD 540 * pwrite(2) system call (offset type is 64-bit in NetBSD). 541 */ 542 pwa.fd = uap->fd; 543 pwa.buf = uap->buf; 544 pwa.nbyte = uap->nbyte; 545 pwa.offset = uap->off; 546 547 return pwrite(td, &pwa); 548} 549#endif 550 551#if defined(NOTYET) 552int 553svr4_sys_pwrite64(td, v, retval) 554 register struct thread *td; 555 void *v; 556 register_t *retval; 557{ 558 struct svr4_sys_pwrite64_args *uap = v; 559 struct sys_pwrite_args pwa; 560 561 /* 562 * Just translate the args structure and call the NetBSD 563 * pwrite(2) system call (offset type is 64-bit in NetBSD). 564 */ 565 pwa.fd = uap->fd; 566 pwa.buf = uap->buf; 567 pwa.nbyte = uap->nbyte; 568 pwa.offset = uap->off; 569 570 return (sys_pwrite(td, &pwa, retval)); 571} 572#endif /* NOTYET */ 573 574int 575svr4_sys_fcntl(td, uap) 576 register struct thread *td; 577 struct svr4_sys_fcntl_args *uap; 578{ 579 int cmd, error, *retval; 580 581 retval = td->td_retval; 582 583 cmd = svr4_to_bsd_cmd(uap->cmd); 584 585 switch (cmd) { 586 case F_DUPFD: 587 case F_GETFD: 588 case F_SETFD: 589 return (kern_fcntl(td, uap->fd, cmd, (intptr_t)uap->arg)); 590 591 case F_GETFL: 592 error = kern_fcntl(td, uap->fd, cmd, (intptr_t)uap->arg); 593 if (error) 594 return (error); 595 *retval = bsd_to_svr4_flags(*retval); 596 return (error); 597 598 case F_SETFL: 599 { 600 /* 601 * we must save the O_ASYNC flag, as that is 602 * handled by ioctl(_, I_SETSIG, _) emulation. 603 */ 604 int flags; 605 606 DPRINTF(("Setting flags %p\n", uap->arg)); 607 608 error = kern_fcntl(td, uap->fd, F_GETFL, 0); 609 if (error) 610 return (error); 611 flags = *retval; 612 flags &= O_ASYNC; 613 flags |= svr4_to_bsd_flags((u_long) uap->arg); 614 return (kern_fcntl(td, uap->fd, F_SETFL, flags)); 615 } 616 617 case F_GETLK: 618 case F_SETLK: 619 case F_SETLKW: 620 { 621 struct svr4_flock ifl; 622 struct flock fl; 623 624 error = copyin(uap->arg, &ifl, sizeof (ifl)); 625 if (error) 626 return (error); 627 628 svr4_to_bsd_flock(&ifl, &fl); 629 630 error = kern_fcntl(td, uap->fd, cmd, (intptr_t)&fl); 631 if (error || cmd != F_GETLK) 632 return (error); 633 634 bsd_to_svr4_flock(&fl, &ifl); 635 636 return (copyout(&ifl, uap->arg, sizeof (ifl))); 637 } 638 case -1: 639 switch (uap->cmd) { 640 case SVR4_F_DUP2FD: 641 { 642 struct dup2_args du; 643 644 du.from = uap->fd; 645 du.to = (int)uap->arg; 646 error = dup2(td, &du); 647 if (error) 648 return error; 649 *retval = du.to; 650 return 0; 651 } 652 653 case SVR4_F_FREESP: 654 { 655 struct svr4_flock ifl; 656 struct flock fl; 657 658 error = copyin(uap->arg, &ifl, 659 sizeof ifl); 660 if (error) 661 return error; 662 svr4_to_bsd_flock(&ifl, &fl); 663 return fd_truncate(td, uap->fd, &fl); 664 } 665 666 case SVR4_F_GETLK64: 667 case SVR4_F_SETLK64: 668 case SVR4_F_SETLKW64: 669 { 670 struct svr4_flock64 ifl; 671 struct flock fl; 672 673 switch (uap->cmd) { 674 case SVR4_F_GETLK64: 675 cmd = F_GETLK; 676 break; 677 case SVR4_F_SETLK64: 678 cmd = F_SETLK; 679 break; 680 case SVR4_F_SETLKW64: 681 cmd = F_SETLKW; 682 break; 683 } 684 error = copyin(uap->arg, &ifl, 685 sizeof (ifl)); 686 if (error) 687 return (error); 688 689 svr4_to_bsd_flock64(&ifl, &fl); 690 691 error = kern_fcntl(td, uap->fd, cmd, 692 (intptr_t)&fl); 693 if (error || cmd != F_GETLK) 694 return (error); 695 696 bsd_to_svr4_flock64(&fl, &ifl); 697 698 return (copyout(&ifl, uap->arg, 699 sizeof (ifl))); 700 } 701 702 case SVR4_F_FREESP64: 703 { 704 struct svr4_flock64 ifl; 705 struct flock fl; 706 707 error = copyin(uap->arg, &ifl, 708 sizeof ifl); 709 if (error) 710 return error; 711 svr4_to_bsd_flock64(&ifl, &fl); 712 return fd_truncate(td, uap->fd, &fl); 713 } 714 715 case SVR4_F_REVOKE: 716 return fd_revoke(td, uap->fd); 717 718 default: 719 return ENOSYS; 720 } 721 722 default: 723 return ENOSYS; 724 } 725} 726