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