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