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