1*2889c8c8Skrw/* $OpenBSD: t9.2,v 1.4 2024/07/10 09:24:03 krw Exp $ */ 2bad3ecd0Sotto/* $NetBSD: vfs_syscalls.c,v 1.71 1996/04/23 10:29:02 mycroft Exp $ */ 3bad3ecd0Sotto 4bad3ecd0Sotto/* 5bad3ecd0Sotto * Copyright (c) 1989, 1993 6bad3ecd0Sotto * The Regents of the University of California. All rights reserved. 7bad3ecd0Sotto * (c) UNIX System Laboratories, Inc. 8bad3ecd0Sotto * All or some portions of this file are derived from material licensed 9bad3ecd0Sotto * to the University of California by American Telephone and Telegraph 10bad3ecd0Sotto * Co. or Unix System Laboratories, Inc. and are reproduced herein with 11bad3ecd0Sotto * the permission of UNIX System Laboratories, Inc. 12bad3ecd0Sotto * 13bad3ecd0Sotto * Redistribution and use in source and binary forms, with or without 14bad3ecd0Sotto * modification, are permitted provided that the following conditions 15bad3ecd0Sotto * are met: 16bad3ecd0Sotto * 1. Redistributions of source code must retain the above copyright 17bad3ecd0Sotto * notice, this list of conditions and the following disclaimer. 18bad3ecd0Sotto * 2. Redistributions in binary form must reproduce the above copyright 19bad3ecd0Sotto * notice, this list of conditions and the following disclaimer in the 20bad3ecd0Sotto * documentation and/or other materials provided with the distribution. 21bad3ecd0Sotto * 3. Neither the name of the University nor the names of its contributors 22bad3ecd0Sotto * may be used to endorse or promote products derived from this software 23bad3ecd0Sotto * without specific prior written permission. 24bad3ecd0Sotto * 25bad3ecd0Sotto * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 26bad3ecd0Sotto * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27bad3ecd0Sotto * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28bad3ecd0Sotto * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 29bad3ecd0Sotto * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30bad3ecd0Sotto * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 31bad3ecd0Sotto * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32bad3ecd0Sotto * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33bad3ecd0Sotto * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 34bad3ecd0Sotto * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35bad3ecd0Sotto * SUCH DAMAGE. 36bad3ecd0Sotto * 37bad3ecd0Sotto * @(#)vfs_syscalls.c 8.28 (Berkeley) 12/10/94 38bad3ecd0Sotto */ 39bad3ecd0Sotto 40bad3ecd0Sotto#include <sys/param.h> 41bad3ecd0Sotto#include <sys/systm.h> 42bad3ecd0Sotto#include <sys/namei.h> 43bad3ecd0Sotto#include <sys/filedesc.h> 44bad3ecd0Sotto#include <sys/kernel.h> 45bad3ecd0Sotto#include <sys/file.h> 46bad3ecd0Sotto#include <sys/stat.h> 47bad3ecd0Sotto#include <sys/vnode.h> 48bad3ecd0Sotto#include <sys/mount.h> 49bad3ecd0Sotto#include <sys/proc.h> 50bad3ecd0Sotto#include <sys/uio.h> 51bad3ecd0Sotto#include <sys/malloc.h> 52bad3ecd0Sotto#include <sys/dirent.h> 53bad3ecd0Sotto#include <sys/extattr.h> 54bad3ecd0Sotto 55bad3ecd0Sotto#include <sys/syscallargs.h> 56bad3ecd0Sotto 57bad3ecd0Sotto#include <uvm/uvm_extern.h> 58bad3ecd0Sotto#include <sys/sysctl.h> 59bad3ecd0Sotto 60bad3ecd0Sottoextern int suid_clear; 61bad3ecd0Sottoint usermount = 0; /* sysctl: by default, users may not mount */ 62bad3ecd0Sotto 63bad3ecd0Sottostatic int change_dir(struct nameidata *, struct proc *); 64bad3ecd0Sotto 65bad3ecd0Sottovoid checkdirs(struct vnode *); 66bad3ecd0Sotto 67bad3ecd0Sotto/* 68bad3ecd0Sotto * Redirection info so we don't have to include the union fs routines in 69bad3ecd0Sotto * the kernel directly. This way, we can build unionfs as an LKM. The 70bad3ecd0Sotto * pointer gets filled in later, when we modload the LKM, or when the 71bad3ecd0Sotto * compiled-in unionfs code gets initialized. For now, we just set 72bad3ecd0Sotto * it to a stub routine. 73bad3ecd0Sotto */ 74bad3ecd0Sotto 75bad3ecd0Sottoint (*union_check_p)(struct proc *, struct vnode **, 76bad3ecd0Sotto struct file *, struct uio, int *) = NULL; 77bad3ecd0Sotto 78bad3ecd0Sotto/* 79bad3ecd0Sotto * Virtual File System System Calls 80bad3ecd0Sotto */ 81bad3ecd0Sotto 82bad3ecd0Sotto/* 83bad3ecd0Sotto * Mount a file system. 84bad3ecd0Sotto */ 85bad3ecd0Sotto/* ARGSUSED */ 86bad3ecd0Sottoint 87bad3ecd0Sottosys_mount(p, v, retval) 88bad3ecd0Sotto struct proc *p; 89bad3ecd0Sotto void *v; 90bad3ecd0Sotto register_t *retval; 91bad3ecd0Sotto{ 92bad3ecd0Sotto register struct sys_mount_args /* { 93bad3ecd0Sotto syscallarg(char *) type; 94bad3ecd0Sotto syscallarg(char *) path; 95bad3ecd0Sotto syscallarg(int) flags; 96bad3ecd0Sotto syscallarg(void *) data; 97bad3ecd0Sotto } */ *uap = v; 98bad3ecd0Sotto register struct vnode *vp; 99bad3ecd0Sotto register struct mount *mp; 100bad3ecd0Sotto int error, flag = 0; 101bad3ecd0Sotto#ifdef COMPAT_43 102bad3ecd0Sotto u_long fstypenum = 0; 103bad3ecd0Sotto#endif 104bad3ecd0Sotto char fstypename[MFSNAMELEN]; 105bad3ecd0Sotto char fspath[MNAMELEN]; 106bad3ecd0Sotto struct vattr va; 107bad3ecd0Sotto struct nameidata nd; 108bad3ecd0Sotto struct vfsconf *vfsp; 109bad3ecd0Sotto struct timeval tv; 110bad3ecd0Sotto 111bad3ecd0Sotto if (usermount == 0 && (error = suser(p->p_ucred, &p->p_acflag))) 112bad3ecd0Sotto return (error); 113bad3ecd0Sotto 114bad3ecd0Sotto /* 115bad3ecd0Sotto * Mount points must fit in MNAMELEN, not MAXPATHLEN. 116bad3ecd0Sotto */ 117bad3ecd0Sotto error = copyinstr(SCARG(uap, path), fspath, MNAMELEN, NULL); 118bad3ecd0Sotto if (error) 119bad3ecd0Sotto return(error); 120bad3ecd0Sotto 121bad3ecd0Sotto /* 122bad3ecd0Sotto * Get vnode to be covered 123bad3ecd0Sotto */ 124bad3ecd0Sotto NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, fspath, p); 125bad3ecd0Sotto if ((error = namei(&nd)) != 0) 126bad3ecd0Sotto return (error); 127bad3ecd0Sotto vp = nd.ni_vp; 128bad3ecd0Sotto if (SCARG(uap, flags) & MNT_UPDATE) { 129bad3ecd0Sotto if ((vp->v_flag & VROOT) == 0) { 130bad3ecd0Sotto vput(vp); 131bad3ecd0Sotto return (EINVAL); 132bad3ecd0Sotto } 133bad3ecd0Sotto mp = vp->v_mount; 134bad3ecd0Sotto flag = mp->mnt_flag; 135bad3ecd0Sotto /* 136bad3ecd0Sotto * We only allow the filesystem to be reloaded if it 137bad3ecd0Sotto * is currently mounted read-only. 138bad3ecd0Sotto */ 139bad3ecd0Sotto if ((SCARG(uap, flags) & MNT_RELOAD) && 140bad3ecd0Sotto ((mp->mnt_flag & MNT_RDONLY) == 0)) { 141bad3ecd0Sotto vput(vp); 142bad3ecd0Sotto return (EOPNOTSUPP); /* Needs translation */ 143bad3ecd0Sotto } 144bad3ecd0Sotto mp->mnt_flag |= 145bad3ecd0Sotto SCARG(uap, flags) & (MNT_RELOAD | MNT_UPDATE); 146bad3ecd0Sotto /* 147bad3ecd0Sotto * Only root, or the user that did the original mount is 148bad3ecd0Sotto * permitted to update it. 149bad3ecd0Sotto */ 150bad3ecd0Sotto if (mp->mnt_stat.f_owner != p->p_ucred->cr_uid && 151bad3ecd0Sotto (error = suser(p->p_ucred, &p->p_acflag))) { 152bad3ecd0Sotto vput(vp); 153bad3ecd0Sotto return (error); 154bad3ecd0Sotto } 155bad3ecd0Sotto /* 156bad3ecd0Sotto * Do not allow NFS export by non-root users. Silently 157bad3ecd0Sotto * enforce MNT_NOSUID and MNT_NODEV for non-root users. 158bad3ecd0Sotto */ 159bad3ecd0Sotto if (p->p_ucred->cr_uid != 0) { 160bad3ecd0Sotto if (SCARG(uap, flags) & MNT_EXPORTED) { 161bad3ecd0Sotto vput(vp); 162bad3ecd0Sotto return (EPERM); 163bad3ecd0Sotto } 164bad3ecd0Sotto SCARG(uap, flags) |= MNT_NOSUID | MNT_NODEV; 165bad3ecd0Sotto } 166bad3ecd0Sotto if ((error = vfs_busy(mp, LK_NOWAIT, 0, p)) != 0) { 167bad3ecd0Sotto vput(vp); 168bad3ecd0Sotto return (error); 169bad3ecd0Sotto } 170bad3ecd0Sotto VOP_UNLOCK(vp, 0, p); 171bad3ecd0Sotto goto update; 172bad3ecd0Sotto } 173bad3ecd0Sotto /* 174bad3ecd0Sotto * If the user is not root, ensure that they own the directory 175bad3ecd0Sotto * onto which we are attempting to mount. 176bad3ecd0Sotto */ 177bad3ecd0Sotto if ((error = VOP_GETATTR(vp, &va, p->p_ucred, p)) || 178bad3ecd0Sotto (va.va_uid != p->p_ucred->cr_uid && 179bad3ecd0Sotto (error = suser(p->p_ucred, &p->p_acflag)))) { 180bad3ecd0Sotto vput(vp); 181bad3ecd0Sotto return (error); 182bad3ecd0Sotto } 183bad3ecd0Sotto /* 184bad3ecd0Sotto * Do not allow NFS export by non-root users. Silently 185bad3ecd0Sotto * enforce MNT_NOSUID and MNT_NODEV for non-root users. 186bad3ecd0Sotto */ 187bad3ecd0Sotto if (p->p_ucred->cr_uid != 0) { 188bad3ecd0Sotto if (SCARG(uap, flags) & MNT_EXPORTED) { 189bad3ecd0Sotto vput(vp); 190bad3ecd0Sotto return (EPERM); 191bad3ecd0Sotto } 192bad3ecd0Sotto SCARG(uap, flags) |= MNT_NOSUID | MNT_NODEV; 193bad3ecd0Sotto } 194bad3ecd0Sotto if ((error = vinvalbuf(vp, V_SAVE, p->p_ucred, p, 0, 0)) != 0) 195bad3ecd0Sotto return (error); 196bad3ecd0Sotto if (vp->v_type != VDIR) { 197bad3ecd0Sotto vput(vp); 198bad3ecd0Sotto return (ENOTDIR); 199bad3ecd0Sotto } 200bad3ecd0Sotto error = copyinstr(SCARG(uap, type), fstypename, MFSNAMELEN, NULL); 201bad3ecd0Sotto if (error) { 202bad3ecd0Sotto#ifdef COMPAT_43 203bad3ecd0Sotto /* 204bad3ecd0Sotto * Historically filesystem types were identified by number. 205bad3ecd0Sotto * If we get an integer for the filesystem type instead of a 206bad3ecd0Sotto * string, we check to see if it matches one of the historic 207bad3ecd0Sotto * filesystem types. 208bad3ecd0Sotto */ 209bad3ecd0Sotto fstypenum = (u_long)SCARG(uap, type); 210bad3ecd0Sotto 211bad3ecd0Sotto for (vfsp = vfsconf; vfsp; vfsp = vfsp->vfc_next) 212bad3ecd0Sotto if (vfsp->vfc_typenum == fstypenum) 213bad3ecd0Sotto break; 214bad3ecd0Sotto if (vfsp == NULL) { 215bad3ecd0Sotto vput(vp); 216bad3ecd0Sotto return (ENODEV); 217bad3ecd0Sotto } 218bad3ecd0Sotto strncpy(fstypename, vfsp->vfc_name, MFSNAMELEN); 219bad3ecd0Sotto 220bad3ecd0Sotto#else 221bad3ecd0Sotto vput(vp); 222bad3ecd0Sotto return (error); 223bad3ecd0Sotto#endif 224bad3ecd0Sotto } 225bad3ecd0Sotto for (vfsp = vfsconf; vfsp; vfsp = vfsp->vfc_next) { 226bad3ecd0Sotto if (!strcmp(vfsp->vfc_name, fstypename)) 227bad3ecd0Sotto break; 228bad3ecd0Sotto } 229bad3ecd0Sotto 230bad3ecd0Sotto if (vfsp == NULL) { 231bad3ecd0Sotto vput(vp); 232bad3ecd0Sotto return (EOPNOTSUPP); 233bad3ecd0Sotto } 234bad3ecd0Sotto 235bad3ecd0Sotto if (vp->v_mountedhere != NULL) { 236bad3ecd0Sotto vput(vp); 237bad3ecd0Sotto return (EBUSY); 238bad3ecd0Sotto } 239bad3ecd0Sotto 240bad3ecd0Sotto /* 241bad3ecd0Sotto * Allocate and initialize the file system. 242bad3ecd0Sotto */ 243bad3ecd0Sotto mp = (struct mount *)malloc((u_long)sizeof(struct mount), 244bad3ecd0Sotto M_MOUNT, M_WAITOK); 245bad3ecd0Sotto bzero((char *)mp, (u_long)sizeof(struct mount)); 246bad3ecd0Sotto lockinit(&mp->mnt_lock, PVFS, "vfslock", 0, 0); 247bad3ecd0Sotto /* This error never happens, but it makes auditing easier */ 248bad3ecd0Sotto if ((error = vfs_busy(mp, LK_NOWAIT, 0, p))) 249bad3ecd0Sotto return (error); 250bad3ecd0Sotto mp->mnt_op = vfsp->vfc_vfsops; 251bad3ecd0Sotto mp->mnt_vfc = vfsp; 252bad3ecd0Sotto mp->mnt_flag |= (vfsp->vfc_flags & MNT_VISFLAGMASK); 253bad3ecd0Sotto strncpy(mp->mnt_stat.f_fstypename, vfsp->vfc_name, MFSNAMELEN); 254bad3ecd0Sotto mp->mnt_vnodecovered = vp; 255bad3ecd0Sotto mp->mnt_stat.f_owner = p->p_ucred->cr_uid; 256bad3ecd0Sottoupdate: 257bad3ecd0Sotto /* 258bad3ecd0Sotto * Set the mount level flags. 259bad3ecd0Sotto */ 260bad3ecd0Sotto if (SCARG(uap, flags) & MNT_RDONLY) 261bad3ecd0Sotto mp->mnt_flag |= MNT_RDONLY; 262bad3ecd0Sotto else if (mp->mnt_flag & MNT_RDONLY) 263bad3ecd0Sotto mp->mnt_flag |= MNT_WANTRDWR; 264bad3ecd0Sotto mp->mnt_flag &=~ (MNT_NOSUID | MNT_NOEXEC | MNT_NODEV | 265bad3ecd0Sotto MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC | MNT_SOFTDEP | 266bad3ecd0Sotto MNT_NOATIME | MNT_FORCE); 267bad3ecd0Sotto mp->mnt_flag |= SCARG(uap, flags) & (MNT_NOSUID | MNT_NOEXEC | 268bad3ecd0Sotto MNT_NODEV | MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC | 269bad3ecd0Sotto MNT_SOFTDEP | MNT_NOATIME | MNT_FORCE); 270bad3ecd0Sotto /* 271bad3ecd0Sotto * Mount the filesystem. 272bad3ecd0Sotto */ 273bad3ecd0Sotto error = VFS_MOUNT(mp, SCARG(uap, path), SCARG(uap, data), &nd, p); 274bad3ecd0Sotto if (!error) { 275bad3ecd0Sotto microtime(&tv); 276bad3ecd0Sotto mp->mnt_stat.f_ctime = tv.tv_sec; 277bad3ecd0Sotto } 278bad3ecd0Sotto if (mp->mnt_flag & MNT_UPDATE) { 279bad3ecd0Sotto vrele(vp); 280bad3ecd0Sotto if (mp->mnt_flag & MNT_WANTRDWR) 281bad3ecd0Sotto mp->mnt_flag &= ~MNT_RDONLY; 282bad3ecd0Sotto mp->mnt_flag &=~ 283bad3ecd0Sotto (MNT_UPDATE | MNT_RELOAD | MNT_FORCE | MNT_WANTRDWR); 284bad3ecd0Sotto if (error) 285bad3ecd0Sotto mp->mnt_flag = flag; 286bad3ecd0Sotto 287bad3ecd0Sotto if ((mp->mnt_flag & MNT_RDONLY) == 0) { 288bad3ecd0Sotto if (mp->mnt_syncer == NULL) 289bad3ecd0Sotto error = vfs_allocate_syncvnode(mp); 290bad3ecd0Sotto } else { 291bad3ecd0Sotto if (mp->mnt_syncer != NULL) 292bad3ecd0Sotto vgone(mp->mnt_syncer); 293bad3ecd0Sotto mp->mnt_syncer = NULL; 294bad3ecd0Sotto } 295bad3ecd0Sotto 296bad3ecd0Sotto vfs_unbusy(mp, p); 297bad3ecd0Sotto return (error); 298bad3ecd0Sotto } 299bad3ecd0Sotto 300bad3ecd0Sotto vp->v_mountedhere = mp; 301bad3ecd0Sotto 302bad3ecd0Sotto /* 303bad3ecd0Sotto * Put the new filesystem on the mount list after root. 304bad3ecd0Sotto */ 305bad3ecd0Sotto cache_purge(vp); 306bad3ecd0Sotto if (!error) { 307bad3ecd0Sotto vfsp->vfc_refcount++; 308bad3ecd0Sotto simple_lock(&mountlist_slock); 3095d9303d4Skrw TAILQ_INSERT_TAIL(&mountlist, mp, mnt_list); 310bad3ecd0Sotto simple_unlock(&mountlist_slock); 311bad3ecd0Sotto checkdirs(vp); 312bad3ecd0Sotto VOP_UNLOCK(vp, 0, p); 313bad3ecd0Sotto if ((mp->mnt_flag & MNT_RDONLY) == 0) 314bad3ecd0Sotto error = vfs_allocate_syncvnode(mp); 315bad3ecd0Sotto vfs_unbusy(mp, p); 316bad3ecd0Sotto (void) VFS_STATFS(mp, &mp->mnt_stat, p); 317bad3ecd0Sotto if ((error = VFS_START(mp, 0, p)) != 0) 318bad3ecd0Sotto vrele(vp); 319bad3ecd0Sotto } else { 320bad3ecd0Sotto mp->mnt_vnodecovered->v_mountedhere = (struct mount *)0; 321bad3ecd0Sotto vfs_unbusy(mp, p); 322bad3ecd0Sotto free((caddr_t)mp, M_MOUNT); 323bad3ecd0Sotto vput(vp); 324bad3ecd0Sotto } 325bad3ecd0Sotto return (error); 326bad3ecd0Sotto} 327bad3ecd0Sotto 328bad3ecd0Sotto/* 329bad3ecd0Sotto * Scan all active processes to see if any of them have a current 330bad3ecd0Sotto * or root directory onto which the new filesystem has just been 331bad3ecd0Sotto * mounted. If so, replace them with the new mount point. 332bad3ecd0Sotto */ 333bad3ecd0Sottovoid 334bad3ecd0Sottocheckdirs(olddp) 335bad3ecd0Sotto struct vnode *olddp; 336bad3ecd0Sotto{ 337bad3ecd0Sotto struct filedesc *fdp; 338bad3ecd0Sotto struct vnode *newdp; 339bad3ecd0Sotto struct proc *p; 340bad3ecd0Sotto 341bad3ecd0Sotto if (olddp->v_usecount == 1) 342bad3ecd0Sotto return; 343bad3ecd0Sotto if (VFS_ROOT(olddp->v_mountedhere, &newdp)) 344bad3ecd0Sotto panic("mount: lost mount"); 345bad3ecd0Sotto for (p = LIST_FIRST(&allproc); p != 0; p = LIST_NEXT(p, p_list)) { 346bad3ecd0Sotto fdp = p->p_fd; 347bad3ecd0Sotto if (fdp->fd_cdir == olddp) { 348bad3ecd0Sotto vrele(fdp->fd_cdir); 349bad3ecd0Sotto VREF(newdp); 350bad3ecd0Sotto fdp->fd_cdir = newdp; 351bad3ecd0Sotto } 352bad3ecd0Sotto if (fdp->fd_rdir == olddp) { 353bad3ecd0Sotto vrele(fdp->fd_rdir); 354bad3ecd0Sotto VREF(newdp); 355bad3ecd0Sotto fdp->fd_rdir = newdp; 356bad3ecd0Sotto } 357bad3ecd0Sotto } 358bad3ecd0Sotto if (rootvnode == olddp) { 359bad3ecd0Sotto vrele(rootvnode); 360bad3ecd0Sotto VREF(newdp); 361bad3ecd0Sotto rootvnode = newdp; 362bad3ecd0Sotto } 363bad3ecd0Sotto vput(newdp); 364bad3ecd0Sotto} 365bad3ecd0Sotto 366bad3ecd0Sotto/* 367bad3ecd0Sotto * Unmount a file system. 368bad3ecd0Sotto * 369bad3ecd0Sotto * Note: unmount takes a path to the vnode mounted on as argument, 370bad3ecd0Sotto * not special file (as before). 371bad3ecd0Sotto */ 372bad3ecd0Sotto/* ARGSUSED */ 373bad3ecd0Sottoint 374bad3ecd0Sottosys_unmount(p, v, retval) 375bad3ecd0Sotto struct proc *p; 376bad3ecd0Sotto void *v; 377bad3ecd0Sotto register_t *retval; 378bad3ecd0Sotto{ 379bad3ecd0Sotto register struct sys_unmount_args /* { 380bad3ecd0Sotto syscallarg(char *) path; 381bad3ecd0Sotto syscallarg(int) flags; 382bad3ecd0Sotto } */ *uap = v; 383bad3ecd0Sotto register struct vnode *vp; 384bad3ecd0Sotto struct mount *mp; 385bad3ecd0Sotto int error; 386bad3ecd0Sotto struct nameidata nd; 387bad3ecd0Sotto 388bad3ecd0Sotto NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, 389bad3ecd0Sotto SCARG(uap, path), p); 390bad3ecd0Sotto if ((error = namei(&nd)) != 0) 391bad3ecd0Sotto return (error); 392bad3ecd0Sotto vp = nd.ni_vp; 393bad3ecd0Sotto mp = vp->v_mount; 394bad3ecd0Sotto 395bad3ecd0Sotto /* 396bad3ecd0Sotto * Only root, or the user that did the original mount is 397bad3ecd0Sotto * permitted to unmount this filesystem. 398bad3ecd0Sotto */ 399bad3ecd0Sotto if ((mp->mnt_stat.f_owner != p->p_ucred->cr_uid) && 400bad3ecd0Sotto (error = suser(p->p_ucred, &p->p_acflag))) { 401bad3ecd0Sotto vput(vp); 402bad3ecd0Sotto return (error); 403bad3ecd0Sotto } 404bad3ecd0Sotto 405bad3ecd0Sotto /* 406bad3ecd0Sotto * Don't allow unmounting the root file system. 407bad3ecd0Sotto */ 408bad3ecd0Sotto if (mp->mnt_flag & MNT_ROOTFS) { 409bad3ecd0Sotto vput(vp); 410bad3ecd0Sotto return (EINVAL); 411bad3ecd0Sotto } 412bad3ecd0Sotto 413bad3ecd0Sotto /* 414bad3ecd0Sotto * Must be the root of the filesystem 415bad3ecd0Sotto */ 416bad3ecd0Sotto if ((vp->v_flag & VROOT) == 0) { 417bad3ecd0Sotto vput(vp); 418bad3ecd0Sotto return (EINVAL); 419bad3ecd0Sotto } 420bad3ecd0Sotto vput(vp); 421bad3ecd0Sotto 422bad3ecd0Sotto if (vfs_busy(mp, LK_EXCLUSIVE, NULL, p)) 423bad3ecd0Sotto return (EBUSY); 424bad3ecd0Sotto 425bad3ecd0Sotto return (dounmount(mp, SCARG(uap, flags), p, vp)); 426bad3ecd0Sotto} 427bad3ecd0Sotto 428bad3ecd0Sotto/* 429bad3ecd0Sotto * Do the actual file system unmount. 430bad3ecd0Sotto */ 431bad3ecd0Sottoint 432bad3ecd0Sottodounmount(struct mount *mp, int flags, struct proc *p, struct vnode *olddp) 433bad3ecd0Sotto{ 434bad3ecd0Sotto struct vnode *coveredvp; 435bad3ecd0Sotto struct proc *p2; 436bad3ecd0Sotto int error; 437bad3ecd0Sotto int hadsyncer = 0; 438bad3ecd0Sotto 439bad3ecd0Sotto mp->mnt_flag &=~ MNT_ASYNC; 440bad3ecd0Sotto cache_purgevfs(mp); /* remove cache entries for this file sys */ 441bad3ecd0Sotto if (mp->mnt_syncer != NULL) { 442bad3ecd0Sotto hadsyncer = 1; 443bad3ecd0Sotto vgone(mp->mnt_syncer); 444bad3ecd0Sotto mp->mnt_syncer = NULL; 445bad3ecd0Sotto } 446bad3ecd0Sotto if (((mp->mnt_flag & MNT_RDONLY) || 447bad3ecd0Sotto (error = VFS_SYNC(mp, MNT_WAIT, p->p_ucred, p)) == 0) || 448bad3ecd0Sotto (flags & MNT_FORCE)) 449bad3ecd0Sotto error = VFS_UNMOUNT(mp, flags, p); 450bad3ecd0Sotto simple_lock(&mountlist_slock); 451bad3ecd0Sotto if (error) { 452bad3ecd0Sotto if ((mp->mnt_flag & MNT_RDONLY) == 0 && hadsyncer) 453bad3ecd0Sotto (void) vfs_allocate_syncvnode(mp); 454bad3ecd0Sotto lockmgr(&mp->mnt_lock, LK_RELEASE | LK_INTERLOCK, 455bad3ecd0Sotto &mountlist_slock, p); 456bad3ecd0Sotto return (error); 457bad3ecd0Sotto } 4585d9303d4Skrw TAILQ_REMOVE(&mountlist, mp, mnt_list); 459bad3ecd0Sotto if ((coveredvp = mp->mnt_vnodecovered) != NULLVP) { 460bad3ecd0Sotto if (olddp) { 461bad3ecd0Sotto /* 462bad3ecd0Sotto * Try to put processes back in a real directory 463bad3ecd0Sotto * after a forced unmount. 464bad3ecd0Sotto * XXX We're not holding a ref on olddp, which may 465bad3ecd0Sotto * change, so compare id numbers. 466bad3ecd0Sotto */ 467bad3ecd0Sotto LIST_FOREACH(p2, &allproc, p_list) { 468bad3ecd0Sotto struct filedesc *fdp = p2->p_fd; 469bad3ecd0Sotto if (fdp->fd_cdir && 470bad3ecd0Sotto fdp->fd_cdir->v_id == olddp->v_id) { 471bad3ecd0Sotto vrele(fdp->fd_cdir); 472bad3ecd0Sotto vref(coveredvp); 473bad3ecd0Sotto fdp->fd_cdir = coveredvp; 474bad3ecd0Sotto } 475bad3ecd0Sotto if (fdp->fd_rdir && 476bad3ecd0Sotto fdp->fd_rdir->v_id == olddp->v_id) { 477bad3ecd0Sotto vrele(fdp->fd_rdir); 478bad3ecd0Sotto vref(coveredvp); 479bad3ecd0Sotto fdp->fd_rdir = coveredvp; 480bad3ecd0Sotto } 481bad3ecd0Sotto } 482bad3ecd0Sotto } 483bad3ecd0Sotto coveredvp->v_mountedhere = NULL; 484bad3ecd0Sotto vrele(coveredvp); 485bad3ecd0Sotto } 486bad3ecd0Sotto mp->mnt_vfc->vfc_refcount--; 487bad3ecd0Sotto if (mp->mnt_vnodelist.lh_first != NULL) 488bad3ecd0Sotto panic("unmount: dangling vnode"); 489bad3ecd0Sotto lockmgr(&mp->mnt_lock, LK_RELEASE | LK_INTERLOCK, &mountlist_slock, p); 490bad3ecd0Sotto free((caddr_t)mp, M_MOUNT); 491bad3ecd0Sotto return (0); 492bad3ecd0Sotto} 493bad3ecd0Sotto 494bad3ecd0Sotto/* 495bad3ecd0Sotto * Sync each mounted filesystem. 496bad3ecd0Sotto */ 497bad3ecd0Sotto#ifdef DEBUG 498bad3ecd0Sottoint syncprt = 0; 499bad3ecd0Sottostruct ctldebug debug0 = { "syncprt", &syncprt }; 500bad3ecd0Sotto#endif 501bad3ecd0Sotto 502bad3ecd0Sotto/* ARGSUSED */ 503bad3ecd0Sottoint 504bad3ecd0Sottosys_sync(p, v, retval) 505bad3ecd0Sotto struct proc *p; 506bad3ecd0Sotto void *v; 507bad3ecd0Sotto register_t *retval; 508bad3ecd0Sotto{ 509bad3ecd0Sotto register struct mount *mp, *nmp; 510bad3ecd0Sotto int asyncflag; 511bad3ecd0Sotto 512bad3ecd0Sotto simple_lock(&mountlist_slock); 5135d9303d4Skrw TAILQ_FOREACH_REVERSE_SAFE(mp, &mountlist, mnt_list, nmp) { 5145d9303d4Skrw if (vfs_busy(mp, LK_NOWAIT, &mountlist_slock, p)) 515bad3ecd0Sotto continue; 516bad3ecd0Sotto if ((mp->mnt_flag & MNT_RDONLY) == 0) { 517bad3ecd0Sotto asyncflag = mp->mnt_flag & MNT_ASYNC; 518bad3ecd0Sotto mp->mnt_flag &= ~MNT_ASYNC; 519bad3ecd0Sotto uvm_vnp_sync(mp); 520bad3ecd0Sotto VFS_SYNC(mp, MNT_NOWAIT, p->p_ucred, p); 521bad3ecd0Sotto if (asyncflag) 522bad3ecd0Sotto mp->mnt_flag |= MNT_ASYNC; 523bad3ecd0Sotto } 524bad3ecd0Sotto simple_lock(&mountlist_slock); 525bad3ecd0Sotto vfs_unbusy(mp, p); 526bad3ecd0Sotto } 527bad3ecd0Sotto simple_unlock(&mountlist_slock); 528bad3ecd0Sotto 529bad3ecd0Sotto#ifdef DEBUG 530bad3ecd0Sotto if (syncprt) 531bad3ecd0Sotto vfs_bufstats(); 532bad3ecd0Sotto#endif /* DEBUG */ 533bad3ecd0Sotto return (0); 534bad3ecd0Sotto} 535bad3ecd0Sotto 536bad3ecd0Sotto/* 537bad3ecd0Sotto * Change filesystem quotas. 538bad3ecd0Sotto */ 539bad3ecd0Sotto/* ARGSUSED */ 540bad3ecd0Sottoint 541bad3ecd0Sottosys_quotactl(p, v, retval) 542bad3ecd0Sotto struct proc *p; 543bad3ecd0Sotto void *v; 544bad3ecd0Sotto register_t *retval; 545bad3ecd0Sotto{ 546bad3ecd0Sotto register struct sys_quotactl_args /* { 547bad3ecd0Sotto syscallarg(char *) path; 548bad3ecd0Sotto syscallarg(int) cmd; 549bad3ecd0Sotto syscallarg(int) uid; 550bad3ecd0Sotto syscallarg(caddr_t) arg; 551bad3ecd0Sotto } */ *uap = v; 552bad3ecd0Sotto register struct mount *mp; 553bad3ecd0Sotto int error; 554bad3ecd0Sotto struct nameidata nd; 555bad3ecd0Sotto 556bad3ecd0Sotto NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 557bad3ecd0Sotto if ((error = namei(&nd)) != 0) 558bad3ecd0Sotto return (error); 559bad3ecd0Sotto mp = nd.ni_vp->v_mount; 560bad3ecd0Sotto vrele(nd.ni_vp); 561bad3ecd0Sotto return (VFS_QUOTACTL(mp, SCARG(uap, cmd), SCARG(uap, uid), 562bad3ecd0Sotto SCARG(uap, arg), p)); 563bad3ecd0Sotto} 564bad3ecd0Sotto 565bad3ecd0Sotto/* 566bad3ecd0Sotto * Get filesystem statistics. 567bad3ecd0Sotto */ 568bad3ecd0Sotto/* ARGSUSED */ 569bad3ecd0Sottoint 570bad3ecd0Sottosys_statfs(p, v, retval) 571bad3ecd0Sotto struct proc *p; 572bad3ecd0Sotto void *v; 573bad3ecd0Sotto register_t *retval; 574bad3ecd0Sotto{ 575bad3ecd0Sotto register struct sys_statfs_args /* { 576bad3ecd0Sotto syscallarg(char *) path; 577bad3ecd0Sotto syscallarg(struct statfs *) buf; 578bad3ecd0Sotto } */ *uap = v; 579bad3ecd0Sotto register struct mount *mp; 580bad3ecd0Sotto register struct statfs *sp; 581bad3ecd0Sotto int error; 582bad3ecd0Sotto struct nameidata nd; 583bad3ecd0Sotto struct statfs sb; 584bad3ecd0Sotto 585bad3ecd0Sotto NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 586bad3ecd0Sotto if ((error = namei(&nd)) != 0) 587bad3ecd0Sotto return (error); 588bad3ecd0Sotto mp = nd.ni_vp->v_mount; 589bad3ecd0Sotto sp = &mp->mnt_stat; 590bad3ecd0Sotto vrele(nd.ni_vp); 591bad3ecd0Sotto if ((error = VFS_STATFS(mp, sp, p)) != 0) 592bad3ecd0Sotto return (error); 593bad3ecd0Sotto sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 594bad3ecd0Sotto /* Don't let non-root see filesystem id (for NFS security) */ 595bad3ecd0Sotto if (suser(p->p_ucred, &p->p_acflag)) { 596bad3ecd0Sotto bcopy((caddr_t)sp, (caddr_t)&sb, sizeof(sb)); 597bad3ecd0Sotto sb.f_fsid.val[0] = sb.f_fsid.val[1] = 0; 598bad3ecd0Sotto sp = &sb; 599bad3ecd0Sotto } 600bad3ecd0Sotto return (copyout((caddr_t)sp, (caddr_t)SCARG(uap, buf), sizeof(*sp))); 601bad3ecd0Sotto} 602bad3ecd0Sotto 603bad3ecd0Sotto/* 604bad3ecd0Sotto * Get filesystem statistics. 605bad3ecd0Sotto */ 606bad3ecd0Sotto/* ARGSUSED */ 607bad3ecd0Sottoint 608bad3ecd0Sottosys_fstatfs(p, v, retval) 609bad3ecd0Sotto struct proc *p; 610bad3ecd0Sotto void *v; 611bad3ecd0Sotto register_t *retval; 612bad3ecd0Sotto{ 613bad3ecd0Sotto struct sys_fstatfs_args /* { 614bad3ecd0Sotto syscallarg(int) fd; 615bad3ecd0Sotto syscallarg(struct statfs *) buf; 616bad3ecd0Sotto } */ *uap = v; 617bad3ecd0Sotto struct file *fp; 618bad3ecd0Sotto struct mount *mp; 619bad3ecd0Sotto struct statfs *sp; 620bad3ecd0Sotto int error; 621bad3ecd0Sotto struct statfs sb; 622bad3ecd0Sotto 623bad3ecd0Sotto if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0) 624bad3ecd0Sotto return (error); 625bad3ecd0Sotto mp = ((struct vnode *)fp->f_data)->v_mount; 626bad3ecd0Sotto sp = &mp->mnt_stat; 627bad3ecd0Sotto error = VFS_STATFS(mp, sp, p); 628bad3ecd0Sotto FRELE(fp); 629bad3ecd0Sotto if (error) 630bad3ecd0Sotto return (error); 631bad3ecd0Sotto sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 632bad3ecd0Sotto /* Don't let non-root see filesystem id (for NFS security) */ 633bad3ecd0Sotto if (suser(p->p_ucred, &p->p_acflag)) { 634bad3ecd0Sotto bcopy((caddr_t)sp, (caddr_t)&sb, sizeof(sb)); 635bad3ecd0Sotto sb.f_fsid.val[0] = sb.f_fsid.val[1] = 0; 636bad3ecd0Sotto sp = &sb; 637bad3ecd0Sotto } 638bad3ecd0Sotto return (copyout((caddr_t)sp, (caddr_t)SCARG(uap, buf), sizeof(*sp))); 639bad3ecd0Sotto} 640bad3ecd0Sotto 641bad3ecd0Sotto/* 642bad3ecd0Sotto * Get statistics on all filesystems. 643bad3ecd0Sotto */ 644bad3ecd0Sottoint 645bad3ecd0Sottosys_getfsstat(p, v, retval) 646bad3ecd0Sotto struct proc *p; 647bad3ecd0Sotto void *v; 648bad3ecd0Sotto register_t *retval; 649bad3ecd0Sotto{ 650bad3ecd0Sotto register struct sys_getfsstat_args /* { 651bad3ecd0Sotto syscallarg(struct statfs *) buf; 652bad3ecd0Sotto syscallarg(size_t) bufsize; 653bad3ecd0Sotto syscallarg(int) flags; 654bad3ecd0Sotto } */ *uap = v; 6555d9303d4Skrw register struct mount *mp *nmp; 656bad3ecd0Sotto register struct statfs *sp; 657bad3ecd0Sotto struct statfs sb; 658bad3ecd0Sotto caddr_t sfsp; 659bad3ecd0Sotto size_t count, maxcount; 660bad3ecd0Sotto int error, flags = SCARG(uap, flags); 661bad3ecd0Sotto 662bad3ecd0Sotto maxcount = SCARG(uap, bufsize) / sizeof(struct statfs); 663bad3ecd0Sotto sfsp = (caddr_t)SCARG(uap, buf); 664bad3ecd0Sotto count = 0; 665bad3ecd0Sotto simple_lock(&mountlist_slock); 6665d9303d4Skrw TAILQ_FOREACH_REVERSE_SAFE(mp, &mountlist, mnt_list, nmp) { 6675d9303d4Skrw if (vfs_busy(mp, LK_NOWAIT, &mountlist_slock, p)) 668bad3ecd0Sotto continue; 669bad3ecd0Sotto if (sfsp && count < maxcount) { 670bad3ecd0Sotto sp = &mp->mnt_stat; 671bad3ecd0Sotto 672bad3ecd0Sotto /* Refresh stats unless MNT_NOWAIT is specified */ 673bad3ecd0Sotto if (flags != MNT_NOWAIT && 674bad3ecd0Sotto flags != MNT_LAZY && 675bad3ecd0Sotto (flags == MNT_WAIT || 676bad3ecd0Sotto flags == 0) && 677bad3ecd0Sotto (error = VFS_STATFS(mp, sp, p))) { 678bad3ecd0Sotto simple_lock(&mountlist_slock); 679bad3ecd0Sotto vfs_unbusy(mp, p); 680bad3ecd0Sotto continue; 681bad3ecd0Sotto } 682bad3ecd0Sotto 683bad3ecd0Sotto sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 684bad3ecd0Sotto if (suser(p->p_ucred, &p->p_acflag)) { 685bad3ecd0Sotto bcopy((caddr_t)sp, (caddr_t)&sb, sizeof(sb)); 686bad3ecd0Sotto sb.f_fsid.val[0] = sb.f_fsid.val[1] = 0; 687bad3ecd0Sotto sp = &sb; 688bad3ecd0Sotto } 689bad3ecd0Sotto error = copyout((caddr_t)sp, sfsp, sizeof(*sp)); 690bad3ecd0Sotto if (error) { 691bad3ecd0Sotto vfs_unbusy(mp, p); 692bad3ecd0Sotto return (error); 693bad3ecd0Sotto } 694bad3ecd0Sotto sfsp += sizeof(*sp); 695bad3ecd0Sotto } 696bad3ecd0Sotto count++; 697bad3ecd0Sotto simple_lock(&mountlist_slock); 698bad3ecd0Sotto vfs_unbusy(mp, p); 699bad3ecd0Sotto } 700bad3ecd0Sotto simple_unlock(&mountlist_slock); 701bad3ecd0Sotto if (sfsp && count > maxcount) 702bad3ecd0Sotto *retval = maxcount; 703bad3ecd0Sotto else 704bad3ecd0Sotto *retval = count; 705bad3ecd0Sotto return (0); 706bad3ecd0Sotto} 707bad3ecd0Sotto 708bad3ecd0Sotto/* 709bad3ecd0Sotto * Change current working directory to a given file descriptor. 710bad3ecd0Sotto */ 711bad3ecd0Sotto/* ARGSUSED */ 712bad3ecd0Sottoint 713bad3ecd0Sottosys_fchdir(p, v, retval) 714bad3ecd0Sotto struct proc *p; 715bad3ecd0Sotto void *v; 716bad3ecd0Sotto register_t *retval; 717bad3ecd0Sotto{ 718bad3ecd0Sotto struct sys_fchdir_args /* { 719bad3ecd0Sotto syscallarg(int) fd; 720bad3ecd0Sotto } */ *uap = v; 721bad3ecd0Sotto struct filedesc *fdp = p->p_fd; 722bad3ecd0Sotto struct vnode *vp, *tdp; 723bad3ecd0Sotto struct mount *mp; 724bad3ecd0Sotto struct file *fp; 725bad3ecd0Sotto int error; 726bad3ecd0Sotto 727bad3ecd0Sotto if ((error = getvnode(fdp, SCARG(uap, fd), &fp)) != 0) 728bad3ecd0Sotto return (error); 729bad3ecd0Sotto vp = (struct vnode *)fp->f_data; 730bad3ecd0Sotto VREF(vp); 731bad3ecd0Sotto FRELE(fp); 732bad3ecd0Sotto vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 733bad3ecd0Sotto if (vp->v_type != VDIR) 734bad3ecd0Sotto error = ENOTDIR; 735bad3ecd0Sotto else 736bad3ecd0Sotto error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p); 737bad3ecd0Sotto 738bad3ecd0Sotto while (!error && (mp = vp->v_mountedhere) != NULL) { 739bad3ecd0Sotto if (vfs_busy(mp, 0, 0, p)) 740bad3ecd0Sotto continue; 741bad3ecd0Sotto error = VFS_ROOT(mp, &tdp); 742bad3ecd0Sotto vfs_unbusy(mp, p); 743bad3ecd0Sotto if (error) 744bad3ecd0Sotto break; 745bad3ecd0Sotto vput(vp); 746bad3ecd0Sotto vp = tdp; 747bad3ecd0Sotto } 748bad3ecd0Sotto if (error) { 749bad3ecd0Sotto vput(vp); 750bad3ecd0Sotto return (error); 751bad3ecd0Sotto } 752bad3ecd0Sotto VOP_UNLOCK(vp, 0, p); 753bad3ecd0Sotto vrele(fdp->fd_cdir); 754bad3ecd0Sotto fdp->fd_cdir = vp; 755bad3ecd0Sotto return (0); 756bad3ecd0Sotto} 757bad3ecd0Sotto 758bad3ecd0Sotto/* 759bad3ecd0Sotto * Change current working directory (``.''). 760bad3ecd0Sotto */ 761bad3ecd0Sotto/* ARGSUSED */ 762bad3ecd0Sottoint 763bad3ecd0Sottosys_chdir(p, v, retval) 764bad3ecd0Sotto struct proc *p; 765bad3ecd0Sotto void *v; 766bad3ecd0Sotto register_t *retval; 767bad3ecd0Sotto{ 768bad3ecd0Sotto struct sys_chdir_args /* { 769bad3ecd0Sotto syscallarg(char *) path; 770bad3ecd0Sotto } */ *uap = v; 771bad3ecd0Sotto register struct filedesc *fdp = p->p_fd; 772bad3ecd0Sotto int error; 773bad3ecd0Sotto struct nameidata nd; 774bad3ecd0Sotto 775bad3ecd0Sotto NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, 776bad3ecd0Sotto SCARG(uap, path), p); 777bad3ecd0Sotto if ((error = change_dir(&nd, p)) != 0) 778bad3ecd0Sotto return (error); 779bad3ecd0Sotto vrele(fdp->fd_cdir); 780bad3ecd0Sotto fdp->fd_cdir = nd.ni_vp; 781bad3ecd0Sotto return (0); 782bad3ecd0Sotto} 783bad3ecd0Sotto 784bad3ecd0Sotto/* 785bad3ecd0Sotto * Change notion of root (``/'') directory. 786bad3ecd0Sotto */ 787bad3ecd0Sotto/* ARGSUSED */ 788bad3ecd0Sottoint 789bad3ecd0Sottosys_chroot(p, v, retval) 790bad3ecd0Sotto struct proc *p; 791bad3ecd0Sotto void *v; 792bad3ecd0Sotto register_t *retval; 793bad3ecd0Sotto{ 794bad3ecd0Sotto struct sys_chroot_args /* { 795bad3ecd0Sotto syscallarg(char *) path; 796bad3ecd0Sotto } */ *uap = v; 797bad3ecd0Sotto register struct filedesc *fdp = p->p_fd; 798bad3ecd0Sotto int error; 799bad3ecd0Sotto struct nameidata nd; 800bad3ecd0Sotto 801bad3ecd0Sotto if ((error = suser(p->p_ucred, &p->p_acflag)) != 0) 802bad3ecd0Sotto return (error); 803bad3ecd0Sotto NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, 804bad3ecd0Sotto SCARG(uap, path), p); 805bad3ecd0Sotto if ((error = change_dir(&nd, p)) != 0) 806bad3ecd0Sotto return (error); 807bad3ecd0Sotto if (fdp->fd_rdir != NULL) { 808bad3ecd0Sotto /* 809bad3ecd0Sotto * A chroot() done inside a changed root environment does 810bad3ecd0Sotto * an automatic chdir to avoid the out-of-tree experience. 811bad3ecd0Sotto */ 812bad3ecd0Sotto vrele(fdp->fd_rdir); 813bad3ecd0Sotto vrele(fdp->fd_cdir); 814bad3ecd0Sotto VREF(nd.ni_vp); 815bad3ecd0Sotto fdp->fd_cdir = nd.ni_vp; 816bad3ecd0Sotto } 817bad3ecd0Sotto fdp->fd_rdir = nd.ni_vp; 818bad3ecd0Sotto return (0); 819bad3ecd0Sotto} 820bad3ecd0Sotto 821bad3ecd0Sotto/* 822bad3ecd0Sotto * Common routine for chroot and chdir. 823bad3ecd0Sotto */ 824bad3ecd0Sottostatic int 825bad3ecd0Sottochange_dir(ndp, p) 826bad3ecd0Sotto register struct nameidata *ndp; 827bad3ecd0Sotto struct proc *p; 828bad3ecd0Sotto{ 829bad3ecd0Sotto struct vnode *vp; 830bad3ecd0Sotto int error; 831bad3ecd0Sotto 832bad3ecd0Sotto if ((error = namei(ndp)) != 0) 833bad3ecd0Sotto return (error); 834bad3ecd0Sotto vp = ndp->ni_vp; 835bad3ecd0Sotto if (vp->v_type != VDIR) 836bad3ecd0Sotto error = ENOTDIR; 837bad3ecd0Sotto else 838bad3ecd0Sotto error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p); 839bad3ecd0Sotto if (error) 840bad3ecd0Sotto vput(vp); 841bad3ecd0Sotto else 842bad3ecd0Sotto VOP_UNLOCK(vp, 0, p); 843bad3ecd0Sotto return (error); 844bad3ecd0Sotto} 845bad3ecd0Sotto 846bad3ecd0Sotto/* 847bad3ecd0Sotto * Check permissions, allocate an open file structure, 848bad3ecd0Sotto * and call the device open routine if any. 849bad3ecd0Sotto */ 850bad3ecd0Sottoint 851bad3ecd0Sottosys_open(p, v, retval) 852bad3ecd0Sotto struct proc *p; 853bad3ecd0Sotto void *v; 854bad3ecd0Sotto register_t *retval; 855bad3ecd0Sotto{ 856bad3ecd0Sotto struct sys_open_args /* { 857bad3ecd0Sotto syscallarg(char *) path; 858bad3ecd0Sotto syscallarg(int) flags; 859bad3ecd0Sotto syscallarg(int) mode; 860bad3ecd0Sotto } */ *uap = v; 861bad3ecd0Sotto struct filedesc *fdp = p->p_fd; 862bad3ecd0Sotto struct file *fp; 863bad3ecd0Sotto struct vnode *vp; 864bad3ecd0Sotto struct vattr vattr; 865bad3ecd0Sotto int flags, cmode; 866bad3ecd0Sotto int type, indx, error, localtrunc = 0; 867bad3ecd0Sotto struct flock lf; 868bad3ecd0Sotto struct nameidata nd; 869bad3ecd0Sotto 870bad3ecd0Sotto if ((error = falloc(p, &fp, &indx)) != 0) 871bad3ecd0Sotto return (error); 872bad3ecd0Sotto 873bad3ecd0Sotto flags = FFLAGS(SCARG(uap, flags)); 874bad3ecd0Sotto cmode = ((SCARG(uap, mode) &~ fdp->fd_cmask) & ALLPERMS) &~ S_ISTXT; 875bad3ecd0Sotto NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 876bad3ecd0Sotto p->p_dupfd = -indx - 1; /* XXX check for fdopen */ 877bad3ecd0Sotto if ((flags & O_TRUNC) && (flags & (O_EXLOCK | O_SHLOCK))) { 878bad3ecd0Sotto localtrunc = 1; 879bad3ecd0Sotto flags &= ~O_TRUNC; /* Must do truncate ourselves */ 880bad3ecd0Sotto } 881bad3ecd0Sotto if ((error = vn_open(&nd, flags, cmode)) != 0) { 882bad3ecd0Sotto if ((error == ENODEV || error == ENXIO) && 883bad3ecd0Sotto p->p_dupfd >= 0 && /* XXX from fdopen */ 884bad3ecd0Sotto (error = 885bad3ecd0Sotto dupfdopen(fdp, indx, p->p_dupfd, flags, error)) == 0) { 886bad3ecd0Sotto closef(fp, p); 887bad3ecd0Sotto *retval = indx; 888bad3ecd0Sotto return (0); 889bad3ecd0Sotto } 890bad3ecd0Sotto if (error == ERESTART) 891bad3ecd0Sotto error = EINTR; 892bad3ecd0Sotto fdremove(fdp, indx); 893bad3ecd0Sotto closef(fp, p); 894bad3ecd0Sotto return (error); 895bad3ecd0Sotto } 896bad3ecd0Sotto p->p_dupfd = 0; 897bad3ecd0Sotto vp = nd.ni_vp; 898bad3ecd0Sotto fp->f_flag = flags & FMASK; 899bad3ecd0Sotto fp->f_type = DTYPE_VNODE; 900bad3ecd0Sotto fp->f_ops = &vnops; 901bad3ecd0Sotto fp->f_data = (caddr_t)vp; 902bad3ecd0Sotto if (flags & (O_EXLOCK | O_SHLOCK)) { 903bad3ecd0Sotto lf.l_whence = SEEK_SET; 904bad3ecd0Sotto lf.l_start = 0; 905bad3ecd0Sotto lf.l_len = 0; 906bad3ecd0Sotto if (flags & O_EXLOCK) 907bad3ecd0Sotto lf.l_type = F_WRLCK; 908bad3ecd0Sotto else 909bad3ecd0Sotto lf.l_type = F_RDLCK; 910bad3ecd0Sotto type = F_FLOCK; 911bad3ecd0Sotto if ((flags & FNONBLOCK) == 0) 912bad3ecd0Sotto type |= F_WAIT; 913bad3ecd0Sotto VOP_UNLOCK(vp, 0, p); 914bad3ecd0Sotto error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, type); 915bad3ecd0Sotto if (error) { 916bad3ecd0Sotto /* closef will vn_close the file for us. */ 917bad3ecd0Sotto fdremove(fdp, indx); 918bad3ecd0Sotto closef(fp, p); 919bad3ecd0Sotto return (error); 920bad3ecd0Sotto } 921bad3ecd0Sotto vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 922bad3ecd0Sotto fp->f_flag |= FHASLOCK; 923bad3ecd0Sotto } 924bad3ecd0Sotto if (localtrunc) { 925bad3ecd0Sotto VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 926bad3ecd0Sotto if ((fp->f_flag & FWRITE) == 0) 927bad3ecd0Sotto error = EACCES; 928bad3ecd0Sotto else if (vp->v_mount->mnt_flag & MNT_RDONLY) 929bad3ecd0Sotto error = EROFS; 930bad3ecd0Sotto else if (vp->v_type == VDIR) 931bad3ecd0Sotto error = EISDIR; 932bad3ecd0Sotto else if ((error = vn_writechk(vp)) == 0) { 933bad3ecd0Sotto VATTR_NULL(&vattr); 934bad3ecd0Sotto vattr.va_size = 0; 935bad3ecd0Sotto error = VOP_SETATTR(vp, &vattr, fp->f_cred, p); 936bad3ecd0Sotto } 937bad3ecd0Sotto if (error) { 938bad3ecd0Sotto VOP_UNLOCK(vp, 0, p); 939bad3ecd0Sotto /* closef will close the file for us. */ 940bad3ecd0Sotto fdremove(fdp, indx); 941bad3ecd0Sotto closef(fp, p); 942bad3ecd0Sotto return (error); 943bad3ecd0Sotto } 944bad3ecd0Sotto } 945bad3ecd0Sotto VOP_UNLOCK(vp, 0, p); 946bad3ecd0Sotto *retval = indx; 947bad3ecd0Sotto FILE_SET_MATURE(fp); 948bad3ecd0Sotto return (0); 949bad3ecd0Sotto} 950bad3ecd0Sotto 951bad3ecd0Sotto/* 952bad3ecd0Sotto * Get file handle system call 953bad3ecd0Sotto */ 954bad3ecd0Sottoint 955bad3ecd0Sottosys_getfh(p, v, retval) 956bad3ecd0Sotto struct proc *p; 957bad3ecd0Sotto register void *v; 958bad3ecd0Sotto register_t *retval; 959bad3ecd0Sotto{ 960bad3ecd0Sotto register struct sys_getfh_args /* { 961bad3ecd0Sotto syscallarg(char *) fname; 962bad3ecd0Sotto syscallarg(fhandle_t *) fhp; 963bad3ecd0Sotto } */ *uap = v; 964bad3ecd0Sotto register struct vnode *vp; 965bad3ecd0Sotto fhandle_t fh; 966bad3ecd0Sotto int error; 967bad3ecd0Sotto struct nameidata nd; 968bad3ecd0Sotto 969bad3ecd0Sotto /* 970bad3ecd0Sotto * Must be super user 971bad3ecd0Sotto */ 972bad3ecd0Sotto error = suser(p->p_ucred, &p->p_acflag); 973bad3ecd0Sotto if (error) 974bad3ecd0Sotto return (error); 975bad3ecd0Sotto NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, 976bad3ecd0Sotto SCARG(uap, fname), p); 977bad3ecd0Sotto error = namei(&nd); 978bad3ecd0Sotto if (error) 979bad3ecd0Sotto return (error); 980bad3ecd0Sotto vp = nd.ni_vp; 981bad3ecd0Sotto bzero((caddr_t)&fh, sizeof(fh)); 982bad3ecd0Sotto fh.fh_fsid = vp->v_mount->mnt_stat.f_fsid; 983bad3ecd0Sotto error = VFS_VPTOFH(vp, &fh.fh_fid); 984bad3ecd0Sotto vput(vp); 985bad3ecd0Sotto if (error) 986bad3ecd0Sotto return (error); 987bad3ecd0Sotto error = copyout((caddr_t)&fh, (caddr_t)SCARG(uap, fhp), sizeof (fh)); 988bad3ecd0Sotto return (error); 989bad3ecd0Sotto} 990bad3ecd0Sotto 991bad3ecd0Sotto/* 992bad3ecd0Sotto * Open a file given a file handle. 993bad3ecd0Sotto * 994bad3ecd0Sotto * Check permissions, allocate an open file structure, 995bad3ecd0Sotto * and call the device open routine if any. 996bad3ecd0Sotto */ 997bad3ecd0Sottoint 998bad3ecd0Sottosys_fhopen(p, v, retval) 999bad3ecd0Sotto struct proc *p; 1000bad3ecd0Sotto void *v; 1001bad3ecd0Sotto register_t *retval; 1002bad3ecd0Sotto{ 1003bad3ecd0Sotto register struct sys_fhopen_args /* { 1004bad3ecd0Sotto syscallarg(const fhandle_t *) fhp; 1005bad3ecd0Sotto syscallarg(int) flags; 1006bad3ecd0Sotto } */ *uap = v; 1007bad3ecd0Sotto struct filedesc *fdp = p->p_fd; 1008bad3ecd0Sotto struct file *fp; 1009bad3ecd0Sotto struct vnode *vp = NULL; 1010bad3ecd0Sotto struct mount *mp; 1011bad3ecd0Sotto struct ucred *cred = p->p_ucred; 1012bad3ecd0Sotto int flags; 1013bad3ecd0Sotto int type, indx, error=0; 1014bad3ecd0Sotto struct flock lf; 1015bad3ecd0Sotto struct vattr va; 1016bad3ecd0Sotto fhandle_t fh; 1017bad3ecd0Sotto 1018bad3ecd0Sotto /* 1019bad3ecd0Sotto * Must be super user 1020bad3ecd0Sotto */ 1021bad3ecd0Sotto if ((error = suser(p->p_ucred, &p->p_acflag))) 1022bad3ecd0Sotto return (error); 1023bad3ecd0Sotto 1024bad3ecd0Sotto flags = FFLAGS(SCARG(uap, flags)); 1025bad3ecd0Sotto if ((flags & (FREAD | FWRITE)) == 0) 1026bad3ecd0Sotto return (EINVAL); 1027bad3ecd0Sotto if ((flags & O_CREAT)) 1028bad3ecd0Sotto return (EINVAL); 1029bad3ecd0Sotto 1030bad3ecd0Sotto if ((error = falloc(p, &fp, &indx)) != 0) 1031bad3ecd0Sotto return (error); 1032bad3ecd0Sotto 1033bad3ecd0Sotto if ((error = copyin(SCARG(uap, fhp), &fh, sizeof(fhandle_t))) != 0) 1034bad3ecd0Sotto goto bad; 1035bad3ecd0Sotto 1036bad3ecd0Sotto if ((mp = vfs_getvfs(&fh.fh_fsid)) == NULL) { 1037bad3ecd0Sotto error = ESTALE; 1038bad3ecd0Sotto goto bad; 1039bad3ecd0Sotto } 1040bad3ecd0Sotto 1041bad3ecd0Sotto if ((error = VFS_FHTOVP(mp, &fh.fh_fid, &vp)) != 0) { 1042bad3ecd0Sotto vp = NULL; /* most likely unnecessary sanity for bad: */ 1043bad3ecd0Sotto goto bad; 1044bad3ecd0Sotto } 1045bad3ecd0Sotto 1046bad3ecd0Sotto /* Now do an effective vn_open */ 1047bad3ecd0Sotto 1048bad3ecd0Sotto if (vp->v_type == VSOCK) { 1049bad3ecd0Sotto error = EOPNOTSUPP; 1050bad3ecd0Sotto goto bad; 1051bad3ecd0Sotto } 1052bad3ecd0Sotto if (flags & FREAD) { 1053bad3ecd0Sotto if ((error = VOP_ACCESS(vp, VREAD, cred, p)) != 0) 1054bad3ecd0Sotto goto bad; 1055bad3ecd0Sotto } 1056bad3ecd0Sotto if (flags & (FWRITE | O_TRUNC)) { 1057bad3ecd0Sotto if (vp->v_type == VDIR) { 1058bad3ecd0Sotto error = EISDIR; 1059bad3ecd0Sotto goto bad; 1060bad3ecd0Sotto } 1061bad3ecd0Sotto if ((error = vn_writechk(vp)) != 0 || 1062bad3ecd0Sotto (error = VOP_ACCESS(vp, VWRITE, cred, p)) != 0) 1063bad3ecd0Sotto goto bad; 1064bad3ecd0Sotto } 1065bad3ecd0Sotto if (flags & O_TRUNC) { 1066bad3ecd0Sotto VOP_UNLOCK(vp, 0, p); /* XXX */ 1067bad3ecd0Sotto VOP_LEASE(vp, p, cred, LEASE_WRITE); 1068bad3ecd0Sotto vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); /* XXX */ 1069bad3ecd0Sotto VATTR_NULL(&va); 1070bad3ecd0Sotto va.va_size = 0; 1071bad3ecd0Sotto if ((error = VOP_SETATTR(vp, &va, cred, p)) != 0) 1072bad3ecd0Sotto goto bad; 1073bad3ecd0Sotto } 1074bad3ecd0Sotto if ((error = VOP_OPEN(vp, flags, cred, p)) != 0) 1075bad3ecd0Sotto goto bad; 1076bad3ecd0Sotto if (flags & FWRITE) 1077bad3ecd0Sotto vp->v_writecount++; 1078bad3ecd0Sotto 1079bad3ecd0Sotto /* done with modified vn_open, now finish what sys_open does. */ 1080bad3ecd0Sotto 1081bad3ecd0Sotto fp->f_flag = flags & FMASK; 1082bad3ecd0Sotto fp->f_type = DTYPE_VNODE; 1083bad3ecd0Sotto fp->f_ops = &vnops; 1084bad3ecd0Sotto fp->f_data = (caddr_t)vp; 1085bad3ecd0Sotto if (flags & (O_EXLOCK | O_SHLOCK)) { 1086bad3ecd0Sotto lf.l_whence = SEEK_SET; 1087bad3ecd0Sotto lf.l_start = 0; 1088bad3ecd0Sotto lf.l_len = 0; 1089bad3ecd0Sotto if (flags & O_EXLOCK) 1090bad3ecd0Sotto lf.l_type = F_WRLCK; 1091bad3ecd0Sotto else 1092bad3ecd0Sotto lf.l_type = F_RDLCK; 1093bad3ecd0Sotto type = F_FLOCK; 1094bad3ecd0Sotto if ((flags & FNONBLOCK) == 0) 1095bad3ecd0Sotto type |= F_WAIT; 1096bad3ecd0Sotto VOP_UNLOCK(vp, 0, p); 1097bad3ecd0Sotto error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, type); 1098bad3ecd0Sotto if (error) { 1099bad3ecd0Sotto /* closef will vn_close the file for us. */ 1100bad3ecd0Sotto fdremove(fdp, indx); 1101bad3ecd0Sotto closef(fp, p); 1102bad3ecd0Sotto return (error); 1103bad3ecd0Sotto } 1104bad3ecd0Sotto vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 1105bad3ecd0Sotto fp->f_flag |= FHASLOCK; 1106bad3ecd0Sotto } 1107bad3ecd0Sotto VOP_UNLOCK(vp, 0, p); 1108bad3ecd0Sotto *retval = indx; 1109bad3ecd0Sotto FILE_SET_MATURE(fp); 1110bad3ecd0Sotto return (0); 1111bad3ecd0Sotto 1112bad3ecd0Sottobad: 1113bad3ecd0Sotto fdremove(fdp, indx); 1114bad3ecd0Sotto closef(fp, p); 1115bad3ecd0Sotto if (vp != NULL) 1116bad3ecd0Sotto vput(vp); 1117bad3ecd0Sotto return (error); 1118bad3ecd0Sotto} 1119bad3ecd0Sotto 1120bad3ecd0Sotto/* ARGSUSED */ 1121bad3ecd0Sottoint 1122bad3ecd0Sottosys_fhstat(p, v, retval) 1123bad3ecd0Sotto struct proc *p; 1124bad3ecd0Sotto void *v; 1125bad3ecd0Sotto register_t *retval; 1126bad3ecd0Sotto{ 1127bad3ecd0Sotto register struct sys_fhstat_args /* { 1128bad3ecd0Sotto syscallarg(const fhandle_t *) fhp; 1129bad3ecd0Sotto syscallarg(struct stat *) sb; 1130bad3ecd0Sotto } */ *uap = v; 1131bad3ecd0Sotto struct stat sb; 1132bad3ecd0Sotto int error; 1133bad3ecd0Sotto fhandle_t fh; 1134bad3ecd0Sotto struct mount *mp; 1135bad3ecd0Sotto struct vnode *vp; 1136bad3ecd0Sotto 1137bad3ecd0Sotto /* 1138bad3ecd0Sotto * Must be super user 1139bad3ecd0Sotto */ 1140bad3ecd0Sotto if ((error = suser(p->p_ucred, &p->p_acflag))) 1141bad3ecd0Sotto return (error); 1142bad3ecd0Sotto 1143bad3ecd0Sotto if ((error = copyin(SCARG(uap, fhp), &fh, sizeof(fhandle_t))) != 0) 1144bad3ecd0Sotto return (error); 1145bad3ecd0Sotto 1146bad3ecd0Sotto if ((mp = vfs_getvfs(&fh.fh_fsid)) == NULL) 1147bad3ecd0Sotto return (ESTALE); 1148bad3ecd0Sotto if ((error = VFS_FHTOVP(mp, &fh.fh_fid, &vp))) 1149bad3ecd0Sotto return (error); 1150bad3ecd0Sotto error = vn_stat(vp, &sb, p); 1151bad3ecd0Sotto vput(vp); 1152bad3ecd0Sotto if (error) 1153bad3ecd0Sotto return (error); 1154bad3ecd0Sotto error = copyout(&sb, SCARG(uap, sb), sizeof(sb)); 1155bad3ecd0Sotto return (error); 1156bad3ecd0Sotto} 1157bad3ecd0Sotto 1158bad3ecd0Sotto/* ARGSUSED */ 1159bad3ecd0Sottoint 1160bad3ecd0Sottosys_fhstatfs(p, v, retval) 1161bad3ecd0Sotto struct proc *p; 1162bad3ecd0Sotto void *v; 1163bad3ecd0Sotto register_t *retval; 1164bad3ecd0Sotto{ 1165bad3ecd0Sotto register struct sys_fhstatfs_args /* 1166bad3ecd0Sotto syscallarg(const fhandle_t *) fhp; 1167bad3ecd0Sotto syscallarg(struct statfs *) buf; 1168bad3ecd0Sotto } */ *uap = v; 1169bad3ecd0Sotto struct statfs sp; 1170bad3ecd0Sotto fhandle_t fh; 1171bad3ecd0Sotto struct mount *mp; 1172bad3ecd0Sotto struct vnode *vp; 1173bad3ecd0Sotto int error; 1174bad3ecd0Sotto 1175bad3ecd0Sotto /* 1176bad3ecd0Sotto * Must be super user 1177bad3ecd0Sotto */ 1178bad3ecd0Sotto if ((error = suser(p->p_ucred, &p->p_acflag))) 1179bad3ecd0Sotto return (error); 1180bad3ecd0Sotto 1181bad3ecd0Sotto if ((error = copyin(SCARG(uap, fhp), &fh, sizeof(fhandle_t))) != 0) 1182bad3ecd0Sotto return (error); 1183bad3ecd0Sotto 1184bad3ecd0Sotto if ((mp = vfs_getvfs(&fh.fh_fsid)) == NULL) 1185bad3ecd0Sotto return (ESTALE); 1186bad3ecd0Sotto if ((error = VFS_FHTOVP(mp, &fh.fh_fid, &vp))) 1187bad3ecd0Sotto return (error); 1188bad3ecd0Sotto mp = vp->v_mount; 1189bad3ecd0Sotto vput(vp); 1190bad3ecd0Sotto if ((error = VFS_STATFS(mp, &sp, p)) != 0) 1191bad3ecd0Sotto return (error); 1192bad3ecd0Sotto sp.f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 1193bad3ecd0Sotto return (copyout(&sp, SCARG(uap, buf), sizeof(sp))); 1194bad3ecd0Sotto} 1195bad3ecd0Sotto 1196bad3ecd0Sotto/* 1197bad3ecd0Sotto * Create a special file. 1198bad3ecd0Sotto */ 1199bad3ecd0Sotto/* ARGSUSED */ 1200bad3ecd0Sottoint 1201bad3ecd0Sottosys_mknod(p, v, retval) 1202bad3ecd0Sotto struct proc *p; 1203bad3ecd0Sotto void *v; 1204bad3ecd0Sotto register_t *retval; 1205bad3ecd0Sotto{ 1206bad3ecd0Sotto register struct sys_mknod_args /* { 1207bad3ecd0Sotto syscallarg(char *) path; 1208bad3ecd0Sotto syscallarg(int) mode; 1209bad3ecd0Sotto syscallarg(int) dev; 1210bad3ecd0Sotto } */ *uap = v; 1211bad3ecd0Sotto register struct vnode *vp; 1212bad3ecd0Sotto struct vattr vattr; 1213bad3ecd0Sotto int error; 1214bad3ecd0Sotto int whiteout = 0; 1215bad3ecd0Sotto struct nameidata nd; 1216bad3ecd0Sotto 1217bad3ecd0Sotto if ((error = suser(p->p_ucred, &p->p_acflag)) != 0) 1218bad3ecd0Sotto return (error); 1219bad3ecd0Sotto if (p->p_fd->fd_rdir) 1220bad3ecd0Sotto return (EINVAL); 1221bad3ecd0Sotto NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p); 1222bad3ecd0Sotto if ((error = namei(&nd)) != 0) 1223bad3ecd0Sotto return (error); 1224bad3ecd0Sotto vp = nd.ni_vp; 1225bad3ecd0Sotto if (vp != NULL) 1226bad3ecd0Sotto error = EEXIST; 1227bad3ecd0Sotto else { 1228bad3ecd0Sotto VATTR_NULL(&vattr); 1229bad3ecd0Sotto vattr.va_mode = (SCARG(uap, mode) & ALLPERMS) &~ p->p_fd->fd_cmask; 1230bad3ecd0Sotto vattr.va_rdev = SCARG(uap, dev); 1231bad3ecd0Sotto whiteout = 0; 1232bad3ecd0Sotto 1233bad3ecd0Sotto switch (SCARG(uap, mode) & S_IFMT) { 1234bad3ecd0Sotto case S_IFMT: /* used by badsect to flag bad sectors */ 1235bad3ecd0Sotto vattr.va_type = VBAD; 1236bad3ecd0Sotto break; 1237bad3ecd0Sotto case S_IFCHR: 1238bad3ecd0Sotto vattr.va_type = VCHR; 1239bad3ecd0Sotto break; 1240bad3ecd0Sotto case S_IFBLK: 1241bad3ecd0Sotto vattr.va_type = VBLK; 1242bad3ecd0Sotto break; 1243bad3ecd0Sotto case S_IFWHT: 1244bad3ecd0Sotto whiteout = 1; 1245bad3ecd0Sotto break; 1246bad3ecd0Sotto default: 1247bad3ecd0Sotto error = EINVAL; 1248bad3ecd0Sotto break; 1249bad3ecd0Sotto } 1250bad3ecd0Sotto } 1251bad3ecd0Sotto if (!error) { 1252bad3ecd0Sotto VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 1253bad3ecd0Sotto if (whiteout) { 1254bad3ecd0Sotto error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, CREATE); 1255bad3ecd0Sotto if (error) 1256bad3ecd0Sotto VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1257bad3ecd0Sotto vput(nd.ni_dvp); 1258bad3ecd0Sotto } else { 1259bad3ecd0Sotto error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, 1260bad3ecd0Sotto &nd.ni_cnd, &vattr); 1261bad3ecd0Sotto } 1262bad3ecd0Sotto } else { 1263bad3ecd0Sotto VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1264bad3ecd0Sotto if (nd.ni_dvp == vp) 1265bad3ecd0Sotto vrele(nd.ni_dvp); 1266bad3ecd0Sotto else 1267bad3ecd0Sotto vput(nd.ni_dvp); 1268bad3ecd0Sotto if (vp) 1269bad3ecd0Sotto vrele(vp); 1270bad3ecd0Sotto } 1271bad3ecd0Sotto return (error); 1272bad3ecd0Sotto} 1273bad3ecd0Sotto 1274bad3ecd0Sotto/* 1275bad3ecd0Sotto * Create a named pipe. 1276bad3ecd0Sotto */ 1277bad3ecd0Sotto/* ARGSUSED */ 1278bad3ecd0Sottoint 1279bad3ecd0Sottosys_mkfifo(p, v, retval) 1280bad3ecd0Sotto struct proc *p; 1281bad3ecd0Sotto void *v; 1282bad3ecd0Sotto register_t *retval; 1283bad3ecd0Sotto{ 1284bad3ecd0Sotto#ifndef FIFO 1285bad3ecd0Sotto return (EOPNOTSUPP); 1286bad3ecd0Sotto#else 1287bad3ecd0Sotto register struct sys_mkfifo_args /* { 1288bad3ecd0Sotto syscallarg(char *) path; 1289bad3ecd0Sotto syscallarg(int) mode; 1290bad3ecd0Sotto } */ *uap = v; 1291bad3ecd0Sotto struct vattr vattr; 1292bad3ecd0Sotto int error; 1293bad3ecd0Sotto struct nameidata nd; 1294bad3ecd0Sotto 1295bad3ecd0Sotto NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p); 1296bad3ecd0Sotto if ((error = namei(&nd)) != 0) 1297bad3ecd0Sotto return (error); 1298bad3ecd0Sotto if (nd.ni_vp != NULL) { 1299bad3ecd0Sotto VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1300bad3ecd0Sotto if (nd.ni_dvp == nd.ni_vp) 1301bad3ecd0Sotto vrele(nd.ni_dvp); 1302bad3ecd0Sotto else 1303bad3ecd0Sotto vput(nd.ni_dvp); 1304bad3ecd0Sotto vrele(nd.ni_vp); 1305bad3ecd0Sotto return (EEXIST); 1306bad3ecd0Sotto } 1307bad3ecd0Sotto VATTR_NULL(&vattr); 1308bad3ecd0Sotto vattr.va_type = VFIFO; 1309bad3ecd0Sotto vattr.va_mode = (SCARG(uap, mode) & ALLPERMS) &~ p->p_fd->fd_cmask; 1310bad3ecd0Sotto VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 1311bad3ecd0Sotto return (VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr)); 1312bad3ecd0Sotto#endif /* FIFO */ 1313bad3ecd0Sotto} 1314bad3ecd0Sotto 1315bad3ecd0Sotto/* 1316bad3ecd0Sotto * Make a hard file link. 1317bad3ecd0Sotto */ 1318bad3ecd0Sotto/* ARGSUSED */ 1319bad3ecd0Sottoint 1320bad3ecd0Sottosys_link(p, v, retval) 1321bad3ecd0Sotto struct proc *p; 1322bad3ecd0Sotto void *v; 1323bad3ecd0Sotto register_t *retval; 1324bad3ecd0Sotto{ 1325bad3ecd0Sotto register struct sys_link_args /* { 1326bad3ecd0Sotto syscallarg(char *) path; 1327bad3ecd0Sotto syscallarg(char *) link; 1328bad3ecd0Sotto } */ *uap = v; 1329bad3ecd0Sotto register struct vnode *vp; 1330bad3ecd0Sotto struct nameidata nd; 1331bad3ecd0Sotto int error; 1332bad3ecd0Sotto int flags; 1333bad3ecd0Sotto 1334bad3ecd0Sotto NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 1335bad3ecd0Sotto if ((error = namei(&nd)) != 0) 1336bad3ecd0Sotto return (error); 1337bad3ecd0Sotto vp = nd.ni_vp; 1338bad3ecd0Sotto 1339bad3ecd0Sotto flags = LOCKPARENT; 1340bad3ecd0Sotto if (vp->v_type == VDIR) { 1341bad3ecd0Sotto flags |= STRIPSLASHES; 1342bad3ecd0Sotto } 1343bad3ecd0Sotto 1344bad3ecd0Sotto NDINIT(&nd, CREATE, flags, UIO_USERSPACE, SCARG(uap, link), p); 1345bad3ecd0Sotto if ((error = namei(&nd)) != 0) 1346bad3ecd0Sotto goto out; 1347bad3ecd0Sotto if (nd.ni_vp) { 1348bad3ecd0Sotto VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1349bad3ecd0Sotto if (nd.ni_dvp == nd.ni_vp) 1350bad3ecd0Sotto vrele(nd.ni_dvp); 1351bad3ecd0Sotto else 1352bad3ecd0Sotto vput(nd.ni_dvp); 1353bad3ecd0Sotto vrele(nd.ni_vp); 1354bad3ecd0Sotto error = EEXIST; 1355bad3ecd0Sotto goto out; 1356bad3ecd0Sotto } 1357bad3ecd0Sotto VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 1358bad3ecd0Sotto VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 1359bad3ecd0Sotto error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd); 1360bad3ecd0Sottoout: 1361bad3ecd0Sotto vrele(vp); 1362bad3ecd0Sotto return (error); 1363bad3ecd0Sotto} 1364bad3ecd0Sotto 1365bad3ecd0Sotto/* 1366bad3ecd0Sotto * Make a symbolic link. 1367bad3ecd0Sotto */ 1368bad3ecd0Sotto/* ARGSUSED */ 1369bad3ecd0Sottoint 1370bad3ecd0Sottosys_symlink(p, v, retval) 1371bad3ecd0Sotto struct proc *p; 1372bad3ecd0Sotto void *v; 1373bad3ecd0Sotto register_t *retval; 1374bad3ecd0Sotto{ 1375bad3ecd0Sotto register struct sys_symlink_args /* { 1376bad3ecd0Sotto syscallarg(char *) path; 1377bad3ecd0Sotto syscallarg(char *) link; 1378bad3ecd0Sotto } */ *uap = v; 1379bad3ecd0Sotto struct vattr vattr; 1380bad3ecd0Sotto char *path; 1381bad3ecd0Sotto int error; 1382bad3ecd0Sotto struct nameidata nd; 1383bad3ecd0Sotto 1384bad3ecd0Sotto MALLOC(path, char *, MAXPATHLEN, M_NAMEI, M_WAITOK); 1385bad3ecd0Sotto error = copyinstr(SCARG(uap, path), path, MAXPATHLEN, NULL); 1386bad3ecd0Sotto if (error) 1387bad3ecd0Sotto goto out; 1388bad3ecd0Sotto NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, link), p); 1389bad3ecd0Sotto if ((error = namei(&nd)) != 0) 1390bad3ecd0Sotto goto out; 1391bad3ecd0Sotto if (nd.ni_vp) { 1392bad3ecd0Sotto VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1393bad3ecd0Sotto if (nd.ni_dvp == nd.ni_vp) 1394bad3ecd0Sotto vrele(nd.ni_dvp); 1395bad3ecd0Sotto else 1396bad3ecd0Sotto vput(nd.ni_dvp); 1397bad3ecd0Sotto vrele(nd.ni_vp); 1398bad3ecd0Sotto error = EEXIST; 1399bad3ecd0Sotto goto out; 1400bad3ecd0Sotto } 1401bad3ecd0Sotto VATTR_NULL(&vattr); 1402bad3ecd0Sotto vattr.va_mode = ACCESSPERMS &~ p->p_fd->fd_cmask; 1403bad3ecd0Sotto VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 1404bad3ecd0Sotto error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr, path); 1405bad3ecd0Sottoout: 1406bad3ecd0Sotto FREE(path, M_NAMEI); 1407bad3ecd0Sotto return (error); 1408bad3ecd0Sotto} 1409bad3ecd0Sotto 1410bad3ecd0Sotto/* 1411bad3ecd0Sotto * Delete a whiteout from the filesystem. 1412bad3ecd0Sotto */ 1413bad3ecd0Sotto/* ARGSUSED */ 1414bad3ecd0Sottoint 1415bad3ecd0Sottosys_undelete(p, v, retval) 1416bad3ecd0Sotto struct proc *p; 1417bad3ecd0Sotto void *v; 1418bad3ecd0Sotto register_t *retval; 1419bad3ecd0Sotto{ 1420bad3ecd0Sotto register struct sys_undelete_args /* { 1421bad3ecd0Sotto syscallarg(char *) path; 1422bad3ecd0Sotto } */ *uap = v; 1423bad3ecd0Sotto int error; 1424bad3ecd0Sotto struct nameidata nd; 1425bad3ecd0Sotto 1426bad3ecd0Sotto NDINIT(&nd, DELETE, LOCKPARENT|DOWHITEOUT, UIO_USERSPACE, 1427bad3ecd0Sotto SCARG(uap, path), p); 1428bad3ecd0Sotto error = namei(&nd); 1429bad3ecd0Sotto if (error) 1430bad3ecd0Sotto return (error); 1431bad3ecd0Sotto 1432bad3ecd0Sotto if (nd.ni_vp != NULLVP || !(nd.ni_cnd.cn_flags & ISWHITEOUT)) { 1433bad3ecd0Sotto VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1434bad3ecd0Sotto if (nd.ni_dvp == nd.ni_vp) 1435bad3ecd0Sotto vrele(nd.ni_dvp); 1436bad3ecd0Sotto else 1437bad3ecd0Sotto vput(nd.ni_dvp); 1438bad3ecd0Sotto if (nd.ni_vp) 1439bad3ecd0Sotto vrele(nd.ni_vp); 1440bad3ecd0Sotto return (EEXIST); 1441bad3ecd0Sotto } 1442bad3ecd0Sotto 1443bad3ecd0Sotto VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 1444bad3ecd0Sotto if ((error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, DELETE)) != 0) 1445bad3ecd0Sotto VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1446bad3ecd0Sotto vput(nd.ni_dvp); 1447bad3ecd0Sotto return (error); 1448bad3ecd0Sotto} 1449bad3ecd0Sotto 1450bad3ecd0Sotto/* 1451bad3ecd0Sotto * Delete a name from the filesystem. 1452bad3ecd0Sotto */ 1453bad3ecd0Sotto/* ARGSUSED */ 1454bad3ecd0Sottoint 1455bad3ecd0Sottosys_unlink(p, v, retval) 1456bad3ecd0Sotto struct proc *p; 1457bad3ecd0Sotto void *v; 1458bad3ecd0Sotto register_t *retval; 1459bad3ecd0Sotto{ 1460bad3ecd0Sotto struct sys_unlink_args /* { 1461bad3ecd0Sotto syscallarg(char *) path; 1462bad3ecd0Sotto } */ *uap = v; 1463bad3ecd0Sotto register struct vnode *vp; 1464bad3ecd0Sotto int error; 1465bad3ecd0Sotto struct nameidata nd; 1466bad3ecd0Sotto 1467bad3ecd0Sotto NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE, 1468bad3ecd0Sotto SCARG(uap, path), p); 1469bad3ecd0Sotto if ((error = namei(&nd)) != 0) 1470bad3ecd0Sotto return (error); 1471bad3ecd0Sotto vp = nd.ni_vp; 1472bad3ecd0Sotto 1473bad3ecd0Sotto /* 1474bad3ecd0Sotto * The root of a mounted filesystem cannot be deleted. 1475bad3ecd0Sotto */ 1476bad3ecd0Sotto if (vp->v_flag & VROOT) { 1477bad3ecd0Sotto VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1478bad3ecd0Sotto if (nd.ni_dvp == vp) 1479bad3ecd0Sotto vrele(nd.ni_dvp); 1480bad3ecd0Sotto else 1481bad3ecd0Sotto vput(nd.ni_dvp); 1482bad3ecd0Sotto vput(vp); 1483bad3ecd0Sotto error = EBUSY; 1484bad3ecd0Sotto goto out; 1485bad3ecd0Sotto } 1486bad3ecd0Sotto 1487bad3ecd0Sotto (void)uvm_vnp_uncache(vp); 1488bad3ecd0Sotto 1489bad3ecd0Sotto VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 1490bad3ecd0Sotto VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 1491bad3ecd0Sotto error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); 1492bad3ecd0Sottoout: 1493bad3ecd0Sotto return (error); 1494bad3ecd0Sotto} 1495bad3ecd0Sotto 1496bad3ecd0Sotto/* 1497bad3ecd0Sotto * Reposition read/write file offset. 1498bad3ecd0Sotto */ 1499bad3ecd0Sottoint 1500bad3ecd0Sottosys_lseek(p, v, retval) 1501bad3ecd0Sotto struct proc *p; 1502bad3ecd0Sotto void *v; 1503bad3ecd0Sotto register_t *retval; 1504bad3ecd0Sotto{ 1505bad3ecd0Sotto register struct sys_lseek_args /* { 1506bad3ecd0Sotto syscallarg(int) fd; 1507bad3ecd0Sotto syscallarg(int) pad; 1508bad3ecd0Sotto syscallarg(off_t) offset; 1509bad3ecd0Sotto syscallarg(int) whence; 1510bad3ecd0Sotto } */ *uap = v; 1511bad3ecd0Sotto struct ucred *cred = p->p_ucred; 1512bad3ecd0Sotto register struct filedesc *fdp = p->p_fd; 1513bad3ecd0Sotto register struct file *fp; 1514bad3ecd0Sotto struct vattr vattr; 1515bad3ecd0Sotto struct vnode *vp; 1516bad3ecd0Sotto int error, special; 1517bad3ecd0Sotto 1518bad3ecd0Sotto if ((fp = fd_getfile(fdp, SCARG(uap, fd))) == NULL) 1519bad3ecd0Sotto return (EBADF); 1520bad3ecd0Sotto if (fp->f_type != DTYPE_VNODE) 1521bad3ecd0Sotto return (ESPIPE); 1522bad3ecd0Sotto vp = (struct vnode *)fp->f_data; 1523bad3ecd0Sotto if (vp->v_type == VFIFO) 1524bad3ecd0Sotto return (ESPIPE); 1525bad3ecd0Sotto if (vp->v_type == VCHR) 1526bad3ecd0Sotto special = 1; 1527bad3ecd0Sotto else 1528bad3ecd0Sotto special = 0; 1529bad3ecd0Sotto switch (SCARG(uap, whence)) { 1530bad3ecd0Sotto case SEEK_CUR: 1531bad3ecd0Sotto if (!special && fp->f_offset + SCARG(uap, offset) < 0) 1532bad3ecd0Sotto return (EINVAL); 1533bad3ecd0Sotto fp->f_offset += SCARG(uap, offset); 1534bad3ecd0Sotto break; 1535bad3ecd0Sotto case SEEK_END: 1536bad3ecd0Sotto error = VOP_GETATTR((struct vnode *)fp->f_data, &vattr, 1537bad3ecd0Sotto cred, p); 1538bad3ecd0Sotto if (error) 1539bad3ecd0Sotto return (error); 1540bad3ecd0Sotto if (!special && (off_t)vattr.va_size + SCARG(uap, offset) < 0) 1541bad3ecd0Sotto return (EINVAL); 1542bad3ecd0Sotto fp->f_offset = SCARG(uap, offset) + vattr.va_size; 1543bad3ecd0Sotto break; 1544bad3ecd0Sotto case SEEK_SET: 1545bad3ecd0Sotto if (!special && SCARG(uap, offset) < 0) 1546bad3ecd0Sotto return (EINVAL); 1547bad3ecd0Sotto fp->f_offset = SCARG(uap, offset); 1548bad3ecd0Sotto break; 1549bad3ecd0Sotto default: 1550bad3ecd0Sotto return (EINVAL); 1551bad3ecd0Sotto } 1552bad3ecd0Sotto *(off_t *)retval = fp->f_offset; 1553bad3ecd0Sotto return (0); 1554bad3ecd0Sotto} 1555bad3ecd0Sotto 1556bad3ecd0Sotto/* 1557bad3ecd0Sotto * Check access permissions. 1558bad3ecd0Sotto */ 1559bad3ecd0Sottoint 1560bad3ecd0Sottosys_access(p, v, retval) 1561bad3ecd0Sotto struct proc *p; 1562bad3ecd0Sotto void *v; 1563bad3ecd0Sotto register_t *retval; 1564bad3ecd0Sotto{ 1565bad3ecd0Sotto register struct sys_access_args /* { 1566bad3ecd0Sotto syscallarg(char *) path; 1567bad3ecd0Sotto syscallarg(int) flags; 1568bad3ecd0Sotto } */ *uap = v; 1569bad3ecd0Sotto register struct ucred *cred = p->p_ucred; 1570bad3ecd0Sotto register struct vnode *vp; 1571bad3ecd0Sotto int error, flags, t_gid, t_uid; 1572bad3ecd0Sotto struct nameidata nd; 1573bad3ecd0Sotto 1574bad3ecd0Sotto if (SCARG(uap, flags) & ~(R_OK | W_OK | X_OK)) 1575bad3ecd0Sotto return (EINVAL); 1576bad3ecd0Sotto t_uid = cred->cr_uid; 1577bad3ecd0Sotto t_gid = cred->cr_gid; 1578bad3ecd0Sotto cred->cr_uid = p->p_cred->p_ruid; 1579bad3ecd0Sotto cred->cr_gid = p->p_cred->p_rgid; 1580bad3ecd0Sotto NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, 1581bad3ecd0Sotto SCARG(uap, path), p); 1582bad3ecd0Sotto if ((error = namei(&nd)) != 0) 1583bad3ecd0Sotto goto out1; 1584bad3ecd0Sotto vp = nd.ni_vp; 1585bad3ecd0Sotto 1586bad3ecd0Sotto /* Flags == 0 means only check for existence. */ 1587bad3ecd0Sotto if (SCARG(uap, flags)) { 1588bad3ecd0Sotto flags = 0; 1589bad3ecd0Sotto if (SCARG(uap, flags) & R_OK) 1590bad3ecd0Sotto flags |= VREAD; 1591bad3ecd0Sotto if (SCARG(uap, flags) & W_OK) 1592bad3ecd0Sotto flags |= VWRITE; 1593bad3ecd0Sotto if (SCARG(uap, flags) & X_OK) 1594bad3ecd0Sotto flags |= VEXEC; 1595bad3ecd0Sotto if ((flags & VWRITE) == 0 || (error = vn_writechk(vp)) == 0) 1596bad3ecd0Sotto error = VOP_ACCESS(vp, flags, cred, p); 1597bad3ecd0Sotto } 1598bad3ecd0Sotto vput(vp); 1599bad3ecd0Sottoout1: 1600bad3ecd0Sotto cred->cr_uid = t_uid; 1601bad3ecd0Sotto cred->cr_gid = t_gid; 1602bad3ecd0Sotto return (error); 1603bad3ecd0Sotto} 1604bad3ecd0Sotto 1605bad3ecd0Sotto/* 1606bad3ecd0Sotto * Get file status; this version follows links. 1607bad3ecd0Sotto */ 1608bad3ecd0Sotto/* ARGSUSED */ 1609bad3ecd0Sottoint 1610bad3ecd0Sottosys_stat(p, v, retval) 1611bad3ecd0Sotto struct proc *p; 1612bad3ecd0Sotto void *v; 1613bad3ecd0Sotto register_t *retval; 1614bad3ecd0Sotto{ 1615bad3ecd0Sotto register struct sys_stat_args /* { 1616bad3ecd0Sotto syscallarg(char *) path; 1617bad3ecd0Sotto syscallarg(struct stat *) ub; 1618bad3ecd0Sotto } */ *uap = v; 1619bad3ecd0Sotto struct stat sb; 1620bad3ecd0Sotto int error; 1621bad3ecd0Sotto struct nameidata nd; 1622bad3ecd0Sotto 1623bad3ecd0Sotto NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, 1624bad3ecd0Sotto SCARG(uap, path), p); 1625bad3ecd0Sotto if ((error = namei(&nd)) != 0) 1626bad3ecd0Sotto return (error); 1627bad3ecd0Sotto error = vn_stat(nd.ni_vp, &sb, p); 1628bad3ecd0Sotto vput(nd.ni_vp); 1629bad3ecd0Sotto if (error) 1630bad3ecd0Sotto return (error); 1631bad3ecd0Sotto /* Don't let non-root see generation numbers (for NFS security) */ 1632bad3ecd0Sotto if (suser(p->p_ucred, &p->p_acflag)) 1633bad3ecd0Sotto sb.st_gen = 0; 1634bad3ecd0Sotto error = copyout((caddr_t)&sb, (caddr_t)SCARG(uap, ub), sizeof (sb)); 1635bad3ecd0Sotto return (error); 1636bad3ecd0Sotto} 1637bad3ecd0Sotto 1638bad3ecd0Sotto/* 1639bad3ecd0Sotto * Get file status; this version does not follow links. 1640bad3ecd0Sotto */ 1641bad3ecd0Sotto/* ARGSUSED */ 1642bad3ecd0Sottoint 1643bad3ecd0Sottosys_lstat(p, v, retval) 1644bad3ecd0Sotto struct proc *p; 1645bad3ecd0Sotto void *v; 1646bad3ecd0Sotto register_t *retval; 1647bad3ecd0Sotto{ 1648bad3ecd0Sotto register struct sys_lstat_args /* { 1649bad3ecd0Sotto syscallarg(char *) path; 1650bad3ecd0Sotto syscallarg(struct stat *) ub; 1651bad3ecd0Sotto } */ *uap = v; 1652bad3ecd0Sotto struct stat sb; 1653bad3ecd0Sotto int error; 1654bad3ecd0Sotto struct nameidata nd; 1655bad3ecd0Sotto 1656bad3ecd0Sotto NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, 1657bad3ecd0Sotto SCARG(uap, path), p); 1658bad3ecd0Sotto if ((error = namei(&nd)) != 0) 1659bad3ecd0Sotto return (error); 1660bad3ecd0Sotto error = vn_stat(nd.ni_vp, &sb, p); 1661bad3ecd0Sotto vput(nd.ni_vp); 1662bad3ecd0Sotto if (error) 1663bad3ecd0Sotto return (error); 1664bad3ecd0Sotto /* Don't let non-root see generation numbers (for NFS security) */ 1665bad3ecd0Sotto if (suser(p->p_ucred, &p->p_acflag)) 1666bad3ecd0Sotto sb.st_gen = 0; 1667bad3ecd0Sotto error = copyout((caddr_t)&sb, (caddr_t)SCARG(uap, ub), sizeof (sb)); 1668bad3ecd0Sotto return (error); 1669bad3ecd0Sotto} 1670bad3ecd0Sotto 1671bad3ecd0Sotto/* 1672bad3ecd0Sotto * Get configurable pathname variables. 1673bad3ecd0Sotto */ 1674bad3ecd0Sotto/* ARGSUSED */ 1675bad3ecd0Sottoint 1676bad3ecd0Sottosys_pathconf(p, v, retval) 1677bad3ecd0Sotto struct proc *p; 1678bad3ecd0Sotto void *v; 1679bad3ecd0Sotto register_t *retval; 1680bad3ecd0Sotto{ 1681bad3ecd0Sotto register struct sys_pathconf_args /* { 1682bad3ecd0Sotto syscallarg(char *) path; 1683bad3ecd0Sotto syscallarg(int) name; 1684bad3ecd0Sotto } */ *uap = v; 1685bad3ecd0Sotto int error; 1686bad3ecd0Sotto struct nameidata nd; 1687bad3ecd0Sotto 1688bad3ecd0Sotto NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, 1689bad3ecd0Sotto SCARG(uap, path), p); 1690bad3ecd0Sotto if ((error = namei(&nd)) != 0) 1691bad3ecd0Sotto return (error); 1692bad3ecd0Sotto error = VOP_PATHCONF(nd.ni_vp, SCARG(uap, name), retval); 1693bad3ecd0Sotto vput(nd.ni_vp); 1694bad3ecd0Sotto return (error); 1695bad3ecd0Sotto} 1696bad3ecd0Sotto 1697bad3ecd0Sotto/* 1698bad3ecd0Sotto * Return target name of a symbolic link. 1699bad3ecd0Sotto */ 1700bad3ecd0Sotto/* ARGSUSED */ 1701bad3ecd0Sottoint 1702bad3ecd0Sottosys_readlink(p, v, retval) 1703bad3ecd0Sotto struct proc *p; 1704bad3ecd0Sotto void *v; 1705bad3ecd0Sotto register_t *retval; 1706bad3ecd0Sotto{ 1707bad3ecd0Sotto register struct sys_readlink_args /* { 1708bad3ecd0Sotto syscallarg(char *) path; 1709bad3ecd0Sotto syscallarg(char *) buf; 1710bad3ecd0Sotto syscallarg(size_t) count; 1711bad3ecd0Sotto } */ *uap = v; 1712bad3ecd0Sotto register struct vnode *vp; 1713bad3ecd0Sotto struct iovec aiov; 1714bad3ecd0Sotto struct uio auio; 1715bad3ecd0Sotto int error; 1716bad3ecd0Sotto struct nameidata nd; 1717bad3ecd0Sotto 1718bad3ecd0Sotto NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, 1719bad3ecd0Sotto SCARG(uap, path), p); 1720bad3ecd0Sotto if ((error = namei(&nd)) != 0) 1721bad3ecd0Sotto return (error); 1722bad3ecd0Sotto vp = nd.ni_vp; 1723bad3ecd0Sotto if (vp->v_type != VLNK) 1724bad3ecd0Sotto error = EINVAL; 1725bad3ecd0Sotto else { 1726bad3ecd0Sotto aiov.iov_base = SCARG(uap, buf); 1727bad3ecd0Sotto aiov.iov_len = SCARG(uap, count); 1728bad3ecd0Sotto auio.uio_iov = &aiov; 1729bad3ecd0Sotto auio.uio_iovcnt = 1; 1730bad3ecd0Sotto auio.uio_offset = 0; 1731bad3ecd0Sotto auio.uio_rw = UIO_READ; 1732bad3ecd0Sotto auio.uio_segflg = UIO_USERSPACE; 1733bad3ecd0Sotto auio.uio_procp = p; 1734bad3ecd0Sotto auio.uio_resid = SCARG(uap, count); 1735bad3ecd0Sotto error = VOP_READLINK(vp, &auio, p->p_ucred); 1736bad3ecd0Sotto } 1737bad3ecd0Sotto vput(vp); 1738bad3ecd0Sotto *retval = SCARG(uap, count) - auio.uio_resid; 1739bad3ecd0Sotto return (error); 1740bad3ecd0Sotto} 1741bad3ecd0Sotto 1742bad3ecd0Sotto/* 1743bad3ecd0Sotto * Change flags of a file given a path name. 1744bad3ecd0Sotto */ 1745bad3ecd0Sotto/* ARGSUSED */ 1746bad3ecd0Sottoint 1747bad3ecd0Sottosys_chflags(p, v, retval) 1748bad3ecd0Sotto struct proc *p; 1749bad3ecd0Sotto void *v; 1750bad3ecd0Sotto register_t *retval; 1751bad3ecd0Sotto{ 1752bad3ecd0Sotto register struct sys_chflags_args /* { 1753bad3ecd0Sotto syscallarg(char *) path; 1754bad3ecd0Sotto syscallarg(unsigned int) flags; 1755bad3ecd0Sotto } */ *uap = v; 1756bad3ecd0Sotto register struct vnode *vp; 1757bad3ecd0Sotto struct vattr vattr; 1758bad3ecd0Sotto int error; 1759bad3ecd0Sotto struct nameidata nd; 1760bad3ecd0Sotto 1761bad3ecd0Sotto NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 1762bad3ecd0Sotto if ((error = namei(&nd)) != 0) 1763bad3ecd0Sotto return (error); 1764bad3ecd0Sotto vp = nd.ni_vp; 1765bad3ecd0Sotto VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 1766bad3ecd0Sotto vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 1767bad3ecd0Sotto if (vp->v_mount->mnt_flag & MNT_RDONLY) 1768bad3ecd0Sotto error = EROFS; 1769bad3ecd0Sotto else if (SCARG(uap, flags) == VNOVAL) 1770bad3ecd0Sotto error = EINVAL; 1771bad3ecd0Sotto else { 1772bad3ecd0Sotto if (suser(p->p_ucred, &p->p_acflag)) { 1773bad3ecd0Sotto if ((error = VOP_GETATTR(vp, &vattr, p->p_ucred, p)) != 0) 1774bad3ecd0Sotto goto out; 1775bad3ecd0Sotto if (vattr.va_type == VCHR || vattr.va_type == VBLK) { 1776bad3ecd0Sotto error = EINVAL; 1777bad3ecd0Sotto goto out; 1778bad3ecd0Sotto } 1779bad3ecd0Sotto } 1780bad3ecd0Sotto VATTR_NULL(&vattr); 1781bad3ecd0Sotto vattr.va_flags = SCARG(uap, flags); 1782bad3ecd0Sotto error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 1783bad3ecd0Sotto } 1784bad3ecd0Sottoout: 1785bad3ecd0Sotto vput(vp); 1786bad3ecd0Sotto return (error); 1787bad3ecd0Sotto} 1788bad3ecd0Sotto 1789bad3ecd0Sotto/* 1790bad3ecd0Sotto * Change flags of a file given a file descriptor. 1791bad3ecd0Sotto */ 1792bad3ecd0Sotto/* ARGSUSED */ 1793bad3ecd0Sottoint 1794bad3ecd0Sottosys_fchflags(p, v, retval) 1795bad3ecd0Sotto struct proc *p; 1796bad3ecd0Sotto void *v; 1797bad3ecd0Sotto register_t *retval; 1798bad3ecd0Sotto{ 1799bad3ecd0Sotto struct sys_fchflags_args /* { 1800bad3ecd0Sotto syscallarg(int) fd; 1801bad3ecd0Sotto syscallarg(unsigned int) flags; 1802bad3ecd0Sotto } */ *uap = v; 1803bad3ecd0Sotto struct vattr vattr; 1804bad3ecd0Sotto struct vnode *vp; 1805bad3ecd0Sotto struct file *fp; 1806bad3ecd0Sotto int error; 1807bad3ecd0Sotto 1808bad3ecd0Sotto if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0) 1809bad3ecd0Sotto return (error); 1810bad3ecd0Sotto vp = (struct vnode *)fp->f_data; 1811bad3ecd0Sotto VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 1812bad3ecd0Sotto vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 1813bad3ecd0Sotto if (vp->v_mount->mnt_flag & MNT_RDONLY) 1814bad3ecd0Sotto error = EROFS; 1815bad3ecd0Sotto else if (SCARG(uap, flags) == VNOVAL) 1816bad3ecd0Sotto error = EINVAL; 1817bad3ecd0Sotto else { 1818bad3ecd0Sotto if (suser(p->p_ucred, &p->p_acflag)) { 1819bad3ecd0Sotto if ((error = VOP_GETATTR(vp, &vattr, p->p_ucred, p)) 1820bad3ecd0Sotto != 0) 1821bad3ecd0Sotto goto out; 1822bad3ecd0Sotto if (vattr.va_type == VCHR || vattr.va_type == VBLK) { 1823bad3ecd0Sotto error = EINVAL; 1824bad3ecd0Sotto goto out; 1825bad3ecd0Sotto } 1826bad3ecd0Sotto } 1827bad3ecd0Sotto VATTR_NULL(&vattr); 1828bad3ecd0Sotto vattr.va_flags = SCARG(uap, flags); 1829bad3ecd0Sotto error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 1830bad3ecd0Sotto } 1831bad3ecd0Sottoout: 1832bad3ecd0Sotto VOP_UNLOCK(vp, 0, p); 1833bad3ecd0Sotto FRELE(fp); 1834bad3ecd0Sotto return (error); 1835bad3ecd0Sotto} 1836bad3ecd0Sotto 1837bad3ecd0Sotto/* 1838bad3ecd0Sotto * Change mode of a file given path name. 1839bad3ecd0Sotto */ 1840bad3ecd0Sotto/* ARGSUSED */ 1841bad3ecd0Sottoint 1842bad3ecd0Sottosys_chmod(p, v, retval) 1843bad3ecd0Sotto struct proc *p; 1844bad3ecd0Sotto void *v; 1845bad3ecd0Sotto register_t *retval; 1846bad3ecd0Sotto{ 1847bad3ecd0Sotto register struct sys_chmod_args /* { 1848bad3ecd0Sotto syscallarg(char *) path; 1849bad3ecd0Sotto syscallarg(int) mode; 1850bad3ecd0Sotto } */ *uap = v; 1851bad3ecd0Sotto register struct vnode *vp; 1852bad3ecd0Sotto struct vattr vattr; 1853bad3ecd0Sotto int error; 1854bad3ecd0Sotto struct nameidata nd; 1855bad3ecd0Sotto 1856bad3ecd0Sotto if (SCARG(uap, mode) & ~(S_IFMT | ALLPERMS)) 1857bad3ecd0Sotto return (EINVAL); 1858bad3ecd0Sotto 1859bad3ecd0Sotto NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 1860bad3ecd0Sotto if ((error = namei(&nd)) != 0) 1861bad3ecd0Sotto return (error); 1862bad3ecd0Sotto vp = nd.ni_vp; 1863bad3ecd0Sotto VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 1864bad3ecd0Sotto vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 1865bad3ecd0Sotto if (vp->v_mount->mnt_flag & MNT_RDONLY) 1866bad3ecd0Sotto error = EROFS; 1867bad3ecd0Sotto else { 1868bad3ecd0Sotto VATTR_NULL(&vattr); 1869bad3ecd0Sotto vattr.va_mode = SCARG(uap, mode) & ALLPERMS; 1870bad3ecd0Sotto error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 1871bad3ecd0Sotto } 1872bad3ecd0Sotto vput(vp); 1873bad3ecd0Sotto return (error); 1874bad3ecd0Sotto} 1875bad3ecd0Sotto 1876bad3ecd0Sotto/* 1877bad3ecd0Sotto * Change mode of a file given a file descriptor. 1878bad3ecd0Sotto */ 1879bad3ecd0Sotto/* ARGSUSED */ 1880bad3ecd0Sottoint 1881bad3ecd0Sottosys_fchmod(p, v, retval) 1882bad3ecd0Sotto struct proc *p; 1883bad3ecd0Sotto void *v; 1884bad3ecd0Sotto register_t *retval; 1885bad3ecd0Sotto{ 1886bad3ecd0Sotto struct sys_fchmod_args /* { 1887bad3ecd0Sotto syscallarg(int) fd; 1888bad3ecd0Sotto syscallarg(int) mode; 1889bad3ecd0Sotto } */ *uap = v; 1890bad3ecd0Sotto struct vattr vattr; 1891bad3ecd0Sotto struct vnode *vp; 1892bad3ecd0Sotto struct file *fp; 1893bad3ecd0Sotto int error; 1894bad3ecd0Sotto 1895bad3ecd0Sotto if (SCARG(uap, mode) & ~(S_IFMT | ALLPERMS)) 1896bad3ecd0Sotto return (EINVAL); 1897bad3ecd0Sotto 1898bad3ecd0Sotto if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0) 1899bad3ecd0Sotto return (error); 1900bad3ecd0Sotto vp = (struct vnode *)fp->f_data; 1901bad3ecd0Sotto VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 1902bad3ecd0Sotto vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 1903bad3ecd0Sotto if (vp->v_mount->mnt_flag & MNT_RDONLY) 1904bad3ecd0Sotto error = EROFS; 1905bad3ecd0Sotto else { 1906bad3ecd0Sotto VATTR_NULL(&vattr); 1907bad3ecd0Sotto vattr.va_mode = SCARG(uap, mode) & ALLPERMS; 1908bad3ecd0Sotto error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 1909bad3ecd0Sotto } 1910bad3ecd0Sotto VOP_UNLOCK(vp, 0, p); 1911bad3ecd0Sotto FRELE(fp); 1912bad3ecd0Sotto return (error); 1913bad3ecd0Sotto} 1914bad3ecd0Sotto 1915bad3ecd0Sotto/* 1916bad3ecd0Sotto * Set ownership given a path name. 1917bad3ecd0Sotto */ 1918bad3ecd0Sotto/* ARGSUSED */ 1919bad3ecd0Sottoint 1920bad3ecd0Sottosys_chown(p, v, retval) 1921bad3ecd0Sotto struct proc *p; 1922bad3ecd0Sotto void *v; 1923bad3ecd0Sotto register_t *retval; 1924bad3ecd0Sotto{ 1925bad3ecd0Sotto register struct sys_chown_args /* { 1926bad3ecd0Sotto syscallarg(char *) path; 1927bad3ecd0Sotto syscallarg(int) uid; 1928bad3ecd0Sotto syscallarg(int) gid; 1929bad3ecd0Sotto } */ *uap = v; 1930bad3ecd0Sotto register struct vnode *vp; 1931bad3ecd0Sotto struct vattr vattr; 1932bad3ecd0Sotto int error; 1933bad3ecd0Sotto struct nameidata nd; 1934bad3ecd0Sotto u_short mode; 1935bad3ecd0Sotto 1936bad3ecd0Sotto NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 1937bad3ecd0Sotto if ((error = namei(&nd)) != 0) 1938bad3ecd0Sotto return (error); 1939bad3ecd0Sotto vp = nd.ni_vp; 1940bad3ecd0Sotto VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 1941bad3ecd0Sotto vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 1942bad3ecd0Sotto if (vp->v_mount->mnt_flag & MNT_RDONLY) 1943bad3ecd0Sotto error = EROFS; 1944bad3ecd0Sotto else { 1945bad3ecd0Sotto if ((SCARG(uap, uid) != -1 || SCARG(uap, gid) != -1) && 1946bad3ecd0Sotto (suser(p->p_ucred, &p->p_acflag) || suid_clear)) { 1947bad3ecd0Sotto error = VOP_GETATTR(vp, &vattr, p->p_ucred, p); 1948bad3ecd0Sotto if (error) 1949bad3ecd0Sotto goto out; 1950bad3ecd0Sotto mode = vattr.va_mode & ~(VSUID | VSGID); 1951bad3ecd0Sotto if (mode == vattr.va_mode) 1952bad3ecd0Sotto mode = VNOVAL; 1953bad3ecd0Sotto } 1954bad3ecd0Sotto else 1955bad3ecd0Sotto mode = VNOVAL; 1956bad3ecd0Sotto VATTR_NULL(&vattr); 1957bad3ecd0Sotto vattr.va_uid = SCARG(uap, uid); 1958bad3ecd0Sotto vattr.va_gid = SCARG(uap, gid); 1959bad3ecd0Sotto vattr.va_mode = mode; 1960bad3ecd0Sotto error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 1961bad3ecd0Sotto } 1962bad3ecd0Sottoout: 1963bad3ecd0Sotto vput(vp); 1964bad3ecd0Sotto return (error); 1965bad3ecd0Sotto} 1966bad3ecd0Sotto 1967bad3ecd0Sotto/* 1968bad3ecd0Sotto * Set ownership given a path name, without following links. 1969bad3ecd0Sotto */ 1970bad3ecd0Sotto/* ARGSUSED */ 1971bad3ecd0Sottoint 1972bad3ecd0Sottosys_lchown(p, v, retval) 1973bad3ecd0Sotto struct proc *p; 1974bad3ecd0Sotto void *v; 1975bad3ecd0Sotto register_t *retval; 1976bad3ecd0Sotto{ 1977bad3ecd0Sotto register struct sys_lchown_args /* { 1978bad3ecd0Sotto syscallarg(char *) path; 1979bad3ecd0Sotto syscallarg(int) uid; 1980bad3ecd0Sotto syscallarg(int) gid; 1981bad3ecd0Sotto } */ *uap = v; 1982bad3ecd0Sotto register struct vnode *vp; 1983bad3ecd0Sotto struct vattr vattr; 1984bad3ecd0Sotto int error; 1985bad3ecd0Sotto struct nameidata nd; 1986bad3ecd0Sotto u_short mode; 1987bad3ecd0Sotto 1988bad3ecd0Sotto NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 1989bad3ecd0Sotto if ((error = namei(&nd)) != 0) 1990bad3ecd0Sotto return (error); 1991bad3ecd0Sotto vp = nd.ni_vp; 1992bad3ecd0Sotto VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 1993bad3ecd0Sotto vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 1994bad3ecd0Sotto if (vp->v_mount->mnt_flag & MNT_RDONLY) 1995bad3ecd0Sotto error = EROFS; 1996bad3ecd0Sotto else { 1997bad3ecd0Sotto if ((SCARG(uap, uid) != -1 || SCARG(uap, gid) != -1) && 1998bad3ecd0Sotto (suser(p->p_ucred, &p->p_acflag) || suid_clear)) { 1999bad3ecd0Sotto error = VOP_GETATTR(vp, &vattr, p->p_ucred, p); 2000bad3ecd0Sotto if (error) 2001bad3ecd0Sotto goto out; 2002bad3ecd0Sotto mode = vattr.va_mode & ~(VSUID | VSGID); 2003bad3ecd0Sotto if (mode == vattr.va_mode) 2004bad3ecd0Sotto mode = VNOVAL; 2005bad3ecd0Sotto } 2006bad3ecd0Sotto else 2007bad3ecd0Sotto mode = VNOVAL; 2008bad3ecd0Sotto VATTR_NULL(&vattr); 2009bad3ecd0Sotto vattr.va_uid = SCARG(uap, uid); 2010bad3ecd0Sotto vattr.va_gid = SCARG(uap, gid); 2011bad3ecd0Sotto vattr.va_mode = mode; 2012bad3ecd0Sotto error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 2013bad3ecd0Sotto } 2014bad3ecd0Sottoout: 2015bad3ecd0Sotto vput(vp); 2016bad3ecd0Sotto return (error); 2017bad3ecd0Sotto} 2018bad3ecd0Sotto 2019bad3ecd0Sotto/* 2020bad3ecd0Sotto * Set ownership given a file descriptor. 2021bad3ecd0Sotto */ 2022bad3ecd0Sotto/* ARGSUSED */ 2023bad3ecd0Sottoint 2024bad3ecd0Sottosys_fchown(p, v, retval) 2025bad3ecd0Sotto struct proc *p; 2026bad3ecd0Sotto void *v; 2027bad3ecd0Sotto register_t *retval; 2028bad3ecd0Sotto{ 2029bad3ecd0Sotto struct sys_fchown_args /* { 2030bad3ecd0Sotto syscallarg(int) fd; 2031bad3ecd0Sotto syscallarg(int) uid; 2032bad3ecd0Sotto syscallarg(int) gid; 2033bad3ecd0Sotto } */ *uap = v; 2034bad3ecd0Sotto struct vnode *vp; 2035bad3ecd0Sotto struct vattr vattr; 2036bad3ecd0Sotto int error; 2037bad3ecd0Sotto struct file *fp; 2038bad3ecd0Sotto u_short mode; 2039bad3ecd0Sotto 2040bad3ecd0Sotto if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0) 2041bad3ecd0Sotto return (error); 2042bad3ecd0Sotto vp = (struct vnode *)fp->f_data; 2043bad3ecd0Sotto VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 2044bad3ecd0Sotto vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 2045bad3ecd0Sotto if (vp->v_mount->mnt_flag & MNT_RDONLY) 2046bad3ecd0Sotto error = EROFS; 2047bad3ecd0Sotto else { 2048bad3ecd0Sotto if ((SCARG(uap, uid) != -1 || SCARG(uap, gid) != -1) && 2049bad3ecd0Sotto (suser(p->p_ucred, &p->p_acflag) || suid_clear)) { 2050bad3ecd0Sotto error = VOP_GETATTR(vp, &vattr, p->p_ucred, p); 2051bad3ecd0Sotto if (error) 2052bad3ecd0Sotto goto out; 2053bad3ecd0Sotto mode = vattr.va_mode & ~(VSUID | VSGID); 2054bad3ecd0Sotto if (mode == vattr.va_mode) 2055bad3ecd0Sotto mode = VNOVAL; 2056bad3ecd0Sotto } else 2057bad3ecd0Sotto mode = VNOVAL; 2058bad3ecd0Sotto VATTR_NULL(&vattr); 2059bad3ecd0Sotto vattr.va_uid = SCARG(uap, uid); 2060bad3ecd0Sotto vattr.va_gid = SCARG(uap, gid); 2061bad3ecd0Sotto vattr.va_mode = mode; 2062bad3ecd0Sotto error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 2063bad3ecd0Sotto } 2064bad3ecd0Sottoout: 2065bad3ecd0Sotto VOP_UNLOCK(vp, 0, p); 2066bad3ecd0Sotto FRELE(fp); 2067bad3ecd0Sotto return (error); 2068bad3ecd0Sotto} 2069bad3ecd0Sotto 2070bad3ecd0Sotto/* 2071bad3ecd0Sotto * Set the access and modification times given a path name. 2072bad3ecd0Sotto */ 2073bad3ecd0Sotto/* ARGSUSED */ 2074bad3ecd0Sottoint 2075bad3ecd0Sottosys_utimes(p, v, retval) 2076bad3ecd0Sotto struct proc *p; 2077bad3ecd0Sotto void *v; 2078bad3ecd0Sotto register_t *retval; 2079bad3ecd0Sotto{ 2080bad3ecd0Sotto register struct sys_utimes_args /* { 2081bad3ecd0Sotto syscallarg(char *) path; 2082bad3ecd0Sotto syscallarg(struct timeval *) tptr; 2083bad3ecd0Sotto } */ *uap = v; 2084bad3ecd0Sotto register struct vnode *vp; 2085bad3ecd0Sotto struct timeval tv[2]; 2086bad3ecd0Sotto struct vattr vattr; 2087bad3ecd0Sotto int error; 2088bad3ecd0Sotto struct nameidata nd; 2089bad3ecd0Sotto 2090bad3ecd0Sotto VATTR_NULL(&vattr); 2091bad3ecd0Sotto if (SCARG(uap, tptr) == NULL) { 2092bad3ecd0Sotto microtime(&tv[0]); 2093bad3ecd0Sotto tv[1] = tv[0]; 2094bad3ecd0Sotto vattr.va_vaflags |= VA_UTIMES_NULL; 2095bad3ecd0Sotto } else { 2096bad3ecd0Sotto error = copyin((caddr_t)SCARG(uap, tptr), (caddr_t)tv, 2097bad3ecd0Sotto sizeof (tv)); 2098bad3ecd0Sotto if (error) 2099bad3ecd0Sotto return (error); 2100bad3ecd0Sotto /* XXX workaround timeval matching the VFS constant VNOVAL */ 2101bad3ecd0Sotto if (tv[0].tv_sec == VNOVAL) 2102bad3ecd0Sotto tv[0].tv_sec = VNOVAL - 1; 2103bad3ecd0Sotto if (tv[1].tv_sec == VNOVAL) 2104bad3ecd0Sotto tv[1].tv_sec = VNOVAL - 1; 2105bad3ecd0Sotto } 2106bad3ecd0Sotto NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 2107bad3ecd0Sotto if ((error = namei(&nd)) != 0) 2108bad3ecd0Sotto return (error); 2109bad3ecd0Sotto vp = nd.ni_vp; 2110bad3ecd0Sotto VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 2111bad3ecd0Sotto vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 2112bad3ecd0Sotto if (vp->v_mount->mnt_flag & MNT_RDONLY) 2113bad3ecd0Sotto error = EROFS; 2114bad3ecd0Sotto else { 2115bad3ecd0Sotto vattr.va_atime.tv_sec = tv[0].tv_sec; 2116bad3ecd0Sotto vattr.va_atime.tv_nsec = tv[0].tv_usec * 1000; 2117bad3ecd0Sotto vattr.va_mtime.tv_sec = tv[1].tv_sec; 2118bad3ecd0Sotto vattr.va_mtime.tv_nsec = tv[1].tv_usec * 1000; 2119bad3ecd0Sotto error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 2120bad3ecd0Sotto } 2121bad3ecd0Sotto vput(vp); 2122bad3ecd0Sotto return (error); 2123bad3ecd0Sotto} 2124bad3ecd0Sotto 2125bad3ecd0Sotto 2126bad3ecd0Sotto/* 2127bad3ecd0Sotto * Set the access and modification times given a file descriptor. 2128bad3ecd0Sotto */ 2129bad3ecd0Sotto/* ARGSUSED */ 2130bad3ecd0Sottoint 2131bad3ecd0Sottosys_futimes(p, v, retval) 2132bad3ecd0Sotto struct proc *p; 2133bad3ecd0Sotto void *v; 2134bad3ecd0Sotto register_t *retval; 2135bad3ecd0Sotto{ 2136bad3ecd0Sotto register struct sys_futimes_args /* { 2137bad3ecd0Sotto syscallarg(int) fd; 2138bad3ecd0Sotto syscallarg(struct timeval *) tptr; 2139bad3ecd0Sotto } */ *uap = v; 2140bad3ecd0Sotto struct vnode *vp; 2141bad3ecd0Sotto struct timeval tv[2]; 2142bad3ecd0Sotto struct vattr vattr; 2143bad3ecd0Sotto int error; 2144bad3ecd0Sotto struct file *fp; 2145bad3ecd0Sotto 2146bad3ecd0Sotto VATTR_NULL(&vattr); 2147bad3ecd0Sotto if (SCARG(uap, tptr) == NULL) { 2148bad3ecd0Sotto microtime(&tv[0]); 2149bad3ecd0Sotto tv[1] = tv[0]; 2150bad3ecd0Sotto vattr.va_vaflags |= VA_UTIMES_NULL; 2151bad3ecd0Sotto } else { 2152bad3ecd0Sotto error = copyin((caddr_t)SCARG(uap, tptr), (caddr_t)tv, 2153bad3ecd0Sotto sizeof (tv)); 2154bad3ecd0Sotto if (error) 2155bad3ecd0Sotto return (error); 2156bad3ecd0Sotto /* XXX workaround timeval matching the VFS constant VNOVAL */ 2157bad3ecd0Sotto if (tv[0].tv_sec == VNOVAL) 2158bad3ecd0Sotto tv[0].tv_sec = VNOVAL - 1; 2159bad3ecd0Sotto if (tv[1].tv_sec == VNOVAL) 2160bad3ecd0Sotto tv[1].tv_sec = VNOVAL - 1; 2161bad3ecd0Sotto } 2162bad3ecd0Sotto if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0) 2163bad3ecd0Sotto return (error); 2164bad3ecd0Sotto vp = (struct vnode *)fp->f_data; 2165bad3ecd0Sotto VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 2166bad3ecd0Sotto vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 2167bad3ecd0Sotto if (vp->v_mount->mnt_flag & MNT_RDONLY) 2168bad3ecd0Sotto error = EROFS; 2169bad3ecd0Sotto else { 2170bad3ecd0Sotto vattr.va_atime.tv_sec = tv[0].tv_sec; 2171bad3ecd0Sotto vattr.va_atime.tv_nsec = tv[0].tv_usec * 1000; 2172bad3ecd0Sotto vattr.va_mtime.tv_sec = tv[1].tv_sec; 2173bad3ecd0Sotto vattr.va_mtime.tv_nsec = tv[1].tv_usec * 1000; 2174bad3ecd0Sotto error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 2175bad3ecd0Sotto } 2176bad3ecd0Sotto VOP_UNLOCK(vp, 0, p); 2177bad3ecd0Sotto FRELE(fp); 2178bad3ecd0Sotto return (error); 2179bad3ecd0Sotto} 2180bad3ecd0Sotto 2181bad3ecd0Sotto/* 2182bad3ecd0Sotto * Truncate a file given its path name. 2183bad3ecd0Sotto */ 2184bad3ecd0Sotto/* ARGSUSED */ 2185bad3ecd0Sottoint 2186bad3ecd0Sottosys_truncate(p, v, retval) 2187bad3ecd0Sotto struct proc *p; 2188bad3ecd0Sotto void *v; 2189bad3ecd0Sotto register_t *retval; 2190bad3ecd0Sotto{ 2191bad3ecd0Sotto register struct sys_truncate_args /* { 2192bad3ecd0Sotto syscallarg(char *) path; 2193bad3ecd0Sotto syscallarg(int) pad; 2194bad3ecd0Sotto syscallarg(off_t) length; 2195bad3ecd0Sotto } */ *uap = v; 2196bad3ecd0Sotto register struct vnode *vp; 2197bad3ecd0Sotto struct vattr vattr; 2198bad3ecd0Sotto int error; 2199bad3ecd0Sotto struct nameidata nd; 2200bad3ecd0Sotto 2201bad3ecd0Sotto NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 2202bad3ecd0Sotto if ((error = namei(&nd)) != 0) 2203bad3ecd0Sotto return (error); 2204bad3ecd0Sotto vp = nd.ni_vp; 2205bad3ecd0Sotto VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 2206bad3ecd0Sotto vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 2207bad3ecd0Sotto if (vp->v_type == VDIR) 2208bad3ecd0Sotto error = EISDIR; 2209bad3ecd0Sotto else if ((error = vn_writechk(vp)) == 0 && 2210bad3ecd0Sotto (error = VOP_ACCESS(vp, VWRITE, p->p_ucred, p)) == 0) { 2211bad3ecd0Sotto VATTR_NULL(&vattr); 2212bad3ecd0Sotto vattr.va_size = SCARG(uap, length); 2213bad3ecd0Sotto error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 2214bad3ecd0Sotto } 2215bad3ecd0Sotto vput(vp); 2216bad3ecd0Sotto return (error); 2217bad3ecd0Sotto} 2218bad3ecd0Sotto 2219bad3ecd0Sotto/* 2220bad3ecd0Sotto * Truncate a file given a file descriptor. 2221bad3ecd0Sotto */ 2222bad3ecd0Sotto/* ARGSUSED */ 2223bad3ecd0Sottoint 2224bad3ecd0Sottosys_ftruncate(p, v, retval) 2225bad3ecd0Sotto struct proc *p; 2226bad3ecd0Sotto void *v; 2227bad3ecd0Sotto register_t *retval; 2228bad3ecd0Sotto{ 2229bad3ecd0Sotto struct sys_ftruncate_args /* { 2230bad3ecd0Sotto syscallarg(int) fd; 2231bad3ecd0Sotto syscallarg(int) pad; 2232bad3ecd0Sotto syscallarg(off_t) length; 2233bad3ecd0Sotto } */ *uap = v; 2234bad3ecd0Sotto struct vattr vattr; 2235bad3ecd0Sotto struct vnode *vp; 2236bad3ecd0Sotto struct file *fp; 2237bad3ecd0Sotto int error; 2238bad3ecd0Sotto 2239bad3ecd0Sotto if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0) 2240bad3ecd0Sotto return (error); 2241bad3ecd0Sotto if ((fp->f_flag & FWRITE) == 0) { 2242bad3ecd0Sotto error = EINVAL; 2243bad3ecd0Sotto goto bad; 2244bad3ecd0Sotto } 2245bad3ecd0Sotto vp = (struct vnode *)fp->f_data; 2246bad3ecd0Sotto VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 2247bad3ecd0Sotto vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 2248bad3ecd0Sotto if (vp->v_type == VDIR) 2249bad3ecd0Sotto error = EISDIR; 2250bad3ecd0Sotto else if ((error = vn_writechk(vp)) == 0) { 2251bad3ecd0Sotto VATTR_NULL(&vattr); 2252bad3ecd0Sotto vattr.va_size = SCARG(uap, length); 2253bad3ecd0Sotto error = VOP_SETATTR(vp, &vattr, fp->f_cred, p); 2254bad3ecd0Sotto } 2255bad3ecd0Sotto VOP_UNLOCK(vp, 0, p); 2256bad3ecd0Sottobad: 2257bad3ecd0Sotto FRELE(fp); 2258bad3ecd0Sotto return (error); 2259bad3ecd0Sotto} 2260bad3ecd0Sotto 2261bad3ecd0Sotto/* 2262bad3ecd0Sotto * Sync an open file. 2263bad3ecd0Sotto */ 2264bad3ecd0Sotto/* ARGSUSED */ 2265bad3ecd0Sottoint 2266bad3ecd0Sottosys_fsync(p, v, retval) 2267bad3ecd0Sotto struct proc *p; 2268bad3ecd0Sotto void *v; 2269bad3ecd0Sotto register_t *retval; 2270bad3ecd0Sotto{ 2271bad3ecd0Sotto struct sys_fsync_args /* { 2272bad3ecd0Sotto syscallarg(int) fd; 2273bad3ecd0Sotto } */ *uap = v; 2274bad3ecd0Sotto struct vnode *vp; 2275bad3ecd0Sotto struct file *fp; 2276bad3ecd0Sotto int error; 2277bad3ecd0Sotto 2278bad3ecd0Sotto if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0) 2279bad3ecd0Sotto return (error); 2280bad3ecd0Sotto vp = (struct vnode *)fp->f_data; 2281bad3ecd0Sotto vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 2282bad3ecd0Sotto error = VOP_FSYNC(vp, fp->f_cred, MNT_WAIT, p); 2283bad3ecd0Sotto 2284bad3ecd0Sotto VOP_UNLOCK(vp, 0, p); 2285bad3ecd0Sotto FRELE(fp); 2286bad3ecd0Sotto return (error); 2287bad3ecd0Sotto} 2288bad3ecd0Sotto 2289bad3ecd0Sotto/* 2290bad3ecd0Sotto * Rename files. Source and destination must either both be directories, 2291bad3ecd0Sotto * or both not be directories. If target is a directory, it must be empty. 2292bad3ecd0Sotto */ 2293bad3ecd0Sotto/* ARGSUSED */ 2294bad3ecd0Sottoint 2295bad3ecd0Sottosys_rename(p, v, retval) 2296bad3ecd0Sotto struct proc *p; 2297bad3ecd0Sotto void *v; 2298bad3ecd0Sotto register_t *retval; 2299bad3ecd0Sotto{ 2300bad3ecd0Sotto register struct sys_rename_args /* { 2301bad3ecd0Sotto syscallarg(char *) from; 2302bad3ecd0Sotto syscallarg(char *) to; 2303bad3ecd0Sotto } */ *uap = v; 2304bad3ecd0Sotto register struct vnode *tvp, *fvp, *tdvp; 2305bad3ecd0Sotto struct nameidata fromnd, tond; 2306bad3ecd0Sotto int error; 2307bad3ecd0Sotto int flags; 2308bad3ecd0Sotto 2309bad3ecd0Sotto NDINIT(&fromnd, DELETE, WANTPARENT | SAVESTART, UIO_USERSPACE, 2310bad3ecd0Sotto SCARG(uap, from), p); 2311bad3ecd0Sotto if ((error = namei(&fromnd)) != 0) 2312bad3ecd0Sotto return (error); 2313bad3ecd0Sotto fvp = fromnd.ni_vp; 2314bad3ecd0Sotto 2315bad3ecd0Sotto flags = LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART; 2316bad3ecd0Sotto /* 2317bad3ecd0Sotto * rename("foo/", "bar/"); is OK 2318bad3ecd0Sotto */ 2319bad3ecd0Sotto if (fvp->v_type == VDIR) 2320bad3ecd0Sotto flags |= STRIPSLASHES; 2321bad3ecd0Sotto 2322bad3ecd0Sotto NDINIT(&tond, RENAME, flags, 2323bad3ecd0Sotto UIO_USERSPACE, SCARG(uap, to), p); 2324bad3ecd0Sotto if ((error = namei(&tond)) != 0) { 2325bad3ecd0Sotto VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 2326bad3ecd0Sotto vrele(fromnd.ni_dvp); 2327bad3ecd0Sotto vrele(fvp); 2328bad3ecd0Sotto goto out1; 2329bad3ecd0Sotto } 2330bad3ecd0Sotto tdvp = tond.ni_dvp; 2331bad3ecd0Sotto tvp = tond.ni_vp; 2332bad3ecd0Sotto if (tvp != NULL) { 2333bad3ecd0Sotto if (fvp->v_type == VDIR && tvp->v_type != VDIR) { 2334bad3ecd0Sotto error = ENOTDIR; 2335bad3ecd0Sotto goto out; 2336bad3ecd0Sotto } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) { 2337bad3ecd0Sotto error = EISDIR; 2338bad3ecd0Sotto goto out; 2339bad3ecd0Sotto } 2340bad3ecd0Sotto } 2341bad3ecd0Sotto if (fvp == tdvp) 2342bad3ecd0Sotto error = EINVAL; 2343bad3ecd0Sotto /* 2344bad3ecd0Sotto * If source is the same as the destination (that is the 2345bad3ecd0Sotto * same inode number) 2346bad3ecd0Sotto */ 2347bad3ecd0Sotto if (fvp == tvp) 2348bad3ecd0Sotto error = -1; 2349bad3ecd0Sottoout: 2350bad3ecd0Sotto if (!error) { 2351bad3ecd0Sotto VOP_LEASE(tdvp, p, p->p_ucred, LEASE_WRITE); 2352bad3ecd0Sotto if (fromnd.ni_dvp != tdvp) 2353bad3ecd0Sotto VOP_LEASE(fromnd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 2354bad3ecd0Sotto if (tvp) { 2355bad3ecd0Sotto (void)uvm_vnp_uncache(tvp); 2356bad3ecd0Sotto VOP_LEASE(tvp, p, p->p_ucred, LEASE_WRITE); 2357bad3ecd0Sotto } 2358bad3ecd0Sotto error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd, 2359bad3ecd0Sotto tond.ni_dvp, tond.ni_vp, &tond.ni_cnd); 2360bad3ecd0Sotto } else { 2361bad3ecd0Sotto VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd); 2362bad3ecd0Sotto if (tdvp == tvp) 2363bad3ecd0Sotto vrele(tdvp); 2364bad3ecd0Sotto else 2365bad3ecd0Sotto vput(tdvp); 2366bad3ecd0Sotto if (tvp) 2367bad3ecd0Sotto vput(tvp); 2368bad3ecd0Sotto VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 2369bad3ecd0Sotto vrele(fromnd.ni_dvp); 2370bad3ecd0Sotto vrele(fvp); 2371bad3ecd0Sotto } 2372bad3ecd0Sotto vrele(tond.ni_startdir); 2373bad3ecd0Sotto FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI); 2374bad3ecd0Sottoout1: 2375bad3ecd0Sotto if (fromnd.ni_startdir) 2376bad3ecd0Sotto vrele(fromnd.ni_startdir); 2377bad3ecd0Sotto FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI); 2378bad3ecd0Sotto if (error == -1) 2379bad3ecd0Sotto return (0); 2380bad3ecd0Sotto return (error); 2381bad3ecd0Sotto} 2382bad3ecd0Sotto 2383bad3ecd0Sotto/* 2384bad3ecd0Sotto * Make a directory file. 2385bad3ecd0Sotto */ 2386bad3ecd0Sotto/* ARGSUSED */ 2387bad3ecd0Sottoint 2388bad3ecd0Sottosys_mkdir(p, v, retval) 2389bad3ecd0Sotto struct proc *p; 2390bad3ecd0Sotto void *v; 2391bad3ecd0Sotto register_t *retval; 2392bad3ecd0Sotto{ 2393bad3ecd0Sotto register struct sys_mkdir_args /* { 2394bad3ecd0Sotto syscallarg(char *) path; 2395bad3ecd0Sotto syscallarg(int) mode; 2396bad3ecd0Sotto } */ *uap = v; 2397bad3ecd0Sotto register struct vnode *vp; 2398bad3ecd0Sotto struct vattr vattr; 2399bad3ecd0Sotto int error; 2400bad3ecd0Sotto struct nameidata nd; 2401bad3ecd0Sotto 2402bad3ecd0Sotto NDINIT(&nd, CREATE, LOCKPARENT | STRIPSLASHES, 2403bad3ecd0Sotto UIO_USERSPACE, SCARG(uap, path), p); 2404bad3ecd0Sotto if ((error = namei(&nd)) != 0) 2405bad3ecd0Sotto return (error); 2406bad3ecd0Sotto vp = nd.ni_vp; 2407bad3ecd0Sotto if (vp != NULL) { 2408bad3ecd0Sotto VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 2409bad3ecd0Sotto if (nd.ni_dvp == vp) 2410bad3ecd0Sotto vrele(nd.ni_dvp); 2411bad3ecd0Sotto else 2412bad3ecd0Sotto vput(nd.ni_dvp); 2413bad3ecd0Sotto vrele(vp); 2414bad3ecd0Sotto return (EEXIST); 2415bad3ecd0Sotto } 2416bad3ecd0Sotto VATTR_NULL(&vattr); 2417bad3ecd0Sotto vattr.va_type = VDIR; 2418bad3ecd0Sotto vattr.va_mode = (SCARG(uap, mode) & ACCESSPERMS) &~ p->p_fd->fd_cmask; 2419bad3ecd0Sotto VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 2420bad3ecd0Sotto error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr); 2421bad3ecd0Sotto if (!error) 2422bad3ecd0Sotto vput(nd.ni_vp); 2423bad3ecd0Sotto return (error); 2424bad3ecd0Sotto} 2425bad3ecd0Sotto 2426bad3ecd0Sotto/* 2427bad3ecd0Sotto * Remove a directory file. 2428bad3ecd0Sotto */ 2429bad3ecd0Sotto/* ARGSUSED */ 2430bad3ecd0Sottoint 2431bad3ecd0Sottosys_rmdir(p, v, retval) 2432bad3ecd0Sotto struct proc *p; 2433bad3ecd0Sotto void *v; 2434bad3ecd0Sotto register_t *retval; 2435bad3ecd0Sotto{ 2436bad3ecd0Sotto struct sys_rmdir_args /* { 2437bad3ecd0Sotto syscallarg(char *) path; 2438bad3ecd0Sotto } */ *uap = v; 2439bad3ecd0Sotto register struct vnode *vp; 2440bad3ecd0Sotto int error; 2441bad3ecd0Sotto struct nameidata nd; 2442bad3ecd0Sotto 2443bad3ecd0Sotto NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE, 2444bad3ecd0Sotto SCARG(uap, path), p); 2445bad3ecd0Sotto if ((error = namei(&nd)) != 0) 2446bad3ecd0Sotto return (error); 2447bad3ecd0Sotto vp = nd.ni_vp; 2448bad3ecd0Sotto if (vp->v_type != VDIR) { 2449bad3ecd0Sotto error = ENOTDIR; 2450bad3ecd0Sotto goto out; 2451bad3ecd0Sotto } 2452bad3ecd0Sotto /* 2453bad3ecd0Sotto * No rmdir "." please. 2454bad3ecd0Sotto */ 2455bad3ecd0Sotto if (nd.ni_dvp == vp) { 2456bad3ecd0Sotto error = EBUSY; 2457bad3ecd0Sotto goto out; 2458bad3ecd0Sotto } 2459bad3ecd0Sotto /* 2460bad3ecd0Sotto * The root of a mounted filesystem cannot be deleted. 2461bad3ecd0Sotto */ 2462bad3ecd0Sotto if (vp->v_flag & VROOT) 2463bad3ecd0Sotto error = EBUSY; 2464bad3ecd0Sottoout: 2465bad3ecd0Sotto if (!error) { 2466bad3ecd0Sotto VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 2467bad3ecd0Sotto VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 2468bad3ecd0Sotto error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); 2469bad3ecd0Sotto } else { 2470bad3ecd0Sotto VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 2471bad3ecd0Sotto if (nd.ni_dvp == vp) 2472bad3ecd0Sotto vrele(nd.ni_dvp); 2473bad3ecd0Sotto else 2474bad3ecd0Sotto vput(nd.ni_dvp); 2475bad3ecd0Sotto vput(vp); 2476bad3ecd0Sotto } 2477bad3ecd0Sotto return (error); 2478bad3ecd0Sotto} 2479bad3ecd0Sotto 2480bad3ecd0Sotto/* 2481bad3ecd0Sotto * Read a block of directory entries in a file system independent format. 2482bad3ecd0Sotto */ 2483bad3ecd0Sottoint 2484bad3ecd0Sottosys_getdirentries(p, v, retval) 2485bad3ecd0Sotto struct proc *p; 2486bad3ecd0Sotto void *v; 2487bad3ecd0Sotto register_t *retval; 2488bad3ecd0Sotto{ 2489bad3ecd0Sotto struct sys_getdirentries_args /* { 2490bad3ecd0Sotto syscallarg(int) fd; 2491bad3ecd0Sotto syscallarg(char *) buf; 2492bad3ecd0Sotto syscallarg(int) count; 2493bad3ecd0Sotto syscallarg(long *) basep; 2494bad3ecd0Sotto } */ *uap = v; 2495bad3ecd0Sotto struct vnode *vp; 2496bad3ecd0Sotto struct file *fp; 2497bad3ecd0Sotto struct uio auio; 2498bad3ecd0Sotto struct iovec aiov; 2499bad3ecd0Sotto long loff; 2500bad3ecd0Sotto int error, eofflag; 2501bad3ecd0Sotto 2502bad3ecd0Sotto if (SCARG(uap, count) < 0) 2503bad3ecd0Sotto return EINVAL; 2504bad3ecd0Sotto if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0) 2505bad3ecd0Sotto return (error); 2506bad3ecd0Sotto if ((fp->f_flag & FREAD) == 0) { 2507bad3ecd0Sotto error = EBADF; 2508bad3ecd0Sotto goto bad; 2509bad3ecd0Sotto } 2510bad3ecd0Sotto vp = (struct vnode *)fp->f_data; 2511bad3ecd0Sottounionread: 2512bad3ecd0Sotto if (vp->v_type != VDIR) { 2513bad3ecd0Sotto error = EINVAL; 2514bad3ecd0Sotto goto bad; 2515bad3ecd0Sotto } 2516bad3ecd0Sotto aiov.iov_base = SCARG(uap, buf); 2517bad3ecd0Sotto aiov.iov_len = SCARG(uap, count); 2518bad3ecd0Sotto auio.uio_iov = &aiov; 2519bad3ecd0Sotto auio.uio_iovcnt = 1; 2520bad3ecd0Sotto auio.uio_rw = UIO_READ; 2521bad3ecd0Sotto auio.uio_segflg = UIO_USERSPACE; 2522bad3ecd0Sotto auio.uio_procp = p; 2523bad3ecd0Sotto auio.uio_resid = SCARG(uap, count); 2524bad3ecd0Sotto vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 2525bad3ecd0Sotto loff = auio.uio_offset = fp->f_offset; 2526bad3ecd0Sotto error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, 0, 0); 2527bad3ecd0Sotto fp->f_offset = auio.uio_offset; 2528bad3ecd0Sotto VOP_UNLOCK(vp, 0, p); 2529bad3ecd0Sotto if (error) 2530bad3ecd0Sotto goto bad; 2531bad3ecd0Sotto if ((SCARG(uap, count) == auio.uio_resid) && 2532bad3ecd0Sotto union_check_p && 2533bad3ecd0Sotto (union_check_p(p, &vp, fp, auio, &error) != 0)) 2534bad3ecd0Sotto goto unionread; 2535bad3ecd0Sotto if (error) 2536bad3ecd0Sotto goto bad; 2537bad3ecd0Sotto 2538bad3ecd0Sotto if ((SCARG(uap, count) == auio.uio_resid) && 2539bad3ecd0Sotto (vp->v_flag & VROOT) && 2540bad3ecd0Sotto (vp->v_mount->mnt_flag & MNT_UNION)) { 2541bad3ecd0Sotto struct vnode *tvp = vp; 2542bad3ecd0Sotto vp = vp->v_mount->mnt_vnodecovered; 2543bad3ecd0Sotto VREF(vp); 2544bad3ecd0Sotto fp->f_data = (caddr_t) vp; 2545bad3ecd0Sotto fp->f_offset = 0; 2546bad3ecd0Sotto vrele(tvp); 2547bad3ecd0Sotto goto unionread; 2548bad3ecd0Sotto } 2549bad3ecd0Sotto error = copyout((caddr_t)&loff, (caddr_t)SCARG(uap, basep), 2550bad3ecd0Sotto sizeof(long)); 2551bad3ecd0Sotto *retval = SCARG(uap, count) - auio.uio_resid; 2552bad3ecd0Sottobad: 2553bad3ecd0Sotto FRELE(fp); 2554bad3ecd0Sotto return (error); 2555bad3ecd0Sotto} 2556bad3ecd0Sotto 2557bad3ecd0Sotto/* 2558bad3ecd0Sotto * Set the mode mask for creation of filesystem nodes. 2559bad3ecd0Sotto */ 2560bad3ecd0Sottoint 2561bad3ecd0Sottosys_umask(p, v, retval) 2562bad3ecd0Sotto struct proc *p; 2563bad3ecd0Sotto void *v; 2564bad3ecd0Sotto register_t *retval; 2565bad3ecd0Sotto{ 2566bad3ecd0Sotto struct sys_umask_args /* { 2567bad3ecd0Sotto syscallarg(int) newmask; 2568bad3ecd0Sotto } */ *uap = v; 2569bad3ecd0Sotto register struct filedesc *fdp; 2570bad3ecd0Sotto 2571bad3ecd0Sotto fdp = p->p_fd; 2572bad3ecd0Sotto *retval = fdp->fd_cmask; 2573bad3ecd0Sotto fdp->fd_cmask = SCARG(uap, newmask) & ACCESSPERMS; 2574bad3ecd0Sotto return (0); 2575bad3ecd0Sotto} 2576bad3ecd0Sotto 2577bad3ecd0Sotto/* 2578bad3ecd0Sotto * Void all references to file by ripping underlying filesystem 2579bad3ecd0Sotto * away from vnode. 2580bad3ecd0Sotto */ 2581bad3ecd0Sotto/* ARGSUSED */ 2582bad3ecd0Sottoint 2583bad3ecd0Sottosys_revoke(p, v, retval) 2584bad3ecd0Sotto struct proc *p; 2585bad3ecd0Sotto void *v; 2586bad3ecd0Sotto register_t *retval; 2587bad3ecd0Sotto{ 2588bad3ecd0Sotto register struct sys_revoke_args /* { 2589bad3ecd0Sotto syscallarg(char *) path; 2590bad3ecd0Sotto } */ *uap = v; 2591bad3ecd0Sotto register struct vnode *vp; 2592bad3ecd0Sotto struct vattr vattr; 2593bad3ecd0Sotto int error; 2594bad3ecd0Sotto struct nameidata nd; 2595bad3ecd0Sotto 2596bad3ecd0Sotto NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 2597bad3ecd0Sotto if ((error = namei(&nd)) != 0) 2598bad3ecd0Sotto return (error); 2599bad3ecd0Sotto vp = nd.ni_vp; 2600bad3ecd0Sotto if ((error = VOP_GETATTR(vp, &vattr, p->p_ucred, p)) != 0) 2601bad3ecd0Sotto goto out; 2602bad3ecd0Sotto if (p->p_ucred->cr_uid != vattr.va_uid && 2603bad3ecd0Sotto (error = suser(p->p_ucred, &p->p_acflag))) 2604bad3ecd0Sotto goto out; 2605bad3ecd0Sotto if (vp->v_usecount > 1 || (vp->v_flag & (VALIASED | VLAYER))) 2606bad3ecd0Sotto VOP_REVOKE(vp, REVOKEALL); 2607bad3ecd0Sottoout: 2608bad3ecd0Sotto vrele(vp); 2609bad3ecd0Sotto return (error); 2610bad3ecd0Sotto} 2611bad3ecd0Sotto 2612bad3ecd0Sotto/* 2613bad3ecd0Sotto * Convert a user file descriptor to a kernel file entry. 2614bad3ecd0Sotto * 2615bad3ecd0Sotto * On return *fpp is FREF:ed. 2616bad3ecd0Sotto */ 2617bad3ecd0Sottoint 2618bad3ecd0Sottogetvnode(fdp, fd, fpp) 2619bad3ecd0Sotto struct filedesc *fdp; 2620bad3ecd0Sotto struct file **fpp; 2621bad3ecd0Sotto int fd; 2622bad3ecd0Sotto{ 2623bad3ecd0Sotto struct file *fp; 2624bad3ecd0Sotto 2625bad3ecd0Sotto if ((fp = fd_getfile(fdp, fd)) == NULL) 2626bad3ecd0Sotto return (EBADF); 2627bad3ecd0Sotto if (fp->f_type != DTYPE_VNODE) 2628bad3ecd0Sotto return (EINVAL); 2629bad3ecd0Sotto FREF(fp); 2630bad3ecd0Sotto *fpp = fp; 2631bad3ecd0Sotto 2632bad3ecd0Sotto return (0); 2633bad3ecd0Sotto} 2634bad3ecd0Sotto 2635bad3ecd0Sotto/* 2636bad3ecd0Sotto * Positional read system call. 2637bad3ecd0Sotto */ 2638bad3ecd0Sottoint 2639bad3ecd0Sottosys_pread(p, v, retval) 2640bad3ecd0Sotto struct proc *p; 2641bad3ecd0Sotto void *v; 2642bad3ecd0Sotto register_t *retval; 2643bad3ecd0Sotto{ 2644bad3ecd0Sotto struct sys_pread_args /* { 2645bad3ecd0Sotto syscallarg(int) fd; 2646bad3ecd0Sotto syscallarg(void *) buf; 2647bad3ecd0Sotto syscallarg(size_t) nbyte; 2648bad3ecd0Sotto syscallarg(int) pad; 2649bad3ecd0Sotto syscallarg(off_t) offset; 2650bad3ecd0Sotto } */ *uap = v; 2651bad3ecd0Sotto struct filedesc *fdp = p->p_fd; 2652bad3ecd0Sotto struct file *fp; 2653bad3ecd0Sotto struct vnode *vp; 2654bad3ecd0Sotto off_t offset; 2655bad3ecd0Sotto int fd = SCARG(uap, fd); 2656bad3ecd0Sotto 2657bad3ecd0Sotto if ((fp = fd_getfile(fdp, fd)) == NULL) 2658bad3ecd0Sotto return (EBADF); 2659bad3ecd0Sotto if ((fp->f_flag & FREAD) == 0) 2660bad3ecd0Sotto return (EBADF); 2661bad3ecd0Sotto 2662bad3ecd0Sotto vp = (struct vnode *)fp->f_data; 2663bad3ecd0Sotto if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO) { 2664bad3ecd0Sotto return (ESPIPE); 2665bad3ecd0Sotto } 2666bad3ecd0Sotto 2667bad3ecd0Sotto offset = SCARG(uap, offset); 2668bad3ecd0Sotto 2669bad3ecd0Sotto FREF(fp); 2670bad3ecd0Sotto 2671bad3ecd0Sotto /* dofileread() will FRELE the descriptor for us */ 2672bad3ecd0Sotto return (dofileread(p, fd, fp, SCARG(uap, buf), SCARG(uap, nbyte), 2673bad3ecd0Sotto &offset, retval)); 2674bad3ecd0Sotto} 2675bad3ecd0Sotto 2676bad3ecd0Sotto/* 2677bad3ecd0Sotto * Positional scatter read system call. 2678bad3ecd0Sotto */ 2679bad3ecd0Sottoint 2680bad3ecd0Sottosys_preadv(p, v, retval) 2681bad3ecd0Sotto struct proc *p; 2682bad3ecd0Sotto void *v; 2683bad3ecd0Sotto register_t *retval; 2684bad3ecd0Sotto{ 2685bad3ecd0Sotto struct sys_preadv_args /* { 2686bad3ecd0Sotto syscallarg(int) fd; 2687bad3ecd0Sotto syscallarg(const struct iovec *) iovp; 2688bad3ecd0Sotto syscallarg(int) iovcnt; 2689bad3ecd0Sotto syscallarg(int) pad; 2690bad3ecd0Sotto syscallarg(off_t) offset; 2691bad3ecd0Sotto } */ *uap = v; 2692bad3ecd0Sotto struct filedesc *fdp = p->p_fd; 2693bad3ecd0Sotto struct file *fp; 2694bad3ecd0Sotto struct vnode *vp; 2695bad3ecd0Sotto off_t offset; 2696bad3ecd0Sotto int fd = SCARG(uap, fd); 2697bad3ecd0Sotto 2698bad3ecd0Sotto if ((fp = fd_getfile(fdp, fd)) == NULL) 2699bad3ecd0Sotto return (EBADF); 2700bad3ecd0Sotto if ((fp->f_flag & FREAD) == 0) 2701bad3ecd0Sotto return (EBADF); 2702bad3ecd0Sotto 2703bad3ecd0Sotto vp = (struct vnode *)fp->f_data; 2704bad3ecd0Sotto if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO) { 2705bad3ecd0Sotto return (ESPIPE); 2706bad3ecd0Sotto } 2707bad3ecd0Sotto 2708bad3ecd0Sotto FREF(fp); 2709bad3ecd0Sotto 2710bad3ecd0Sotto offset = SCARG(uap, offset); 2711bad3ecd0Sotto 2712bad3ecd0Sotto /* dofilereadv() will FRELE the descriptor for us */ 2713bad3ecd0Sotto return (dofilereadv(p, fd, fp, SCARG(uap, iovp), SCARG(uap, iovcnt), 2714bad3ecd0Sotto &offset, retval)); 2715bad3ecd0Sotto} 2716bad3ecd0Sotto 2717bad3ecd0Sotto/* 2718bad3ecd0Sotto * Positional write system call. 2719bad3ecd0Sotto */ 2720bad3ecd0Sottoint 2721bad3ecd0Sottosys_pwrite(p, v, retval) 2722bad3ecd0Sotto struct proc *p; 2723bad3ecd0Sotto void *v; 2724bad3ecd0Sotto register_t *retval; 2725bad3ecd0Sotto{ 2726bad3ecd0Sotto struct sys_pwrite_args /* { 2727bad3ecd0Sotto syscallarg(int) fd; 2728bad3ecd0Sotto syscallarg(const void *) buf; 2729bad3ecd0Sotto syscallarg(size_t) nbyte; 2730bad3ecd0Sotto syscallarg(int) pad; 2731bad3ecd0Sotto syscallarg(off_t) offset; 2732bad3ecd0Sotto } */ *uap = v; 2733bad3ecd0Sotto struct filedesc *fdp = p->p_fd; 2734bad3ecd0Sotto struct file *fp; 2735bad3ecd0Sotto struct vnode *vp; 2736bad3ecd0Sotto off_t offset; 2737bad3ecd0Sotto int fd = SCARG(uap, fd); 2738bad3ecd0Sotto 2739bad3ecd0Sotto if ((fp = fd_getfile(fdp, fd)) == NULL) 2740bad3ecd0Sotto return (EBADF); 2741bad3ecd0Sotto if ((fp->f_flag & FWRITE) == 0) 2742bad3ecd0Sotto return (EBADF); 2743bad3ecd0Sotto 2744bad3ecd0Sotto vp = (struct vnode *)fp->f_data; 2745bad3ecd0Sotto if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO) { 2746bad3ecd0Sotto return (ESPIPE); 2747bad3ecd0Sotto } 2748bad3ecd0Sotto 2749bad3ecd0Sotto FREF(fp); 2750bad3ecd0Sotto 2751bad3ecd0Sotto offset = SCARG(uap, offset); 2752bad3ecd0Sotto 2753bad3ecd0Sotto /* dofilewrite() will FRELE the descriptor for us */ 2754bad3ecd0Sotto return (dofilewrite(p, fd, fp, SCARG(uap, buf), SCARG(uap, nbyte), 2755bad3ecd0Sotto &offset, retval)); 2756bad3ecd0Sotto} 2757bad3ecd0Sotto 2758bad3ecd0Sotto 2759bad3ecd0Sotto/* 2760bad3ecd0Sotto * Positional gather write system call. 2761bad3ecd0Sotto */ 2762bad3ecd0Sottoint 2763bad3ecd0Sottosys_pwritev(p, v, retval) 2764bad3ecd0Sotto struct proc *p; 2765bad3ecd0Sotto void *v; 2766bad3ecd0Sotto register_t *retval; 2767bad3ecd0Sotto{ 2768bad3ecd0Sotto struct sys_pwritev_args /* { 2769bad3ecd0Sotto syscallarg(int) fd; 2770bad3ecd0Sotto syscallarg(const struct iovec *) iovp; 2771bad3ecd0Sotto syscallarg(int) iovcnt; 2772bad3ecd0Sotto syscallarg(int) pad; 2773bad3ecd0Sotto syscallarg(off_t) offset; 2774bad3ecd0Sotto } */ *uap = v; 2775bad3ecd0Sotto struct filedesc *fdp = p->p_fd; 2776bad3ecd0Sotto struct file *fp; 2777bad3ecd0Sotto struct vnode *vp; 2778bad3ecd0Sotto off_t offset; 2779bad3ecd0Sotto int fd = SCARG(uap, fd); 2780bad3ecd0Sotto 2781bad3ecd0Sotto if ((fp = fd_getfile(fdp, fd)) == NULL) 2782bad3ecd0Sotto return (EBADF); 2783bad3ecd0Sotto if ((fp->f_flag & FWRITE) == 0) 2784bad3ecd0Sotto return (EBADF); 2785bad3ecd0Sotto 2786bad3ecd0Sotto vp = (struct vnode *)fp->f_data; 2787bad3ecd0Sotto if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO) { 2788bad3ecd0Sotto return (ESPIPE); 2789bad3ecd0Sotto } 2790bad3ecd0Sotto 2791bad3ecd0Sotto FREF(fp); 2792bad3ecd0Sotto 2793bad3ecd0Sotto offset = SCARG(uap, offset); 2794bad3ecd0Sotto 2795bad3ecd0Sotto /* dofilewritev() will FRELE the descriptor for us */ 2796bad3ecd0Sotto return (dofilewritev(p, fd, fp, SCARG(uap, iovp), SCARG(uap, iovcnt), 2797bad3ecd0Sotto &offset, retval)); 2798bad3ecd0Sotto} 2799bad3ecd0Sotto 2800bad3ecd0Sotto#ifdef UFS_EXTATTR 2801bad3ecd0Sotto/* 2802bad3ecd0Sotto * Syscall to push extended attribute configuration information into the 2803bad3ecd0Sotto * VFS. Accepts a path, which it converts to a mountpoint, as well as 2804bad3ecd0Sotto * a command (int cmd), and attribute name and misc data. For now, the 2805bad3ecd0Sotto * attribute name is left in userspace for consumption by the VFS_op. 2806bad3ecd0Sotto * It will probably be changed to be copied into sysspace by the 2807bad3ecd0Sotto * syscall in the future, once issues with various consumers of the 2808bad3ecd0Sotto * attribute code have raised their hands. 2809bad3ecd0Sotto * 2810bad3ecd0Sotto * Currently this is used only by UFS Extended Attributes. 2811bad3ecd0Sotto */ 2812bad3ecd0Sottoint 2813bad3ecd0Sottosys_extattrctl(struct proc *p, void *v, register_t *reval) 2814bad3ecd0Sotto{ 2815bad3ecd0Sotto struct sys_extattrctl_args /* { 2816bad3ecd0Sotto syscallarg(const char *) path; 2817bad3ecd0Sotto syscallarg(int) cmd; 2818bad3ecd0Sotto syscallarg(const char *) filename; 2819bad3ecd0Sotto syscallarg(int) attrnamespace; 2820bad3ecd0Sotto syscallarg(const char *) attrname; 2821bad3ecd0Sotto } */ *uap = v; 2822bad3ecd0Sotto struct vnode *filename_vp; 2823bad3ecd0Sotto struct nameidata nd; 2824bad3ecd0Sotto struct mount *mp; 2825bad3ecd0Sotto char attrname[EXTATTR_MAXNAMELEN]; 2826bad3ecd0Sotto int error; 2827bad3ecd0Sotto 2828bad3ecd0Sotto /* 2829bad3ecd0Sotto * SCARG(uap, attrname) not always defined. We check again later 2830bad3ecd0Sotto * when we invoke the VFS call so as to pass in NULL there if needed. 2831bad3ecd0Sotto */ 2832bad3ecd0Sotto if (SCARG(uap, attrname) != NULL) { 2833bad3ecd0Sotto error = copyinstr(SCARG(uap, attrname), attrname, 2834bad3ecd0Sotto EXTATTR_MAXNAMELEN, NULL); 2835bad3ecd0Sotto if (error) 2836bad3ecd0Sotto return (error); 2837bad3ecd0Sotto } 2838bad3ecd0Sotto 2839bad3ecd0Sotto /* 2840bad3ecd0Sotto * SCARG(uap, filename) not always defined. If it is, grab 2841bad3ecd0Sotto * a vnode lock, which VFS_EXTATTRCTL() will later release. 2842bad3ecd0Sotto */ 2843bad3ecd0Sotto filename_vp = NULL; 2844bad3ecd0Sotto if (SCARG(uap, filename) != NULL) { 2845bad3ecd0Sotto NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, 2846bad3ecd0Sotto SCARG(uap, filename), p); 2847bad3ecd0Sotto if ((error = namei(&nd)) != 0) 2848bad3ecd0Sotto return (error); 2849bad3ecd0Sotto filename_vp = nd.ni_vp; 2850bad3ecd0Sotto } 2851bad3ecd0Sotto 2852bad3ecd0Sotto /* SCARG(uap, path) always defined. */ 2853bad3ecd0Sotto NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 2854bad3ecd0Sotto if ((error = namei(&nd)) != 0) { 2855bad3ecd0Sotto if (filename_vp != NULL) 2856bad3ecd0Sotto vput(filename_vp); 2857bad3ecd0Sotto return (error); 2858bad3ecd0Sotto } 2859bad3ecd0Sotto 2860bad3ecd0Sotto mp = nd.ni_vp->v_mount; 2861bad3ecd0Sotto if (error) { 2862bad3ecd0Sotto if (filename_vp != NULL) 2863bad3ecd0Sotto vput(filename_vp); 2864bad3ecd0Sotto return (error); 2865bad3ecd0Sotto } 2866bad3ecd0Sotto 2867bad3ecd0Sotto if (SCARG(uap, attrname) != NULL) { 2868bad3ecd0Sotto error = VFS_EXTATTRCTL(mp, SCARG(uap, cmd), filename_vp, 2869bad3ecd0Sotto SCARG(uap, attrnamespace), attrname, p); 2870bad3ecd0Sotto } else { 2871bad3ecd0Sotto error = VFS_EXTATTRCTL(mp, SCARG(uap, cmd), filename_vp, 2872bad3ecd0Sotto SCARG(uap, attrnamespace), NULL, p); 2873bad3ecd0Sotto } 2874bad3ecd0Sotto 2875bad3ecd0Sotto /* 2876bad3ecd0Sotto * VFS_EXTATTRCTL will have unlocked, but not de-ref'd, 2877bad3ecd0Sotto * filename_vp, so vrele it if it is defined. 2878bad3ecd0Sotto */ 2879bad3ecd0Sotto if (filename_vp != NULL) 2880bad3ecd0Sotto vrele(filename_vp); 2881bad3ecd0Sotto 2882bad3ecd0Sotto return (error); 2883bad3ecd0Sotto} 2884bad3ecd0Sotto 2885bad3ecd0Sotto/*- 2886bad3ecd0Sotto * Set a named extended attribute on a file or directory 2887bad3ecd0Sotto * 2888bad3ecd0Sotto * Arguments: unlocked vnode "vp", attribute namespace "attrnamespace", 2889bad3ecd0Sotto * kernelspace string pointer "attrname", userspace buffer 2890bad3ecd0Sotto * pointer "data", buffer length "nbytes", thread "td". 2891bad3ecd0Sotto * Returns: 0 on success, an error number otherwise 2892bad3ecd0Sotto * Locks: none 2893bad3ecd0Sotto * References: vp must be a valid reference for the duration of the call 2894bad3ecd0Sotto */ 2895bad3ecd0Sottostatic int 2896bad3ecd0Sottoextattr_set_vp(struct vnode *vp, int attrnamespace, const char *attrname, 2897bad3ecd0Sotto void *data, size_t nbytes, struct proc *p, register_t *retval) 2898bad3ecd0Sotto{ 2899bad3ecd0Sotto struct uio auio; 2900bad3ecd0Sotto struct iovec aiov; 2901bad3ecd0Sotto ssize_t cnt; 2902bad3ecd0Sotto int error; 2903bad3ecd0Sotto 2904bad3ecd0Sotto VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 2905bad3ecd0Sotto vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 2906bad3ecd0Sotto 2907bad3ecd0Sotto aiov.iov_base = data; 2908bad3ecd0Sotto aiov.iov_len = nbytes; 2909bad3ecd0Sotto auio.uio_iov = &aiov; 2910bad3ecd0Sotto auio.uio_iovcnt = 1; 2911bad3ecd0Sotto auio.uio_offset = 0; 2912bad3ecd0Sotto if (nbytes > INT_MAX) { 2913bad3ecd0Sotto error = EINVAL; 2914bad3ecd0Sotto goto done; 2915bad3ecd0Sotto } 2916bad3ecd0Sotto auio.uio_resid = nbytes; 2917bad3ecd0Sotto auio.uio_rw = UIO_WRITE; 2918bad3ecd0Sotto auio.uio_segflg = UIO_USERSPACE; 2919bad3ecd0Sotto auio.uio_procp = p; 2920bad3ecd0Sotto cnt = nbytes; 2921bad3ecd0Sotto 2922bad3ecd0Sotto error = VOP_SETEXTATTR(vp, attrnamespace, attrname, &auio, 2923bad3ecd0Sotto p->p_ucred, p); 2924bad3ecd0Sotto cnt -= auio.uio_resid; 2925bad3ecd0Sotto retval[0] = cnt; 2926bad3ecd0Sotto 2927bad3ecd0Sottodone: 2928bad3ecd0Sotto VOP_UNLOCK(vp, 0, p); 2929bad3ecd0Sotto return (error); 2930bad3ecd0Sotto} 2931bad3ecd0Sotto 2932bad3ecd0Sottoint 2933bad3ecd0Sottosys_extattr_set_file(struct proc *p, void *v, register_t *retval) 2934bad3ecd0Sotto{ 2935bad3ecd0Sotto struct sys_extattr_set_file_args /* { 2936bad3ecd0Sotto syscallarg(const char *) path; 2937bad3ecd0Sotto syscallarg(int) attrnamespace; 2938bad3ecd0Sotto syscallarg(const char *) attrname; 2939bad3ecd0Sotto syscallarg(void *) data; 2940bad3ecd0Sotto syscallarg(size_t) nbytes; 2941bad3ecd0Sotto } */ *uap = v; 2942bad3ecd0Sotto struct nameidata nd; 2943bad3ecd0Sotto char attrname[EXTATTR_MAXNAMELEN]; 2944bad3ecd0Sotto int error; 2945bad3ecd0Sotto 2946bad3ecd0Sotto error = copyinstr(SCARG(uap, attrname), attrname, EXTATTR_MAXNAMELEN, 2947bad3ecd0Sotto NULL); 2948bad3ecd0Sotto if (error) 2949bad3ecd0Sotto return (error); 2950bad3ecd0Sotto 2951bad3ecd0Sotto NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 2952bad3ecd0Sotto if ((error = namei(&nd)) != 0) 2953bad3ecd0Sotto return (error); 2954bad3ecd0Sotto 2955bad3ecd0Sotto error = extattr_set_vp(nd.ni_vp, SCARG(uap, attrnamespace), attrname, 2956bad3ecd0Sotto SCARG(uap, data), SCARG(uap, nbytes), p, retval); 2957bad3ecd0Sotto 2958bad3ecd0Sotto vrele(nd.ni_vp); 2959bad3ecd0Sotto return (error); 2960bad3ecd0Sotto} 2961bad3ecd0Sotto 2962bad3ecd0Sottoint 2963bad3ecd0Sottosys_extattr_set_fd(struct proc *p, void *v, register_t *retval) 2964bad3ecd0Sotto{ 2965bad3ecd0Sotto struct sys_extattr_set_fd_args /* { 2966bad3ecd0Sotto syscallarg(int) fd; 2967bad3ecd0Sotto syscallarg(int) attrnamespace; 2968bad3ecd0Sotto syscallarg(const char *) attrname; 2969bad3ecd0Sotto syscallarg(struct iovec *) iovp; 2970bad3ecd0Sotto syscallarg(int) iovcnt; 2971bad3ecd0Sotto } */ *uap = v; 2972bad3ecd0Sotto struct file *fp; 2973bad3ecd0Sotto char attrname[EXTATTR_MAXNAMELEN]; 2974bad3ecd0Sotto int error; 2975bad3ecd0Sotto 2976bad3ecd0Sotto error = copyinstr(SCARG(uap, attrname), attrname, EXTATTR_MAXNAMELEN, 2977bad3ecd0Sotto NULL); 2978bad3ecd0Sotto if (error) 2979bad3ecd0Sotto return (error); 2980bad3ecd0Sotto 2981bad3ecd0Sotto if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0) 2982bad3ecd0Sotto return (error); 2983bad3ecd0Sotto 2984bad3ecd0Sotto error = extattr_set_vp((struct vnode *)fp->f_data, 2985bad3ecd0Sotto SCARG(uap, attrnamespace), attrname, SCARG(uap, data), 2986bad3ecd0Sotto SCARG(uap, nbytes), p, retval); 2987bad3ecd0Sotto FRELE(fp); 2988bad3ecd0Sotto 2989bad3ecd0Sotto return (error); 2990bad3ecd0Sotto} 2991bad3ecd0Sotto 2992bad3ecd0Sotto/*- 2993bad3ecd0Sotto * Get a named extended attribute on a file or directory 2994bad3ecd0Sotto * 2995bad3ecd0Sotto * Arguments: unlocked vnode "vp", attribute namespace "attrnamespace", 2996bad3ecd0Sotto * kernelspace string pointer "attrname", userspace buffer 2997bad3ecd0Sotto * pointer "data", buffer length "nbytes", thread "td". 2998bad3ecd0Sotto * Returns: 0 on success, an error number otherwise 2999bad3ecd0Sotto * Locks: none 3000bad3ecd0Sotto * References: vp must be a valid reference for the duration of the call 3001bad3ecd0Sotto */ 3002bad3ecd0Sottostatic int 3003bad3ecd0Sottoextattr_get_vp(struct vnode *vp, int attrnamespace, const char *attrname, 3004bad3ecd0Sotto void *data, size_t nbytes, struct proc *p, register_t *retval) 3005bad3ecd0Sotto{ 3006bad3ecd0Sotto struct uio auio; 3007bad3ecd0Sotto struct iovec aiov; 3008bad3ecd0Sotto ssize_t cnt; 3009bad3ecd0Sotto size_t size; 3010bad3ecd0Sotto int error; 3011bad3ecd0Sotto 3012bad3ecd0Sotto VOP_LEASE(vp, p, p->p_ucred, LEASE_READ); 3013bad3ecd0Sotto vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 3014bad3ecd0Sotto 3015bad3ecd0Sotto /* 3016bad3ecd0Sotto * Slightly unusual semantics: if the user provides a NULL data 3017bad3ecd0Sotto * pointer, they don't want to receive the data, just the 3018bad3ecd0Sotto * maximum read length. 3019bad3ecd0Sotto */ 3020bad3ecd0Sotto if (data != NULL) { 3021bad3ecd0Sotto aiov.iov_base = data; 3022bad3ecd0Sotto aiov.iov_len = nbytes; 3023bad3ecd0Sotto auio.uio_iov = &aiov; 3024bad3ecd0Sotto auio.uio_offset = 0; 3025bad3ecd0Sotto if (nbytes > INT_MAX) { 3026bad3ecd0Sotto error = EINVAL; 3027bad3ecd0Sotto goto done; 3028bad3ecd0Sotto } 3029bad3ecd0Sotto auio.uio_resid = nbytes; 3030bad3ecd0Sotto auio.uio_rw = UIO_READ; 3031bad3ecd0Sotto auio.uio_segflg = UIO_USERSPACE; 3032bad3ecd0Sotto auio.uio_procp = p; 3033bad3ecd0Sotto cnt = nbytes; 3034bad3ecd0Sotto error = VOP_GETEXTATTR(vp, attrnamespace, attrname, &auio, 3035bad3ecd0Sotto NULL, p->p_ucred, p); 3036bad3ecd0Sotto cnt -= auio.uio_resid; 3037bad3ecd0Sotto retval[0] = cnt; 3038bad3ecd0Sotto } else { 3039bad3ecd0Sotto error = VOP_GETEXTATTR(vp, attrnamespace, attrname, NULL, 3040bad3ecd0Sotto &size, p->p_ucred, p); 3041bad3ecd0Sotto retval[0] = size; 3042bad3ecd0Sotto } 3043bad3ecd0Sottodone: 3044bad3ecd0Sotto VOP_UNLOCK(vp, 0, p); 3045bad3ecd0Sotto return (error); 3046bad3ecd0Sotto} 3047bad3ecd0Sotto 3048bad3ecd0Sottoint 3049bad3ecd0Sottosys_extattr_get_file(p, v, retval) 3050bad3ecd0Sotto struct proc *p; 3051bad3ecd0Sotto void *v; 3052bad3ecd0Sotto register_t *retval; 3053bad3ecd0Sotto{ 3054bad3ecd0Sotto struct sys_extattr_get_file_args /* { 3055bad3ecd0Sotto syscallarg(const char *) path; 3056bad3ecd0Sotto syscallarg(int) attrnamespace; 3057bad3ecd0Sotto syscallarg(const char *) attrname; 3058bad3ecd0Sotto syscallarg(void *) data; 3059bad3ecd0Sotto syscallarg(size_t) nbytes; 3060bad3ecd0Sotto } */ *uap = v; 3061bad3ecd0Sotto struct nameidata nd; 3062bad3ecd0Sotto char attrname[EXTATTR_MAXNAMELEN]; 3063bad3ecd0Sotto int error; 3064bad3ecd0Sotto 3065bad3ecd0Sotto error = copyinstr(SCARG(uap, attrname), attrname, EXTATTR_MAXNAMELEN, 3066bad3ecd0Sotto NULL); 3067bad3ecd0Sotto if (error) 3068bad3ecd0Sotto return (error); 3069bad3ecd0Sotto 3070bad3ecd0Sotto NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 3071bad3ecd0Sotto if ((error = namei(&nd)) != 0) 3072bad3ecd0Sotto return (error); 3073bad3ecd0Sotto 3074bad3ecd0Sotto error = extattr_get_vp(nd.ni_vp, SCARG(uap, attrnamespace), attrname, 3075bad3ecd0Sotto SCARG(uap, data), SCARG(uap, nbytes), p, retval); 3076bad3ecd0Sotto 3077bad3ecd0Sotto vrele(nd.ni_vp); 3078bad3ecd0Sotto return (error); 3079bad3ecd0Sotto} 3080bad3ecd0Sotto 3081bad3ecd0Sottoint 3082bad3ecd0Sottosys_extattr_get_fd(p, v, retval) 3083bad3ecd0Sotto struct proc *p; 3084bad3ecd0Sotto void *v; 3085bad3ecd0Sotto register_t *retval; 3086bad3ecd0Sotto{ 3087bad3ecd0Sotto struct sys_extattr_get_fd_args /* { 3088bad3ecd0Sotto syscallarg(int) fd; 3089bad3ecd0Sotto syscallarg(int) attrnamespace; 3090bad3ecd0Sotto syscallarg(const char *) attrname; 3091bad3ecd0Sotto syscallarg(void *) data; 3092bad3ecd0Sotto syscallarg(size_t) nbytes; 3093bad3ecd0Sotto } */ *uap = v; 3094bad3ecd0Sotto struct file *fp; 3095bad3ecd0Sotto char attrname[EXTATTR_MAXNAMELEN]; 3096bad3ecd0Sotto int error; 3097bad3ecd0Sotto 3098bad3ecd0Sotto error = copyinstr(SCARG(uap, attrname), attrname, EXTATTR_MAXNAMELEN, 3099bad3ecd0Sotto NULL); 3100bad3ecd0Sotto if (error) 3101bad3ecd0Sotto return (error); 3102bad3ecd0Sotto 3103bad3ecd0Sotto if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0) 3104bad3ecd0Sotto return (error); 3105bad3ecd0Sotto 3106bad3ecd0Sotto error = extattr_get_vp((struct vnode *)fp->f_data, 3107bad3ecd0Sotto SCARG(uap, attrnamespace), attrname, SCARG(uap, data), 3108bad3ecd0Sotto SCARG(uap, nbytes), p, retval); 3109bad3ecd0Sotto FRELE(fp); 3110bad3ecd0Sotto 3111bad3ecd0Sotto return (error); 3112bad3ecd0Sotto} 3113bad3ecd0Sotto 3114bad3ecd0Sotto/* 3115bad3ecd0Sotto * extattr_delete_vp(): Delete a named extended attribute on a file or 3116bad3ecd0Sotto * directory 3117bad3ecd0Sotto * 3118bad3ecd0Sotto * Arguments: unlocked vnode "vp", attribute namespace "attrnamespace", 3119bad3ecd0Sotto * kernelspace string pointer "attrname", proc "p" 3120bad3ecd0Sotto * Returns: 0 on success, an error number otherwise 3121bad3ecd0Sotto * Locks: none 3122bad3ecd0Sotto * References: vp must be a valid reference for the duration of the call 3123bad3ecd0Sotto */ 3124bad3ecd0Sottostatic int 3125bad3ecd0Sottoextattr_delete_vp(struct vnode *vp, int attrnamespace, const char *attrname, 3126bad3ecd0Sotto struct proc *p) 3127bad3ecd0Sotto{ 3128bad3ecd0Sotto int error; 3129bad3ecd0Sotto 3130bad3ecd0Sotto VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 3131bad3ecd0Sotto vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 3132bad3ecd0Sotto 3133bad3ecd0Sotto error = VOP_SETEXTATTR(vp, attrnamespace, attrname, NULL, 3134bad3ecd0Sotto p->p_ucred, p); 3135bad3ecd0Sotto 3136bad3ecd0Sotto VOP_UNLOCK(vp, 0, p); 3137bad3ecd0Sotto return (error); 3138bad3ecd0Sotto} 3139bad3ecd0Sotto 3140bad3ecd0Sottoint 3141bad3ecd0Sottosys_extattr_delete_file(p, v, retval) 3142bad3ecd0Sotto struct proc *p; 3143bad3ecd0Sotto void *v; 3144bad3ecd0Sotto register_t *retval; 3145bad3ecd0Sotto{ 3146bad3ecd0Sotto struct sys_extattr_delete_file_args /* { 3147bad3ecd0Sotto syscallarg(int) fd; 3148bad3ecd0Sotto syscallarg(int) attrnamespace; 3149bad3ecd0Sotto syscallarg(const char *) attrname; 3150bad3ecd0Sotto } */ *uap = v; 3151bad3ecd0Sotto struct nameidata nd; 3152bad3ecd0Sotto char attrname[EXTATTR_MAXNAMELEN]; 3153bad3ecd0Sotto int error; 3154bad3ecd0Sotto 3155bad3ecd0Sotto error = copyinstr(SCARG(uap, attrname), attrname, EXTATTR_MAXNAMELEN, 3156bad3ecd0Sotto NULL); 3157bad3ecd0Sotto if (error) 3158bad3ecd0Sotto return(error); 3159bad3ecd0Sotto 3160bad3ecd0Sotto NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 3161bad3ecd0Sotto if ((error = namei(&nd)) != 0) 3162bad3ecd0Sotto return(error); 3163bad3ecd0Sotto 3164bad3ecd0Sotto error = extattr_delete_vp(nd.ni_vp, SCARG(uap, attrnamespace), 3165bad3ecd0Sotto attrname, p); 3166bad3ecd0Sotto 3167bad3ecd0Sotto vrele(nd.ni_vp); 3168bad3ecd0Sotto return(error); 3169bad3ecd0Sotto} 3170bad3ecd0Sotto 3171bad3ecd0Sottoint 3172bad3ecd0Sottosys_extattr_delete_fd(p, v, retval) 3173bad3ecd0Sotto struct proc *p; 3174bad3ecd0Sotto void *v; 3175bad3ecd0Sotto register_t *retval; 3176bad3ecd0Sotto{ 3177bad3ecd0Sotto struct sys_extattr_delete_fd_args /* { 3178bad3ecd0Sotto syscallarg(int) fd; 3179bad3ecd0Sotto syscallarg(int) attrnamespace; 3180bad3ecd0Sotto syscallarg(const char *) attrname; 3181bad3ecd0Sotto } */ *uap = v; 3182bad3ecd0Sotto struct file *fp; 3183bad3ecd0Sotto char attrname[EXTATTR_MAXNAMELEN]; 3184bad3ecd0Sotto int error; 3185bad3ecd0Sotto 3186bad3ecd0Sotto error = copyinstr(SCARG(uap, attrname), attrname, EXTATTR_MAXNAMELEN, 3187bad3ecd0Sotto NULL); 3188bad3ecd0Sotto if (error) 3189bad3ecd0Sotto return (error); 3190bad3ecd0Sotto 3191bad3ecd0Sotto if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0) 3192bad3ecd0Sotto return (error); 3193bad3ecd0Sotto 3194bad3ecd0Sotto error = extattr_delete_vp((struct vnode *)fp->f_data, 3195bad3ecd0Sotto SCARG(uap, attrnamespace), attrname, p); 3196bad3ecd0Sotto FRELE(fp); 3197bad3ecd0Sotto 3198bad3ecd0Sotto return (error); 3199bad3ecd0Sotto} 3200bad3ecd0Sotto#endif 3201