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