1 /* 2 * Copyright (c) 1989, 1993 3 * The Regents of the University of California. All rights reserved. 4 * (c) UNIX System Laboratories, Inc. 5 * All or some portions of this file are derived from material licensed 6 * to the University of California by American Telephone and Telegraph 7 * Co. or Unix System Laboratories, Inc. and are reproduced herein with 8 * the permission of UNIX System Laboratories, Inc. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the University of 21 * California, Berkeley and its contributors. 22 * 4. Neither the name of the University nor the names of its contributors 23 * may be used to endorse or promote products derived from this software 24 * without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36 * SUCH DAMAGE. 37 * 38 * @(#)vfs_syscalls.c 8.13 (Berkeley) 4/15/94 39 * $Id: vfs_syscalls.c,v 1.16 1994/11/04 14:41:34 davidg Exp $ 40 */ 41 42 #include <sys/param.h> 43 #include <sys/systm.h> 44 #include <sys/namei.h> 45 #include <sys/filedesc.h> 46 #include <sys/kernel.h> 47 #include <sys/file.h> 48 #include <sys/stat.h> 49 #include <sys/vnode.h> 50 #include <sys/mount.h> 51 #include <sys/proc.h> 52 #include <sys/uio.h> 53 #include <sys/malloc.h> 54 #include <sys/dirent.h> 55 56 #include <vm/vm.h> 57 #include <sys/sysctl.h> 58 59 static int change_dir __P((struct nameidata *ndp, struct proc *p)); 60 int getvnode __P((struct filedesc *, int, struct file **)); 61 62 /* 63 * Virtual File System System Calls 64 */ 65 66 /* 67 * Mount a file system. 68 */ 69 struct mount_args { 70 int type; 71 char *path; 72 int flags; 73 caddr_t data; 74 }; 75 /* ARGSUSED */ 76 int 77 mount(p, uap, retval) 78 struct proc *p; 79 register struct mount_args *uap; 80 int *retval; 81 { 82 register struct vnode *vp; 83 register struct mount *mp; 84 int error, flag = 0; 85 struct nameidata nd; 86 87 /* 88 * Must be super user 89 */ 90 error = suser(p->p_ucred, &p->p_acflag); 91 if (error) 92 return (error); 93 /* 94 * Get vnode to be covered 95 */ 96 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); 97 error = namei(&nd); 98 if (error) 99 return (error); 100 vp = nd.ni_vp; 101 if (uap->flags & MNT_UPDATE) { 102 if ((vp->v_flag & VROOT) == 0) { 103 vput(vp); 104 return (EINVAL); 105 } 106 mp = vp->v_mount; 107 flag = mp->mnt_flag; 108 /* 109 * We only allow the filesystem to be reloaded if it 110 * is currently mounted read-only. 111 */ 112 if ((uap->flags & MNT_RELOAD) && 113 ((mp->mnt_flag & MNT_RDONLY) == 0)) { 114 vput(vp); 115 return (EOPNOTSUPP); /* Needs translation */ 116 } 117 mp->mnt_flag |= 118 uap->flags & (MNT_RELOAD | MNT_FORCE | MNT_UPDATE); 119 VOP_UNLOCK(vp); 120 goto update; 121 } 122 error = vinvalbuf(vp, V_SAVE, p->p_ucred, p, 0, 0); 123 if (error) 124 return (error); 125 if (vp->v_type != VDIR) { 126 vput(vp); 127 return (ENOTDIR); 128 } 129 if ((u_long)uap->type > MOUNT_MAXTYPE || vfssw[uap->type] == NULL) { 130 vput(vp); 131 return (ENODEV); 132 } 133 134 /* 135 * Allocate and initialize the file system. 136 */ 137 mp = (struct mount *)malloc((u_long)sizeof(struct mount), 138 M_MOUNT, M_WAITOK); 139 bzero((char *)mp, (u_long)sizeof(struct mount)); 140 mp->mnt_op = vfssw[uap->type]; 141 mp->mnt_vfc = vfsconf[uap->type]; 142 error = vfs_lock(mp); 143 if (error) { 144 free((caddr_t)mp, M_MOUNT); 145 vput(vp); 146 return (error); 147 } 148 if (vp->v_mountedhere != NULL) { 149 vfs_unlock(mp); 150 free((caddr_t)mp, M_MOUNT); 151 vput(vp); 152 return (EBUSY); 153 } 154 vp->v_mountedhere = mp; 155 mp->mnt_vnodecovered = vp; 156 vfsconf[uap->type]->vfc_refcount++; 157 158 update: 159 /* 160 * Set the mount level flags. 161 */ 162 if (uap->flags & MNT_RDONLY) 163 mp->mnt_flag |= MNT_RDONLY; 164 else if (mp->mnt_flag & MNT_RDONLY) 165 mp->mnt_flag |= MNT_WANTRDWR; 166 mp->mnt_flag &=~ (MNT_NOSUID | MNT_NOEXEC | MNT_NODEV | 167 MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC); 168 mp->mnt_flag |= uap->flags & (MNT_NOSUID | MNT_NOEXEC | MNT_NODEV | 169 MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC); 170 /* 171 * Mount the filesystem. 172 */ 173 error = VFS_MOUNT(mp, uap->path, uap->data, &nd, p); 174 if (mp->mnt_flag & MNT_UPDATE) { 175 vrele(vp); 176 if (mp->mnt_flag & MNT_WANTRDWR) 177 mp->mnt_flag &= ~MNT_RDONLY; 178 mp->mnt_flag &=~ 179 (MNT_UPDATE | MNT_RELOAD | MNT_FORCE | MNT_WANTRDWR); 180 if (error) 181 mp->mnt_flag = flag; 182 return (error); 183 } 184 /* 185 * Put the new filesystem on the mount list after root. 186 */ 187 cache_purge(vp); 188 if (!error) { 189 TAILQ_INSERT_TAIL(&mountlist, mp, mnt_list); 190 VOP_UNLOCK(vp); 191 vfs_unlock(mp); 192 error = VFS_START(mp, 0, p); 193 } else { 194 mp->mnt_vnodecovered->v_mountedhere = (struct mount *)0; 195 vfs_unlock(mp); 196 free((caddr_t)mp, M_MOUNT); 197 vput(vp); 198 vfsconf[uap->type]->vfc_refcount--; 199 } 200 return (error); 201 } 202 203 /* 204 * Unmount a file system. 205 * 206 * Note: unmount takes a path to the vnode mounted on as argument, 207 * not special file (as before). 208 */ 209 struct unmount_args { 210 char *path; 211 int flags; 212 }; 213 /* ARGSUSED */ 214 int 215 unmount(p, uap, retval) 216 struct proc *p; 217 register struct unmount_args *uap; 218 int *retval; 219 { 220 register struct vnode *vp; 221 struct mount *mp; 222 int error; 223 struct nameidata nd; 224 225 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); 226 error = namei(&nd); 227 if (error) 228 return (error); 229 vp = nd.ni_vp; 230 231 /* 232 * Unless this is a user mount, then must 233 * have suser privilege. 234 */ 235 if (((vp->v_mount->mnt_flag & MNT_USER) == 0) && 236 (error = suser(p->p_ucred, &p->p_acflag))) { 237 vput(vp); 238 return (error); 239 } 240 241 /* 242 * Must be the root of the filesystem 243 */ 244 if ((vp->v_flag & VROOT) == 0) { 245 vput(vp); 246 return (EINVAL); 247 } 248 mp = vp->v_mount; 249 vput(vp); 250 251 /* 252 * Don't allow unmount of the root filesystem 253 */ 254 if (mp->mnt_flag & MNT_ROOTFS) 255 return (EINVAL); 256 257 return (dounmount(mp, uap->flags, p)); 258 } 259 260 /* 261 * Do the actual file system unmount. 262 */ 263 int 264 dounmount(mp, flags, p) 265 register struct mount *mp; 266 int flags; 267 struct proc *p; 268 { 269 struct vnode *coveredvp; 270 int error; 271 272 coveredvp = mp->mnt_vnodecovered; 273 if (vfs_busy(mp)) 274 return (EBUSY); 275 mp->mnt_flag |= MNT_UNMOUNT; 276 error = vfs_lock(mp); 277 if (error) 278 return (error); 279 280 mp->mnt_flag &=~ MNT_ASYNC; 281 vnode_pager_umount(mp); /* release cached vnodes */ 282 cache_purgevfs(mp); /* remove cache entries for this file sys */ 283 if ((error = VFS_SYNC(mp, MNT_WAIT, p->p_ucred, p)) == 0 || 284 (flags & MNT_FORCE)) 285 error = VFS_UNMOUNT(mp, flags, p); 286 mp->mnt_flag &= ~MNT_UNMOUNT; 287 vfs_unbusy(mp); 288 if (error) { 289 vfs_unlock(mp); 290 } else { 291 vrele(coveredvp); 292 TAILQ_REMOVE(&mountlist, mp, mnt_list); 293 mp->mnt_vnodecovered->v_mountedhere = (struct mount *)0; 294 vfs_unlock(mp); 295 mp->mnt_vfc->vfc_refcount--; 296 if (mp->mnt_vnodelist.lh_first != NULL) 297 panic("unmount: dangling vnode"); 298 free((caddr_t)mp, M_MOUNT); 299 } 300 return (error); 301 } 302 303 /* 304 * Sync each mounted filesystem. 305 */ 306 #ifdef DIAGNOSTIC 307 int syncprt = 0; 308 struct ctldebug debug0 = { "syncprt", &syncprt }; 309 #endif 310 311 struct sync_args { 312 int dummy; 313 }; 314 /* ARGSUSED */ 315 int 316 sync(p, uap, retval) 317 struct proc *p; 318 struct sync_args *uap; 319 int *retval; 320 { 321 register struct mount *mp, *nmp; 322 int asyncflag; 323 324 for (mp = mountlist.tqh_first; mp != NULL; mp = nmp) { 325 nmp = mp->mnt_list.tqe_next; 326 /* 327 * The lock check below is to avoid races with mount 328 * and unmount. 329 */ 330 if ((mp->mnt_flag & (MNT_MLOCK|MNT_RDONLY|MNT_MPBUSY)) == 0 && 331 !vfs_busy(mp)) { 332 asyncflag = mp->mnt_flag & MNT_ASYNC; 333 mp->mnt_flag &= ~MNT_ASYNC; 334 VFS_SYNC(mp, MNT_NOWAIT, p != NULL ? p->p_ucred : NOCRED, p); 335 if (asyncflag) 336 mp->mnt_flag |= MNT_ASYNC; 337 vfs_unbusy(mp); 338 } 339 } 340 return (0); 341 } 342 343 /* 344 * Change filesystem quotas. 345 */ 346 struct quotactl_args { 347 char *path; 348 int cmd; 349 int uid; 350 caddr_t arg; 351 }; 352 /* ARGSUSED */ 353 int 354 quotactl(p, uap, retval) 355 struct proc *p; 356 register struct quotactl_args *uap; 357 int *retval; 358 { 359 register struct mount *mp; 360 int error; 361 struct nameidata nd; 362 363 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); 364 error = namei(&nd); 365 if (error) 366 return (error); 367 mp = nd.ni_vp->v_mount; 368 vrele(nd.ni_vp); 369 return (VFS_QUOTACTL(mp, uap->cmd, uap->uid, uap->arg, p)); 370 } 371 372 /* 373 * Get filesystem statistics. 374 */ 375 struct statfs_args { 376 char *path; 377 struct statfs *buf; 378 }; 379 /* ARGSUSED */ 380 int 381 statfs(p, uap, retval) 382 struct proc *p; 383 register struct statfs_args *uap; 384 int *retval; 385 { 386 register struct mount *mp; 387 register struct statfs *sp; 388 int error; 389 struct nameidata nd; 390 391 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); 392 error = namei(&nd); 393 if (error) 394 return (error); 395 mp = nd.ni_vp->v_mount; 396 sp = &mp->mnt_stat; 397 vrele(nd.ni_vp); 398 error = VFS_STATFS(mp, sp, p); 399 if (error) 400 return (error); 401 sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 402 return (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp))); 403 } 404 405 /* 406 * Get filesystem statistics. 407 */ 408 struct fstatfs_args { 409 int fd; 410 struct statfs *buf; 411 }; 412 /* ARGSUSED */ 413 int 414 fstatfs(p, uap, retval) 415 struct proc *p; 416 register struct fstatfs_args *uap; 417 int *retval; 418 { 419 struct file *fp; 420 struct mount *mp; 421 register struct statfs *sp; 422 int error; 423 424 error = getvnode(p->p_fd, uap->fd, &fp); 425 if (error) 426 return (error); 427 mp = ((struct vnode *)fp->f_data)->v_mount; 428 sp = &mp->mnt_stat; 429 error = VFS_STATFS(mp, sp, p); 430 if (error) 431 return (error); 432 sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 433 return (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp))); 434 } 435 436 /* 437 * Get statistics on all filesystems. 438 */ 439 struct getfsstat_args { 440 struct statfs *buf; 441 long bufsize; 442 int flags; 443 }; 444 int 445 getfsstat(p, uap, retval) 446 struct proc *p; 447 register struct getfsstat_args *uap; 448 int *retval; 449 { 450 register struct mount *mp, *nmp; 451 register struct statfs *sp; 452 caddr_t sfsp; 453 long count, maxcount, error; 454 455 maxcount = uap->bufsize / sizeof(struct statfs); 456 sfsp = (caddr_t)uap->buf; 457 for (count = 0, mp = mountlist.tqh_first; mp != NULL; mp = nmp) { 458 nmp = mp->mnt_list.tqe_next; 459 if (sfsp && count < maxcount && 460 ((mp->mnt_flag & MNT_MLOCK) == 0)) { 461 sp = &mp->mnt_stat; 462 /* 463 * If MNT_NOWAIT is specified, do not refresh the 464 * fsstat cache. MNT_WAIT overrides MNT_NOWAIT. 465 */ 466 if (((uap->flags & MNT_NOWAIT) == 0 || 467 (uap->flags & MNT_WAIT)) && 468 (error = VFS_STATFS(mp, sp, p))) 469 continue; 470 sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 471 error = copyout((caddr_t)sp, sfsp, sizeof(*sp)); 472 if (error) 473 return (error); 474 sfsp += sizeof(*sp); 475 } 476 count++; 477 } 478 if (sfsp && count > maxcount) 479 *retval = maxcount; 480 else 481 *retval = count; 482 return (0); 483 } 484 485 /* 486 * Change current working directory to a given file descriptor. 487 */ 488 struct fchdir_args { 489 int fd; 490 }; 491 /* ARGSUSED */ 492 int 493 fchdir(p, uap, retval) 494 struct proc *p; 495 struct fchdir_args *uap; 496 int *retval; 497 { 498 register struct filedesc *fdp = p->p_fd; 499 register struct vnode *vp; 500 struct file *fp; 501 int error; 502 503 error = getvnode(fdp, uap->fd, &fp); 504 if (error) 505 return (error); 506 vp = (struct vnode *)fp->f_data; 507 VOP_LOCK(vp); 508 if (vp->v_type != VDIR) 509 error = ENOTDIR; 510 else 511 error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p); 512 VOP_UNLOCK(vp); 513 if (error) 514 return (error); 515 VREF(vp); 516 vrele(fdp->fd_cdir); 517 fdp->fd_cdir = vp; 518 return (0); 519 } 520 521 /* 522 * Change current working directory (``.''). 523 */ 524 struct chdir_args { 525 char *path; 526 }; 527 /* ARGSUSED */ 528 int 529 chdir(p, uap, retval) 530 struct proc *p; 531 struct chdir_args *uap; 532 int *retval; 533 { 534 register struct filedesc *fdp = p->p_fd; 535 int error; 536 struct nameidata nd; 537 538 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); 539 error = change_dir(&nd, p); 540 if (error) 541 return (error); 542 vrele(fdp->fd_cdir); 543 fdp->fd_cdir = nd.ni_vp; 544 return (0); 545 } 546 547 /* 548 * Change notion of root (``/'') directory. 549 */ 550 struct chroot_args { 551 char *path; 552 }; 553 /* ARGSUSED */ 554 int 555 chroot(p, uap, retval) 556 struct proc *p; 557 struct chroot_args *uap; 558 int *retval; 559 { 560 register struct filedesc *fdp = p->p_fd; 561 int error; 562 struct nameidata nd; 563 564 error = suser(p->p_ucred, &p->p_acflag); 565 if (error) 566 return (error); 567 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); 568 error = change_dir(&nd, p); 569 if (error) 570 return (error); 571 if (fdp->fd_rdir != NULL) 572 vrele(fdp->fd_rdir); 573 fdp->fd_rdir = nd.ni_vp; 574 return (0); 575 } 576 577 /* 578 * Common routine for chroot and chdir. 579 */ 580 static int 581 change_dir(ndp, p) 582 register struct nameidata *ndp; 583 struct proc *p; 584 { 585 struct vnode *vp; 586 int error; 587 588 error = namei(ndp); 589 if (error) 590 return (error); 591 vp = ndp->ni_vp; 592 if (vp->v_type != VDIR) 593 error = ENOTDIR; 594 else 595 error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p); 596 VOP_UNLOCK(vp); 597 if (error) 598 vrele(vp); 599 return (error); 600 } 601 602 /* 603 * Check permissions, allocate an open file structure, 604 * and call the device open routine if any. 605 */ 606 struct open_args { 607 char *path; 608 int flags; 609 int mode; 610 }; 611 int 612 open(p, uap, retval) 613 struct proc *p; 614 register struct open_args *uap; 615 int *retval; 616 { 617 register struct filedesc *fdp = p->p_fd; 618 register struct file *fp; 619 register struct vnode *vp; 620 int flags, cmode; 621 struct file *nfp; 622 int type, indx, error; 623 struct flock lf; 624 struct nameidata nd; 625 extern struct fileops vnops; 626 627 error = falloc(p, &nfp, &indx); 628 if (error) 629 return (error); 630 fp = nfp; 631 flags = FFLAGS(uap->flags); 632 cmode = ((uap->mode &~ fdp->fd_cmask) & ALLPERMS) &~ S_ISTXT; 633 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); 634 p->p_dupfd = -indx - 1; /* XXX check for fdopen */ 635 error = vn_open(&nd, flags, cmode); 636 if (error) { 637 ffree(fp); 638 if ((error == ENODEV || error == ENXIO) && 639 p->p_dupfd >= 0 && /* XXX from fdopen */ 640 (error = 641 dupfdopen(fdp, indx, p->p_dupfd, flags, error)) == 0) { 642 *retval = indx; 643 return (0); 644 } 645 if (error == ERESTART) 646 error = EINTR; 647 fdp->fd_ofiles[indx] = NULL; 648 return (error); 649 } 650 p->p_dupfd = 0; 651 vp = nd.ni_vp; 652 fp->f_flag = flags & FMASK; 653 fp->f_type = DTYPE_VNODE; 654 fp->f_ops = &vnops; 655 fp->f_data = (caddr_t)vp; 656 if (flags & (O_EXLOCK | O_SHLOCK)) { 657 lf.l_whence = SEEK_SET; 658 lf.l_start = 0; 659 lf.l_len = 0; 660 if (flags & O_EXLOCK) 661 lf.l_type = F_WRLCK; 662 else 663 lf.l_type = F_RDLCK; 664 type = F_FLOCK; 665 if ((flags & FNONBLOCK) == 0) 666 type |= F_WAIT; 667 VOP_UNLOCK(vp); 668 error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, type); 669 if (error) { 670 (void) vn_close(vp, fp->f_flag, fp->f_cred, p); 671 ffree(fp); 672 fdp->fd_ofiles[indx] = NULL; 673 return (error); 674 } 675 VOP_LOCK(vp); 676 fp->f_flag |= FHASLOCK; 677 } 678 VOP_UNLOCK(vp); 679 *retval = indx; 680 return (0); 681 } 682 683 #ifdef COMPAT_43 684 /* 685 * Create a file. 686 */ 687 struct ocreat_args { 688 char *path; 689 int mode; 690 }; 691 int 692 ocreat(p, uap, retval) 693 struct proc *p; 694 register struct ocreat_args *uap; 695 int *retval; 696 { 697 struct open_args openuap; 698 699 openuap.path = uap->path; 700 openuap.mode = uap->mode; 701 openuap.flags = O_WRONLY | O_CREAT | O_TRUNC; 702 return (open(p, &openuap, retval)); 703 } 704 #endif /* COMPAT_43 */ 705 706 /* 707 * Create a special file. 708 */ 709 struct mknod_args { 710 char *path; 711 int mode; 712 int dev; 713 }; 714 /* ARGSUSED */ 715 int 716 mknod(p, uap, retval) 717 struct proc *p; 718 register struct mknod_args *uap; 719 int *retval; 720 { 721 register struct vnode *vp; 722 struct vattr vattr; 723 int error; 724 struct nameidata nd; 725 726 error = suser(p->p_ucred, &p->p_acflag); 727 if (error) 728 return (error); 729 NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->path, p); 730 error = namei(&nd); 731 if (error) 732 return (error); 733 vp = nd.ni_vp; 734 if (vp != NULL) 735 error = EEXIST; 736 else { 737 VATTR_NULL(&vattr); 738 vattr.va_mode = (uap->mode & ALLPERMS) &~ p->p_fd->fd_cmask; 739 vattr.va_rdev = uap->dev; 740 741 switch (uap->mode & S_IFMT) { 742 case S_IFMT: /* used by badsect to flag bad sectors */ 743 vattr.va_type = VBAD; 744 break; 745 case S_IFCHR: 746 vattr.va_type = VCHR; 747 break; 748 case S_IFBLK: 749 vattr.va_type = VBLK; 750 break; 751 default: 752 error = EINVAL; 753 break; 754 } 755 } 756 if (!error) { 757 LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 758 error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr); 759 } else { 760 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 761 if (nd.ni_dvp == vp) 762 vrele(nd.ni_dvp); 763 else 764 vput(nd.ni_dvp); 765 if (vp) 766 vrele(vp); 767 } 768 return (error); 769 } 770 771 /* 772 * Create named pipe. 773 */ 774 struct mkfifo_args { 775 char *path; 776 int mode; 777 }; 778 /* ARGSUSED */ 779 int 780 mkfifo(p, uap, retval) 781 struct proc *p; 782 register struct mkfifo_args *uap; 783 int *retval; 784 { 785 struct vattr vattr; 786 int error; 787 struct nameidata nd; 788 789 NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->path, p); 790 error = namei(&nd); 791 if (error) 792 return (error); 793 if (nd.ni_vp != NULL) { 794 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 795 if (nd.ni_dvp == nd.ni_vp) 796 vrele(nd.ni_dvp); 797 else 798 vput(nd.ni_dvp); 799 vrele(nd.ni_vp); 800 return (EEXIST); 801 } 802 VATTR_NULL(&vattr); 803 vattr.va_type = VFIFO; 804 vattr.va_mode = (uap->mode & ALLPERMS) &~ p->p_fd->fd_cmask; 805 LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 806 return (VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr)); 807 } 808 809 /* 810 * Make a hard file link. 811 */ 812 struct link_args { 813 char *path; 814 char *link; 815 }; 816 /* ARGSUSED */ 817 int 818 link(p, uap, retval) 819 struct proc *p; 820 register struct link_args *uap; 821 int *retval; 822 { 823 register struct vnode *vp; 824 struct nameidata nd; 825 int error; 826 827 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); 828 error = namei(&nd); 829 if (error) 830 return (error); 831 vp = nd.ni_vp; 832 if (vp->v_type != VDIR || 833 (error = suser(p->p_ucred, &p->p_acflag)) == 0) { 834 nd.ni_cnd.cn_nameiop = CREATE; 835 nd.ni_cnd.cn_flags = LOCKPARENT; 836 nd.ni_dirp = uap->link; 837 error = namei(&nd); 838 if (!error) { 839 if (nd.ni_vp != NULL) 840 error = EEXIST; 841 if (!error) { 842 LEASE_CHECK(nd.ni_dvp, 843 p, p->p_ucred, LEASE_WRITE); 844 LEASE_CHECK(vp, 845 p, p->p_ucred, LEASE_WRITE); 846 error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd); 847 } else { 848 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 849 if (nd.ni_dvp == nd.ni_vp) 850 vrele(nd.ni_dvp); 851 else 852 vput(nd.ni_dvp); 853 if (nd.ni_vp) 854 vrele(nd.ni_vp); 855 } 856 } 857 } 858 vrele(vp); 859 return (error); 860 } 861 862 /* 863 * Make a symbolic link. 864 */ 865 struct symlink_args { 866 char *path; 867 char *link; 868 }; 869 /* ARGSUSED */ 870 int 871 symlink(p, uap, retval) 872 struct proc *p; 873 register struct symlink_args *uap; 874 int *retval; 875 { 876 struct vattr vattr; 877 char *path; 878 int error; 879 struct nameidata nd; 880 881 MALLOC(path, char *, MAXPATHLEN, M_NAMEI, M_WAITOK); 882 error = copyinstr(uap->path, path, MAXPATHLEN, NULL); 883 if (error) 884 goto out; 885 NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->link, p); 886 error = namei(&nd); 887 if (error) 888 goto out; 889 if (nd.ni_vp) { 890 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 891 if (nd.ni_dvp == nd.ni_vp) 892 vrele(nd.ni_dvp); 893 else 894 vput(nd.ni_dvp); 895 vrele(nd.ni_vp); 896 error = EEXIST; 897 goto out; 898 } 899 VATTR_NULL(&vattr); 900 vattr.va_mode = ACCESSPERMS &~ p->p_fd->fd_cmask; 901 LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 902 error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr, path); 903 out: 904 FREE(path, M_NAMEI); 905 return (error); 906 } 907 908 /* 909 * Delete a name from the filesystem. 910 */ 911 struct unlink_args { 912 char *path; 913 }; 914 /* ARGSUSED */ 915 int 916 unlink(p, uap, retval) 917 struct proc *p; 918 struct unlink_args *uap; 919 int *retval; 920 { 921 register struct vnode *vp; 922 int error; 923 struct nameidata nd; 924 925 NDINIT(&nd, DELETE, LOCKPARENT, UIO_USERSPACE, uap->path, p); 926 error = namei(&nd); 927 if (error) 928 return (error); 929 vp = nd.ni_vp; 930 LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 931 VOP_LOCK(vp); 932 933 if (vp->v_type != VDIR || 934 (error = suser(p->p_ucred, &p->p_acflag)) == 0) { 935 /* 936 * The root of a mounted filesystem cannot be deleted. 937 */ 938 if (vp->v_flag & VROOT) 939 error = EBUSY; 940 else 941 (void)vnode_pager_uncache(vp); 942 } 943 944 if (!error) { 945 LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 946 error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); 947 } else { 948 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 949 if (nd.ni_dvp == vp) 950 vrele(nd.ni_dvp); 951 else 952 vput(nd.ni_dvp); 953 vput(vp); 954 } 955 return (error); 956 } 957 958 /* 959 * Reposition read/write file offset. 960 */ 961 struct lseek_args { 962 int fd; 963 int pad; 964 off_t offset; 965 int whence; 966 }; 967 int 968 lseek(p, uap, retval) 969 struct proc *p; 970 register struct lseek_args *uap; 971 int *retval; 972 { 973 struct ucred *cred = p->p_ucred; 974 register struct filedesc *fdp = p->p_fd; 975 register struct file *fp; 976 struct vattr vattr; 977 int error; 978 979 if ((u_int)uap->fd >= fdp->fd_nfiles || 980 (fp = fdp->fd_ofiles[uap->fd]) == NULL) 981 return (EBADF); 982 if (fp->f_type != DTYPE_VNODE) 983 return (ESPIPE); 984 switch (uap->whence) { 985 case L_INCR: 986 fp->f_offset += uap->offset; 987 break; 988 case L_XTND: 989 error=VOP_GETATTR((struct vnode *)fp->f_data, &vattr, cred, p); 990 if (error) 991 return (error); 992 fp->f_offset = uap->offset + vattr.va_size; 993 break; 994 case L_SET: 995 fp->f_offset = uap->offset; 996 break; 997 default: 998 return (EINVAL); 999 } 1000 *(off_t *)retval = fp->f_offset; 1001 return (0); 1002 } 1003 1004 #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 1005 /* 1006 * Reposition read/write file offset. 1007 */ 1008 struct olseek_args { 1009 int fd; 1010 long offset; 1011 int whence; 1012 }; 1013 int 1014 olseek(p, uap, retval) 1015 struct proc *p; 1016 register struct olseek_args *uap; 1017 int *retval; 1018 { 1019 struct lseek_args nuap; 1020 off_t qret; 1021 int error; 1022 1023 nuap.fd = uap->fd; 1024 nuap.offset = uap->offset; 1025 nuap.whence = uap->whence; 1026 error = lseek(p, &nuap, &qret); 1027 *(long *)retval = qret; 1028 return (error); 1029 } 1030 #endif /* COMPAT_43 */ 1031 1032 /* 1033 * Check access permissions. 1034 */ 1035 struct access_args { 1036 char *path; 1037 int flags; 1038 }; 1039 int 1040 access(p, uap, retval) 1041 struct proc *p; 1042 register struct access_args *uap; 1043 int *retval; 1044 { 1045 register struct ucred *cred = p->p_ucred; 1046 register struct vnode *vp; 1047 int error, flags, t_gid, t_uid; 1048 struct nameidata nd; 1049 1050 t_uid = cred->cr_uid; 1051 t_gid = cred->cr_groups[0]; 1052 cred->cr_uid = p->p_cred->p_ruid; 1053 cred->cr_groups[0] = p->p_cred->p_rgid; 1054 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); 1055 error = namei(&nd); 1056 if (error) 1057 goto out1; 1058 vp = nd.ni_vp; 1059 1060 /* Flags == 0 means only check for existence. */ 1061 if (uap->flags) { 1062 flags = 0; 1063 if (uap->flags & R_OK) 1064 flags |= VREAD; 1065 if (uap->flags & W_OK) 1066 flags |= VWRITE; 1067 if (uap->flags & X_OK) 1068 flags |= VEXEC; 1069 if ((flags & VWRITE) == 0 || (error = vn_writechk(vp)) == 0) 1070 error = VOP_ACCESS(vp, flags, cred, p); 1071 } 1072 vput(vp); 1073 out1: 1074 cred->cr_uid = t_uid; 1075 cred->cr_groups[0] = t_gid; 1076 return (error); 1077 } 1078 1079 #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 1080 /* 1081 * Get file status; this version follows links. 1082 */ 1083 struct ostat_args { 1084 char *path; 1085 struct ostat *ub; 1086 }; 1087 /* ARGSUSED */ 1088 int 1089 ostat(p, uap, retval) 1090 struct proc *p; 1091 register struct ostat_args *uap; 1092 int *retval; 1093 { 1094 struct stat sb; 1095 struct ostat osb; 1096 int error; 1097 struct nameidata nd; 1098 1099 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); 1100 error = namei(&nd); 1101 if (error) 1102 return (error); 1103 error = vn_stat(nd.ni_vp, &sb, p); 1104 vput(nd.ni_vp); 1105 if (error) 1106 return (error); 1107 cvtstat(&sb, &osb); 1108 error = copyout((caddr_t)&osb, (caddr_t)uap->ub, sizeof (osb)); 1109 return (error); 1110 } 1111 1112 /* 1113 * Get file status; this version does not follow links. 1114 */ 1115 struct olstat_args { 1116 char *path; 1117 struct ostat *ub; 1118 }; 1119 /* ARGSUSED */ 1120 int 1121 olstat(p, uap, retval) 1122 struct proc *p; 1123 register struct olstat_args *uap; 1124 int *retval; 1125 { 1126 struct vnode *vp, *dvp; 1127 struct stat sb, sb1; 1128 struct ostat osb; 1129 int error; 1130 struct nameidata nd; 1131 1132 NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | LOCKPARENT, UIO_USERSPACE, 1133 uap->path, p); 1134 error = namei(&nd); 1135 if (error) 1136 return (error); 1137 /* 1138 * For symbolic links, always return the attributes of its 1139 * containing directory, except for mode, size, and links. 1140 */ 1141 vp = nd.ni_vp; 1142 dvp = nd.ni_dvp; 1143 if (vp->v_type != VLNK) { 1144 if (dvp == vp) 1145 vrele(dvp); 1146 else 1147 vput(dvp); 1148 error = vn_stat(vp, &sb, p); 1149 vput(vp); 1150 if (error) 1151 return (error); 1152 } else { 1153 error = vn_stat(dvp, &sb, p); 1154 vput(dvp); 1155 if (error) { 1156 vput(vp); 1157 return (error); 1158 } 1159 error = vn_stat(vp, &sb1, p); 1160 vput(vp); 1161 if (error) 1162 return (error); 1163 sb.st_mode &= ~S_IFDIR; 1164 sb.st_mode |= S_IFLNK; 1165 sb.st_nlink = sb1.st_nlink; 1166 sb.st_size = sb1.st_size; 1167 sb.st_blocks = sb1.st_blocks; 1168 } 1169 cvtstat(&sb, &osb); 1170 error = copyout((caddr_t)&osb, (caddr_t)uap->ub, sizeof (osb)); 1171 return (error); 1172 } 1173 1174 /* 1175 * Convert from an old to a new stat structure. 1176 */ 1177 void 1178 cvtstat(st, ost) 1179 struct stat *st; 1180 struct ostat *ost; 1181 { 1182 1183 ost->st_dev = st->st_dev; 1184 ost->st_ino = st->st_ino; 1185 ost->st_mode = st->st_mode; 1186 ost->st_nlink = st->st_nlink; 1187 ost->st_uid = st->st_uid; 1188 ost->st_gid = st->st_gid; 1189 ost->st_rdev = st->st_rdev; 1190 if (st->st_size < (quad_t)1 << 32) 1191 ost->st_size = st->st_size; 1192 else 1193 ost->st_size = -2; 1194 ost->st_atime = st->st_atime; 1195 ost->st_mtime = st->st_mtime; 1196 ost->st_ctime = st->st_ctime; 1197 ost->st_blksize = st->st_blksize; 1198 ost->st_blocks = st->st_blocks; 1199 ost->st_flags = st->st_flags; 1200 ost->st_gen = st->st_gen; 1201 } 1202 #endif /* COMPAT_43 || COMPAT_SUNOS */ 1203 1204 /* 1205 * Get file status; this version follows links. 1206 */ 1207 struct stat_args { 1208 char *path; 1209 struct stat *ub; 1210 }; 1211 /* ARGSUSED */ 1212 int 1213 stat(p, uap, retval) 1214 struct proc *p; 1215 register struct stat_args *uap; 1216 int *retval; 1217 { 1218 struct stat sb; 1219 int error; 1220 struct nameidata nd; 1221 1222 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); 1223 error = namei(&nd); 1224 if (error) 1225 return (error); 1226 error = vn_stat(nd.ni_vp, &sb, p); 1227 vput(nd.ni_vp); 1228 if (error) 1229 return (error); 1230 error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb)); 1231 return (error); 1232 } 1233 1234 /* 1235 * Get file status; this version does not follow links. 1236 */ 1237 struct lstat_args { 1238 char *path; 1239 struct stat *ub; 1240 }; 1241 /* ARGSUSED */ 1242 int 1243 lstat(p, uap, retval) 1244 struct proc *p; 1245 register struct lstat_args *uap; 1246 int *retval; 1247 { 1248 int error; 1249 struct vnode *vp, *dvp; 1250 struct stat sb, sb1; 1251 struct nameidata nd; 1252 1253 NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | LOCKPARENT, UIO_USERSPACE, 1254 uap->path, p); 1255 error = namei(&nd); 1256 if (error) 1257 return (error); 1258 /* 1259 * For symbolic links, always return the attributes of its 1260 * containing directory, except for mode, size, and links. 1261 */ 1262 vp = nd.ni_vp; 1263 dvp = nd.ni_dvp; 1264 if (vp->v_type != VLNK) { 1265 if (dvp == vp) 1266 vrele(dvp); 1267 else 1268 vput(dvp); 1269 error = vn_stat(vp, &sb, p); 1270 vput(vp); 1271 if (error) 1272 return (error); 1273 } else { 1274 error = vn_stat(dvp, &sb, p); 1275 vput(dvp); 1276 if (error) { 1277 vput(vp); 1278 return (error); 1279 } 1280 error = vn_stat(vp, &sb1, p); 1281 vput(vp); 1282 if (error) 1283 return (error); 1284 sb.st_mode &= ~S_IFDIR; 1285 sb.st_mode |= S_IFLNK; 1286 sb.st_nlink = sb1.st_nlink; 1287 sb.st_size = sb1.st_size; 1288 sb.st_blocks = sb1.st_blocks; 1289 } 1290 error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb)); 1291 return (error); 1292 } 1293 1294 /* 1295 * Get configurable pathname variables. 1296 */ 1297 struct pathconf_args { 1298 char *path; 1299 int name; 1300 }; 1301 /* ARGSUSED */ 1302 int 1303 pathconf(p, uap, retval) 1304 struct proc *p; 1305 register struct pathconf_args *uap; 1306 int *retval; 1307 { 1308 int error; 1309 struct nameidata nd; 1310 1311 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); 1312 error = namei(&nd); 1313 if (error) 1314 return (error); 1315 error = VOP_PATHCONF(nd.ni_vp, uap->name, retval); 1316 vput(nd.ni_vp); 1317 return (error); 1318 } 1319 1320 /* 1321 * Return target name of a symbolic link. 1322 */ 1323 struct readlink_args { 1324 char *path; 1325 char *buf; 1326 int count; 1327 }; 1328 /* ARGSUSED */ 1329 int 1330 readlink(p, uap, retval) 1331 struct proc *p; 1332 register struct readlink_args *uap; 1333 int *retval; 1334 { 1335 register struct vnode *vp; 1336 struct iovec aiov; 1337 struct uio auio; 1338 int error; 1339 struct nameidata nd; 1340 1341 NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); 1342 error = namei(&nd); 1343 if (error) 1344 return (error); 1345 vp = nd.ni_vp; 1346 if (vp->v_type != VLNK) 1347 error = EINVAL; 1348 else { 1349 aiov.iov_base = uap->buf; 1350 aiov.iov_len = uap->count; 1351 auio.uio_iov = &aiov; 1352 auio.uio_iovcnt = 1; 1353 auio.uio_offset = 0; 1354 auio.uio_rw = UIO_READ; 1355 auio.uio_segflg = UIO_USERSPACE; 1356 auio.uio_procp = p; 1357 auio.uio_resid = uap->count; 1358 error = VOP_READLINK(vp, &auio, p->p_ucred); 1359 } 1360 vput(vp); 1361 *retval = uap->count - auio.uio_resid; 1362 return (error); 1363 } 1364 1365 /* 1366 * Change flags of a file given a path name. 1367 */ 1368 struct chflags_args { 1369 char *path; 1370 int flags; 1371 }; 1372 /* ARGSUSED */ 1373 int 1374 chflags(p, uap, retval) 1375 struct proc *p; 1376 register struct chflags_args *uap; 1377 int *retval; 1378 { 1379 register struct vnode *vp; 1380 struct vattr vattr; 1381 int error; 1382 struct nameidata nd; 1383 1384 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); 1385 error = namei(&nd); 1386 if (error) 1387 return (error); 1388 vp = nd.ni_vp; 1389 LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 1390 VOP_LOCK(vp); 1391 if (vp->v_mount->mnt_flag & MNT_RDONLY) 1392 error = EROFS; 1393 else { 1394 VATTR_NULL(&vattr); 1395 vattr.va_flags = uap->flags; 1396 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 1397 } 1398 vput(vp); 1399 return (error); 1400 } 1401 1402 /* 1403 * Change flags of a file given a file descriptor. 1404 */ 1405 struct fchflags_args { 1406 int fd; 1407 int flags; 1408 }; 1409 /* ARGSUSED */ 1410 int 1411 fchflags(p, uap, retval) 1412 struct proc *p; 1413 register struct fchflags_args *uap; 1414 int *retval; 1415 { 1416 struct vattr vattr; 1417 struct vnode *vp; 1418 struct file *fp; 1419 int error; 1420 1421 error = getvnode(p->p_fd, uap->fd, &fp); 1422 if (error) 1423 return (error); 1424 vp = (struct vnode *)fp->f_data; 1425 LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 1426 VOP_LOCK(vp); 1427 if (vp->v_mount->mnt_flag & MNT_RDONLY) 1428 error = EROFS; 1429 else { 1430 VATTR_NULL(&vattr); 1431 vattr.va_flags = uap->flags; 1432 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 1433 } 1434 VOP_UNLOCK(vp); 1435 return (error); 1436 } 1437 1438 /* 1439 * Change mode of a file given path name. 1440 */ 1441 struct chmod_args { 1442 char *path; 1443 int mode; 1444 }; 1445 /* ARGSUSED */ 1446 int 1447 chmod(p, uap, retval) 1448 struct proc *p; 1449 register struct chmod_args *uap; 1450 int *retval; 1451 { 1452 register struct vnode *vp; 1453 struct vattr vattr; 1454 int error; 1455 struct nameidata nd; 1456 1457 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); 1458 error = namei(&nd); 1459 if (error) 1460 return (error); 1461 vp = nd.ni_vp; 1462 LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 1463 VOP_LOCK(vp); 1464 if (vp->v_mount->mnt_flag & MNT_RDONLY) 1465 error = EROFS; 1466 else { 1467 VATTR_NULL(&vattr); 1468 vattr.va_mode = uap->mode & ALLPERMS; 1469 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 1470 } 1471 vput(vp); 1472 return (error); 1473 } 1474 1475 /* 1476 * Change mode of a file given a file descriptor. 1477 */ 1478 struct fchmod_args { 1479 int fd; 1480 int mode; 1481 }; 1482 /* ARGSUSED */ 1483 int 1484 fchmod(p, uap, retval) 1485 struct proc *p; 1486 register struct fchmod_args *uap; 1487 int *retval; 1488 { 1489 struct vattr vattr; 1490 struct vnode *vp; 1491 struct file *fp; 1492 int error; 1493 1494 error = getvnode(p->p_fd, uap->fd, &fp); 1495 if (error) 1496 return (error); 1497 vp = (struct vnode *)fp->f_data; 1498 LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 1499 VOP_LOCK(vp); 1500 if (vp->v_mount->mnt_flag & MNT_RDONLY) 1501 error = EROFS; 1502 else { 1503 VATTR_NULL(&vattr); 1504 vattr.va_mode = uap->mode & ALLPERMS; 1505 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 1506 } 1507 VOP_UNLOCK(vp); 1508 return (error); 1509 } 1510 1511 /* 1512 * Set ownership given a path name. 1513 */ 1514 struct chown_args { 1515 char *path; 1516 int uid; 1517 int gid; 1518 }; 1519 /* ARGSUSED */ 1520 int 1521 chown(p, uap, retval) 1522 struct proc *p; 1523 register struct chown_args *uap; 1524 int *retval; 1525 { 1526 register struct vnode *vp; 1527 struct vattr vattr; 1528 int error; 1529 struct nameidata nd; 1530 1531 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); 1532 error = namei(&nd); 1533 if (error) 1534 return (error); 1535 vp = nd.ni_vp; 1536 LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 1537 VOP_LOCK(vp); 1538 if (vp->v_mount->mnt_flag & MNT_RDONLY) 1539 error = EROFS; 1540 else { 1541 VATTR_NULL(&vattr); 1542 vattr.va_uid = uap->uid; 1543 vattr.va_gid = uap->gid; 1544 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 1545 } 1546 vput(vp); 1547 return (error); 1548 } 1549 1550 /* 1551 * Set ownership given a file descriptor. 1552 */ 1553 struct fchown_args { 1554 int fd; 1555 int uid; 1556 int gid; 1557 }; 1558 /* ARGSUSED */ 1559 int 1560 fchown(p, uap, retval) 1561 struct proc *p; 1562 register struct fchown_args *uap; 1563 int *retval; 1564 { 1565 struct vattr vattr; 1566 struct vnode *vp; 1567 struct file *fp; 1568 int error; 1569 1570 error = getvnode(p->p_fd, uap->fd, &fp); 1571 if (error) 1572 return (error); 1573 vp = (struct vnode *)fp->f_data; 1574 LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 1575 VOP_LOCK(vp); 1576 if (vp->v_mount->mnt_flag & MNT_RDONLY) 1577 error = EROFS; 1578 else { 1579 VATTR_NULL(&vattr); 1580 vattr.va_uid = uap->uid; 1581 vattr.va_gid = uap->gid; 1582 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 1583 } 1584 VOP_UNLOCK(vp); 1585 return (error); 1586 } 1587 1588 /* 1589 * Set the access and modification times of a file. 1590 */ 1591 struct utimes_args { 1592 char *path; 1593 struct timeval *tptr; 1594 }; 1595 /* ARGSUSED */ 1596 int 1597 utimes(p, uap, retval) 1598 struct proc *p; 1599 register struct utimes_args *uap; 1600 int *retval; 1601 { 1602 register struct vnode *vp; 1603 struct timeval tv[2]; 1604 struct vattr vattr; 1605 int error; 1606 struct nameidata nd; 1607 1608 VATTR_NULL(&vattr); 1609 if (uap->tptr == NULL) { 1610 microtime(&tv[0]); 1611 tv[1] = tv[0]; 1612 vattr.va_vaflags |= VA_UTIMES_NULL; 1613 } else { 1614 error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv)); 1615 if (error) 1616 return (error); 1617 } 1618 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); 1619 error = namei(&nd); 1620 if (error) 1621 return (error); 1622 vp = nd.ni_vp; 1623 LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 1624 VOP_LOCK(vp); 1625 if (vp->v_mount->mnt_flag & MNT_RDONLY) 1626 error = EROFS; 1627 else { 1628 vattr.va_atime.ts_sec = tv[0].tv_sec; 1629 vattr.va_atime.ts_nsec = tv[0].tv_usec * 1000; 1630 vattr.va_mtime.ts_sec = tv[1].tv_sec; 1631 vattr.va_mtime.ts_nsec = tv[1].tv_usec * 1000; 1632 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 1633 } 1634 vput(vp); 1635 return (error); 1636 } 1637 1638 /* 1639 * Truncate a file given its path name. 1640 */ 1641 struct truncate_args { 1642 char *path; 1643 int pad; 1644 off_t length; 1645 }; 1646 /* ARGSUSED */ 1647 int 1648 truncate(p, uap, retval) 1649 struct proc *p; 1650 register struct truncate_args *uap; 1651 int *retval; 1652 { 1653 register struct vnode *vp; 1654 struct vattr vattr; 1655 int error; 1656 struct nameidata nd; 1657 1658 if (uap->length < 0) 1659 return(EINVAL); 1660 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); 1661 error = namei(&nd); 1662 if (error) 1663 return (error); 1664 vp = nd.ni_vp; 1665 LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 1666 VOP_LOCK(vp); 1667 if (vp->v_type == VDIR) 1668 error = EISDIR; 1669 else if ((error = vn_writechk(vp)) == 0 && 1670 (error = VOP_ACCESS(vp, VWRITE, p->p_ucred, p)) == 0) { 1671 VATTR_NULL(&vattr); 1672 vattr.va_size = uap->length; 1673 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 1674 } 1675 vput(vp); 1676 return (error); 1677 } 1678 1679 /* 1680 * Truncate a file given a file descriptor. 1681 */ 1682 struct ftruncate_args { 1683 int fd; 1684 int pad; 1685 off_t length; 1686 }; 1687 /* ARGSUSED */ 1688 int 1689 ftruncate(p, uap, retval) 1690 struct proc *p; 1691 register struct ftruncate_args *uap; 1692 int *retval; 1693 { 1694 struct vattr vattr; 1695 struct vnode *vp; 1696 struct file *fp; 1697 int error; 1698 1699 if (uap->length < 0) 1700 return(EINVAL); 1701 error = getvnode(p->p_fd, uap->fd, &fp); 1702 if (error) 1703 return (error); 1704 if ((fp->f_flag & FWRITE) == 0) 1705 return (EINVAL); 1706 vp = (struct vnode *)fp->f_data; 1707 LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 1708 VOP_LOCK(vp); 1709 if (vp->v_type == VDIR) 1710 error = EISDIR; 1711 else if ((error = vn_writechk(vp)) == 0) { 1712 VATTR_NULL(&vattr); 1713 vattr.va_size = uap->length; 1714 error = VOP_SETATTR(vp, &vattr, fp->f_cred, p); 1715 } 1716 VOP_UNLOCK(vp); 1717 return (error); 1718 } 1719 1720 #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 1721 /* 1722 * Truncate a file given its path name. 1723 */ 1724 struct otruncate_args { 1725 char *path; 1726 long length; 1727 }; 1728 /* ARGSUSED */ 1729 int 1730 otruncate(p, uap, retval) 1731 struct proc *p; 1732 register struct otruncate_args *uap; 1733 int *retval; 1734 { 1735 struct truncate_args nuap; 1736 1737 nuap.path = uap->path; 1738 nuap.length = uap->length; 1739 return (truncate(p, &nuap, retval)); 1740 } 1741 1742 /* 1743 * Truncate a file given a file descriptor. 1744 */ 1745 struct oftruncate_args { 1746 int fd; 1747 long length; 1748 }; 1749 /* ARGSUSED */ 1750 int 1751 oftruncate(p, uap, retval) 1752 struct proc *p; 1753 register struct oftruncate_args *uap; 1754 int *retval; 1755 { 1756 struct ftruncate_args nuap; 1757 1758 nuap.fd = uap->fd; 1759 nuap.length = uap->length; 1760 return (ftruncate(p, &nuap, retval)); 1761 } 1762 #endif /* COMPAT_43 || COMPAT_SUNOS */ 1763 1764 /* 1765 * Sync an open file. 1766 */ 1767 struct fsync_args { 1768 int fd; 1769 }; 1770 /* ARGSUSED */ 1771 int 1772 fsync(p, uap, retval) 1773 struct proc *p; 1774 struct fsync_args *uap; 1775 int *retval; 1776 { 1777 register struct vnode *vp; 1778 struct file *fp; 1779 int error; 1780 1781 error = getvnode(p->p_fd, uap->fd, &fp); 1782 if (error) 1783 return (error); 1784 vp = (struct vnode *)fp->f_data; 1785 VOP_LOCK(vp); 1786 error = VOP_FSYNC(vp, fp->f_cred, MNT_WAIT, p); 1787 VOP_UNLOCK(vp); 1788 return (error); 1789 } 1790 1791 /* 1792 * Rename files. Source and destination must either both be directories, 1793 * or both not be directories. If target is a directory, it must be empty. 1794 */ 1795 struct rename_args { 1796 char *from; 1797 char *to; 1798 }; 1799 /* ARGSUSED */ 1800 int 1801 rename(p, uap, retval) 1802 struct proc *p; 1803 register struct rename_args *uap; 1804 int *retval; 1805 { 1806 register struct vnode *tvp, *fvp, *tdvp; 1807 struct nameidata fromnd, tond; 1808 int error; 1809 1810 NDINIT(&fromnd, DELETE, WANTPARENT | SAVESTART, UIO_USERSPACE, 1811 uap->from, p); 1812 error = namei(&fromnd); 1813 if (error) 1814 return (error); 1815 fvp = fromnd.ni_vp; 1816 NDINIT(&tond, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART, 1817 UIO_USERSPACE, uap->to, p); 1818 error = namei(&tond); 1819 if (error) { 1820 VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 1821 vrele(fromnd.ni_dvp); 1822 vrele(fvp); 1823 goto out1; 1824 } 1825 tdvp = tond.ni_dvp; 1826 tvp = tond.ni_vp; 1827 if (tvp != NULL) { 1828 if (fvp->v_type == VDIR && tvp->v_type != VDIR) { 1829 error = ENOTDIR; 1830 goto out; 1831 } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) { 1832 error = EISDIR; 1833 goto out; 1834 } 1835 } 1836 if (fvp == tdvp) 1837 error = EINVAL; 1838 /* 1839 * If source is the same as the destination (that is the 1840 * same inode number with the same name in the same directory), 1841 * then there is nothing to do. 1842 */ 1843 if (fvp == tvp && fromnd.ni_dvp == tdvp && 1844 fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen && 1845 !bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr, 1846 fromnd.ni_cnd.cn_namelen)) 1847 error = -1; 1848 out: 1849 if (!error) { 1850 LEASE_CHECK(tdvp, p, p->p_ucred, LEASE_WRITE); 1851 if (fromnd.ni_dvp != tdvp) 1852 LEASE_CHECK(fromnd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 1853 if (tvp) 1854 LEASE_CHECK(tvp, p, p->p_ucred, LEASE_WRITE); 1855 error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd, 1856 tond.ni_dvp, tond.ni_vp, &tond.ni_cnd); 1857 } else { 1858 VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd); 1859 if (tdvp == tvp) 1860 vrele(tdvp); 1861 else 1862 vput(tdvp); 1863 if (tvp) 1864 vput(tvp); 1865 VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 1866 vrele(fromnd.ni_dvp); 1867 vrele(fvp); 1868 } 1869 vrele(tond.ni_startdir); 1870 FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI); 1871 out1: 1872 if (fromnd.ni_startdir) 1873 vrele(fromnd.ni_startdir); 1874 FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI); 1875 if (error == -1) 1876 return (0); 1877 return (error); 1878 } 1879 1880 /* 1881 * Make a directory file. 1882 */ 1883 struct mkdir_args { 1884 char *path; 1885 int mode; 1886 }; 1887 /* ARGSUSED */ 1888 int 1889 mkdir(p, uap, retval) 1890 struct proc *p; 1891 register struct mkdir_args *uap; 1892 int *retval; 1893 { 1894 register struct vnode *vp; 1895 struct vattr vattr; 1896 int error; 1897 struct nameidata nd; 1898 1899 NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->path, p); 1900 error = namei(&nd); 1901 if (error) 1902 return (error); 1903 vp = nd.ni_vp; 1904 if (vp != NULL) { 1905 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1906 if (nd.ni_dvp == vp) 1907 vrele(nd.ni_dvp); 1908 else 1909 vput(nd.ni_dvp); 1910 vrele(vp); 1911 return (EEXIST); 1912 } 1913 VATTR_NULL(&vattr); 1914 vattr.va_type = VDIR; 1915 vattr.va_mode = (uap->mode & ACCESSPERMS) &~ p->p_fd->fd_cmask; 1916 LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 1917 error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr); 1918 if (!error) 1919 vput(nd.ni_vp); 1920 return (error); 1921 } 1922 1923 /* 1924 * Remove a directory file. 1925 */ 1926 struct rmdir_args { 1927 char *path; 1928 }; 1929 /* ARGSUSED */ 1930 int 1931 rmdir(p, uap, retval) 1932 struct proc *p; 1933 struct rmdir_args *uap; 1934 int *retval; 1935 { 1936 register struct vnode *vp; 1937 int error; 1938 struct nameidata nd; 1939 1940 NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE, uap->path, p); 1941 error = namei(&nd); 1942 if (error) 1943 return (error); 1944 vp = nd.ni_vp; 1945 if (vp->v_type != VDIR) { 1946 error = ENOTDIR; 1947 goto out; 1948 } 1949 /* 1950 * No rmdir "." please. 1951 */ 1952 if (nd.ni_dvp == vp) { 1953 error = EINVAL; 1954 goto out; 1955 } 1956 /* 1957 * The root of a mounted filesystem cannot be deleted. 1958 */ 1959 if (vp->v_flag & VROOT) 1960 error = EBUSY; 1961 out: 1962 if (!error) { 1963 LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 1964 LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 1965 error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); 1966 } else { 1967 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1968 if (nd.ni_dvp == vp) 1969 vrele(nd.ni_dvp); 1970 else 1971 vput(nd.ni_dvp); 1972 vput(vp); 1973 } 1974 return (error); 1975 } 1976 1977 #ifdef COMPAT_43 1978 /* 1979 * Read a block of directory entries in a file system independent format. 1980 */ 1981 struct ogetdirentries_args { 1982 int fd; 1983 char *buf; 1984 u_int count; 1985 long *basep; 1986 }; 1987 int 1988 ogetdirentries(p, uap, retval) 1989 struct proc *p; 1990 register struct ogetdirentries_args *uap; 1991 int *retval; 1992 { 1993 register struct vnode *vp; 1994 struct file *fp; 1995 struct uio auio, kuio; 1996 struct iovec aiov, kiov; 1997 struct dirent *dp, *edp; 1998 caddr_t dirbuf; 1999 int error, readcnt; 2000 long loff; 2001 2002 error = getvnode(p->p_fd, uap->fd, &fp); 2003 if (error) 2004 return (error); 2005 if ((fp->f_flag & FREAD) == 0) 2006 return (EBADF); 2007 vp = (struct vnode *)fp->f_data; 2008 if (vp->v_type != VDIR) 2009 return (EINVAL); 2010 aiov.iov_base = uap->buf; 2011 aiov.iov_len = uap->count; 2012 auio.uio_iov = &aiov; 2013 auio.uio_iovcnt = 1; 2014 auio.uio_rw = UIO_READ; 2015 auio.uio_segflg = UIO_USERSPACE; 2016 auio.uio_procp = p; 2017 auio.uio_resid = uap->count; 2018 VOP_LOCK(vp); 2019 loff = auio.uio_offset = fp->f_offset; 2020 # if (BYTE_ORDER != LITTLE_ENDIAN) 2021 if (vp->v_mount->mnt_maxsymlinklen <= 0) { 2022 error = VOP_READDIR(vp, &auio, fp->f_cred, NULL, NULL, NULL); 2023 fp->f_offset = auio.uio_offset; 2024 } else 2025 # endif 2026 { 2027 kuio = auio; 2028 kuio.uio_iov = &kiov; 2029 kuio.uio_segflg = UIO_SYSSPACE; 2030 kiov.iov_len = uap->count; 2031 MALLOC(dirbuf, caddr_t, uap->count, M_TEMP, M_WAITOK); 2032 kiov.iov_base = dirbuf; 2033 error = VOP_READDIR(vp, &kuio, fp->f_cred, NULL, NULL, NULL); 2034 fp->f_offset = kuio.uio_offset; 2035 if (error == 0) { 2036 readcnt = uap->count - kuio.uio_resid; 2037 edp = (struct dirent *)&dirbuf[readcnt]; 2038 for (dp = (struct dirent *)dirbuf; dp < edp; ) { 2039 # if (BYTE_ORDER == LITTLE_ENDIAN) 2040 /* 2041 * The expected low byte of 2042 * dp->d_namlen is our dp->d_type. 2043 * The high MBZ byte of dp->d_namlen 2044 * is our dp->d_namlen. 2045 */ 2046 dp->d_type = dp->d_namlen; 2047 dp->d_namlen = 0; 2048 # else 2049 /* 2050 * The dp->d_type is the high byte 2051 * of the expected dp->d_namlen, 2052 * so must be zero'ed. 2053 */ 2054 dp->d_type = 0; 2055 # endif 2056 if (dp->d_reclen > 0) { 2057 dp = (struct dirent *) 2058 ((char *)dp + dp->d_reclen); 2059 } else { 2060 error = EIO; 2061 break; 2062 } 2063 } 2064 if (dp >= edp) 2065 error = uiomove(dirbuf, readcnt, &auio); 2066 } 2067 FREE(dirbuf, M_TEMP); 2068 } 2069 VOP_UNLOCK(vp); 2070 if (error) 2071 return (error); 2072 error = copyout((caddr_t)&loff, (caddr_t)uap->basep, sizeof(long)); 2073 *retval = uap->count - auio.uio_resid; 2074 return (error); 2075 } 2076 #endif 2077 2078 /* 2079 * Read a block of directory entries in a file system independent format. 2080 */ 2081 struct getdirentries_args { 2082 int fd; 2083 char *buf; 2084 u_int count; 2085 long *basep; 2086 }; 2087 int 2088 getdirentries(p, uap, retval) 2089 struct proc *p; 2090 register struct getdirentries_args *uap; 2091 int *retval; 2092 { 2093 register struct vnode *vp; 2094 struct file *fp; 2095 struct uio auio; 2096 struct iovec aiov; 2097 long loff; 2098 int error; 2099 2100 error = getvnode(p->p_fd, uap->fd, &fp); 2101 if (error) 2102 return (error); 2103 if ((fp->f_flag & FREAD) == 0) 2104 return (EBADF); 2105 vp = (struct vnode *)fp->f_data; 2106 unionread: 2107 if (vp->v_type != VDIR) 2108 return (EINVAL); 2109 aiov.iov_base = uap->buf; 2110 aiov.iov_len = uap->count; 2111 auio.uio_iov = &aiov; 2112 auio.uio_iovcnt = 1; 2113 auio.uio_rw = UIO_READ; 2114 auio.uio_segflg = UIO_USERSPACE; 2115 auio.uio_procp = p; 2116 auio.uio_resid = uap->count; 2117 VOP_LOCK(vp); 2118 loff = auio.uio_offset = fp->f_offset; 2119 error = VOP_READDIR(vp, &auio, fp->f_cred, NULL, NULL, NULL); 2120 fp->f_offset = auio.uio_offset; 2121 VOP_UNLOCK(vp); 2122 if (error) 2123 return (error); 2124 2125 #ifdef UNION 2126 { 2127 extern int (**union_vnodeop_p)(); 2128 extern struct vnode *union_lowervp __P((struct vnode *)); 2129 2130 if ((uap->count == auio.uio_resid) && 2131 (vp->v_op == union_vnodeop_p)) { 2132 struct vnode *tvp = vp; 2133 2134 vp = union_lowervp(vp); 2135 if (vp != NULLVP) { 2136 VOP_LOCK(vp); 2137 error = VOP_OPEN(vp, FREAD); 2138 VOP_UNLOCK(vp); 2139 2140 if (error) { 2141 vrele(vp); 2142 return (error); 2143 } 2144 fp->f_data = (caddr_t) vp; 2145 fp->f_offset = 0; 2146 error = vn_close(tvp, FREAD, fp->f_cred, p); 2147 if (error) 2148 return (error); 2149 goto unionread; 2150 } 2151 } 2152 } 2153 #endif 2154 2155 if ((uap->count == auio.uio_resid) && 2156 vp && 2157 (vp->v_flag & VROOT) && 2158 (vp->v_mount->mnt_flag & MNT_UNION)) { 2159 struct vnode *tvp = vp; 2160 vp = vp->v_mount->mnt_vnodecovered; 2161 VREF(vp); 2162 fp->f_data = (caddr_t) vp; 2163 fp->f_offset = 0; 2164 vrele(tvp); 2165 goto unionread; 2166 } 2167 error = copyout((caddr_t)&loff, (caddr_t)uap->basep, sizeof(long)); 2168 *retval = uap->count - auio.uio_resid; 2169 return (error); 2170 } 2171 2172 /* 2173 * Set the mode mask for creation of filesystem nodes. 2174 */ 2175 struct umask_args { 2176 int newmask; 2177 }; 2178 mode_t /* XXX */ 2179 umask(p, uap, retval) 2180 struct proc *p; 2181 struct umask_args *uap; 2182 int *retval; 2183 { 2184 register struct filedesc *fdp; 2185 2186 fdp = p->p_fd; 2187 *retval = fdp->fd_cmask; 2188 fdp->fd_cmask = uap->newmask & ALLPERMS; 2189 return (0); 2190 } 2191 2192 /* 2193 * Void all references to file by ripping underlying filesystem 2194 * away from vnode. 2195 */ 2196 struct revoke_args { 2197 char *path; 2198 }; 2199 /* ARGSUSED */ 2200 int 2201 revoke(p, uap, retval) 2202 struct proc *p; 2203 register struct revoke_args *uap; 2204 int *retval; 2205 { 2206 register struct vnode *vp; 2207 struct vattr vattr; 2208 int error; 2209 struct nameidata nd; 2210 2211 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); 2212 error = namei(&nd); 2213 if (error) 2214 return (error); 2215 vp = nd.ni_vp; 2216 if (vp->v_type != VCHR && vp->v_type != VBLK) { 2217 error = EINVAL; 2218 goto out; 2219 } 2220 error = VOP_GETATTR(vp, &vattr, p->p_ucred, p); 2221 if (error) 2222 goto out; 2223 if (p->p_ucred->cr_uid != vattr.va_uid && 2224 (error = suser(p->p_ucred, &p->p_acflag))) 2225 goto out; 2226 if( vp->v_vmdata) 2227 vnode_pager_uncache( vp); 2228 if (vp->v_usecount > 1 || (vp->v_flag & VALIASED)) 2229 vgoneall(vp); 2230 out: 2231 vrele(vp); 2232 return (error); 2233 } 2234 2235 /* 2236 * Convert a user file descriptor to a kernel file entry. 2237 */ 2238 int 2239 getvnode(fdp, fd, fpp) 2240 struct filedesc *fdp; 2241 struct file **fpp; 2242 int fd; 2243 { 2244 struct file *fp; 2245 2246 if ((u_int)fd >= fdp->fd_nfiles || 2247 (fp = fdp->fd_ofiles[fd]) == NULL) 2248 return (EBADF); 2249 if (fp->f_type != DTYPE_VNODE) 2250 return (EINVAL); 2251 *fpp = fp; 2252 return (0); 2253 } 2254