123405Smckusick /* 263428Sbostic * Copyright (c) 1989, 1993 363428Sbostic * The Regents of the University of California. All rights reserved. 465771Sbostic * (c) UNIX System Laboratories, Inc. 565771Sbostic * All or some portions of this file are derived from material licensed 665771Sbostic * to the University of California by American Telephone and Telegraph 765771Sbostic * Co. or Unix System Laboratories, Inc. and are reproduced herein with 865771Sbostic * the permission of UNIX System Laboratories, Inc. 923405Smckusick * 1044459Sbostic * %sccs.include.redist.c% 1137741Smckusick * 12*69409Smckusick * @(#)vfs_syscalls.c 8.37 (Berkeley) 05/14/95 1323405Smckusick */ 1437Sbill 1556517Sbostic #include <sys/param.h> 1656517Sbostic #include <sys/systm.h> 1756517Sbostic #include <sys/namei.h> 1856517Sbostic #include <sys/filedesc.h> 1956517Sbostic #include <sys/kernel.h> 2056517Sbostic #include <sys/file.h> 2156517Sbostic #include <sys/stat.h> 2256517Sbostic #include <sys/vnode.h> 2356517Sbostic #include <sys/mount.h> 2456517Sbostic #include <sys/proc.h> 2556517Sbostic #include <sys/uio.h> 2656517Sbostic #include <sys/malloc.h> 2756517Sbostic #include <sys/dirent.h> 2856517Sbostic 2968318Scgd #include <sys/syscallargs.h> 3068318Scgd 3153468Smckusick #include <vm/vm.h> 3259875Smckusick #include <sys/sysctl.h> 3337Sbill 3464410Sbostic static int change_dir __P((struct nameidata *ndp, struct proc *p)); 3568318Scgd static void checkdirs __P((struct vnode *olddp)); 3664410Sbostic 3737741Smckusick /* 3837741Smckusick * Virtual File System System Calls 3937741Smckusick */ 4012756Ssam 419167Ssam /* 4264410Sbostic * Mount a file system. 439167Ssam */ 4442441Smckusick /* ARGSUSED */ 4568318Scgd int 4642441Smckusick mount(p, uap, retval) 4745914Smckusick struct proc *p; 4868318Scgd register struct mount_args /* { 4968663Smckusick syscallarg(char *) type; 5068318Scgd syscallarg(char *) path; 5168318Scgd syscallarg(int) flags; 5268318Scgd syscallarg(caddr_t) data; 5368318Scgd } */ *uap; 5468318Scgd register_t *retval; 5542441Smckusick { 5668663Smckusick struct vnode *vp; 5768663Smckusick struct mount *mp; 5868663Smckusick struct vfsconf *vfsp; 5940111Smckusick int error, flag; 6067532Smckusick struct vattr va; 6168663Smckusick u_long fstypenum; 6247540Skarels struct nameidata nd; 6368663Smckusick char fstypename[MFSNAMELEN]; 646254Sroot 6537741Smckusick /* 6637741Smckusick * Get vnode to be covered 6737741Smckusick */ 6868318Scgd NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, 6968318Scgd SCARG(uap, path), p); 7052322Smckusick if (error = namei(&nd)) 7147540Skarels return (error); 7252322Smckusick vp = nd.ni_vp; 7368318Scgd if (SCARG(uap, flags) & MNT_UPDATE) { 7439335Smckusick if ((vp->v_flag & VROOT) == 0) { 7539335Smckusick vput(vp); 7647540Skarels return (EINVAL); 7739335Smckusick } 7839335Smckusick mp = vp->v_mount; 7957047Smckusick flag = mp->mnt_flag; 8039335Smckusick /* 8157047Smckusick * We only allow the filesystem to be reloaded if it 8257047Smckusick * is currently mounted read-only. 8339335Smckusick */ 8468318Scgd if ((SCARG(uap, flags) & MNT_RELOAD) && 8557047Smckusick ((mp->mnt_flag & MNT_RDONLY) == 0)) { 8639335Smckusick vput(vp); 8747540Skarels return (EOPNOTSUPP); /* Needs translation */ 8839335Smckusick } 8957047Smckusick mp->mnt_flag |= 9068318Scgd SCARG(uap, flags) & (MNT_RELOAD | MNT_FORCE | MNT_UPDATE); 9167532Smckusick /* 9267532Smckusick * Only root, or the user that did the original mount is 9367532Smckusick * permitted to update it. 9467532Smckusick */ 9567532Smckusick if (mp->mnt_stat.f_owner != p->p_ucred->cr_uid && 9667532Smckusick (error = suser(p->p_ucred, &p->p_acflag))) { 9767532Smckusick vput(vp); 9867532Smckusick return (error); 9967532Smckusick } 10067532Smckusick /* 10167532Smckusick * Do not allow NFS export by non-root users. Silently 10267532Smckusick * enforce MNT_NOSUID and MNT_NODEV for non-root users. 10367532Smckusick */ 10467532Smckusick if (p->p_ucred->cr_uid != 0) { 10568318Scgd if (SCARG(uap, flags) & MNT_EXPORTED) { 10667532Smckusick vput(vp); 10767532Smckusick return (EPERM); 10867532Smckusick } 10968318Scgd SCARG(uap, flags) |= MNT_NOSUID | MNT_NODEV; 11067532Smckusick } 111*69409Smckusick VOP_UNLOCK(vp, 0, p); 11239335Smckusick goto update; 11339335Smckusick } 11467532Smckusick /* 11567532Smckusick * If the user is not root, ensure that they own the directory 11667532Smckusick * onto which we are attempting to mount. 11767532Smckusick */ 11867532Smckusick if ((error = VOP_GETATTR(vp, &va, p->p_ucred, p)) || 11967532Smckusick (va.va_uid != p->p_ucred->cr_uid && 12067532Smckusick (error = suser(p->p_ucred, &p->p_acflag)))) { 12167532Smckusick vput(vp); 12267532Smckusick return (error); 12367532Smckusick } 12467532Smckusick /* 12567532Smckusick * Do not allow NFS export by non-root users. Silently 12667532Smckusick * enforce MNT_NOSUID and MNT_NODEV for non-root users. 12767532Smckusick */ 12867532Smckusick if (p->p_ucred->cr_uid != 0) { 12968318Scgd if (SCARG(uap, flags) & MNT_EXPORTED) { 13067532Smckusick vput(vp); 13167532Smckusick return (EPERM); 13267532Smckusick } 13368318Scgd SCARG(uap, flags) |= MNT_NOSUID | MNT_NODEV; 13467532Smckusick } 13557793Smckusick if (error = vinvalbuf(vp, V_SAVE, p->p_ucred, p, 0, 0)) 13654441Smckusick return (error); 13737741Smckusick if (vp->v_type != VDIR) { 13837741Smckusick vput(vp); 13947540Skarels return (ENOTDIR); 14037741Smckusick } 14168663Smckusick #ifdef COMPAT_43 14268663Smckusick /* 14368663Smckusick * Historically filesystem types were identified by number. If we 14468663Smckusick * get an integer for the filesystem type instead of a string, we 14568663Smckusick * check to see if it matches one of the historic filesystem types. 14668663Smckusick */ 14768663Smckusick fstypenum = (u_long)SCARG(uap, type); 14868663Smckusick if (fstypenum < maxvfsconf) { 14968663Smckusick for (vfsp = vfsconf; vfsp; vfsp = vfsp->vfc_next) 15068663Smckusick if (vfsp->vfc_typenum == fstypenum) 15168663Smckusick break; 15268663Smckusick if (vfsp == NULL) { 15368663Smckusick vput(vp); 15468663Smckusick return (ENODEV); 15568663Smckusick } 15668663Smckusick strncpy(fstypename, vfsp->vfc_name, MFSNAMELEN); 15768663Smckusick } else 15868663Smckusick #endif /* COMPAT_43 */ 15968663Smckusick if (error = copyinstr(SCARG(uap, type), fstypename, MFSNAMELEN, NULL)) { 16037741Smckusick vput(vp); 16168663Smckusick return (error); 16268663Smckusick } 16368663Smckusick for (vfsp = vfsconf; vfsp; vfsp = vfsp->vfc_next) 16468663Smckusick if (!strcmp(vfsp->vfc_name, fstypename)) 16568663Smckusick break; 16668663Smckusick if (vfsp == NULL) { 16768663Smckusick vput(vp); 16847540Skarels return (ENODEV); 16937741Smckusick } 17067969Spendry if (vp->v_mountedhere != NULL) { 17167961Smckusick vput(vp); 17267961Smckusick return (EBUSY); 17367961Smckusick } 17437741Smckusick 17537741Smckusick /* 17668663Smckusick * Allocate and initialize the filesystem. 17737741Smckusick */ 17837741Smckusick mp = (struct mount *)malloc((u_long)sizeof(struct mount), 17937741Smckusick M_MOUNT, M_WAITOK); 18054172Smckusick bzero((char *)mp, (u_long)sizeof(struct mount)); 18168663Smckusick mp->mnt_op = vfsp->vfc_vfsops; 18239335Smckusick if (error = vfs_lock(mp)) { 18339335Smckusick free((caddr_t)mp, M_MOUNT); 18439335Smckusick vput(vp); 18547540Skarels return (error); 18639335Smckusick } 18768663Smckusick mp->mnt_vfc = vfsp; 18868663Smckusick vfsp->vfc_refcount++; 18968663Smckusick mp->mnt_stat.f_type = vfsp->vfc_typenum; 19068663Smckusick mp->mnt_flag |= vfsp->vfc_flags & MNT_VISFLAGMASK; 19168663Smckusick strncpy(mp->mnt_stat.f_fstypename, vfsp->vfc_name, MFSNAMELEN); 19239335Smckusick vp->v_mountedhere = mp; 19341400Smckusick mp->mnt_vnodecovered = vp; 19467532Smckusick mp->mnt_stat.f_owner = p->p_ucred->cr_uid; 19539335Smckusick update: 19639335Smckusick /* 19739335Smckusick * Set the mount level flags. 19839335Smckusick */ 19968318Scgd if (SCARG(uap, flags) & MNT_RDONLY) 20041400Smckusick mp->mnt_flag |= MNT_RDONLY; 20157047Smckusick else if (mp->mnt_flag & MNT_RDONLY) 20257047Smckusick mp->mnt_flag |= MNT_WANTRDWR; 20365613Smckusick mp->mnt_flag &=~ (MNT_NOSUID | MNT_NOEXEC | MNT_NODEV | 20465613Smckusick MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC); 20568318Scgd mp->mnt_flag |= SCARG(uap, flags) & (MNT_NOSUID | MNT_NOEXEC | 20668318Scgd MNT_NODEV | MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC); 20739335Smckusick /* 20839335Smckusick * Mount the filesystem. 20939335Smckusick */ 21068318Scgd error = VFS_MOUNT(mp, SCARG(uap, path), SCARG(uap, data), &nd, p); 21141400Smckusick if (mp->mnt_flag & MNT_UPDATE) { 21239335Smckusick vrele(vp); 21357047Smckusick if (mp->mnt_flag & MNT_WANTRDWR) 21457047Smckusick mp->mnt_flag &= ~MNT_RDONLY; 21557047Smckusick mp->mnt_flag &=~ 21657047Smckusick (MNT_UPDATE | MNT_RELOAD | MNT_FORCE | MNT_WANTRDWR); 21740111Smckusick if (error) 21841400Smckusick mp->mnt_flag = flag; 21947540Skarels return (error); 22039335Smckusick } 22140110Smckusick /* 22240110Smckusick * Put the new filesystem on the mount list after root. 22340110Smckusick */ 22437741Smckusick cache_purge(vp); 22537741Smckusick if (!error) { 22669325Smckusick CIRCLEQ_INSERT_TAIL(&mountlist, mp, mnt_list); 22767974Smckusick checkdirs(vp); 228*69409Smckusick VOP_UNLOCK(vp, 0, p); 22937741Smckusick vfs_unlock(mp); 23048026Smckusick error = VFS_START(mp, 0, p); 23137741Smckusick } else { 23265259Smckusick mp->mnt_vnodecovered->v_mountedhere = (struct mount *)0; 23368663Smckusick mp->mnt_vfc->vfc_refcount--; 23465259Smckusick vfs_unlock(mp); 23537741Smckusick free((caddr_t)mp, M_MOUNT); 23639335Smckusick vput(vp); 23737741Smckusick } 23847540Skarels return (error); 2396254Sroot } 2406254Sroot 2419167Ssam /* 24267974Smckusick * Scan all active processes to see if any of them have a current 24367974Smckusick * or root directory onto which the new filesystem has just been 24467974Smckusick * mounted. If so, replace them with the new mount point. 24567974Smckusick */ 24668318Scgd static void 24767974Smckusick checkdirs(olddp) 24867974Smckusick struct vnode *olddp; 24967974Smckusick { 25067974Smckusick struct filedesc *fdp; 25167974Smckusick struct vnode *newdp; 25267974Smckusick struct proc *p; 25367974Smckusick 25467974Smckusick if (olddp->v_usecount == 1) 25567974Smckusick return; 25667974Smckusick if (VFS_ROOT(olddp->v_mountedhere, &newdp)) 25767974Smckusick panic("mount: lost mount"); 25867974Smckusick for (p = allproc.lh_first; p != 0; p = p->p_list.le_next) { 25967974Smckusick fdp = p->p_fd; 26067974Smckusick if (fdp->fd_cdir == olddp) { 26167974Smckusick vrele(fdp->fd_cdir); 26267974Smckusick VREF(newdp); 26367974Smckusick fdp->fd_cdir = newdp; 26467974Smckusick } 26567974Smckusick if (fdp->fd_rdir == olddp) { 26667974Smckusick vrele(fdp->fd_rdir); 26767974Smckusick VREF(newdp); 26867974Smckusick fdp->fd_rdir = newdp; 26967974Smckusick } 27067974Smckusick } 27167974Smckusick if (rootvnode == olddp) { 27267974Smckusick vrele(rootvnode); 27367974Smckusick VREF(newdp); 27467974Smckusick rootvnode = newdp; 27567974Smckusick } 27667974Smckusick vput(newdp); 27767974Smckusick } 27867974Smckusick 27967974Smckusick /* 28064410Sbostic * Unmount a file system. 28137741Smckusick * 28237741Smckusick * Note: unmount takes a path to the vnode mounted on as argument, 28337741Smckusick * not special file (as before). 2849167Ssam */ 28542441Smckusick /* ARGSUSED */ 28668318Scgd int 28742441Smckusick unmount(p, uap, retval) 28845914Smckusick struct proc *p; 28968318Scgd register struct unmount_args /* { 29068318Scgd syscallarg(char *) path; 29168318Scgd syscallarg(int) flags; 29268318Scgd } */ *uap; 29368318Scgd register_t *retval; 29442441Smckusick { 29537741Smckusick register struct vnode *vp; 29639356Smckusick struct mount *mp; 29737741Smckusick int error; 29847540Skarels struct nameidata nd; 2996254Sroot 30068318Scgd NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, 30168318Scgd SCARG(uap, path), p); 30252322Smckusick if (error = namei(&nd)) 30347540Skarels return (error); 30452322Smckusick vp = nd.ni_vp; 30567532Smckusick mp = vp->v_mount; 30666172Spendry 30737741Smckusick /* 30867532Smckusick * Only root, or the user that did the original mount is 30967532Smckusick * permitted to unmount this filesystem. 31066172Spendry */ 31167532Smckusick if ((mp->mnt_stat.f_owner != p->p_ucred->cr_uid) && 31266172Spendry (error = suser(p->p_ucred, &p->p_acflag))) { 31366172Spendry vput(vp); 31466172Spendry return (error); 31566172Spendry } 31666172Spendry 31766172Spendry /* 31869334Smckusick * Don't allow unmounting the root file system. 31969334Smckusick */ 32069334Smckusick if (mp->mnt_flag & MNT_ROOTFS) { 32169334Smckusick vput(vp); 32269334Smckusick return (EINVAL); 32369334Smckusick } 32469334Smckusick 32569334Smckusick /* 32637741Smckusick * Must be the root of the filesystem 32737741Smckusick */ 32837741Smckusick if ((vp->v_flag & VROOT) == 0) { 32937741Smckusick vput(vp); 33047540Skarels return (EINVAL); 33137741Smckusick } 33237741Smckusick vput(vp); 33368318Scgd return (dounmount(mp, SCARG(uap, flags), p)); 33439356Smckusick } 33539356Smckusick 33639356Smckusick /* 33764410Sbostic * Do the actual file system unmount. 33839356Smckusick */ 33968318Scgd int 34048026Smckusick dounmount(mp, flags, p) 34139356Smckusick register struct mount *mp; 34239356Smckusick int flags; 34348026Smckusick struct proc *p; 34439356Smckusick { 34539356Smckusick struct vnode *coveredvp; 34639356Smckusick int error; 34739356Smckusick 34841400Smckusick coveredvp = mp->mnt_vnodecovered; 34941298Smckusick if (vfs_busy(mp)) 35041298Smckusick return (EBUSY); 35141400Smckusick mp->mnt_flag |= MNT_UNMOUNT; 35237741Smckusick if (error = vfs_lock(mp)) 35339356Smckusick return (error); 35437741Smckusick 35565859Smckusick mp->mnt_flag &=~ MNT_ASYNC; 35645738Smckusick vnode_pager_umount(mp); /* release cached vnodes */ 35737741Smckusick cache_purgevfs(mp); /* remove cache entries for this file sys */ 35869357Spendry if (((mp->mnt_flag & MNT_RDONLY) || 35969357Spendry (error = VFS_SYNC(mp, MNT_WAIT, p->p_ucred, p)) == 0) || 36054441Smckusick (flags & MNT_FORCE)) 36148026Smckusick error = VFS_UNMOUNT(mp, flags, p); 36241400Smckusick mp->mnt_flag &= ~MNT_UNMOUNT; 36341298Smckusick vfs_unbusy(mp); 36437741Smckusick if (error) { 36537741Smckusick vfs_unlock(mp); 36637741Smckusick } else { 36769325Smckusick CIRCLEQ_REMOVE(&mountlist, mp, mnt_list); 36869325Smckusick if (coveredvp != NULLVP) { 36969325Smckusick vrele(coveredvp); 37069325Smckusick mp->mnt_vnodecovered->v_mountedhere = (struct mount *)0; 37169325Smckusick } 37268663Smckusick mp->mnt_vfc->vfc_refcount--; 37365259Smckusick vfs_unlock(mp); 37465259Smckusick if (mp->mnt_vnodelist.lh_first != NULL) 37552287Smckusick panic("unmount: dangling vnode"); 37637741Smckusick free((caddr_t)mp, M_MOUNT); 37737741Smckusick } 37839356Smckusick return (error); 3796254Sroot } 3806254Sroot 3819167Ssam /* 38237741Smckusick * Sync each mounted filesystem. 3839167Ssam */ 38467403Smckusick #ifdef DEBUG 38556352Smckusick int syncprt = 0; 38659875Smckusick struct ctldebug debug0 = { "syncprt", &syncprt }; 38756352Smckusick #endif 38856352Smckusick 38939491Smckusick /* ARGSUSED */ 39068318Scgd int 39142441Smckusick sync(p, uap, retval) 39245914Smckusick struct proc *p; 39368318Scgd void *uap; 39468318Scgd register_t *retval; 3956254Sroot { 39665259Smckusick register struct mount *mp, *nmp; 39765859Smckusick int asyncflag; 39837741Smckusick 39969325Smckusick for (mp = mountlist.cqh_first; mp != (void *)&mountlist; mp = nmp) { 40067678Smckusick /* 40167678Smckusick * Get the next pointer in case we hang on vfs_busy 40267678Smckusick * while we are being unmounted. 40367678Smckusick */ 40469325Smckusick nmp = mp->mnt_list.cqe_next; 40540343Smckusick /* 40640343Smckusick * The lock check below is to avoid races with mount 40740343Smckusick * and unmount. 40840343Smckusick */ 40941400Smckusick if ((mp->mnt_flag & (MNT_MLOCK|MNT_RDONLY|MNT_MPBUSY)) == 0 && 41041298Smckusick !vfs_busy(mp)) { 41165859Smckusick asyncflag = mp->mnt_flag & MNT_ASYNC; 41265859Smckusick mp->mnt_flag &= ~MNT_ASYNC; 41354441Smckusick VFS_SYNC(mp, MNT_NOWAIT, p->p_ucred, p); 41465859Smckusick if (asyncflag) 41565859Smckusick mp->mnt_flag |= MNT_ASYNC; 41667678Smckusick /* 41767678Smckusick * Get the next pointer again, as the next filesystem 41867678Smckusick * might have been unmounted while we were sync'ing. 41967678Smckusick */ 42069325Smckusick nmp = mp->mnt_list.cqe_next; 42165259Smckusick vfs_unbusy(mp); 42265259Smckusick } 42365259Smckusick } 42456352Smckusick #ifdef DIAGNOSTIC 42556352Smckusick if (syncprt) 42656352Smckusick vfs_bufstats(); 42756352Smckusick #endif /* DIAGNOSTIC */ 42847688Skarels return (0); 42937741Smckusick } 43037741Smckusick 43137741Smckusick /* 43264410Sbostic * Change filesystem quotas. 43341298Smckusick */ 43442441Smckusick /* ARGSUSED */ 43568318Scgd int 43642441Smckusick quotactl(p, uap, retval) 43745914Smckusick struct proc *p; 43868318Scgd register struct quotactl_args /* { 43968318Scgd syscallarg(char *) path; 44068318Scgd syscallarg(int) cmd; 44168318Scgd syscallarg(int) uid; 44268318Scgd syscallarg(caddr_t) arg; 44368318Scgd } */ *uap; 44468318Scgd register_t *retval; 44542441Smckusick { 44641298Smckusick register struct mount *mp; 44741298Smckusick int error; 44847540Skarels struct nameidata nd; 44941298Smckusick 45068318Scgd NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 45152322Smckusick if (error = namei(&nd)) 45247540Skarels return (error); 45352322Smckusick mp = nd.ni_vp->v_mount; 45452322Smckusick vrele(nd.ni_vp); 45568318Scgd return (VFS_QUOTACTL(mp, SCARG(uap, cmd), SCARG(uap, uid), 45668318Scgd SCARG(uap, arg), p)); 45741298Smckusick } 45841298Smckusick 45941298Smckusick /* 46049365Smckusick * Get filesystem statistics. 46137741Smckusick */ 46242441Smckusick /* ARGSUSED */ 46368318Scgd int 46442441Smckusick statfs(p, uap, retval) 46545914Smckusick struct proc *p; 46668318Scgd register struct statfs_args /* { 46768318Scgd syscallarg(char *) path; 46868318Scgd syscallarg(struct statfs *) buf; 46968318Scgd } */ *uap; 47068318Scgd register_t *retval; 47142441Smckusick { 47239464Smckusick register struct mount *mp; 47340343Smckusick register struct statfs *sp; 47437741Smckusick int error; 47547540Skarels struct nameidata nd; 47637741Smckusick 47768318Scgd NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 47852322Smckusick if (error = namei(&nd)) 47947540Skarels return (error); 48052322Smckusick mp = nd.ni_vp->v_mount; 48141400Smckusick sp = &mp->mnt_stat; 48252322Smckusick vrele(nd.ni_vp); 48348026Smckusick if (error = VFS_STATFS(mp, sp, p)) 48447540Skarels return (error); 48541400Smckusick sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 48668318Scgd return (copyout((caddr_t)sp, (caddr_t)SCARG(uap, buf), sizeof(*sp))); 48737741Smckusick } 48837741Smckusick 48942441Smckusick /* 49049365Smckusick * Get filesystem statistics. 49142441Smckusick */ 49242441Smckusick /* ARGSUSED */ 49368318Scgd int 49442441Smckusick fstatfs(p, uap, retval) 49545914Smckusick struct proc *p; 49668318Scgd register struct fstatfs_args /* { 49768318Scgd syscallarg(int) fd; 49868318Scgd syscallarg(struct statfs *) buf; 49968318Scgd } */ *uap; 50068318Scgd register_t *retval; 50142441Smckusick { 50237741Smckusick struct file *fp; 50339464Smckusick struct mount *mp; 50440343Smckusick register struct statfs *sp; 50537741Smckusick int error; 50637741Smckusick 50768318Scgd if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) 50847540Skarels return (error); 50939464Smckusick mp = ((struct vnode *)fp->f_data)->v_mount; 51041400Smckusick sp = &mp->mnt_stat; 51148026Smckusick if (error = VFS_STATFS(mp, sp, p)) 51247540Skarels return (error); 51341400Smckusick sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 51468318Scgd return (copyout((caddr_t)sp, (caddr_t)SCARG(uap, buf), sizeof(*sp))); 51537741Smckusick } 51637741Smckusick 51737741Smckusick /* 51849365Smckusick * Get statistics on all filesystems. 51938270Smckusick */ 52068318Scgd int 52142441Smckusick getfsstat(p, uap, retval) 52245914Smckusick struct proc *p; 52368318Scgd register struct getfsstat_args /* { 52468318Scgd syscallarg(struct statfs *) buf; 52568318Scgd syscallarg(long) bufsize; 52668318Scgd syscallarg(int) flags; 52768318Scgd } */ *uap; 52868318Scgd register_t *retval; 52942441Smckusick { 53065259Smckusick register struct mount *mp, *nmp; 53140343Smckusick register struct statfs *sp; 53239606Smckusick caddr_t sfsp; 53338270Smckusick long count, maxcount, error; 53438270Smckusick 53568318Scgd maxcount = SCARG(uap, bufsize) / sizeof(struct statfs); 53668318Scgd sfsp = (caddr_t)SCARG(uap, buf); 53769325Smckusick count = 0; 53869325Smckusick for (mp = mountlist.cqh_first; mp != (void *)&mountlist; mp = nmp) { 53969325Smckusick nmp = mp->mnt_list.cqe_next; 54041400Smckusick if (sfsp && count < maxcount && 54141400Smckusick ((mp->mnt_flag & MNT_MLOCK) == 0)) { 54241400Smckusick sp = &mp->mnt_stat; 54340343Smckusick /* 54440343Smckusick * If MNT_NOWAIT is specified, do not refresh the 54540343Smckusick * fsstat cache. MNT_WAIT overrides MNT_NOWAIT. 54640343Smckusick */ 54768318Scgd if (((SCARG(uap, flags) & MNT_NOWAIT) == 0 || 54868318Scgd (SCARG(uap, flags) & MNT_WAIT)) && 54965259Smckusick (error = VFS_STATFS(mp, sp, p))) 55039607Smckusick continue; 55141400Smckusick sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 55240343Smckusick if (error = copyout((caddr_t)sp, sfsp, sizeof(*sp))) 55347540Skarels return (error); 55440343Smckusick sfsp += sizeof(*sp); 55538270Smckusick } 55639606Smckusick count++; 55765259Smckusick } 55838270Smckusick if (sfsp && count > maxcount) 55942441Smckusick *retval = maxcount; 56038270Smckusick else 56142441Smckusick *retval = count; 56247540Skarels return (0); 56338270Smckusick } 56438270Smckusick 56538270Smckusick /* 56638259Smckusick * Change current working directory to a given file descriptor. 56738259Smckusick */ 56842441Smckusick /* ARGSUSED */ 56968318Scgd int 57042441Smckusick fchdir(p, uap, retval) 57145914Smckusick struct proc *p; 57268318Scgd struct fchdir_args /* { 57368318Scgd syscallarg(int) fd; 57468318Scgd } */ *uap; 57568318Scgd register_t *retval; 57638259Smckusick { 57745914Smckusick register struct filedesc *fdp = p->p_fd; 57867974Smckusick struct vnode *vp, *tdp; 57967974Smckusick struct mount *mp; 58038259Smckusick struct file *fp; 58138259Smckusick int error; 58238259Smckusick 58368318Scgd if (error = getvnode(fdp, SCARG(uap, fd), &fp)) 58447540Skarels return (error); 58538259Smckusick vp = (struct vnode *)fp->f_data; 58667974Smckusick VREF(vp); 587*69409Smckusick vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 58838259Smckusick if (vp->v_type != VDIR) 58938259Smckusick error = ENOTDIR; 59038259Smckusick else 59148026Smckusick error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p); 59267974Smckusick while (!error && (mp = vp->v_mountedhere) != NULL) { 59367974Smckusick if (mp->mnt_flag & MNT_MLOCK) { 59467974Smckusick mp->mnt_flag |= MNT_MWAIT; 59567974Smckusick sleep((caddr_t)mp, PVFS); 59667974Smckusick continue; 59767974Smckusick } 59867974Smckusick if (error = VFS_ROOT(mp, &tdp)) 59967974Smckusick break; 60067974Smckusick vput(vp); 60167974Smckusick vp = tdp; 60267974Smckusick } 603*69409Smckusick VOP_UNLOCK(vp, 0, p); 60467974Smckusick if (error) { 60567974Smckusick vrele(vp); 60647540Skarels return (error); 60767974Smckusick } 60845914Smckusick vrele(fdp->fd_cdir); 60945914Smckusick fdp->fd_cdir = vp; 61047540Skarels return (0); 61138259Smckusick } 61238259Smckusick 61338259Smckusick /* 61437741Smckusick * Change current working directory (``.''). 61537741Smckusick */ 61642441Smckusick /* ARGSUSED */ 61768318Scgd int 61842441Smckusick chdir(p, uap, retval) 61945914Smckusick struct proc *p; 62068318Scgd struct chdir_args /* { 62168318Scgd syscallarg(char *) path; 62268318Scgd } */ *uap; 62368318Scgd register_t *retval; 62437741Smckusick { 62545914Smckusick register struct filedesc *fdp = p->p_fd; 62637741Smckusick int error; 62747540Skarels struct nameidata nd; 6286254Sroot 62968318Scgd NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, 63068318Scgd SCARG(uap, path), p); 63164410Sbostic if (error = change_dir(&nd, p)) 63247540Skarels return (error); 63345914Smckusick vrele(fdp->fd_cdir); 63452322Smckusick fdp->fd_cdir = nd.ni_vp; 63547540Skarels return (0); 63637741Smckusick } 6376254Sroot 63837741Smckusick /* 63937741Smckusick * Change notion of root (``/'') directory. 64037741Smckusick */ 64142441Smckusick /* ARGSUSED */ 64268318Scgd int 64342441Smckusick chroot(p, uap, retval) 64445914Smckusick struct proc *p; 64568318Scgd struct chroot_args /* { 64668318Scgd syscallarg(char *) path; 64768318Scgd } */ *uap; 64868318Scgd register_t *retval; 64937741Smckusick { 65045914Smckusick register struct filedesc *fdp = p->p_fd; 65137741Smckusick int error; 65247540Skarels struct nameidata nd; 65337741Smckusick 65447540Skarels if (error = suser(p->p_ucred, &p->p_acflag)) 65547540Skarels return (error); 65668318Scgd NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, 65768318Scgd SCARG(uap, path), p); 65864410Sbostic if (error = change_dir(&nd, p)) 65947540Skarels return (error); 66045914Smckusick if (fdp->fd_rdir != NULL) 66145914Smckusick vrele(fdp->fd_rdir); 66252322Smckusick fdp->fd_rdir = nd.ni_vp; 66347540Skarels return (0); 6646254Sroot } 6656254Sroot 66637Sbill /* 66737741Smckusick * Common routine for chroot and chdir. 66837741Smckusick */ 66964410Sbostic static int 67064410Sbostic change_dir(ndp, p) 67152322Smckusick register struct nameidata *ndp; 67247540Skarels struct proc *p; 67337741Smckusick { 67437741Smckusick struct vnode *vp; 67537741Smckusick int error; 67637741Smckusick 67752322Smckusick if (error = namei(ndp)) 67837741Smckusick return (error); 67937741Smckusick vp = ndp->ni_vp; 68037741Smckusick if (vp->v_type != VDIR) 68137741Smckusick error = ENOTDIR; 68237741Smckusick else 68348026Smckusick error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p); 684*69409Smckusick VOP_UNLOCK(vp, 0, p); 68537741Smckusick if (error) 68637741Smckusick vrele(vp); 68737741Smckusick return (error); 68837741Smckusick } 68937741Smckusick 69037741Smckusick /* 69142441Smckusick * Check permissions, allocate an open file structure, 69242441Smckusick * and call the device open routine if any. 6936254Sroot */ 69468318Scgd int 69542441Smckusick open(p, uap, retval) 69645914Smckusick struct proc *p; 69768318Scgd register struct open_args /* { 69868318Scgd syscallarg(char *) path; 69968318Scgd syscallarg(int) flags; 70068318Scgd syscallarg(int) mode; 70168318Scgd } */ *uap; 70268318Scgd register_t *retval; 7036254Sroot { 70445914Smckusick register struct filedesc *fdp = p->p_fd; 70542441Smckusick register struct file *fp; 70650111Smckusick register struct vnode *vp; 70764410Sbostic int flags, cmode; 70837741Smckusick struct file *nfp; 70949945Smckusick int type, indx, error; 71049945Smckusick struct flock lf; 71147540Skarels struct nameidata nd; 71237741Smckusick extern struct fileops vnops; 7136254Sroot 71445914Smckusick if (error = falloc(p, &nfp, &indx)) 71547540Skarels return (error); 71637741Smckusick fp = nfp; 71768318Scgd flags = FFLAGS(SCARG(uap, flags)); 71868318Scgd cmode = ((SCARG(uap, mode) &~ fdp->fd_cmask) & ALLPERMS) &~ S_ISTXT; 71968318Scgd NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 72045202Smckusick p->p_dupfd = -indx - 1; /* XXX check for fdopen */ 72164410Sbostic if (error = vn_open(&nd, flags, cmode)) { 72249980Smckusick ffree(fp); 72354723Smckusick if ((error == ENODEV || error == ENXIO) && 72468318Scgd p->p_dupfd >= 0 && /* XXX from fdopen */ 72564410Sbostic (error = 72668318Scgd dupfdopen(fdp, indx, p->p_dupfd, flags, error)) == 0) { 72742441Smckusick *retval = indx; 72847540Skarels return (0); 72942441Smckusick } 73040884Smckusick if (error == ERESTART) 73140884Smckusick error = EINTR; 73247688Skarels fdp->fd_ofiles[indx] = NULL; 73347540Skarels return (error); 73412756Ssam } 73553828Spendry p->p_dupfd = 0; 73652322Smckusick vp = nd.ni_vp; 73764410Sbostic fp->f_flag = flags & FMASK; 73854348Smckusick fp->f_type = DTYPE_VNODE; 73954348Smckusick fp->f_ops = &vnops; 74054348Smckusick fp->f_data = (caddr_t)vp; 74164410Sbostic if (flags & (O_EXLOCK | O_SHLOCK)) { 74249945Smckusick lf.l_whence = SEEK_SET; 74349945Smckusick lf.l_start = 0; 74449945Smckusick lf.l_len = 0; 74564410Sbostic if (flags & O_EXLOCK) 74649945Smckusick lf.l_type = F_WRLCK; 74749945Smckusick else 74849945Smckusick lf.l_type = F_RDLCK; 74949945Smckusick type = F_FLOCK; 75064410Sbostic if ((flags & FNONBLOCK) == 0) 75149945Smckusick type |= F_WAIT; 752*69409Smckusick VOP_UNLOCK(vp, 0, p); 75350111Smckusick if (error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, type)) { 75450111Smckusick (void) vn_close(vp, fp->f_flag, fp->f_cred, p); 75549980Smckusick ffree(fp); 75649945Smckusick fdp->fd_ofiles[indx] = NULL; 75749945Smckusick return (error); 75849945Smckusick } 759*69409Smckusick vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 76049949Smckusick fp->f_flag |= FHASLOCK; 76149945Smckusick } 762*69409Smckusick VOP_UNLOCK(vp, 0, p); 76342441Smckusick *retval = indx; 76447540Skarels return (0); 7656254Sroot } 7666254Sroot 76742955Smckusick #ifdef COMPAT_43 7686254Sroot /* 76964410Sbostic * Create a file. 7706254Sroot */ 77168318Scgd int 77268318Scgd compat_43_creat(p, uap, retval) 77342441Smckusick struct proc *p; 77468318Scgd register struct compat_43_creat_args /* { 77568318Scgd syscallarg(char *) path; 77668318Scgd syscallarg(int) mode; 77768318Scgd } */ *uap; 77868318Scgd register_t *retval; 7796254Sroot { 78068318Scgd struct open_args /* { 78168318Scgd syscallarg(char *) path; 78268318Scgd syscallarg(int) flags; 78368318Scgd syscallarg(int) mode; 78468318Scgd } */ nuap; 78542441Smckusick 78668318Scgd SCARG(&nuap, path) = SCARG(uap, path); 78768318Scgd SCARG(&nuap, mode) = SCARG(uap, mode); 78868318Scgd SCARG(&nuap, flags) = O_WRONLY | O_CREAT | O_TRUNC; 78968318Scgd return (open(p, &nuap, retval)); 79042441Smckusick } 79142955Smckusick #endif /* COMPAT_43 */ 79242441Smckusick 79342441Smckusick /* 79464410Sbostic * Create a special file. 79542441Smckusick */ 79642441Smckusick /* ARGSUSED */ 79768318Scgd int 79842441Smckusick mknod(p, uap, retval) 79945914Smckusick struct proc *p; 80068318Scgd register struct mknod_args /* { 80168318Scgd syscallarg(char *) path; 80268318Scgd syscallarg(int) mode; 80368318Scgd syscallarg(int) dev; 80468318Scgd } */ *uap; 80568318Scgd register_t *retval; 80642441Smckusick { 80737741Smckusick register struct vnode *vp; 80837741Smckusick struct vattr vattr; 80937741Smckusick int error; 81067575Spendry int whiteout; 81147540Skarels struct nameidata nd; 8126254Sroot 81347540Skarels if (error = suser(p->p_ucred, &p->p_acflag)) 81447540Skarels return (error); 81568318Scgd NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p); 81652322Smckusick if (error = namei(&nd)) 81747540Skarels return (error); 81852322Smckusick vp = nd.ni_vp; 81964585Sbostic if (vp != NULL) 82037741Smckusick error = EEXIST; 82164585Sbostic else { 82264585Sbostic VATTR_NULL(&vattr); 82368318Scgd vattr.va_mode = (SCARG(uap, mode) & ALLPERMS) &~ p->p_fd->fd_cmask; 82468318Scgd vattr.va_rdev = SCARG(uap, dev); 82567575Spendry whiteout = 0; 82664585Sbostic 82768318Scgd switch (SCARG(uap, mode) & S_IFMT) { 82864585Sbostic case S_IFMT: /* used by badsect to flag bad sectors */ 82964585Sbostic vattr.va_type = VBAD; 83064585Sbostic break; 83164585Sbostic case S_IFCHR: 83264585Sbostic vattr.va_type = VCHR; 83364585Sbostic break; 83464585Sbostic case S_IFBLK: 83564585Sbostic vattr.va_type = VBLK; 83664585Sbostic break; 83767575Spendry case S_IFWHT: 83867575Spendry whiteout = 1; 83967575Spendry break; 84064585Sbostic default: 84164585Sbostic error = EINVAL; 84264585Sbostic break; 84364585Sbostic } 8446254Sroot } 84567747Spendry if (!error) { 84667654Smckusick VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 84767747Spendry if (whiteout) { 84867747Spendry error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, CREATE); 84967747Spendry if (error) 85067747Spendry VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 85167747Spendry vput(nd.ni_dvp); 85267747Spendry } else { 85367747Spendry error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, 85467747Spendry &nd.ni_cnd, &vattr); 85567747Spendry } 85642465Smckusick } else { 85752322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 85852322Smckusick if (nd.ni_dvp == vp) 85952322Smckusick vrele(nd.ni_dvp); 86043344Smckusick else 86152322Smckusick vput(nd.ni_dvp); 86242465Smckusick if (vp) 86342465Smckusick vrele(vp); 86442465Smckusick } 86547540Skarels return (error); 8666254Sroot } 8676254Sroot 8686254Sroot /* 86968318Scgd * Create a named pipe. 87040285Smckusick */ 87142441Smckusick /* ARGSUSED */ 87268318Scgd int 87342441Smckusick mkfifo(p, uap, retval) 87445914Smckusick struct proc *p; 87568318Scgd register struct mkfifo_args /* { 87668318Scgd syscallarg(char *) path; 87768318Scgd syscallarg(int) mode; 87868318Scgd } */ *uap; 87968318Scgd register_t *retval; 88042441Smckusick { 88140285Smckusick struct vattr vattr; 88240285Smckusick int error; 88347540Skarels struct nameidata nd; 88440285Smckusick 88540285Smckusick #ifndef FIFO 88647540Skarels return (EOPNOTSUPP); 88740285Smckusick #else 88868318Scgd NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p); 88952322Smckusick if (error = namei(&nd)) 89047540Skarels return (error); 89152322Smckusick if (nd.ni_vp != NULL) { 89252322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 89352322Smckusick if (nd.ni_dvp == nd.ni_vp) 89452322Smckusick vrele(nd.ni_dvp); 89543344Smckusick else 89652322Smckusick vput(nd.ni_dvp); 89752322Smckusick vrele(nd.ni_vp); 89847540Skarels return (EEXIST); 89940285Smckusick } 90045785Sbostic VATTR_NULL(&vattr); 90145785Sbostic vattr.va_type = VFIFO; 90268318Scgd vattr.va_mode = (SCARG(uap, mode) & ALLPERMS) &~ p->p_fd->fd_cmask; 90367654Smckusick VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 90452322Smckusick return (VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr)); 90540285Smckusick #endif /* FIFO */ 90640285Smckusick } 90740285Smckusick 90840285Smckusick /* 90964410Sbostic * Make a hard file link. 9106254Sroot */ 91142441Smckusick /* ARGSUSED */ 91268318Scgd int 91342441Smckusick link(p, uap, retval) 91445914Smckusick struct proc *p; 91568318Scgd register struct link_args /* { 91668318Scgd syscallarg(char *) path; 91768318Scgd syscallarg(char *) link; 91868318Scgd } */ *uap; 91968318Scgd register_t *retval; 92042441Smckusick { 92164410Sbostic register struct vnode *vp; 92264410Sbostic struct nameidata nd; 92337741Smckusick int error; 9246254Sroot 92568318Scgd NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 92652322Smckusick if (error = namei(&nd)) 92747540Skarels return (error); 92852322Smckusick vp = nd.ni_vp; 92964585Sbostic if (vp->v_type != VDIR || 93064585Sbostic (error = suser(p->p_ucred, &p->p_acflag)) == 0) { 93164585Sbostic nd.ni_cnd.cn_nameiop = CREATE; 93264585Sbostic nd.ni_cnd.cn_flags = LOCKPARENT; 93368318Scgd nd.ni_dirp = SCARG(uap, link); 93464585Sbostic if ((error = namei(&nd)) == 0) { 93564585Sbostic if (nd.ni_vp != NULL) 93664585Sbostic error = EEXIST; 93764585Sbostic if (!error) { 93867654Smckusick VOP_LEASE(nd.ni_dvp, p, p->p_ucred, 93967654Smckusick LEASE_WRITE); 94067654Smckusick VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 94168538Smckusick error = VOP_LINK(vp, nd.ni_dvp, &nd.ni_cnd); 94264585Sbostic } else { 94364585Sbostic VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 94464585Sbostic if (nd.ni_dvp == nd.ni_vp) 94564585Sbostic vrele(nd.ni_dvp); 94664585Sbostic else 94764585Sbostic vput(nd.ni_dvp); 94864585Sbostic if (nd.ni_vp) 94964585Sbostic vrele(nd.ni_vp); 95064585Sbostic } 95164585Sbostic } 95242465Smckusick } 95364585Sbostic vrele(vp); 95447540Skarels return (error); 9556254Sroot } 9566254Sroot 9576254Sroot /* 95849365Smckusick * Make a symbolic link. 9596254Sroot */ 96042441Smckusick /* ARGSUSED */ 96168318Scgd int 96242441Smckusick symlink(p, uap, retval) 96345914Smckusick struct proc *p; 96468318Scgd register struct symlink_args /* { 96568318Scgd syscallarg(char *) path; 96668318Scgd syscallarg(char *) link; 96768318Scgd } */ *uap; 96868318Scgd register_t *retval; 96942441Smckusick { 97037741Smckusick struct vattr vattr; 97164410Sbostic char *path; 97237741Smckusick int error; 97347540Skarels struct nameidata nd; 9746254Sroot 97564410Sbostic MALLOC(path, char *, MAXPATHLEN, M_NAMEI, M_WAITOK); 97668318Scgd if (error = copyinstr(SCARG(uap, path), path, MAXPATHLEN, NULL)) 97742465Smckusick goto out; 97868318Scgd NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, link), p); 97952322Smckusick if (error = namei(&nd)) 98042465Smckusick goto out; 98152322Smckusick if (nd.ni_vp) { 98252322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 98352322Smckusick if (nd.ni_dvp == nd.ni_vp) 98452322Smckusick vrele(nd.ni_dvp); 98543344Smckusick else 98652322Smckusick vput(nd.ni_dvp); 98752322Smckusick vrele(nd.ni_vp); 98837741Smckusick error = EEXIST; 98937741Smckusick goto out; 9906254Sroot } 99141362Smckusick VATTR_NULL(&vattr); 99264410Sbostic vattr.va_mode = ACCESSPERMS &~ p->p_fd->fd_cmask; 99367654Smckusick VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 99464410Sbostic error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr, path); 99537741Smckusick out: 99664410Sbostic FREE(path, M_NAMEI); 99747540Skarels return (error); 9986254Sroot } 9996254Sroot 10006254Sroot /* 100167518Spendry * Delete a whiteout from the filesystem. 100267518Spendry */ 100367518Spendry /* ARGSUSED */ 100468318Scgd int 100567845Smckusick undelete(p, uap, retval) 100667518Spendry struct proc *p; 100768318Scgd register struct undelete_args /* { 100868318Scgd syscallarg(char *) path; 100968318Scgd } */ *uap; 101068318Scgd register_t *retval; 101167518Spendry { 101267518Spendry int error; 101367518Spendry struct nameidata nd; 101467518Spendry 101568318Scgd NDINIT(&nd, DELETE, LOCKPARENT|DOWHITEOUT, UIO_USERSPACE, 101668318Scgd SCARG(uap, path), p); 101767575Spendry error = namei(&nd); 101867575Spendry if (error) 101967518Spendry return (error); 102067575Spendry 102167575Spendry if (nd.ni_vp != NULLVP || !(nd.ni_cnd.cn_flags & ISWHITEOUT)) { 102267518Spendry VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 102367518Spendry if (nd.ni_dvp == nd.ni_vp) 102467518Spendry vrele(nd.ni_dvp); 102567518Spendry else 102667518Spendry vput(nd.ni_dvp); 102767518Spendry if (nd.ni_vp) 102867518Spendry vrele(nd.ni_vp); 102967518Spendry return (EEXIST); 103067518Spendry } 103167575Spendry 103267654Smckusick VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 103367747Spendry if (error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, DELETE)) 103467575Spendry VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 103567518Spendry vput(nd.ni_dvp); 103667518Spendry return (error); 103767518Spendry } 103867518Spendry 103967518Spendry /* 104049365Smckusick * Delete a name from the filesystem. 10416254Sroot */ 104242441Smckusick /* ARGSUSED */ 104368318Scgd int 104442441Smckusick unlink(p, uap, retval) 104545914Smckusick struct proc *p; 104668318Scgd struct unlink_args /* { 104768318Scgd syscallarg(char *) path; 104868318Scgd } */ *uap; 104968318Scgd register_t *retval; 10506254Sroot { 105137741Smckusick register struct vnode *vp; 105237741Smckusick int error; 105347540Skarels struct nameidata nd; 10546254Sroot 105568318Scgd NDINIT(&nd, DELETE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p); 105652322Smckusick if (error = namei(&nd)) 105747540Skarels return (error); 105852322Smckusick vp = nd.ni_vp; 105967654Smckusick VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 1060*69409Smckusick vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 106164410Sbostic 106264585Sbostic if (vp->v_type != VDIR || 106364585Sbostic (error = suser(p->p_ucred, &p->p_acflag)) == 0) { 106464585Sbostic /* 106564585Sbostic * The root of a mounted filesystem cannot be deleted. 106664585Sbostic */ 106764585Sbostic if (vp->v_flag & VROOT) 106864585Sbostic error = EBUSY; 106964585Sbostic else 107064585Sbostic (void)vnode_pager_uncache(vp); 107164585Sbostic } 107264585Sbostic 107364585Sbostic if (!error) { 107467654Smckusick VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 107552322Smckusick error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); 107642465Smckusick } else { 107752322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 107852322Smckusick if (nd.ni_dvp == vp) 107952322Smckusick vrele(nd.ni_dvp); 108043344Smckusick else 108152322Smckusick vput(nd.ni_dvp); 108267575Spendry if (vp != NULLVP) 108367575Spendry vput(vp); 108442465Smckusick } 108547540Skarels return (error); 10866254Sroot } 10876254Sroot 108864410Sbostic /* 108964410Sbostic * Reposition read/write file offset. 109064410Sbostic */ 109168318Scgd int 109260414Smckusick lseek(p, uap, retval) 109353468Smckusick struct proc *p; 109468318Scgd register struct lseek_args /* { 109568318Scgd syscallarg(int) fd; 109668318Scgd syscallarg(int) pad; 109768318Scgd syscallarg(off_t) offset; 109868318Scgd syscallarg(int) whence; 109968318Scgd } */ *uap; 110068318Scgd register_t *retval; 110142441Smckusick { 110247540Skarels struct ucred *cred = p->p_ucred; 110345914Smckusick register struct filedesc *fdp = p->p_fd; 110442441Smckusick register struct file *fp; 110537741Smckusick struct vattr vattr; 110637741Smckusick int error; 11076254Sroot 110868318Scgd if ((u_int)SCARG(uap, fd) >= fdp->fd_nfiles || 110968318Scgd (fp = fdp->fd_ofiles[SCARG(uap, fd)]) == NULL) 111047540Skarels return (EBADF); 111137741Smckusick if (fp->f_type != DTYPE_VNODE) 111247540Skarels return (ESPIPE); 111368318Scgd switch (SCARG(uap, whence)) { 111413878Ssam case L_INCR: 111568318Scgd fp->f_offset += SCARG(uap, offset); 111613878Ssam break; 111713878Ssam case L_XTND: 111864410Sbostic if (error = 111964410Sbostic VOP_GETATTR((struct vnode *)fp->f_data, &vattr, cred, p)) 112047540Skarels return (error); 112168318Scgd fp->f_offset = SCARG(uap, offset) + vattr.va_size; 112213878Ssam break; 112313878Ssam case L_SET: 112468318Scgd fp->f_offset = SCARG(uap, offset); 112513878Ssam break; 112613878Ssam default: 112747540Skarels return (EINVAL); 112813878Ssam } 112954916Storek *(off_t *)retval = fp->f_offset; 113047540Skarels return (0); 11316254Sroot } 11326254Sroot 113360414Smckusick #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 11346254Sroot /* 113564410Sbostic * Reposition read/write file offset. 113660036Smckusick */ 113768318Scgd int 113868318Scgd compat_43_lseek(p, uap, retval) 113960036Smckusick struct proc *p; 114068318Scgd register struct compat_43_lseek_args /* { 114168318Scgd syscallarg(int) fd; 114268318Scgd syscallarg(long) offset; 114368318Scgd syscallarg(int) whence; 114468318Scgd } */ *uap; 114568318Scgd register_t *retval; 114660036Smckusick { 114768318Scgd struct lseek_args /* { 114868318Scgd syscallarg(int) fd; 114968318Scgd syscallarg(int) pad; 115068318Scgd syscallarg(off_t) offset; 115168318Scgd syscallarg(int) whence; 115268318Scgd } */ nuap; 115360036Smckusick off_t qret; 115460036Smckusick int error; 115560036Smckusick 115668318Scgd SCARG(&nuap, fd) = SCARG(uap, fd); 115768318Scgd SCARG(&nuap, offset) = SCARG(uap, offset); 115868318Scgd SCARG(&nuap, whence) = SCARG(uap, whence); 115960428Smckusick error = lseek(p, &nuap, &qret); 116060036Smckusick *(long *)retval = qret; 116160036Smckusick return (error); 116260036Smckusick } 116360414Smckusick #endif /* COMPAT_43 */ 116460036Smckusick 116560036Smckusick /* 116649365Smckusick * Check access permissions. 11676254Sroot */ 116868318Scgd int 116963427Sbostic access(p, uap, retval) 117045914Smckusick struct proc *p; 117168318Scgd register struct access_args /* { 117268318Scgd syscallarg(char *) path; 117368318Scgd syscallarg(int) flags; 117468318Scgd } */ *uap; 117568318Scgd register_t *retval; 117642441Smckusick { 117747540Skarels register struct ucred *cred = p->p_ucred; 117837741Smckusick register struct vnode *vp; 117964585Sbostic int error, flags, t_gid, t_uid; 118047540Skarels struct nameidata nd; 11816254Sroot 118264585Sbostic t_uid = cred->cr_uid; 118364585Sbostic t_gid = cred->cr_groups[0]; 118447540Skarels cred->cr_uid = p->p_cred->p_ruid; 118547540Skarels cred->cr_groups[0] = p->p_cred->p_rgid; 118668318Scgd NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, 118768318Scgd SCARG(uap, path), p); 118852322Smckusick if (error = namei(&nd)) 118937741Smckusick goto out1; 119052322Smckusick vp = nd.ni_vp; 119164410Sbostic 119264410Sbostic /* Flags == 0 means only check for existence. */ 119368318Scgd if (SCARG(uap, flags)) { 119464410Sbostic flags = 0; 119568318Scgd if (SCARG(uap, flags) & R_OK) 119664410Sbostic flags |= VREAD; 119768318Scgd if (SCARG(uap, flags) & W_OK) 119864410Sbostic flags |= VWRITE; 119968318Scgd if (SCARG(uap, flags) & X_OK) 120064410Sbostic flags |= VEXEC; 120164410Sbostic if ((flags & VWRITE) == 0 || (error = vn_writechk(vp)) == 0) 120264410Sbostic error = VOP_ACCESS(vp, flags, cred, p); 12036254Sroot } 120437741Smckusick vput(vp); 120537741Smckusick out1: 120664585Sbostic cred->cr_uid = t_uid; 120764585Sbostic cred->cr_groups[0] = t_gid; 120847540Skarels return (error); 12096254Sroot } 12106254Sroot 121154348Smckusick #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 12126254Sroot /* 121364410Sbostic * Get file status; this version follows links. 121437Sbill */ 121542441Smckusick /* ARGSUSED */ 121668318Scgd int 121768318Scgd compat_43_stat(p, uap, retval) 121845914Smckusick struct proc *p; 121968318Scgd register struct compat_43_stat_args /* { 122068318Scgd syscallarg(char *) path; 122168318Scgd syscallarg(struct ostat *) ub; 122268318Scgd } */ *uap; 122368318Scgd register_t *retval; 122453468Smckusick { 122553468Smckusick struct stat sb; 122653468Smckusick struct ostat osb; 122753468Smckusick int error; 122853468Smckusick struct nameidata nd; 122953468Smckusick 123068318Scgd NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, 123168318Scgd SCARG(uap, path), p); 123253468Smckusick if (error = namei(&nd)) 123353468Smckusick return (error); 123453468Smckusick error = vn_stat(nd.ni_vp, &sb, p); 123553468Smckusick vput(nd.ni_vp); 123653468Smckusick if (error) 123753468Smckusick return (error); 123853468Smckusick cvtstat(&sb, &osb); 123968318Scgd error = copyout((caddr_t)&osb, (caddr_t)SCARG(uap, ub), sizeof (osb)); 124053468Smckusick return (error); 124153468Smckusick } 124253468Smckusick 124353468Smckusick /* 124464410Sbostic * Get file status; this version does not follow links. 124553468Smckusick */ 124653468Smckusick /* ARGSUSED */ 124768318Scgd int 124868318Scgd compat_43_lstat(p, uap, retval) 124953468Smckusick struct proc *p; 125068318Scgd register struct compat_43_lstat_args /* { 125168318Scgd syscallarg(char *) path; 125268318Scgd syscallarg(struct ostat *) ub; 125368318Scgd } */ *uap; 125468318Scgd register_t *retval; 125553468Smckusick { 125667748Smckusick struct vnode *vp, *dvp; 125767748Smckusick struct stat sb, sb1; 125853468Smckusick struct ostat osb; 125953468Smckusick int error; 126053468Smckusick struct nameidata nd; 126153468Smckusick 126267748Smckusick NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | LOCKPARENT, UIO_USERSPACE, 126368318Scgd SCARG(uap, path), p); 126453468Smckusick if (error = namei(&nd)) 126553468Smckusick return (error); 126667748Smckusick /* 126767748Smckusick * For symbolic links, always return the attributes of its 126867748Smckusick * containing directory, except for mode, size, and links. 126967748Smckusick */ 127067748Smckusick vp = nd.ni_vp; 127167748Smckusick dvp = nd.ni_dvp; 127267748Smckusick if (vp->v_type != VLNK) { 127367748Smckusick if (dvp == vp) 127467748Smckusick vrele(dvp); 127567748Smckusick else 127667748Smckusick vput(dvp); 127767748Smckusick error = vn_stat(vp, &sb, p); 127867748Smckusick vput(vp); 127967748Smckusick if (error) 128067748Smckusick return (error); 128167748Smckusick } else { 128267748Smckusick error = vn_stat(dvp, &sb, p); 128367748Smckusick vput(dvp); 128467748Smckusick if (error) { 128567748Smckusick vput(vp); 128667748Smckusick return (error); 128767748Smckusick } 128867748Smckusick error = vn_stat(vp, &sb1, p); 128967748Smckusick vput(vp); 129067748Smckusick if (error) 129167748Smckusick return (error); 129267748Smckusick sb.st_mode &= ~S_IFDIR; 129367748Smckusick sb.st_mode |= S_IFLNK; 129467748Smckusick sb.st_nlink = sb1.st_nlink; 129567748Smckusick sb.st_size = sb1.st_size; 129667748Smckusick sb.st_blocks = sb1.st_blocks; 129767748Smckusick } 129853468Smckusick cvtstat(&sb, &osb); 129968318Scgd error = copyout((caddr_t)&osb, (caddr_t)SCARG(uap, ub), sizeof (osb)); 130053468Smckusick return (error); 130153468Smckusick } 130253468Smckusick 130353468Smckusick /* 130464410Sbostic * Convert from an old to a new stat structure. 130553468Smckusick */ 130668318Scgd void 130753468Smckusick cvtstat(st, ost) 130853468Smckusick struct stat *st; 130953468Smckusick struct ostat *ost; 131053468Smckusick { 131153468Smckusick 131253468Smckusick ost->st_dev = st->st_dev; 131353468Smckusick ost->st_ino = st->st_ino; 131453468Smckusick ost->st_mode = st->st_mode; 131553468Smckusick ost->st_nlink = st->st_nlink; 131653468Smckusick ost->st_uid = st->st_uid; 131753468Smckusick ost->st_gid = st->st_gid; 131853468Smckusick ost->st_rdev = st->st_rdev; 131953468Smckusick if (st->st_size < (quad_t)1 << 32) 132053468Smckusick ost->st_size = st->st_size; 132153468Smckusick else 132253468Smckusick ost->st_size = -2; 132353468Smckusick ost->st_atime = st->st_atime; 132453468Smckusick ost->st_mtime = st->st_mtime; 132553468Smckusick ost->st_ctime = st->st_ctime; 132653468Smckusick ost->st_blksize = st->st_blksize; 132753468Smckusick ost->st_blocks = st->st_blocks; 132853468Smckusick ost->st_flags = st->st_flags; 132953468Smckusick ost->st_gen = st->st_gen; 133053468Smckusick } 133154348Smckusick #endif /* COMPAT_43 || COMPAT_SUNOS */ 133253468Smckusick 133353468Smckusick /* 133464410Sbostic * Get file status; this version follows links. 133553468Smckusick */ 133653468Smckusick /* ARGSUSED */ 133768318Scgd int 133853759Smckusick stat(p, uap, retval) 133953468Smckusick struct proc *p; 134068318Scgd register struct stat_args /* { 134168318Scgd syscallarg(char *) path; 134268318Scgd syscallarg(struct stat *) ub; 134368318Scgd } */ *uap; 134468318Scgd register_t *retval; 134537Sbill { 134642441Smckusick struct stat sb; 134742441Smckusick int error; 134847540Skarels struct nameidata nd; 134937Sbill 135068318Scgd NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, 135168318Scgd SCARG(uap, path), p); 135252322Smckusick if (error = namei(&nd)) 135347540Skarels return (error); 135452322Smckusick error = vn_stat(nd.ni_vp, &sb, p); 135552322Smckusick vput(nd.ni_vp); 135642441Smckusick if (error) 135747540Skarels return (error); 135868318Scgd error = copyout((caddr_t)&sb, (caddr_t)SCARG(uap, ub), sizeof (sb)); 135947540Skarels return (error); 136037Sbill } 136137Sbill 136237Sbill /* 136364410Sbostic * Get file status; this version does not follow links. 13645992Swnj */ 136542441Smckusick /* ARGSUSED */ 136668318Scgd int 136753759Smckusick lstat(p, uap, retval) 136845914Smckusick struct proc *p; 136968318Scgd register struct lstat_args /* { 137068318Scgd syscallarg(char *) path; 137168318Scgd syscallarg(struct stat *) ub; 137268318Scgd } */ *uap; 137368318Scgd register_t *retval; 137442441Smckusick { 137537741Smckusick int error; 137659373Smckusick struct vnode *vp, *dvp; 137759373Smckusick struct stat sb, sb1; 137847540Skarels struct nameidata nd; 13795992Swnj 138059373Smckusick NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | LOCKPARENT, UIO_USERSPACE, 138168318Scgd SCARG(uap, path), p); 138252322Smckusick if (error = namei(&nd)) 138347540Skarels return (error); 138459373Smckusick /* 138568579Smckusick * For symbolic links, always return the attributes of its containing 138668579Smckusick * directory, except for mode, size, inode number, and links. 138759373Smckusick */ 138859373Smckusick vp = nd.ni_vp; 138959373Smckusick dvp = nd.ni_dvp; 139059373Smckusick if (vp->v_type != VLNK) { 139159373Smckusick if (dvp == vp) 139259373Smckusick vrele(dvp); 139359373Smckusick else 139459373Smckusick vput(dvp); 139559373Smckusick error = vn_stat(vp, &sb, p); 139659373Smckusick vput(vp); 139759373Smckusick if (error) 139859373Smckusick return (error); 139959373Smckusick } else { 140059373Smckusick error = vn_stat(dvp, &sb, p); 140159373Smckusick vput(dvp); 140259373Smckusick if (error) { 140359373Smckusick vput(vp); 140459373Smckusick return (error); 140559373Smckusick } 140659373Smckusick error = vn_stat(vp, &sb1, p); 140759373Smckusick vput(vp); 140859373Smckusick if (error) 140959373Smckusick return (error); 141059373Smckusick sb.st_mode &= ~S_IFDIR; 141159373Smckusick sb.st_mode |= S_IFLNK; 141259373Smckusick sb.st_nlink = sb1.st_nlink; 141359373Smckusick sb.st_size = sb1.st_size; 141459373Smckusick sb.st_blocks = sb1.st_blocks; 141568579Smckusick sb.st_ino = sb1.st_ino; 141659373Smckusick } 141768318Scgd error = copyout((caddr_t)&sb, (caddr_t)SCARG(uap, ub), sizeof (sb)); 141847540Skarels return (error); 14195992Swnj } 14205992Swnj 14215992Swnj /* 142264410Sbostic * Get configurable pathname variables. 142360414Smckusick */ 142460414Smckusick /* ARGSUSED */ 142568318Scgd int 142660414Smckusick pathconf(p, uap, retval) 142760414Smckusick struct proc *p; 142868318Scgd register struct pathconf_args /* { 142968318Scgd syscallarg(char *) path; 143068318Scgd syscallarg(int) name; 143168318Scgd } */ *uap; 143268318Scgd register_t *retval; 143360414Smckusick { 143460414Smckusick int error; 143560414Smckusick struct nameidata nd; 143660414Smckusick 143768318Scgd NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, 143868318Scgd SCARG(uap, path), p); 143960414Smckusick if (error = namei(&nd)) 144060414Smckusick return (error); 144168318Scgd error = VOP_PATHCONF(nd.ni_vp, SCARG(uap, name), retval); 144260414Smckusick vput(nd.ni_vp); 144360414Smckusick return (error); 144460414Smckusick } 144560414Smckusick 144660414Smckusick /* 144749365Smckusick * Return target name of a symbolic link. 144837Sbill */ 144942441Smckusick /* ARGSUSED */ 145068318Scgd int 145142441Smckusick readlink(p, uap, retval) 145245914Smckusick struct proc *p; 145368318Scgd register struct readlink_args /* { 145468318Scgd syscallarg(char *) path; 145568318Scgd syscallarg(char *) buf; 145668318Scgd syscallarg(int) count; 145768318Scgd } */ *uap; 145868318Scgd register_t *retval; 145942441Smckusick { 146037741Smckusick register struct vnode *vp; 146137741Smckusick struct iovec aiov; 146237741Smckusick struct uio auio; 146337741Smckusick int error; 146447540Skarels struct nameidata nd; 14655992Swnj 146668318Scgd NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, 146768318Scgd SCARG(uap, path), p); 146852322Smckusick if (error = namei(&nd)) 146947540Skarels return (error); 147052322Smckusick vp = nd.ni_vp; 147164410Sbostic if (vp->v_type != VLNK) 147237741Smckusick error = EINVAL; 147364410Sbostic else { 147468318Scgd aiov.iov_base = SCARG(uap, buf); 147568318Scgd aiov.iov_len = SCARG(uap, count); 147664410Sbostic auio.uio_iov = &aiov; 147764410Sbostic auio.uio_iovcnt = 1; 147864410Sbostic auio.uio_offset = 0; 147964410Sbostic auio.uio_rw = UIO_READ; 148064410Sbostic auio.uio_segflg = UIO_USERSPACE; 148164410Sbostic auio.uio_procp = p; 148268318Scgd auio.uio_resid = SCARG(uap, count); 148364410Sbostic error = VOP_READLINK(vp, &auio, p->p_ucred); 14845992Swnj } 148537741Smckusick vput(vp); 148668318Scgd *retval = SCARG(uap, count) - auio.uio_resid; 148747540Skarels return (error); 14885992Swnj } 14895992Swnj 14909167Ssam /* 149164410Sbostic * Change flags of a file given a path name. 149238259Smckusick */ 149342441Smckusick /* ARGSUSED */ 149468318Scgd int 149542441Smckusick chflags(p, uap, retval) 149645914Smckusick struct proc *p; 149768318Scgd register struct chflags_args /* { 149868318Scgd syscallarg(char *) path; 149968318Scgd syscallarg(int) flags; 150068318Scgd } */ *uap; 150168318Scgd register_t *retval; 150242441Smckusick { 150338259Smckusick register struct vnode *vp; 150438259Smckusick struct vattr vattr; 150538259Smckusick int error; 150647540Skarels struct nameidata nd; 150738259Smckusick 150868318Scgd NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 150952322Smckusick if (error = namei(&nd)) 151047540Skarels return (error); 151152322Smckusick vp = nd.ni_vp; 151267654Smckusick VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 1513*69409Smckusick vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 151464410Sbostic if (vp->v_mount->mnt_flag & MNT_RDONLY) 151538259Smckusick error = EROFS; 151664410Sbostic else { 151764410Sbostic VATTR_NULL(&vattr); 151868318Scgd vattr.va_flags = SCARG(uap, flags); 151964410Sbostic error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 152038259Smckusick } 152138259Smckusick vput(vp); 152247540Skarels return (error); 152338259Smckusick } 152438259Smckusick 152538259Smckusick /* 152638259Smckusick * Change flags of a file given a file descriptor. 152738259Smckusick */ 152842441Smckusick /* ARGSUSED */ 152968318Scgd int 153042441Smckusick fchflags(p, uap, retval) 153145914Smckusick struct proc *p; 153268318Scgd register struct fchflags_args /* { 153368318Scgd syscallarg(int) fd; 153468318Scgd syscallarg(int) flags; 153568318Scgd } */ *uap; 153668318Scgd register_t *retval; 153742441Smckusick { 153838259Smckusick struct vattr vattr; 153938259Smckusick struct vnode *vp; 154038259Smckusick struct file *fp; 154138259Smckusick int error; 154238259Smckusick 154368318Scgd if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) 154447540Skarels return (error); 154538259Smckusick vp = (struct vnode *)fp->f_data; 154667654Smckusick VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 1547*69409Smckusick vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 154864410Sbostic if (vp->v_mount->mnt_flag & MNT_RDONLY) 154938259Smckusick error = EROFS; 155064410Sbostic else { 155164410Sbostic VATTR_NULL(&vattr); 155268318Scgd vattr.va_flags = SCARG(uap, flags); 155364410Sbostic error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 155438259Smckusick } 1555*69409Smckusick VOP_UNLOCK(vp, 0, p); 155647540Skarels return (error); 155738259Smckusick } 155838259Smckusick 155938259Smckusick /* 15609167Ssam * Change mode of a file given path name. 15619167Ssam */ 156242441Smckusick /* ARGSUSED */ 156368318Scgd int 156442441Smckusick chmod(p, uap, retval) 156545914Smckusick struct proc *p; 156668318Scgd register struct chmod_args /* { 156768318Scgd syscallarg(char *) path; 156868318Scgd syscallarg(int) mode; 156968318Scgd } */ *uap; 157068318Scgd register_t *retval; 157142441Smckusick { 157237741Smckusick register struct vnode *vp; 157337741Smckusick struct vattr vattr; 157437741Smckusick int error; 157547540Skarels struct nameidata nd; 15765992Swnj 157768318Scgd NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 157852322Smckusick if (error = namei(&nd)) 157947540Skarels return (error); 158052322Smckusick vp = nd.ni_vp; 158167654Smckusick VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 1582*69409Smckusick vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 158364410Sbostic if (vp->v_mount->mnt_flag & MNT_RDONLY) 158437741Smckusick error = EROFS; 158564410Sbostic else { 158664410Sbostic VATTR_NULL(&vattr); 158768318Scgd vattr.va_mode = SCARG(uap, mode) & ALLPERMS; 158864410Sbostic error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 158937741Smckusick } 159037741Smckusick vput(vp); 159147540Skarels return (error); 15927701Ssam } 15937439Sroot 15949167Ssam /* 15959167Ssam * Change mode of a file given a file descriptor. 15969167Ssam */ 159742441Smckusick /* ARGSUSED */ 159868318Scgd int 159942441Smckusick fchmod(p, uap, retval) 160045914Smckusick struct proc *p; 160168318Scgd register struct fchmod_args /* { 160268318Scgd syscallarg(int) fd; 160368318Scgd syscallarg(int) mode; 160468318Scgd } */ *uap; 160568318Scgd register_t *retval; 160642441Smckusick { 160737741Smckusick struct vattr vattr; 160837741Smckusick struct vnode *vp; 160937741Smckusick struct file *fp; 161037741Smckusick int error; 16117701Ssam 161268318Scgd if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) 161347540Skarels return (error); 161437741Smckusick vp = (struct vnode *)fp->f_data; 161567654Smckusick VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 1616*69409Smckusick vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 161764410Sbostic if (vp->v_mount->mnt_flag & MNT_RDONLY) 161837741Smckusick error = EROFS; 161964410Sbostic else { 162064410Sbostic VATTR_NULL(&vattr); 162168318Scgd vattr.va_mode = SCARG(uap, mode) & ALLPERMS; 162264410Sbostic error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 16237439Sroot } 1624*69409Smckusick VOP_UNLOCK(vp, 0, p); 162547540Skarels return (error); 16265992Swnj } 16275992Swnj 16289167Ssam /* 16299167Ssam * Set ownership given a path name. 16309167Ssam */ 163142441Smckusick /* ARGSUSED */ 163268318Scgd int 163342441Smckusick chown(p, uap, retval) 163445914Smckusick struct proc *p; 163568318Scgd register struct chown_args /* { 163668318Scgd syscallarg(char *) path; 163768318Scgd syscallarg(int) uid; 163868318Scgd syscallarg(int) gid; 163968318Scgd } */ *uap; 164068318Scgd register_t *retval; 164142441Smckusick { 164237741Smckusick register struct vnode *vp; 164337741Smckusick struct vattr vattr; 164437741Smckusick int error; 164547540Skarels struct nameidata nd; 164637Sbill 164768318Scgd NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 164852322Smckusick if (error = namei(&nd)) 164947540Skarels return (error); 165052322Smckusick vp = nd.ni_vp; 165167654Smckusick VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 1652*69409Smckusick vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 165364410Sbostic if (vp->v_mount->mnt_flag & MNT_RDONLY) 165437741Smckusick error = EROFS; 165564410Sbostic else { 165664410Sbostic VATTR_NULL(&vattr); 165768318Scgd vattr.va_uid = SCARG(uap, uid); 165868318Scgd vattr.va_gid = SCARG(uap, gid); 165964410Sbostic error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 166037741Smckusick } 166137741Smckusick vput(vp); 166247540Skarels return (error); 16637701Ssam } 16647439Sroot 16659167Ssam /* 16669167Ssam * Set ownership given a file descriptor. 16679167Ssam */ 166842441Smckusick /* ARGSUSED */ 166968318Scgd int 167042441Smckusick fchown(p, uap, retval) 167145914Smckusick struct proc *p; 167268318Scgd register struct fchown_args /* { 167368318Scgd syscallarg(int) fd; 167468318Scgd syscallarg(int) uid; 167568318Scgd syscallarg(int) gid; 167668318Scgd } */ *uap; 167768318Scgd register_t *retval; 167842441Smckusick { 167937741Smckusick struct vattr vattr; 168037741Smckusick struct vnode *vp; 168137741Smckusick struct file *fp; 168237741Smckusick int error; 16837701Ssam 168468318Scgd if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) 168547540Skarels return (error); 168637741Smckusick vp = (struct vnode *)fp->f_data; 168767654Smckusick VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 1688*69409Smckusick vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 168964410Sbostic if (vp->v_mount->mnt_flag & MNT_RDONLY) 169037741Smckusick error = EROFS; 169164410Sbostic else { 169264410Sbostic VATTR_NULL(&vattr); 169368318Scgd vattr.va_uid = SCARG(uap, uid); 169468318Scgd vattr.va_gid = SCARG(uap, gid); 169564410Sbostic error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 169637741Smckusick } 1697*69409Smckusick VOP_UNLOCK(vp, 0, p); 169847540Skarels return (error); 16997701Ssam } 17007701Ssam 170142441Smckusick /* 170242441Smckusick * Set the access and modification times of a file. 170342441Smckusick */ 170442441Smckusick /* ARGSUSED */ 170568318Scgd int 170642441Smckusick utimes(p, uap, retval) 170745914Smckusick struct proc *p; 170868318Scgd register struct utimes_args /* { 170968318Scgd syscallarg(char *) path; 171068318Scgd syscallarg(struct timeval *) tptr; 171168318Scgd } */ *uap; 171268318Scgd register_t *retval; 171342441Smckusick { 171437741Smckusick register struct vnode *vp; 171511811Ssam struct timeval tv[2]; 171637741Smckusick struct vattr vattr; 171758840Storek int error; 171847540Skarels struct nameidata nd; 171911811Ssam 172058505Sbostic VATTR_NULL(&vattr); 172168318Scgd if (SCARG(uap, tptr) == NULL) { 172258505Sbostic microtime(&tv[0]); 172358505Sbostic tv[1] = tv[0]; 172458548Sbostic vattr.va_vaflags |= VA_UTIMES_NULL; 172568318Scgd } else if (error = copyin((caddr_t)SCARG(uap, tptr), (caddr_t)tv, 172668318Scgd sizeof (tv))) 172758505Sbostic return (error); 172868318Scgd NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 172952322Smckusick if (error = namei(&nd)) 173047540Skarels return (error); 173152322Smckusick vp = nd.ni_vp; 173267654Smckusick VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 1733*69409Smckusick vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 173464410Sbostic if (vp->v_mount->mnt_flag & MNT_RDONLY) 173537741Smckusick error = EROFS; 173664410Sbostic else { 173764410Sbostic vattr.va_atime.ts_sec = tv[0].tv_sec; 173864410Sbostic vattr.va_atime.ts_nsec = tv[0].tv_usec * 1000; 173964410Sbostic vattr.va_mtime.ts_sec = tv[1].tv_sec; 174064410Sbostic vattr.va_mtime.ts_nsec = tv[1].tv_usec * 1000; 174164410Sbostic error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 174221015Smckusick } 174337741Smckusick vput(vp); 174447540Skarels return (error); 174511811Ssam } 174611811Ssam 174764410Sbostic /* 174864410Sbostic * Truncate a file given its path name. 174964410Sbostic */ 175053468Smckusick /* ARGSUSED */ 175168318Scgd int 175260414Smckusick truncate(p, uap, retval) 175353468Smckusick struct proc *p; 175468318Scgd register struct truncate_args /* { 175568318Scgd syscallarg(char *) path; 175668318Scgd syscallarg(int) pad; 175768318Scgd syscallarg(off_t) length; 175868318Scgd } */ *uap; 175968318Scgd register_t *retval; 176053468Smckusick { 176137741Smckusick register struct vnode *vp; 176237741Smckusick struct vattr vattr; 176337741Smckusick int error; 176447540Skarels struct nameidata nd; 17657701Ssam 176668318Scgd NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 176752322Smckusick if (error = namei(&nd)) 176847540Skarels return (error); 176952322Smckusick vp = nd.ni_vp; 177067654Smckusick VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 1771*69409Smckusick vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 177264410Sbostic if (vp->v_type == VDIR) 177337741Smckusick error = EISDIR; 177464410Sbostic else if ((error = vn_writechk(vp)) == 0 && 177564410Sbostic (error = VOP_ACCESS(vp, VWRITE, p->p_ucred, p)) == 0) { 177664410Sbostic VATTR_NULL(&vattr); 177768318Scgd vattr.va_size = SCARG(uap, length); 177864410Sbostic error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 17797701Ssam } 178037741Smckusick vput(vp); 178147540Skarels return (error); 17827701Ssam } 17837701Ssam 178464410Sbostic /* 178564410Sbostic * Truncate a file given a file descriptor. 178664410Sbostic */ 178742441Smckusick /* ARGSUSED */ 178868318Scgd int 178960414Smckusick ftruncate(p, uap, retval) 179045914Smckusick struct proc *p; 179168318Scgd register struct ftruncate_args /* { 179268318Scgd syscallarg(int) fd; 179368318Scgd syscallarg(int) pad; 179468318Scgd syscallarg(off_t) length; 179568318Scgd } */ *uap; 179668318Scgd register_t *retval; 179742441Smckusick { 179837741Smckusick struct vattr vattr; 179937741Smckusick struct vnode *vp; 18007701Ssam struct file *fp; 180137741Smckusick int error; 18027701Ssam 180368318Scgd if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) 180447540Skarels return (error); 180537741Smckusick if ((fp->f_flag & FWRITE) == 0) 180647540Skarels return (EINVAL); 180737741Smckusick vp = (struct vnode *)fp->f_data; 180867654Smckusick VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 1809*69409Smckusick vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 181064410Sbostic if (vp->v_type == VDIR) 181137741Smckusick error = EISDIR; 181264410Sbostic else if ((error = vn_writechk(vp)) == 0) { 181364410Sbostic VATTR_NULL(&vattr); 181468318Scgd vattr.va_size = SCARG(uap, length); 181564410Sbostic error = VOP_SETATTR(vp, &vattr, fp->f_cred, p); 18167701Ssam } 1817*69409Smckusick VOP_UNLOCK(vp, 0, p); 181847540Skarels return (error); 18197701Ssam } 18207701Ssam 182154863Storek #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 18229167Ssam /* 182354863Storek * Truncate a file given its path name. 182454863Storek */ 182554863Storek /* ARGSUSED */ 182668318Scgd int 182768318Scgd compat_43_truncate(p, uap, retval) 182854863Storek struct proc *p; 182968318Scgd register struct compat_43_truncate_args /* { 183068318Scgd syscallarg(char *) path; 183168318Scgd syscallarg(long) length; 183268318Scgd } */ *uap; 183368318Scgd register_t *retval; 183454863Storek { 183568318Scgd struct truncate_args /* { 183668318Scgd syscallarg(char *) path; 183768318Scgd syscallarg(int) pad; 183868318Scgd syscallarg(off_t) length; 183968318Scgd } */ nuap; 184054863Storek 184168318Scgd SCARG(&nuap, path) = SCARG(uap, path); 184268318Scgd SCARG(&nuap, length) = SCARG(uap, length); 184360428Smckusick return (truncate(p, &nuap, retval)); 184454863Storek } 184554863Storek 184654863Storek /* 184754863Storek * Truncate a file given a file descriptor. 184854863Storek */ 184954863Storek /* ARGSUSED */ 185068318Scgd int 185168318Scgd compat_43_ftruncate(p, uap, retval) 185254863Storek struct proc *p; 185368318Scgd register struct compat_43_ftruncate_args /* { 185468318Scgd syscallarg(int) fd; 185568318Scgd syscallarg(long) length; 185668318Scgd } */ *uap; 185768318Scgd register_t *retval; 185854863Storek { 185968318Scgd struct ftruncate_args /* { 186068318Scgd syscallarg(int) fd; 186168318Scgd syscallarg(int) pad; 186268318Scgd syscallarg(off_t) length; 186368318Scgd } */ nuap; 186454863Storek 186568318Scgd SCARG(&nuap, fd) = SCARG(uap, fd); 186668318Scgd SCARG(&nuap, length) = SCARG(uap, length); 186760428Smckusick return (ftruncate(p, &nuap, retval)); 186854863Storek } 186954863Storek #endif /* COMPAT_43 || COMPAT_SUNOS */ 187054863Storek 187154863Storek /* 187264410Sbostic * Sync an open file. 18739167Ssam */ 187442441Smckusick /* ARGSUSED */ 187568318Scgd int 187642441Smckusick fsync(p, uap, retval) 187745914Smckusick struct proc *p; 187868318Scgd struct fsync_args /* { 187968318Scgd syscallarg(int) fd; 188068318Scgd } */ *uap; 188168318Scgd register_t *retval; 18829167Ssam { 188339592Smckusick register struct vnode *vp; 18849167Ssam struct file *fp; 188537741Smckusick int error; 18869167Ssam 188768318Scgd if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) 188847540Skarels return (error); 188939592Smckusick vp = (struct vnode *)fp->f_data; 1890*69409Smckusick vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 189154441Smckusick error = VOP_FSYNC(vp, fp->f_cred, MNT_WAIT, p); 1892*69409Smckusick VOP_UNLOCK(vp, 0, p); 189347540Skarels return (error); 18949167Ssam } 18959167Ssam 18969167Ssam /* 189764410Sbostic * Rename files. Source and destination must either both be directories, 189864410Sbostic * or both not be directories. If target is a directory, it must be empty. 18999167Ssam */ 190042441Smckusick /* ARGSUSED */ 190168318Scgd int 190242441Smckusick rename(p, uap, retval) 190345914Smckusick struct proc *p; 190468318Scgd register struct rename_args /* { 190568318Scgd syscallarg(char *) from; 190668318Scgd syscallarg(char *) to; 190768318Scgd } */ *uap; 190868318Scgd register_t *retval; 190942441Smckusick { 191037741Smckusick register struct vnode *tvp, *fvp, *tdvp; 191149735Smckusick struct nameidata fromnd, tond; 191237741Smckusick int error; 19137701Ssam 191452322Smckusick NDINIT(&fromnd, DELETE, WANTPARENT | SAVESTART, UIO_USERSPACE, 191568318Scgd SCARG(uap, from), p); 191652322Smckusick if (error = namei(&fromnd)) 191747540Skarels return (error); 191849735Smckusick fvp = fromnd.ni_vp; 191952322Smckusick NDINIT(&tond, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART, 192068318Scgd UIO_USERSPACE, SCARG(uap, to), p); 192152322Smckusick if (error = namei(&tond)) { 192252230Sheideman VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 192349735Smckusick vrele(fromnd.ni_dvp); 192442465Smckusick vrele(fvp); 192542465Smckusick goto out1; 192642465Smckusick } 192737741Smckusick tdvp = tond.ni_dvp; 192837741Smckusick tvp = tond.ni_vp; 192937741Smckusick if (tvp != NULL) { 193037741Smckusick if (fvp->v_type == VDIR && tvp->v_type != VDIR) { 193139242Sbostic error = ENOTDIR; 193237741Smckusick goto out; 193337741Smckusick } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) { 193439242Sbostic error = EISDIR; 193537741Smckusick goto out; 19369167Ssam } 19379167Ssam } 193839286Smckusick if (fvp == tdvp) 193937741Smckusick error = EINVAL; 194039286Smckusick /* 194149735Smckusick * If source is the same as the destination (that is the 194249735Smckusick * same inode number with the same name in the same directory), 194339286Smckusick * then there is nothing to do. 194439286Smckusick */ 194549735Smckusick if (fvp == tvp && fromnd.ni_dvp == tdvp && 194652322Smckusick fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen && 194752322Smckusick !bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr, 194852322Smckusick fromnd.ni_cnd.cn_namelen)) 194939286Smckusick error = -1; 195037741Smckusick out: 195142465Smckusick if (!error) { 195267654Smckusick VOP_LEASE(tdvp, p, p->p_ucred, LEASE_WRITE); 195352192Smckusick if (fromnd.ni_dvp != tdvp) 195467654Smckusick VOP_LEASE(fromnd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 195552192Smckusick if (tvp) 195667654Smckusick VOP_LEASE(tvp, p, p->p_ucred, LEASE_WRITE); 195752230Sheideman error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd, 195852230Sheideman tond.ni_dvp, tond.ni_vp, &tond.ni_cnd); 195942465Smckusick } else { 196052230Sheideman VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd); 196143344Smckusick if (tdvp == tvp) 196243344Smckusick vrele(tdvp); 196343344Smckusick else 196443344Smckusick vput(tdvp); 196542465Smckusick if (tvp) 196642465Smckusick vput(tvp); 196752230Sheideman VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 196849735Smckusick vrele(fromnd.ni_dvp); 196942465Smckusick vrele(fvp); 19709167Ssam } 197149735Smckusick vrele(tond.ni_startdir); 197252322Smckusick FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI); 197337741Smckusick out1: 197466801Smckusick if (fromnd.ni_startdir) 197566801Smckusick vrele(fromnd.ni_startdir); 197652322Smckusick FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI); 197739286Smckusick if (error == -1) 197847540Skarels return (0); 197947540Skarels return (error); 19807701Ssam } 19817701Ssam 19827535Sroot /* 198364410Sbostic * Make a directory file. 198412756Ssam */ 198542441Smckusick /* ARGSUSED */ 198668318Scgd int 198742441Smckusick mkdir(p, uap, retval) 198845914Smckusick struct proc *p; 198968318Scgd register struct mkdir_args /* { 199068318Scgd syscallarg(char *) path; 199168318Scgd syscallarg(int) mode; 199268318Scgd } */ *uap; 199368318Scgd register_t *retval; 199442441Smckusick { 199537741Smckusick register struct vnode *vp; 199637741Smckusick struct vattr vattr; 199737741Smckusick int error; 199847540Skarels struct nameidata nd; 199912756Ssam 200068318Scgd NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p); 200152322Smckusick if (error = namei(&nd)) 200247540Skarels return (error); 200352322Smckusick vp = nd.ni_vp; 200437741Smckusick if (vp != NULL) { 200552322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 200652322Smckusick if (nd.ni_dvp == vp) 200752322Smckusick vrele(nd.ni_dvp); 200843344Smckusick else 200952322Smckusick vput(nd.ni_dvp); 201042465Smckusick vrele(vp); 201147540Skarels return (EEXIST); 201212756Ssam } 201341362Smckusick VATTR_NULL(&vattr); 201437741Smckusick vattr.va_type = VDIR; 201568318Scgd vattr.va_mode = (SCARG(uap, mode) & ACCESSPERMS) &~ p->p_fd->fd_cmask; 201667654Smckusick VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 201752322Smckusick error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr); 201838145Smckusick if (!error) 201952322Smckusick vput(nd.ni_vp); 202047540Skarels return (error); 202112756Ssam } 202212756Ssam 202312756Ssam /* 202464410Sbostic * Remove a directory file. 202512756Ssam */ 202642441Smckusick /* ARGSUSED */ 202768318Scgd int 202842441Smckusick rmdir(p, uap, retval) 202945914Smckusick struct proc *p; 203068318Scgd struct rmdir_args /* { 203168318Scgd syscallarg(char *) path; 203268318Scgd } */ *uap; 203368318Scgd register_t *retval; 203412756Ssam { 203537741Smckusick register struct vnode *vp; 203637741Smckusick int error; 203747540Skarels struct nameidata nd; 203812756Ssam 203968318Scgd NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE, 204068318Scgd SCARG(uap, path), p); 204152322Smckusick if (error = namei(&nd)) 204247540Skarels return (error); 204352322Smckusick vp = nd.ni_vp; 204437741Smckusick if (vp->v_type != VDIR) { 204537741Smckusick error = ENOTDIR; 204612756Ssam goto out; 204712756Ssam } 204812756Ssam /* 204937741Smckusick * No rmdir "." please. 205012756Ssam */ 205152322Smckusick if (nd.ni_dvp == vp) { 205237741Smckusick error = EINVAL; 205312756Ssam goto out; 205412756Ssam } 205512756Ssam /* 205649365Smckusick * The root of a mounted filesystem cannot be deleted. 205712756Ssam */ 205837741Smckusick if (vp->v_flag & VROOT) 205937741Smckusick error = EBUSY; 206012756Ssam out: 206142465Smckusick if (!error) { 206267654Smckusick VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 206367654Smckusick VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 206452322Smckusick error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); 206542465Smckusick } else { 206652322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 206752322Smckusick if (nd.ni_dvp == vp) 206852322Smckusick vrele(nd.ni_dvp); 206943344Smckusick else 207052322Smckusick vput(nd.ni_dvp); 207142465Smckusick vput(vp); 207242465Smckusick } 207347540Skarels return (error); 207412756Ssam } 207512756Ssam 207654620Smckusick #ifdef COMPAT_43 207737741Smckusick /* 207849365Smckusick * Read a block of directory entries in a file system independent format. 207937741Smckusick */ 208068318Scgd int 208168318Scgd compat_43_getdirentries(p, uap, retval) 208254620Smckusick struct proc *p; 208368318Scgd register struct compat_43_getdirentries_args /* { 208468318Scgd syscallarg(int) fd; 208568318Scgd syscallarg(char *) buf; 208668318Scgd syscallarg(u_int) count; 208768318Scgd syscallarg(long *) basep; 208868318Scgd } */ *uap; 208968318Scgd register_t *retval; 209054620Smckusick { 209154620Smckusick register struct vnode *vp; 209254620Smckusick struct file *fp; 209354620Smckusick struct uio auio, kuio; 209454620Smckusick struct iovec aiov, kiov; 209554620Smckusick struct dirent *dp, *edp; 209654620Smckusick caddr_t dirbuf; 209767362Smckusick int error, eofflag, readcnt; 209854969Smckusick long loff; 209954620Smckusick 210068318Scgd if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) 210154620Smckusick return (error); 210254620Smckusick if ((fp->f_flag & FREAD) == 0) 210354620Smckusick return (EBADF); 210454620Smckusick vp = (struct vnode *)fp->f_data; 210567362Smckusick unionread: 210654620Smckusick if (vp->v_type != VDIR) 210754620Smckusick return (EINVAL); 210868318Scgd aiov.iov_base = SCARG(uap, buf); 210968318Scgd aiov.iov_len = SCARG(uap, count); 211054620Smckusick auio.uio_iov = &aiov; 211154620Smckusick auio.uio_iovcnt = 1; 211254620Smckusick auio.uio_rw = UIO_READ; 211354620Smckusick auio.uio_segflg = UIO_USERSPACE; 211454620Smckusick auio.uio_procp = p; 211568318Scgd auio.uio_resid = SCARG(uap, count); 2116*69409Smckusick vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 211754969Smckusick loff = auio.uio_offset = fp->f_offset; 211854620Smckusick # if (BYTE_ORDER != LITTLE_ENDIAN) 211956339Smckusick if (vp->v_mount->mnt_maxsymlinklen <= 0) { 212067362Smckusick error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, 212168663Smckusick (int *)0, (u_long *)0); 212256339Smckusick fp->f_offset = auio.uio_offset; 212356339Smckusick } else 212454620Smckusick # endif 212554620Smckusick { 212654620Smckusick kuio = auio; 212754620Smckusick kuio.uio_iov = &kiov; 212854620Smckusick kuio.uio_segflg = UIO_SYSSPACE; 212968318Scgd kiov.iov_len = SCARG(uap, count); 213068318Scgd MALLOC(dirbuf, caddr_t, SCARG(uap, count), M_TEMP, M_WAITOK); 213154620Smckusick kiov.iov_base = dirbuf; 213267362Smckusick error = VOP_READDIR(vp, &kuio, fp->f_cred, &eofflag, 213368663Smckusick (int *)0, (u_long *)0); 213456339Smckusick fp->f_offset = kuio.uio_offset; 213554620Smckusick if (error == 0) { 213668318Scgd readcnt = SCARG(uap, count) - kuio.uio_resid; 213754620Smckusick edp = (struct dirent *)&dirbuf[readcnt]; 213854620Smckusick for (dp = (struct dirent *)dirbuf; dp < edp; ) { 213954620Smckusick # if (BYTE_ORDER == LITTLE_ENDIAN) 214054969Smckusick /* 214155009Smckusick * The expected low byte of 214255009Smckusick * dp->d_namlen is our dp->d_type. 214355009Smckusick * The high MBZ byte of dp->d_namlen 214455009Smckusick * is our dp->d_namlen. 214554969Smckusick */ 214655009Smckusick dp->d_type = dp->d_namlen; 214755009Smckusick dp->d_namlen = 0; 214855009Smckusick # else 214955009Smckusick /* 215055009Smckusick * The dp->d_type is the high byte 215155009Smckusick * of the expected dp->d_namlen, 215255009Smckusick * so must be zero'ed. 215355009Smckusick */ 215455009Smckusick dp->d_type = 0; 215554620Smckusick # endif 215654620Smckusick if (dp->d_reclen > 0) { 215754620Smckusick dp = (struct dirent *) 215854620Smckusick ((char *)dp + dp->d_reclen); 215954620Smckusick } else { 216054620Smckusick error = EIO; 216154620Smckusick break; 216254620Smckusick } 216354620Smckusick } 216454620Smckusick if (dp >= edp) 216554620Smckusick error = uiomove(dirbuf, readcnt, &auio); 216654620Smckusick } 216754620Smckusick FREE(dirbuf, M_TEMP); 216854620Smckusick } 2169*69409Smckusick VOP_UNLOCK(vp, 0, p); 217054620Smckusick if (error) 217154620Smckusick return (error); 217267362Smckusick 217367362Smckusick #ifdef UNION 217467362Smckusick { 217567362Smckusick extern int (**union_vnodeop_p)(); 217668079Spendry extern struct vnode *union_dircache __P((struct vnode *)); 217767362Smckusick 217868318Scgd if ((SCARG(uap, count) == auio.uio_resid) && 217967362Smckusick (vp->v_op == union_vnodeop_p)) { 218067362Smckusick struct vnode *lvp; 218167362Smckusick 218268079Spendry lvp = union_dircache(vp); 218367362Smckusick if (lvp != NULLVP) { 218467575Spendry struct vattr va; 218567575Spendry 218667575Spendry /* 218767575Spendry * If the directory is opaque, 218867575Spendry * then don't show lower entries 218967575Spendry */ 219067575Spendry error = VOP_GETATTR(vp, &va, fp->f_cred, p); 219167575Spendry if (va.va_flags & OPAQUE) { 219268079Spendry vput(lvp); 219367575Spendry lvp = NULL; 219467575Spendry } 219567575Spendry } 219667575Spendry 219767575Spendry if (lvp != NULLVP) { 219867362Smckusick error = VOP_OPEN(lvp, FREAD, fp->f_cred, p); 2199*69409Smckusick VOP_UNLOCK(lvp, 0, p); 220067362Smckusick 220167362Smckusick if (error) { 220267362Smckusick vrele(lvp); 220367362Smckusick return (error); 220467362Smckusick } 220567362Smckusick fp->f_data = (caddr_t) lvp; 220667362Smckusick fp->f_offset = 0; 220767362Smckusick error = vn_close(vp, FREAD, fp->f_cred, p); 220867362Smckusick if (error) 220967362Smckusick return (error); 221067362Smckusick vp = lvp; 221167362Smckusick goto unionread; 221267362Smckusick } 221367362Smckusick } 221467362Smckusick } 221567362Smckusick #endif /* UNION */ 221667362Smckusick 221768318Scgd if ((SCARG(uap, count) == auio.uio_resid) && 221867362Smckusick (vp->v_flag & VROOT) && 221967362Smckusick (vp->v_mount->mnt_flag & MNT_UNION)) { 222067362Smckusick struct vnode *tvp = vp; 222167362Smckusick vp = vp->v_mount->mnt_vnodecovered; 222267362Smckusick VREF(vp); 222367362Smckusick fp->f_data = (caddr_t) vp; 222467362Smckusick fp->f_offset = 0; 222567362Smckusick vrele(tvp); 222667362Smckusick goto unionread; 222767362Smckusick } 222868318Scgd error = copyout((caddr_t)&loff, (caddr_t)SCARG(uap, basep), 222968318Scgd sizeof(long)); 223068318Scgd *retval = SCARG(uap, count) - auio.uio_resid; 223154620Smckusick return (error); 223254620Smckusick } 223367362Smckusick #endif /* COMPAT_43 */ 223454620Smckusick 223554620Smckusick /* 223654620Smckusick * Read a block of directory entries in a file system independent format. 223754620Smckusick */ 223868318Scgd int 223942441Smckusick getdirentries(p, uap, retval) 224045914Smckusick struct proc *p; 224168318Scgd register struct getdirentries_args /* { 224268318Scgd syscallarg(int) fd; 224368318Scgd syscallarg(char *) buf; 224468318Scgd syscallarg(u_int) count; 224568318Scgd syscallarg(long *) basep; 224668318Scgd } */ *uap; 224768318Scgd register_t *retval; 224842441Smckusick { 224939592Smckusick register struct vnode *vp; 225016540Ssam struct file *fp; 225137741Smckusick struct uio auio; 225237741Smckusick struct iovec aiov; 225354969Smckusick long loff; 225467362Smckusick int error, eofflag; 225512756Ssam 225668318Scgd if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) 225747540Skarels return (error); 225837741Smckusick if ((fp->f_flag & FREAD) == 0) 225947540Skarels return (EBADF); 226039592Smckusick vp = (struct vnode *)fp->f_data; 226155451Spendry unionread: 226239592Smckusick if (vp->v_type != VDIR) 226347540Skarels return (EINVAL); 226468318Scgd aiov.iov_base = SCARG(uap, buf); 226568318Scgd aiov.iov_len = SCARG(uap, count); 226637741Smckusick auio.uio_iov = &aiov; 226737741Smckusick auio.uio_iovcnt = 1; 226837741Smckusick auio.uio_rw = UIO_READ; 226937741Smckusick auio.uio_segflg = UIO_USERSPACE; 227048026Smckusick auio.uio_procp = p; 227168318Scgd auio.uio_resid = SCARG(uap, count); 2272*69409Smckusick vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 227354969Smckusick loff = auio.uio_offset = fp->f_offset; 227468663Smckusick error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, 227568663Smckusick (int *)0, (u_long *)0); 227639592Smckusick fp->f_offset = auio.uio_offset; 2277*69409Smckusick VOP_UNLOCK(vp, 0, p); 227839592Smckusick if (error) 227947540Skarels return (error); 228066095Spendry 228166095Spendry #ifdef UNION 228266095Spendry { 228366095Spendry extern int (**union_vnodeop_p)(); 228468079Spendry extern struct vnode *union_dircache __P((struct vnode *)); 228566095Spendry 228668318Scgd if ((SCARG(uap, count) == auio.uio_resid) && 228766095Spendry (vp->v_op == union_vnodeop_p)) { 228867122Spendry struct vnode *lvp; 228966095Spendry 229068079Spendry lvp = union_dircache(vp); 229167122Spendry if (lvp != NULLVP) { 229267575Spendry struct vattr va; 229367575Spendry 229467575Spendry /* 229567575Spendry * If the directory is opaque, 229667575Spendry * then don't show lower entries 229767575Spendry */ 229867575Spendry error = VOP_GETATTR(vp, &va, fp->f_cred, p); 229967575Spendry if (va.va_flags & OPAQUE) { 230068079Spendry vput(lvp); 230167575Spendry lvp = NULL; 230267575Spendry } 230367575Spendry } 230467575Spendry 230567575Spendry if (lvp != NULLVP) { 230667362Smckusick error = VOP_OPEN(lvp, FREAD, fp->f_cred, p); 2307*69409Smckusick VOP_UNLOCK(lvp, 0, p); 230866095Spendry 230966095Spendry if (error) { 231067122Spendry vrele(lvp); 231166095Spendry return (error); 231266095Spendry } 231367122Spendry fp->f_data = (caddr_t) lvp; 231466095Spendry fp->f_offset = 0; 231567122Spendry error = vn_close(vp, FREAD, fp->f_cred, p); 231666095Spendry if (error) 231766095Spendry return (error); 231867122Spendry vp = lvp; 231966095Spendry goto unionread; 232066095Spendry } 232166095Spendry } 232266095Spendry } 232368318Scgd #endif /* UNION */ 232466095Spendry 232568318Scgd if ((SCARG(uap, count) == auio.uio_resid) && 232655451Spendry (vp->v_flag & VROOT) && 232755451Spendry (vp->v_mount->mnt_flag & MNT_UNION)) { 232855451Spendry struct vnode *tvp = vp; 232955451Spendry vp = vp->v_mount->mnt_vnodecovered; 233055451Spendry VREF(vp); 233155451Spendry fp->f_data = (caddr_t) vp; 233255451Spendry fp->f_offset = 0; 233355451Spendry vrele(tvp); 233455451Spendry goto unionread; 233555451Spendry } 233668318Scgd error = copyout((caddr_t)&loff, (caddr_t)SCARG(uap, basep), 233768318Scgd sizeof(long)); 233868318Scgd *retval = SCARG(uap, count) - auio.uio_resid; 233947540Skarels return (error); 234012756Ssam } 234112756Ssam 234212756Ssam /* 234349365Smckusick * Set the mode mask for creation of filesystem nodes. 234412756Ssam */ 234568318Scgd int 234642441Smckusick umask(p, uap, retval) 234745914Smckusick struct proc *p; 234868318Scgd struct umask_args /* { 234968318Scgd syscallarg(int) newmask; 235068318Scgd } */ *uap; 235168318Scgd register_t *retval; 235212756Ssam { 235364410Sbostic register struct filedesc *fdp; 235412756Ssam 235564410Sbostic fdp = p->p_fd; 235645914Smckusick *retval = fdp->fd_cmask; 235768318Scgd fdp->fd_cmask = SCARG(uap, newmask) & ALLPERMS; 235847540Skarels return (0); 235912756Ssam } 236037741Smckusick 236139566Smarc /* 236239566Smarc * Void all references to file by ripping underlying filesystem 236339566Smarc * away from vnode. 236439566Smarc */ 236542441Smckusick /* ARGSUSED */ 236668318Scgd int 236742441Smckusick revoke(p, uap, retval) 236845914Smckusick struct proc *p; 236968318Scgd register struct revoke_args /* { 237068318Scgd syscallarg(char *) path; 237168318Scgd } */ *uap; 237268318Scgd register_t *retval; 237342441Smckusick { 237439566Smarc register struct vnode *vp; 237539566Smarc struct vattr vattr; 237639566Smarc int error; 237747540Skarels struct nameidata nd; 237839566Smarc 237968318Scgd NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 238052322Smckusick if (error = namei(&nd)) 238147540Skarels return (error); 238252322Smckusick vp = nd.ni_vp; 238348026Smckusick if (error = VOP_GETATTR(vp, &vattr, p->p_ucred, p)) 238439566Smarc goto out; 238547540Skarels if (p->p_ucred->cr_uid != vattr.va_uid && 238647540Skarels (error = suser(p->p_ucred, &p->p_acflag))) 238739566Smarc goto out; 238839805Smckusick if (vp->v_usecount > 1 || (vp->v_flag & VALIASED)) 238968423Smckusick VOP_REVOKE(vp, REVOKEALL); 239039566Smarc out: 239139566Smarc vrele(vp); 239247540Skarels return (error); 239339566Smarc } 239439566Smarc 239549365Smckusick /* 239649365Smckusick * Convert a user file descriptor to a kernel file entry. 239749365Smckusick */ 239868318Scgd int 239964410Sbostic getvnode(fdp, fd, fpp) 240045914Smckusick struct filedesc *fdp; 240137741Smckusick struct file **fpp; 240264410Sbostic int fd; 240337741Smckusick { 240437741Smckusick struct file *fp; 240537741Smckusick 240664410Sbostic if ((u_int)fd >= fdp->fd_nfiles || 240764410Sbostic (fp = fdp->fd_ofiles[fd]) == NULL) 240837741Smckusick return (EBADF); 240937741Smckusick if (fp->f_type != DTYPE_VNODE) 241037741Smckusick return (EINVAL); 241137741Smckusick *fpp = fp; 241237741Smckusick return (0); 241337741Smckusick } 2414