svr4_fcntl.c revision 177633
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 177633 2008-03-26 15:23:12Z dfr $"); 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_DUP2FD: 83 return F_DUP2FD; 84 case SVR4_F_GETFD: 85 return F_GETFD; 86 case SVR4_F_SETFD: 87 return F_SETFD; 88 case SVR4_F_GETFL: 89 return F_GETFL; 90 case SVR4_F_SETFL: 91 return F_SETFL; 92 case SVR4_F_GETLK: 93 return F_GETLK; 94 case SVR4_F_SETLK: 95 return F_SETLK; 96 case SVR4_F_SETLKW: 97 return F_SETLKW; 98 default: 99 return -1; 100 } 101} 102 103static int 104svr4_to_bsd_flags(l) 105 int l; 106{ 107 int r = 0; 108 r |= (l & SVR4_O_RDONLY) ? O_RDONLY : 0; 109 r |= (l & SVR4_O_WRONLY) ? O_WRONLY : 0; 110 r |= (l & SVR4_O_RDWR) ? O_RDWR : 0; 111 r |= (l & SVR4_O_NDELAY) ? O_NONBLOCK : 0; 112 r |= (l & SVR4_O_APPEND) ? O_APPEND : 0; 113 r |= (l & SVR4_O_SYNC) ? O_FSYNC : 0; 114 r |= (l & SVR4_O_NONBLOCK) ? O_NONBLOCK : 0; 115 r |= (l & SVR4_O_PRIV) ? O_EXLOCK : 0; 116 r |= (l & SVR4_O_CREAT) ? O_CREAT : 0; 117 r |= (l & SVR4_O_TRUNC) ? O_TRUNC : 0; 118 r |= (l & SVR4_O_EXCL) ? O_EXCL : 0; 119 r |= (l & SVR4_O_NOCTTY) ? O_NOCTTY : 0; 120 return r; 121} 122 123static int 124bsd_to_svr4_flags(l) 125 int l; 126{ 127 int r = 0; 128 r |= (l & O_RDONLY) ? SVR4_O_RDONLY : 0; 129 r |= (l & O_WRONLY) ? SVR4_O_WRONLY : 0; 130 r |= (l & O_RDWR) ? SVR4_O_RDWR : 0; 131 r |= (l & O_NDELAY) ? SVR4_O_NONBLOCK : 0; 132 r |= (l & O_APPEND) ? SVR4_O_APPEND : 0; 133 r |= (l & O_FSYNC) ? SVR4_O_SYNC : 0; 134 r |= (l & O_NONBLOCK) ? SVR4_O_NONBLOCK : 0; 135 r |= (l & O_EXLOCK) ? SVR4_O_PRIV : 0; 136 r |= (l & O_CREAT) ? SVR4_O_CREAT : 0; 137 r |= (l & O_TRUNC) ? SVR4_O_TRUNC : 0; 138 r |= (l & O_EXCL) ? SVR4_O_EXCL : 0; 139 r |= (l & O_NOCTTY) ? SVR4_O_NOCTTY : 0; 140 return r; 141} 142 143 144static void 145bsd_to_svr4_flock(iflp, oflp) 146 struct flock *iflp; 147 struct svr4_flock *oflp; 148{ 149 switch (iflp->l_type) { 150 case F_RDLCK: 151 oflp->l_type = SVR4_F_RDLCK; 152 break; 153 case F_WRLCK: 154 oflp->l_type = SVR4_F_WRLCK; 155 break; 156 case F_UNLCK: 157 oflp->l_type = SVR4_F_UNLCK; 158 break; 159 default: 160 oflp->l_type = -1; 161 break; 162 } 163 164 oflp->l_whence = (short) iflp->l_whence; 165 oflp->l_start = (svr4_off_t) iflp->l_start; 166 oflp->l_len = (svr4_off_t) iflp->l_len; 167 oflp->l_sysid = 0; 168 oflp->l_pid = (svr4_pid_t) iflp->l_pid; 169} 170 171 172static void 173svr4_to_bsd_flock(iflp, oflp) 174 struct svr4_flock *iflp; 175 struct flock *oflp; 176{ 177 switch (iflp->l_type) { 178 case SVR4_F_RDLCK: 179 oflp->l_type = F_RDLCK; 180 break; 181 case SVR4_F_WRLCK: 182 oflp->l_type = F_WRLCK; 183 break; 184 case SVR4_F_UNLCK: 185 oflp->l_type = F_UNLCK; 186 break; 187 default: 188 oflp->l_type = -1; 189 break; 190 } 191 192 oflp->l_whence = iflp->l_whence; 193 oflp->l_start = (off_t) iflp->l_start; 194 oflp->l_len = (off_t) iflp->l_len; 195 oflp->l_pid = (pid_t) iflp->l_pid; 196 oflp->l_sysid = iflp->l_sysid; 197} 198 199static void 200bsd_to_svr4_flock64(iflp, oflp) 201 struct flock *iflp; 202 struct svr4_flock64 *oflp; 203{ 204 switch (iflp->l_type) { 205 case F_RDLCK: 206 oflp->l_type = SVR4_F_RDLCK; 207 break; 208 case F_WRLCK: 209 oflp->l_type = SVR4_F_WRLCK; 210 break; 211 case F_UNLCK: 212 oflp->l_type = SVR4_F_UNLCK; 213 break; 214 default: 215 oflp->l_type = -1; 216 break; 217 } 218 219 oflp->l_whence = (short) iflp->l_whence; 220 oflp->l_start = (svr4_off64_t) iflp->l_start; 221 oflp->l_len = (svr4_off64_t) iflp->l_len; 222 oflp->l_sysid = iflp->l_sysid; 223 oflp->l_pid = (svr4_pid_t) iflp->l_pid; 224} 225 226 227static void 228svr4_to_bsd_flock64(iflp, oflp) 229 struct svr4_flock64 *iflp; 230 struct flock *oflp; 231{ 232 switch (iflp->l_type) { 233 case SVR4_F_RDLCK: 234 oflp->l_type = F_RDLCK; 235 break; 236 case SVR4_F_WRLCK: 237 oflp->l_type = F_WRLCK; 238 break; 239 case SVR4_F_UNLCK: 240 oflp->l_type = F_UNLCK; 241 break; 242 default: 243 oflp->l_type = -1; 244 break; 245 } 246 247 oflp->l_whence = iflp->l_whence; 248 oflp->l_start = (off_t) iflp->l_start; 249 oflp->l_len = (off_t) iflp->l_len; 250 oflp->l_pid = (pid_t) iflp->l_pid; 251 252} 253 254 255static int 256fd_revoke(td, fd) 257 struct thread *td; 258 int fd; 259{ 260 struct vnode *vp; 261 struct mount *mp; 262 struct vattr vattr; 263 int error, *retval; 264 265 retval = td->td_retval; 266 if ((error = fgetvp(td, fd, &vp)) != 0) 267 return (error); 268 269 if (vp->v_type != VCHR && vp->v_type != VBLK) { 270 error = EINVAL; 271 goto out; 272 } 273 274#ifdef MAC 275 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 276 error = mac_vnode_check_revoke(td->td_ucred, vp); 277 VOP_UNLOCK(vp, 0); 278 if (error) 279 goto out; 280#endif 281 282 if ((error = VOP_GETATTR(vp, &vattr, td->td_ucred, td)) != 0) 283 goto out; 284 285 if (td->td_ucred->cr_uid != vattr.va_uid && 286 (error = priv_check(td, PRIV_VFS_ADMIN)) != 0) 287 goto out; 288 289 if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0) 290 goto out; 291 if (vcount(vp) > 1) 292 VOP_REVOKE(vp, REVOKEALL); 293 vn_finished_write(mp); 294out: 295 vrele(vp); 296 return error; 297} 298 299 300static int 301fd_truncate(td, fd, flp) 302 struct thread *td; 303 int fd; 304 struct flock *flp; 305{ 306 off_t start, length; 307 struct file *fp; 308 struct vnode *vp; 309 struct vattr vattr; 310 int error, *retval; 311 struct ftruncate_args ft; 312 313 retval = td->td_retval; 314 315 /* 316 * We only support truncating the file. 317 */ 318 if ((error = fget(td, fd, &fp)) != 0) 319 return (error); 320 321 vp = fp->f_vnode; 322 323 if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO) { 324 fdrop(fp, td); 325 return ESPIPE; 326 } 327 328 if ((error = VOP_GETATTR(vp, &vattr, td->td_ucred, td)) != 0) { 329 fdrop(fp, td); 330 return error; 331 } 332 333 length = vattr.va_size; 334 335 switch (flp->l_whence) { 336 case SEEK_CUR: 337 start = fp->f_offset + flp->l_start; 338 break; 339 340 case SEEK_END: 341 start = flp->l_start + length; 342 break; 343 344 case SEEK_SET: 345 start = flp->l_start; 346 break; 347 348 default: 349 fdrop(fp, td); 350 return EINVAL; 351 } 352 353 if (start + flp->l_len < length) { 354 /* We don't support free'ing in the middle of the file */ 355 fdrop(fp, td); 356 return EINVAL; 357 } 358 359 ft.fd = fd; 360 ft.length = start; 361 362 error = ftruncate(td, &ft); 363 364 fdrop(fp, td); 365 return (error); 366} 367 368int 369svr4_sys_open(td, uap) 370 register struct thread *td; 371 struct svr4_sys_open_args *uap; 372{ 373 struct proc *p = td->td_proc; 374 char *newpath; 375 int bsd_flags, error, retval; 376 377 CHECKALTEXIST(td, uap->path, &newpath); 378 379 bsd_flags = svr4_to_bsd_flags(uap->flags); 380 error = kern_open(td, newpath, UIO_SYSSPACE, bsd_flags, uap->mode); 381 free(newpath, M_TEMP); 382 383 if (error) { 384 /* uprintf("svr4_open(%s, 0x%0x, 0%o): %d\n", uap->path, 385 uap->flags, uap->mode, error);*/ 386 return error; 387 } 388 389 retval = td->td_retval[0]; 390 391 PROC_LOCK(p); 392 if (!(bsd_flags & O_NOCTTY) && SESS_LEADER(p) && 393 !(p->p_flag & P_CONTROLT)) { 394#if defined(NOTYET) 395 struct file *fp; 396 397 error = fget(td, retval, &fp); 398 PROC_UNLOCK(p); 399 /* 400 * we may have lost a race the above open() and 401 * another thread issuing a close() 402 */ 403 if (error) 404 return (EBADF); /* XXX: correct errno? */ 405 /* ignore any error, just give it a try */ 406 if (fp->f_type == DTYPE_VNODE) 407 fo_ioctl(fp, TIOCSCTTY, (caddr_t) 0, td->td_ucred, 408 td); 409 fdrop(fp, td); 410 } else { 411 PROC_UNLOCK(p); 412 } 413#else 414 } 415 PROC_UNLOCK(p); 416#endif 417 return error; 418} 419 420int 421svr4_sys_open64(td, uap) 422 register struct thread *td; 423 struct svr4_sys_open64_args *uap; 424{ 425 return svr4_sys_open(td, (struct svr4_sys_open_args *)uap); 426} 427 428int 429svr4_sys_creat(td, uap) 430 register struct thread *td; 431 struct svr4_sys_creat_args *uap; 432{ 433 char *newpath; 434 int error; 435 436 CHECKALTEXIST(td, uap->path, &newpath); 437 438 error = kern_open(td, newpath, UIO_SYSSPACE, O_WRONLY | O_CREAT | 439 O_TRUNC, uap->mode); 440 free(newpath, M_TEMP); 441 return (error); 442} 443 444int 445svr4_sys_creat64(td, uap) 446 register struct thread *td; 447 struct svr4_sys_creat64_args *uap; 448{ 449 return svr4_sys_creat(td, (struct svr4_sys_creat_args *)uap); 450} 451 452int 453svr4_sys_llseek(td, uap) 454 register struct thread *td; 455 struct svr4_sys_llseek_args *uap; 456{ 457 struct lseek_args ap; 458 459 ap.fd = uap->fd; 460 461#if BYTE_ORDER == BIG_ENDIAN 462 ap.offset = (((u_int64_t) uap->offset1) << 32) | 463 uap->offset2; 464#else 465 ap.offset = (((u_int64_t) uap->offset2) << 32) | 466 uap->offset1; 467#endif 468 ap.whence = uap->whence; 469 470 return lseek(td, &ap); 471} 472 473int 474svr4_sys_access(td, uap) 475 register struct thread *td; 476 struct svr4_sys_access_args *uap; 477{ 478 char *newpath; 479 int error; 480 481 CHECKALTEXIST(td, uap->path, &newpath); 482 error = kern_access(td, newpath, UIO_SYSSPACE, uap->flags); 483 free(newpath, M_TEMP); 484 return (error); 485} 486 487#if defined(NOTYET) 488int 489svr4_sys_pread(td, uap) 490 register struct thread *td; 491 struct svr4_sys_pread_args *uap; 492{ 493 struct pread_args pra; 494 495 /* 496 * Just translate the args structure and call the NetBSD 497 * pread(2) system call (offset type is 64-bit in NetBSD). 498 */ 499 pra.fd = uap->fd; 500 pra.buf = uap->buf; 501 pra.nbyte = uap->nbyte; 502 pra.offset = uap->off; 503 504 return pread(td, &pra); 505} 506#endif 507 508#if defined(NOTYET) 509int 510svr4_sys_pread64(td, v, retval) 511 register struct thread *td; 512 void *v; 513 register_t *retval; 514{ 515 516 struct svr4_sys_pread64_args *uap = v; 517 struct sys_pread_args pra; 518 519 /* 520 * Just translate the args structure and call the NetBSD 521 * pread(2) system call (offset type is 64-bit in NetBSD). 522 */ 523 pra.fd = uap->fd; 524 pra.buf = uap->buf; 525 pra.nbyte = uap->nbyte; 526 pra.offset = uap->off; 527 528 return (sys_pread(td, &pra, retval)); 529} 530#endif /* NOTYET */ 531 532#if defined(NOTYET) 533int 534svr4_sys_pwrite(td, uap) 535 register struct thread *td; 536 struct svr4_sys_pwrite_args *uap; 537{ 538 struct pwrite_args pwa; 539 540 /* 541 * Just translate the args structure and call the NetBSD 542 * pwrite(2) system call (offset type is 64-bit in NetBSD). 543 */ 544 pwa.fd = uap->fd; 545 pwa.buf = uap->buf; 546 pwa.nbyte = uap->nbyte; 547 pwa.offset = uap->off; 548 549 return pwrite(td, &pwa); 550} 551#endif 552 553#if defined(NOTYET) 554int 555svr4_sys_pwrite64(td, v, retval) 556 register struct thread *td; 557 void *v; 558 register_t *retval; 559{ 560 struct svr4_sys_pwrite64_args *uap = v; 561 struct sys_pwrite_args pwa; 562 563 /* 564 * Just translate the args structure and call the NetBSD 565 * pwrite(2) system call (offset type is 64-bit in NetBSD). 566 */ 567 pwa.fd = uap->fd; 568 pwa.buf = uap->buf; 569 pwa.nbyte = uap->nbyte; 570 pwa.offset = uap->off; 571 572 return (sys_pwrite(td, &pwa, retval)); 573} 574#endif /* NOTYET */ 575 576int 577svr4_sys_fcntl(td, uap) 578 register struct thread *td; 579 struct svr4_sys_fcntl_args *uap; 580{ 581 int cmd, error, *retval; 582 583 retval = td->td_retval; 584 585 cmd = svr4_to_bsd_cmd(uap->cmd); 586 587 switch (cmd) { 588 case F_DUPFD: 589 case F_DUP2FD: 590 case F_GETFD: 591 case F_SETFD: 592 return (kern_fcntl(td, uap->fd, cmd, (intptr_t)uap->arg)); 593 594 case F_GETFL: 595 error = kern_fcntl(td, uap->fd, cmd, (intptr_t)uap->arg); 596 if (error) 597 return (error); 598 *retval = bsd_to_svr4_flags(*retval); 599 return (error); 600 601 case F_SETFL: 602 { 603 /* 604 * we must save the O_ASYNC flag, as that is 605 * handled by ioctl(_, I_SETSIG, _) emulation. 606 */ 607 int flags; 608 609 DPRINTF(("Setting flags %p\n", uap->arg)); 610 611 error = kern_fcntl(td, uap->fd, F_GETFL, 0); 612 if (error) 613 return (error); 614 flags = *retval; 615 flags &= O_ASYNC; 616 flags |= svr4_to_bsd_flags((u_long) uap->arg); 617 return (kern_fcntl(td, uap->fd, F_SETFL, flags)); 618 } 619 620 case F_GETLK: 621 case F_SETLK: 622 case F_SETLKW: 623 { 624 struct svr4_flock ifl; 625 struct flock fl; 626 627 error = copyin(uap->arg, &ifl, sizeof (ifl)); 628 if (error) 629 return (error); 630 631 svr4_to_bsd_flock(&ifl, &fl); 632 633 error = kern_fcntl(td, uap->fd, cmd, (intptr_t)&fl); 634 if (error || cmd != F_GETLK) 635 return (error); 636 637 bsd_to_svr4_flock(&fl, &ifl); 638 639 return (copyout(&ifl, uap->arg, sizeof (ifl))); 640 } 641 case -1: 642 switch (uap->cmd) { 643 case SVR4_F_FREESP: 644 { 645 struct svr4_flock ifl; 646 struct flock fl; 647 648 error = copyin(uap->arg, &ifl, 649 sizeof ifl); 650 if (error) 651 return error; 652 svr4_to_bsd_flock(&ifl, &fl); 653 return fd_truncate(td, uap->fd, &fl); 654 } 655 656 case SVR4_F_GETLK64: 657 case SVR4_F_SETLK64: 658 case SVR4_F_SETLKW64: 659 { 660 struct svr4_flock64 ifl; 661 struct flock fl; 662 663 switch (uap->cmd) { 664 case SVR4_F_GETLK64: 665 cmd = F_GETLK; 666 break; 667 case SVR4_F_SETLK64: 668 cmd = F_SETLK; 669 break; 670 case SVR4_F_SETLKW64: 671 cmd = F_SETLKW; 672 break; 673 } 674 error = copyin(uap->arg, &ifl, 675 sizeof (ifl)); 676 if (error) 677 return (error); 678 679 svr4_to_bsd_flock64(&ifl, &fl); 680 681 error = kern_fcntl(td, uap->fd, cmd, 682 (intptr_t)&fl); 683 if (error || cmd != F_GETLK) 684 return (error); 685 686 bsd_to_svr4_flock64(&fl, &ifl); 687 688 return (copyout(&ifl, uap->arg, 689 sizeof (ifl))); 690 } 691 692 case SVR4_F_FREESP64: 693 { 694 struct svr4_flock64 ifl; 695 struct flock fl; 696 697 error = copyin(uap->arg, &ifl, 698 sizeof ifl); 699 if (error) 700 return error; 701 svr4_to_bsd_flock64(&ifl, &fl); 702 return fd_truncate(td, uap->fd, &fl); 703 } 704 705 case SVR4_F_REVOKE: 706 return fd_revoke(td, uap->fd); 707 708 default: 709 return ENOSYS; 710 } 711 712 default: 713 return ENOSYS; 714 } 715} 716