vfs_syscalls.c revision 35275
1167514Skmacy/* 2167514Skmacy * Copyright (c) 1989, 1993 3167514Skmacy * The Regents of the University of California. All rights reserved. 4167514Skmacy * (c) UNIX System Laboratories, Inc. 5167514Skmacy * All or some portions of this file are derived from material licensed 6167514Skmacy * to the University of California by American Telephone and Telegraph 7167514Skmacy * Co. or Unix System Laboratories, Inc. and are reproduced herein with 8167514Skmacy * the permission of UNIX System Laboratories, Inc. 9167514Skmacy * 10167514Skmacy * Redistribution and use in source and binary forms, with or without 11167514Skmacy * modification, are permitted provided that the following conditions 12169978Skmacy * are met: 13167514Skmacy * 1. Redistributions of source code must retain the above copyright 14167514Skmacy * notice, this list of conditions and the following disclaimer. 15167514Skmacy * 2. Redistributions in binary form must reproduce the above copyright 16167514Skmacy * notice, this list of conditions and the following disclaimer in the 17167514Skmacy * documentation and/or other materials provided with the distribution. 18167514Skmacy * 3. All advertising materials mentioning features or use of this software 19167514Skmacy * must display the following acknowledgement: 20167514Skmacy * This product includes software developed by the University of 21167514Skmacy * California, Berkeley and its contributors. 22167514Skmacy * 4. Neither the name of the University nor the names of its contributors 23167514Skmacy * may be used to endorse or promote products derived from this software 24167514Skmacy * without specific prior written permission. 25167514Skmacy * 26167514Skmacy * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 27167514Skmacy * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28167514Skmacy * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29167514Skmacy * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 30167514Skmacy * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31167514Skmacy * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32167514Skmacy * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33167514Skmacy * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34167514Skmacy * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35167514Skmacy * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36167514Skmacy * SUCH DAMAGE. 37167514Skmacy * 38167514Skmacy * @(#)vfs_syscalls.c 8.13 (Berkeley) 4/15/94 39174708Skmacy * $Id: vfs_syscalls.c,v 1.97 1998/04/08 18:31:57 wosch Exp $ 40174708Skmacy */ 41174708Skmacy 42167514Skmacy/* For 4.3 integer FS ID compatibility */ 43167514Skmacy#include "opt_compat.h" 44171471Skmacy 45171471Skmacy/* 46171471Skmacy * XXX - The following is required because of some magic done 47171471Skmacy * in getdirentries() below which is only done if the translucent 48167514Skmacy * filesystem `UNION' is compiled into the kernel. This is broken, 49167526Skmacy * but I don't have time to study the code deeply enough to understand 50171471Skmacy * what's going on and determine an appropriate fix. -GAW 51167514Skmacy */ 52167514Skmacy#include "opt_union.h" 53167514Skmacy 54167514Skmacy#include <sys/param.h> 55167514Skmacy#include <sys/systm.h> 56167514Skmacy#include <sys/sysent.h> 57167514Skmacy#include <sys/sysproto.h> 58180583Skmacy#include <sys/namei.h> 59180583Skmacy#include <sys/filedesc.h> 60180583Skmacy#include <sys/kernel.h> 61180583Skmacy#include <sys/fcntl.h> 62180583Skmacy#include <sys/file.h> 63180583Skmacy#include <sys/stat.h> 64174708Skmacy#include <sys/unistd.h> 65172101Skmacy#include <sys/vnode.h> 66172101Skmacy#include <sys/malloc.h> 67172101Skmacy#include <sys/mount.h> 68172101Skmacy#include <sys/proc.h> 69172101Skmacy#include <sys/dirent.h> 70178800Skmacy 71169978Skmacy#ifdef UNION 72169978Skmacy#include <miscfs/union/union.h> 73174626Skmacy#endif 74169978Skmacy 75178800Skmacy#include <vm/vm.h> 76169978Skmacy#include <vm/vm_object.h> 77169978Skmacy#include <vm/vm_extern.h> 78170038Skmacy#include <vm/vm_zone.h> 79174638Skmacy#include <sys/sysctl.h> 80174638Skmacy 81174638Skmacystatic int change_dir __P((struct nameidata *ndp, struct proc *p)); 82174638Skmacystatic void checkdirs __P((struct vnode *olddp)); 83169978Skmacy 84174638Skmacystatic int usermount = 0; /* if 1, non-root can mount fs. */ 85174638Skmacy 86174638SkmacySYSCTL_INT(_vfs, OID_AUTO, usermount, CTLFLAG_RW, &usermount, 0, ""); 87174638Skmacy 88174638Skmacy/* 89174638Skmacy * Virtual File System System Calls 90174638Skmacy */ 91174638Skmacy 92174638Skmacy/* 93174638Skmacy * Mount a file system. 94176472Skmacy */ 95176472Skmacy#ifndef _SYS_SYSPROTO_H_ 96176472Skmacystruct mount_args { 97174638Skmacy char *type; 98174638Skmacy char *path; 99167514Skmacy int flags; 100167514Skmacy caddr_t data; 101167514Skmacy}; 102167514Skmacy#endif 103167514Skmacy/* ARGSUSED */ 104167514Skmacyint 105167514Skmacymount(p, uap) 106167514Skmacy struct proc *p; 107167514Skmacy register struct mount_args /* { 108167514Skmacy syscallarg(char *) type; 109167514Skmacy syscallarg(char *) path; 110167514Skmacy syscallarg(int) flags; 111167514Skmacy syscallarg(caddr_t) data; 112167514Skmacy } */ *uap; 113172109Skmacy{ 114172109Skmacy struct vnode *vp; 115172109Skmacy struct mount *mp; 116167514Skmacy struct vfsconf *vfsp; 117167514Skmacy int error, flag = 0, flag2 = 0; 118169978Skmacy struct vattr va; 119169978Skmacy u_long fstypenum; 120167514Skmacy struct nameidata nd; 121167514Skmacy char fstypename[MFSNAMELEN]; 122167514Skmacy 123167514Skmacy if (usermount == 0 && (error = suser(p->p_ucred, &p->p_acflag))) 124167514Skmacy return (error); 125167514Skmacy 126167514Skmacy /* 127169978Skmacy * Get vnode to be covered 128167514Skmacy */ 129174708Skmacy NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, 130167514Skmacy SCARG(uap, path), p); 131167514Skmacy if (error = namei(&nd)) 132167514Skmacy return (error); 133167514Skmacy vp = nd.ni_vp; 134167514Skmacy if (SCARG(uap, flags) & MNT_UPDATE) { 135167514Skmacy if ((vp->v_flag & VROOT) == 0) { 136167514Skmacy vput(vp); 137167514Skmacy return (EINVAL); 138174708Skmacy } 139167514Skmacy mp = vp->v_mount; 140171471Skmacy flag = mp->mnt_flag; 141174708Skmacy flag2 = mp->mnt_kern_flag; 142171471Skmacy /* 143171469Skmacy * We only allow the filesystem to be reloaded if it 144167514Skmacy * is currently mounted read-only. 145171471Skmacy */ 146170038Skmacy if ((SCARG(uap, flags) & MNT_RELOAD) && 147167514Skmacy ((mp->mnt_flag & MNT_RDONLY) == 0)) { 148174708Skmacy vput(vp); 149174708Skmacy return (EOPNOTSUPP); /* Needs translation */ 150174708Skmacy } 151174708Skmacy mp->mnt_flag |= 152174708Skmacy SCARG(uap, flags) & (MNT_RELOAD | MNT_FORCE | MNT_UPDATE); 153174708Skmacy /* 154167514Skmacy * Only root, or the user that did the original mount is 155167514Skmacy * permitted to update it. 156167514Skmacy */ 157167514Skmacy if (mp->mnt_stat.f_owner != p->p_ucred->cr_uid && 158167514Skmacy (error = suser(p->p_ucred, &p->p_acflag))) { 159167514Skmacy vput(vp); 160167514Skmacy return (error); 161167526Skmacy } 162174708Skmacy /* 163167526Skmacy * Do not allow NFS export by non-root users. Silently 164167526Skmacy * enforce MNT_NOSUID and MNT_NODEV for non-root users. 165167526Skmacy */ 166167526Skmacy if (p->p_ucred->cr_uid != 0) { 167167526Skmacy if (SCARG(uap, flags) & MNT_EXPORTED) { 168167560Skmacy vput(vp); 169169978Skmacy return (EPERM); 170169978Skmacy } 171169978Skmacy SCARG(uap, flags) |= MNT_NOSUID | MNT_NODEV; 172183063Skmacy } 173169978Skmacy if (vfs_busy(mp, LK_NOWAIT, 0, p)) { 174169978Skmacy vput(vp); 175169978Skmacy return (EBUSY); 176169978Skmacy } 177169978Skmacy VOP_UNLOCK(vp, 0, p); 178169978Skmacy goto update; 179167528Skmacy } 180167528Skmacy /* 181167528Skmacy * If the user is not root, ensure that they own the directory 182167528Skmacy * onto which we are attempting to mount. 183167528Skmacy */ 184167560Skmacy if ((error = VOP_GETATTR(vp, &va, p->p_ucred, p)) || 185167561Skmacy (va.va_uid != p->p_ucred->cr_uid && 186167526Skmacy (error = suser(p->p_ucred, &p->p_acflag)))) { 187174708Skmacy vput(vp); 188174708Skmacy return (error); 189174708Skmacy } 190174708Skmacy /* 191174708Skmacy * Do not allow NFS export by non-root users. Silently 192174708Skmacy * enforce MNT_NOSUID and MNT_NODEV for non-root users. 193174708Skmacy */ 194174708Skmacy if (p->p_ucred->cr_uid != 0) { 195174708Skmacy if (SCARG(uap, flags) & MNT_EXPORTED) { 196174708Skmacy vput(vp); 197174708Skmacy return (EPERM); 198174708Skmacy } 199174708Skmacy SCARG(uap, flags) |= MNT_NOSUID | MNT_NODEV; 200174708Skmacy } 201174708Skmacy if (error = vinvalbuf(vp, V_SAVE, p->p_ucred, p, 0, 0)) 202174708Skmacy return (error); 203175311Skmacy if (vp->v_type != VDIR) { 204174708Skmacy vput(vp); 205174708Skmacy return (ENOTDIR); 206174708Skmacy } 207174708Skmacy#ifdef COMPAT_43 208174708Skmacy /* 209174708Skmacy * Historically filesystem types were identified by number. If we 210174708Skmacy * get an integer for the filesystem type instead of a string, we 211174708Skmacy * check to see if it matches one of the historic filesystem types. 212174708Skmacy */ 213174708Skmacy fstypenum = (u_long)SCARG(uap, type); 214175304Skmacy if (fstypenum < maxvfsconf) { 215175304Skmacy for (vfsp = vfsconf; vfsp; vfsp = vfsp->vfc_next) 216175304Skmacy if (vfsp->vfc_typenum == fstypenum) 217175311Skmacy break; 218175311Skmacy if (vfsp == NULL) { 219175311Skmacy vput(vp); 220175311Skmacy return (ENODEV); 221175304Skmacy } 222175304Skmacy strncpy(fstypename, vfsp->vfc_name, MFSNAMELEN); 223174708Skmacy } else 224174708Skmacy#endif /* COMPAT_43 */ 225174708Skmacy if (error = copyinstr(SCARG(uap, type), fstypename, MFSNAMELEN, NULL)) { 226174708Skmacy vput(vp); 227174708Skmacy return (error); 228174708Skmacy } 229174708Skmacy for (vfsp = vfsconf; vfsp; vfsp = vfsp->vfc_next) 230174708Skmacy if (!strcmp(vfsp->vfc_name, fstypename)) 231175311Skmacy break; 232174708Skmacy if (vfsp == NULL) { 233174708Skmacy vput(vp); 234174708Skmacy return (ENODEV); 235174708Skmacy } 236174708Skmacy if (vp->v_mountedhere != NULL) { 237175304Skmacy vput(vp); 238174708Skmacy return (EBUSY); 239174708Skmacy } 240174708Skmacy 241174708Skmacy /* 242175311Skmacy * Allocate and initialize the filesystem. 243174708Skmacy */ 244174708Skmacy mp = (struct mount *)malloc((u_long)sizeof(struct mount), 245174708Skmacy M_MOUNT, M_WAITOK); 246174708Skmacy bzero((char *)mp, (u_long)sizeof(struct mount)); 247174708Skmacy lockinit(&mp->mnt_lock, PVFS, "vfslock", 0, LK_NOPAUSE); 248174708Skmacy (void)vfs_busy(mp, LK_NOWAIT, 0, p); 249175311Skmacy mp->mnt_op = vfsp->vfc_vfsops; 250175311Skmacy mp->mnt_vfc = vfsp; 251175311Skmacy vfsp->vfc_refcount++; 252175311Skmacy mp->mnt_stat.f_type = vfsp->vfc_typenum; 253175311Skmacy mp->mnt_flag |= vfsp->vfc_flags & MNT_VISFLAGMASK; 254174708Skmacy strncpy(mp->mnt_stat.f_fstypename, vfsp->vfc_name, MFSNAMELEN); 255175311Skmacy vp->v_mountedhere = mp; 256175311Skmacy mp->mnt_vnodecovered = vp; 257175311Skmacy mp->mnt_stat.f_owner = p->p_ucred->cr_uid; 258175311Skmacyupdate: 259175311Skmacy /* 260175311Skmacy * Set the mount level flags. 261175311Skmacy */ 262175311Skmacy if (SCARG(uap, flags) & MNT_RDONLY) 263175311Skmacy mp->mnt_flag |= MNT_RDONLY; 264175311Skmacy else if (mp->mnt_flag & MNT_RDONLY) 265175311Skmacy mp->mnt_kern_flag |= MNTK_WANTRDWR; 266175311Skmacy mp->mnt_flag &=~ (MNT_NOSUID | MNT_NOEXEC | MNT_NODEV | 267175311Skmacy MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC | MNT_NOATIME | 268175311Skmacy MNT_NOSYMFOLLOW | 269175311Skmacy MNT_NOCLUSTERR | MNT_NOCLUSTERW | MNT_SUIDDIR); 270175311Skmacy mp->mnt_flag |= SCARG(uap, flags) & (MNT_NOSUID | MNT_NOEXEC | 271175311Skmacy MNT_NODEV | MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC | MNT_FORCE | 272175311Skmacy MNT_NOSYMFOLLOW | 273175311Skmacy MNT_NOATIME | MNT_NOCLUSTERR | MNT_NOCLUSTERW | MNT_SUIDDIR); 274175311Skmacy /* 275175311Skmacy * Mount the filesystem. 276175311Skmacy */ 277175311Skmacy error = VFS_MOUNT(mp, SCARG(uap, path), SCARG(uap, data), &nd, p); 278175311Skmacy if (mp->mnt_flag & MNT_UPDATE) { 279175311Skmacy vrele(vp); 280175311Skmacy if (mp->mnt_kern_flag & MNTK_WANTRDWR) 281174708Skmacy mp->mnt_flag &= ~MNT_RDONLY; 282175311Skmacy mp->mnt_flag &=~ (MNT_UPDATE | MNT_RELOAD | MNT_FORCE); 283174708Skmacy mp->mnt_kern_flag &=~ MNTK_WANTRDWR; 284174708Skmacy if (error) { 285175311Skmacy mp->mnt_flag = flag; 286175311Skmacy mp->mnt_kern_flag = flag2; 287174708Skmacy } 288175304Skmacy if ((mp->mnt_flag & MNT_RDONLY) == 0) { 289175304Skmacy if (mp->mnt_syncer == NULL) 290175304Skmacy error = vfs_allocate_syncvnode(mp); 291174708Skmacy } else { 292175311Skmacy if (mp->mnt_syncer != NULL) 293174708Skmacy vrele(mp->mnt_syncer); 294175311Skmacy mp->mnt_syncer = NULL; 295174708Skmacy } 296174708Skmacy vfs_unbusy(mp, p); 297174708Skmacy return (error); 298174708Skmacy } 299174708Skmacy /* 300174708Skmacy * Put the new filesystem on the mount list after root. 301174708Skmacy */ 302174708Skmacy cache_purge(vp); 303174708Skmacy if (!error) { 304174708Skmacy simple_lock(&mountlist_slock); 305174708Skmacy CIRCLEQ_INSERT_TAIL(&mountlist, mp, mnt_list); 306175311Skmacy simple_unlock(&mountlist_slock); 307174708Skmacy checkdirs(vp); 308174708Skmacy VOP_UNLOCK(vp, 0, p); 309174708Skmacy if ((mp->mnt_flag & MNT_RDONLY) == 0) 310174708Skmacy error = vfs_allocate_syncvnode(mp); 311175311Skmacy vfs_unbusy(mp, p); 312174708Skmacy if (error = VFS_START(mp, 0, p)) 313174708Skmacy vrele(vp); 314174708Skmacy } else { 315174708Skmacy mp->mnt_vnodecovered->v_mountedhere = (struct mount *)0; 316174708Skmacy mp->mnt_vfc->vfc_refcount--; 317175311Skmacy vfs_unbusy(mp, p); 318175311Skmacy free((caddr_t)mp, M_MOUNT); 319175311Skmacy vput(vp); 320174708Skmacy } 321174708Skmacy return (error); 322174708Skmacy} 323174708Skmacy 324174708Skmacy/* 325174708Skmacy * Scan all active processes to see if any of them have a current 326174708Skmacy * or root directory onto which the new filesystem has just been 327174708Skmacy * mounted. If so, replace them with the new mount point. 328174708Skmacy */ 329174708Skmacystatic void 330174708Skmacycheckdirs(olddp) 331174708Skmacy struct vnode *olddp; 332174708Skmacy{ 333174708Skmacy struct filedesc *fdp; 334174708Skmacy struct vnode *newdp; 335174708Skmacy struct proc *p; 336174708Skmacy 337167514Skmacy if (olddp->v_usecount == 1) 338167514Skmacy return; 339167514Skmacy if (VFS_ROOT(olddp->v_mountedhere, &newdp)) 340167514Skmacy panic("mount: lost mount"); 341167514Skmacy for (p = allproc.lh_first; p != 0; p = p->p_list.le_next) { 342167514Skmacy fdp = p->p_fd; 343167514Skmacy if (fdp->fd_cdir == olddp) { 344167514Skmacy vrele(fdp->fd_cdir); 345167514Skmacy VREF(newdp); 346167514Skmacy fdp->fd_cdir = newdp; 347167514Skmacy } 348167514Skmacy if (fdp->fd_rdir == olddp) { 349176472Skmacy vrele(fdp->fd_rdir); 350176472Skmacy VREF(newdp); 351167514Skmacy fdp->fd_rdir = newdp; 352167514Skmacy } 353167514Skmacy } 354176472Skmacy if (rootvnode == olddp) { 355176472Skmacy vrele(rootvnode); 356176472Skmacy VREF(newdp); 357167514Skmacy rootvnode = newdp; 358167514Skmacy } 359167514Skmacy vput(newdp); 360174708Skmacy} 361169978Skmacy 362167746Skmacy/* 363169978Skmacy * Unmount a file system. 364171471Skmacy * 365167746Skmacy * Note: unmount takes a path to the vnode mounted on as argument, 366167514Skmacy * not special file (as before). 367167514Skmacy */ 368167514Skmacy#ifndef _SYS_SYSPROTO_H_ 369167514Skmacystruct unmount_args { 370167514Skmacy char *path; 371167514Skmacy int flags; 372167514Skmacy}; 373167514Skmacy#endif 374167514Skmacy/* ARGSUSED */ 375167514Skmacyint 376167514Skmacyunmount(p, uap) 377167514Skmacy struct proc *p; 378167514Skmacy register struct unmount_args /* { 379167514Skmacy syscallarg(char *) path; 380167514Skmacy syscallarg(int) flags; 381167514Skmacy } */ *uap; 382176472Skmacy{ 383176472Skmacy register struct vnode *vp; 384167514Skmacy struct mount *mp; 385167514Skmacy int error; 386167514Skmacy struct nameidata nd; 387167514Skmacy 388167514Skmacy NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, 389167514Skmacy SCARG(uap, path), p); 390167514Skmacy if (error = namei(&nd)) 391176472Skmacy return (error); 392176472Skmacy vp = nd.ni_vp; 393176472Skmacy mp = vp->v_mount; 394176472Skmacy 395176472Skmacy /* 396176472Skmacy * Only root, or the user that did the original mount is 397180583Skmacy * permitted to unmount this filesystem. 398180583Skmacy */ 399176472Skmacy if ((mp->mnt_stat.f_owner != p->p_ucred->cr_uid) && 400180583Skmacy (error = suser(p->p_ucred, &p->p_acflag))) { 401167514Skmacy vput(vp); 402167514Skmacy return (error); 403167514Skmacy } 404167514Skmacy 405167514Skmacy /* 406167514Skmacy * Don't allow unmounting the root file system. 407167514Skmacy */ 408167514Skmacy if (mp->mnt_flag & MNT_ROOTFS) { 409167514Skmacy vput(vp); 410167514Skmacy return (EINVAL); 411167514Skmacy } 412167514Skmacy 413167514Skmacy /* 414167514Skmacy * Must be the root of the filesystem 415167514Skmacy */ 416167514Skmacy if ((vp->v_flag & VROOT) == 0) { 417167514Skmacy vput(vp); 418167514Skmacy return (EINVAL); 419167514Skmacy } 420167514Skmacy vput(vp); 421167514Skmacy return (dounmount(mp, SCARG(uap, flags), p)); 422176472Skmacy} 423167514Skmacy 424167514Skmacy/* 425167514Skmacy * Do the actual file system unmount. 426167514Skmacy */ 427174708Skmacyint 428176472Skmacydounmount(mp, flags, p) 429176472Skmacy register struct mount *mp; 430176472Skmacy int flags; 431176472Skmacy struct proc *p; 432176472Skmacy{ 433174708Skmacy struct vnode *coveredvp; 434176472Skmacy int error; 435176472Skmacy 436176472Skmacy simple_lock(&mountlist_slock); 437176472Skmacy mp->mnt_kern_flag |= MNTK_UNMOUNT; 438176472Skmacy lockmgr(&mp->mnt_lock, LK_DRAIN | LK_INTERLOCK, &mountlist_slock, p); 439176472Skmacy 440176472Skmacy if (mp->mnt_flag & MNT_EXPUBLIC) 441176472Skmacy vfs_setpublicfs(NULL, NULL, NULL); 442167514Skmacy 443174708Skmacy vfs_msync(mp, MNT_WAIT); 444167514Skmacy mp->mnt_flag &=~ MNT_ASYNC; 445167514Skmacy cache_purgevfs(mp); /* remove cache entries for this file sys */ 446167514Skmacy if (mp->mnt_syncer != NULL) 447167514Skmacy vrele(mp->mnt_syncer); 448167514Skmacy if (((mp->mnt_flag & MNT_RDONLY) || 449167514Skmacy (error = VFS_SYNC(mp, MNT_WAIT, p->p_ucred, p)) == 0) || 450167514Skmacy (flags & MNT_FORCE)) 451167514Skmacy error = VFS_UNMOUNT(mp, flags, p); 452167514Skmacy simple_lock(&mountlist_slock); 453167514Skmacy if (error) { 454167514Skmacy if ((mp->mnt_flag & MNT_RDONLY) == 0 && mp->mnt_syncer == NULL) 455167514Skmacy (void) vfs_allocate_syncvnode(mp); 456167514Skmacy mp->mnt_kern_flag &= ~MNTK_UNMOUNT; 457167514Skmacy lockmgr(&mp->mnt_lock, LK_RELEASE | LK_INTERLOCK | LK_REENABLE, 458167514Skmacy &mountlist_slock, p); 459167514Skmacy return (error); 460167514Skmacy } 461167514Skmacy CIRCLEQ_REMOVE(&mountlist, mp, mnt_list); 462167514Skmacy if ((coveredvp = mp->mnt_vnodecovered) != NULLVP) { 463167514Skmacy coveredvp->v_mountedhere = (struct mount *)0; 464167514Skmacy vrele(coveredvp); 465167514Skmacy } 466167514Skmacy mp->mnt_vfc->vfc_refcount--; 467167514Skmacy if (mp->mnt_vnodelist.lh_first != NULL) 468167514Skmacy panic("unmount: dangling vnode"); 469167514Skmacy lockmgr(&mp->mnt_lock, LK_RELEASE | LK_INTERLOCK, &mountlist_slock, p); 470167514Skmacy if (mp->mnt_kern_flag & MNTK_MWAIT) 471167514Skmacy wakeup((caddr_t)mp); 472167514Skmacy free((caddr_t)mp, M_MOUNT); 473167514Skmacy return (0); 474167514Skmacy} 475167514Skmacy 476167514Skmacy/* 477167514Skmacy * Sync each mounted filesystem. 478167514Skmacy */ 479167514Skmacy#ifndef _SYS_SYSPROTO_H_ 480167514Skmacystruct sync_args { 481167514Skmacy int dummy; 482167514Skmacy}; 483167514Skmacy#endif 484167514Skmacy 485167514Skmacy#ifdef DEBUG 486167514Skmacystatic int syncprt = 0; 487167514SkmacySYSCTL_INT(_debug, OID_AUTO, syncprt, CTLFLAG_RW, &syncprt, 0, ""); 488167514Skmacy#endif 489167514Skmacy 490167514Skmacy/* ARGSUSED */ 491167514Skmacyint 492167514Skmacysync(p, uap) 493167514Skmacy struct proc *p; 494167514Skmacy struct sync_args *uap; 495167514Skmacy{ 496167514Skmacy register struct mount *mp, *nmp; 497167514Skmacy int asyncflag; 498167514Skmacy 499167514Skmacy simple_lock(&mountlist_slock); 500 for (mp = mountlist.cqh_first; mp != (void *)&mountlist; mp = nmp) { 501 if (vfs_busy(mp, LK_NOWAIT, &mountlist_slock, p)) { 502 nmp = mp->mnt_list.cqe_next; 503 continue; 504 } 505 if ((mp->mnt_flag & MNT_RDONLY) == 0) { 506 asyncflag = mp->mnt_flag & MNT_ASYNC; 507 mp->mnt_flag &= ~MNT_ASYNC; 508 vfs_msync(mp, MNT_NOWAIT); 509 VFS_SYNC(mp, MNT_NOWAIT, 510 ((p != NULL) ? p->p_ucred : NOCRED), p); 511 mp->mnt_flag |= asyncflag; 512 } 513 simple_lock(&mountlist_slock); 514 nmp = mp->mnt_list.cqe_next; 515 vfs_unbusy(mp, p); 516 } 517 simple_unlock(&mountlist_slock); 518#if 0 519/* 520 * XXX don't call vfs_bufstats() yet because that routine 521 * was not imported in the Lite2 merge. 522 */ 523#ifdef DIAGNOSTIC 524 if (syncprt) 525 vfs_bufstats(); 526#endif /* DIAGNOSTIC */ 527#endif 528 return (0); 529} 530 531/* 532 * Change filesystem quotas. 533 */ 534#ifndef _SYS_SYSPROTO_H_ 535struct quotactl_args { 536 char *path; 537 int cmd; 538 int uid; 539 caddr_t arg; 540}; 541#endif 542/* ARGSUSED */ 543int 544quotactl(p, uap) 545 struct proc *p; 546 register struct quotactl_args /* { 547 syscallarg(char *) path; 548 syscallarg(int) cmd; 549 syscallarg(int) uid; 550 syscallarg(caddr_t) arg; 551 } */ *uap; 552{ 553 register struct mount *mp; 554 int error; 555 struct nameidata nd; 556 557 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 558 if (error = namei(&nd)) 559 return (error); 560 mp = nd.ni_vp->v_mount; 561 vrele(nd.ni_vp); 562 return (VFS_QUOTACTL(mp, SCARG(uap, cmd), SCARG(uap, uid), 563 SCARG(uap, arg), p)); 564} 565 566/* 567 * Get filesystem statistics. 568 */ 569#ifndef _SYS_SYSPROTO_H_ 570struct statfs_args { 571 char *path; 572 struct statfs *buf; 573}; 574#endif 575/* ARGSUSED */ 576int 577statfs(p, uap) 578 struct proc *p; 579 register struct statfs_args /* { 580 syscallarg(char *) path; 581 syscallarg(struct statfs *) buf; 582 } */ *uap; 583{ 584 register struct mount *mp; 585 register struct statfs *sp; 586 int error; 587 struct nameidata nd; 588 struct statfs sb; 589 590 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 591 if (error = namei(&nd)) 592 return (error); 593 mp = nd.ni_vp->v_mount; 594 sp = &mp->mnt_stat; 595 vrele(nd.ni_vp); 596 error = VFS_STATFS(mp, sp, p); 597 if (error) 598 return (error); 599 sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 600 if (p->p_ucred->cr_uid != 0) { 601 bcopy((caddr_t)sp, (caddr_t)&sb, sizeof(sb)); 602 sb.f_fsid.val[0] = sb.f_fsid.val[1] = 0; 603 sp = &sb; 604 } 605 return (copyout((caddr_t)sp, (caddr_t)SCARG(uap, buf), sizeof(*sp))); 606} 607 608/* 609 * Get filesystem statistics. 610 */ 611#ifndef _SYS_SYSPROTO_H_ 612struct fstatfs_args { 613 int fd; 614 struct statfs *buf; 615}; 616#endif 617/* ARGSUSED */ 618int 619fstatfs(p, uap) 620 struct proc *p; 621 register struct fstatfs_args /* { 622 syscallarg(int) fd; 623 syscallarg(struct statfs *) buf; 624 } */ *uap; 625{ 626 struct file *fp; 627 struct mount *mp; 628 register struct statfs *sp; 629 int error; 630 struct statfs sb; 631 632 if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) 633 return (error); 634 mp = ((struct vnode *)fp->f_data)->v_mount; 635 sp = &mp->mnt_stat; 636 error = VFS_STATFS(mp, sp, p); 637 if (error) 638 return (error); 639 sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 640 if (p->p_ucred->cr_uid != 0) { 641 bcopy((caddr_t)sp, (caddr_t)&sb, sizeof(sb)); 642 sb.f_fsid.val[0] = sb.f_fsid.val[1] = 0; 643 sp = &sb; 644 } 645 return (copyout((caddr_t)sp, (caddr_t)SCARG(uap, buf), sizeof(*sp))); 646} 647 648/* 649 * Get statistics on all filesystems. 650 */ 651#ifndef _SYS_SYSPROTO_H_ 652struct getfsstat_args { 653 struct statfs *buf; 654 long bufsize; 655 int flags; 656}; 657#endif 658int 659getfsstat(p, uap) 660 struct proc *p; 661 register struct getfsstat_args /* { 662 syscallarg(struct statfs *) buf; 663 syscallarg(long) bufsize; 664 syscallarg(int) flags; 665 } */ *uap; 666{ 667 register struct mount *mp, *nmp; 668 register struct statfs *sp; 669 caddr_t sfsp; 670 long count, maxcount, error; 671 672 maxcount = SCARG(uap, bufsize) / sizeof(struct statfs); 673 sfsp = (caddr_t)SCARG(uap, buf); 674 count = 0; 675 simple_lock(&mountlist_slock); 676 for (mp = mountlist.cqh_first; mp != (void *)&mountlist; mp = nmp) { 677 if (vfs_busy(mp, LK_NOWAIT, &mountlist_slock, p)) { 678 nmp = mp->mnt_list.cqe_next; 679 continue; 680 } 681 if (sfsp && count < maxcount) { 682 sp = &mp->mnt_stat; 683 /* 684 * If MNT_NOWAIT or MNT_LAZY is specified, do not 685 * refresh the fsstat cache. MNT_NOWAIT or MNT_LAZY 686 * overrides MNT_WAIT. 687 */ 688 if (((SCARG(uap, flags) & (MNT_LAZY|MNT_NOWAIT)) == 0 || 689 (SCARG(uap, flags) & MNT_WAIT)) && 690 (error = VFS_STATFS(mp, sp, p))) { 691 simple_lock(&mountlist_slock); 692 nmp = mp->mnt_list.cqe_next; 693 vfs_unbusy(mp, p); 694 continue; 695 } 696 sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 697 error = copyout((caddr_t)sp, sfsp, sizeof(*sp)); 698 if (error) { 699 vfs_unbusy(mp, p); 700 return (error); 701 } 702 sfsp += sizeof(*sp); 703 } 704 count++; 705 simple_lock(&mountlist_slock); 706 nmp = mp->mnt_list.cqe_next; 707 vfs_unbusy(mp, p); 708 } 709 simple_unlock(&mountlist_slock); 710 if (sfsp && count > maxcount) 711 p->p_retval[0] = maxcount; 712 else 713 p->p_retval[0] = count; 714 return (0); 715} 716 717/* 718 * Change current working directory to a given file descriptor. 719 */ 720#ifndef _SYS_SYSPROTO_H_ 721struct fchdir_args { 722 int fd; 723}; 724#endif 725/* ARGSUSED */ 726int 727fchdir(p, uap) 728 struct proc *p; 729 struct fchdir_args /* { 730 syscallarg(int) fd; 731 } */ *uap; 732{ 733 register struct filedesc *fdp = p->p_fd; 734 struct vnode *vp, *tdp; 735 struct mount *mp; 736 struct file *fp; 737 int error; 738 739 if (error = getvnode(fdp, SCARG(uap, fd), &fp)) 740 return (error); 741 vp = (struct vnode *)fp->f_data; 742 VREF(vp); 743 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 744 if (vp->v_type != VDIR) 745 error = ENOTDIR; 746 else 747 error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p); 748 while (!error && (mp = vp->v_mountedhere) != NULL) { 749 if (vfs_busy(mp, 0, 0, p)) 750 continue; 751 error = VFS_ROOT(mp, &tdp); 752 vfs_unbusy(mp, p); 753 if (error) 754 break; 755 vput(vp); 756 vp = tdp; 757 } 758 if (error) { 759 vput(vp); 760 return (error); 761 } 762 VOP_UNLOCK(vp, 0, p); 763 vrele(fdp->fd_cdir); 764 fdp->fd_cdir = vp; 765 return (0); 766} 767 768/* 769 * Change current working directory (``.''). 770 */ 771#ifndef _SYS_SYSPROTO_H_ 772struct chdir_args { 773 char *path; 774}; 775#endif 776/* ARGSUSED */ 777int 778chdir(p, uap) 779 struct proc *p; 780 struct chdir_args /* { 781 syscallarg(char *) path; 782 } */ *uap; 783{ 784 register struct filedesc *fdp = p->p_fd; 785 int error; 786 struct nameidata nd; 787 788 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, 789 SCARG(uap, path), p); 790 if (error = change_dir(&nd, p)) 791 return (error); 792 vrele(fdp->fd_cdir); 793 fdp->fd_cdir = nd.ni_vp; 794 return (0); 795} 796 797/* 798 * Change notion of root (``/'') directory. 799 */ 800#ifndef _SYS_SYSPROTO_H_ 801struct chroot_args { 802 char *path; 803}; 804#endif 805/* ARGSUSED */ 806int 807chroot(p, uap) 808 struct proc *p; 809 struct chroot_args /* { 810 syscallarg(char *) path; 811 } */ *uap; 812{ 813 register struct filedesc *fdp = p->p_fd; 814 int error; 815 struct nameidata nd; 816 817 error = suser(p->p_ucred, &p->p_acflag); 818 if (error) 819 return (error); 820 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, 821 SCARG(uap, path), p); 822 if (error = change_dir(&nd, p)) 823 return (error); 824 vrele(fdp->fd_rdir); 825 fdp->fd_rdir = nd.ni_vp; 826 return (0); 827} 828 829/* 830 * Common routine for chroot and chdir. 831 */ 832static int 833change_dir(ndp, p) 834 register struct nameidata *ndp; 835 struct proc *p; 836{ 837 struct vnode *vp; 838 int error; 839 840 error = namei(ndp); 841 if (error) 842 return (error); 843 vp = ndp->ni_vp; 844 if (vp->v_type != VDIR) 845 error = ENOTDIR; 846 else 847 error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p); 848 if (error) 849 vput(vp); 850 else 851 VOP_UNLOCK(vp, 0, p); 852 return (error); 853} 854 855/* 856 * Check permissions, allocate an open file structure, 857 * and call the device open routine if any. 858 */ 859#ifndef _SYS_SYSPROTO_H_ 860struct open_args { 861 char *path; 862 int flags; 863 int mode; 864}; 865#endif 866int 867open(p, uap) 868 struct proc *p; 869 register struct open_args /* { 870 syscallarg(char *) path; 871 syscallarg(int) flags; 872 syscallarg(int) mode; 873 } */ *uap; 874{ 875 register struct filedesc *fdp = p->p_fd; 876 register struct file *fp; 877 register struct vnode *vp; 878 int cmode, flags, oflags; 879 struct file *nfp; 880 int type, indx, error; 881 struct flock lf; 882 struct nameidata nd; 883 884 oflags = SCARG(uap, flags); 885 if ((oflags & O_ACCMODE) == O_ACCMODE) 886 return (EINVAL); 887 flags = FFLAGS(oflags); 888 error = falloc(p, &nfp, &indx); 889 if (error) 890 return (error); 891 fp = nfp; 892 cmode = ((SCARG(uap, mode) &~ fdp->fd_cmask) & ALLPERMS) &~ S_ISTXT; 893 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 894 p->p_dupfd = -indx - 1; /* XXX check for fdopen */ 895 error = vn_open(&nd, flags, cmode); 896 if (error) { 897 ffree(fp); 898 if ((error == ENODEV || error == ENXIO) && 899 p->p_dupfd >= 0 && /* XXX from fdopen */ 900 (error = 901 dupfdopen(fdp, indx, p->p_dupfd, flags, error)) == 0) { 902 p->p_retval[0] = indx; 903 return (0); 904 } 905 if (error == ERESTART) 906 error = EINTR; 907 fdp->fd_ofiles[indx] = NULL; 908 return (error); 909 } 910 p->p_dupfd = 0; 911 vp = nd.ni_vp; 912 913 fp->f_flag = flags & FMASK; 914 fp->f_type = (vp->v_type == VFIFO ? DTYPE_FIFO : DTYPE_VNODE); 915 fp->f_ops = &vnops; 916 fp->f_data = (caddr_t)vp; 917 if (flags & (O_EXLOCK | O_SHLOCK)) { 918 lf.l_whence = SEEK_SET; 919 lf.l_start = 0; 920 lf.l_len = 0; 921 if (flags & O_EXLOCK) 922 lf.l_type = F_WRLCK; 923 else 924 lf.l_type = F_RDLCK; 925 type = F_FLOCK; 926 if ((flags & FNONBLOCK) == 0) 927 type |= F_WAIT; 928 VOP_UNLOCK(vp, 0, p); 929 if (error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, type)) { 930 (void) vn_close(vp, fp->f_flag, fp->f_cred, p); 931 ffree(fp); 932 fdp->fd_ofiles[indx] = NULL; 933 return (error); 934 } 935 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 936 fp->f_flag |= FHASLOCK; 937 } 938 if ((vp->v_type == VREG) && (vp->v_object == NULL)) 939 vfs_object_create(vp, p, p->p_ucred, TRUE); 940 VOP_UNLOCK(vp, 0, p); 941 p->p_retval[0] = indx; 942 return (0); 943} 944 945#ifdef COMPAT_43 946/* 947 * Create a file. 948 */ 949#ifndef _SYS_SYSPROTO_H_ 950struct ocreat_args { 951 char *path; 952 int mode; 953}; 954#endif 955int 956ocreat(p, uap) 957 struct proc *p; 958 register struct ocreat_args /* { 959 syscallarg(char *) path; 960 syscallarg(int) mode; 961 } */ *uap; 962{ 963 struct open_args /* { 964 syscallarg(char *) path; 965 syscallarg(int) flags; 966 syscallarg(int) mode; 967 } */ nuap; 968 969 SCARG(&nuap, path) = SCARG(uap, path); 970 SCARG(&nuap, mode) = SCARG(uap, mode); 971 SCARG(&nuap, flags) = O_WRONLY | O_CREAT | O_TRUNC; 972 return (open(p, &nuap)); 973} 974#endif /* COMPAT_43 */ 975 976/* 977 * Create a special file. 978 */ 979#ifndef _SYS_SYSPROTO_H_ 980struct mknod_args { 981 char *path; 982 int mode; 983 int dev; 984}; 985#endif 986/* ARGSUSED */ 987int 988mknod(p, uap) 989 struct proc *p; 990 register struct mknod_args /* { 991 syscallarg(char *) path; 992 syscallarg(int) mode; 993 syscallarg(int) dev; 994 } */ *uap; 995{ 996 register struct vnode *vp; 997 struct vattr vattr; 998 int error; 999 int whiteout; 1000 struct nameidata nd; 1001 1002 error = suser(p->p_ucred, &p->p_acflag); 1003 if (error) 1004 return (error); 1005 NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p); 1006 if (error = namei(&nd)) 1007 return (error); 1008 vp = nd.ni_vp; 1009 if (vp != NULL) 1010 error = EEXIST; 1011 else { 1012 VATTR_NULL(&vattr); 1013 vattr.va_mode = (SCARG(uap, mode) & ALLPERMS) &~ p->p_fd->fd_cmask; 1014 vattr.va_rdev = SCARG(uap, dev); 1015 whiteout = 0; 1016 1017 switch (SCARG(uap, mode) & S_IFMT) { 1018 case S_IFMT: /* used by badsect to flag bad sectors */ 1019 vattr.va_type = VBAD; 1020 break; 1021 case S_IFCHR: 1022 vattr.va_type = VCHR; 1023 break; 1024 case S_IFBLK: 1025 vattr.va_type = VBLK; 1026 break; 1027 case S_IFWHT: 1028 whiteout = 1; 1029 break; 1030 default: 1031 error = EINVAL; 1032 break; 1033 } 1034 } 1035 if (!error) { 1036 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 1037 if (whiteout) { 1038 error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, CREATE); 1039 if (error) 1040 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1041 vput(nd.ni_dvp); 1042 } else { 1043 error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, 1044 &nd.ni_cnd, &vattr); 1045 } 1046 } else { 1047 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1048 if (nd.ni_dvp == vp) 1049 vrele(nd.ni_dvp); 1050 else 1051 vput(nd.ni_dvp); 1052 if (vp) 1053 vrele(vp); 1054 } 1055 ASSERT_VOP_UNLOCKED(nd.ni_dvp, "mknod"); 1056 ASSERT_VOP_UNLOCKED(nd.ni_vp, "mknod"); 1057 return (error); 1058} 1059 1060/* 1061 * Create a named pipe. 1062 */ 1063#ifndef _SYS_SYSPROTO_H_ 1064struct mkfifo_args { 1065 char *path; 1066 int mode; 1067}; 1068#endif 1069/* ARGSUSED */ 1070int 1071mkfifo(p, uap) 1072 struct proc *p; 1073 register struct mkfifo_args /* { 1074 syscallarg(char *) path; 1075 syscallarg(int) mode; 1076 } */ *uap; 1077{ 1078 struct vattr vattr; 1079 int error; 1080 struct nameidata nd; 1081 1082 NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p); 1083 if (error = namei(&nd)) 1084 return (error); 1085 if (nd.ni_vp != NULL) { 1086 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1087 if (nd.ni_dvp == nd.ni_vp) 1088 vrele(nd.ni_dvp); 1089 else 1090 vput(nd.ni_dvp); 1091 vrele(nd.ni_vp); 1092 return (EEXIST); 1093 } 1094 VATTR_NULL(&vattr); 1095 vattr.va_type = VFIFO; 1096 vattr.va_mode = (SCARG(uap, mode) & ALLPERMS) &~ p->p_fd->fd_cmask; 1097 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 1098 return (VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr)); 1099} 1100 1101/* 1102 * Make a hard file link. 1103 */ 1104#ifndef _SYS_SYSPROTO_H_ 1105struct link_args { 1106 char *path; 1107 char *link; 1108}; 1109#endif 1110/* ARGSUSED */ 1111int 1112link(p, uap) 1113 struct proc *p; 1114 register struct link_args /* { 1115 syscallarg(char *) path; 1116 syscallarg(char *) link; 1117 } */ *uap; 1118{ 1119 register struct vnode *vp; 1120 struct nameidata nd; 1121 int error; 1122 1123 NDINIT(&nd, LOOKUP, FOLLOW|NOOBJ, UIO_USERSPACE, SCARG(uap, path), p); 1124 if (error = namei(&nd)) 1125 return (error); 1126 vp = nd.ni_vp; 1127 if (vp->v_type == VDIR) 1128 error = EPERM; /* POSIX */ 1129 else { 1130 NDINIT(&nd, CREATE, LOCKPARENT|NOOBJ, UIO_USERSPACE, SCARG(uap, link), p); 1131 error = namei(&nd); 1132 if (!error) { 1133 if (nd.ni_vp != NULL) { 1134 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1135 if (nd.ni_dvp == nd.ni_vp) 1136 vrele(nd.ni_dvp); 1137 else 1138 vput(nd.ni_dvp); 1139 if (nd.ni_vp) 1140 vrele(nd.ni_vp); 1141 error = EEXIST; 1142 } else { 1143 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, 1144 LEASE_WRITE); 1145 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 1146 error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd); 1147 } 1148 } 1149 } 1150 vrele(vp); 1151 ASSERT_VOP_UNLOCKED(nd.ni_dvp, "link"); 1152 ASSERT_VOP_UNLOCKED(nd.ni_vp, "link"); 1153 return (error); 1154} 1155 1156/* 1157 * Make a symbolic link. 1158 */ 1159#ifndef _SYS_SYSPROTO_H_ 1160struct symlink_args { 1161 char *path; 1162 char *link; 1163}; 1164#endif 1165/* ARGSUSED */ 1166int 1167symlink(p, uap) 1168 struct proc *p; 1169 register struct symlink_args /* { 1170 syscallarg(char *) path; 1171 syscallarg(char *) link; 1172 } */ *uap; 1173{ 1174 struct vattr vattr; 1175 char *path; 1176 int error; 1177 struct nameidata nd; 1178 1179 path = zalloc(namei_zone); 1180 if (error = copyinstr(SCARG(uap, path), path, MAXPATHLEN, NULL)) 1181 goto out; 1182 NDINIT(&nd, CREATE, LOCKPARENT|NOOBJ, UIO_USERSPACE, SCARG(uap, link), p); 1183 if (error = namei(&nd)) 1184 goto out; 1185 if (nd.ni_vp) { 1186 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1187 if (nd.ni_dvp == nd.ni_vp) 1188 vrele(nd.ni_dvp); 1189 else 1190 vput(nd.ni_dvp); 1191 vrele(nd.ni_vp); 1192 error = EEXIST; 1193 goto out; 1194 } 1195 VATTR_NULL(&vattr); 1196 vattr.va_mode = ACCESSPERMS &~ p->p_fd->fd_cmask; 1197 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 1198 error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr, path); 1199 ASSERT_VOP_UNLOCKED(nd.ni_dvp, "symlink"); 1200 ASSERT_VOP_UNLOCKED(nd.ni_vp, "symlink"); 1201out: 1202 zfree(namei_zone, path); 1203 return (error); 1204} 1205 1206/* 1207 * Delete a whiteout from the filesystem. 1208 */ 1209/* ARGSUSED */ 1210int 1211undelete(p, uap) 1212 struct proc *p; 1213 register struct undelete_args /* { 1214 syscallarg(char *) path; 1215 } */ *uap; 1216{ 1217 int error; 1218 struct nameidata nd; 1219 1220 NDINIT(&nd, DELETE, LOCKPARENT|DOWHITEOUT, UIO_USERSPACE, 1221 SCARG(uap, path), p); 1222 error = namei(&nd); 1223 if (error) 1224 return (error); 1225 1226 if (nd.ni_vp != NULLVP || !(nd.ni_cnd.cn_flags & ISWHITEOUT)) { 1227 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1228 if (nd.ni_dvp == nd.ni_vp) 1229 vrele(nd.ni_dvp); 1230 else 1231 vput(nd.ni_dvp); 1232 if (nd.ni_vp) 1233 vrele(nd.ni_vp); 1234 return (EEXIST); 1235 } 1236 1237 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 1238 if (error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, DELETE)) 1239 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1240 vput(nd.ni_dvp); 1241 ASSERT_VOP_UNLOCKED(nd.ni_dvp, "undelete"); 1242 ASSERT_VOP_UNLOCKED(nd.ni_vp, "undelete"); 1243 return (error); 1244} 1245 1246/* 1247 * Delete a name from the filesystem. 1248 */ 1249#ifndef _SYS_SYSPROTO_H_ 1250struct unlink_args { 1251 char *path; 1252}; 1253#endif 1254/* ARGSUSED */ 1255int 1256unlink(p, uap) 1257 struct proc *p; 1258 struct unlink_args /* { 1259 syscallarg(char *) path; 1260 } */ *uap; 1261{ 1262 register struct vnode *vp; 1263 int error; 1264 struct nameidata nd; 1265 1266 NDINIT(&nd, DELETE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p); 1267 if (error = namei(&nd)) 1268 return (error); 1269 vp = nd.ni_vp; 1270 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 1271 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 1272 1273 if (vp->v_type == VDIR) 1274 error = EPERM; /* POSIX */ 1275 else { 1276 /* 1277 * The root of a mounted filesystem cannot be deleted. 1278 * 1279 * XXX: can this only be a VDIR case? 1280 */ 1281 if (vp->v_flag & VROOT) 1282 error = EBUSY; 1283 } 1284 1285 if (!error) { 1286 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 1287 error = VOP_REMOVE(nd.ni_dvp, vp, &nd.ni_cnd); 1288 } else { 1289 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1290 if (nd.ni_dvp == vp) 1291 vrele(nd.ni_dvp); 1292 else 1293 vput(nd.ni_dvp); 1294 if (vp != NULLVP) 1295 vput(vp); 1296 } 1297 ASSERT_VOP_UNLOCKED(nd.ni_dvp, "unlink"); 1298 ASSERT_VOP_UNLOCKED(nd.ni_vp, "unlink"); 1299 return (error); 1300} 1301 1302/* 1303 * Reposition read/write file offset. 1304 */ 1305#ifndef _SYS_SYSPROTO_H_ 1306struct lseek_args { 1307 int fd; 1308 int pad; 1309 off_t offset; 1310 int whence; 1311}; 1312#endif 1313int 1314lseek(p, uap) 1315 struct proc *p; 1316 register struct lseek_args /* { 1317 syscallarg(int) fd; 1318 syscallarg(int) pad; 1319 syscallarg(off_t) offset; 1320 syscallarg(int) whence; 1321 } */ *uap; 1322{ 1323 struct ucred *cred = p->p_ucred; 1324 register struct filedesc *fdp = p->p_fd; 1325 register struct file *fp; 1326 struct vattr vattr; 1327 off_t ofs; 1328 int error; 1329 1330 if ((u_int)SCARG(uap, fd) >= fdp->fd_nfiles || 1331 (fp = fdp->fd_ofiles[SCARG(uap, fd)]) == NULL) 1332 return (EBADF); 1333 if (fp->f_type != DTYPE_VNODE) 1334 return (ESPIPE); 1335 switch (SCARG(uap, whence)) { 1336 case L_INCR: 1337 ofs = fp->f_offset + SCARG(uap, offset); 1338 break; 1339 case L_XTND: 1340 error=VOP_GETATTR((struct vnode *)fp->f_data, &vattr, cred, p); 1341 if (error) 1342 return (error); 1343 ofs = SCARG(uap, offset) + vattr.va_size; 1344 break; 1345 case L_SET: 1346 ofs = SCARG(uap, offset); 1347 break; 1348 default: 1349 return (EINVAL); 1350 } 1351 if (ofs < 0) return (EINVAL); 1352 *(off_t *)(p->p_retval) = fp->f_offset = ofs; 1353 return (0); 1354} 1355 1356#if defined(COMPAT_43) || defined(COMPAT_SUNOS) 1357/* 1358 * Reposition read/write file offset. 1359 */ 1360#ifndef _SYS_SYSPROTO_H_ 1361struct olseek_args { 1362 int fd; 1363 long offset; 1364 int whence; 1365}; 1366#endif 1367int 1368olseek(p, uap) 1369 struct proc *p; 1370 register struct olseek_args /* { 1371 syscallarg(int) fd; 1372 syscallarg(long) offset; 1373 syscallarg(int) whence; 1374 } */ *uap; 1375{ 1376 struct lseek_args /* { 1377 syscallarg(int) fd; 1378 syscallarg(int) pad; 1379 syscallarg(off_t) offset; 1380 syscallarg(int) whence; 1381 } */ nuap; 1382 int error; 1383 1384 SCARG(&nuap, fd) = SCARG(uap, fd); 1385 SCARG(&nuap, offset) = SCARG(uap, offset); 1386 SCARG(&nuap, whence) = SCARG(uap, whence); 1387 error = lseek(p, &nuap); 1388 return (error); 1389} 1390#endif /* COMPAT_43 */ 1391 1392/* 1393 * Check access permissions. 1394 */ 1395#ifndef _SYS_SYSPROTO_H_ 1396struct access_args { 1397 char *path; 1398 int flags; 1399}; 1400#endif 1401int 1402access(p, uap) 1403 struct proc *p; 1404 register struct access_args /* { 1405 syscallarg(char *) path; 1406 syscallarg(int) flags; 1407 } */ *uap; 1408{ 1409 register struct ucred *cred = p->p_ucred; 1410 register struct vnode *vp; 1411 int error, flags, t_gid, t_uid; 1412 struct nameidata nd; 1413 1414 t_uid = cred->cr_uid; 1415 t_gid = cred->cr_groups[0]; 1416 cred->cr_uid = p->p_cred->p_ruid; 1417 cred->cr_groups[0] = p->p_cred->p_rgid; 1418 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE, 1419 SCARG(uap, path), p); 1420 if (error = namei(&nd)) 1421 goto out1; 1422 vp = nd.ni_vp; 1423 1424 /* Flags == 0 means only check for existence. */ 1425 if (SCARG(uap, flags)) { 1426 flags = 0; 1427 if (SCARG(uap, flags) & R_OK) 1428 flags |= VREAD; 1429 if (SCARG(uap, flags) & W_OK) 1430 flags |= VWRITE; 1431 if (SCARG(uap, flags) & X_OK) 1432 flags |= VEXEC; 1433 if ((flags & VWRITE) == 0 || (error = vn_writechk(vp)) == 0) 1434 error = VOP_ACCESS(vp, flags, cred, p); 1435 } 1436 vput(vp); 1437out1: 1438 cred->cr_uid = t_uid; 1439 cred->cr_groups[0] = t_gid; 1440 return (error); 1441} 1442 1443#if defined(COMPAT_43) || defined(COMPAT_SUNOS) 1444/* 1445 * Get file status; this version follows links. 1446 */ 1447#ifndef _SYS_SYSPROTO_H_ 1448struct ostat_args { 1449 char *path; 1450 struct ostat *ub; 1451}; 1452#endif 1453/* ARGSUSED */ 1454int 1455ostat(p, uap) 1456 struct proc *p; 1457 register struct ostat_args /* { 1458 syscallarg(char *) path; 1459 syscallarg(struct ostat *) ub; 1460 } */ *uap; 1461{ 1462 struct stat sb; 1463 struct ostat osb; 1464 int error; 1465 struct nameidata nd; 1466 1467 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE, 1468 SCARG(uap, path), p); 1469 if (error = namei(&nd)) 1470 return (error); 1471 error = vn_stat(nd.ni_vp, &sb, p); 1472 vput(nd.ni_vp); 1473 if (error) 1474 return (error); 1475 cvtstat(&sb, &osb); 1476 error = copyout((caddr_t)&osb, (caddr_t)SCARG(uap, ub), sizeof (osb)); 1477 return (error); 1478} 1479 1480/* 1481 * Get file status; this version does not follow links. 1482 */ 1483#ifndef _SYS_SYSPROTO_H_ 1484struct olstat_args { 1485 char *path; 1486 struct ostat *ub; 1487}; 1488#endif 1489/* ARGSUSED */ 1490int 1491olstat(p, uap) 1492 struct proc *p; 1493 register struct olstat_args /* { 1494 syscallarg(char *) path; 1495 syscallarg(struct ostat *) ub; 1496 } */ *uap; 1497{ 1498 struct vnode *vp; 1499 struct stat sb; 1500 struct ostat osb; 1501 int error; 1502 struct nameidata nd; 1503 1504 NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE, 1505 SCARG(uap, path), p); 1506 if (error = namei(&nd)) 1507 return (error); 1508 vp = nd.ni_vp; 1509 error = vn_stat(vp, &sb, p); 1510 vput(vp); 1511 if (error) 1512 return (error); 1513 cvtstat(&sb, &osb); 1514 error = copyout((caddr_t)&osb, (caddr_t)SCARG(uap, ub), sizeof (osb)); 1515 return (error); 1516} 1517 1518/* 1519 * Convert from an old to a new stat structure. 1520 */ 1521void 1522cvtstat(st, ost) 1523 struct stat *st; 1524 struct ostat *ost; 1525{ 1526 1527 ost->st_dev = st->st_dev; 1528 ost->st_ino = st->st_ino; 1529 ost->st_mode = st->st_mode; 1530 ost->st_nlink = st->st_nlink; 1531 ost->st_uid = st->st_uid; 1532 ost->st_gid = st->st_gid; 1533 ost->st_rdev = st->st_rdev; 1534 if (st->st_size < (quad_t)1 << 32) 1535 ost->st_size = st->st_size; 1536 else 1537 ost->st_size = -2; 1538 ost->st_atime = st->st_atime; 1539 ost->st_mtime = st->st_mtime; 1540 ost->st_ctime = st->st_ctime; 1541 ost->st_blksize = st->st_blksize; 1542 ost->st_blocks = st->st_blocks; 1543 ost->st_flags = st->st_flags; 1544 ost->st_gen = st->st_gen; 1545} 1546#endif /* COMPAT_43 || COMPAT_SUNOS */ 1547 1548/* 1549 * Get file status; this version follows links. 1550 */ 1551#ifndef _SYS_SYSPROTO_H_ 1552struct stat_args { 1553 char *path; 1554 struct stat *ub; 1555}; 1556#endif 1557/* ARGSUSED */ 1558int 1559stat(p, uap) 1560 struct proc *p; 1561 register struct stat_args /* { 1562 syscallarg(char *) path; 1563 syscallarg(struct stat *) ub; 1564 } */ *uap; 1565{ 1566 struct stat sb; 1567 int error; 1568 struct nameidata nd; 1569 1570 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE, 1571 SCARG(uap, path), p); 1572 if (error = namei(&nd)) 1573 return (error); 1574 error = vn_stat(nd.ni_vp, &sb, p); 1575 vput(nd.ni_vp); 1576 if (error) 1577 return (error); 1578 error = copyout((caddr_t)&sb, (caddr_t)SCARG(uap, ub), sizeof (sb)); 1579 return (error); 1580} 1581 1582/* 1583 * Get file status; this version does not follow links. 1584 */ 1585#ifndef _SYS_SYSPROTO_H_ 1586struct lstat_args { 1587 char *path; 1588 struct stat *ub; 1589}; 1590#endif 1591/* ARGSUSED */ 1592int 1593lstat(p, uap) 1594 struct proc *p; 1595 register struct lstat_args /* { 1596 syscallarg(char *) path; 1597 syscallarg(struct stat *) ub; 1598 } */ *uap; 1599{ 1600 int error; 1601 struct vnode *vp; 1602 struct stat sb; 1603 struct nameidata nd; 1604 1605 NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE, 1606 SCARG(uap, path), p); 1607 if (error = namei(&nd)) 1608 return (error); 1609 vp = nd.ni_vp; 1610 error = vn_stat(vp, &sb, p); 1611 vput(vp); 1612 if (error) 1613 return (error); 1614 error = copyout((caddr_t)&sb, (caddr_t)SCARG(uap, ub), sizeof (sb)); 1615 return (error); 1616} 1617 1618/* 1619 * Get configurable pathname variables. 1620 */ 1621#ifndef _SYS_SYSPROTO_H_ 1622struct pathconf_args { 1623 char *path; 1624 int name; 1625}; 1626#endif 1627/* ARGSUSED */ 1628int 1629pathconf(p, uap) 1630 struct proc *p; 1631 register struct pathconf_args /* { 1632 syscallarg(char *) path; 1633 syscallarg(int) name; 1634 } */ *uap; 1635{ 1636 int error; 1637 struct nameidata nd; 1638 1639 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE, 1640 SCARG(uap, path), p); 1641 if (error = namei(&nd)) 1642 return (error); 1643 error = VOP_PATHCONF(nd.ni_vp, SCARG(uap, name), p->p_retval); 1644 vput(nd.ni_vp); 1645 return (error); 1646} 1647 1648/* 1649 * Return target name of a symbolic link. 1650 */ 1651#ifndef _SYS_SYSPROTO_H_ 1652struct readlink_args { 1653 char *path; 1654 char *buf; 1655 int count; 1656}; 1657#endif 1658/* ARGSUSED */ 1659int 1660readlink(p, uap) 1661 struct proc *p; 1662 register struct readlink_args /* { 1663 syscallarg(char *) path; 1664 syscallarg(char *) buf; 1665 syscallarg(int) count; 1666 } */ *uap; 1667{ 1668 register struct vnode *vp; 1669 struct iovec aiov; 1670 struct uio auio; 1671 int error; 1672 struct nameidata nd; 1673 1674 NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE, 1675 SCARG(uap, path), p); 1676 if (error = namei(&nd)) 1677 return (error); 1678 vp = nd.ni_vp; 1679 if (vp->v_type != VLNK) 1680 error = EINVAL; 1681 else { 1682 aiov.iov_base = SCARG(uap, buf); 1683 aiov.iov_len = SCARG(uap, count); 1684 auio.uio_iov = &aiov; 1685 auio.uio_iovcnt = 1; 1686 auio.uio_offset = 0; 1687 auio.uio_rw = UIO_READ; 1688 auio.uio_segflg = UIO_USERSPACE; 1689 auio.uio_procp = p; 1690 auio.uio_resid = SCARG(uap, count); 1691 error = VOP_READLINK(vp, &auio, p->p_ucred); 1692 } 1693 vput(vp); 1694 p->p_retval[0] = SCARG(uap, count) - auio.uio_resid; 1695 return (error); 1696} 1697 1698/* 1699 * Change flags of a file given a path name. 1700 */ 1701#ifndef _SYS_SYSPROTO_H_ 1702struct chflags_args { 1703 char *path; 1704 int flags; 1705}; 1706#endif 1707/* ARGSUSED */ 1708int 1709chflags(p, uap) 1710 struct proc *p; 1711 register struct chflags_args /* { 1712 syscallarg(char *) path; 1713 syscallarg(int) flags; 1714 } */ *uap; 1715{ 1716 register struct vnode *vp; 1717 struct vattr vattr; 1718 int error; 1719 struct nameidata nd; 1720 1721 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 1722 if (error = namei(&nd)) 1723 return (error); 1724 vp = nd.ni_vp; 1725 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 1726 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 1727 VATTR_NULL(&vattr); 1728 vattr.va_flags = SCARG(uap, flags); 1729 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 1730 vput(vp); 1731 return (error); 1732} 1733 1734/* 1735 * Change flags of a file given a file descriptor. 1736 */ 1737#ifndef _SYS_SYSPROTO_H_ 1738struct fchflags_args { 1739 int fd; 1740 int flags; 1741}; 1742#endif 1743/* ARGSUSED */ 1744int 1745fchflags(p, uap) 1746 struct proc *p; 1747 register struct fchflags_args /* { 1748 syscallarg(int) fd; 1749 syscallarg(int) flags; 1750 } */ *uap; 1751{ 1752 struct vattr vattr; 1753 struct vnode *vp; 1754 struct file *fp; 1755 int error; 1756 1757 if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) 1758 return (error); 1759 vp = (struct vnode *)fp->f_data; 1760 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 1761 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 1762 VATTR_NULL(&vattr); 1763 vattr.va_flags = SCARG(uap, flags); 1764 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 1765 VOP_UNLOCK(vp, 0, p); 1766 return (error); 1767} 1768 1769/* 1770 * Change mode of a file given path name. 1771 */ 1772#ifndef _SYS_SYSPROTO_H_ 1773struct chmod_args { 1774 char *path; 1775 int mode; 1776}; 1777#endif 1778/* ARGSUSED */ 1779int 1780chmod(p, uap) 1781 struct proc *p; 1782 register struct chmod_args /* { 1783 syscallarg(char *) path; 1784 syscallarg(int) mode; 1785 } */ *uap; 1786{ 1787 register struct vnode *vp; 1788 struct vattr vattr; 1789 int error; 1790 struct nameidata nd; 1791 1792 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 1793 if (error = namei(&nd)) 1794 return (error); 1795 vp = nd.ni_vp; 1796 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 1797 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 1798 VATTR_NULL(&vattr); 1799 vattr.va_mode = SCARG(uap, mode) & ALLPERMS; 1800 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 1801 vput(vp); 1802 return (error); 1803} 1804 1805/* 1806 * Change mode of a file given a file descriptor. 1807 */ 1808#ifndef _SYS_SYSPROTO_H_ 1809struct fchmod_args { 1810 int fd; 1811 int mode; 1812}; 1813#endif 1814/* ARGSUSED */ 1815int 1816fchmod(p, uap) 1817 struct proc *p; 1818 register struct fchmod_args /* { 1819 syscallarg(int) fd; 1820 syscallarg(int) mode; 1821 } */ *uap; 1822{ 1823 struct vattr vattr; 1824 struct vnode *vp; 1825 struct file *fp; 1826 int error; 1827 1828 if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) 1829 return (error); 1830 vp = (struct vnode *)fp->f_data; 1831 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 1832 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 1833 VATTR_NULL(&vattr); 1834 vattr.va_mode = SCARG(uap, mode) & ALLPERMS; 1835 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 1836 VOP_UNLOCK(vp, 0, p); 1837 return (error); 1838} 1839 1840/* 1841 * Set ownership given a path name. 1842 */ 1843#ifndef _SYS_SYSPROTO_H_ 1844struct chown_args { 1845 char *path; 1846 int uid; 1847 int gid; 1848}; 1849#endif 1850/* ARGSUSED */ 1851int 1852chown(p, uap) 1853 struct proc *p; 1854 register struct chown_args /* { 1855 syscallarg(char *) path; 1856 syscallarg(int) uid; 1857 syscallarg(int) gid; 1858 } */ *uap; 1859{ 1860 register struct vnode *vp; 1861 struct vattr vattr; 1862 int error; 1863 struct nameidata nd; 1864 1865 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 1866 if (error = namei(&nd)) 1867 return (error); 1868 vp = nd.ni_vp; 1869 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 1870 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 1871 VATTR_NULL(&vattr); 1872 vattr.va_uid = SCARG(uap, uid); 1873 vattr.va_gid = SCARG(uap, gid); 1874 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 1875 vput(vp); 1876 return (error); 1877} 1878 1879/* 1880 * Set ownership given a path name, do not cross symlinks. 1881 */ 1882#ifndef _SYS_SYSPROTO_H_ 1883struct lchown_args { 1884 char *path; 1885 int uid; 1886 int gid; 1887}; 1888#endif 1889/* ARGSUSED */ 1890int 1891lchown(p, uap) 1892 struct proc *p; 1893 register struct lchown_args /* { 1894 syscallarg(char *) path; 1895 syscallarg(int) uid; 1896 syscallarg(int) gid; 1897 } */ *uap; 1898{ 1899 register struct vnode *vp; 1900 struct vattr vattr; 1901 int error; 1902 struct nameidata nd; 1903 1904 NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 1905 if (error = namei(&nd)) 1906 return (error); 1907 vp = nd.ni_vp; 1908 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 1909 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 1910 VATTR_NULL(&vattr); 1911 vattr.va_uid = SCARG(uap, uid); 1912 vattr.va_gid = SCARG(uap, gid); 1913 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 1914 vput(vp); 1915 return (error); 1916} 1917 1918/* 1919 * Set ownership given a file descriptor. 1920 */ 1921#ifndef _SYS_SYSPROTO_H_ 1922struct fchown_args { 1923 int fd; 1924 int uid; 1925 int gid; 1926}; 1927#endif 1928/* ARGSUSED */ 1929int 1930fchown(p, uap) 1931 struct proc *p; 1932 register struct fchown_args /* { 1933 syscallarg(int) fd; 1934 syscallarg(int) uid; 1935 syscallarg(int) gid; 1936 } */ *uap; 1937{ 1938 struct vattr vattr; 1939 struct vnode *vp; 1940 struct file *fp; 1941 int error; 1942 1943 if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) 1944 return (error); 1945 vp = (struct vnode *)fp->f_data; 1946 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 1947 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 1948 VATTR_NULL(&vattr); 1949 vattr.va_uid = SCARG(uap, uid); 1950 vattr.va_gid = SCARG(uap, gid); 1951 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 1952 VOP_UNLOCK(vp, 0, p); 1953 return (error); 1954} 1955 1956/* 1957 * Set the access and modification times of a file. 1958 */ 1959#ifndef _SYS_SYSPROTO_H_ 1960struct utimes_args { 1961 char *path; 1962 struct timeval *tptr; 1963}; 1964#endif 1965/* ARGSUSED */ 1966int 1967utimes(p, uap) 1968 struct proc *p; 1969 register struct utimes_args /* { 1970 syscallarg(char *) path; 1971 syscallarg(struct timeval *) tptr; 1972 } */ *uap; 1973{ 1974 register struct vnode *vp; 1975 struct timeval tv[2]; 1976 struct vattr vattr; 1977 int error; 1978 struct nameidata nd; 1979 1980 VATTR_NULL(&vattr); 1981 if (SCARG(uap, tptr) == NULL) { 1982 microtime(&tv[0]); 1983 tv[1] = tv[0]; 1984 vattr.va_vaflags |= VA_UTIMES_NULL; 1985 } else if (error = copyin((caddr_t)SCARG(uap, tptr), (caddr_t)tv, 1986 sizeof (tv))) 1987 return (error); 1988 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 1989 if (error = namei(&nd)) 1990 return (error); 1991 vp = nd.ni_vp; 1992 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 1993 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 1994 vattr.va_atime.tv_sec = tv[0].tv_sec; 1995 vattr.va_atime.tv_nsec = tv[0].tv_usec * 1000; 1996 vattr.va_mtime.tv_sec = tv[1].tv_sec; 1997 vattr.va_mtime.tv_nsec = tv[1].tv_usec * 1000; 1998 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 1999 vput(vp); 2000 return (error); 2001} 2002 2003/* 2004 * Truncate a file given its path name. 2005 */ 2006#ifndef _SYS_SYSPROTO_H_ 2007struct truncate_args { 2008 char *path; 2009 int pad; 2010 off_t length; 2011}; 2012#endif 2013/* ARGSUSED */ 2014int 2015truncate(p, uap) 2016 struct proc *p; 2017 register struct truncate_args /* { 2018 syscallarg(char *) path; 2019 syscallarg(int) pad; 2020 syscallarg(off_t) length; 2021 } */ *uap; 2022{ 2023 register struct vnode *vp; 2024 struct vattr vattr; 2025 int error; 2026 struct nameidata nd; 2027 2028 if (uap->length < 0) 2029 return(EINVAL); 2030 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 2031 if (error = namei(&nd)) 2032 return (error); 2033 vp = nd.ni_vp; 2034 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 2035 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 2036 if (vp->v_type == VDIR) 2037 error = EISDIR; 2038 else if ((error = vn_writechk(vp)) == 0 && 2039 (error = VOP_ACCESS(vp, VWRITE, p->p_ucred, p)) == 0) { 2040 VATTR_NULL(&vattr); 2041 vattr.va_size = SCARG(uap, length); 2042 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 2043 } 2044 vput(vp); 2045 return (error); 2046} 2047 2048/* 2049 * Truncate a file given a file descriptor. 2050 */ 2051#ifndef _SYS_SYSPROTO_H_ 2052struct ftruncate_args { 2053 int fd; 2054 int pad; 2055 off_t length; 2056}; 2057#endif 2058/* ARGSUSED */ 2059int 2060ftruncate(p, uap) 2061 struct proc *p; 2062 register struct ftruncate_args /* { 2063 syscallarg(int) fd; 2064 syscallarg(int) pad; 2065 syscallarg(off_t) length; 2066 } */ *uap; 2067{ 2068 struct vattr vattr; 2069 struct vnode *vp; 2070 struct file *fp; 2071 int error; 2072 2073 if (uap->length < 0) 2074 return(EINVAL); 2075 if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) 2076 return (error); 2077 if ((fp->f_flag & FWRITE) == 0) 2078 return (EINVAL); 2079 vp = (struct vnode *)fp->f_data; 2080 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 2081 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 2082 if (vp->v_type == VDIR) 2083 error = EISDIR; 2084 else if ((error = vn_writechk(vp)) == 0) { 2085 VATTR_NULL(&vattr); 2086 vattr.va_size = SCARG(uap, length); 2087 error = VOP_SETATTR(vp, &vattr, fp->f_cred, p); 2088 } 2089 VOP_UNLOCK(vp, 0, p); 2090 return (error); 2091} 2092 2093#if defined(COMPAT_43) || defined(COMPAT_SUNOS) 2094/* 2095 * Truncate a file given its path name. 2096 */ 2097#ifndef _SYS_SYSPROTO_H_ 2098struct otruncate_args { 2099 char *path; 2100 long length; 2101}; 2102#endif 2103/* ARGSUSED */ 2104int 2105otruncate(p, uap) 2106 struct proc *p; 2107 register struct otruncate_args /* { 2108 syscallarg(char *) path; 2109 syscallarg(long) length; 2110 } */ *uap; 2111{ 2112 struct truncate_args /* { 2113 syscallarg(char *) path; 2114 syscallarg(int) pad; 2115 syscallarg(off_t) length; 2116 } */ nuap; 2117 2118 SCARG(&nuap, path) = SCARG(uap, path); 2119 SCARG(&nuap, length) = SCARG(uap, length); 2120 return (truncate(p, &nuap)); 2121} 2122 2123/* 2124 * Truncate a file given a file descriptor. 2125 */ 2126#ifndef _SYS_SYSPROTO_H_ 2127struct oftruncate_args { 2128 int fd; 2129 long length; 2130}; 2131#endif 2132/* ARGSUSED */ 2133int 2134oftruncate(p, uap) 2135 struct proc *p; 2136 register struct oftruncate_args /* { 2137 syscallarg(int) fd; 2138 syscallarg(long) length; 2139 } */ *uap; 2140{ 2141 struct ftruncate_args /* { 2142 syscallarg(int) fd; 2143 syscallarg(int) pad; 2144 syscallarg(off_t) length; 2145 } */ nuap; 2146 2147 SCARG(&nuap, fd) = SCARG(uap, fd); 2148 SCARG(&nuap, length) = SCARG(uap, length); 2149 return (ftruncate(p, &nuap)); 2150} 2151#endif /* COMPAT_43 || COMPAT_SUNOS */ 2152 2153/* 2154 * Sync an open file. 2155 */ 2156#ifndef _SYS_SYSPROTO_H_ 2157struct fsync_args { 2158 int fd; 2159}; 2160#endif 2161/* ARGSUSED */ 2162int 2163fsync(p, uap) 2164 struct proc *p; 2165 struct fsync_args /* { 2166 syscallarg(int) fd; 2167 } */ *uap; 2168{ 2169 register struct vnode *vp; 2170 struct file *fp; 2171 int error; 2172 2173 if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) 2174 return (error); 2175 vp = (struct vnode *)fp->f_data; 2176 if ((error = vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p)) == NULL) { 2177 if (vp->v_object) { 2178 vm_object_page_clean(vp->v_object, 0, 0, FALSE); 2179 } 2180 if (vp->v_mount && (vp->v_mount->mnt_flag & MNT_SOFTDEP)) { 2181 error = VOP_FSYNC(vp, fp->f_cred, MNT_LAZY, p); 2182 } else { 2183 error = VOP_FSYNC(vp, fp->f_cred, 2184 (vp->v_mount && (vp->v_mount->mnt_flag & MNT_ASYNC)) ? 2185 MNT_NOWAIT : MNT_WAIT, p); 2186 } 2187 VOP_UNLOCK(vp, 0, p); 2188 2189 if ((vp->v_mount->mnt_flag & MNT_SOFTDEP) && bioops.io_sync) 2190 (*bioops.io_sync)(NULL); 2191 } 2192 return (error); 2193} 2194 2195/* 2196 * Rename files. Source and destination must either both be directories, 2197 * or both not be directories. If target is a directory, it must be empty. 2198 */ 2199#ifndef _SYS_SYSPROTO_H_ 2200struct rename_args { 2201 char *from; 2202 char *to; 2203}; 2204#endif 2205/* ARGSUSED */ 2206int 2207rename(p, uap) 2208 struct proc *p; 2209 register struct rename_args /* { 2210 syscallarg(char *) from; 2211 syscallarg(char *) to; 2212 } */ *uap; 2213{ 2214 register struct vnode *tvp, *fvp, *tdvp; 2215 struct nameidata fromnd, tond; 2216 int error; 2217 2218 NDINIT(&fromnd, DELETE, WANTPARENT | SAVESTART, UIO_USERSPACE, 2219 SCARG(uap, from), p); 2220 if (error = namei(&fromnd)) 2221 return (error); 2222 fvp = fromnd.ni_vp; 2223 NDINIT(&tond, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART | NOOBJ, 2224 UIO_USERSPACE, SCARG(uap, to), p); 2225 if (fromnd.ni_vp->v_type == VDIR) 2226 tond.ni_cnd.cn_flags |= WILLBEDIR; 2227 if (error = namei(&tond)) { 2228 /* Translate error code for rename("dir1", "dir2/."). */ 2229 if (error == EISDIR && fvp->v_type == VDIR) 2230 error = EINVAL; 2231 VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 2232 vrele(fromnd.ni_dvp); 2233 vrele(fvp); 2234 goto out1; 2235 } 2236 tdvp = tond.ni_dvp; 2237 tvp = tond.ni_vp; 2238 if (tvp != NULL) { 2239 if (fvp->v_type == VDIR && tvp->v_type != VDIR) { 2240 error = ENOTDIR; 2241 goto out; 2242 } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) { 2243 error = EISDIR; 2244 goto out; 2245 } 2246 } 2247 if (fvp == tdvp) 2248 error = EINVAL; 2249 /* 2250 * If source is the same as the destination (that is the 2251 * same inode number with the same name in the same directory), 2252 * then there is nothing to do. 2253 */ 2254 if (fvp == tvp && fromnd.ni_dvp == tdvp && 2255 fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen && 2256 !bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr, 2257 fromnd.ni_cnd.cn_namelen)) 2258 error = -1; 2259out: 2260 if (!error) { 2261 VOP_LEASE(tdvp, p, p->p_ucred, LEASE_WRITE); 2262 if (fromnd.ni_dvp != tdvp) { 2263 VOP_LEASE(fromnd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 2264 } 2265 if (tvp) { 2266 VOP_LEASE(tvp, p, p->p_ucred, LEASE_WRITE); 2267 } 2268 error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd, 2269 tond.ni_dvp, tond.ni_vp, &tond.ni_cnd); 2270 } else { 2271 VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd); 2272 if (tdvp == tvp) 2273 vrele(tdvp); 2274 else 2275 vput(tdvp); 2276 if (tvp) 2277 vput(tvp); 2278 VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 2279 vrele(fromnd.ni_dvp); 2280 vrele(fvp); 2281 } 2282 vrele(tond.ni_startdir); 2283 ASSERT_VOP_UNLOCKED(fromnd.ni_dvp, "rename"); 2284 ASSERT_VOP_UNLOCKED(fromnd.ni_vp, "rename"); 2285 ASSERT_VOP_UNLOCKED(tond.ni_dvp, "rename"); 2286 ASSERT_VOP_UNLOCKED(tond.ni_vp, "rename"); 2287 zfree(namei_zone, tond.ni_cnd.cn_pnbuf); 2288out1: 2289 if (fromnd.ni_startdir) 2290 vrele(fromnd.ni_startdir); 2291 zfree(namei_zone, fromnd.ni_cnd.cn_pnbuf); 2292 if (error == -1) 2293 return (0); 2294 return (error); 2295} 2296 2297/* 2298 * Make a directory file. 2299 */ 2300#ifndef _SYS_SYSPROTO_H_ 2301struct mkdir_args { 2302 char *path; 2303 int mode; 2304}; 2305#endif 2306/* ARGSUSED */ 2307int 2308mkdir(p, uap) 2309 struct proc *p; 2310 register struct mkdir_args /* { 2311 syscallarg(char *) path; 2312 syscallarg(int) mode; 2313 } */ *uap; 2314{ 2315 register struct vnode *vp; 2316 struct vattr vattr; 2317 int error; 2318 struct nameidata nd; 2319 2320 NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p); 2321 nd.ni_cnd.cn_flags |= WILLBEDIR; 2322 if (error = namei(&nd)) 2323 return (error); 2324 vp = nd.ni_vp; 2325 if (vp != NULL) { 2326 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 2327 if (nd.ni_dvp == vp) 2328 vrele(nd.ni_dvp); 2329 else 2330 vput(nd.ni_dvp); 2331 vrele(vp); 2332 return (EEXIST); 2333 } 2334 VATTR_NULL(&vattr); 2335 vattr.va_type = VDIR; 2336 vattr.va_mode = (SCARG(uap, mode) & ACCESSPERMS) &~ p->p_fd->fd_cmask; 2337 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 2338 error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr); 2339 if (!error) 2340 vput(nd.ni_vp); 2341 ASSERT_VOP_UNLOCKED(nd.ni_dvp, "mkdir"); 2342 ASSERT_VOP_UNLOCKED(nd.ni_vp, "mkdir"); 2343 return (error); 2344} 2345 2346/* 2347 * Remove a directory file. 2348 */ 2349#ifndef _SYS_SYSPROTO_H_ 2350struct rmdir_args { 2351 char *path; 2352}; 2353#endif 2354/* ARGSUSED */ 2355int 2356rmdir(p, uap) 2357 struct proc *p; 2358 struct rmdir_args /* { 2359 syscallarg(char *) path; 2360 } */ *uap; 2361{ 2362 register struct vnode *vp; 2363 int error; 2364 struct nameidata nd; 2365 2366 NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE, 2367 SCARG(uap, path), p); 2368 if (error = namei(&nd)) 2369 return (error); 2370 vp = nd.ni_vp; 2371 if (vp->v_type != VDIR) { 2372 error = ENOTDIR; 2373 goto out; 2374 } 2375 /* 2376 * No rmdir "." please. 2377 */ 2378 if (nd.ni_dvp == vp) { 2379 error = EINVAL; 2380 goto out; 2381 } 2382 /* 2383 * The root of a mounted filesystem cannot be deleted. 2384 */ 2385 if (vp->v_flag & VROOT) 2386 error = EBUSY; 2387out: 2388 if (!error) { 2389 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 2390 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 2391 error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); 2392 } else { 2393 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 2394 if (nd.ni_dvp == vp) 2395 vrele(nd.ni_dvp); 2396 else 2397 vput(nd.ni_dvp); 2398 vput(vp); 2399 } 2400 ASSERT_VOP_UNLOCKED(nd.ni_dvp, "rmdir"); 2401 ASSERT_VOP_UNLOCKED(nd.ni_vp, "rmdir"); 2402 return (error); 2403} 2404 2405#ifdef COMPAT_43 2406/* 2407 * Read a block of directory entries in a file system independent format. 2408 */ 2409#ifndef _SYS_SYSPROTO_H_ 2410struct ogetdirentries_args { 2411 int fd; 2412 char *buf; 2413 u_int count; 2414 long *basep; 2415}; 2416#endif 2417int 2418ogetdirentries(p, uap) 2419 struct proc *p; 2420 register struct ogetdirentries_args /* { 2421 syscallarg(int) fd; 2422 syscallarg(char *) buf; 2423 syscallarg(u_int) count; 2424 syscallarg(long *) basep; 2425 } */ *uap; 2426{ 2427 register struct vnode *vp; 2428 struct file *fp; 2429 struct uio auio, kuio; 2430 struct iovec aiov, kiov; 2431 struct dirent *dp, *edp; 2432 caddr_t dirbuf; 2433 int error, eofflag, readcnt; 2434 long loff; 2435 2436 if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) 2437 return (error); 2438 if ((fp->f_flag & FREAD) == 0) 2439 return (EBADF); 2440 vp = (struct vnode *)fp->f_data; 2441unionread: 2442 if (vp->v_type != VDIR) 2443 return (EINVAL); 2444 aiov.iov_base = SCARG(uap, buf); 2445 aiov.iov_len = SCARG(uap, count); 2446 auio.uio_iov = &aiov; 2447 auio.uio_iovcnt = 1; 2448 auio.uio_rw = UIO_READ; 2449 auio.uio_segflg = UIO_USERSPACE; 2450 auio.uio_procp = p; 2451 auio.uio_resid = SCARG(uap, count); 2452 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 2453 loff = auio.uio_offset = fp->f_offset; 2454# if (BYTE_ORDER != LITTLE_ENDIAN) 2455 if (vp->v_mount->mnt_maxsymlinklen <= 0) { 2456 error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, 2457 NULL, NULL); 2458 fp->f_offset = auio.uio_offset; 2459 } else 2460# endif 2461 { 2462 kuio = auio; 2463 kuio.uio_iov = &kiov; 2464 kuio.uio_segflg = UIO_SYSSPACE; 2465 kiov.iov_len = SCARG(uap, count); 2466 MALLOC(dirbuf, caddr_t, SCARG(uap, count), M_TEMP, M_WAITOK); 2467 kiov.iov_base = dirbuf; 2468 error = VOP_READDIR(vp, &kuio, fp->f_cred, &eofflag, 2469 NULL, NULL); 2470 fp->f_offset = kuio.uio_offset; 2471 if (error == 0) { 2472 readcnt = SCARG(uap, count) - kuio.uio_resid; 2473 edp = (struct dirent *)&dirbuf[readcnt]; 2474 for (dp = (struct dirent *)dirbuf; dp < edp; ) { 2475# if (BYTE_ORDER == LITTLE_ENDIAN) 2476 /* 2477 * The expected low byte of 2478 * dp->d_namlen is our dp->d_type. 2479 * The high MBZ byte of dp->d_namlen 2480 * is our dp->d_namlen. 2481 */ 2482 dp->d_type = dp->d_namlen; 2483 dp->d_namlen = 0; 2484# else 2485 /* 2486 * The dp->d_type is the high byte 2487 * of the expected dp->d_namlen, 2488 * so must be zero'ed. 2489 */ 2490 dp->d_type = 0; 2491# endif 2492 if (dp->d_reclen > 0) { 2493 dp = (struct dirent *) 2494 ((char *)dp + dp->d_reclen); 2495 } else { 2496 error = EIO; 2497 break; 2498 } 2499 } 2500 if (dp >= edp) 2501 error = uiomove(dirbuf, readcnt, &auio); 2502 } 2503 FREE(dirbuf, M_TEMP); 2504 } 2505 VOP_UNLOCK(vp, 0, p); 2506 if (error) 2507 return (error); 2508 2509#ifdef UNION 2510{ 2511 if ((SCARG(uap, count) == auio.uio_resid) && 2512 (vp->v_op == union_vnodeop_p)) { 2513 struct vnode *lvp; 2514 2515 lvp = union_dircache(vp, p); 2516 if (lvp != NULLVP) { 2517 struct vattr va; 2518 2519 /* 2520 * If the directory is opaque, 2521 * then don't show lower entries 2522 */ 2523 error = VOP_GETATTR(vp, &va, fp->f_cred, p); 2524 if (va.va_flags & OPAQUE) { 2525 vput(lvp); 2526 lvp = NULL; 2527 } 2528 } 2529 2530 if (lvp != NULLVP) { 2531 error = VOP_OPEN(lvp, FREAD, fp->f_cred, p); 2532 if (error) { 2533 vput(lvp); 2534 return (error); 2535 } 2536 VOP_UNLOCK(lvp, 0, p); 2537 fp->f_data = (caddr_t) lvp; 2538 fp->f_offset = 0; 2539 error = vn_close(vp, FREAD, fp->f_cred, p); 2540 if (error) 2541 return (error); 2542 vp = lvp; 2543 goto unionread; 2544 } 2545 } 2546} 2547#endif /* UNION */ 2548 2549 if ((SCARG(uap, count) == auio.uio_resid) && 2550 (vp->v_flag & VROOT) && 2551 (vp->v_mount->mnt_flag & MNT_UNION)) { 2552 struct vnode *tvp = vp; 2553 vp = vp->v_mount->mnt_vnodecovered; 2554 VREF(vp); 2555 fp->f_data = (caddr_t) vp; 2556 fp->f_offset = 0; 2557 vrele(tvp); 2558 goto unionread; 2559 } 2560 error = copyout((caddr_t)&loff, (caddr_t)SCARG(uap, basep), 2561 sizeof(long)); 2562 p->p_retval[0] = SCARG(uap, count) - auio.uio_resid; 2563 return (error); 2564} 2565#endif /* COMPAT_43 */ 2566 2567/* 2568 * Read a block of directory entries in a file system independent format. 2569 */ 2570#ifndef _SYS_SYSPROTO_H_ 2571struct getdirentries_args { 2572 int fd; 2573 char *buf; 2574 u_int count; 2575 long *basep; 2576}; 2577#endif 2578int 2579getdirentries(p, uap) 2580 struct proc *p; 2581 register struct getdirentries_args /* { 2582 syscallarg(int) fd; 2583 syscallarg(char *) buf; 2584 syscallarg(u_int) count; 2585 syscallarg(long *) basep; 2586 } */ *uap; 2587{ 2588 register struct vnode *vp; 2589 struct file *fp; 2590 struct uio auio; 2591 struct iovec aiov; 2592 long loff; 2593 int error, eofflag; 2594 2595 if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) 2596 return (error); 2597 if ((fp->f_flag & FREAD) == 0) 2598 return (EBADF); 2599 vp = (struct vnode *)fp->f_data; 2600unionread: 2601 if (vp->v_type != VDIR) 2602 return (EINVAL); 2603 aiov.iov_base = SCARG(uap, buf); 2604 aiov.iov_len = SCARG(uap, count); 2605 auio.uio_iov = &aiov; 2606 auio.uio_iovcnt = 1; 2607 auio.uio_rw = UIO_READ; 2608 auio.uio_segflg = UIO_USERSPACE; 2609 auio.uio_procp = p; 2610 auio.uio_resid = SCARG(uap, count); 2611 /* vn_lock(vp, LK_SHARED | LK_RETRY, p); */ 2612 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 2613 loff = auio.uio_offset = fp->f_offset; 2614 error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, NULL, NULL); 2615 fp->f_offset = auio.uio_offset; 2616 VOP_UNLOCK(vp, 0, p); 2617 if (error) 2618 return (error); 2619 2620#ifdef UNION 2621{ 2622 if ((SCARG(uap, count) == auio.uio_resid) && 2623 (vp->v_op == union_vnodeop_p)) { 2624 struct vnode *lvp; 2625 2626 lvp = union_dircache(vp, p); 2627 if (lvp != NULLVP) { 2628 struct vattr va; 2629 2630 /* 2631 * If the directory is opaque, 2632 * then don't show lower entries 2633 */ 2634 error = VOP_GETATTR(vp, &va, fp->f_cred, p); 2635 if (va.va_flags & OPAQUE) { 2636 vput(lvp); 2637 lvp = NULL; 2638 } 2639 } 2640 2641 if (lvp != NULLVP) { 2642 error = VOP_OPEN(lvp, FREAD, fp->f_cred, p); 2643 if (error) { 2644 vput(lvp); 2645 return (error); 2646 } 2647 VOP_UNLOCK(lvp, 0, p); 2648 fp->f_data = (caddr_t) lvp; 2649 fp->f_offset = 0; 2650 error = vn_close(vp, FREAD, fp->f_cred, p); 2651 if (error) 2652 return (error); 2653 vp = lvp; 2654 goto unionread; 2655 } 2656 } 2657} 2658#endif /* UNION */ 2659 2660 if ((SCARG(uap, count) == auio.uio_resid) && 2661 (vp->v_flag & VROOT) && 2662 (vp->v_mount->mnt_flag & MNT_UNION)) { 2663 struct vnode *tvp = vp; 2664 vp = vp->v_mount->mnt_vnodecovered; 2665 VREF(vp); 2666 fp->f_data = (caddr_t) vp; 2667 fp->f_offset = 0; 2668 vrele(tvp); 2669 goto unionread; 2670 } 2671 error = copyout((caddr_t)&loff, (caddr_t)SCARG(uap, basep), 2672 sizeof(long)); 2673 p->p_retval[0] = SCARG(uap, count) - auio.uio_resid; 2674 return (error); 2675} 2676 2677/* 2678 * Set the mode mask for creation of filesystem nodes. 2679 */ 2680#ifndef _SYS_SYSPROTO_H_ 2681struct umask_args { 2682 int newmask; 2683}; 2684#endif 2685int 2686umask(p, uap) 2687 struct proc *p; 2688 struct umask_args /* { 2689 syscallarg(int) newmask; 2690 } */ *uap; 2691{ 2692 register struct filedesc *fdp; 2693 2694 fdp = p->p_fd; 2695 p->p_retval[0] = fdp->fd_cmask; 2696 fdp->fd_cmask = SCARG(uap, newmask) & ALLPERMS; 2697 return (0); 2698} 2699 2700/* 2701 * Void all references to file by ripping underlying filesystem 2702 * away from vnode. 2703 */ 2704#ifndef _SYS_SYSPROTO_H_ 2705struct revoke_args { 2706 char *path; 2707}; 2708#endif 2709/* ARGSUSED */ 2710int 2711revoke(p, uap) 2712 struct proc *p; 2713 register struct revoke_args /* { 2714 syscallarg(char *) path; 2715 } */ *uap; 2716{ 2717 register struct vnode *vp; 2718 struct vattr vattr; 2719 int error; 2720 struct nameidata nd; 2721 2722 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 2723 if (error = namei(&nd)) 2724 return (error); 2725 vp = nd.ni_vp; 2726 if (error = VOP_GETATTR(vp, &vattr, p->p_ucred, p)) 2727 goto out; 2728 if (p->p_ucred->cr_uid != vattr.va_uid && 2729 (error = suser(p->p_ucred, &p->p_acflag))) 2730 goto out; 2731 if (vp->v_usecount > 1 || (vp->v_flag & VALIASED)) 2732 VOP_REVOKE(vp, REVOKEALL); 2733out: 2734 vrele(vp); 2735 return (error); 2736} 2737 2738/* 2739 * Convert a user file descriptor to a kernel file entry. 2740 */ 2741int 2742getvnode(fdp, fd, fpp) 2743 struct filedesc *fdp; 2744 int fd; 2745 struct file **fpp; 2746{ 2747 struct file *fp; 2748 2749 if ((u_int)fd >= fdp->fd_nfiles || 2750 (fp = fdp->fd_ofiles[fd]) == NULL) 2751 return (EBADF); 2752 if (fp->f_type != DTYPE_VNODE && fp->f_type != DTYPE_FIFO) 2753 return (EINVAL); 2754 *fpp = fp; 2755 return (0); 2756} 2757#ifndef _SYS_SYSPROTO_H_ 2758struct __getcwd_args { 2759 u_char *buf; 2760 u_int buflen; 2761}; 2762#endif 2763#define STATNODE(mode, name, var) \ 2764 SYSCTL_INT(_vfs_cache, OID_AUTO, name, mode, var, 0, ""); 2765 2766static int disablecwd; 2767SYSCTL_INT(_debug, OID_AUTO, disablecwd, CTLFLAG_RW, &disablecwd, 0, ""); 2768 2769static u_long numcwdcalls; STATNODE(CTLFLAG_RD, numcwdcalls, &numcwdcalls); 2770static u_long numcwdfail1; STATNODE(CTLFLAG_RD, numcwdfail1, &numcwdfail1); 2771static u_long numcwdfail2; STATNODE(CTLFLAG_RD, numcwdfail2, &numcwdfail2); 2772static u_long numcwdfail3; STATNODE(CTLFLAG_RD, numcwdfail3, &numcwdfail3); 2773static u_long numcwdfail4; STATNODE(CTLFLAG_RD, numcwdfail4, &numcwdfail4); 2774static u_long numcwdfound; STATNODE(CTLFLAG_RD, numcwdfound, &numcwdfound); 2775int 2776__getcwd(p, uap) 2777 struct proc *p; 2778 struct __getcwd_args *uap; 2779{ 2780 char *bp, *buf; 2781 int error, i, slash_prefixed; 2782 struct filedesc *fdp; 2783 struct namecache *ncp; 2784 struct vnode *vp; 2785 2786 numcwdcalls++; 2787 if (disablecwd) 2788 return (ENODEV); 2789 if (uap->buflen < 2) 2790 return (EINVAL); 2791 if (uap->buflen > MAXPATHLEN) 2792 uap->buflen = MAXPATHLEN; 2793 buf = bp = malloc(uap->buflen, M_TEMP, M_WAITOK); 2794 bp += uap->buflen - 1; 2795 *bp = '\0'; 2796 fdp = p->p_fd; 2797 slash_prefixed = 0; 2798 for (vp = fdp->fd_cdir; vp != fdp->fd_rdir && vp != rootvnode;) { 2799 if (vp->v_flag & VROOT) { 2800 vp = vp->v_mount->mnt_vnodecovered; 2801 continue; 2802 } 2803 if (vp->v_dd->v_id != vp->v_ddid) { 2804 numcwdfail1++; 2805 free(buf, M_TEMP); 2806 return (ENOTDIR); 2807 } 2808 ncp = TAILQ_FIRST(&vp->v_cache_dst); 2809 if (!ncp) { 2810 numcwdfail2++; 2811 free(buf, M_TEMP); 2812 return (ENOENT); 2813 } 2814 if (ncp->nc_dvp != vp->v_dd) { 2815 numcwdfail3++; 2816 free(buf, M_TEMP); 2817 return (EBADF); 2818 } 2819 for (i = ncp->nc_nlen - 1; i >= 0; i--) { 2820 if (bp == buf) { 2821 numcwdfail4++; 2822 free(buf, M_TEMP); 2823 return (ENOMEM); 2824 } 2825 *--bp = ncp->nc_name[i]; 2826 } 2827 if (bp == buf) { 2828 numcwdfail4++; 2829 free(buf, M_TEMP); 2830 return (ENOMEM); 2831 } 2832 *--bp = '/'; 2833 slash_prefixed = 1; 2834 vp = vp->v_dd; 2835 } 2836 if (!slash_prefixed) { 2837 if (bp == buf) { 2838 numcwdfail4++; 2839 free(buf, M_TEMP); 2840 return (ENOMEM); 2841 } 2842 *--bp = '/'; 2843 } 2844 numcwdfound++; 2845 error = copyout(bp, uap->buf, strlen(bp) + 1); 2846 free(buf, M_TEMP); 2847 return (error); 2848} 2849