123405Smckusick /* 237741Smckusick * Copyright (c) 1989 The Regents of the University of California. 337741Smckusick * All rights reserved. 423405Smckusick * 544459Sbostic * %sccs.include.redist.c% 637741Smckusick * 7*54441Smckusick * @(#)vfs_syscalls.c 7.88 (Berkeley) 06/25/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 } 8039805Smckusick if (vp->v_usecount != 1) { 8137741Smckusick vput(vp); 8247540Skarels return (EBUSY); 8337741Smckusick } 84*54441Smckusick if (error = vinvalbuf(vp, 1, p->p_ucred, p)) 85*54441Smckusick return (error); 8637741Smckusick if (vp->v_type != VDIR) { 8737741Smckusick vput(vp); 8847540Skarels return (ENOTDIR); 8937741Smckusick } 9039741Smckusick if ((unsigned long)uap->type > MOUNT_MAXTYPE || 9137741Smckusick vfssw[uap->type] == (struct vfsops *)0) { 9237741Smckusick vput(vp); 9347540Skarels return (ENODEV); 9437741Smckusick } 9537741Smckusick 9637741Smckusick /* 9739335Smckusick * Allocate and initialize the file system. 9837741Smckusick */ 9937741Smckusick mp = (struct mount *)malloc((u_long)sizeof(struct mount), 10037741Smckusick M_MOUNT, M_WAITOK); 10154172Smckusick bzero((char *)mp, (u_long)sizeof(struct mount)); 10241400Smckusick mp->mnt_op = vfssw[uap->type]; 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 */ 233*54441Smckusick if ((error = VFS_SYNC(mp, MNT_WAIT, p->p_ucred, p)) == 0 || 234*54441Smckusick (flags & MNT_FORCE)) 23548026Smckusick error = VFS_UNMOUNT(mp, flags, p); 23641400Smckusick mp->mnt_flag &= ~MNT_UNMOUNT; 23741298Smckusick vfs_unbusy(mp); 23837741Smckusick if (error) { 23937741Smckusick vfs_unlock(mp); 24037741Smckusick } else { 24137741Smckusick vrele(coveredvp); 24237741Smckusick vfs_remove(mp); 24352287Smckusick if (mp->mnt_mounth != NULL) 24452287Smckusick panic("unmount: dangling vnode"); 24537741Smckusick free((caddr_t)mp, M_MOUNT); 24637741Smckusick } 24739356Smckusick return (error); 2486254Sroot } 2496254Sroot 2509167Ssam /* 25137741Smckusick * Sync system call. 25237741Smckusick * Sync each mounted filesystem. 2539167Ssam */ 25439491Smckusick /* ARGSUSED */ 25542441Smckusick sync(p, uap, retval) 25645914Smckusick struct proc *p; 25747540Skarels void *uap; 25842441Smckusick int *retval; 2596254Sroot { 26037741Smckusick register struct mount *mp; 26141298Smckusick struct mount *omp; 26237741Smckusick 26337741Smckusick mp = rootfs; 26437741Smckusick do { 26540343Smckusick /* 26640343Smckusick * The lock check below is to avoid races with mount 26740343Smckusick * and unmount. 26840343Smckusick */ 26941400Smckusick if ((mp->mnt_flag & (MNT_MLOCK|MNT_RDONLY|MNT_MPBUSY)) == 0 && 27041298Smckusick !vfs_busy(mp)) { 271*54441Smckusick VFS_SYNC(mp, MNT_NOWAIT, p->p_ucred, p); 27241298Smckusick omp = mp; 27341400Smckusick mp = mp->mnt_next; 27441298Smckusick vfs_unbusy(omp); 27541298Smckusick } else 27641400Smckusick mp = mp->mnt_next; 27737741Smckusick } while (mp != rootfs); 27847688Skarels return (0); 27937741Smckusick } 28037741Smckusick 28137741Smckusick /* 28249365Smckusick * Operate on filesystem quotas. 28341298Smckusick */ 28442441Smckusick /* ARGSUSED */ 28542441Smckusick quotactl(p, uap, retval) 28645914Smckusick struct proc *p; 28742441Smckusick register struct args { 28841298Smckusick char *path; 28941298Smckusick int cmd; 29041298Smckusick int uid; 29141298Smckusick caddr_t arg; 29242441Smckusick } *uap; 29342441Smckusick int *retval; 29442441Smckusick { 29541298Smckusick register struct mount *mp; 29641298Smckusick int error; 29747540Skarels struct nameidata nd; 29841298Smckusick 29952322Smckusick NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); 30052322Smckusick if (error = namei(&nd)) 30147540Skarels return (error); 30252322Smckusick mp = nd.ni_vp->v_mount; 30352322Smckusick vrele(nd.ni_vp); 30448026Smckusick return (VFS_QUOTACTL(mp, uap->cmd, uap->uid, uap->arg, p)); 30541298Smckusick } 30641298Smckusick 30741298Smckusick /* 30849365Smckusick * Get filesystem statistics. 30937741Smckusick */ 31042441Smckusick /* ARGSUSED */ 31142441Smckusick statfs(p, uap, retval) 31245914Smckusick struct proc *p; 31342441Smckusick register struct args { 31437741Smckusick char *path; 31537741Smckusick struct statfs *buf; 31642441Smckusick } *uap; 31742441Smckusick int *retval; 31842441Smckusick { 31939464Smckusick register struct mount *mp; 32040343Smckusick register struct statfs *sp; 32137741Smckusick int error; 32247540Skarels struct nameidata nd; 32337741Smckusick 32452322Smckusick NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); 32552322Smckusick if (error = namei(&nd)) 32647540Skarels return (error); 32752322Smckusick mp = nd.ni_vp->v_mount; 32841400Smckusick sp = &mp->mnt_stat; 32952322Smckusick vrele(nd.ni_vp); 33048026Smckusick if (error = VFS_STATFS(mp, sp, p)) 33147540Skarels return (error); 33241400Smckusick sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 33347540Skarels return (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp))); 33437741Smckusick } 33537741Smckusick 33642441Smckusick /* 33749365Smckusick * Get filesystem statistics. 33842441Smckusick */ 33942441Smckusick /* ARGSUSED */ 34042441Smckusick fstatfs(p, uap, retval) 34145914Smckusick struct proc *p; 34242441Smckusick register struct args { 34337741Smckusick int fd; 34437741Smckusick struct statfs *buf; 34542441Smckusick } *uap; 34642441Smckusick int *retval; 34742441Smckusick { 34837741Smckusick struct file *fp; 34939464Smckusick struct mount *mp; 35040343Smckusick register struct statfs *sp; 35137741Smckusick int error; 35237741Smckusick 35345914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 35447540Skarels return (error); 35539464Smckusick mp = ((struct vnode *)fp->f_data)->v_mount; 35641400Smckusick sp = &mp->mnt_stat; 35748026Smckusick if (error = VFS_STATFS(mp, sp, p)) 35847540Skarels return (error); 35941400Smckusick sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 36047540Skarels return (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp))); 36137741Smckusick } 36237741Smckusick 36337741Smckusick /* 36449365Smckusick * Get statistics on all filesystems. 36538270Smckusick */ 36642441Smckusick getfsstat(p, uap, retval) 36745914Smckusick struct proc *p; 36842441Smckusick register struct args { 36938270Smckusick struct statfs *buf; 37038270Smckusick long bufsize; 37140343Smckusick int flags; 37242441Smckusick } *uap; 37342441Smckusick int *retval; 37442441Smckusick { 37538270Smckusick register struct mount *mp; 37640343Smckusick register struct statfs *sp; 37739606Smckusick caddr_t sfsp; 37838270Smckusick long count, maxcount, error; 37938270Smckusick 38038270Smckusick maxcount = uap->bufsize / sizeof(struct statfs); 38139606Smckusick sfsp = (caddr_t)uap->buf; 38238270Smckusick mp = rootfs; 38338270Smckusick count = 0; 38438270Smckusick do { 38541400Smckusick if (sfsp && count < maxcount && 38641400Smckusick ((mp->mnt_flag & MNT_MLOCK) == 0)) { 38741400Smckusick sp = &mp->mnt_stat; 38840343Smckusick /* 38940343Smckusick * If MNT_NOWAIT is specified, do not refresh the 39040343Smckusick * fsstat cache. MNT_WAIT overrides MNT_NOWAIT. 39140343Smckusick */ 39240343Smckusick if (((uap->flags & MNT_NOWAIT) == 0 || 39340343Smckusick (uap->flags & MNT_WAIT)) && 39448026Smckusick (error = VFS_STATFS(mp, sp, p))) { 39541400Smckusick mp = mp->mnt_prev; 39639607Smckusick continue; 39739607Smckusick } 39841400Smckusick sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 39940343Smckusick if (error = copyout((caddr_t)sp, sfsp, sizeof(*sp))) 40047540Skarels return (error); 40140343Smckusick sfsp += sizeof(*sp); 40238270Smckusick } 40339606Smckusick count++; 40441400Smckusick mp = mp->mnt_prev; 40538270Smckusick } while (mp != rootfs); 40638270Smckusick if (sfsp && count > maxcount) 40742441Smckusick *retval = maxcount; 40838270Smckusick else 40942441Smckusick *retval = count; 41047540Skarels return (0); 41138270Smckusick } 41238270Smckusick 41338270Smckusick /* 41438259Smckusick * Change current working directory to a given file descriptor. 41538259Smckusick */ 41642441Smckusick /* ARGSUSED */ 41742441Smckusick fchdir(p, uap, retval) 41845914Smckusick struct proc *p; 41942441Smckusick struct args { 42042441Smckusick int fd; 42142441Smckusick } *uap; 42242441Smckusick int *retval; 42338259Smckusick { 42453548Sheideman USES_VOP_ACCESS; 42553548Sheideman USES_VOP_LOCK; 42653548Sheideman USES_VOP_UNLOCK; 42745914Smckusick register struct filedesc *fdp = p->p_fd; 42838259Smckusick register struct vnode *vp; 42938259Smckusick struct file *fp; 43038259Smckusick int error; 43138259Smckusick 43245914Smckusick if (error = getvnode(fdp, uap->fd, &fp)) 43347540Skarels return (error); 43438259Smckusick vp = (struct vnode *)fp->f_data; 43538259Smckusick VOP_LOCK(vp); 43638259Smckusick if (vp->v_type != VDIR) 43738259Smckusick error = ENOTDIR; 43838259Smckusick else 43948026Smckusick error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p); 44038259Smckusick VOP_UNLOCK(vp); 44139860Smckusick if (error) 44247540Skarels return (error); 44339860Smckusick VREF(vp); 44445914Smckusick vrele(fdp->fd_cdir); 44545914Smckusick fdp->fd_cdir = vp; 44647540Skarels return (0); 44738259Smckusick } 44838259Smckusick 44938259Smckusick /* 45037741Smckusick * Change current working directory (``.''). 45137741Smckusick */ 45242441Smckusick /* ARGSUSED */ 45342441Smckusick chdir(p, uap, retval) 45445914Smckusick struct proc *p; 45542441Smckusick struct args { 45642441Smckusick char *fname; 45742441Smckusick } *uap; 45842441Smckusick int *retval; 45937741Smckusick { 46045914Smckusick register struct filedesc *fdp = p->p_fd; 46137741Smckusick int error; 46247540Skarels struct nameidata nd; 4636254Sroot 46452322Smckusick NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 46552781Sralph if (error = chdirec(&nd, p)) 46647540Skarels return (error); 46745914Smckusick vrele(fdp->fd_cdir); 46852322Smckusick fdp->fd_cdir = nd.ni_vp; 46947540Skarels return (0); 47037741Smckusick } 4716254Sroot 47237741Smckusick /* 47337741Smckusick * Change notion of root (``/'') directory. 47437741Smckusick */ 47542441Smckusick /* ARGSUSED */ 47642441Smckusick chroot(p, uap, retval) 47745914Smckusick struct proc *p; 47842441Smckusick struct args { 47942441Smckusick char *fname; 48042441Smckusick } *uap; 48142441Smckusick int *retval; 48237741Smckusick { 48345914Smckusick register struct filedesc *fdp = p->p_fd; 48437741Smckusick int error; 48547540Skarels struct nameidata nd; 48637741Smckusick 48747540Skarels if (error = suser(p->p_ucred, &p->p_acflag)) 48847540Skarels return (error); 48952322Smckusick NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 49052781Sralph if (error = chdirec(&nd, p)) 49147540Skarels return (error); 49245914Smckusick if (fdp->fd_rdir != NULL) 49345914Smckusick vrele(fdp->fd_rdir); 49452322Smckusick fdp->fd_rdir = nd.ni_vp; 49547540Skarels return (0); 4966254Sroot } 4976254Sroot 49837Sbill /* 49937741Smckusick * Common routine for chroot and chdir. 50037741Smckusick */ 50147540Skarels chdirec(ndp, p) 50252322Smckusick register struct nameidata *ndp; 50347540Skarels struct proc *p; 50437741Smckusick { 50553548Sheideman USES_VOP_ACCESS; 50653548Sheideman USES_VOP_UNLOCK; 50737741Smckusick struct vnode *vp; 50837741Smckusick int error; 50937741Smckusick 51052322Smckusick if (error = namei(ndp)) 51137741Smckusick return (error); 51237741Smckusick vp = ndp->ni_vp; 51337741Smckusick if (vp->v_type != VDIR) 51437741Smckusick error = ENOTDIR; 51537741Smckusick else 51648026Smckusick error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p); 51737741Smckusick VOP_UNLOCK(vp); 51837741Smckusick if (error) 51937741Smckusick vrele(vp); 52037741Smckusick return (error); 52137741Smckusick } 52237741Smckusick 52337741Smckusick /* 5246254Sroot * Open system call. 52542441Smckusick * Check permissions, allocate an open file structure, 52642441Smckusick * and call the device open routine if any. 5276254Sroot */ 52842441Smckusick open(p, uap, retval) 52945914Smckusick struct proc *p; 53042441Smckusick register struct args { 5316254Sroot char *fname; 5327701Ssam int mode; 53312756Ssam int crtmode; 53442441Smckusick } *uap; 53542441Smckusick int *retval; 5366254Sroot { 53753548Sheideman USES_VOP_ADVLOCK; 53853548Sheideman USES_VOP_UNLOCK; 53945914Smckusick register struct filedesc *fdp = p->p_fd; 54042441Smckusick register struct file *fp; 54150111Smckusick register struct vnode *vp; 54237741Smckusick int fmode, cmode; 54337741Smckusick struct file *nfp; 54449945Smckusick int type, indx, error; 54549945Smckusick struct flock lf; 54647540Skarels struct nameidata nd; 54737741Smckusick extern struct fileops vnops; 5486254Sroot 54945914Smckusick if (error = falloc(p, &nfp, &indx)) 55047540Skarels return (error); 55137741Smckusick fp = nfp; 55246553Skarels fmode = FFLAGS(uap->mode); 55345914Smckusick cmode = ((uap->crtmode &~ fdp->fd_cmask) & 07777) &~ S_ISVTX; 55452322Smckusick NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->fname, p); 55545202Smckusick p->p_dupfd = -indx - 1; /* XXX check for fdopen */ 55652322Smckusick if (error = vn_open(&nd, fmode, cmode)) { 55753828Spendry int dfd = p->p_dupfd; 55853828Spendry p->p_dupfd = 0; 55949980Smckusick ffree(fp); 56053828Spendry if ((error == ENODEV || error == ENXIO) && /* XXX from fdopen */ 56153828Spendry dfd >= 0 && 56253828Spendry (error = dupfdopen(fdp, indx, p->p_dupfd, 56353828Spendry fmode, error)) == 0) { 56442441Smckusick *retval = indx; 56547540Skarels return (0); 56642441Smckusick } 56740884Smckusick if (error == ERESTART) 56840884Smckusick error = EINTR; 56947688Skarels fdp->fd_ofiles[indx] = NULL; 57047540Skarels return (error); 57112756Ssam } 57253828Spendry p->p_dupfd = 0; 57352322Smckusick vp = nd.ni_vp; 57449949Smckusick fp->f_flag = fmode & FMASK; 57554348Smckusick fp->f_type = DTYPE_VNODE; 57654348Smckusick fp->f_ops = &vnops; 57754348Smckusick fp->f_data = (caddr_t)vp; 57849945Smckusick if (fmode & (O_EXLOCK | O_SHLOCK)) { 57949945Smckusick lf.l_whence = SEEK_SET; 58049945Smckusick lf.l_start = 0; 58149945Smckusick lf.l_len = 0; 58249945Smckusick if (fmode & O_EXLOCK) 58349945Smckusick lf.l_type = F_WRLCK; 58449945Smckusick else 58549945Smckusick lf.l_type = F_RDLCK; 58649945Smckusick type = F_FLOCK; 58749945Smckusick if ((fmode & FNONBLOCK) == 0) 58849945Smckusick type |= F_WAIT; 58950111Smckusick if (error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, type)) { 59050111Smckusick VOP_UNLOCK(vp); 59150111Smckusick (void) vn_close(vp, fp->f_flag, fp->f_cred, p); 59249980Smckusick ffree(fp); 59349945Smckusick fdp->fd_ofiles[indx] = NULL; 59449945Smckusick return (error); 59549945Smckusick } 59649949Smckusick fp->f_flag |= FHASLOCK; 59749945Smckusick } 59850111Smckusick VOP_UNLOCK(vp); 59942441Smckusick *retval = indx; 60047540Skarels return (0); 6016254Sroot } 6026254Sroot 60342955Smckusick #ifdef COMPAT_43 6046254Sroot /* 60542441Smckusick * Creat system call. 6066254Sroot */ 60742955Smckusick ocreat(p, uap, retval) 60842441Smckusick struct proc *p; 60942441Smckusick register struct args { 61042441Smckusick char *fname; 61142441Smckusick int fmode; 61242441Smckusick } *uap; 61342441Smckusick int *retval; 6146254Sroot { 61542441Smckusick struct args { 6166254Sroot char *fname; 61742441Smckusick int mode; 61842441Smckusick int crtmode; 61942441Smckusick } openuap; 62042441Smckusick 62142441Smckusick openuap.fname = uap->fname; 62242441Smckusick openuap.crtmode = uap->fmode; 62342441Smckusick openuap.mode = O_WRONLY | O_CREAT | O_TRUNC; 62447540Skarels return (open(p, &openuap, retval)); 62542441Smckusick } 62642955Smckusick #endif /* COMPAT_43 */ 62742441Smckusick 62842441Smckusick /* 62949365Smckusick * Mknod system call. 63042441Smckusick */ 63142441Smckusick /* ARGSUSED */ 63242441Smckusick mknod(p, uap, retval) 63345914Smckusick struct proc *p; 63442441Smckusick register struct args { 63542441Smckusick char *fname; 6366254Sroot int fmode; 6376254Sroot int dev; 63842441Smckusick } *uap; 63942441Smckusick int *retval; 64042441Smckusick { 64153548Sheideman USES_VOP_ABORTOP; 64253548Sheideman USES_VOP_MKNOD; 64337741Smckusick register struct vnode *vp; 64437741Smckusick struct vattr vattr; 64537741Smckusick int error; 64647540Skarels struct nameidata nd; 6476254Sroot 64847540Skarels if (error = suser(p->p_ucred, &p->p_acflag)) 64947540Skarels return (error); 65052322Smckusick NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->fname, p); 65152322Smckusick if (error = namei(&nd)) 65247540Skarels return (error); 65352322Smckusick vp = nd.ni_vp; 65437741Smckusick if (vp != NULL) { 65537741Smckusick error = EEXIST; 65612756Ssam goto out; 6576254Sroot } 65841362Smckusick VATTR_NULL(&vattr); 65940635Smckusick switch (uap->fmode & S_IFMT) { 66012756Ssam 66140635Smckusick case S_IFMT: /* used by badsect to flag bad sectors */ 66237741Smckusick vattr.va_type = VBAD; 66337741Smckusick break; 66440635Smckusick case S_IFCHR: 66537741Smckusick vattr.va_type = VCHR; 66637741Smckusick break; 66740635Smckusick case S_IFBLK: 66837741Smckusick vattr.va_type = VBLK; 66937741Smckusick break; 67037741Smckusick default: 67137741Smckusick error = EINVAL; 67237741Smckusick goto out; 6736254Sroot } 67445914Smckusick vattr.va_mode = (uap->fmode & 07777) &~ p->p_fd->fd_cmask; 67537741Smckusick vattr.va_rdev = uap->dev; 6766254Sroot out: 67742465Smckusick if (!error) { 67852322Smckusick LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 67952322Smckusick error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr); 68042465Smckusick } else { 68152322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 68252322Smckusick if (nd.ni_dvp == vp) 68352322Smckusick vrele(nd.ni_dvp); 68443344Smckusick else 68552322Smckusick vput(nd.ni_dvp); 68642465Smckusick if (vp) 68742465Smckusick vrele(vp); 68842465Smckusick } 68947540Skarels return (error); 6906254Sroot } 6916254Sroot 6926254Sroot /* 69349365Smckusick * Mkfifo system call. 69440285Smckusick */ 69542441Smckusick /* ARGSUSED */ 69642441Smckusick mkfifo(p, uap, retval) 69745914Smckusick struct proc *p; 69842441Smckusick register struct args { 69940285Smckusick char *fname; 70040285Smckusick int fmode; 70142441Smckusick } *uap; 70242441Smckusick int *retval; 70342441Smckusick { 70453548Sheideman USES_VOP_ABORTOP; 70553548Sheideman USES_VOP_MKNOD; 70640285Smckusick struct vattr vattr; 70740285Smckusick int error; 70847540Skarels struct nameidata nd; 70940285Smckusick 71040285Smckusick #ifndef FIFO 71147540Skarels return (EOPNOTSUPP); 71240285Smckusick #else 71352322Smckusick NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->fname, p); 71452322Smckusick if (error = namei(&nd)) 71547540Skarels return (error); 71652322Smckusick if (nd.ni_vp != NULL) { 71752322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 71852322Smckusick if (nd.ni_dvp == nd.ni_vp) 71952322Smckusick vrele(nd.ni_dvp); 72043344Smckusick else 72152322Smckusick vput(nd.ni_dvp); 72252322Smckusick vrele(nd.ni_vp); 72347540Skarels return (EEXIST); 72440285Smckusick } 72545785Sbostic VATTR_NULL(&vattr); 72645785Sbostic vattr.va_type = VFIFO; 72745914Smckusick vattr.va_mode = (uap->fmode & 07777) &~ p->p_fd->fd_cmask; 72852322Smckusick LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 72952322Smckusick return (VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr)); 73040285Smckusick #endif /* FIFO */ 73140285Smckusick } 73240285Smckusick 73340285Smckusick /* 73449365Smckusick * Link system call. 7356254Sroot */ 73642441Smckusick /* ARGSUSED */ 73742441Smckusick link(p, uap, retval) 73845914Smckusick struct proc *p; 73942441Smckusick register struct args { 7406254Sroot char *target; 7416254Sroot char *linkname; 74242441Smckusick } *uap; 74342441Smckusick int *retval; 74442441Smckusick { 74553548Sheideman USES_VOP_ABORTOP; 74653548Sheideman USES_VOP_LINK; 74737741Smckusick register struct vnode *vp, *xp; 74837741Smckusick int error; 74947540Skarels struct nameidata nd; 7506254Sroot 75152322Smckusick NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->target, p); 75252322Smckusick if (error = namei(&nd)) 75347540Skarels return (error); 75452322Smckusick vp = nd.ni_vp; 75537741Smckusick if (vp->v_type == VDIR && 75647540Skarels (error = suser(p->p_ucred, &p->p_acflag))) 75737741Smckusick goto out1; 75852322Smckusick nd.ni_cnd.cn_nameiop = CREATE; 75952322Smckusick nd.ni_cnd.cn_flags = LOCKPARENT; 76052322Smckusick nd.ni_dirp = (caddr_t)uap->linkname; 76152322Smckusick if (error = namei(&nd)) 76237741Smckusick goto out1; 76352322Smckusick xp = nd.ni_vp; 7646254Sroot if (xp != NULL) { 76537741Smckusick error = EEXIST; 7666254Sroot goto out; 7676254Sroot } 76852322Smckusick xp = nd.ni_dvp; 7696254Sroot out: 77042465Smckusick if (!error) { 77152192Smckusick LEASE_CHECK(xp, p, p->p_ucred, LEASE_WRITE); 77252192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 77352821Smckusick error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd); 77442465Smckusick } else { 77552322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 77652322Smckusick if (nd.ni_dvp == nd.ni_vp) 77752322Smckusick vrele(nd.ni_dvp); 77843344Smckusick else 77952322Smckusick vput(nd.ni_dvp); 78052322Smckusick if (nd.ni_vp) 78152322Smckusick vrele(nd.ni_vp); 78242465Smckusick } 78337741Smckusick out1: 78437741Smckusick vrele(vp); 78547540Skarels return (error); 7866254Sroot } 7876254Sroot 7886254Sroot /* 78949365Smckusick * Make a symbolic link. 7906254Sroot */ 79142441Smckusick /* ARGSUSED */ 79242441Smckusick symlink(p, uap, retval) 79345914Smckusick struct proc *p; 79442441Smckusick register struct args { 7956254Sroot char *target; 7966254Sroot char *linkname; 79742441Smckusick } *uap; 79842441Smckusick int *retval; 79942441Smckusick { 80053548Sheideman USES_VOP_ABORTOP; 80153548Sheideman USES_VOP_SYMLINK; 80237741Smckusick struct vattr vattr; 80337741Smckusick char *target; 80437741Smckusick int error; 80547540Skarels struct nameidata nd; 8066254Sroot 80737741Smckusick MALLOC(target, char *, MAXPATHLEN, M_NAMEI, M_WAITOK); 80837741Smckusick if (error = copyinstr(uap->target, target, MAXPATHLEN, (u_int *)0)) 80942465Smckusick goto out; 81052322Smckusick NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->linkname, p); 81152322Smckusick if (error = namei(&nd)) 81242465Smckusick goto out; 81352322Smckusick if (nd.ni_vp) { 81452322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 81552322Smckusick if (nd.ni_dvp == nd.ni_vp) 81652322Smckusick vrele(nd.ni_dvp); 81743344Smckusick else 81852322Smckusick vput(nd.ni_dvp); 81952322Smckusick vrele(nd.ni_vp); 82037741Smckusick error = EEXIST; 82137741Smckusick goto out; 8226254Sroot } 82341362Smckusick VATTR_NULL(&vattr); 82445914Smckusick vattr.va_mode = 0777 &~ p->p_fd->fd_cmask; 82552322Smckusick LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 82652322Smckusick error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr, target); 82737741Smckusick out: 82837741Smckusick FREE(target, M_NAMEI); 82947540Skarels return (error); 8306254Sroot } 8316254Sroot 8326254Sroot /* 83349365Smckusick * Delete a name from the filesystem. 8346254Sroot */ 83542441Smckusick /* ARGSUSED */ 83642441Smckusick unlink(p, uap, retval) 83745914Smckusick struct proc *p; 83842441Smckusick struct args { 83952322Smckusick char *name; 84042441Smckusick } *uap; 84142441Smckusick int *retval; 8426254Sroot { 84353548Sheideman USES_VOP_ABORTOP; 84453548Sheideman USES_VOP_REMOVE; 84537741Smckusick register struct vnode *vp; 84637741Smckusick int error; 84747540Skarels struct nameidata nd; 8486254Sroot 84952322Smckusick NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE, uap->name, p); 85052322Smckusick if (error = namei(&nd)) 85147540Skarels return (error); 85252322Smckusick vp = nd.ni_vp; 85337741Smckusick if (vp->v_type == VDIR && 85447540Skarels (error = suser(p->p_ucred, &p->p_acflag))) 8556254Sroot goto out; 8566254Sroot /* 85749365Smckusick * The root of a mounted filesystem cannot be deleted. 8586254Sroot */ 85937741Smckusick if (vp->v_flag & VROOT) { 86037741Smckusick error = EBUSY; 8616254Sroot goto out; 8626254Sroot } 86345738Smckusick (void) vnode_pager_uncache(vp); 8646254Sroot out: 86542465Smckusick if (!error) { 86652322Smckusick LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 86752192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 86852322Smckusick error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); 86942465Smckusick } else { 87052322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 87152322Smckusick if (nd.ni_dvp == vp) 87252322Smckusick vrele(nd.ni_dvp); 87343344Smckusick else 87452322Smckusick vput(nd.ni_dvp); 87542465Smckusick vput(vp); 87642465Smckusick } 87747540Skarels return (error); 8786254Sroot } 8796254Sroot 88054348Smckusick #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 8816254Sroot /* 88249365Smckusick * Seek system call. 8836254Sroot */ 88442441Smckusick lseek(p, uap, retval) 88545914Smckusick struct proc *p; 88642441Smckusick register struct args { 88737741Smckusick int fdes; 88853468Smckusick long off; 88953468Smckusick int sbase; 89053468Smckusick } *uap; 89153468Smckusick long *retval; 89253468Smckusick { 89353468Smckusick struct nargs { 89453468Smckusick int fdes; 8956254Sroot off_t off; 8966254Sroot int sbase; 89753468Smckusick } nuap; 89853468Smckusick quad_t qret; 89953468Smckusick int error; 90053468Smckusick 90153468Smckusick nuap.fdes = uap->fdes; 90253468Smckusick nuap.off = uap->off; 90353468Smckusick nuap.sbase = uap->sbase; 90453759Smckusick error = __lseek(p, &nuap, &qret); 90553468Smckusick *retval = qret; 90653468Smckusick return (error); 90753468Smckusick } 90854348Smckusick #endif /* COMPAT_43 || COMPAT_SUNOS */ 90953468Smckusick 91053468Smckusick /* 91153468Smckusick * Seek system call. 91253468Smckusick */ 91353759Smckusick __lseek(p, uap, retval) 91453468Smckusick struct proc *p; 91553468Smckusick register struct args { 91653468Smckusick int fdes; 91753468Smckusick off_t off; 91853468Smckusick int sbase; 91942441Smckusick } *uap; 92042441Smckusick off_t *retval; 92142441Smckusick { 92253548Sheideman USES_VOP_GETATTR; 92347540Skarels struct ucred *cred = p->p_ucred; 92445914Smckusick register struct filedesc *fdp = p->p_fd; 92542441Smckusick register struct file *fp; 92637741Smckusick struct vattr vattr; 92737741Smckusick int error; 9286254Sroot 92947540Skarels if ((unsigned)uap->fdes >= fdp->fd_nfiles || 93047688Skarels (fp = fdp->fd_ofiles[uap->fdes]) == NULL) 93147540Skarels return (EBADF); 93237741Smckusick if (fp->f_type != DTYPE_VNODE) 93347540Skarels return (ESPIPE); 93413878Ssam switch (uap->sbase) { 93513878Ssam 93613878Ssam case L_INCR: 93713878Ssam fp->f_offset += uap->off; 93813878Ssam break; 93913878Ssam 94013878Ssam case L_XTND: 94137741Smckusick if (error = VOP_GETATTR((struct vnode *)fp->f_data, 94248026Smckusick &vattr, cred, p)) 94347540Skarels return (error); 94437741Smckusick fp->f_offset = uap->off + vattr.va_size; 94513878Ssam break; 94613878Ssam 94713878Ssam case L_SET: 94813878Ssam fp->f_offset = uap->off; 94913878Ssam break; 95013878Ssam 95113878Ssam default: 95247540Skarels return (EINVAL); 95313878Ssam } 95442441Smckusick *retval = fp->f_offset; 95547540Skarels return (0); 9566254Sroot } 9576254Sroot 9586254Sroot /* 95949365Smckusick * Check access permissions. 9606254Sroot */ 96142441Smckusick /* ARGSUSED */ 96242441Smckusick saccess(p, uap, retval) 96345914Smckusick struct proc *p; 96442441Smckusick register struct args { 9656254Sroot char *fname; 9666254Sroot int fmode; 96742441Smckusick } *uap; 96842441Smckusick int *retval; 96942441Smckusick { 97053548Sheideman USES_VOP_ACCESS; 97147540Skarels register struct ucred *cred = p->p_ucred; 97237741Smckusick register struct vnode *vp; 97337741Smckusick int error, mode, svuid, svgid; 97447540Skarels struct nameidata nd; 9756254Sroot 97642441Smckusick svuid = cred->cr_uid; 97742441Smckusick svgid = cred->cr_groups[0]; 97847540Skarels cred->cr_uid = p->p_cred->p_ruid; 97947540Skarels cred->cr_groups[0] = p->p_cred->p_rgid; 98052322Smckusick NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 98152322Smckusick if (error = namei(&nd)) 98237741Smckusick goto out1; 98352322Smckusick vp = nd.ni_vp; 98437741Smckusick /* 98537741Smckusick * fmode == 0 means only check for exist 98637741Smckusick */ 98737741Smckusick if (uap->fmode) { 98837741Smckusick mode = 0; 98937741Smckusick if (uap->fmode & R_OK) 99037741Smckusick mode |= VREAD; 99137741Smckusick if (uap->fmode & W_OK) 99237741Smckusick mode |= VWRITE; 99337741Smckusick if (uap->fmode & X_OK) 99437741Smckusick mode |= VEXEC; 99539543Smckusick if ((mode & VWRITE) == 0 || (error = vn_writechk(vp)) == 0) 99648026Smckusick error = VOP_ACCESS(vp, mode, cred, p); 9976254Sroot } 99837741Smckusick vput(vp); 99937741Smckusick out1: 100042441Smckusick cred->cr_uid = svuid; 100142441Smckusick cred->cr_groups[0] = svgid; 100247540Skarels return (error); 10036254Sroot } 10046254Sroot 100554348Smckusick #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 10066254Sroot /* 100749365Smckusick * Stat system call. 100849365Smckusick * This version follows links. 100937Sbill */ 101042441Smckusick /* ARGSUSED */ 101153759Smckusick ostat(p, uap, retval) 101245914Smckusick struct proc *p; 101342441Smckusick register struct args { 101442441Smckusick char *fname; 101553468Smckusick struct ostat *ub; 101653468Smckusick } *uap; 101753468Smckusick int *retval; 101853468Smckusick { 101953468Smckusick struct stat sb; 102053468Smckusick struct ostat osb; 102153468Smckusick int error; 102253468Smckusick struct nameidata nd; 102353468Smckusick 102453468Smckusick NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 102553468Smckusick if (error = namei(&nd)) 102653468Smckusick return (error); 102753468Smckusick error = vn_stat(nd.ni_vp, &sb, p); 102853468Smckusick vput(nd.ni_vp); 102953468Smckusick if (error) 103053468Smckusick return (error); 103153468Smckusick cvtstat(&sb, &osb); 103253468Smckusick error = copyout((caddr_t)&osb, (caddr_t)uap->ub, sizeof (osb)); 103353468Smckusick return (error); 103453468Smckusick } 103553468Smckusick 103653468Smckusick /* 103753468Smckusick * Lstat system call. 103853468Smckusick * This version does not follow links. 103953468Smckusick */ 104053468Smckusick /* ARGSUSED */ 104153759Smckusick olstat(p, uap, retval) 104253468Smckusick struct proc *p; 104353468Smckusick register struct args { 104453468Smckusick char *fname; 104553468Smckusick struct ostat *ub; 104653468Smckusick } *uap; 104753468Smckusick int *retval; 104853468Smckusick { 104953468Smckusick struct stat sb; 105053468Smckusick struct ostat osb; 105153468Smckusick int error; 105253468Smckusick struct nameidata nd; 105353468Smckusick 105453468Smckusick NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 105553468Smckusick if (error = namei(&nd)) 105653468Smckusick return (error); 105753468Smckusick error = vn_stat(nd.ni_vp, &sb, p); 105853468Smckusick vput(nd.ni_vp); 105953468Smckusick if (error) 106053468Smckusick return (error); 106153468Smckusick cvtstat(&sb, &osb); 106253468Smckusick error = copyout((caddr_t)&osb, (caddr_t)uap->ub, sizeof (osb)); 106353468Smckusick return (error); 106453468Smckusick } 106553468Smckusick 106653468Smckusick /* 106753468Smckusick * convert from an old to a new stat structure. 106853468Smckusick */ 106953468Smckusick cvtstat(st, ost) 107053468Smckusick struct stat *st; 107153468Smckusick struct ostat *ost; 107253468Smckusick { 107353468Smckusick 107453468Smckusick ost->st_dev = st->st_dev; 107553468Smckusick ost->st_ino = st->st_ino; 107653468Smckusick ost->st_mode = st->st_mode; 107753468Smckusick ost->st_nlink = st->st_nlink; 107853468Smckusick ost->st_uid = st->st_uid; 107953468Smckusick ost->st_gid = st->st_gid; 108053468Smckusick ost->st_rdev = st->st_rdev; 108153468Smckusick if (st->st_size < (quad_t)1 << 32) 108253468Smckusick ost->st_size = st->st_size; 108353468Smckusick else 108453468Smckusick ost->st_size = -2; 108553468Smckusick ost->st_atime = st->st_atime; 108653468Smckusick ost->st_mtime = st->st_mtime; 108753468Smckusick ost->st_ctime = st->st_ctime; 108853468Smckusick ost->st_blksize = st->st_blksize; 108953468Smckusick ost->st_blocks = st->st_blocks; 109053468Smckusick ost->st_flags = st->st_flags; 109153468Smckusick ost->st_gen = st->st_gen; 109253468Smckusick } 109354348Smckusick #endif /* COMPAT_43 || COMPAT_SUNOS */ 109453468Smckusick 109553468Smckusick /* 109653468Smckusick * Stat system call. 109753468Smckusick * This version follows links. 109853468Smckusick */ 109953468Smckusick /* ARGSUSED */ 110053759Smckusick stat(p, uap, retval) 110153468Smckusick struct proc *p; 110253468Smckusick register struct args { 110353468Smckusick char *fname; 110442441Smckusick struct stat *ub; 110542441Smckusick } *uap; 110642441Smckusick int *retval; 110737Sbill { 110842441Smckusick struct stat sb; 110942441Smckusick int error; 111047540Skarels struct nameidata nd; 111137Sbill 111252322Smckusick NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 111352322Smckusick if (error = namei(&nd)) 111447540Skarels return (error); 111552322Smckusick error = vn_stat(nd.ni_vp, &sb, p); 111652322Smckusick vput(nd.ni_vp); 111742441Smckusick if (error) 111847540Skarels return (error); 111942441Smckusick error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb)); 112047540Skarels return (error); 112137Sbill } 112237Sbill 112337Sbill /* 112449365Smckusick * Lstat system call. 112549365Smckusick * This version does not follow links. 11265992Swnj */ 112742441Smckusick /* ARGSUSED */ 112853759Smckusick lstat(p, uap, retval) 112945914Smckusick struct proc *p; 113042441Smckusick register struct args { 11315992Swnj char *fname; 113212756Ssam struct stat *ub; 113342441Smckusick } *uap; 113442441Smckusick int *retval; 113542441Smckusick { 113612756Ssam struct stat sb; 113737741Smckusick int error; 113847540Skarels struct nameidata nd; 11395992Swnj 114052322Smckusick NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 114152322Smckusick if (error = namei(&nd)) 114247540Skarels return (error); 114352322Smckusick error = vn_stat(nd.ni_vp, &sb, p); 114452322Smckusick vput(nd.ni_vp); 114537741Smckusick if (error) 114647540Skarels return (error); 114737741Smckusick error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb)); 114847540Skarels return (error); 11495992Swnj } 11505992Swnj 11515992Swnj /* 115249365Smckusick * Return target name of a symbolic link. 115337Sbill */ 115442441Smckusick /* ARGSUSED */ 115542441Smckusick readlink(p, uap, retval) 115645914Smckusick struct proc *p; 115742441Smckusick register struct args { 11585992Swnj char *name; 11595992Swnj char *buf; 11605992Swnj int count; 116142441Smckusick } *uap; 116242441Smckusick int *retval; 116342441Smckusick { 116453548Sheideman USES_VOP_READLINK; 116537741Smckusick register struct vnode *vp; 116637741Smckusick struct iovec aiov; 116737741Smckusick struct uio auio; 116837741Smckusick int error; 116947540Skarels struct nameidata nd; 11705992Swnj 117152322Smckusick NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, uap->name, p); 117252322Smckusick if (error = namei(&nd)) 117347540Skarels return (error); 117452322Smckusick vp = nd.ni_vp; 117537741Smckusick if (vp->v_type != VLNK) { 117637741Smckusick error = EINVAL; 11775992Swnj goto out; 11785992Swnj } 117937741Smckusick aiov.iov_base = uap->buf; 118037741Smckusick aiov.iov_len = uap->count; 118137741Smckusick auio.uio_iov = &aiov; 118237741Smckusick auio.uio_iovcnt = 1; 118337741Smckusick auio.uio_offset = 0; 118437741Smckusick auio.uio_rw = UIO_READ; 118537741Smckusick auio.uio_segflg = UIO_USERSPACE; 118648026Smckusick auio.uio_procp = p; 118737741Smckusick auio.uio_resid = uap->count; 118847540Skarels error = VOP_READLINK(vp, &auio, p->p_ucred); 11895992Swnj out: 119037741Smckusick vput(vp); 119142441Smckusick *retval = uap->count - auio.uio_resid; 119247540Skarels return (error); 11935992Swnj } 11945992Swnj 11959167Ssam /* 119638259Smckusick * Change flags of a file given path name. 119738259Smckusick */ 119842441Smckusick /* ARGSUSED */ 119942441Smckusick chflags(p, uap, retval) 120045914Smckusick struct proc *p; 120142441Smckusick register struct args { 120238259Smckusick char *fname; 120338259Smckusick int flags; 120442441Smckusick } *uap; 120542441Smckusick int *retval; 120642441Smckusick { 120753548Sheideman USES_VOP_SETATTR; 120838259Smckusick register struct vnode *vp; 120938259Smckusick struct vattr vattr; 121038259Smckusick int error; 121147540Skarels struct nameidata nd; 121238259Smckusick 121352322Smckusick NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 121452322Smckusick if (error = namei(&nd)) 121547540Skarels return (error); 121652322Smckusick vp = nd.ni_vp; 121741400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 121838259Smckusick error = EROFS; 121938259Smckusick goto out; 122038259Smckusick } 122145785Sbostic VATTR_NULL(&vattr); 122245785Sbostic vattr.va_flags = uap->flags; 122352192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 122448026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 122538259Smckusick out: 122638259Smckusick vput(vp); 122747540Skarels return (error); 122838259Smckusick } 122938259Smckusick 123038259Smckusick /* 123138259Smckusick * Change flags of a file given a file descriptor. 123238259Smckusick */ 123342441Smckusick /* ARGSUSED */ 123442441Smckusick fchflags(p, uap, retval) 123545914Smckusick struct proc *p; 123642441Smckusick register struct args { 123738259Smckusick int fd; 123838259Smckusick int flags; 123942441Smckusick } *uap; 124042441Smckusick int *retval; 124142441Smckusick { 124253548Sheideman USES_VOP_LOCK; 124353548Sheideman USES_VOP_SETATTR; 124453548Sheideman USES_VOP_UNLOCK; 124538259Smckusick struct vattr vattr; 124638259Smckusick struct vnode *vp; 124738259Smckusick struct file *fp; 124838259Smckusick int error; 124938259Smckusick 125045914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 125147540Skarels return (error); 125238259Smckusick vp = (struct vnode *)fp->f_data; 125338259Smckusick VOP_LOCK(vp); 125441400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 125538259Smckusick error = EROFS; 125638259Smckusick goto out; 125738259Smckusick } 125845785Sbostic VATTR_NULL(&vattr); 125945785Sbostic vattr.va_flags = uap->flags; 126052192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 126148026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 126238259Smckusick out: 126338259Smckusick VOP_UNLOCK(vp); 126447540Skarels return (error); 126538259Smckusick } 126638259Smckusick 126738259Smckusick /* 12689167Ssam * Change mode of a file given path name. 12699167Ssam */ 127042441Smckusick /* ARGSUSED */ 127142441Smckusick chmod(p, uap, retval) 127245914Smckusick struct proc *p; 127342441Smckusick register struct args { 12746254Sroot char *fname; 12756254Sroot int fmode; 127642441Smckusick } *uap; 127742441Smckusick int *retval; 127842441Smckusick { 127953548Sheideman USES_VOP_SETATTR; 128037741Smckusick register struct vnode *vp; 128137741Smckusick struct vattr vattr; 128237741Smckusick int error; 128347540Skarels struct nameidata nd; 12845992Swnj 128552322Smckusick NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 128652322Smckusick if (error = namei(&nd)) 128747540Skarels return (error); 128852322Smckusick vp = nd.ni_vp; 128941400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 129037741Smckusick error = EROFS; 129137741Smckusick goto out; 129237741Smckusick } 129345785Sbostic VATTR_NULL(&vattr); 129445785Sbostic vattr.va_mode = uap->fmode & 07777; 129552192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 129648026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 129737741Smckusick out: 129837741Smckusick vput(vp); 129947540Skarels return (error); 13007701Ssam } 13017439Sroot 13029167Ssam /* 13039167Ssam * Change mode of a file given a file descriptor. 13049167Ssam */ 130542441Smckusick /* ARGSUSED */ 130642441Smckusick fchmod(p, uap, retval) 130745914Smckusick struct proc *p; 130842441Smckusick register struct args { 13097701Ssam int fd; 13107701Ssam int fmode; 131142441Smckusick } *uap; 131242441Smckusick int *retval; 131342441Smckusick { 131453548Sheideman USES_VOP_LOCK; 131553548Sheideman USES_VOP_SETATTR; 131653548Sheideman USES_VOP_UNLOCK; 131737741Smckusick struct vattr vattr; 131837741Smckusick struct vnode *vp; 131937741Smckusick struct file *fp; 132037741Smckusick int error; 13217701Ssam 132245914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 132347540Skarels return (error); 132437741Smckusick vp = (struct vnode *)fp->f_data; 132537741Smckusick VOP_LOCK(vp); 132641400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 132737741Smckusick error = EROFS; 132837741Smckusick goto out; 13297439Sroot } 133045785Sbostic VATTR_NULL(&vattr); 133145785Sbostic vattr.va_mode = uap->fmode & 07777; 133252192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 133348026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 133437741Smckusick out: 133537741Smckusick VOP_UNLOCK(vp); 133647540Skarels return (error); 13375992Swnj } 13385992Swnj 13399167Ssam /* 13409167Ssam * Set ownership given a path name. 13419167Ssam */ 134242441Smckusick /* ARGSUSED */ 134342441Smckusick chown(p, uap, retval) 134445914Smckusick struct proc *p; 134542441Smckusick register struct args { 13466254Sroot char *fname; 13476254Sroot int uid; 13486254Sroot int gid; 134942441Smckusick } *uap; 135042441Smckusick int *retval; 135142441Smckusick { 135253548Sheideman USES_VOP_SETATTR; 135337741Smckusick register struct vnode *vp; 135437741Smckusick struct vattr vattr; 135537741Smckusick int error; 135647540Skarels struct nameidata nd; 135737Sbill 135852322Smckusick NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 135952322Smckusick if (error = namei(&nd)) 136047540Skarels return (error); 136152322Smckusick vp = nd.ni_vp; 136241400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 136337741Smckusick error = EROFS; 136437741Smckusick goto out; 136537741Smckusick } 136645785Sbostic VATTR_NULL(&vattr); 136745785Sbostic vattr.va_uid = uap->uid; 136845785Sbostic vattr.va_gid = uap->gid; 136952192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 137048026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 137137741Smckusick out: 137237741Smckusick vput(vp); 137347540Skarels return (error); 13747701Ssam } 13757439Sroot 13769167Ssam /* 13779167Ssam * Set ownership given a file descriptor. 13789167Ssam */ 137942441Smckusick /* ARGSUSED */ 138042441Smckusick fchown(p, uap, retval) 138145914Smckusick struct proc *p; 138242441Smckusick register struct args { 13837701Ssam int fd; 13847701Ssam int uid; 13857701Ssam int gid; 138642441Smckusick } *uap; 138742441Smckusick int *retval; 138842441Smckusick { 138953548Sheideman USES_VOP_LOCK; 139053548Sheideman USES_VOP_SETATTR; 139153548Sheideman USES_VOP_UNLOCK; 139237741Smckusick struct vattr vattr; 139337741Smckusick struct vnode *vp; 139437741Smckusick struct file *fp; 139537741Smckusick int error; 13967701Ssam 139745914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 139847540Skarels return (error); 139937741Smckusick vp = (struct vnode *)fp->f_data; 140037741Smckusick VOP_LOCK(vp); 140141400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 140237741Smckusick error = EROFS; 140337741Smckusick goto out; 140437741Smckusick } 140545785Sbostic VATTR_NULL(&vattr); 140645785Sbostic vattr.va_uid = uap->uid; 140745785Sbostic vattr.va_gid = uap->gid; 140852192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 140948026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 141037741Smckusick out: 141137741Smckusick VOP_UNLOCK(vp); 141247540Skarels return (error); 14137701Ssam } 14147701Ssam 141542441Smckusick /* 141642441Smckusick * Set the access and modification times of a file. 141742441Smckusick */ 141842441Smckusick /* ARGSUSED */ 141942441Smckusick utimes(p, uap, retval) 142045914Smckusick struct proc *p; 142142441Smckusick register struct args { 142211811Ssam char *fname; 142311811Ssam struct timeval *tptr; 142442441Smckusick } *uap; 142542441Smckusick int *retval; 142642441Smckusick { 142753548Sheideman USES_VOP_SETATTR; 142837741Smckusick register struct vnode *vp; 142911811Ssam struct timeval tv[2]; 143037741Smckusick struct vattr vattr; 143137741Smckusick int error; 143247540Skarels struct nameidata nd; 143311811Ssam 143437741Smckusick if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv))) 143547540Skarels return (error); 143652322Smckusick NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 143752322Smckusick if (error = namei(&nd)) 143847540Skarels return (error); 143952322Smckusick vp = nd.ni_vp; 144041400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 144137741Smckusick error = EROFS; 144237741Smckusick goto out; 144321015Smckusick } 144445785Sbostic VATTR_NULL(&vattr); 144554100Smckusick vattr.va_atime.ts_sec = tv[0].tv_sec; 144654100Smckusick vattr.va_atime.ts_nsec = tv[0].tv_usec * 1000; 144754100Smckusick vattr.va_mtime.ts_sec = tv[1].tv_sec; 144854100Smckusick vattr.va_mtime.ts_nsec = tv[1].tv_usec * 1000; 144952192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 145048026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 145137741Smckusick out: 145237741Smckusick vput(vp); 145347540Skarels return (error); 145411811Ssam } 145511811Ssam 145654348Smckusick #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 14579167Ssam /* 14589167Ssam * Truncate a file given its path name. 14599167Ssam */ 146042441Smckusick /* ARGSUSED */ 146142441Smckusick truncate(p, uap, retval) 146245914Smckusick struct proc *p; 146342441Smckusick register struct args { 14647701Ssam char *fname; 146553468Smckusick long length; 146653468Smckusick } *uap; 146753468Smckusick int *retval; 146853468Smckusick { 146953468Smckusick struct nargs { 147053468Smckusick char *fname; 147126473Skarels off_t length; 147253468Smckusick } nuap; 147353468Smckusick 147453468Smckusick nuap.fname = uap->fname; 147553468Smckusick nuap.length = uap->length; 147653759Smckusick return (__truncate(p, &nuap, retval)); 147753468Smckusick } 147853468Smckusick 147953468Smckusick /* 148053468Smckusick * Truncate a file given a file descriptor. 148153468Smckusick */ 148253468Smckusick /* ARGSUSED */ 148353468Smckusick ftruncate(p, uap, retval) 148453468Smckusick struct proc *p; 148553468Smckusick register struct args { 148653468Smckusick int fd; 148753468Smckusick long length; 148842441Smckusick } *uap; 148942441Smckusick int *retval; 149042441Smckusick { 149153468Smckusick struct nargs { 149253468Smckusick int fd; 149353468Smckusick off_t length; 149453468Smckusick } nuap; 149553468Smckusick 149653468Smckusick nuap.fd = uap->fd; 149753468Smckusick nuap.length = uap->length; 149853759Smckusick return (__ftruncate(p, &nuap, retval)); 149953468Smckusick } 150054348Smckusick #endif /* COMPAT_43 || COMPAT_SUNOS */ 150153468Smckusick 150253468Smckusick /* 150353468Smckusick * Truncate a file given its path name. 150453468Smckusick */ 150553468Smckusick /* ARGSUSED */ 150653759Smckusick __truncate(p, uap, retval) 150753468Smckusick struct proc *p; 150853468Smckusick register struct args { 150953468Smckusick char *fname; 151053468Smckusick off_t length; 151153468Smckusick } *uap; 151253468Smckusick int *retval; 151353468Smckusick { 151453548Sheideman USES_VOP_ACCESS; 151553548Sheideman USES_VOP_SETATTR; 151637741Smckusick register struct vnode *vp; 151737741Smckusick struct vattr vattr; 151837741Smckusick int error; 151947540Skarels struct nameidata nd; 15207701Ssam 152152322Smckusick NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 152252322Smckusick if (error = namei(&nd)) 152347540Skarels return (error); 152452322Smckusick vp = nd.ni_vp; 152537741Smckusick if (vp->v_type == VDIR) { 152637741Smckusick error = EISDIR; 152737741Smckusick goto out; 15287701Ssam } 152938399Smckusick if ((error = vn_writechk(vp)) || 153048026Smckusick (error = VOP_ACCESS(vp, VWRITE, p->p_ucred, p))) 153137741Smckusick goto out; 153245785Sbostic VATTR_NULL(&vattr); 153345785Sbostic vattr.va_size = uap->length; 153452192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 153548026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 153637741Smckusick out: 153737741Smckusick vput(vp); 153847540Skarels return (error); 15397701Ssam } 15407701Ssam 15419167Ssam /* 15429167Ssam * Truncate a file given a file descriptor. 15439167Ssam */ 154442441Smckusick /* ARGSUSED */ 154553759Smckusick __ftruncate(p, uap, retval) 154645914Smckusick struct proc *p; 154742441Smckusick register struct args { 15487701Ssam int fd; 154926473Skarels off_t length; 155042441Smckusick } *uap; 155142441Smckusick int *retval; 155242441Smckusick { 155353548Sheideman USES_VOP_LOCK; 155453548Sheideman USES_VOP_SETATTR; 155553548Sheideman USES_VOP_UNLOCK; 155637741Smckusick struct vattr vattr; 155737741Smckusick struct vnode *vp; 15587701Ssam struct file *fp; 155937741Smckusick int error; 15607701Ssam 156145914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 156247540Skarels return (error); 156337741Smckusick if ((fp->f_flag & FWRITE) == 0) 156447540Skarels return (EINVAL); 156537741Smckusick vp = (struct vnode *)fp->f_data; 156637741Smckusick VOP_LOCK(vp); 156737741Smckusick if (vp->v_type == VDIR) { 156837741Smckusick error = EISDIR; 156937741Smckusick goto out; 15707701Ssam } 157138399Smckusick if (error = vn_writechk(vp)) 157237741Smckusick goto out; 157345785Sbostic VATTR_NULL(&vattr); 157445785Sbostic vattr.va_size = uap->length; 157552192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 157648026Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred, p); 157737741Smckusick out: 157837741Smckusick VOP_UNLOCK(vp); 157947540Skarels return (error); 15807701Ssam } 15817701Ssam 15829167Ssam /* 15839167Ssam * Synch an open file. 15849167Ssam */ 158542441Smckusick /* ARGSUSED */ 158642441Smckusick fsync(p, uap, retval) 158745914Smckusick struct proc *p; 158842441Smckusick struct args { 158942441Smckusick int fd; 159042441Smckusick } *uap; 159142441Smckusick int *retval; 15929167Ssam { 159353548Sheideman USES_VOP_FSYNC; 159453548Sheideman USES_VOP_LOCK; 159553548Sheideman USES_VOP_UNLOCK; 159639592Smckusick register struct vnode *vp; 15979167Ssam struct file *fp; 159837741Smckusick int error; 15999167Ssam 160045914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 160147540Skarels return (error); 160239592Smckusick vp = (struct vnode *)fp->f_data; 160339592Smckusick VOP_LOCK(vp); 1604*54441Smckusick error = VOP_FSYNC(vp, fp->f_cred, MNT_WAIT, p); 160539592Smckusick VOP_UNLOCK(vp); 160647540Skarels return (error); 16079167Ssam } 16089167Ssam 16099167Ssam /* 16109167Ssam * Rename system call. 16119167Ssam * 16129167Ssam * Source and destination must either both be directories, or both 16139167Ssam * not be directories. If target is a directory, it must be empty. 16149167Ssam */ 161542441Smckusick /* ARGSUSED */ 161642441Smckusick rename(p, uap, retval) 161745914Smckusick struct proc *p; 161842441Smckusick register struct args { 16197701Ssam char *from; 16207701Ssam char *to; 162142441Smckusick } *uap; 162242441Smckusick int *retval; 162342441Smckusick { 162453548Sheideman USES_VOP_ABORTOP; 162553548Sheideman USES_VOP_RENAME; 162637741Smckusick register struct vnode *tvp, *fvp, *tdvp; 162749735Smckusick struct nameidata fromnd, tond; 162837741Smckusick int error; 16297701Ssam 163052322Smckusick NDINIT(&fromnd, DELETE, WANTPARENT | SAVESTART, UIO_USERSPACE, 163152322Smckusick uap->from, p); 163252322Smckusick if (error = namei(&fromnd)) 163347540Skarels return (error); 163449735Smckusick fvp = fromnd.ni_vp; 163552322Smckusick NDINIT(&tond, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART, 163652322Smckusick UIO_USERSPACE, uap->to, p); 163752322Smckusick if (error = namei(&tond)) { 163852230Sheideman VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 163949735Smckusick vrele(fromnd.ni_dvp); 164042465Smckusick vrele(fvp); 164142465Smckusick goto out1; 164242465Smckusick } 164337741Smckusick tdvp = tond.ni_dvp; 164437741Smckusick tvp = tond.ni_vp; 164537741Smckusick if (tvp != NULL) { 164637741Smckusick if (fvp->v_type == VDIR && tvp->v_type != VDIR) { 164739242Sbostic error = ENOTDIR; 164837741Smckusick goto out; 164937741Smckusick } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) { 165039242Sbostic error = EISDIR; 165137741Smckusick goto out; 16529167Ssam } 16539167Ssam } 165439286Smckusick if (fvp == tdvp) 165537741Smckusick error = EINVAL; 165639286Smckusick /* 165749735Smckusick * If source is the same as the destination (that is the 165849735Smckusick * same inode number with the same name in the same directory), 165939286Smckusick * then there is nothing to do. 166039286Smckusick */ 166149735Smckusick if (fvp == tvp && fromnd.ni_dvp == tdvp && 166252322Smckusick fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen && 166352322Smckusick !bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr, 166452322Smckusick fromnd.ni_cnd.cn_namelen)) 166539286Smckusick error = -1; 166637741Smckusick out: 166742465Smckusick if (!error) { 166852192Smckusick LEASE_CHECK(tdvp, p, p->p_ucred, LEASE_WRITE); 166952192Smckusick if (fromnd.ni_dvp != tdvp) 167052192Smckusick LEASE_CHECK(fromnd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 167152192Smckusick if (tvp) 167252192Smckusick LEASE_CHECK(tvp, p, p->p_ucred, LEASE_WRITE); 167352230Sheideman error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd, 167452230Sheideman tond.ni_dvp, tond.ni_vp, &tond.ni_cnd); 167542465Smckusick } else { 167652230Sheideman VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd); 167743344Smckusick if (tdvp == tvp) 167843344Smckusick vrele(tdvp); 167943344Smckusick else 168043344Smckusick vput(tdvp); 168142465Smckusick if (tvp) 168242465Smckusick vput(tvp); 168352230Sheideman VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 168449735Smckusick vrele(fromnd.ni_dvp); 168542465Smckusick vrele(fvp); 16869167Ssam } 168749735Smckusick vrele(tond.ni_startdir); 168852322Smckusick FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI); 168937741Smckusick out1: 169049735Smckusick vrele(fromnd.ni_startdir); 169152322Smckusick FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI); 169239286Smckusick if (error == -1) 169347540Skarels return (0); 169447540Skarels return (error); 16957701Ssam } 16967701Ssam 16977535Sroot /* 169849365Smckusick * Mkdir system call. 169912756Ssam */ 170042441Smckusick /* ARGSUSED */ 170142441Smckusick mkdir(p, uap, retval) 170245914Smckusick struct proc *p; 170342441Smckusick register struct args { 170412756Ssam char *name; 170512756Ssam int dmode; 170642441Smckusick } *uap; 170742441Smckusick int *retval; 170842441Smckusick { 170953548Sheideman USES_VOP_ABORTOP; 171053548Sheideman USES_VOP_MKDIR; 171137741Smckusick register struct vnode *vp; 171237741Smckusick struct vattr vattr; 171337741Smckusick int error; 171447540Skarels struct nameidata nd; 171512756Ssam 171652322Smckusick NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->name, p); 171752322Smckusick if (error = namei(&nd)) 171847540Skarels return (error); 171952322Smckusick vp = nd.ni_vp; 172037741Smckusick if (vp != NULL) { 172152322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 172252322Smckusick if (nd.ni_dvp == vp) 172352322Smckusick vrele(nd.ni_dvp); 172443344Smckusick else 172552322Smckusick vput(nd.ni_dvp); 172642465Smckusick vrele(vp); 172747540Skarels return (EEXIST); 172812756Ssam } 172941362Smckusick VATTR_NULL(&vattr); 173037741Smckusick vattr.va_type = VDIR; 173145914Smckusick vattr.va_mode = (uap->dmode & 0777) &~ p->p_fd->fd_cmask; 173252322Smckusick LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 173352322Smckusick error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr); 173438145Smckusick if (!error) 173552322Smckusick vput(nd.ni_vp); 173647540Skarels return (error); 173712756Ssam } 173812756Ssam 173912756Ssam /* 174012756Ssam * Rmdir system call. 174112756Ssam */ 174242441Smckusick /* ARGSUSED */ 174342441Smckusick rmdir(p, uap, retval) 174445914Smckusick struct proc *p; 174542441Smckusick struct args { 174642441Smckusick char *name; 174742441Smckusick } *uap; 174842441Smckusick int *retval; 174912756Ssam { 175053548Sheideman USES_VOP_ABORTOP; 175153548Sheideman USES_VOP_RMDIR; 175237741Smckusick register struct vnode *vp; 175337741Smckusick int error; 175447540Skarels struct nameidata nd; 175512756Ssam 175652322Smckusick NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE, uap->name, p); 175752322Smckusick if (error = namei(&nd)) 175847540Skarels return (error); 175952322Smckusick vp = nd.ni_vp; 176037741Smckusick if (vp->v_type != VDIR) { 176137741Smckusick error = ENOTDIR; 176212756Ssam goto out; 176312756Ssam } 176412756Ssam /* 176537741Smckusick * No rmdir "." please. 176612756Ssam */ 176752322Smckusick if (nd.ni_dvp == vp) { 176837741Smckusick error = EINVAL; 176912756Ssam goto out; 177012756Ssam } 177112756Ssam /* 177249365Smckusick * The root of a mounted filesystem cannot be deleted. 177312756Ssam */ 177437741Smckusick if (vp->v_flag & VROOT) 177537741Smckusick error = EBUSY; 177612756Ssam out: 177742465Smckusick if (!error) { 177852322Smckusick LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 177952192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 178052322Smckusick error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); 178142465Smckusick } else { 178252322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 178352322Smckusick if (nd.ni_dvp == vp) 178452322Smckusick vrele(nd.ni_dvp); 178543344Smckusick else 178652322Smckusick vput(nd.ni_dvp); 178742465Smckusick vput(vp); 178842465Smckusick } 178947540Skarels return (error); 179012756Ssam } 179112756Ssam 179237741Smckusick /* 179349365Smckusick * Read a block of directory entries in a file system independent format. 179437741Smckusick */ 179542441Smckusick getdirentries(p, uap, retval) 179645914Smckusick struct proc *p; 179742441Smckusick register struct args { 179837741Smckusick int fd; 179937741Smckusick char *buf; 180037741Smckusick unsigned count; 180137741Smckusick long *basep; 180242441Smckusick } *uap; 180342441Smckusick int *retval; 180442441Smckusick { 180553548Sheideman USES_VOP_LOCK; 180653548Sheideman USES_VOP_READDIR; 180753548Sheideman USES_VOP_UNLOCK; 180839592Smckusick register struct vnode *vp; 180916540Ssam struct file *fp; 181037741Smckusick struct uio auio; 181137741Smckusick struct iovec aiov; 181238129Smckusick off_t off; 1813*54441Smckusick int error; 181412756Ssam 181545914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 181647540Skarels return (error); 181737741Smckusick if ((fp->f_flag & FREAD) == 0) 181847540Skarels return (EBADF); 181939592Smckusick vp = (struct vnode *)fp->f_data; 182039592Smckusick if (vp->v_type != VDIR) 182147540Skarels return (EINVAL); 182237741Smckusick aiov.iov_base = uap->buf; 182337741Smckusick aiov.iov_len = uap->count; 182437741Smckusick auio.uio_iov = &aiov; 182537741Smckusick auio.uio_iovcnt = 1; 182637741Smckusick auio.uio_rw = UIO_READ; 182737741Smckusick auio.uio_segflg = UIO_USERSPACE; 182848026Smckusick auio.uio_procp = p; 182937741Smckusick auio.uio_resid = uap->count; 183039592Smckusick VOP_LOCK(vp); 183139592Smckusick auio.uio_offset = off = fp->f_offset; 1832*54441Smckusick error = VOP_READDIR(vp, &auio, fp->f_cred); 183339592Smckusick fp->f_offset = auio.uio_offset; 183439592Smckusick VOP_UNLOCK(vp); 183539592Smckusick if (error) 183647540Skarels return (error); 183739592Smckusick error = copyout((caddr_t)&off, (caddr_t)uap->basep, sizeof(long)); 183842441Smckusick *retval = uap->count - auio.uio_resid; 183947540Skarels return (error); 184012756Ssam } 184112756Ssam 184212756Ssam /* 184349365Smckusick * Set the mode mask for creation of filesystem nodes. 184412756Ssam */ 184542441Smckusick mode_t 184642441Smckusick umask(p, uap, retval) 184745914Smckusick struct proc *p; 184842441Smckusick struct args { 184942441Smckusick int mask; 185042441Smckusick } *uap; 185142441Smckusick int *retval; 185212756Ssam { 185345914Smckusick register struct filedesc *fdp = p->p_fd; 185412756Ssam 185545914Smckusick *retval = fdp->fd_cmask; 185645914Smckusick fdp->fd_cmask = uap->mask & 07777; 185747540Skarels return (0); 185812756Ssam } 185937741Smckusick 186039566Smarc /* 186139566Smarc * Void all references to file by ripping underlying filesystem 186239566Smarc * away from vnode. 186339566Smarc */ 186442441Smckusick /* ARGSUSED */ 186542441Smckusick revoke(p, uap, retval) 186645914Smckusick struct proc *p; 186742441Smckusick register struct args { 186839566Smarc char *fname; 186942441Smckusick } *uap; 187042441Smckusick int *retval; 187142441Smckusick { 187253548Sheideman USES_VOP_GETATTR; 187339566Smarc register struct vnode *vp; 187439566Smarc struct vattr vattr; 187539566Smarc int error; 187647540Skarels struct nameidata nd; 187739566Smarc 187852322Smckusick NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->fname, p); 187952322Smckusick if (error = namei(&nd)) 188047540Skarels return (error); 188152322Smckusick vp = nd.ni_vp; 188239566Smarc if (vp->v_type != VCHR && vp->v_type != VBLK) { 188339566Smarc error = EINVAL; 188439566Smarc goto out; 188539566Smarc } 188648026Smckusick if (error = VOP_GETATTR(vp, &vattr, p->p_ucred, p)) 188739566Smarc goto out; 188847540Skarels if (p->p_ucred->cr_uid != vattr.va_uid && 188947540Skarels (error = suser(p->p_ucred, &p->p_acflag))) 189039566Smarc goto out; 189139805Smckusick if (vp->v_usecount > 1 || (vp->v_flag & VALIASED)) 189239632Smckusick vgoneall(vp); 189339566Smarc out: 189439566Smarc vrele(vp); 189547540Skarels return (error); 189639566Smarc } 189739566Smarc 189849365Smckusick /* 189949365Smckusick * Convert a user file descriptor to a kernel file entry. 190049365Smckusick */ 190145914Smckusick getvnode(fdp, fdes, fpp) 190245914Smckusick struct filedesc *fdp; 190337741Smckusick struct file **fpp; 190437741Smckusick int fdes; 190537741Smckusick { 190637741Smckusick struct file *fp; 190737741Smckusick 190847540Skarels if ((unsigned)fdes >= fdp->fd_nfiles || 190947688Skarels (fp = fdp->fd_ofiles[fdes]) == NULL) 191037741Smckusick return (EBADF); 191137741Smckusick if (fp->f_type != DTYPE_VNODE) 191237741Smckusick return (EINVAL); 191337741Smckusick *fpp = fp; 191437741Smckusick return (0); 191537741Smckusick } 1916