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