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