vfs_syscalls.c revision 24438
1183724Ssos/* 2183724Ssos * Copyright (c) 1989, 1993 3183724Ssos * The Regents of the University of California. All rights reserved. 4183724Ssos * (c) UNIX System Laboratories, Inc. 5183724Ssos * All or some portions of this file are derived from material licensed 6183724Ssos * to the University of California by American Telephone and Telegraph 7183724Ssos * Co. or Unix System Laboratories, Inc. and are reproduced herein with 8183724Ssos * the permission of UNIX System Laboratories, Inc. 9183724Ssos * 10183724Ssos * Redistribution and use in source and binary forms, with or without 11183724Ssos * modification, are permitted provided that the following conditions 12183724Ssos * are met: 13183724Ssos * 1. Redistributions of source code must retain the above copyright 14183724Ssos * notice, this list of conditions and the following disclaimer. 15183724Ssos * 2. Redistributions in binary form must reproduce the above copyright 16183724Ssos * notice, this list of conditions and the following disclaimer in the 17183724Ssos * documentation and/or other materials provided with the distribution. 18183724Ssos * 3. All advertising materials mentioning features or use of this software 19183724Ssos * must display the following acknowledgement: 20183724Ssos * This product includes software developed by the University of 21183724Ssos * California, Berkeley and its contributors. 22183724Ssos * 4. Neither the name of the University nor the names of its contributors 23183724Ssos * may be used to endorse or promote products derived from this software 24183724Ssos * without specific prior written permission. 25183724Ssos * 26183724Ssos * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 27183724Ssos * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28183724Ssos * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29183724Ssos * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 30183724Ssos * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31183724Ssos * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32183724Ssos * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33183724Ssos * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34183724Ssos * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35183724Ssos * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36183724Ssos * SUCH DAMAGE. 37183724Ssos * 38183724Ssos * @(#)vfs_syscalls.c 8.13 (Berkeley) 4/15/94 39183724Ssos * $Id: vfs_syscalls.c,v 1.61 1997/03/23 20:08:11 guido Exp $ 40183724Ssos */ 41183724Ssos 42183724Ssos/* 43183724Ssos * XXX - The following is required because of some magic done 44183724Ssos * in getdirentries() below which is only done if the translucent 45183724Ssos * filesystem `UNION' is compiled into the kernel. This is broken, 46183724Ssos * but I don't have time to study the code deeply enough to understand 47183724Ssos * what's going on and determine an appropriate fix. -GAW 48183724Ssos */ 49183724Ssos#include "opt_union.h" 50183724Ssos 51183724Ssos#include <sys/param.h> 52183724Ssos#include <sys/systm.h> 53183724Ssos#include <sys/sysent.h> 54183724Ssos#include <sys/sysproto.h> 55188765Smav#include <sys/namei.h> 56183724Ssos#include <sys/filedesc.h> 57183724Ssos#include <sys/kernel.h> 58188765Smav#include <sys/fcntl.h> 59183724Ssos#include <sys/file.h> 60183724Ssos#include <sys/stat.h> 61183724Ssos#include <sys/unistd.h> 62188765Smav#include <sys/vnode.h> 63183724Ssos#include <sys/mount.h> 64183724Ssos#include <sys/proc.h> 65183724Ssos#include <sys/uio.h> 66183724Ssos#include <sys/malloc.h> 67183724Ssos#include <sys/dirent.h> 68183724Ssos 69183724Ssos#ifdef UNION 70183724Ssos#include <miscfs/union/union.h> 71183724Ssos#endif 72183724Ssos 73183724Ssos#include <vm/vm.h> 74183724Ssos#include <vm/vm_param.h> 75183724Ssos#include <vm/vm_object.h> 76183724Ssos#include <vm/vm_extern.h> 77183724Ssos#include <sys/sysctl.h> 78183724Ssos 79183724Ssosstatic int change_dir __P((struct nameidata *ndp, struct proc *p)); 80183724Ssosstatic void checkdirs __P((struct vnode *olddp)); 81183724Ssos 82183724Ssos/* 83183724Ssos * Virtual File System System Calls 84183724Ssos */ 85183724Ssos 86183724Ssos/* 87183724Ssos * Mount a file system. 88183724Ssos */ 89183724Ssos#ifndef _SYS_SYSPROTO_H_ 90183724Ssosstruct mount_args { 91183724Ssos char *type; 92183724Ssos char *path; 93183724Ssos int flags; 94183724Ssos caddr_t data; 95183724Ssos}; 96183724Ssos#endif 97183724Ssos/* ARGSUSED */ 98183724Ssosint 99183724Ssosmount(p, uap, retval) 100183724Ssos struct proc *p; 101183724Ssos register struct mount_args /* { 102183724Ssos syscallarg(char *) type; 103183724Ssos syscallarg(char *) path; 104183724Ssos syscallarg(int) flags; 105183724Ssos syscallarg(caddr_t) data; 106183724Ssos } */ *uap; 107183724Ssos register_t *retval; 108183724Ssos{ 109183724Ssos struct vnode *vp; 110183724Ssos struct mount *mp; 111183724Ssos struct vfsconf *vfsp; 112183724Ssos int error, flag = 0; 113183724Ssos struct vattr va; 114183724Ssos u_long fstypenum; 115183724Ssos struct nameidata nd; 116183724Ssos char fstypename[MFSNAMELEN]; 117183724Ssos 118183724Ssos /* 119183724Ssos * Get vnode to be covered 120183724Ssos */ 121183724Ssos NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, 122183724Ssos SCARG(uap, path), p); 123183724Ssos if (error = namei(&nd)) 124183724Ssos return (error); 125183724Ssos vp = nd.ni_vp; 126183724Ssos if (SCARG(uap, flags) & MNT_UPDATE) { 127183724Ssos if ((vp->v_flag & VROOT) == 0) { 128183724Ssos vput(vp); 129183724Ssos return (EINVAL); 130183724Ssos } 131183724Ssos mp = vp->v_mount; 132183724Ssos flag = mp->mnt_flag; 133183724Ssos /* 134183724Ssos * We only allow the filesystem to be reloaded if it 135183724Ssos * is currently mounted read-only. 136183724Ssos */ 137183724Ssos if ((SCARG(uap, flags) & MNT_RELOAD) && 138183724Ssos ((mp->mnt_flag & MNT_RDONLY) == 0)) { 139183724Ssos vput(vp); 140183724Ssos return (EOPNOTSUPP); /* Needs translation */ 141188765Smav } 142183724Ssos mp->mnt_flag |= 143183724Ssos SCARG(uap, flags) & (MNT_RELOAD | MNT_FORCE | MNT_UPDATE); 144183724Ssos /* 145183724Ssos * Only root, or the user that did the original mount is 146183724Ssos * permitted to update it. 147183724Ssos */ 148183724Ssos if (mp->mnt_stat.f_owner != p->p_ucred->cr_uid && 149183724Ssos (error = suser(p->p_ucred, &p->p_acflag))) { 150183724Ssos vput(vp); 151183724Ssos return (error); 152183724Ssos } 153183724Ssos /* 154183724Ssos * Do not allow NFS export by non-root users. Silently 155183724Ssos * enforce MNT_NOSUID and MNT_NODEV for non-root users. 156183724Ssos */ 157183724Ssos if (p->p_ucred->cr_uid != 0) { 158183724Ssos if (SCARG(uap, flags) & MNT_EXPORTED) { 159183724Ssos vput(vp); 160183724Ssos return (EPERM); 161183724Ssos } 162183724Ssos SCARG(uap, flags) |= MNT_NOSUID | MNT_NODEV; 163183724Ssos } 164183724Ssos if (vfs_busy(mp, LK_NOWAIT, 0, p)) { 165183724Ssos vput(vp); 166183724Ssos return (EBUSY); 167183724Ssos } 168183724Ssos VOP_UNLOCK(vp, 0, p); 169183724Ssos goto update; 170183724Ssos } 171183724Ssos /* 172183724Ssos * If the user is not root, ensure that they own the directory 173183724Ssos * onto which we are attempting to mount. 174183724Ssos */ 175183724Ssos if ((error = VOP_GETATTR(vp, &va, p->p_ucred, p)) || 176183724Ssos (va.va_uid != p->p_ucred->cr_uid && 177183724Ssos (error = suser(p->p_ucred, &p->p_acflag)))) { 178183724Ssos vput(vp); 179183724Ssos return (error); 180183724Ssos } 181183724Ssos /* 182183724Ssos * Do not allow NFS export by non-root users. Silently 183183724Ssos * enforce MNT_NOSUID and MNT_NODEV for non-root users. 184183724Ssos */ 185183724Ssos if (p->p_ucred->cr_uid != 0) { 186183724Ssos if (SCARG(uap, flags) & MNT_EXPORTED) { 187183724Ssos vput(vp); 188183724Ssos return (EPERM); 189188765Smav } 190183724Ssos SCARG(uap, flags) |= MNT_NOSUID | MNT_NODEV; 191183724Ssos } 192183724Ssos if (error = vinvalbuf(vp, V_SAVE, p->p_ucred, p, 0, 0)) 193183724Ssos return (error); 194183724Ssos if (vp->v_type != VDIR) { 195183724Ssos vput(vp); 196183724Ssos return (ENOTDIR); 197183724Ssos } 198183724Ssos#ifdef COMPAT_43 199183724Ssos /* 200183724Ssos * Historically filesystem types were identified by number. If we 201183724Ssos * get an integer for the filesystem type instead of a string, we 202183724Ssos * check to see if it matches one of the historic filesystem types. 203183724Ssos */ 204183724Ssos fstypenum = (u_long)SCARG(uap, type); 205183724Ssos if (fstypenum < maxvfsconf) { 206183724Ssos for (vfsp = vfsconf; vfsp; vfsp = vfsp->vfc_next) 207183724Ssos if (vfsp->vfc_typenum == fstypenum) 208188765Smav break; 209183724Ssos if (vfsp == NULL) { 210183724Ssos vput(vp); 211183724Ssos return (ENODEV); 212183724Ssos } 213183724Ssos strncpy(fstypename, vfsp->vfc_name, MFSNAMELEN); 214183724Ssos } else 215183724Ssos#endif /* COMPAT_43 */ 216188765Smav if (error = copyinstr(SCARG(uap, type), fstypename, MFSNAMELEN, NULL)) { 217183724Ssos vput(vp); 218183724Ssos return (error); 219183724Ssos } 220183724Ssos for (vfsp = vfsconf; vfsp; vfsp = vfsp->vfc_next) 221183724Ssos if (!strcmp(vfsp->vfc_name, fstypename)) 222188765Smav break; 223183724Ssos if (vfsp == NULL) { 224183724Ssos vput(vp); 225183724Ssos return (ENODEV); 226183724Ssos } 227183724Ssos if (vp->v_mountedhere != NULL) { 228183724Ssos vput(vp); 229183724Ssos return (EBUSY); 230183724Ssos } 231183724Ssos 232183724Ssos /* 233183724Ssos * Allocate and initialize the filesystem. 234183724Ssos */ 235183724Ssos mp = (struct mount *)malloc((u_long)sizeof(struct mount), 236183724Ssos M_MOUNT, M_WAITOK); 237183724Ssos bzero((char *)mp, (u_long)sizeof(struct mount)); 238183724Ssos lockinit(&mp->mnt_lock, PVFS, "vfslock", 0, 0); 239183724Ssos (void)vfs_busy(mp, LK_NOWAIT, 0, p); 240183724Ssos mp->mnt_op = vfsp->vfc_vfsops; 241183724Ssos mp->mnt_vfc = vfsp; 242183724Ssos vfsp->vfc_refcount++; 243183724Ssos mp->mnt_stat.f_type = vfsp->vfc_typenum; 244183724Ssos mp->mnt_flag |= vfsp->vfc_flags & MNT_VISFLAGMASK; 245183724Ssos strncpy(mp->mnt_stat.f_fstypename, vfsp->vfc_name, MFSNAMELEN); 246183724Ssos vp->v_mountedhere = mp; 247183724Ssos mp->mnt_vnodecovered = vp; 248183724Ssos mp->mnt_stat.f_owner = p->p_ucred->cr_uid; 249183724Ssosupdate: 250183724Ssos /* 251183724Ssos * Set the mount level flags. 252183724Ssos */ 253183724Ssos if (SCARG(uap, flags) & MNT_RDONLY) 254183724Ssos mp->mnt_flag |= MNT_RDONLY; 255183724Ssos else if (mp->mnt_flag & MNT_RDONLY) 256183724Ssos mp->mnt_flag |= MNT_WANTRDWR; 257183724Ssos mp->mnt_flag &=~ (MNT_NOSUID | MNT_NOEXEC | MNT_NODEV | 258183724Ssos MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC | MNT_NOATIME); 259183724Ssos mp->mnt_flag |= SCARG(uap, flags) & (MNT_NOSUID | MNT_NOEXEC | 260183724Ssos MNT_NODEV | MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC | MNT_FORCE | 261183724Ssos MNT_NOATIME); 262183724Ssos /* 263183724Ssos * Mount the filesystem. 264183724Ssos */ 265183724Ssos error = VFS_MOUNT(mp, SCARG(uap, path), SCARG(uap, data), &nd, p); 266183724Ssos if (mp->mnt_flag & MNT_UPDATE) { 267183724Ssos vrele(vp); 268183724Ssos if (mp->mnt_flag & MNT_WANTRDWR) 269183724Ssos mp->mnt_flag &= ~MNT_RDONLY; 270183724Ssos mp->mnt_flag &=~ 271183724Ssos (MNT_UPDATE | MNT_RELOAD | MNT_FORCE | MNT_WANTRDWR); 272183724Ssos if (error) 273183724Ssos mp->mnt_flag = flag; 274183724Ssos vfs_unbusy(mp, p); 275183724Ssos return (error); 276183724Ssos } 277183724Ssos /* 278183724Ssos * Put the new filesystem on the mount list after root. 279183724Ssos */ 280183724Ssos cache_purge(vp); 281183724Ssos if (!error) { 282183724Ssos simple_lock(&mountlist_slock); 283183724Ssos CIRCLEQ_INSERT_TAIL(&mountlist, mp, mnt_list); 284183724Ssos simple_unlock(&mountlist_slock); 285183724Ssos checkdirs(vp); 286183724Ssos VOP_UNLOCK(vp, 0, p); 287183724Ssos vfs_unbusy(mp, p); 288183724Ssos if (error = VFS_START(mp, 0, p)) 289183724Ssos vrele(vp); 290183724Ssos } else { 291183724Ssos mp->mnt_vnodecovered->v_mountedhere = (struct mount *)0; 292183724Ssos mp->mnt_vfc->vfc_refcount--; 293183724Ssos vfs_unbusy(mp, p); 294183724Ssos free((caddr_t)mp, M_MOUNT); 295183724Ssos vput(vp); 296183724Ssos } 297183724Ssos return (error); 298183724Ssos} 299183724Ssos 300183724Ssos/* 301183724Ssos * Scan all active processes to see if any of them have a current 302188765Smav * or root directory onto which the new filesystem has just been 303183724Ssos * mounted. If so, replace them with the new mount point. 304183724Ssos */ 305183724Ssosstatic void 306183724Ssoscheckdirs(olddp) 307183724Ssos struct vnode *olddp; 308183724Ssos{ 309183724Ssos struct filedesc *fdp; 310183724Ssos struct vnode *newdp; 311183724Ssos struct proc *p; 312183724Ssos 313183724Ssos if (olddp->v_usecount == 1) 314183724Ssos return; 315183724Ssos if (VFS_ROOT(olddp->v_mountedhere, &newdp)) 316183724Ssos panic("mount: lost mount"); 317183724Ssos for (p = allproc.lh_first; p != 0; p = p->p_list.le_next) { 318183724Ssos fdp = p->p_fd; 319183724Ssos if (fdp->fd_cdir == olddp) { 320183724Ssos vrele(fdp->fd_cdir); 321183724Ssos VREF(newdp); 322183724Ssos fdp->fd_cdir = newdp; 323183724Ssos } 324183724Ssos if (fdp->fd_rdir == olddp) { 325183724Ssos vrele(fdp->fd_rdir); 326183724Ssos VREF(newdp); 327183724Ssos fdp->fd_rdir = newdp; 328183724Ssos } 329183724Ssos } 330183724Ssos if (rootvnode == olddp) { 331183724Ssos vrele(rootvnode); 332183724Ssos VREF(newdp); 333183724Ssos rootvnode = newdp; 334183724Ssos } 335183724Ssos vput(newdp); 336183724Ssos} 337183724Ssos 338183724Ssos/* 339183724Ssos * Unmount a file system. 340183724Ssos * 341183724Ssos * Note: unmount takes a path to the vnode mounted on as argument, 342183724Ssos * not special file (as before). 343183724Ssos */ 344183724Ssos#ifndef _SYS_SYSPROTO_H_ 345183724Ssosstruct unmount_args { 346183724Ssos char *path; 347183724Ssos int flags; 348183724Ssos}; 349183724Ssos#endif 350183724Ssos/* ARGSUSED */ 351183724Ssosint 352183724Ssosunmount(p, uap, retval) 353183724Ssos struct proc *p; 354183724Ssos register struct unmount_args /* { 355183724Ssos syscallarg(char *) path; 356183724Ssos syscallarg(int) flags; 357183724Ssos } */ *uap; 358183724Ssos register_t *retval; 359183724Ssos{ 360183724Ssos register struct vnode *vp; 361183724Ssos struct mount *mp; 362183724Ssos int error; 363183724Ssos struct nameidata nd; 364183724Ssos 365183724Ssos NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, 366183724Ssos SCARG(uap, path), p); 367183724Ssos if (error = namei(&nd)) 368183724Ssos return (error); 369183724Ssos vp = nd.ni_vp; 370183724Ssos mp = vp->v_mount; 371183724Ssos 372183724Ssos /* 373183724Ssos * Only root, or the user that did the original mount is 374183724Ssos * permitted to unmount this filesystem. 375183724Ssos */ 376183724Ssos if ((mp->mnt_stat.f_owner != p->p_ucred->cr_uid) && 377183724Ssos (error = suser(p->p_ucred, &p->p_acflag))) { 378183724Ssos vput(vp); 379183724Ssos return (error); 380183724Ssos } 381183724Ssos 382183724Ssos /* 383183724Ssos * Don't allow unmounting the root file system. 384183724Ssos */ 385183724Ssos if (mp->mnt_flag & MNT_ROOTFS) { 386183724Ssos vput(vp); 387183724Ssos return (EINVAL); 388183724Ssos } 389183724Ssos 390183724Ssos /* 391183724Ssos * Must be the root of the filesystem 392183724Ssos */ 393183724Ssos if ((vp->v_flag & VROOT) == 0) { 394183724Ssos vput(vp); 395183724Ssos return (EINVAL); 396183724Ssos } 397183724Ssos vput(vp); 398183724Ssos return (dounmount(mp, SCARG(uap, flags), p)); 399183724Ssos} 400183724Ssos 401183724Ssos/* 402183724Ssos * Do the actual file system unmount. 403183724Ssos */ 404183724Ssosint 405183724Ssosdounmount(mp, flags, p) 406183724Ssos register struct mount *mp; 407183724Ssos int flags; 408183724Ssos struct proc *p; 409183724Ssos{ 410183724Ssos struct vnode *coveredvp; 411183724Ssos int error; 412183724Ssos 413183724Ssos simple_lock(&mountlist_slock); 414183724Ssos mp->mnt_flag |= MNT_UNMOUNT; 415183724Ssos lockmgr(&mp->mnt_lock, LK_DRAIN | LK_INTERLOCK, &mountlist_slock, p); 416183724Ssos mp->mnt_flag &=~ MNT_ASYNC; 417183724Ssos vfs_msync(mp, MNT_NOWAIT); 418183724Ssos vnode_pager_umount(mp); /* release cached vnodes */ 419183724Ssos cache_purgevfs(mp); /* remove cache entries for this file sys */ 420183724Ssos if (((mp->mnt_flag & MNT_RDONLY) || 421183724Ssos (error = VFS_SYNC(mp, MNT_WAIT, p->p_ucred, p)) == 0) || 422183724Ssos (flags & MNT_FORCE)) 423183724Ssos error = VFS_UNMOUNT(mp, flags, p); 424183724Ssos simple_lock(&mountlist_slock); 425183724Ssos if (error) { 426183724Ssos mp->mnt_flag &= ~MNT_UNMOUNT; 427183724Ssos lockmgr(&mp->mnt_lock, LK_RELEASE | LK_INTERLOCK | LK_REENABLE, 428183724Ssos &mountlist_slock, p); 429183724Ssos return (error); 430183724Ssos } 431183724Ssos CIRCLEQ_REMOVE(&mountlist, mp, mnt_list); 432183724Ssos if ((coveredvp = mp->mnt_vnodecovered) != NULLVP) { 433183724Ssos coveredvp->v_mountedhere = (struct mount *)0; 434183724Ssos vrele(coveredvp); 435183724Ssos } 436183724Ssos mp->mnt_vfc->vfc_refcount--; 437183724Ssos if (mp->mnt_vnodelist.lh_first != NULL) 438183724Ssos panic("unmount: dangling vnode"); 439183724Ssos lockmgr(&mp->mnt_lock, LK_RELEASE | LK_INTERLOCK, &mountlist_slock, p); 440183724Ssos if (mp->mnt_flag & MNT_MWAIT) 441183724Ssos wakeup((caddr_t)mp); 442183724Ssos free((caddr_t)mp, M_MOUNT); 443183724Ssos return (0); 444183724Ssos} 445183724Ssos 446183724Ssos/* 447183724Ssos * Sync each mounted filesystem. 448183724Ssos */ 449183724Ssos#ifndef _SYS_SYSPROTO_H_ 450183724Ssosstruct sync_args { 451183724Ssos int dummy; 452183724Ssos}; 453183724Ssos#endif 454183724Ssos 455183724Ssos#ifdef DEBUG 456183724Ssosint syncprt = 0; 457183724SsosSYSCTL_INT(_debug, 0, syncprt, CTLFLAG_RW, &syncprt, 0, ""); 458183724Ssos#endif 459183724Ssos 460183724Ssos/* ARGSUSED */ 461183724Ssosint 462183724Ssossync(p, uap, retval) 463183724Ssos struct proc *p; 464183724Ssos struct sync_args *uap; 465183724Ssos register_t *retval; 466183724Ssos{ 467183724Ssos register struct mount *mp, *nmp; 468183724Ssos int asyncflag; 469188765Smav 470183724Ssos simple_lock(&mountlist_slock); 471183724Ssos for (mp = mountlist.cqh_first; mp != (void *)&mountlist; mp = nmp) { 472183724Ssos if (vfs_busy(mp, LK_NOWAIT, &mountlist_slock, p)) { 473183724Ssos nmp = mp->mnt_list.cqe_next; 474183724Ssos continue; 475188765Smav } 476188765Smav if ((mp->mnt_flag & MNT_RDONLY) == 0) { 477183724Ssos asyncflag = mp->mnt_flag & MNT_ASYNC; 478183724Ssos mp->mnt_flag &= ~MNT_ASYNC; 479183724Ssos vfs_msync(mp, MNT_NOWAIT); 480183724Ssos VFS_SYNC(mp, MNT_NOWAIT, p != NULL ? p->p_ucred : NOCRED, p); 481183724Ssos if (asyncflag) 482183724Ssos mp->mnt_flag |= MNT_ASYNC; 483183724Ssos } 484183724Ssos simple_lock(&mountlist_slock); 485183724Ssos nmp = mp->mnt_list.cqe_next; 486183724Ssos vfs_unbusy(mp, p); 487183724Ssos } 488183724Ssos simple_unlock(&mountlist_slock); 489183724Ssos#if 0 490183724Ssos/* 491183724Ssos * XXX don't call vfs_bufstats() yet because that routine 492183724Ssos * was not imported in the Lite2 merge. 493183724Ssos */ 494183724Ssos#ifdef DIAGNOSTIC 495183724Ssos if (syncprt) 496183724Ssos vfs_bufstats(); 497183724Ssos#endif /* DIAGNOSTIC */ 498183724Ssos#endif 499183724Ssos return (0); 500183724Ssos} 501183724Ssos 502183724Ssos/* 503183724Ssos * Change filesystem quotas. 504183724Ssos */ 505183724Ssos#ifndef _SYS_SYSPROTO_H_ 506183724Ssosstruct quotactl_args { 507183724Ssos char *path; 508183724Ssos int cmd; 509183724Ssos int uid; 510183724Ssos caddr_t arg; 511183724Ssos}; 512183724Ssos#endif 513183724Ssos/* ARGSUSED */ 514183724Ssosint 515183724Ssosquotactl(p, uap, retval) 516183724Ssos struct proc *p; 517183724Ssos register struct quotactl_args /* { 518183724Ssos syscallarg(char *) path; 519183724Ssos syscallarg(int) cmd; 520183724Ssos syscallarg(int) uid; 521183724Ssos syscallarg(caddr_t) arg; 522183724Ssos } */ *uap; 523183724Ssos register_t *retval; 524183724Ssos{ 525183724Ssos register struct mount *mp; 526183724Ssos int error; 527183724Ssos struct nameidata nd; 528183724Ssos 529183724Ssos NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 530183724Ssos if (error = namei(&nd)) 531183724Ssos return (error); 532183724Ssos mp = nd.ni_vp->v_mount; 533183724Ssos vrele(nd.ni_vp); 534183724Ssos return (VFS_QUOTACTL(mp, SCARG(uap, cmd), SCARG(uap, uid), 535183724Ssos SCARG(uap, arg), p)); 536183724Ssos} 537183724Ssos 538183724Ssos/* 539183724Ssos * Get filesystem statistics. 540183724Ssos */ 541183724Ssos#ifndef _SYS_SYSPROTO_H_ 542183724Ssosstruct statfs_args { 543183724Ssos char *path; 544183724Ssos struct statfs *buf; 545183724Ssos}; 546183724Ssos#endif 547183724Ssos/* ARGSUSED */ 548183724Ssosint 549183724Ssosstatfs(p, uap, retval) 550183724Ssos struct proc *p; 551183724Ssos register struct statfs_args /* { 552183724Ssos syscallarg(char *) path; 553183724Ssos syscallarg(struct statfs *) buf; 554183724Ssos } */ *uap; 555183724Ssos register_t *retval; 556183724Ssos{ 557183724Ssos register struct mount *mp; 558183724Ssos register struct statfs *sp; 559183724Ssos int error; 560183724Ssos struct nameidata nd; 561183724Ssos struct statfs sb; 562183724Ssos 563183724Ssos NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 564183724Ssos if (error = namei(&nd)) 565183724Ssos return (error); 566183724Ssos mp = nd.ni_vp->v_mount; 567183724Ssos sp = &mp->mnt_stat; 568183724Ssos vrele(nd.ni_vp); 569183724Ssos error = VFS_STATFS(mp, sp, p); 570183724Ssos if (error) 571183724Ssos return (error); 572183724Ssos sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 573183724Ssos if (p->p_ucred->cr_uid != 0) { 574183724Ssos bcopy((caddr_t)sp, (caddr_t)&sb, sizeof(sb)); 575183724Ssos sb.f_fsid.val[0] = sb.f_fsid.val[1] = 0; 576183724Ssos sp = &sb; 577183724Ssos } 578183724Ssos return (copyout((caddr_t)sp, (caddr_t)SCARG(uap, buf), sizeof(*sp))); 579183724Ssos} 580183724Ssos 581183724Ssos/* 582183724Ssos * Get filesystem statistics. 583183724Ssos */ 584183724Ssos#ifndef _SYS_SYSPROTO_H_ 585183724Ssosstruct fstatfs_args { 586183724Ssos int fd; 587183724Ssos struct statfs *buf; 588183724Ssos}; 589183724Ssos#endif 590183724Ssos/* ARGSUSED */ 591183724Ssosint 592183724Ssosfstatfs(p, uap, retval) 593183724Ssos struct proc *p; 594183724Ssos register struct fstatfs_args /* { 595183724Ssos syscallarg(int) fd; 596183724Ssos syscallarg(struct statfs *) buf; 597183724Ssos } */ *uap; 598183724Ssos register_t *retval; 599183724Ssos{ 600183724Ssos struct file *fp; 601183724Ssos struct mount *mp; 602183724Ssos register struct statfs *sp; 603183724Ssos int error; 604183724Ssos struct statfs sb; 605183724Ssos 606183724Ssos if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) 607183724Ssos return (error); 608183724Ssos mp = ((struct vnode *)fp->f_data)->v_mount; 609183724Ssos sp = &mp->mnt_stat; 610183724Ssos error = VFS_STATFS(mp, sp, p); 611183724Ssos if (error) 612183724Ssos return (error); 613183724Ssos sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 614183724Ssos if (p->p_ucred->cr_uid != 0) { 615183724Ssos bcopy((caddr_t)sp, (caddr_t)&sb, sizeof(sb)); 616183724Ssos sb.f_fsid.val[0] = sb.f_fsid.val[1] = 0; 617183724Ssos sp = &sb; 618183724Ssos } 619183724Ssos return (copyout((caddr_t)sp, (caddr_t)SCARG(uap, buf), sizeof(*sp))); 620183724Ssos} 621183724Ssos 622183724Ssos/* 623183724Ssos * Get statistics on all filesystems. 624183724Ssos */ 625183724Ssos#ifndef _SYS_SYSPROTO_H_ 626183724Ssosstruct getfsstat_args { 627183724Ssos struct statfs *buf; 628183724Ssos long bufsize; 629183724Ssos int flags; 630183724Ssos}; 631183724Ssos#endif 632183724Ssosint 633183724Ssosgetfsstat(p, uap, retval) 634183724Ssos struct proc *p; 635183724Ssos register struct getfsstat_args /* { 636183724Ssos syscallarg(struct statfs *) buf; 637183724Ssos syscallarg(long) bufsize; 638183724Ssos syscallarg(int) flags; 639183724Ssos } */ *uap; 640183724Ssos register_t *retval; 641183724Ssos{ 642183724Ssos register struct mount *mp, *nmp; 643183724Ssos register struct statfs *sp; 644183724Ssos caddr_t sfsp; 645183724Ssos long count, maxcount, error; 646183724Ssos 647183724Ssos maxcount = SCARG(uap, bufsize) / sizeof(struct statfs); 648183724Ssos sfsp = (caddr_t)SCARG(uap, buf); 649183724Ssos count = 0; 650183724Ssos simple_lock(&mountlist_slock); 651183724Ssos for (mp = mountlist.cqh_first; mp != (void *)&mountlist; mp = nmp) { 652183724Ssos if (vfs_busy(mp, LK_NOWAIT, &mountlist_slock, p)) { 653183724Ssos nmp = mp->mnt_list.cqe_next; 654183724Ssos continue; 655183724Ssos } 656183724Ssos if (sfsp && count < maxcount) { 657183724Ssos sp = &mp->mnt_stat; 658183724Ssos /* 659183724Ssos * If MNT_NOWAIT is specified, do not refresh the 660183724Ssos * fsstat cache. MNT_WAIT overrides MNT_NOWAIT. 661183724Ssos */ 662183724Ssos if (((SCARG(uap, flags) & MNT_NOWAIT) == 0 || 663183724Ssos (SCARG(uap, flags) & MNT_WAIT)) && 664183724Ssos (error = VFS_STATFS(mp, sp, p))) { 665183724Ssos simple_lock(&mountlist_slock); 666183724Ssos nmp = mp->mnt_list.cqe_next; 667183724Ssos vfs_unbusy(mp, p); 668183724Ssos continue; 669183724Ssos } 670183724Ssos sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 671183724Ssos error = copyout((caddr_t)sp, sfsp, sizeof(*sp)); 672183724Ssos if (error) { 673183724Ssos vfs_unbusy(mp, p); 674183724Ssos return (error); 675183724Ssos } 676183724Ssos sfsp += sizeof(*sp); 677183724Ssos } 678183724Ssos count++; 679183724Ssos simple_lock(&mountlist_slock); 680183724Ssos nmp = mp->mnt_list.cqe_next; 681183724Ssos vfs_unbusy(mp, p); 682183724Ssos } 683183724Ssos simple_unlock(&mountlist_slock); 684183724Ssos if (sfsp && count > maxcount) 685183724Ssos *retval = maxcount; 686183724Ssos else 687183724Ssos *retval = count; 688183724Ssos return (0); 689183724Ssos} 690183724Ssos 691183724Ssos/* 692183724Ssos * Change current working directory to a given file descriptor. 693183724Ssos */ 694183724Ssos#ifndef _SYS_SYSPROTO_H_ 695183724Ssosstruct fchdir_args { 696183724Ssos int fd; 697183724Ssos}; 698183724Ssos#endif 699183724Ssos/* ARGSUSED */ 700183724Ssosint 701183724Ssosfchdir(p, uap, retval) 702183724Ssos struct proc *p; 703183724Ssos struct fchdir_args /* { 704183724Ssos syscallarg(int) fd; 705183724Ssos } */ *uap; 706183724Ssos register_t *retval; 707183724Ssos{ 708183724Ssos register struct filedesc *fdp = p->p_fd; 709183724Ssos struct vnode *vp, *tdp; 710183724Ssos struct mount *mp; 711183724Ssos struct file *fp; 712183724Ssos int error; 713183724Ssos 714183724Ssos if (error = getvnode(fdp, SCARG(uap, fd), &fp)) 715183724Ssos return (error); 716183724Ssos vp = (struct vnode *)fp->f_data; 717183724Ssos VREF(vp); 718183724Ssos vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 719183724Ssos if (vp->v_type != VDIR) 720183724Ssos error = ENOTDIR; 721183724Ssos else 722183724Ssos error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p); 723183724Ssos while (!error && (mp = vp->v_mountedhere) != NULL) { 724183724Ssos if (vfs_busy(mp, 0, 0, p)) 725183724Ssos continue; 726183724Ssos error = VFS_ROOT(mp, &tdp); 727183724Ssos vfs_unbusy(mp, p); 728183724Ssos if (error) 729183724Ssos break; 730183724Ssos vput(vp); 731183724Ssos vp = tdp; 732183724Ssos } 733183724Ssos if (error) { 734183724Ssos vput(vp); 735183724Ssos return (error); 736183724Ssos } 737183724Ssos VOP_UNLOCK(vp, 0, p); 738183724Ssos vrele(fdp->fd_cdir); 739183724Ssos fdp->fd_cdir = vp; 740183724Ssos return (0); 741183724Ssos} 742183724Ssos 743183724Ssos/* 744183724Ssos * Change current working directory (``.''). 745183724Ssos */ 746183724Ssos#ifndef _SYS_SYSPROTO_H_ 747183724Ssosstruct chdir_args { 748183724Ssos char *path; 749183724Ssos}; 750183724Ssos#endif 751183724Ssos/* ARGSUSED */ 752183724Ssosint 753183724Ssoschdir(p, uap, retval) 754183724Ssos struct proc *p; 755183724Ssos struct chdir_args /* { 756183724Ssos syscallarg(char *) path; 757183724Ssos } */ *uap; 758183724Ssos register_t *retval; 759183724Ssos{ 760183724Ssos register struct filedesc *fdp = p->p_fd; 761183724Ssos int error; 762183724Ssos struct nameidata nd; 763183724Ssos 764183724Ssos NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, 765183724Ssos SCARG(uap, path), p); 766183724Ssos if (error = change_dir(&nd, p)) 767183724Ssos return (error); 768183724Ssos vrele(fdp->fd_cdir); 769183724Ssos fdp->fd_cdir = nd.ni_vp; 770183724Ssos return (0); 771183724Ssos} 772183724Ssos 773183724Ssos/* 774183724Ssos * Change notion of root (``/'') directory. 775183724Ssos */ 776183724Ssos#ifndef _SYS_SYSPROTO_H_ 777183724Ssosstruct chroot_args { 778183724Ssos char *path; 779183724Ssos}; 780183724Ssos#endif 781183724Ssos/* ARGSUSED */ 782183724Ssosint 783183724Ssoschroot(p, uap, retval) 784183724Ssos struct proc *p; 785183724Ssos struct chroot_args /* { 786183724Ssos syscallarg(char *) path; 787183724Ssos } */ *uap; 788183724Ssos register_t *retval; 789183724Ssos{ 790183724Ssos register struct filedesc *fdp = p->p_fd; 791183724Ssos int error; 792183724Ssos struct nameidata nd; 793183724Ssos 794183724Ssos error = suser(p->p_ucred, &p->p_acflag); 795183724Ssos if (error) 796183724Ssos return (error); 797183724Ssos NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, 798183724Ssos SCARG(uap, path), p); 799183724Ssos if (error = change_dir(&nd, p)) 800183724Ssos return (error); 801183724Ssos if (fdp->fd_rdir != NULL) 802183724Ssos vrele(fdp->fd_rdir); 803183724Ssos fdp->fd_rdir = nd.ni_vp; 804183724Ssos return (0); 805183724Ssos} 806183724Ssos 807183724Ssos/* 808183724Ssos * Common routine for chroot and chdir. 809183724Ssos */ 810183724Ssosstatic int 811183724Ssoschange_dir(ndp, p) 812183724Ssos register struct nameidata *ndp; 813183724Ssos struct proc *p; 814183724Ssos{ 815183724Ssos struct vnode *vp; 816183724Ssos int error; 817183724Ssos 818183724Ssos error = namei(ndp); 819183724Ssos if (error) 820183724Ssos return (error); 821183724Ssos vp = ndp->ni_vp; 822183724Ssos if (vp->v_type != VDIR) 823183724Ssos error = ENOTDIR; 824183724Ssos else 825183724Ssos error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p); 826183724Ssos if (error) 827183724Ssos vput(vp); 828183724Ssos else 829183724Ssos VOP_UNLOCK(vp, 0, p); 830183724Ssos return (error); 831183724Ssos} 832183724Ssos 833183724Ssos/* 834183724Ssos * Check permissions, allocate an open file structure, 835183724Ssos * and call the device open routine if any. 836183724Ssos */ 837183724Ssos#ifndef _SYS_SYSPROTO_H_ 838183724Ssosstruct open_args { 839183724Ssos char *path; 840183724Ssos int flags; 841183724Ssos int mode; 842183724Ssos}; 843183724Ssos#endif 844183724Ssosint 845183724Ssosopen(p, uap, retval) 846183724Ssos struct proc *p; 847183724Ssos register struct open_args /* { 848183724Ssos syscallarg(char *) path; 849183724Ssos syscallarg(int) flags; 850183724Ssos syscallarg(int) mode; 851183724Ssos } */ *uap; 852183724Ssos register_t *retval; 853183724Ssos{ 854183724Ssos register struct filedesc *fdp = p->p_fd; 855183724Ssos register struct file *fp; 856183724Ssos register struct vnode *vp; 857183724Ssos int flags, cmode; 858183724Ssos struct file *nfp; 859183724Ssos int type, indx, error; 860183724Ssos struct flock lf; 861183724Ssos struct nameidata nd; 862183724Ssos 863183724Ssos error = falloc(p, &nfp, &indx); 864183724Ssos if (error) 865183724Ssos return (error); 866183724Ssos fp = nfp; 867183724Ssos flags = FFLAGS(SCARG(uap, flags)); 868183724Ssos cmode = ((SCARG(uap, mode) &~ fdp->fd_cmask) & ALLPERMS) &~ S_ISTXT; 869183724Ssos NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 870183724Ssos p->p_dupfd = -indx - 1; /* XXX check for fdopen */ 871183724Ssos error = vn_open(&nd, flags, cmode); 872183724Ssos if (error) { 873183724Ssos ffree(fp); 874183724Ssos if ((error == ENODEV || error == ENXIO) && 875183724Ssos p->p_dupfd >= 0 && /* XXX from fdopen */ 876183724Ssos (error = 877183724Ssos dupfdopen(fdp, indx, p->p_dupfd, flags, error)) == 0) { 878183724Ssos *retval = indx; 879183724Ssos return (0); 880183724Ssos } 881183724Ssos if (error == ERESTART) 882183724Ssos error = EINTR; 883183724Ssos fdp->fd_ofiles[indx] = NULL; 884183724Ssos return (error); 885183724Ssos } 886183724Ssos p->p_dupfd = 0; 887183724Ssos vp = nd.ni_vp; 888183724Ssos 889183724Ssos fp->f_flag = flags & FMASK; 890183724Ssos fp->f_type = (vp->v_type == VFIFO ? DTYPE_FIFO : DTYPE_VNODE); 891183724Ssos fp->f_ops = &vnops; 892 fp->f_data = (caddr_t)vp; 893 if (flags & (O_EXLOCK | O_SHLOCK)) { 894 lf.l_whence = SEEK_SET; 895 lf.l_start = 0; 896 lf.l_len = 0; 897 if (flags & O_EXLOCK) 898 lf.l_type = F_WRLCK; 899 else 900 lf.l_type = F_RDLCK; 901 type = F_FLOCK; 902 if ((flags & FNONBLOCK) == 0) 903 type |= F_WAIT; 904 VOP_UNLOCK(vp, 0, p); 905 if (error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, type)) { 906 (void) vn_close(vp, fp->f_flag, fp->f_cred, p); 907 ffree(fp); 908 fdp->fd_ofiles[indx] = NULL; 909 return (error); 910 } 911 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 912 fp->f_flag |= FHASLOCK; 913 } 914 VOP_UNLOCK(vp, 0, p); 915 *retval = indx; 916 return (0); 917} 918 919#ifdef COMPAT_43 920/* 921 * Create a file. 922 */ 923#ifndef _SYS_SYSPROTO_H_ 924struct ocreat_args { 925 char *path; 926 int mode; 927}; 928#endif 929int 930ocreat(p, uap, retval) 931 struct proc *p; 932 register struct ocreat_args /* { 933 syscallarg(char *) path; 934 syscallarg(int) mode; 935 } */ *uap; 936 register_t *retval; 937{ 938 struct open_args /* { 939 syscallarg(char *) path; 940 syscallarg(int) flags; 941 syscallarg(int) mode; 942 } */ nuap; 943 944 SCARG(&nuap, path) = SCARG(uap, path); 945 SCARG(&nuap, mode) = SCARG(uap, mode); 946 SCARG(&nuap, flags) = O_WRONLY | O_CREAT | O_TRUNC; 947 return (open(p, &nuap, retval)); 948} 949#endif /* COMPAT_43 */ 950 951/* 952 * Create a special file. 953 */ 954#ifndef _SYS_SYSPROTO_H_ 955struct mknod_args { 956 char *path; 957 int mode; 958 int dev; 959}; 960#endif 961/* ARGSUSED */ 962int 963mknod(p, uap, retval) 964 struct proc *p; 965 register struct mknod_args /* { 966 syscallarg(char *) path; 967 syscallarg(int) mode; 968 syscallarg(int) dev; 969 } */ *uap; 970 register_t *retval; 971{ 972 register struct vnode *vp; 973 struct vattr vattr; 974 int error; 975 int whiteout; 976 struct nameidata nd; 977 978 error = suser(p->p_ucred, &p->p_acflag); 979 if (error) 980 return (error); 981 NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p); 982 if (error = namei(&nd)) 983 return (error); 984 vp = nd.ni_vp; 985 if (vp != NULL) 986 error = EEXIST; 987 else { 988 VATTR_NULL(&vattr); 989 vattr.va_mode = (SCARG(uap, mode) & ALLPERMS) &~ p->p_fd->fd_cmask; 990 vattr.va_rdev = SCARG(uap, dev); 991 whiteout = 0; 992 993 switch (SCARG(uap, mode) & S_IFMT) { 994 case S_IFMT: /* used by badsect to flag bad sectors */ 995 vattr.va_type = VBAD; 996 break; 997 case S_IFCHR: 998 vattr.va_type = VCHR; 999 break; 1000 case S_IFBLK: 1001 vattr.va_type = VBLK; 1002 break; 1003 case S_IFWHT: 1004 whiteout = 1; 1005 break; 1006 default: 1007 error = EINVAL; 1008 break; 1009 } 1010 } 1011 if (!error) { 1012 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 1013 if (whiteout) { 1014 error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, CREATE); 1015 if (error) 1016 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1017 vput(nd.ni_dvp); 1018 } else { 1019 error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, 1020 &nd.ni_cnd, &vattr); 1021 } 1022 } else { 1023 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1024 if (nd.ni_dvp == vp) 1025 vrele(nd.ni_dvp); 1026 else 1027 vput(nd.ni_dvp); 1028 if (vp) 1029 vrele(vp); 1030 } 1031 return (error); 1032} 1033 1034/* 1035 * Create a named pipe. 1036 */ 1037#ifndef _SYS_SYSPROTO_H_ 1038struct mkfifo_args { 1039 char *path; 1040 int mode; 1041}; 1042#endif 1043/* ARGSUSED */ 1044int 1045mkfifo(p, uap, retval) 1046 struct proc *p; 1047 register struct mkfifo_args /* { 1048 syscallarg(char *) path; 1049 syscallarg(int) mode; 1050 } */ *uap; 1051 register_t *retval; 1052{ 1053 struct vattr vattr; 1054 int error; 1055 struct nameidata nd; 1056 1057 NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p); 1058 if (error = namei(&nd)) 1059 return (error); 1060 if (nd.ni_vp != NULL) { 1061 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1062 if (nd.ni_dvp == nd.ni_vp) 1063 vrele(nd.ni_dvp); 1064 else 1065 vput(nd.ni_dvp); 1066 vrele(nd.ni_vp); 1067 return (EEXIST); 1068 } 1069 VATTR_NULL(&vattr); 1070 vattr.va_type = VFIFO; 1071 vattr.va_mode = (SCARG(uap, mode) & ALLPERMS) &~ p->p_fd->fd_cmask; 1072 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 1073 return (VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr)); 1074} 1075 1076/* 1077 * Make a hard file link. 1078 */ 1079#ifndef _SYS_SYSPROTO_H_ 1080struct link_args { 1081 char *path; 1082 char *link; 1083}; 1084#endif 1085/* ARGSUSED */ 1086int 1087link(p, uap, retval) 1088 struct proc *p; 1089 register struct link_args /* { 1090 syscallarg(char *) path; 1091 syscallarg(char *) link; 1092 } */ *uap; 1093 register_t *retval; 1094{ 1095 register struct vnode *vp; 1096 struct nameidata nd; 1097 int error; 1098 1099 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 1100 if (error = namei(&nd)) 1101 return (error); 1102 vp = nd.ni_vp; 1103 if (vp->v_type == VDIR) 1104 error = EPERM; /* POSIX */ 1105 else { 1106 NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, link), p); 1107 error = namei(&nd); 1108 if (!error) { 1109 if (nd.ni_vp != NULL) { 1110 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1111 if (nd.ni_dvp == nd.ni_vp) 1112 vrele(nd.ni_dvp); 1113 else 1114 vput(nd.ni_dvp); 1115 if (nd.ni_vp) 1116 vrele(nd.ni_vp); 1117 error = EEXIST; 1118 } else { 1119 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, 1120 LEASE_WRITE); 1121 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 1122 error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd); 1123 } 1124 } 1125 } 1126 vrele(vp); 1127 return (error); 1128} 1129 1130/* 1131 * Make a symbolic link. 1132 */ 1133#ifndef _SYS_SYSPROTO_H_ 1134struct symlink_args { 1135 char *path; 1136 char *link; 1137}; 1138#endif 1139/* ARGSUSED */ 1140int 1141symlink(p, uap, retval) 1142 struct proc *p; 1143 register struct symlink_args /* { 1144 syscallarg(char *) path; 1145 syscallarg(char *) link; 1146 } */ *uap; 1147 register_t *retval; 1148{ 1149 struct vattr vattr; 1150 char *path; 1151 int error; 1152 struct nameidata nd; 1153 1154 MALLOC(path, char *, MAXPATHLEN, M_NAMEI, M_WAITOK); 1155 if (error = copyinstr(SCARG(uap, path), path, MAXPATHLEN, NULL)) 1156 goto out; 1157 NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, link), p); 1158 if (error = namei(&nd)) 1159 goto out; 1160 if (nd.ni_vp) { 1161 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1162 if (nd.ni_dvp == nd.ni_vp) 1163 vrele(nd.ni_dvp); 1164 else 1165 vput(nd.ni_dvp); 1166 vrele(nd.ni_vp); 1167 error = EEXIST; 1168 goto out; 1169 } 1170 VATTR_NULL(&vattr); 1171 vattr.va_mode = ACCESSPERMS &~ p->p_fd->fd_cmask; 1172 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 1173 error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr, path); 1174out: 1175 FREE(path, M_NAMEI); 1176 return (error); 1177} 1178 1179/* 1180 * Delete a whiteout from the filesystem. 1181 */ 1182/* ARGSUSED */ 1183int 1184undelete(p, uap, retval) 1185 struct proc *p; 1186 register struct undelete_args /* { 1187 syscallarg(char *) path; 1188 } */ *uap; 1189 register_t *retval; 1190{ 1191 int error; 1192 struct nameidata nd; 1193 1194 NDINIT(&nd, DELETE, LOCKPARENT|DOWHITEOUT, UIO_USERSPACE, 1195 SCARG(uap, path), p); 1196 error = namei(&nd); 1197 if (error) 1198 return (error); 1199 1200 if (nd.ni_vp != NULLVP || !(nd.ni_cnd.cn_flags & ISWHITEOUT)) { 1201 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1202 if (nd.ni_dvp == nd.ni_vp) 1203 vrele(nd.ni_dvp); 1204 else 1205 vput(nd.ni_dvp); 1206 if (nd.ni_vp) 1207 vrele(nd.ni_vp); 1208 return (EEXIST); 1209 } 1210 1211 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 1212 if (error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, DELETE)) 1213 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1214 vput(nd.ni_dvp); 1215 return (error); 1216} 1217 1218/* 1219 * Delete a name from the filesystem. 1220 */ 1221#ifndef _SYS_SYSPROTO_H_ 1222struct unlink_args { 1223 char *path; 1224}; 1225#endif 1226/* ARGSUSED */ 1227int 1228unlink(p, uap, retval) 1229 struct proc *p; 1230 struct unlink_args /* { 1231 syscallarg(char *) path; 1232 } */ *uap; 1233 register_t *retval; 1234{ 1235 register struct vnode *vp; 1236 int error; 1237 struct nameidata nd; 1238 1239 NDINIT(&nd, DELETE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p); 1240 if (error = namei(&nd)) 1241 return (error); 1242 vp = nd.ni_vp; 1243 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 1244 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 1245 1246 if (vp->v_type == VDIR) 1247 error = EPERM; /* POSIX */ 1248 else { 1249 /* 1250 * The root of a mounted filesystem cannot be deleted. 1251 * 1252 * XXX: can this only be a VDIR case? 1253 */ 1254 if (vp->v_flag & VROOT) 1255 error = EBUSY; 1256 else 1257 (void) vnode_pager_uncache(vp, p); 1258 } 1259 1260 if (!error) { 1261 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 1262 error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); 1263 } else { 1264 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1265 if (nd.ni_dvp == vp) 1266 vrele(nd.ni_dvp); 1267 else 1268 vput(nd.ni_dvp); 1269 if (vp != NULLVP) 1270 vput(vp); 1271 } 1272 return (error); 1273} 1274 1275/* 1276 * Reposition read/write file offset. 1277 */ 1278#ifndef _SYS_SYSPROTO_H_ 1279struct lseek_args { 1280 int fd; 1281 int pad; 1282 off_t offset; 1283 int whence; 1284}; 1285#endif 1286int 1287lseek(p, uap, retval) 1288 struct proc *p; 1289 register struct lseek_args /* { 1290 syscallarg(int) fd; 1291 syscallarg(int) pad; 1292 syscallarg(off_t) offset; 1293 syscallarg(int) whence; 1294 } */ *uap; 1295 register_t *retval; /* XXX */ 1296{ 1297 struct ucred *cred = p->p_ucred; 1298 register struct filedesc *fdp = p->p_fd; 1299 register struct file *fp; 1300 struct vattr vattr; 1301 int error; 1302 1303 if ((u_int)SCARG(uap, fd) >= fdp->fd_nfiles || 1304 (fp = fdp->fd_ofiles[SCARG(uap, fd)]) == NULL) 1305 return (EBADF); 1306 if (fp->f_type != DTYPE_VNODE) 1307 return (ESPIPE); 1308 switch (SCARG(uap, whence)) { 1309 case L_INCR: 1310 fp->f_offset += SCARG(uap, offset); 1311 break; 1312 case L_XTND: 1313 error=VOP_GETATTR((struct vnode *)fp->f_data, &vattr, cred, p); 1314 if (error) 1315 return (error); 1316 fp->f_offset = SCARG(uap, offset) + vattr.va_size; 1317 break; 1318 case L_SET: 1319 fp->f_offset = SCARG(uap, offset); 1320 break; 1321 default: 1322 return (EINVAL); 1323 } 1324 *(off_t *)retval = fp->f_offset; 1325 return (0); 1326} 1327 1328#if defined(COMPAT_43) || defined(COMPAT_SUNOS) 1329/* 1330 * Reposition read/write file offset. 1331 */ 1332#ifndef _SYS_SYSPROTO_H_ 1333struct olseek_args { 1334 int fd; 1335 long offset; 1336 int whence; 1337}; 1338#endif 1339int 1340olseek(p, uap, retval) 1341 struct proc *p; 1342 register struct olseek_args /* { 1343 syscallarg(int) fd; 1344 syscallarg(long) offset; 1345 syscallarg(int) whence; 1346 } */ *uap; 1347 register_t *retval; 1348{ 1349 struct lseek_args /* { 1350 syscallarg(int) fd; 1351 syscallarg(int) pad; 1352 syscallarg(off_t) offset; 1353 syscallarg(int) whence; 1354 } */ nuap; 1355 off_t qret; 1356 int error; 1357 1358 SCARG(&nuap, fd) = SCARG(uap, fd); 1359 SCARG(&nuap, offset) = SCARG(uap, offset); 1360 SCARG(&nuap, whence) = SCARG(uap, whence); 1361 error = lseek(p, &nuap, (register_t *) &qret); 1362 *(long *)retval = qret; 1363 return (error); 1364} 1365#endif /* COMPAT_43 */ 1366 1367/* 1368 * Check access permissions. 1369 */ 1370#ifndef _SYS_SYSPROTO_H_ 1371struct access_args { 1372 char *path; 1373 int flags; 1374}; 1375#endif 1376int 1377access(p, uap, retval) 1378 struct proc *p; 1379 register struct access_args /* { 1380 syscallarg(char *) path; 1381 syscallarg(int) flags; 1382 } */ *uap; 1383 register_t *retval; 1384{ 1385 register struct ucred *cred = p->p_ucred; 1386 register struct vnode *vp; 1387 int error, flags, t_gid, t_uid; 1388 struct nameidata nd; 1389 1390 t_uid = cred->cr_uid; 1391 t_gid = cred->cr_groups[0]; 1392 cred->cr_uid = p->p_cred->p_ruid; 1393 cred->cr_groups[0] = p->p_cred->p_rgid; 1394 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, 1395 SCARG(uap, path), p); 1396 if (error = namei(&nd)) 1397 goto out1; 1398 vp = nd.ni_vp; 1399 1400 /* Flags == 0 means only check for existence. */ 1401 if (SCARG(uap, flags)) { 1402 flags = 0; 1403 if (SCARG(uap, flags) & R_OK) 1404 flags |= VREAD; 1405 if (SCARG(uap, flags) & W_OK) 1406 flags |= VWRITE; 1407 if (SCARG(uap, flags) & X_OK) 1408 flags |= VEXEC; 1409 if ((flags & VWRITE) == 0 || (error = vn_writechk(vp)) == 0) 1410 error = VOP_ACCESS(vp, flags, cred, p); 1411 } 1412 vput(vp); 1413out1: 1414 cred->cr_uid = t_uid; 1415 cred->cr_groups[0] = t_gid; 1416 return (error); 1417} 1418 1419#if defined(COMPAT_43) || defined(COMPAT_SUNOS) 1420/* 1421 * Get file status; this version follows links. 1422 */ 1423#ifndef _SYS_SYSPROTO_H_ 1424struct ostat_args { 1425 char *path; 1426 struct ostat *ub; 1427}; 1428#endif 1429/* ARGSUSED */ 1430int 1431ostat(p, uap, retval) 1432 struct proc *p; 1433 register struct ostat_args /* { 1434 syscallarg(char *) path; 1435 syscallarg(struct ostat *) ub; 1436 } */ *uap; 1437 register_t *retval; 1438{ 1439 struct stat sb; 1440 struct ostat osb; 1441 int error; 1442 struct nameidata nd; 1443 1444 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, 1445 SCARG(uap, path), p); 1446 if (error = namei(&nd)) 1447 return (error); 1448 error = vn_stat(nd.ni_vp, &sb, p); 1449 vput(nd.ni_vp); 1450 if (error) 1451 return (error); 1452 cvtstat(&sb, &osb); 1453 error = copyout((caddr_t)&osb, (caddr_t)SCARG(uap, ub), sizeof (osb)); 1454 return (error); 1455} 1456 1457/* 1458 * Get file status; this version does not follow links. 1459 */ 1460#ifndef _SYS_SYSPROTO_H_ 1461struct olstat_args { 1462 char *path; 1463 struct ostat *ub; 1464}; 1465#endif 1466/* ARGSUSED */ 1467int 1468olstat(p, uap, retval) 1469 struct proc *p; 1470 register struct olstat_args /* { 1471 syscallarg(char *) path; 1472 syscallarg(struct ostat *) ub; 1473 } */ *uap; 1474 register_t *retval; 1475{ 1476 struct vnode *vp; 1477 struct stat sb; 1478 struct ostat osb; 1479 int error; 1480 struct nameidata nd; 1481 1482 NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, 1483 SCARG(uap, path), p); 1484 if (error = namei(&nd)) 1485 return (error); 1486 vp = nd.ni_vp; 1487 error = vn_stat(vp, &sb, p); 1488 if (vp->v_type == VLNK) 1489 sb.st_mode |= S_IFLNK | ACCESSPERMS; /* 0777 */ 1490 vput(vp); 1491 if (error) 1492 return (error); 1493 cvtstat(&sb, &osb); 1494 error = copyout((caddr_t)&osb, (caddr_t)SCARG(uap, ub), sizeof (osb)); 1495 return (error); 1496} 1497 1498/* 1499 * Convert from an old to a new stat structure. 1500 */ 1501void 1502cvtstat(st, ost) 1503 struct stat *st; 1504 struct ostat *ost; 1505{ 1506 1507 ost->st_dev = st->st_dev; 1508 ost->st_ino = st->st_ino; 1509 ost->st_mode = st->st_mode; 1510 ost->st_nlink = st->st_nlink; 1511 ost->st_uid = st->st_uid; 1512 ost->st_gid = st->st_gid; 1513 ost->st_rdev = st->st_rdev; 1514 if (st->st_size < (quad_t)1 << 32) 1515 ost->st_size = st->st_size; 1516 else 1517 ost->st_size = -2; 1518 ost->st_atime = st->st_atime; 1519 ost->st_mtime = st->st_mtime; 1520 ost->st_ctime = st->st_ctime; 1521 ost->st_blksize = st->st_blksize; 1522 ost->st_blocks = st->st_blocks; 1523 ost->st_flags = st->st_flags; 1524 ost->st_gen = st->st_gen; 1525} 1526#endif /* COMPAT_43 || COMPAT_SUNOS */ 1527 1528/* 1529 * Get file status; this version follows links. 1530 */ 1531#ifndef _SYS_SYSPROTO_H_ 1532struct stat_args { 1533 char *path; 1534 struct stat *ub; 1535}; 1536#endif 1537/* ARGSUSED */ 1538int 1539stat(p, uap, retval) 1540 struct proc *p; 1541 register struct stat_args /* { 1542 syscallarg(char *) path; 1543 syscallarg(struct stat *) ub; 1544 } */ *uap; 1545 register_t *retval; 1546{ 1547 struct stat sb; 1548 int error; 1549 struct nameidata nd; 1550 1551 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, 1552 SCARG(uap, path), p); 1553 if (error = namei(&nd)) 1554 return (error); 1555 error = vn_stat(nd.ni_vp, &sb, p); 1556 vput(nd.ni_vp); 1557 if (error) 1558 return (error); 1559 error = copyout((caddr_t)&sb, (caddr_t)SCARG(uap, ub), sizeof (sb)); 1560 return (error); 1561} 1562 1563/* 1564 * Get file status; this version does not follow links. 1565 */ 1566#ifndef _SYS_SYSPROTO_H_ 1567struct lstat_args { 1568 char *path; 1569 struct stat *ub; 1570}; 1571#endif 1572/* ARGSUSED */ 1573int 1574lstat(p, uap, retval) 1575 struct proc *p; 1576 register struct lstat_args /* { 1577 syscallarg(char *) path; 1578 syscallarg(struct stat *) ub; 1579 } */ *uap; 1580 register_t *retval; 1581{ 1582 int error; 1583 struct vnode *vp; 1584 struct stat sb; 1585 struct nameidata nd; 1586 1587 NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, 1588 SCARG(uap, path), p); 1589 if (error = namei(&nd)) 1590 return (error); 1591 vp = nd.ni_vp; 1592 error = vn_stat(vp, &sb, p); 1593 if (vp->v_type == VLNK) 1594 sb.st_mode |= S_IFLNK | ACCESSPERMS; /* 0777 */ 1595 vput(vp); 1596 if (error) 1597 return (error); 1598 error = copyout((caddr_t)&sb, (caddr_t)SCARG(uap, ub), sizeof (sb)); 1599 return (error); 1600} 1601 1602/* 1603 * Get configurable pathname variables. 1604 */ 1605#ifndef _SYS_SYSPROTO_H_ 1606struct pathconf_args { 1607 char *path; 1608 int name; 1609}; 1610#endif 1611/* ARGSUSED */ 1612int 1613pathconf(p, uap, retval) 1614 struct proc *p; 1615 register struct pathconf_args /* { 1616 syscallarg(char *) path; 1617 syscallarg(int) name; 1618 } */ *uap; 1619 register_t *retval; 1620{ 1621 int error; 1622 struct nameidata nd; 1623 1624 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, 1625 SCARG(uap, path), p); 1626 if (error = namei(&nd)) 1627 return (error); 1628 error = VOP_PATHCONF(nd.ni_vp, SCARG(uap, name), retval); 1629 vput(nd.ni_vp); 1630 return (error); 1631} 1632 1633/* 1634 * Return target name of a symbolic link. 1635 */ 1636#ifndef _SYS_SYSPROTO_H_ 1637struct readlink_args { 1638 char *path; 1639 char *buf; 1640 int count; 1641}; 1642#endif 1643/* ARGSUSED */ 1644int 1645readlink(p, uap, retval) 1646 struct proc *p; 1647 register struct readlink_args /* { 1648 syscallarg(char *) path; 1649 syscallarg(char *) buf; 1650 syscallarg(int) count; 1651 } */ *uap; 1652 register_t *retval; 1653{ 1654 register struct vnode *vp; 1655 struct iovec aiov; 1656 struct uio auio; 1657 int error; 1658 struct nameidata nd; 1659 1660 NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, 1661 SCARG(uap, path), p); 1662 if (error = namei(&nd)) 1663 return (error); 1664 vp = nd.ni_vp; 1665 if (vp->v_type != VLNK) 1666 error = EINVAL; 1667 else { 1668 aiov.iov_base = SCARG(uap, buf); 1669 aiov.iov_len = SCARG(uap, count); 1670 auio.uio_iov = &aiov; 1671 auio.uio_iovcnt = 1; 1672 auio.uio_offset = 0; 1673 auio.uio_rw = UIO_READ; 1674 auio.uio_segflg = UIO_USERSPACE; 1675 auio.uio_procp = p; 1676 auio.uio_resid = SCARG(uap, count); 1677 error = VOP_READLINK(vp, &auio, p->p_ucred); 1678 } 1679 vput(vp); 1680 *retval = SCARG(uap, count) - auio.uio_resid; 1681 return (error); 1682} 1683 1684/* 1685 * Change flags of a file given a path name. 1686 */ 1687#ifndef _SYS_SYSPROTO_H_ 1688struct chflags_args { 1689 char *path; 1690 int flags; 1691}; 1692#endif 1693/* ARGSUSED */ 1694int 1695chflags(p, uap, retval) 1696 struct proc *p; 1697 register struct chflags_args /* { 1698 syscallarg(char *) path; 1699 syscallarg(int) flags; 1700 } */ *uap; 1701 register_t *retval; 1702{ 1703 register struct vnode *vp; 1704 struct vattr vattr; 1705 int error; 1706 struct nameidata nd; 1707 1708 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 1709 if (error = namei(&nd)) 1710 return (error); 1711 vp = nd.ni_vp; 1712 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 1713 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 1714 VATTR_NULL(&vattr); 1715 vattr.va_flags = SCARG(uap, flags); 1716 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 1717 vput(vp); 1718 return (error); 1719} 1720 1721/* 1722 * Change flags of a file given a file descriptor. 1723 */ 1724#ifndef _SYS_SYSPROTO_H_ 1725struct fchflags_args { 1726 int fd; 1727 int flags; 1728}; 1729#endif 1730/* ARGSUSED */ 1731int 1732fchflags(p, uap, retval) 1733 struct proc *p; 1734 register struct fchflags_args /* { 1735 syscallarg(int) fd; 1736 syscallarg(int) flags; 1737 } */ *uap; 1738 register_t *retval; 1739{ 1740 struct vattr vattr; 1741 struct vnode *vp; 1742 struct file *fp; 1743 int error; 1744 1745 if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) 1746 return (error); 1747 vp = (struct vnode *)fp->f_data; 1748 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 1749 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 1750 VATTR_NULL(&vattr); 1751 vattr.va_flags = SCARG(uap, flags); 1752 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 1753 VOP_UNLOCK(vp, 0, p); 1754 return (error); 1755} 1756 1757/* 1758 * Change mode of a file given path name. 1759 */ 1760#ifndef _SYS_SYSPROTO_H_ 1761struct chmod_args { 1762 char *path; 1763 int mode; 1764}; 1765#endif 1766/* ARGSUSED */ 1767int 1768chmod(p, uap, retval) 1769 struct proc *p; 1770 register struct chmod_args /* { 1771 syscallarg(char *) path; 1772 syscallarg(int) mode; 1773 } */ *uap; 1774 register_t *retval; 1775{ 1776 register struct vnode *vp; 1777 struct vattr vattr; 1778 int error; 1779 struct nameidata nd; 1780 1781 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 1782 if (error = namei(&nd)) 1783 return (error); 1784 vp = nd.ni_vp; 1785 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 1786 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 1787 VATTR_NULL(&vattr); 1788 vattr.va_mode = SCARG(uap, mode) & ALLPERMS; 1789 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 1790 vput(vp); 1791 return (error); 1792} 1793 1794/* 1795 * Change mode of a file given a file descriptor. 1796 */ 1797#ifndef _SYS_SYSPROTO_H_ 1798struct fchmod_args { 1799 int fd; 1800 int mode; 1801}; 1802#endif 1803/* ARGSUSED */ 1804int 1805fchmod(p, uap, retval) 1806 struct proc *p; 1807 register struct fchmod_args /* { 1808 syscallarg(int) fd; 1809 syscallarg(int) mode; 1810 } */ *uap; 1811 register_t *retval; 1812{ 1813 struct vattr vattr; 1814 struct vnode *vp; 1815 struct file *fp; 1816 int error; 1817 1818 if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) 1819 return (error); 1820 vp = (struct vnode *)fp->f_data; 1821 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 1822 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 1823 VATTR_NULL(&vattr); 1824 vattr.va_mode = SCARG(uap, mode) & ALLPERMS; 1825 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 1826 VOP_UNLOCK(vp, 0, p); 1827 return (error); 1828} 1829 1830/* 1831 * Set ownership given a path name. 1832 */ 1833#ifndef _SYS_SYSPROTO_H_ 1834struct chown_args { 1835 char *path; 1836 int uid; 1837 int gid; 1838}; 1839#endif 1840/* ARGSUSED */ 1841int 1842chown(p, uap, retval) 1843 struct proc *p; 1844 register struct chown_args /* { 1845 syscallarg(char *) path; 1846 syscallarg(int) uid; 1847 syscallarg(int) gid; 1848 } */ *uap; 1849 register_t *retval; 1850{ 1851 register struct vnode *vp; 1852 struct vattr vattr; 1853 int error; 1854 struct nameidata nd; 1855 1856 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 1857 if (error = namei(&nd)) 1858 return (error); 1859 vp = nd.ni_vp; 1860 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 1861 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 1862 VATTR_NULL(&vattr); 1863 vattr.va_uid = SCARG(uap, uid); 1864 vattr.va_gid = SCARG(uap, gid); 1865 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 1866 vput(vp); 1867 return (error); 1868} 1869 1870/* 1871 * Set ownership given a file descriptor. 1872 */ 1873#ifndef _SYS_SYSPROTO_H_ 1874struct fchown_args { 1875 int fd; 1876 int uid; 1877 int gid; 1878}; 1879#endif 1880/* ARGSUSED */ 1881int 1882fchown(p, uap, retval) 1883 struct proc *p; 1884 register struct fchown_args /* { 1885 syscallarg(int) fd; 1886 syscallarg(int) uid; 1887 syscallarg(int) gid; 1888 } */ *uap; 1889 register_t *retval; 1890{ 1891 struct vattr vattr; 1892 struct vnode *vp; 1893 struct file *fp; 1894 int error; 1895 1896 if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) 1897 return (error); 1898 vp = (struct vnode *)fp->f_data; 1899 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 1900 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 1901 VATTR_NULL(&vattr); 1902 vattr.va_uid = SCARG(uap, uid); 1903 vattr.va_gid = SCARG(uap, gid); 1904 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 1905 VOP_UNLOCK(vp, 0, p); 1906 return (error); 1907} 1908 1909/* 1910 * Set the access and modification times of a file. 1911 */ 1912#ifndef _SYS_SYSPROTO_H_ 1913struct utimes_args { 1914 char *path; 1915 struct timeval *tptr; 1916}; 1917#endif 1918/* ARGSUSED */ 1919int 1920utimes(p, uap, retval) 1921 struct proc *p; 1922 register struct utimes_args /* { 1923 syscallarg(char *) path; 1924 syscallarg(struct timeval *) tptr; 1925 } */ *uap; 1926 register_t *retval; 1927{ 1928 register struct vnode *vp; 1929 struct timeval tv[2]; 1930 struct vattr vattr; 1931 int error; 1932 struct nameidata nd; 1933 1934 VATTR_NULL(&vattr); 1935 if (SCARG(uap, tptr) == NULL) { 1936 microtime(&tv[0]); 1937 tv[1] = tv[0]; 1938 vattr.va_vaflags |= VA_UTIMES_NULL; 1939 } else if (error = copyin((caddr_t)SCARG(uap, tptr), (caddr_t)tv, 1940 sizeof (tv))) 1941 return (error); 1942 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 1943 if (error = namei(&nd)) 1944 return (error); 1945 vp = nd.ni_vp; 1946 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 1947 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 1948 vattr.va_atime.tv_sec = tv[0].tv_sec; 1949 vattr.va_atime.tv_nsec = tv[0].tv_usec * 1000; 1950 vattr.va_mtime.tv_sec = tv[1].tv_sec; 1951 vattr.va_mtime.tv_nsec = tv[1].tv_usec * 1000; 1952 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 1953 vput(vp); 1954 return (error); 1955} 1956 1957/* 1958 * Truncate a file given its path name. 1959 */ 1960#ifndef _SYS_SYSPROTO_H_ 1961struct truncate_args { 1962 char *path; 1963 int pad; 1964 off_t length; 1965}; 1966#endif 1967/* ARGSUSED */ 1968int 1969truncate(p, uap, retval) 1970 struct proc *p; 1971 register struct truncate_args /* { 1972 syscallarg(char *) path; 1973 syscallarg(int) pad; 1974 syscallarg(off_t) length; 1975 } */ *uap; 1976 register_t *retval; 1977{ 1978 register struct vnode *vp; 1979 struct vattr vattr; 1980 int error; 1981 struct nameidata nd; 1982 1983 if (uap->length < 0) 1984 return(EINVAL); 1985 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 1986 if (error = namei(&nd)) 1987 return (error); 1988 vp = nd.ni_vp; 1989 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 1990 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 1991 if (vp->v_type == VDIR) 1992 error = EISDIR; 1993 else if ((error = vn_writechk(vp)) == 0 && 1994 (error = VOP_ACCESS(vp, VWRITE, p->p_ucred, p)) == 0) { 1995 VATTR_NULL(&vattr); 1996 vattr.va_size = SCARG(uap, length); 1997 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 1998 } 1999 vput(vp); 2000 return (error); 2001} 2002 2003/* 2004 * Truncate a file given a file descriptor. 2005 */ 2006#ifndef _SYS_SYSPROTO_H_ 2007struct ftruncate_args { 2008 int fd; 2009 int pad; 2010 off_t length; 2011}; 2012#endif 2013/* ARGSUSED */ 2014int 2015ftruncate(p, uap, retval) 2016 struct proc *p; 2017 register struct ftruncate_args /* { 2018 syscallarg(int) fd; 2019 syscallarg(int) pad; 2020 syscallarg(off_t) length; 2021 } */ *uap; 2022 register_t *retval; 2023{ 2024 struct vattr vattr; 2025 struct vnode *vp; 2026 struct file *fp; 2027 int error; 2028 2029 if (uap->length < 0) 2030 return(EINVAL); 2031 if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) 2032 return (error); 2033 if ((fp->f_flag & FWRITE) == 0) 2034 return (EINVAL); 2035 vp = (struct vnode *)fp->f_data; 2036 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 2037 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 2038 if (vp->v_type == VDIR) 2039 error = EISDIR; 2040 else if ((error = vn_writechk(vp)) == 0) { 2041 VATTR_NULL(&vattr); 2042 vattr.va_size = SCARG(uap, length); 2043 error = VOP_SETATTR(vp, &vattr, fp->f_cred, p); 2044 } 2045 VOP_UNLOCK(vp, 0, p); 2046 return (error); 2047} 2048 2049#if defined(COMPAT_43) || defined(COMPAT_SUNOS) 2050/* 2051 * Truncate a file given its path name. 2052 */ 2053#ifndef _SYS_SYSPROTO_H_ 2054struct otruncate_args { 2055 char *path; 2056 long length; 2057}; 2058#endif 2059/* ARGSUSED */ 2060int 2061otruncate(p, uap, retval) 2062 struct proc *p; 2063 register struct otruncate_args /* { 2064 syscallarg(char *) path; 2065 syscallarg(long) length; 2066 } */ *uap; 2067 register_t *retval; 2068{ 2069 struct truncate_args /* { 2070 syscallarg(char *) path; 2071 syscallarg(int) pad; 2072 syscallarg(off_t) length; 2073 } */ nuap; 2074 2075 SCARG(&nuap, path) = SCARG(uap, path); 2076 SCARG(&nuap, length) = SCARG(uap, length); 2077 return (truncate(p, &nuap, retval)); 2078} 2079 2080/* 2081 * Truncate a file given a file descriptor. 2082 */ 2083#ifndef _SYS_SYSPROTO_H_ 2084struct oftruncate_args { 2085 int fd; 2086 long length; 2087}; 2088#endif 2089/* ARGSUSED */ 2090int 2091oftruncate(p, uap, retval) 2092 struct proc *p; 2093 register struct oftruncate_args /* { 2094 syscallarg(int) fd; 2095 syscallarg(long) length; 2096 } */ *uap; 2097 register_t *retval; 2098{ 2099 struct ftruncate_args /* { 2100 syscallarg(int) fd; 2101 syscallarg(int) pad; 2102 syscallarg(off_t) length; 2103 } */ nuap; 2104 2105 SCARG(&nuap, fd) = SCARG(uap, fd); 2106 SCARG(&nuap, length) = SCARG(uap, length); 2107 return (ftruncate(p, &nuap, retval)); 2108} 2109#endif /* COMPAT_43 || COMPAT_SUNOS */ 2110 2111/* 2112 * Sync an open file. 2113 */ 2114#ifndef _SYS_SYSPROTO_H_ 2115struct fsync_args { 2116 int fd; 2117}; 2118#endif 2119/* ARGSUSED */ 2120int 2121fsync(p, uap, retval) 2122 struct proc *p; 2123 struct fsync_args /* { 2124 syscallarg(int) fd; 2125 } */ *uap; 2126 register_t *retval; 2127{ 2128 register struct vnode *vp; 2129 struct file *fp; 2130 int error; 2131 2132 if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) 2133 return (error); 2134 vp = (struct vnode *)fp->f_data; 2135 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 2136 if (vp->v_object) { 2137 vm_object_page_clean(vp->v_object, 0, 0 ,0, FALSE); 2138 } 2139 error = VOP_FSYNC(vp, fp->f_cred, 2140 (vp->v_mount && (vp->v_mount->mnt_flag & MNT_ASYNC)) ? 2141 MNT_NOWAIT : MNT_WAIT, p); 2142 VOP_UNLOCK(vp, 0, p); 2143 return (error); 2144} 2145 2146/* 2147 * Rename files. Source and destination must either both be directories, 2148 * or both not be directories. If target is a directory, it must be empty. 2149 */ 2150#ifndef _SYS_SYSPROTO_H_ 2151struct rename_args { 2152 char *from; 2153 char *to; 2154}; 2155#endif 2156/* ARGSUSED */ 2157int 2158rename(p, uap, retval) 2159 struct proc *p; 2160 register struct rename_args /* { 2161 syscallarg(char *) from; 2162 syscallarg(char *) to; 2163 } */ *uap; 2164 register_t *retval; 2165{ 2166 register struct vnode *tvp, *fvp, *tdvp; 2167 struct nameidata fromnd, tond; 2168 int error; 2169 2170 NDINIT(&fromnd, DELETE, WANTPARENT | SAVESTART, UIO_USERSPACE, 2171 SCARG(uap, from), p); 2172 if (error = namei(&fromnd)) 2173 return (error); 2174 fvp = fromnd.ni_vp; 2175 NDINIT(&tond, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART, 2176 UIO_USERSPACE, SCARG(uap, to), p); 2177 if (fromnd.ni_vp->v_type == VDIR) 2178 tond.ni_cnd.cn_flags |= WILLBEDIR; 2179 if (error = namei(&tond)) { 2180 /* Translate error code for rename("dir1", "dir2/."). */ 2181 if (error == EISDIR && fvp->v_type == VDIR) 2182 error = EINVAL; 2183 VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 2184 vrele(fromnd.ni_dvp); 2185 vrele(fvp); 2186 goto out1; 2187 } 2188 tdvp = tond.ni_dvp; 2189 tvp = tond.ni_vp; 2190 if (tvp != NULL) { 2191 if (fvp->v_type == VDIR && tvp->v_type != VDIR) { 2192 error = ENOTDIR; 2193 goto out; 2194 } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) { 2195 error = EISDIR; 2196 goto out; 2197 } 2198 } 2199 if (fvp == tdvp) 2200 error = EINVAL; 2201 /* 2202 * If source is the same as the destination (that is the 2203 * same inode number with the same name in the same directory), 2204 * then there is nothing to do. 2205 */ 2206 if (fvp == tvp && fromnd.ni_dvp == tdvp && 2207 fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen && 2208 !bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr, 2209 fromnd.ni_cnd.cn_namelen)) 2210 error = -1; 2211out: 2212 if (!error) { 2213 VOP_LEASE(tdvp, p, p->p_ucred, LEASE_WRITE); 2214 if (fromnd.ni_dvp != tdvp) 2215 VOP_LEASE(fromnd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 2216 if (tvp) { 2217 VOP_LEASE(tvp, p, p->p_ucred, LEASE_WRITE); 2218 (void) vnode_pager_uncache(tvp, p); 2219 } 2220 error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd, 2221 tond.ni_dvp, tond.ni_vp, &tond.ni_cnd); 2222 } else { 2223 VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd); 2224 if (tdvp == tvp) 2225 vrele(tdvp); 2226 else 2227 vput(tdvp); 2228 if (tvp) 2229 vput(tvp); 2230 VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 2231 vrele(fromnd.ni_dvp); 2232 vrele(fvp); 2233 } 2234 vrele(tond.ni_startdir); 2235 FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI); 2236out1: 2237 if (fromnd.ni_startdir) 2238 vrele(fromnd.ni_startdir); 2239 FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI); 2240 if (error == -1) 2241 return (0); 2242 return (error); 2243} 2244 2245/* 2246 * Make a directory file. 2247 */ 2248#ifndef _SYS_SYSPROTO_H_ 2249struct mkdir_args { 2250 char *path; 2251 int mode; 2252}; 2253#endif 2254/* ARGSUSED */ 2255int 2256mkdir(p, uap, retval) 2257 struct proc *p; 2258 register struct mkdir_args /* { 2259 syscallarg(char *) path; 2260 syscallarg(int) mode; 2261 } */ *uap; 2262 register_t *retval; 2263{ 2264 register struct vnode *vp; 2265 struct vattr vattr; 2266 int error; 2267 struct nameidata nd; 2268 2269 NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p); 2270 nd.ni_cnd.cn_flags |= WILLBEDIR; 2271 if (error = namei(&nd)) 2272 return (error); 2273 vp = nd.ni_vp; 2274 if (vp != NULL) { 2275 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 2276 if (nd.ni_dvp == vp) 2277 vrele(nd.ni_dvp); 2278 else 2279 vput(nd.ni_dvp); 2280 vrele(vp); 2281 return (EEXIST); 2282 } 2283 VATTR_NULL(&vattr); 2284 vattr.va_type = VDIR; 2285 vattr.va_mode = (SCARG(uap, mode) & ACCESSPERMS) &~ p->p_fd->fd_cmask; 2286 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 2287 error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr); 2288 if (!error) 2289 vput(nd.ni_vp); 2290 return (error); 2291} 2292 2293/* 2294 * Remove a directory file. 2295 */ 2296#ifndef _SYS_SYSPROTO_H_ 2297struct rmdir_args { 2298 char *path; 2299}; 2300#endif 2301/* ARGSUSED */ 2302int 2303rmdir(p, uap, retval) 2304 struct proc *p; 2305 struct rmdir_args /* { 2306 syscallarg(char *) path; 2307 } */ *uap; 2308 register_t *retval; 2309{ 2310 register struct vnode *vp; 2311 int error; 2312 struct nameidata nd; 2313 2314 NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE, 2315 SCARG(uap, path), p); 2316 if (error = namei(&nd)) 2317 return (error); 2318 vp = nd.ni_vp; 2319 if (vp->v_type != VDIR) { 2320 error = ENOTDIR; 2321 goto out; 2322 } 2323 /* 2324 * No rmdir "." please. 2325 */ 2326 if (nd.ni_dvp == vp) { 2327 error = EINVAL; 2328 goto out; 2329 } 2330 /* 2331 * The root of a mounted filesystem cannot be deleted. 2332 */ 2333 if (vp->v_flag & VROOT) 2334 error = EBUSY; 2335out: 2336 if (!error) { 2337 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 2338 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 2339 error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); 2340 } else { 2341 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 2342 if (nd.ni_dvp == vp) 2343 vrele(nd.ni_dvp); 2344 else 2345 vput(nd.ni_dvp); 2346 vput(vp); 2347 } 2348 return (error); 2349} 2350 2351#ifdef COMPAT_43 2352/* 2353 * Read a block of directory entries in a file system independent format. 2354 */ 2355#ifndef _SYS_SYSPROTO_H_ 2356struct ogetdirentries_args { 2357 int fd; 2358 char *buf; 2359 u_int count; 2360 long *basep; 2361}; 2362#endif 2363int 2364ogetdirentries(p, uap, retval) 2365 struct proc *p; 2366 register struct ogetdirentries_args /* { 2367 syscallarg(int) fd; 2368 syscallarg(char *) buf; 2369 syscallarg(u_int) count; 2370 syscallarg(long *) basep; 2371 } */ *uap; 2372 register_t *retval; 2373{ 2374 register struct vnode *vp; 2375 struct file *fp; 2376 struct uio auio, kuio; 2377 struct iovec aiov, kiov; 2378 struct dirent *dp, *edp; 2379 caddr_t dirbuf; 2380 int error, eofflag, readcnt; 2381 long loff; 2382 2383 if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) 2384 return (error); 2385 if ((fp->f_flag & FREAD) == 0) 2386 return (EBADF); 2387 vp = (struct vnode *)fp->f_data; 2388unionread: 2389 if (vp->v_type != VDIR) 2390 return (EINVAL); 2391 aiov.iov_base = SCARG(uap, buf); 2392 aiov.iov_len = SCARG(uap, count); 2393 auio.uio_iov = &aiov; 2394 auio.uio_iovcnt = 1; 2395 auio.uio_rw = UIO_READ; 2396 auio.uio_segflg = UIO_USERSPACE; 2397 auio.uio_procp = p; 2398 auio.uio_resid = SCARG(uap, count); 2399 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 2400 loff = auio.uio_offset = fp->f_offset; 2401# if (BYTE_ORDER != LITTLE_ENDIAN) 2402 if (vp->v_mount->mnt_maxsymlinklen <= 0) { 2403 error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, 2404 NULL, NULL); 2405 fp->f_offset = auio.uio_offset; 2406 } else 2407# endif 2408 { 2409 kuio = auio; 2410 kuio.uio_iov = &kiov; 2411 kuio.uio_segflg = UIO_SYSSPACE; 2412 kiov.iov_len = SCARG(uap, count); 2413 MALLOC(dirbuf, caddr_t, SCARG(uap, count), M_TEMP, M_WAITOK); 2414 kiov.iov_base = dirbuf; 2415 error = VOP_READDIR(vp, &kuio, fp->f_cred, &eofflag, 2416 NULL, NULL); 2417 fp->f_offset = kuio.uio_offset; 2418 if (error == 0) { 2419 readcnt = SCARG(uap, count) - kuio.uio_resid; 2420 edp = (struct dirent *)&dirbuf[readcnt]; 2421 for (dp = (struct dirent *)dirbuf; dp < edp; ) { 2422# if (BYTE_ORDER == LITTLE_ENDIAN) 2423 /* 2424 * The expected low byte of 2425 * dp->d_namlen is our dp->d_type. 2426 * The high MBZ byte of dp->d_namlen 2427 * is our dp->d_namlen. 2428 */ 2429 dp->d_type = dp->d_namlen; 2430 dp->d_namlen = 0; 2431# else 2432 /* 2433 * The dp->d_type is the high byte 2434 * of the expected dp->d_namlen, 2435 * so must be zero'ed. 2436 */ 2437 dp->d_type = 0; 2438# endif 2439 if (dp->d_reclen > 0) { 2440 dp = (struct dirent *) 2441 ((char *)dp + dp->d_reclen); 2442 } else { 2443 error = EIO; 2444 break; 2445 } 2446 } 2447 if (dp >= edp) 2448 error = uiomove(dirbuf, readcnt, &auio); 2449 } 2450 FREE(dirbuf, M_TEMP); 2451 } 2452 VOP_UNLOCK(vp, 0, p); 2453 if (error) 2454 return (error); 2455 2456#ifdef UNION 2457{ 2458 if ((SCARG(uap, count) == auio.uio_resid) && 2459 (vp->v_op == union_vnodeop_p)) { 2460 struct vnode *lvp; 2461 2462 lvp = union_dircache(vp, p); 2463 if (lvp != NULLVP) { 2464 struct vattr va; 2465 2466 /* 2467 * If the directory is opaque, 2468 * then don't show lower entries 2469 */ 2470 error = VOP_GETATTR(vp, &va, fp->f_cred, p); 2471 if (va.va_flags & OPAQUE) { 2472 vput(lvp); 2473 lvp = NULL; 2474 } 2475 } 2476 2477 if (lvp != NULLVP) { 2478 error = VOP_OPEN(lvp, FREAD, fp->f_cred, p); 2479 if (error) { 2480 vput(lvp); 2481 return (error); 2482 } 2483 VOP_UNLOCK(lvp, 0, p); 2484 fp->f_data = (caddr_t) lvp; 2485 fp->f_offset = 0; 2486 error = vn_close(vp, FREAD, fp->f_cred, p); 2487 if (error) 2488 return (error); 2489 vp = lvp; 2490 goto unionread; 2491 } 2492 } 2493} 2494#endif /* UNION */ 2495 2496 if ((SCARG(uap, count) == auio.uio_resid) && 2497 (vp->v_flag & VROOT) && 2498 (vp->v_mount->mnt_flag & MNT_UNION)) { 2499 struct vnode *tvp = vp; 2500 vp = vp->v_mount->mnt_vnodecovered; 2501 VREF(vp); 2502 fp->f_data = (caddr_t) vp; 2503 fp->f_offset = 0; 2504 vrele(tvp); 2505 goto unionread; 2506 } 2507 error = copyout((caddr_t)&loff, (caddr_t)SCARG(uap, basep), 2508 sizeof(long)); 2509 *retval = SCARG(uap, count) - auio.uio_resid; 2510 return (error); 2511} 2512#endif /* COMPAT_43 */ 2513 2514/* 2515 * Read a block of directory entries in a file system independent format. 2516 */ 2517#ifndef _SYS_SYSPROTO_H_ 2518struct getdirentries_args { 2519 int fd; 2520 char *buf; 2521 u_int count; 2522 long *basep; 2523}; 2524#endif 2525int 2526getdirentries(p, uap, retval) 2527 struct proc *p; 2528 register struct getdirentries_args /* { 2529 syscallarg(int) fd; 2530 syscallarg(char *) buf; 2531 syscallarg(u_int) count; 2532 syscallarg(long *) basep; 2533 } */ *uap; 2534 register_t *retval; 2535{ 2536 register struct vnode *vp; 2537 struct file *fp; 2538 struct uio auio; 2539 struct iovec aiov; 2540 long loff; 2541 int error, eofflag; 2542 2543 if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) 2544 return (error); 2545 if ((fp->f_flag & FREAD) == 0) 2546 return (EBADF); 2547 vp = (struct vnode *)fp->f_data; 2548unionread: 2549 if (vp->v_type != VDIR) 2550 return (EINVAL); 2551 aiov.iov_base = SCARG(uap, buf); 2552 aiov.iov_len = SCARG(uap, count); 2553 auio.uio_iov = &aiov; 2554 auio.uio_iovcnt = 1; 2555 auio.uio_rw = UIO_READ; 2556 auio.uio_segflg = UIO_USERSPACE; 2557 auio.uio_procp = p; 2558 auio.uio_resid = SCARG(uap, count); 2559 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 2560 loff = auio.uio_offset = fp->f_offset; 2561 error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, NULL, NULL); 2562 fp->f_offset = auio.uio_offset; 2563 VOP_UNLOCK(vp, 0, p); 2564 if (error) 2565 return (error); 2566 2567#ifdef UNION 2568{ 2569 if ((SCARG(uap, count) == auio.uio_resid) && 2570 (vp->v_op == union_vnodeop_p)) { 2571 struct vnode *lvp; 2572 2573 lvp = union_dircache(vp, p); 2574 if (lvp != NULLVP) { 2575 struct vattr va; 2576 2577 /* 2578 * If the directory is opaque, 2579 * then don't show lower entries 2580 */ 2581 error = VOP_GETATTR(vp, &va, fp->f_cred, p); 2582 if (va.va_flags & OPAQUE) { 2583 vput(lvp); 2584 lvp = NULL; 2585 } 2586 } 2587 2588 if (lvp != NULLVP) { 2589 error = VOP_OPEN(lvp, FREAD, fp->f_cred, p); 2590 if (error) { 2591 vput(lvp); 2592 return (error); 2593 } 2594 VOP_UNLOCK(lvp, 0, p); 2595 fp->f_data = (caddr_t) lvp; 2596 fp->f_offset = 0; 2597 error = vn_close(vp, FREAD, fp->f_cred, p); 2598 if (error) 2599 return (error); 2600 vp = lvp; 2601 goto unionread; 2602 } 2603 } 2604} 2605#endif /* UNION */ 2606 2607 if ((SCARG(uap, count) == auio.uio_resid) && 2608 (vp->v_flag & VROOT) && 2609 (vp->v_mount->mnt_flag & MNT_UNION)) { 2610 struct vnode *tvp = vp; 2611 vp = vp->v_mount->mnt_vnodecovered; 2612 VREF(vp); 2613 fp->f_data = (caddr_t) vp; 2614 fp->f_offset = 0; 2615 vrele(tvp); 2616 goto unionread; 2617 } 2618 error = copyout((caddr_t)&loff, (caddr_t)SCARG(uap, basep), 2619 sizeof(long)); 2620 *retval = SCARG(uap, count) - auio.uio_resid; 2621 return (error); 2622} 2623 2624/* 2625 * Set the mode mask for creation of filesystem nodes. 2626 */ 2627#ifndef _SYS_SYSPROTO_H_ 2628struct umask_args { 2629 int newmask; 2630}; 2631#endif 2632int 2633umask(p, uap, retval) 2634 struct proc *p; 2635 struct umask_args /* { 2636 syscallarg(int) newmask; 2637 } */ *uap; 2638 int *retval; /* XXX */ 2639{ 2640 register struct filedesc *fdp; 2641 2642 fdp = p->p_fd; 2643 *retval = fdp->fd_cmask; 2644 fdp->fd_cmask = SCARG(uap, newmask) & ALLPERMS; 2645 return (0); 2646} 2647 2648/* 2649 * Void all references to file by ripping underlying filesystem 2650 * away from vnode. 2651 */ 2652#ifndef _SYS_SYSPROTO_H_ 2653struct revoke_args { 2654 char *path; 2655}; 2656#endif 2657/* ARGSUSED */ 2658int 2659revoke(p, uap, retval) 2660 struct proc *p; 2661 register struct revoke_args /* { 2662 syscallarg(char *) path; 2663 } */ *uap; 2664 register_t *retval; 2665{ 2666 register struct vnode *vp; 2667 struct vattr vattr; 2668 int error; 2669 struct nameidata nd; 2670 2671 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 2672 if (error = namei(&nd)) 2673 return (error); 2674 vp = nd.ni_vp; 2675 if (error = VOP_GETATTR(vp, &vattr, p->p_ucred, p)) 2676 goto out; 2677 if (p->p_ucred->cr_uid != vattr.va_uid && 2678 (error = suser(p->p_ucred, &p->p_acflag))) 2679 goto out; 2680 if (vp->v_usecount > 1 || (vp->v_flag & VALIASED)) 2681 VOP_REVOKE(vp, REVOKEALL); 2682out: 2683 vrele(vp); 2684 return (error); 2685} 2686 2687/* 2688 * Convert a user file descriptor to a kernel file entry. 2689 */ 2690int 2691getvnode(fdp, fd, fpp) 2692 struct filedesc *fdp; 2693 int fd; 2694 struct file **fpp; 2695{ 2696 struct file *fp; 2697 2698 if ((u_int)fd >= fdp->fd_nfiles || 2699 (fp = fdp->fd_ofiles[fd]) == NULL) 2700 return (EBADF); 2701 if (fp->f_type != DTYPE_VNODE && fp->f_type != DTYPE_FIFO) 2702 return (EINVAL); 2703 *fpp = fp; 2704 return (0); 2705} 2706