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