123405Smckusick /* 237741Smckusick * Copyright (c) 1989 The Regents of the University of California. 337741Smckusick * All rights reserved. 423405Smckusick * 544459Sbostic * %sccs.include.redist.c% 637741Smckusick * 7*54100Smckusick * @(#)vfs_syscalls.c 7.85 (Berkeley) 06/19/92 823405Smckusick */ 937Sbill 1017101Sbloom #include "param.h" 1117101Sbloom #include "systm.h" 1247540Skarels #include "namei.h" 1345914Smckusick #include "filedesc.h" 1417101Sbloom #include "kernel.h" 1517101Sbloom #include "file.h" 1617101Sbloom #include "stat.h" 1737741Smckusick #include "vnode.h" 1837741Smckusick #include "mount.h" 1917101Sbloom #include "proc.h" 2017101Sbloom #include "uio.h" 2137741Smckusick #include "malloc.h" 2253468Smckusick #include <vm/vm.h> 2337Sbill 2437741Smckusick /* 2537741Smckusick * Virtual File System System Calls 2637741Smckusick */ 2712756Ssam 289167Ssam /* 2949365Smckusick * Mount system call. 309167Ssam */ 3142441Smckusick /* ARGSUSED */ 3242441Smckusick mount(p, uap, retval) 3345914Smckusick struct proc *p; 3442441Smckusick register struct args { 3537741Smckusick int type; 3637741Smckusick char *dir; 3737741Smckusick int flags; 3837741Smckusick caddr_t data; 3942441Smckusick } *uap; 4042441Smckusick int *retval; 4142441Smckusick { 4253548Sheideman USES_VOP_UNLOCK; 4339335Smckusick register struct vnode *vp; 4439335Smckusick register struct mount *mp; 4540111Smckusick int error, flag; 4647540Skarels struct nameidata nd; 476254Sroot 4837741Smckusick /* 4937741Smckusick * Must be super user 5037741Smckusick */ 5147540Skarels if (error = suser(p->p_ucred, &p->p_acflag)) 5247540Skarels return (error); 5337741Smckusick /* 5437741Smckusick * Get vnode to be covered 5537741Smckusick */ 5652322Smckusick NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->dir, p); 5752322Smckusick if (error = namei(&nd)) 5847540Skarels return (error); 5952322Smckusick vp = nd.ni_vp; 6041400Smckusick if (uap->flags & MNT_UPDATE) { 6139335Smckusick if ((vp->v_flag & VROOT) == 0) { 6239335Smckusick vput(vp); 6347540Skarels return (EINVAL); 6439335Smckusick } 6539335Smckusick mp = vp->v_mount; 6639335Smckusick /* 6739335Smckusick * We allow going from read-only to read-write, 6839335Smckusick * but not from read-write to read-only. 6939335Smckusick */ 7041400Smckusick if ((mp->mnt_flag & MNT_RDONLY) == 0 && 7141400Smckusick (uap->flags & MNT_RDONLY) != 0) { 7239335Smckusick vput(vp); 7347540Skarels return (EOPNOTSUPP); /* Needs translation */ 7439335Smckusick } 7541400Smckusick flag = mp->mnt_flag; 7641400Smckusick mp->mnt_flag |= MNT_UPDATE; 7739335Smckusick VOP_UNLOCK(vp); 7839335Smckusick goto update; 7939335Smckusick } 8039665Smckusick vinvalbuf(vp, 1); 8139805Smckusick if (vp->v_usecount != 1) { 8237741Smckusick vput(vp); 8347540Skarels return (EBUSY); 8437741Smckusick } 8537741Smckusick if (vp->v_type != VDIR) { 8637741Smckusick vput(vp); 8747540Skarels return (ENOTDIR); 8837741Smckusick } 8939741Smckusick if ((unsigned long)uap->type > MOUNT_MAXTYPE || 9037741Smckusick vfssw[uap->type] == (struct vfsops *)0) { 9137741Smckusick vput(vp); 9247540Skarels return (ENODEV); 9337741Smckusick } 9437741Smckusick 9537741Smckusick /* 9639335Smckusick * Allocate and initialize the file system. 9737741Smckusick */ 9837741Smckusick mp = (struct mount *)malloc((u_long)sizeof(struct mount), 9937741Smckusick M_MOUNT, M_WAITOK); 10041400Smckusick mp->mnt_op = vfssw[uap->type]; 10141400Smckusick mp->mnt_flag = 0; 10241400Smckusick mp->mnt_mounth = NULLVP; 10339335Smckusick if (error = vfs_lock(mp)) { 10439335Smckusick free((caddr_t)mp, M_MOUNT); 10539335Smckusick vput(vp); 10647540Skarels return (error); 10739335Smckusick } 10839335Smckusick if (vp->v_mountedhere != (struct mount *)0) { 10939335Smckusick vfs_unlock(mp); 11039335Smckusick free((caddr_t)mp, M_MOUNT); 11139335Smckusick vput(vp); 11247540Skarels return (EBUSY); 11339335Smckusick } 11439335Smckusick vp->v_mountedhere = mp; 11541400Smckusick mp->mnt_vnodecovered = vp; 11639335Smckusick update: 11739335Smckusick /* 11839335Smckusick * Set the mount level flags. 11939335Smckusick */ 12041400Smckusick if (uap->flags & MNT_RDONLY) 12141400Smckusick mp->mnt_flag |= MNT_RDONLY; 12239335Smckusick else 12341400Smckusick mp->mnt_flag &= ~MNT_RDONLY; 12441400Smckusick if (uap->flags & MNT_NOSUID) 12541400Smckusick mp->mnt_flag |= MNT_NOSUID; 12639335Smckusick else 12741400Smckusick mp->mnt_flag &= ~MNT_NOSUID; 12841400Smckusick if (uap->flags & MNT_NOEXEC) 12941400Smckusick mp->mnt_flag |= MNT_NOEXEC; 13039335Smckusick else 13141400Smckusick mp->mnt_flag &= ~MNT_NOEXEC; 13241400Smckusick if (uap->flags & MNT_NODEV) 13341400Smckusick mp->mnt_flag |= MNT_NODEV; 13439335Smckusick else 13541400Smckusick mp->mnt_flag &= ~MNT_NODEV; 13641400Smckusick if (uap->flags & MNT_SYNCHRONOUS) 13741400Smckusick mp->mnt_flag |= MNT_SYNCHRONOUS; 13839335Smckusick else 13941400Smckusick mp->mnt_flag &= ~MNT_SYNCHRONOUS; 14039335Smckusick /* 14139335Smckusick * Mount the filesystem. 14239335Smckusick */ 14352322Smckusick error = VFS_MOUNT(mp, uap->dir, uap->data, &nd, p); 14441400Smckusick if (mp->mnt_flag & MNT_UPDATE) { 14541400Smckusick mp->mnt_flag &= ~MNT_UPDATE; 14639335Smckusick vrele(vp); 14740111Smckusick if (error) 14841400Smckusick mp->mnt_flag = flag; 14947540Skarels return (error); 15039335Smckusick } 15140110Smckusick /* 15240110Smckusick * Put the new filesystem on the mount list after root. 15340110Smckusick */ 15441400Smckusick mp->mnt_next = rootfs->mnt_next; 15541400Smckusick mp->mnt_prev = rootfs; 15641400Smckusick rootfs->mnt_next = mp; 15741400Smckusick mp->mnt_next->mnt_prev = mp; 15837741Smckusick cache_purge(vp); 15937741Smckusick if (!error) { 16039335Smckusick VOP_UNLOCK(vp); 16137741Smckusick vfs_unlock(mp); 16248026Smckusick error = VFS_START(mp, 0, p); 16337741Smckusick } else { 16437741Smckusick vfs_remove(mp); 16537741Smckusick free((caddr_t)mp, M_MOUNT); 16639335Smckusick vput(vp); 16737741Smckusick } 16847540Skarels return (error); 1696254Sroot } 1706254Sroot 1719167Ssam /* 17237741Smckusick * Unmount system call. 17337741Smckusick * 17437741Smckusick * Note: unmount takes a path to the vnode mounted on as argument, 17537741Smckusick * not special file (as before). 1769167Ssam */ 17742441Smckusick /* ARGSUSED */ 17842441Smckusick unmount(p, uap, retval) 17945914Smckusick struct proc *p; 18042441Smckusick register struct args { 18137741Smckusick char *pathp; 18237741Smckusick int flags; 18342441Smckusick } *uap; 18442441Smckusick int *retval; 18542441Smckusick { 18637741Smckusick register struct vnode *vp; 18739356Smckusick struct mount *mp; 18837741Smckusick int error; 18947540Skarels struct nameidata nd; 1906254Sroot 19137741Smckusick /* 19237741Smckusick * Must be super user 19337741Smckusick */ 19447540Skarels if (error = suser(p->p_ucred, &p->p_acflag)) 19547540Skarels return (error); 19637741Smckusick 19752322Smckusick NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->pathp, p); 19852322Smckusick if (error = namei(&nd)) 19947540Skarels return (error); 20052322Smckusick vp = nd.ni_vp; 20137741Smckusick /* 20237741Smckusick * Must be the root of the filesystem 20337741Smckusick */ 20437741Smckusick if ((vp->v_flag & VROOT) == 0) { 20537741Smckusick vput(vp); 20647540Skarels return (EINVAL); 20737741Smckusick } 20837741Smckusick mp = vp->v_mount; 20937741Smckusick vput(vp); 21048026Smckusick return (dounmount(mp, uap->flags, p)); 21139356Smckusick } 21239356Smckusick 21339356Smckusick /* 21439356Smckusick * Do an unmount. 21539356Smckusick */ 21648026Smckusick dounmount(mp, flags, p) 21739356Smckusick register struct mount *mp; 21839356Smckusick int flags; 21948026Smckusick struct proc *p; 22039356Smckusick { 22139356Smckusick struct vnode *coveredvp; 22239356Smckusick int error; 22339356Smckusick 22441400Smckusick coveredvp = mp->mnt_vnodecovered; 22541298Smckusick if (vfs_busy(mp)) 22641298Smckusick return (EBUSY); 22741400Smckusick mp->mnt_flag |= MNT_UNMOUNT; 22837741Smckusick if (error = vfs_lock(mp)) 22939356Smckusick return (error); 23037741Smckusick 23145738Smckusick vnode_pager_umount(mp); /* release cached vnodes */ 23237741Smckusick cache_purgevfs(mp); /* remove cache entries for this file sys */ 23341676Smckusick if ((error = VFS_SYNC(mp, MNT_WAIT)) == 0 || (flags & MNT_FORCE)) 23448026Smckusick error = VFS_UNMOUNT(mp, flags, p); 23541400Smckusick mp->mnt_flag &= ~MNT_UNMOUNT; 23641298Smckusick vfs_unbusy(mp); 23737741Smckusick if (error) { 23837741Smckusick vfs_unlock(mp); 23937741Smckusick } else { 24037741Smckusick vrele(coveredvp); 24137741Smckusick vfs_remove(mp); 24252287Smckusick if (mp->mnt_mounth != NULL) 24352287Smckusick panic("unmount: dangling vnode"); 24437741Smckusick free((caddr_t)mp, M_MOUNT); 24537741Smckusick } 24639356Smckusick return (error); 2476254Sroot } 2486254Sroot 2499167Ssam /* 25037741Smckusick * Sync system call. 25137741Smckusick * Sync each mounted filesystem. 2529167Ssam */ 25339491Smckusick /* ARGSUSED */ 25442441Smckusick sync(p, uap, retval) 25545914Smckusick struct proc *p; 25647540Skarels void *uap; 25742441Smckusick int *retval; 2586254Sroot { 25937741Smckusick register struct mount *mp; 26041298Smckusick struct mount *omp; 26137741Smckusick 26237741Smckusick mp = rootfs; 26337741Smckusick do { 26440343Smckusick /* 26540343Smckusick * The lock check below is to avoid races with mount 26640343Smckusick * and unmount. 26740343Smckusick */ 26841400Smckusick if ((mp->mnt_flag & (MNT_MLOCK|MNT_RDONLY|MNT_MPBUSY)) == 0 && 26941298Smckusick !vfs_busy(mp)) { 27037741Smckusick VFS_SYNC(mp, MNT_NOWAIT); 27141298Smckusick omp = mp; 27241400Smckusick mp = mp->mnt_next; 27341298Smckusick vfs_unbusy(omp); 27441298Smckusick } else 27541400Smckusick mp = mp->mnt_next; 27637741Smckusick } while (mp != rootfs); 27747688Skarels return (0); 27837741Smckusick } 27937741Smckusick 28037741Smckusick /* 28149365Smckusick * Operate on filesystem quotas. 28241298Smckusick */ 28342441Smckusick /* ARGSUSED */ 28442441Smckusick quotactl(p, uap, retval) 28545914Smckusick struct proc *p; 28642441Smckusick register struct args { 28741298Smckusick char *path; 28841298Smckusick int cmd; 28941298Smckusick int uid; 29041298Smckusick caddr_t arg; 29142441Smckusick } *uap; 29242441Smckusick int *retval; 29342441Smckusick { 29441298Smckusick register struct mount *mp; 29541298Smckusick int error; 29647540Skarels struct nameidata nd; 29741298Smckusick 29852322Smckusick NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); 29952322Smckusick if (error = namei(&nd)) 30047540Skarels return (error); 30152322Smckusick mp = nd.ni_vp->v_mount; 30252322Smckusick vrele(nd.ni_vp); 30348026Smckusick return (VFS_QUOTACTL(mp, uap->cmd, uap->uid, uap->arg, p)); 30441298Smckusick } 30541298Smckusick 30641298Smckusick /* 30749365Smckusick * Get filesystem statistics. 30837741Smckusick */ 30942441Smckusick /* ARGSUSED */ 31042441Smckusick statfs(p, uap, retval) 31145914Smckusick struct proc *p; 31242441Smckusick register struct args { 31337741Smckusick char *path; 31437741Smckusick struct statfs *buf; 31542441Smckusick } *uap; 31642441Smckusick int *retval; 31742441Smckusick { 31839464Smckusick register struct mount *mp; 31940343Smckusick register struct statfs *sp; 32037741Smckusick int error; 32147540Skarels struct nameidata nd; 32237741Smckusick 32352322Smckusick NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); 32452322Smckusick if (error = namei(&nd)) 32547540Skarels return (error); 32652322Smckusick mp = nd.ni_vp->v_mount; 32741400Smckusick sp = &mp->mnt_stat; 32852322Smckusick vrele(nd.ni_vp); 32948026Smckusick if (error = VFS_STATFS(mp, sp, p)) 33047540Skarels return (error); 33141400Smckusick sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 33247540Skarels return (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp))); 33337741Smckusick } 33437741Smckusick 33542441Smckusick /* 33649365Smckusick * Get filesystem statistics. 33742441Smckusick */ 33842441Smckusick /* ARGSUSED */ 33942441Smckusick fstatfs(p, uap, retval) 34045914Smckusick struct proc *p; 34142441Smckusick register struct args { 34237741Smckusick int fd; 34337741Smckusick struct statfs *buf; 34442441Smckusick } *uap; 34542441Smckusick int *retval; 34642441Smckusick { 34737741Smckusick struct file *fp; 34839464Smckusick struct mount *mp; 34940343Smckusick register struct statfs *sp; 35037741Smckusick int error; 35137741Smckusick 35245914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 35347540Skarels return (error); 35439464Smckusick mp = ((struct vnode *)fp->f_data)->v_mount; 35541400Smckusick sp = &mp->mnt_stat; 35648026Smckusick if (error = VFS_STATFS(mp, sp, p)) 35747540Skarels return (error); 35841400Smckusick sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 35947540Skarels return (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp))); 36037741Smckusick } 36137741Smckusick 36237741Smckusick /* 36349365Smckusick * Get statistics on all filesystems. 36438270Smckusick */ 36542441Smckusick getfsstat(p, uap, retval) 36645914Smckusick struct proc *p; 36742441Smckusick register struct args { 36838270Smckusick struct statfs *buf; 36938270Smckusick long bufsize; 37040343Smckusick int flags; 37142441Smckusick } *uap; 37242441Smckusick int *retval; 37342441Smckusick { 37438270Smckusick register struct mount *mp; 37540343Smckusick register struct statfs *sp; 37639606Smckusick caddr_t sfsp; 37738270Smckusick long count, maxcount, error; 37838270Smckusick 37938270Smckusick maxcount = uap->bufsize / sizeof(struct statfs); 38039606Smckusick sfsp = (caddr_t)uap->buf; 38138270Smckusick mp = rootfs; 38238270Smckusick count = 0; 38338270Smckusick do { 38441400Smckusick if (sfsp && count < maxcount && 38541400Smckusick ((mp->mnt_flag & MNT_MLOCK) == 0)) { 38641400Smckusick sp = &mp->mnt_stat; 38740343Smckusick /* 38840343Smckusick * If MNT_NOWAIT is specified, do not refresh the 38940343Smckusick * fsstat cache. MNT_WAIT overrides MNT_NOWAIT. 39040343Smckusick */ 39140343Smckusick if (((uap->flags & MNT_NOWAIT) == 0 || 39240343Smckusick (uap->flags & MNT_WAIT)) && 39348026Smckusick (error = VFS_STATFS(mp, sp, p))) { 39441400Smckusick mp = mp->mnt_prev; 39539607Smckusick continue; 39639607Smckusick } 39741400Smckusick sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 39840343Smckusick if (error = copyout((caddr_t)sp, sfsp, sizeof(*sp))) 39947540Skarels return (error); 40040343Smckusick sfsp += sizeof(*sp); 40138270Smckusick } 40239606Smckusick count++; 40341400Smckusick mp = mp->mnt_prev; 40438270Smckusick } while (mp != rootfs); 40538270Smckusick if (sfsp && count > maxcount) 40642441Smckusick *retval = maxcount; 40738270Smckusick else 40842441Smckusick *retval = count; 40947540Skarels return (0); 41038270Smckusick } 41138270Smckusick 41238270Smckusick /* 41338259Smckusick * Change current working directory to a given file descriptor. 41438259Smckusick */ 41542441Smckusick /* ARGSUSED */ 41642441Smckusick fchdir(p, uap, retval) 41745914Smckusick struct proc *p; 41842441Smckusick struct args { 41942441Smckusick int fd; 42042441Smckusick } *uap; 42142441Smckusick int *retval; 42238259Smckusick { 42353548Sheideman USES_VOP_ACCESS; 42453548Sheideman USES_VOP_LOCK; 42553548Sheideman USES_VOP_UNLOCK; 42645914Smckusick register struct filedesc *fdp = p->p_fd; 42738259Smckusick register struct vnode *vp; 42838259Smckusick struct file *fp; 42938259Smckusick int error; 43038259Smckusick 43145914Smckusick if (error = getvnode(fdp, uap->fd, &fp)) 43247540Skarels return (error); 43338259Smckusick vp = (struct vnode *)fp->f_data; 43438259Smckusick VOP_LOCK(vp); 43538259Smckusick if (vp->v_type != VDIR) 43638259Smckusick error = ENOTDIR; 43738259Smckusick else 43848026Smckusick error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p); 43938259Smckusick VOP_UNLOCK(vp); 44039860Smckusick if (error) 44147540Skarels return (error); 44239860Smckusick VREF(vp); 44345914Smckusick vrele(fdp->fd_cdir); 44445914Smckusick fdp->fd_cdir = vp; 44547540Skarels return (0); 44638259Smckusick } 44738259Smckusick 44838259Smckusick /* 44937741Smckusick * Change current working directory (``.''). 45037741Smckusick */ 45142441Smckusick /* ARGSUSED */ 45242441Smckusick chdir(p, uap, retval) 45345914Smckusick struct proc *p; 45442441Smckusick struct args { 45542441Smckusick char *fname; 45642441Smckusick } *uap; 45742441Smckusick int *retval; 45837741Smckusick { 45945914Smckusick register struct filedesc *fdp = p->p_fd; 46037741Smckusick int error; 46147540Skarels struct nameidata nd; 4626254Sroot 46352322Smckusick NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 46452781Sralph if (error = chdirec(&nd, p)) 46547540Skarels return (error); 46645914Smckusick vrele(fdp->fd_cdir); 46752322Smckusick fdp->fd_cdir = nd.ni_vp; 46847540Skarels return (0); 46937741Smckusick } 4706254Sroot 47137741Smckusick /* 47237741Smckusick * Change notion of root (``/'') directory. 47337741Smckusick */ 47442441Smckusick /* ARGSUSED */ 47542441Smckusick chroot(p, uap, retval) 47645914Smckusick struct proc *p; 47742441Smckusick struct args { 47842441Smckusick char *fname; 47942441Smckusick } *uap; 48042441Smckusick int *retval; 48137741Smckusick { 48245914Smckusick register struct filedesc *fdp = p->p_fd; 48337741Smckusick int error; 48447540Skarels struct nameidata nd; 48537741Smckusick 48647540Skarels if (error = suser(p->p_ucred, &p->p_acflag)) 48747540Skarels return (error); 48852322Smckusick NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 48952781Sralph if (error = chdirec(&nd, p)) 49047540Skarels return (error); 49145914Smckusick if (fdp->fd_rdir != NULL) 49245914Smckusick vrele(fdp->fd_rdir); 49352322Smckusick fdp->fd_rdir = nd.ni_vp; 49447540Skarels return (0); 4956254Sroot } 4966254Sroot 49737Sbill /* 49837741Smckusick * Common routine for chroot and chdir. 49937741Smckusick */ 50047540Skarels chdirec(ndp, p) 50152322Smckusick register struct nameidata *ndp; 50247540Skarels struct proc *p; 50337741Smckusick { 50453548Sheideman USES_VOP_ACCESS; 50553548Sheideman USES_VOP_UNLOCK; 50637741Smckusick struct vnode *vp; 50737741Smckusick int error; 50837741Smckusick 50952322Smckusick if (error = namei(ndp)) 51037741Smckusick return (error); 51137741Smckusick vp = ndp->ni_vp; 51237741Smckusick if (vp->v_type != VDIR) 51337741Smckusick error = ENOTDIR; 51437741Smckusick else 51548026Smckusick error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p); 51637741Smckusick VOP_UNLOCK(vp); 51737741Smckusick if (error) 51837741Smckusick vrele(vp); 51937741Smckusick return (error); 52037741Smckusick } 52137741Smckusick 52237741Smckusick /* 5236254Sroot * Open system call. 52442441Smckusick * Check permissions, allocate an open file structure, 52542441Smckusick * and call the device open routine if any. 5266254Sroot */ 52742441Smckusick open(p, uap, retval) 52845914Smckusick struct proc *p; 52942441Smckusick register struct args { 5306254Sroot char *fname; 5317701Ssam int mode; 53212756Ssam int crtmode; 53342441Smckusick } *uap; 53442441Smckusick int *retval; 5356254Sroot { 53653548Sheideman USES_VOP_ADVLOCK; 53753548Sheideman USES_VOP_UNLOCK; 53845914Smckusick register struct filedesc *fdp = p->p_fd; 53942441Smckusick register struct file *fp; 54050111Smckusick register struct vnode *vp; 54137741Smckusick int fmode, cmode; 54237741Smckusick struct file *nfp; 54349945Smckusick int type, indx, error; 54449945Smckusick struct flock lf; 54547540Skarels struct nameidata nd; 54637741Smckusick extern struct fileops vnops; 5476254Sroot 54845914Smckusick if (error = falloc(p, &nfp, &indx)) 54947540Skarels return (error); 55037741Smckusick fp = nfp; 55146553Skarels fmode = FFLAGS(uap->mode); 55245914Smckusick cmode = ((uap->crtmode &~ fdp->fd_cmask) & 07777) &~ S_ISVTX; 55352322Smckusick NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->fname, p); 55445202Smckusick p->p_dupfd = -indx - 1; /* XXX check for fdopen */ 55552322Smckusick if (error = vn_open(&nd, fmode, cmode)) { 55653828Spendry int dfd = p->p_dupfd; 55753828Spendry p->p_dupfd = 0; 55849980Smckusick ffree(fp); 55953828Spendry if ((error == ENODEV || error == ENXIO) && /* XXX from fdopen */ 56053828Spendry dfd >= 0 && 56153828Spendry (error = dupfdopen(fdp, indx, p->p_dupfd, 56253828Spendry fmode, error)) == 0) { 56342441Smckusick *retval = indx; 56447540Skarels return (0); 56542441Smckusick } 56640884Smckusick if (error == ERESTART) 56740884Smckusick error = EINTR; 56847688Skarels fdp->fd_ofiles[indx] = NULL; 56947540Skarels return (error); 57012756Ssam } 57153828Spendry p->p_dupfd = 0; 57252322Smckusick vp = nd.ni_vp; 57349949Smckusick fp->f_flag = fmode & FMASK; 57449945Smckusick if (fmode & (O_EXLOCK | O_SHLOCK)) { 57549945Smckusick lf.l_whence = SEEK_SET; 57649945Smckusick lf.l_start = 0; 57749945Smckusick lf.l_len = 0; 57849945Smckusick if (fmode & O_EXLOCK) 57949945Smckusick lf.l_type = F_WRLCK; 58049945Smckusick else 58149945Smckusick lf.l_type = F_RDLCK; 58249945Smckusick type = F_FLOCK; 58349945Smckusick if ((fmode & FNONBLOCK) == 0) 58449945Smckusick type |= F_WAIT; 58550111Smckusick if (error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, type)) { 58650111Smckusick VOP_UNLOCK(vp); 58750111Smckusick (void) vn_close(vp, fp->f_flag, fp->f_cred, p); 58849980Smckusick ffree(fp); 58949945Smckusick fdp->fd_ofiles[indx] = NULL; 59049945Smckusick return (error); 59149945Smckusick } 59249949Smckusick fp->f_flag |= FHASLOCK; 59349945Smckusick } 59450111Smckusick VOP_UNLOCK(vp); 59537741Smckusick fp->f_type = DTYPE_VNODE; 59637741Smckusick fp->f_ops = &vnops; 59750111Smckusick fp->f_data = (caddr_t)vp; 59842441Smckusick *retval = indx; 59947540Skarels return (0); 6006254Sroot } 6016254Sroot 60242955Smckusick #ifdef COMPAT_43 6036254Sroot /* 60442441Smckusick * Creat system call. 6056254Sroot */ 60642955Smckusick ocreat(p, uap, retval) 60742441Smckusick struct proc *p; 60842441Smckusick register struct args { 60942441Smckusick char *fname; 61042441Smckusick int fmode; 61142441Smckusick } *uap; 61242441Smckusick int *retval; 6136254Sroot { 61442441Smckusick struct args { 6156254Sroot char *fname; 61642441Smckusick int mode; 61742441Smckusick int crtmode; 61842441Smckusick } openuap; 61942441Smckusick 62042441Smckusick openuap.fname = uap->fname; 62142441Smckusick openuap.crtmode = uap->fmode; 62242441Smckusick openuap.mode = O_WRONLY | O_CREAT | O_TRUNC; 62347540Skarels return (open(p, &openuap, retval)); 62442441Smckusick } 62542955Smckusick #endif /* COMPAT_43 */ 62642441Smckusick 62742441Smckusick /* 62849365Smckusick * Mknod system call. 62942441Smckusick */ 63042441Smckusick /* ARGSUSED */ 63142441Smckusick mknod(p, uap, retval) 63245914Smckusick struct proc *p; 63342441Smckusick register struct args { 63442441Smckusick char *fname; 6356254Sroot int fmode; 6366254Sroot int dev; 63742441Smckusick } *uap; 63842441Smckusick int *retval; 63942441Smckusick { 64053548Sheideman USES_VOP_ABORTOP; 64153548Sheideman USES_VOP_MKNOD; 64237741Smckusick register struct vnode *vp; 64337741Smckusick struct vattr vattr; 64437741Smckusick int error; 64547540Skarels struct nameidata nd; 6466254Sroot 64747540Skarels if (error = suser(p->p_ucred, &p->p_acflag)) 64847540Skarels return (error); 64952322Smckusick NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->fname, p); 65052322Smckusick if (error = namei(&nd)) 65147540Skarels return (error); 65252322Smckusick vp = nd.ni_vp; 65337741Smckusick if (vp != NULL) { 65437741Smckusick error = EEXIST; 65512756Ssam goto out; 6566254Sroot } 65741362Smckusick VATTR_NULL(&vattr); 65840635Smckusick switch (uap->fmode & S_IFMT) { 65912756Ssam 66040635Smckusick case S_IFMT: /* used by badsect to flag bad sectors */ 66137741Smckusick vattr.va_type = VBAD; 66237741Smckusick break; 66340635Smckusick case S_IFCHR: 66437741Smckusick vattr.va_type = VCHR; 66537741Smckusick break; 66640635Smckusick case S_IFBLK: 66737741Smckusick vattr.va_type = VBLK; 66837741Smckusick break; 66937741Smckusick default: 67037741Smckusick error = EINVAL; 67137741Smckusick goto out; 6726254Sroot } 67345914Smckusick vattr.va_mode = (uap->fmode & 07777) &~ p->p_fd->fd_cmask; 67437741Smckusick vattr.va_rdev = uap->dev; 6756254Sroot out: 67642465Smckusick if (!error) { 67752322Smckusick LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 67852322Smckusick error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr); 67942465Smckusick } else { 68052322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 68152322Smckusick if (nd.ni_dvp == vp) 68252322Smckusick vrele(nd.ni_dvp); 68343344Smckusick else 68452322Smckusick vput(nd.ni_dvp); 68542465Smckusick if (vp) 68642465Smckusick vrele(vp); 68742465Smckusick } 68847540Skarels return (error); 6896254Sroot } 6906254Sroot 6916254Sroot /* 69249365Smckusick * Mkfifo system call. 69340285Smckusick */ 69442441Smckusick /* ARGSUSED */ 69542441Smckusick mkfifo(p, uap, retval) 69645914Smckusick struct proc *p; 69742441Smckusick register struct args { 69840285Smckusick char *fname; 69940285Smckusick int fmode; 70042441Smckusick } *uap; 70142441Smckusick int *retval; 70242441Smckusick { 70353548Sheideman USES_VOP_ABORTOP; 70453548Sheideman USES_VOP_MKNOD; 70540285Smckusick struct vattr vattr; 70640285Smckusick int error; 70747540Skarels struct nameidata nd; 70840285Smckusick 70940285Smckusick #ifndef FIFO 71047540Skarels return (EOPNOTSUPP); 71140285Smckusick #else 71252322Smckusick NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->fname, p); 71352322Smckusick if (error = namei(&nd)) 71447540Skarels return (error); 71552322Smckusick if (nd.ni_vp != NULL) { 71652322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 71752322Smckusick if (nd.ni_dvp == nd.ni_vp) 71852322Smckusick vrele(nd.ni_dvp); 71943344Smckusick else 72052322Smckusick vput(nd.ni_dvp); 72152322Smckusick vrele(nd.ni_vp); 72247540Skarels return (EEXIST); 72340285Smckusick } 72445785Sbostic VATTR_NULL(&vattr); 72545785Sbostic vattr.va_type = VFIFO; 72645914Smckusick vattr.va_mode = (uap->fmode & 07777) &~ p->p_fd->fd_cmask; 72752322Smckusick LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 72852322Smckusick return (VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr)); 72940285Smckusick #endif /* FIFO */ 73040285Smckusick } 73140285Smckusick 73240285Smckusick /* 73349365Smckusick * Link system call. 7346254Sroot */ 73542441Smckusick /* ARGSUSED */ 73642441Smckusick link(p, uap, retval) 73745914Smckusick struct proc *p; 73842441Smckusick register struct args { 7396254Sroot char *target; 7406254Sroot char *linkname; 74142441Smckusick } *uap; 74242441Smckusick int *retval; 74342441Smckusick { 74453548Sheideman USES_VOP_ABORTOP; 74553548Sheideman USES_VOP_LINK; 74637741Smckusick register struct vnode *vp, *xp; 74737741Smckusick int error; 74847540Skarels struct nameidata nd; 7496254Sroot 75052322Smckusick NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->target, p); 75152322Smckusick if (error = namei(&nd)) 75247540Skarels return (error); 75352322Smckusick vp = nd.ni_vp; 75437741Smckusick if (vp->v_type == VDIR && 75547540Skarels (error = suser(p->p_ucred, &p->p_acflag))) 75637741Smckusick goto out1; 75752322Smckusick nd.ni_cnd.cn_nameiop = CREATE; 75852322Smckusick nd.ni_cnd.cn_flags = LOCKPARENT; 75952322Smckusick nd.ni_dirp = (caddr_t)uap->linkname; 76052322Smckusick if (error = namei(&nd)) 76137741Smckusick goto out1; 76252322Smckusick xp = nd.ni_vp; 7636254Sroot if (xp != NULL) { 76437741Smckusick error = EEXIST; 7656254Sroot goto out; 7666254Sroot } 76752322Smckusick xp = nd.ni_dvp; 7686254Sroot out: 76942465Smckusick if (!error) { 77052192Smckusick LEASE_CHECK(xp, p, p->p_ucred, LEASE_WRITE); 77152192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 77252821Smckusick error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd); 77342465Smckusick } else { 77452322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 77552322Smckusick if (nd.ni_dvp == nd.ni_vp) 77652322Smckusick vrele(nd.ni_dvp); 77743344Smckusick else 77852322Smckusick vput(nd.ni_dvp); 77952322Smckusick if (nd.ni_vp) 78052322Smckusick vrele(nd.ni_vp); 78142465Smckusick } 78237741Smckusick out1: 78337741Smckusick vrele(vp); 78447540Skarels return (error); 7856254Sroot } 7866254Sroot 7876254Sroot /* 78849365Smckusick * Make a symbolic link. 7896254Sroot */ 79042441Smckusick /* ARGSUSED */ 79142441Smckusick symlink(p, uap, retval) 79245914Smckusick struct proc *p; 79342441Smckusick register struct args { 7946254Sroot char *target; 7956254Sroot char *linkname; 79642441Smckusick } *uap; 79742441Smckusick int *retval; 79842441Smckusick { 79953548Sheideman USES_VOP_ABORTOP; 80053548Sheideman USES_VOP_SYMLINK; 80137741Smckusick struct vattr vattr; 80237741Smckusick char *target; 80337741Smckusick int error; 80447540Skarels struct nameidata nd; 8056254Sroot 80637741Smckusick MALLOC(target, char *, MAXPATHLEN, M_NAMEI, M_WAITOK); 80737741Smckusick if (error = copyinstr(uap->target, target, MAXPATHLEN, (u_int *)0)) 80842465Smckusick goto out; 80952322Smckusick NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->linkname, p); 81052322Smckusick if (error = namei(&nd)) 81142465Smckusick goto out; 81252322Smckusick if (nd.ni_vp) { 81352322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 81452322Smckusick if (nd.ni_dvp == nd.ni_vp) 81552322Smckusick vrele(nd.ni_dvp); 81643344Smckusick else 81752322Smckusick vput(nd.ni_dvp); 81852322Smckusick vrele(nd.ni_vp); 81937741Smckusick error = EEXIST; 82037741Smckusick goto out; 8216254Sroot } 82241362Smckusick VATTR_NULL(&vattr); 82345914Smckusick vattr.va_mode = 0777 &~ p->p_fd->fd_cmask; 82452322Smckusick LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 82552322Smckusick error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr, target); 82637741Smckusick out: 82737741Smckusick FREE(target, M_NAMEI); 82847540Skarels return (error); 8296254Sroot } 8306254Sroot 8316254Sroot /* 83249365Smckusick * Delete a name from the filesystem. 8336254Sroot */ 83442441Smckusick /* ARGSUSED */ 83542441Smckusick unlink(p, uap, retval) 83645914Smckusick struct proc *p; 83742441Smckusick struct args { 83852322Smckusick char *name; 83942441Smckusick } *uap; 84042441Smckusick int *retval; 8416254Sroot { 84253548Sheideman USES_VOP_ABORTOP; 84353548Sheideman USES_VOP_REMOVE; 84437741Smckusick register struct vnode *vp; 84537741Smckusick int error; 84647540Skarels struct nameidata nd; 8476254Sroot 84852322Smckusick NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE, uap->name, p); 84952322Smckusick if (error = namei(&nd)) 85047540Skarels return (error); 85152322Smckusick vp = nd.ni_vp; 85237741Smckusick if (vp->v_type == VDIR && 85347540Skarels (error = suser(p->p_ucred, &p->p_acflag))) 8546254Sroot goto out; 8556254Sroot /* 85649365Smckusick * The root of a mounted filesystem cannot be deleted. 8576254Sroot */ 85837741Smckusick if (vp->v_flag & VROOT) { 85937741Smckusick error = EBUSY; 8606254Sroot goto out; 8616254Sroot } 86245738Smckusick (void) vnode_pager_uncache(vp); 8636254Sroot out: 86442465Smckusick if (!error) { 86552322Smckusick LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 86652192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 86752322Smckusick error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); 86842465Smckusick } else { 86952322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 87052322Smckusick if (nd.ni_dvp == vp) 87152322Smckusick vrele(nd.ni_dvp); 87243344Smckusick else 87352322Smckusick vput(nd.ni_dvp); 87442465Smckusick vput(vp); 87542465Smckusick } 87647540Skarels return (error); 8776254Sroot } 8786254Sroot 87953468Smckusick #ifdef COMPAT_43 8806254Sroot /* 88149365Smckusick * Seek system call. 8826254Sroot */ 88342441Smckusick lseek(p, uap, retval) 88445914Smckusick struct proc *p; 88542441Smckusick register struct args { 88637741Smckusick int fdes; 88753468Smckusick long off; 88853468Smckusick int sbase; 88953468Smckusick } *uap; 89053468Smckusick long *retval; 89153468Smckusick { 89253468Smckusick struct nargs { 89353468Smckusick int fdes; 8946254Sroot off_t off; 8956254Sroot int sbase; 89653468Smckusick } nuap; 89753468Smckusick quad_t qret; 89853468Smckusick int error; 89953468Smckusick 90053468Smckusick nuap.fdes = uap->fdes; 90153468Smckusick nuap.off = uap->off; 90253468Smckusick nuap.sbase = uap->sbase; 90353759Smckusick error = __lseek(p, &nuap, &qret); 90453468Smckusick *retval = qret; 90553468Smckusick return (error); 90653468Smckusick } 90753468Smckusick #endif /* COMPAT_43 */ 90853468Smckusick 90953468Smckusick /* 91053468Smckusick * Seek system call. 91153468Smckusick */ 91253759Smckusick __lseek(p, uap, retval) 91353468Smckusick struct proc *p; 91453468Smckusick register struct args { 91553468Smckusick int fdes; 91653468Smckusick off_t off; 91753468Smckusick int sbase; 91842441Smckusick } *uap; 91942441Smckusick off_t *retval; 92042441Smckusick { 92153548Sheideman USES_VOP_GETATTR; 92247540Skarels struct ucred *cred = p->p_ucred; 92345914Smckusick register struct filedesc *fdp = p->p_fd; 92442441Smckusick register struct file *fp; 92537741Smckusick struct vattr vattr; 92637741Smckusick int error; 9276254Sroot 92847540Skarels if ((unsigned)uap->fdes >= fdp->fd_nfiles || 92947688Skarels (fp = fdp->fd_ofiles[uap->fdes]) == NULL) 93047540Skarels return (EBADF); 93137741Smckusick if (fp->f_type != DTYPE_VNODE) 93247540Skarels return (ESPIPE); 93313878Ssam switch (uap->sbase) { 93413878Ssam 93513878Ssam case L_INCR: 93613878Ssam fp->f_offset += uap->off; 93713878Ssam break; 93813878Ssam 93913878Ssam case L_XTND: 94037741Smckusick if (error = VOP_GETATTR((struct vnode *)fp->f_data, 94148026Smckusick &vattr, cred, p)) 94247540Skarels return (error); 94337741Smckusick fp->f_offset = uap->off + vattr.va_size; 94413878Ssam break; 94513878Ssam 94613878Ssam case L_SET: 94713878Ssam fp->f_offset = uap->off; 94813878Ssam break; 94913878Ssam 95013878Ssam default: 95147540Skarels return (EINVAL); 95213878Ssam } 95342441Smckusick *retval = fp->f_offset; 95447540Skarels return (0); 9556254Sroot } 9566254Sroot 9576254Sroot /* 95849365Smckusick * Check access permissions. 9596254Sroot */ 96042441Smckusick /* ARGSUSED */ 96142441Smckusick saccess(p, uap, retval) 96245914Smckusick struct proc *p; 96342441Smckusick register struct args { 9646254Sroot char *fname; 9656254Sroot int fmode; 96642441Smckusick } *uap; 96742441Smckusick int *retval; 96842441Smckusick { 96953548Sheideman USES_VOP_ACCESS; 97047540Skarels register struct ucred *cred = p->p_ucred; 97137741Smckusick register struct vnode *vp; 97237741Smckusick int error, mode, svuid, svgid; 97347540Skarels struct nameidata nd; 9746254Sroot 97542441Smckusick svuid = cred->cr_uid; 97642441Smckusick svgid = cred->cr_groups[0]; 97747540Skarels cred->cr_uid = p->p_cred->p_ruid; 97847540Skarels cred->cr_groups[0] = p->p_cred->p_rgid; 97952322Smckusick NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 98052322Smckusick if (error = namei(&nd)) 98137741Smckusick goto out1; 98252322Smckusick vp = nd.ni_vp; 98337741Smckusick /* 98437741Smckusick * fmode == 0 means only check for exist 98537741Smckusick */ 98637741Smckusick if (uap->fmode) { 98737741Smckusick mode = 0; 98837741Smckusick if (uap->fmode & R_OK) 98937741Smckusick mode |= VREAD; 99037741Smckusick if (uap->fmode & W_OK) 99137741Smckusick mode |= VWRITE; 99237741Smckusick if (uap->fmode & X_OK) 99337741Smckusick mode |= VEXEC; 99439543Smckusick if ((mode & VWRITE) == 0 || (error = vn_writechk(vp)) == 0) 99548026Smckusick error = VOP_ACCESS(vp, mode, cred, p); 9966254Sroot } 99737741Smckusick vput(vp); 99837741Smckusick out1: 99942441Smckusick cred->cr_uid = svuid; 100042441Smckusick cred->cr_groups[0] = svgid; 100147540Skarels return (error); 10026254Sroot } 10036254Sroot 100453468Smckusick #ifdef COMPAT_43 10056254Sroot /* 100649365Smckusick * Stat system call. 100749365Smckusick * This version follows links. 100837Sbill */ 100942441Smckusick /* ARGSUSED */ 101053759Smckusick ostat(p, uap, retval) 101145914Smckusick struct proc *p; 101242441Smckusick register struct args { 101342441Smckusick char *fname; 101453468Smckusick struct ostat *ub; 101553468Smckusick } *uap; 101653468Smckusick int *retval; 101753468Smckusick { 101853468Smckusick struct stat sb; 101953468Smckusick struct ostat osb; 102053468Smckusick int error; 102153468Smckusick struct nameidata nd; 102253468Smckusick 102353468Smckusick NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 102453468Smckusick if (error = namei(&nd)) 102553468Smckusick return (error); 102653468Smckusick error = vn_stat(nd.ni_vp, &sb, p); 102753468Smckusick vput(nd.ni_vp); 102853468Smckusick if (error) 102953468Smckusick return (error); 103053468Smckusick cvtstat(&sb, &osb); 103153468Smckusick error = copyout((caddr_t)&osb, (caddr_t)uap->ub, sizeof (osb)); 103253468Smckusick return (error); 103353468Smckusick } 103453468Smckusick 103553468Smckusick /* 103653468Smckusick * Lstat system call. 103753468Smckusick * This version does not follow links. 103853468Smckusick */ 103953468Smckusick /* ARGSUSED */ 104053759Smckusick olstat(p, uap, retval) 104153468Smckusick struct proc *p; 104253468Smckusick register struct args { 104353468Smckusick char *fname; 104453468Smckusick struct ostat *ub; 104553468Smckusick } *uap; 104653468Smckusick int *retval; 104753468Smckusick { 104853468Smckusick struct stat sb; 104953468Smckusick struct ostat osb; 105053468Smckusick int error; 105153468Smckusick struct nameidata nd; 105253468Smckusick 105353468Smckusick NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 105453468Smckusick if (error = namei(&nd)) 105553468Smckusick return (error); 105653468Smckusick error = vn_stat(nd.ni_vp, &sb, p); 105753468Smckusick vput(nd.ni_vp); 105853468Smckusick if (error) 105953468Smckusick return (error); 106053468Smckusick cvtstat(&sb, &osb); 106153468Smckusick error = copyout((caddr_t)&osb, (caddr_t)uap->ub, sizeof (osb)); 106253468Smckusick return (error); 106353468Smckusick } 106453468Smckusick 106553468Smckusick /* 106653468Smckusick * convert from an old to a new stat structure. 106753468Smckusick */ 106853468Smckusick cvtstat(st, ost) 106953468Smckusick struct stat *st; 107053468Smckusick struct ostat *ost; 107153468Smckusick { 107253468Smckusick 107353468Smckusick ost->st_dev = st->st_dev; 107453468Smckusick ost->st_ino = st->st_ino; 107553468Smckusick ost->st_mode = st->st_mode; 107653468Smckusick ost->st_nlink = st->st_nlink; 107753468Smckusick ost->st_uid = st->st_uid; 107853468Smckusick ost->st_gid = st->st_gid; 107953468Smckusick ost->st_rdev = st->st_rdev; 108053468Smckusick if (st->st_size < (quad_t)1 << 32) 108153468Smckusick ost->st_size = st->st_size; 108253468Smckusick else 108353468Smckusick ost->st_size = -2; 108453468Smckusick ost->st_atime = st->st_atime; 108553468Smckusick ost->st_mtime = st->st_mtime; 108653468Smckusick ost->st_ctime = st->st_ctime; 108753468Smckusick ost->st_blksize = st->st_blksize; 108853468Smckusick ost->st_blocks = st->st_blocks; 108953468Smckusick ost->st_flags = st->st_flags; 109053468Smckusick ost->st_gen = st->st_gen; 109153468Smckusick } 109253468Smckusick #endif /* COMPAT_43 */ 109353468Smckusick 109453468Smckusick /* 109553468Smckusick * Stat system call. 109653468Smckusick * This version follows links. 109753468Smckusick */ 109853468Smckusick /* ARGSUSED */ 109953759Smckusick stat(p, uap, retval) 110053468Smckusick struct proc *p; 110153468Smckusick register struct args { 110253468Smckusick char *fname; 110342441Smckusick struct stat *ub; 110442441Smckusick } *uap; 110542441Smckusick int *retval; 110637Sbill { 110742441Smckusick struct stat sb; 110842441Smckusick int error; 110947540Skarels struct nameidata nd; 111037Sbill 111152322Smckusick NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 111252322Smckusick if (error = namei(&nd)) 111347540Skarels return (error); 111452322Smckusick error = vn_stat(nd.ni_vp, &sb, p); 111552322Smckusick vput(nd.ni_vp); 111642441Smckusick if (error) 111747540Skarels return (error); 111842441Smckusick error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb)); 111947540Skarels return (error); 112037Sbill } 112137Sbill 112237Sbill /* 112349365Smckusick * Lstat system call. 112449365Smckusick * This version does not follow links. 11255992Swnj */ 112642441Smckusick /* ARGSUSED */ 112753759Smckusick lstat(p, uap, retval) 112845914Smckusick struct proc *p; 112942441Smckusick register struct args { 11305992Swnj char *fname; 113112756Ssam struct stat *ub; 113242441Smckusick } *uap; 113342441Smckusick int *retval; 113442441Smckusick { 113512756Ssam struct stat sb; 113637741Smckusick int error; 113747540Skarels struct nameidata nd; 11385992Swnj 113952322Smckusick NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 114052322Smckusick if (error = namei(&nd)) 114147540Skarels return (error); 114252322Smckusick error = vn_stat(nd.ni_vp, &sb, p); 114352322Smckusick vput(nd.ni_vp); 114437741Smckusick if (error) 114547540Skarels return (error); 114637741Smckusick error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb)); 114747540Skarels return (error); 11485992Swnj } 11495992Swnj 11505992Swnj /* 115149365Smckusick * Return target name of a symbolic link. 115237Sbill */ 115342441Smckusick /* ARGSUSED */ 115442441Smckusick readlink(p, uap, retval) 115545914Smckusick struct proc *p; 115642441Smckusick register struct args { 11575992Swnj char *name; 11585992Swnj char *buf; 11595992Swnj int count; 116042441Smckusick } *uap; 116142441Smckusick int *retval; 116242441Smckusick { 116353548Sheideman USES_VOP_READLINK; 116437741Smckusick register struct vnode *vp; 116537741Smckusick struct iovec aiov; 116637741Smckusick struct uio auio; 116737741Smckusick int error; 116847540Skarels struct nameidata nd; 11695992Swnj 117052322Smckusick NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, uap->name, p); 117152322Smckusick if (error = namei(&nd)) 117247540Skarels return (error); 117352322Smckusick vp = nd.ni_vp; 117437741Smckusick if (vp->v_type != VLNK) { 117537741Smckusick error = EINVAL; 11765992Swnj goto out; 11775992Swnj } 117837741Smckusick aiov.iov_base = uap->buf; 117937741Smckusick aiov.iov_len = uap->count; 118037741Smckusick auio.uio_iov = &aiov; 118137741Smckusick auio.uio_iovcnt = 1; 118237741Smckusick auio.uio_offset = 0; 118337741Smckusick auio.uio_rw = UIO_READ; 118437741Smckusick auio.uio_segflg = UIO_USERSPACE; 118548026Smckusick auio.uio_procp = p; 118637741Smckusick auio.uio_resid = uap->count; 118747540Skarels error = VOP_READLINK(vp, &auio, p->p_ucred); 11885992Swnj out: 118937741Smckusick vput(vp); 119042441Smckusick *retval = uap->count - auio.uio_resid; 119147540Skarels return (error); 11925992Swnj } 11935992Swnj 11949167Ssam /* 119538259Smckusick * Change flags of a file given path name. 119638259Smckusick */ 119742441Smckusick /* ARGSUSED */ 119842441Smckusick chflags(p, uap, retval) 119945914Smckusick struct proc *p; 120042441Smckusick register struct args { 120138259Smckusick char *fname; 120238259Smckusick int flags; 120342441Smckusick } *uap; 120442441Smckusick int *retval; 120542441Smckusick { 120653548Sheideman USES_VOP_SETATTR; 120738259Smckusick register struct vnode *vp; 120838259Smckusick struct vattr vattr; 120938259Smckusick int error; 121047540Skarels struct nameidata nd; 121138259Smckusick 121252322Smckusick NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 121352322Smckusick if (error = namei(&nd)) 121447540Skarels return (error); 121552322Smckusick vp = nd.ni_vp; 121641400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 121738259Smckusick error = EROFS; 121838259Smckusick goto out; 121938259Smckusick } 122045785Sbostic VATTR_NULL(&vattr); 122145785Sbostic vattr.va_flags = uap->flags; 122252192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 122348026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 122438259Smckusick out: 122538259Smckusick vput(vp); 122647540Skarels return (error); 122738259Smckusick } 122838259Smckusick 122938259Smckusick /* 123038259Smckusick * Change flags of a file given a file descriptor. 123138259Smckusick */ 123242441Smckusick /* ARGSUSED */ 123342441Smckusick fchflags(p, uap, retval) 123445914Smckusick struct proc *p; 123542441Smckusick register struct args { 123638259Smckusick int fd; 123738259Smckusick int flags; 123842441Smckusick } *uap; 123942441Smckusick int *retval; 124042441Smckusick { 124153548Sheideman USES_VOP_LOCK; 124253548Sheideman USES_VOP_SETATTR; 124353548Sheideman USES_VOP_UNLOCK; 124438259Smckusick struct vattr vattr; 124538259Smckusick struct vnode *vp; 124638259Smckusick struct file *fp; 124738259Smckusick int error; 124838259Smckusick 124945914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 125047540Skarels return (error); 125138259Smckusick vp = (struct vnode *)fp->f_data; 125238259Smckusick VOP_LOCK(vp); 125341400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 125438259Smckusick error = EROFS; 125538259Smckusick goto out; 125638259Smckusick } 125745785Sbostic VATTR_NULL(&vattr); 125845785Sbostic vattr.va_flags = uap->flags; 125952192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 126048026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 126138259Smckusick out: 126238259Smckusick VOP_UNLOCK(vp); 126347540Skarels return (error); 126438259Smckusick } 126538259Smckusick 126638259Smckusick /* 12679167Ssam * Change mode of a file given path name. 12689167Ssam */ 126942441Smckusick /* ARGSUSED */ 127042441Smckusick chmod(p, uap, retval) 127145914Smckusick struct proc *p; 127242441Smckusick register struct args { 12736254Sroot char *fname; 12746254Sroot int fmode; 127542441Smckusick } *uap; 127642441Smckusick int *retval; 127742441Smckusick { 127853548Sheideman USES_VOP_SETATTR; 127937741Smckusick register struct vnode *vp; 128037741Smckusick struct vattr vattr; 128137741Smckusick int error; 128247540Skarels struct nameidata nd; 12835992Swnj 128452322Smckusick NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 128552322Smckusick if (error = namei(&nd)) 128647540Skarels return (error); 128752322Smckusick vp = nd.ni_vp; 128841400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 128937741Smckusick error = EROFS; 129037741Smckusick goto out; 129137741Smckusick } 129245785Sbostic VATTR_NULL(&vattr); 129345785Sbostic vattr.va_mode = uap->fmode & 07777; 129452192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 129548026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 129637741Smckusick out: 129737741Smckusick vput(vp); 129847540Skarels return (error); 12997701Ssam } 13007439Sroot 13019167Ssam /* 13029167Ssam * Change mode of a file given a file descriptor. 13039167Ssam */ 130442441Smckusick /* ARGSUSED */ 130542441Smckusick fchmod(p, uap, retval) 130645914Smckusick struct proc *p; 130742441Smckusick register struct args { 13087701Ssam int fd; 13097701Ssam int fmode; 131042441Smckusick } *uap; 131142441Smckusick int *retval; 131242441Smckusick { 131353548Sheideman USES_VOP_LOCK; 131453548Sheideman USES_VOP_SETATTR; 131553548Sheideman USES_VOP_UNLOCK; 131637741Smckusick struct vattr vattr; 131737741Smckusick struct vnode *vp; 131837741Smckusick struct file *fp; 131937741Smckusick int error; 13207701Ssam 132145914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 132247540Skarels return (error); 132337741Smckusick vp = (struct vnode *)fp->f_data; 132437741Smckusick VOP_LOCK(vp); 132541400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 132637741Smckusick error = EROFS; 132737741Smckusick goto out; 13287439Sroot } 132945785Sbostic VATTR_NULL(&vattr); 133045785Sbostic vattr.va_mode = uap->fmode & 07777; 133152192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 133248026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 133337741Smckusick out: 133437741Smckusick VOP_UNLOCK(vp); 133547540Skarels return (error); 13365992Swnj } 13375992Swnj 13389167Ssam /* 13399167Ssam * Set ownership given a path name. 13409167Ssam */ 134142441Smckusick /* ARGSUSED */ 134242441Smckusick chown(p, uap, retval) 134345914Smckusick struct proc *p; 134442441Smckusick register struct args { 13456254Sroot char *fname; 13466254Sroot int uid; 13476254Sroot int gid; 134842441Smckusick } *uap; 134942441Smckusick int *retval; 135042441Smckusick { 135153548Sheideman USES_VOP_SETATTR; 135237741Smckusick register struct vnode *vp; 135337741Smckusick struct vattr vattr; 135437741Smckusick int error; 135547540Skarels struct nameidata nd; 135637Sbill 135752322Smckusick NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 135852322Smckusick if (error = namei(&nd)) 135947540Skarels return (error); 136052322Smckusick vp = nd.ni_vp; 136141400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 136237741Smckusick error = EROFS; 136337741Smckusick goto out; 136437741Smckusick } 136545785Sbostic VATTR_NULL(&vattr); 136645785Sbostic vattr.va_uid = uap->uid; 136745785Sbostic vattr.va_gid = uap->gid; 136852192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 136948026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 137037741Smckusick out: 137137741Smckusick vput(vp); 137247540Skarels return (error); 13737701Ssam } 13747439Sroot 13759167Ssam /* 13769167Ssam * Set ownership given a file descriptor. 13779167Ssam */ 137842441Smckusick /* ARGSUSED */ 137942441Smckusick fchown(p, uap, retval) 138045914Smckusick struct proc *p; 138142441Smckusick register struct args { 13827701Ssam int fd; 13837701Ssam int uid; 13847701Ssam int gid; 138542441Smckusick } *uap; 138642441Smckusick int *retval; 138742441Smckusick { 138853548Sheideman USES_VOP_LOCK; 138953548Sheideman USES_VOP_SETATTR; 139053548Sheideman USES_VOP_UNLOCK; 139137741Smckusick struct vattr vattr; 139237741Smckusick struct vnode *vp; 139337741Smckusick struct file *fp; 139437741Smckusick int error; 13957701Ssam 139645914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 139747540Skarels return (error); 139837741Smckusick vp = (struct vnode *)fp->f_data; 139937741Smckusick VOP_LOCK(vp); 140041400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 140137741Smckusick error = EROFS; 140237741Smckusick goto out; 140337741Smckusick } 140445785Sbostic VATTR_NULL(&vattr); 140545785Sbostic vattr.va_uid = uap->uid; 140645785Sbostic vattr.va_gid = uap->gid; 140752192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 140848026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 140937741Smckusick out: 141037741Smckusick VOP_UNLOCK(vp); 141147540Skarels return (error); 14127701Ssam } 14137701Ssam 141442441Smckusick /* 141542441Smckusick * Set the access and modification times of a file. 141642441Smckusick */ 141742441Smckusick /* ARGSUSED */ 141842441Smckusick utimes(p, uap, retval) 141945914Smckusick struct proc *p; 142042441Smckusick register struct args { 142111811Ssam char *fname; 142211811Ssam struct timeval *tptr; 142342441Smckusick } *uap; 142442441Smckusick int *retval; 142542441Smckusick { 142653548Sheideman USES_VOP_SETATTR; 142737741Smckusick register struct vnode *vp; 142811811Ssam struct timeval tv[2]; 142937741Smckusick struct vattr vattr; 143037741Smckusick int error; 143147540Skarels struct nameidata nd; 143211811Ssam 143337741Smckusick if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv))) 143447540Skarels return (error); 143552322Smckusick NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 143652322Smckusick if (error = namei(&nd)) 143747540Skarels return (error); 143852322Smckusick vp = nd.ni_vp; 143941400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 144037741Smckusick error = EROFS; 144137741Smckusick goto out; 144221015Smckusick } 144345785Sbostic VATTR_NULL(&vattr); 1444*54100Smckusick vattr.va_atime.ts_sec = tv[0].tv_sec; 1445*54100Smckusick vattr.va_atime.ts_nsec = tv[0].tv_usec * 1000; 1446*54100Smckusick vattr.va_mtime.ts_sec = tv[1].tv_sec; 1447*54100Smckusick vattr.va_mtime.ts_nsec = tv[1].tv_usec * 1000; 144852192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 144948026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 145037741Smckusick out: 145137741Smckusick vput(vp); 145247540Skarels return (error); 145311811Ssam } 145411811Ssam 145553468Smckusick #ifdef COMPAT_43 14569167Ssam /* 14579167Ssam * Truncate a file given its path name. 14589167Ssam */ 145942441Smckusick /* ARGSUSED */ 146042441Smckusick truncate(p, uap, retval) 146145914Smckusick struct proc *p; 146242441Smckusick register struct args { 14637701Ssam char *fname; 146453468Smckusick long length; 146553468Smckusick } *uap; 146653468Smckusick int *retval; 146753468Smckusick { 146853468Smckusick struct nargs { 146953468Smckusick char *fname; 147026473Skarels off_t length; 147153468Smckusick } nuap; 147253468Smckusick 147353468Smckusick nuap.fname = uap->fname; 147453468Smckusick nuap.length = uap->length; 147553759Smckusick return (__truncate(p, &nuap, retval)); 147653468Smckusick } 147753468Smckusick 147853468Smckusick /* 147953468Smckusick * Truncate a file given a file descriptor. 148053468Smckusick */ 148153468Smckusick /* ARGSUSED */ 148253468Smckusick ftruncate(p, uap, retval) 148353468Smckusick struct proc *p; 148453468Smckusick register struct args { 148553468Smckusick int fd; 148653468Smckusick long length; 148742441Smckusick } *uap; 148842441Smckusick int *retval; 148942441Smckusick { 149053468Smckusick struct nargs { 149153468Smckusick int fd; 149253468Smckusick off_t length; 149353468Smckusick } nuap; 149453468Smckusick 149553468Smckusick nuap.fd = uap->fd; 149653468Smckusick nuap.length = uap->length; 149753759Smckusick return (__ftruncate(p, &nuap, retval)); 149853468Smckusick } 149953468Smckusick #endif /* COMPAT_43 */ 150053468Smckusick 150153468Smckusick /* 150253468Smckusick * Truncate a file given its path name. 150353468Smckusick */ 150453468Smckusick /* ARGSUSED */ 150553759Smckusick __truncate(p, uap, retval) 150653468Smckusick struct proc *p; 150753468Smckusick register struct args { 150853468Smckusick char *fname; 150953468Smckusick off_t length; 151053468Smckusick } *uap; 151153468Smckusick int *retval; 151253468Smckusick { 151353548Sheideman USES_VOP_ACCESS; 151453548Sheideman USES_VOP_SETATTR; 151537741Smckusick register struct vnode *vp; 151637741Smckusick struct vattr vattr; 151737741Smckusick int error; 151847540Skarels struct nameidata nd; 15197701Ssam 152052322Smckusick NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 152152322Smckusick if (error = namei(&nd)) 152247540Skarels return (error); 152352322Smckusick vp = nd.ni_vp; 152437741Smckusick if (vp->v_type == VDIR) { 152537741Smckusick error = EISDIR; 152637741Smckusick goto out; 15277701Ssam } 152838399Smckusick if ((error = vn_writechk(vp)) || 152948026Smckusick (error = VOP_ACCESS(vp, VWRITE, p->p_ucred, p))) 153037741Smckusick goto out; 153145785Sbostic VATTR_NULL(&vattr); 153245785Sbostic vattr.va_size = uap->length; 153352192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 153448026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 153537741Smckusick out: 153637741Smckusick vput(vp); 153747540Skarels return (error); 15387701Ssam } 15397701Ssam 15409167Ssam /* 15419167Ssam * Truncate a file given a file descriptor. 15429167Ssam */ 154342441Smckusick /* ARGSUSED */ 154453759Smckusick __ftruncate(p, uap, retval) 154545914Smckusick struct proc *p; 154642441Smckusick register struct args { 15477701Ssam int fd; 154826473Skarels off_t length; 154942441Smckusick } *uap; 155042441Smckusick int *retval; 155142441Smckusick { 155253548Sheideman USES_VOP_LOCK; 155353548Sheideman USES_VOP_SETATTR; 155453548Sheideman USES_VOP_UNLOCK; 155537741Smckusick struct vattr vattr; 155637741Smckusick struct vnode *vp; 15577701Ssam struct file *fp; 155837741Smckusick int error; 15597701Ssam 156045914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 156147540Skarels return (error); 156237741Smckusick if ((fp->f_flag & FWRITE) == 0) 156347540Skarels return (EINVAL); 156437741Smckusick vp = (struct vnode *)fp->f_data; 156537741Smckusick VOP_LOCK(vp); 156637741Smckusick if (vp->v_type == VDIR) { 156737741Smckusick error = EISDIR; 156837741Smckusick goto out; 15697701Ssam } 157038399Smckusick if (error = vn_writechk(vp)) 157137741Smckusick goto out; 157245785Sbostic VATTR_NULL(&vattr); 157345785Sbostic vattr.va_size = uap->length; 157452192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 157548026Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred, p); 157637741Smckusick out: 157737741Smckusick VOP_UNLOCK(vp); 157847540Skarels return (error); 15797701Ssam } 15807701Ssam 15819167Ssam /* 15829167Ssam * Synch an open file. 15839167Ssam */ 158442441Smckusick /* ARGSUSED */ 158542441Smckusick fsync(p, uap, retval) 158645914Smckusick struct proc *p; 158742441Smckusick struct args { 158842441Smckusick int fd; 158942441Smckusick } *uap; 159042441Smckusick int *retval; 15919167Ssam { 159253548Sheideman USES_VOP_FSYNC; 159353548Sheideman USES_VOP_LOCK; 159453548Sheideman USES_VOP_UNLOCK; 159539592Smckusick register struct vnode *vp; 15969167Ssam struct file *fp; 159737741Smckusick int error; 15989167Ssam 159945914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 160047540Skarels return (error); 160139592Smckusick vp = (struct vnode *)fp->f_data; 160239592Smckusick VOP_LOCK(vp); 160348026Smckusick error = VOP_FSYNC(vp, fp->f_flag, fp->f_cred, MNT_WAIT, p); 160439592Smckusick VOP_UNLOCK(vp); 160547540Skarels return (error); 16069167Ssam } 16079167Ssam 16089167Ssam /* 16099167Ssam * Rename system call. 16109167Ssam * 16119167Ssam * Source and destination must either both be directories, or both 16129167Ssam * not be directories. If target is a directory, it must be empty. 16139167Ssam */ 161442441Smckusick /* ARGSUSED */ 161542441Smckusick rename(p, uap, retval) 161645914Smckusick struct proc *p; 161742441Smckusick register struct args { 16187701Ssam char *from; 16197701Ssam char *to; 162042441Smckusick } *uap; 162142441Smckusick int *retval; 162242441Smckusick { 162353548Sheideman USES_VOP_ABORTOP; 162453548Sheideman USES_VOP_RENAME; 162537741Smckusick register struct vnode *tvp, *fvp, *tdvp; 162649735Smckusick struct nameidata fromnd, tond; 162737741Smckusick int error; 16287701Ssam 162952322Smckusick NDINIT(&fromnd, DELETE, WANTPARENT | SAVESTART, UIO_USERSPACE, 163052322Smckusick uap->from, p); 163152322Smckusick if (error = namei(&fromnd)) 163247540Skarels return (error); 163349735Smckusick fvp = fromnd.ni_vp; 163452322Smckusick NDINIT(&tond, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART, 163552322Smckusick UIO_USERSPACE, uap->to, p); 163652322Smckusick if (error = namei(&tond)) { 163752230Sheideman VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 163849735Smckusick vrele(fromnd.ni_dvp); 163942465Smckusick vrele(fvp); 164042465Smckusick goto out1; 164142465Smckusick } 164237741Smckusick tdvp = tond.ni_dvp; 164337741Smckusick tvp = tond.ni_vp; 164437741Smckusick if (tvp != NULL) { 164537741Smckusick if (fvp->v_type == VDIR && tvp->v_type != VDIR) { 164639242Sbostic error = ENOTDIR; 164737741Smckusick goto out; 164837741Smckusick } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) { 164939242Sbostic error = EISDIR; 165037741Smckusick goto out; 16519167Ssam } 16529167Ssam } 165339286Smckusick if (fvp == tdvp) 165437741Smckusick error = EINVAL; 165539286Smckusick /* 165649735Smckusick * If source is the same as the destination (that is the 165749735Smckusick * same inode number with the same name in the same directory), 165839286Smckusick * then there is nothing to do. 165939286Smckusick */ 166049735Smckusick if (fvp == tvp && fromnd.ni_dvp == tdvp && 166152322Smckusick fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen && 166252322Smckusick !bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr, 166352322Smckusick fromnd.ni_cnd.cn_namelen)) 166439286Smckusick error = -1; 166537741Smckusick out: 166642465Smckusick if (!error) { 166752192Smckusick LEASE_CHECK(tdvp, p, p->p_ucred, LEASE_WRITE); 166852192Smckusick if (fromnd.ni_dvp != tdvp) 166952192Smckusick LEASE_CHECK(fromnd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 167052192Smckusick if (tvp) 167152192Smckusick LEASE_CHECK(tvp, p, p->p_ucred, LEASE_WRITE); 167252230Sheideman error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd, 167352230Sheideman tond.ni_dvp, tond.ni_vp, &tond.ni_cnd); 167442465Smckusick } else { 167552230Sheideman VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd); 167643344Smckusick if (tdvp == tvp) 167743344Smckusick vrele(tdvp); 167843344Smckusick else 167943344Smckusick vput(tdvp); 168042465Smckusick if (tvp) 168142465Smckusick vput(tvp); 168252230Sheideman VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 168349735Smckusick vrele(fromnd.ni_dvp); 168442465Smckusick vrele(fvp); 16859167Ssam } 168649735Smckusick vrele(tond.ni_startdir); 168752322Smckusick FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI); 168837741Smckusick out1: 168949735Smckusick vrele(fromnd.ni_startdir); 169052322Smckusick FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI); 169139286Smckusick if (error == -1) 169247540Skarels return (0); 169347540Skarels return (error); 16947701Ssam } 16957701Ssam 16967535Sroot /* 169749365Smckusick * Mkdir system call. 169812756Ssam */ 169942441Smckusick /* ARGSUSED */ 170042441Smckusick mkdir(p, uap, retval) 170145914Smckusick struct proc *p; 170242441Smckusick register struct args { 170312756Ssam char *name; 170412756Ssam int dmode; 170542441Smckusick } *uap; 170642441Smckusick int *retval; 170742441Smckusick { 170853548Sheideman USES_VOP_ABORTOP; 170953548Sheideman USES_VOP_MKDIR; 171037741Smckusick register struct vnode *vp; 171137741Smckusick struct vattr vattr; 171237741Smckusick int error; 171347540Skarels struct nameidata nd; 171412756Ssam 171552322Smckusick NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->name, p); 171652322Smckusick if (error = namei(&nd)) 171747540Skarels return (error); 171852322Smckusick vp = nd.ni_vp; 171937741Smckusick if (vp != NULL) { 172052322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 172152322Smckusick if (nd.ni_dvp == vp) 172252322Smckusick vrele(nd.ni_dvp); 172343344Smckusick else 172452322Smckusick vput(nd.ni_dvp); 172542465Smckusick vrele(vp); 172647540Skarels return (EEXIST); 172712756Ssam } 172841362Smckusick VATTR_NULL(&vattr); 172937741Smckusick vattr.va_type = VDIR; 173045914Smckusick vattr.va_mode = (uap->dmode & 0777) &~ p->p_fd->fd_cmask; 173152322Smckusick LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 173252322Smckusick error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr); 173338145Smckusick if (!error) 173452322Smckusick vput(nd.ni_vp); 173547540Skarels return (error); 173612756Ssam } 173712756Ssam 173812756Ssam /* 173912756Ssam * Rmdir system call. 174012756Ssam */ 174142441Smckusick /* ARGSUSED */ 174242441Smckusick rmdir(p, uap, retval) 174345914Smckusick struct proc *p; 174442441Smckusick struct args { 174542441Smckusick char *name; 174642441Smckusick } *uap; 174742441Smckusick int *retval; 174812756Ssam { 174953548Sheideman USES_VOP_ABORTOP; 175053548Sheideman USES_VOP_RMDIR; 175137741Smckusick register struct vnode *vp; 175237741Smckusick int error; 175347540Skarels struct nameidata nd; 175412756Ssam 175552322Smckusick NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE, uap->name, p); 175652322Smckusick if (error = namei(&nd)) 175747540Skarels return (error); 175852322Smckusick vp = nd.ni_vp; 175937741Smckusick if (vp->v_type != VDIR) { 176037741Smckusick error = ENOTDIR; 176112756Ssam goto out; 176212756Ssam } 176312756Ssam /* 176437741Smckusick * No rmdir "." please. 176512756Ssam */ 176652322Smckusick if (nd.ni_dvp == vp) { 176737741Smckusick error = EINVAL; 176812756Ssam goto out; 176912756Ssam } 177012756Ssam /* 177149365Smckusick * The root of a mounted filesystem cannot be deleted. 177212756Ssam */ 177337741Smckusick if (vp->v_flag & VROOT) 177437741Smckusick error = EBUSY; 177512756Ssam out: 177642465Smckusick if (!error) { 177752322Smckusick LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 177852192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 177952322Smckusick error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); 178042465Smckusick } else { 178152322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 178252322Smckusick if (nd.ni_dvp == vp) 178352322Smckusick vrele(nd.ni_dvp); 178443344Smckusick else 178552322Smckusick vput(nd.ni_dvp); 178642465Smckusick vput(vp); 178742465Smckusick } 178847540Skarels return (error); 178912756Ssam } 179012756Ssam 179137741Smckusick /* 179249365Smckusick * Read a block of directory entries in a file system independent format. 179337741Smckusick */ 179442441Smckusick getdirentries(p, uap, retval) 179545914Smckusick struct proc *p; 179642441Smckusick register struct args { 179737741Smckusick int fd; 179837741Smckusick char *buf; 179937741Smckusick unsigned count; 180037741Smckusick long *basep; 180142441Smckusick } *uap; 180242441Smckusick int *retval; 180342441Smckusick { 180453548Sheideman USES_VOP_LOCK; 180553548Sheideman USES_VOP_READDIR; 180653548Sheideman USES_VOP_UNLOCK; 180739592Smckusick register struct vnode *vp; 180816540Ssam struct file *fp; 180937741Smckusick struct uio auio; 181037741Smckusick struct iovec aiov; 181138129Smckusick off_t off; 181240321Smckusick int error, eofflag; 181312756Ssam 181445914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 181547540Skarels return (error); 181637741Smckusick if ((fp->f_flag & FREAD) == 0) 181747540Skarels return (EBADF); 181839592Smckusick vp = (struct vnode *)fp->f_data; 181939592Smckusick if (vp->v_type != VDIR) 182047540Skarels return (EINVAL); 182137741Smckusick aiov.iov_base = uap->buf; 182237741Smckusick aiov.iov_len = uap->count; 182337741Smckusick auio.uio_iov = &aiov; 182437741Smckusick auio.uio_iovcnt = 1; 182537741Smckusick auio.uio_rw = UIO_READ; 182637741Smckusick auio.uio_segflg = UIO_USERSPACE; 182748026Smckusick auio.uio_procp = p; 182837741Smckusick auio.uio_resid = uap->count; 182939592Smckusick VOP_LOCK(vp); 183039592Smckusick auio.uio_offset = off = fp->f_offset; 183140321Smckusick error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag); 183239592Smckusick fp->f_offset = auio.uio_offset; 183339592Smckusick VOP_UNLOCK(vp); 183439592Smckusick if (error) 183547540Skarels return (error); 183639592Smckusick error = copyout((caddr_t)&off, (caddr_t)uap->basep, sizeof(long)); 183742441Smckusick *retval = uap->count - auio.uio_resid; 183847540Skarels return (error); 183912756Ssam } 184012756Ssam 184112756Ssam /* 184249365Smckusick * Set the mode mask for creation of filesystem nodes. 184312756Ssam */ 184442441Smckusick mode_t 184542441Smckusick umask(p, uap, retval) 184645914Smckusick struct proc *p; 184742441Smckusick struct args { 184842441Smckusick int mask; 184942441Smckusick } *uap; 185042441Smckusick int *retval; 185112756Ssam { 185245914Smckusick register struct filedesc *fdp = p->p_fd; 185312756Ssam 185445914Smckusick *retval = fdp->fd_cmask; 185545914Smckusick fdp->fd_cmask = uap->mask & 07777; 185647540Skarels return (0); 185712756Ssam } 185837741Smckusick 185939566Smarc /* 186039566Smarc * Void all references to file by ripping underlying filesystem 186139566Smarc * away from vnode. 186239566Smarc */ 186342441Smckusick /* ARGSUSED */ 186442441Smckusick revoke(p, uap, retval) 186545914Smckusick struct proc *p; 186642441Smckusick register struct args { 186739566Smarc char *fname; 186842441Smckusick } *uap; 186942441Smckusick int *retval; 187042441Smckusick { 187153548Sheideman USES_VOP_GETATTR; 187239566Smarc register struct vnode *vp; 187339566Smarc struct vattr vattr; 187439566Smarc int error; 187547540Skarels struct nameidata nd; 187639566Smarc 187752322Smckusick NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->fname, p); 187852322Smckusick if (error = namei(&nd)) 187947540Skarels return (error); 188052322Smckusick vp = nd.ni_vp; 188139566Smarc if (vp->v_type != VCHR && vp->v_type != VBLK) { 188239566Smarc error = EINVAL; 188339566Smarc goto out; 188439566Smarc } 188548026Smckusick if (error = VOP_GETATTR(vp, &vattr, p->p_ucred, p)) 188639566Smarc goto out; 188747540Skarels if (p->p_ucred->cr_uid != vattr.va_uid && 188847540Skarels (error = suser(p->p_ucred, &p->p_acflag))) 188939566Smarc goto out; 189039805Smckusick if (vp->v_usecount > 1 || (vp->v_flag & VALIASED)) 189139632Smckusick vgoneall(vp); 189239566Smarc out: 189339566Smarc vrele(vp); 189447540Skarels return (error); 189539566Smarc } 189639566Smarc 189749365Smckusick /* 189849365Smckusick * Convert a user file descriptor to a kernel file entry. 189949365Smckusick */ 190045914Smckusick getvnode(fdp, fdes, fpp) 190145914Smckusick struct filedesc *fdp; 190237741Smckusick struct file **fpp; 190337741Smckusick int fdes; 190437741Smckusick { 190537741Smckusick struct file *fp; 190637741Smckusick 190747540Skarels if ((unsigned)fdes >= fdp->fd_nfiles || 190847688Skarels (fp = fdp->fd_ofiles[fdes]) == NULL) 190937741Smckusick return (EBADF); 191037741Smckusick if (fp->f_type != DTYPE_VNODE) 191137741Smckusick return (EINVAL); 191237741Smckusick *fpp = fp; 191337741Smckusick return (0); 191437741Smckusick } 1915