svr4_fcntl.c revision 164033
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 164033 2006-11-06 13:42:10Z 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_check_vnode_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_cred(td->td_ucred, PRIV_VFS_ADMIN, 285 SUSER_ALLOWJAIL)) != 0) 286 goto out; 287 288 if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0) 289 goto out; 290 if (vcount(vp) > 1) 291 VOP_REVOKE(vp, REVOKEALL); 292 vn_finished_write(mp); 293out: 294 vrele(vp); 295 return error; 296} 297 298 299static int 300fd_truncate(td, fd, flp) 301 struct thread *td; 302 int fd; 303 struct flock *flp; 304{ 305 off_t start, length; 306 struct file *fp; 307 struct vnode *vp; 308 struct vattr vattr; 309 int error, *retval; 310 struct ftruncate_args ft; 311 312 retval = td->td_retval; 313 314 /* 315 * We only support truncating the file. 316 */ 317 if ((error = fget(td, fd, &fp)) != 0) 318 return (error); 319 320 vp = fp->f_vnode; 321 322 if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO) { 323 fdrop(fp, td); 324 return ESPIPE; 325 } 326 327 if ((error = VOP_GETATTR(vp, &vattr, td->td_ucred, td)) != 0) { 328 fdrop(fp, td); 329 return error; 330 } 331 332 length = vattr.va_size; 333 334 switch (flp->l_whence) { 335 case SEEK_CUR: 336 start = fp->f_offset + flp->l_start; 337 break; 338 339 case SEEK_END: 340 start = flp->l_start + length; 341 break; 342 343 case SEEK_SET: 344 start = flp->l_start; 345 break; 346 347 default: 348 fdrop(fp, td); 349 return EINVAL; 350 } 351 352 if (start + flp->l_len < length) { 353 /* We don't support free'ing in the middle of the file */ 354 fdrop(fp, td); 355 return EINVAL; 356 } 357 358 ft.fd = fd; 359 ft.length = start; 360 361 error = ftruncate(td, &ft); 362 363 fdrop(fp, td); 364 return (error); 365} 366 367int 368svr4_sys_open(td, uap) 369 register struct thread *td; 370 struct svr4_sys_open_args *uap; 371{ 372 struct proc *p = td->td_proc; 373 char *newpath; 374 int bsd_flags, error, retval; 375 376 CHECKALTEXIST(td, uap->path, &newpath); 377 378 bsd_flags = svr4_to_bsd_flags(uap->flags); 379 error = kern_open(td, newpath, UIO_SYSSPACE, bsd_flags, uap->mode); 380 free(newpath, M_TEMP); 381 382 if (error) { 383 /* uprintf("svr4_open(%s, 0x%0x, 0%o): %d\n", uap->path, 384 uap->flags, uap->mode, error);*/ 385 return error; 386 } 387 388 retval = td->td_retval[0]; 389 390 PROC_LOCK(p); 391 if (!(bsd_flags & O_NOCTTY) && SESS_LEADER(p) && 392 !(p->p_flag & P_CONTROLT)) { 393#if defined(NOTYET) 394 struct file *fp; 395 396 error = fget(td, retval, &fp); 397 PROC_UNLOCK(p); 398 /* 399 * we may have lost a race the above open() and 400 * another thread issuing a close() 401 */ 402 if (error) 403 return (EBADF); /* XXX: correct errno? */ 404 /* ignore any error, just give it a try */ 405 if (fp->f_type == DTYPE_VNODE) 406 fo_ioctl(fp, TIOCSCTTY, (caddr_t) 0, td->td_ucred, 407 td); 408 fdrop(fp, td); 409 } else { 410 PROC_UNLOCK(p); 411 } 412#else 413 } 414 PROC_UNLOCK(p); 415#endif 416 return error; 417} 418 419int 420svr4_sys_open64(td, uap) 421 register struct thread *td; 422 struct svr4_sys_open64_args *uap; 423{ 424 return svr4_sys_open(td, (struct svr4_sys_open_args *)uap); 425} 426 427int 428svr4_sys_creat(td, uap) 429 register struct thread *td; 430 struct svr4_sys_creat_args *uap; 431{ 432 char *newpath; 433 int error; 434 435 CHECKALTEXIST(td, uap->path, &newpath); 436 437 error = kern_open(td, newpath, UIO_SYSSPACE, O_WRONLY | O_CREAT | 438 O_TRUNC, uap->mode); 439 free(newpath, M_TEMP); 440 return (error); 441} 442 443int 444svr4_sys_creat64(td, uap) 445 register struct thread *td; 446 struct svr4_sys_creat64_args *uap; 447{ 448 return svr4_sys_creat(td, (struct svr4_sys_creat_args *)uap); 449} 450 451int 452svr4_sys_llseek(td, uap) 453 register struct thread *td; 454 struct svr4_sys_llseek_args *uap; 455{ 456 struct lseek_args ap; 457 458 ap.fd = uap->fd; 459 460#if BYTE_ORDER == BIG_ENDIAN 461 ap.offset = (((u_int64_t) uap->offset1) << 32) | 462 uap->offset2; 463#else 464 ap.offset = (((u_int64_t) uap->offset2) << 32) | 465 uap->offset1; 466#endif 467 ap.whence = uap->whence; 468 469 return lseek(td, &ap); 470} 471 472int 473svr4_sys_access(td, uap) 474 register struct thread *td; 475 struct svr4_sys_access_args *uap; 476{ 477 char *newpath; 478 int error; 479 480 CHECKALTEXIST(td, uap->path, &newpath); 481 error = kern_access(td, newpath, UIO_SYSSPACE, uap->flags); 482 free(newpath, M_TEMP); 483 return (error); 484} 485 486#if defined(NOTYET) 487int 488svr4_sys_pread(td, uap) 489 register struct thread *td; 490 struct svr4_sys_pread_args *uap; 491{ 492 struct pread_args pra; 493 494 /* 495 * Just translate the args structure and call the NetBSD 496 * pread(2) system call (offset type is 64-bit in NetBSD). 497 */ 498 pra.fd = uap->fd; 499 pra.buf = uap->buf; 500 pra.nbyte = uap->nbyte; 501 pra.offset = uap->off; 502 503 return pread(td, &pra); 504} 505#endif 506 507#if defined(NOTYET) 508int 509svr4_sys_pread64(td, v, retval) 510 register struct thread *td; 511 void *v; 512 register_t *retval; 513{ 514 515 struct svr4_sys_pread64_args *uap = v; 516 struct sys_pread_args pra; 517 518 /* 519 * Just translate the args structure and call the NetBSD 520 * pread(2) system call (offset type is 64-bit in NetBSD). 521 */ 522 pra.fd = uap->fd; 523 pra.buf = uap->buf; 524 pra.nbyte = uap->nbyte; 525 pra.offset = uap->off; 526 527 return (sys_pread(td, &pra, retval)); 528} 529#endif /* NOTYET */ 530 531#if defined(NOTYET) 532int 533svr4_sys_pwrite(td, uap) 534 register struct thread *td; 535 struct svr4_sys_pwrite_args *uap; 536{ 537 struct pwrite_args pwa; 538 539 /* 540 * Just translate the args structure and call the NetBSD 541 * pwrite(2) system call (offset type is 64-bit in NetBSD). 542 */ 543 pwa.fd = uap->fd; 544 pwa.buf = uap->buf; 545 pwa.nbyte = uap->nbyte; 546 pwa.offset = uap->off; 547 548 return pwrite(td, &pwa); 549} 550#endif 551 552#if defined(NOTYET) 553int 554svr4_sys_pwrite64(td, v, retval) 555 register struct thread *td; 556 void *v; 557 register_t *retval; 558{ 559 struct svr4_sys_pwrite64_args *uap = v; 560 struct sys_pwrite_args pwa; 561 562 /* 563 * Just translate the args structure and call the NetBSD 564 * pwrite(2) system call (offset type is 64-bit in NetBSD). 565 */ 566 pwa.fd = uap->fd; 567 pwa.buf = uap->buf; 568 pwa.nbyte = uap->nbyte; 569 pwa.offset = uap->off; 570 571 return (sys_pwrite(td, &pwa, retval)); 572} 573#endif /* NOTYET */ 574 575int 576svr4_sys_fcntl(td, uap) 577 register struct thread *td; 578 struct svr4_sys_fcntl_args *uap; 579{ 580 int cmd, error, *retval; 581 582 retval = td->td_retval; 583 584 cmd = svr4_to_bsd_cmd(uap->cmd); 585 586 switch (cmd) { 587 case F_DUPFD: 588 case F_GETFD: 589 case F_SETFD: 590 return (kern_fcntl(td, uap->fd, cmd, (intptr_t)uap->arg)); 591 592 case F_GETFL: 593 error = kern_fcntl(td, uap->fd, cmd, (intptr_t)uap->arg); 594 if (error) 595 return (error); 596 *retval = bsd_to_svr4_flags(*retval); 597 return (error); 598 599 case F_SETFL: 600 { 601 /* 602 * we must save the O_ASYNC flag, as that is 603 * handled by ioctl(_, I_SETSIG, _) emulation. 604 */ 605 int flags; 606 607 DPRINTF(("Setting flags %p\n", uap->arg)); 608 609 error = kern_fcntl(td, uap->fd, F_GETFL, 0); 610 if (error) 611 return (error); 612 flags = *retval; 613 flags &= O_ASYNC; 614 flags |= svr4_to_bsd_flags((u_long) uap->arg); 615 return (kern_fcntl(td, uap->fd, F_SETFL, flags)); 616 } 617 618 case F_GETLK: 619 case F_SETLK: 620 case F_SETLKW: 621 { 622 struct svr4_flock ifl; 623 struct flock fl; 624 625 error = copyin(uap->arg, &ifl, sizeof (ifl)); 626 if (error) 627 return (error); 628 629 svr4_to_bsd_flock(&ifl, &fl); 630 631 error = kern_fcntl(td, uap->fd, cmd, (intptr_t)&fl); 632 if (error || cmd != F_GETLK) 633 return (error); 634 635 bsd_to_svr4_flock(&fl, &ifl); 636 637 return (copyout(&ifl, uap->arg, sizeof (ifl))); 638 } 639 case -1: 640 switch (uap->cmd) { 641 case SVR4_F_DUP2FD: 642 { 643 struct dup2_args du; 644 645 du.from = uap->fd; 646 du.to = (int)uap->arg; 647 error = dup2(td, &du); 648 if (error) 649 return error; 650 *retval = du.to; 651 return 0; 652 } 653 654 case SVR4_F_FREESP: 655 { 656 struct svr4_flock ifl; 657 struct flock fl; 658 659 error = copyin(uap->arg, &ifl, 660 sizeof ifl); 661 if (error) 662 return error; 663 svr4_to_bsd_flock(&ifl, &fl); 664 return fd_truncate(td, uap->fd, &fl); 665 } 666 667 case SVR4_F_GETLK64: 668 case SVR4_F_SETLK64: 669 case SVR4_F_SETLKW64: 670 { 671 struct svr4_flock64 ifl; 672 struct flock fl; 673 674 switch (uap->cmd) { 675 case SVR4_F_GETLK64: 676 cmd = F_GETLK; 677 break; 678 case SVR4_F_SETLK64: 679 cmd = F_SETLK; 680 break; 681 case SVR4_F_SETLKW64: 682 cmd = F_SETLKW; 683 break; 684 } 685 error = copyin(uap->arg, &ifl, 686 sizeof (ifl)); 687 if (error) 688 return (error); 689 690 svr4_to_bsd_flock64(&ifl, &fl); 691 692 error = kern_fcntl(td, uap->fd, cmd, 693 (intptr_t)&fl); 694 if (error || cmd != F_GETLK) 695 return (error); 696 697 bsd_to_svr4_flock64(&fl, &ifl); 698 699 return (copyout(&ifl, uap->arg, 700 sizeof (ifl))); 701 } 702 703 case SVR4_F_FREESP64: 704 { 705 struct svr4_flock64 ifl; 706 struct flock fl; 707 708 error = copyin(uap->arg, &ifl, 709 sizeof ifl); 710 if (error) 711 return error; 712 svr4_to_bsd_flock64(&ifl, &fl); 713 return fd_truncate(td, uap->fd, &fl); 714 } 715 716 case SVR4_F_REVOKE: 717 return fd_revoke(td, uap->fd); 718 719 default: 720 return ENOSYS; 721 } 722 723 default: 724 return ENOSYS; 725 } 726} 727