123405Smckusick /* 237741Smckusick * Copyright (c) 1989 The Regents of the University of California. 337741Smckusick * All rights reserved. 423405Smckusick * 544459Sbostic * %sccs.include.redist.c% 637741Smckusick * 7*54723Smckusick * @(#)vfs_syscalls.c 7.91 (Berkeley) 07/06/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" 2254620Smckusick #include "dirent.h" 2353468Smckusick #include <vm/vm.h> 2437Sbill 2537741Smckusick /* 2637741Smckusick * Virtual File System System Calls 2737741Smckusick */ 2812756Ssam 299167Ssam /* 3049365Smckusick * Mount system call. 319167Ssam */ 3242441Smckusick /* ARGSUSED */ 3342441Smckusick mount(p, uap, retval) 3445914Smckusick struct proc *p; 3542441Smckusick register struct args { 3637741Smckusick int type; 3737741Smckusick char *dir; 3837741Smckusick int flags; 3937741Smckusick caddr_t data; 4042441Smckusick } *uap; 4142441Smckusick int *retval; 4242441Smckusick { 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 } 8454441Smckusick if (error = vinvalbuf(vp, 1, p->p_ucred, p)) 8554441Smckusick 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 */ 23354441Smckusick if ((error = VFS_SYNC(mp, MNT_WAIT, p->p_ucred, p)) == 0 || 23454441Smckusick (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)) { 27154441Smckusick 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 { 42445914Smckusick register struct filedesc *fdp = p->p_fd; 42538259Smckusick register struct vnode *vp; 42638259Smckusick struct file *fp; 42738259Smckusick int error; 42838259Smckusick 42945914Smckusick if (error = getvnode(fdp, uap->fd, &fp)) 43047540Skarels return (error); 43138259Smckusick vp = (struct vnode *)fp->f_data; 43238259Smckusick VOP_LOCK(vp); 43338259Smckusick if (vp->v_type != VDIR) 43438259Smckusick error = ENOTDIR; 43538259Smckusick else 43648026Smckusick error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p); 43738259Smckusick VOP_UNLOCK(vp); 43839860Smckusick if (error) 43947540Skarels return (error); 44039860Smckusick VREF(vp); 44145914Smckusick vrele(fdp->fd_cdir); 44245914Smckusick fdp->fd_cdir = vp; 44347540Skarels return (0); 44438259Smckusick } 44538259Smckusick 44638259Smckusick /* 44737741Smckusick * Change current working directory (``.''). 44837741Smckusick */ 44942441Smckusick /* ARGSUSED */ 45042441Smckusick chdir(p, uap, retval) 45145914Smckusick struct proc *p; 45242441Smckusick struct args { 45342441Smckusick char *fname; 45442441Smckusick } *uap; 45542441Smckusick int *retval; 45637741Smckusick { 45745914Smckusick register struct filedesc *fdp = p->p_fd; 45837741Smckusick int error; 45947540Skarels struct nameidata nd; 4606254Sroot 46152322Smckusick NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 46252781Sralph if (error = chdirec(&nd, p)) 46347540Skarels return (error); 46445914Smckusick vrele(fdp->fd_cdir); 46552322Smckusick fdp->fd_cdir = nd.ni_vp; 46647540Skarels return (0); 46737741Smckusick } 4686254Sroot 46937741Smckusick /* 47037741Smckusick * Change notion of root (``/'') directory. 47137741Smckusick */ 47242441Smckusick /* ARGSUSED */ 47342441Smckusick chroot(p, uap, retval) 47445914Smckusick struct proc *p; 47542441Smckusick struct args { 47642441Smckusick char *fname; 47742441Smckusick } *uap; 47842441Smckusick int *retval; 47937741Smckusick { 48045914Smckusick register struct filedesc *fdp = p->p_fd; 48137741Smckusick int error; 48247540Skarels struct nameidata nd; 48337741Smckusick 48447540Skarels if (error = suser(p->p_ucred, &p->p_acflag)) 48547540Skarels return (error); 48652322Smckusick NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 48752781Sralph if (error = chdirec(&nd, p)) 48847540Skarels return (error); 48945914Smckusick if (fdp->fd_rdir != NULL) 49045914Smckusick vrele(fdp->fd_rdir); 49152322Smckusick fdp->fd_rdir = nd.ni_vp; 49247540Skarels return (0); 4936254Sroot } 4946254Sroot 49537Sbill /* 49637741Smckusick * Common routine for chroot and chdir. 49737741Smckusick */ 49847540Skarels chdirec(ndp, p) 49952322Smckusick register struct nameidata *ndp; 50047540Skarels struct proc *p; 50137741Smckusick { 50237741Smckusick struct vnode *vp; 50337741Smckusick int error; 50437741Smckusick 50552322Smckusick if (error = namei(ndp)) 50637741Smckusick return (error); 50737741Smckusick vp = ndp->ni_vp; 50837741Smckusick if (vp->v_type != VDIR) 50937741Smckusick error = ENOTDIR; 51037741Smckusick else 51148026Smckusick error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p); 51237741Smckusick VOP_UNLOCK(vp); 51337741Smckusick if (error) 51437741Smckusick vrele(vp); 51537741Smckusick return (error); 51637741Smckusick } 51737741Smckusick 51837741Smckusick /* 5196254Sroot * Open system call. 52042441Smckusick * Check permissions, allocate an open file structure, 52142441Smckusick * and call the device open routine if any. 5226254Sroot */ 52342441Smckusick open(p, uap, retval) 52445914Smckusick struct proc *p; 52542441Smckusick register struct args { 5266254Sroot char *fname; 5277701Ssam int mode; 52812756Ssam int crtmode; 52942441Smckusick } *uap; 53042441Smckusick int *retval; 5316254Sroot { 53245914Smckusick register struct filedesc *fdp = p->p_fd; 53342441Smckusick register struct file *fp; 53450111Smckusick register struct vnode *vp; 53537741Smckusick int fmode, cmode; 53637741Smckusick struct file *nfp; 53749945Smckusick int type, indx, error; 53849945Smckusick struct flock lf; 53947540Skarels struct nameidata nd; 54037741Smckusick extern struct fileops vnops; 5416254Sroot 54245914Smckusick if (error = falloc(p, &nfp, &indx)) 54347540Skarels return (error); 54437741Smckusick fp = nfp; 54546553Skarels fmode = FFLAGS(uap->mode); 54645914Smckusick cmode = ((uap->crtmode &~ fdp->fd_cmask) & 07777) &~ S_ISVTX; 54752322Smckusick NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->fname, p); 54845202Smckusick p->p_dupfd = -indx - 1; /* XXX check for fdopen */ 54952322Smckusick if (error = vn_open(&nd, fmode, cmode)) { 55049980Smckusick ffree(fp); 551*54723Smckusick if ((error == ENODEV || error == ENXIO) && 552*54723Smckusick p->p_dupfd >= 0 && /* XXX from fdopen */ 55353828Spendry (error = dupfdopen(fdp, indx, p->p_dupfd, 55453828Spendry fmode, error)) == 0) { 55542441Smckusick *retval = indx; 55647540Skarels return (0); 55742441Smckusick } 55840884Smckusick if (error == ERESTART) 55940884Smckusick error = EINTR; 56047688Skarels fdp->fd_ofiles[indx] = NULL; 56147540Skarels return (error); 56212756Ssam } 56353828Spendry p->p_dupfd = 0; 56452322Smckusick vp = nd.ni_vp; 56549949Smckusick fp->f_flag = fmode & FMASK; 56654348Smckusick fp->f_type = DTYPE_VNODE; 56754348Smckusick fp->f_ops = &vnops; 56854348Smckusick fp->f_data = (caddr_t)vp; 56949945Smckusick if (fmode & (O_EXLOCK | O_SHLOCK)) { 57049945Smckusick lf.l_whence = SEEK_SET; 57149945Smckusick lf.l_start = 0; 57249945Smckusick lf.l_len = 0; 57349945Smckusick if (fmode & O_EXLOCK) 57449945Smckusick lf.l_type = F_WRLCK; 57549945Smckusick else 57649945Smckusick lf.l_type = F_RDLCK; 57749945Smckusick type = F_FLOCK; 57849945Smckusick if ((fmode & FNONBLOCK) == 0) 57949945Smckusick type |= F_WAIT; 58050111Smckusick if (error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, type)) { 58150111Smckusick VOP_UNLOCK(vp); 58250111Smckusick (void) vn_close(vp, fp->f_flag, fp->f_cred, p); 58349980Smckusick ffree(fp); 58449945Smckusick fdp->fd_ofiles[indx] = NULL; 58549945Smckusick return (error); 58649945Smckusick } 58749949Smckusick fp->f_flag |= FHASLOCK; 58849945Smckusick } 58950111Smckusick VOP_UNLOCK(vp); 59042441Smckusick *retval = indx; 59147540Skarels return (0); 5926254Sroot } 5936254Sroot 59442955Smckusick #ifdef COMPAT_43 5956254Sroot /* 59642441Smckusick * Creat system call. 5976254Sroot */ 59842955Smckusick ocreat(p, uap, retval) 59942441Smckusick struct proc *p; 60042441Smckusick register struct args { 60142441Smckusick char *fname; 60242441Smckusick int fmode; 60342441Smckusick } *uap; 60442441Smckusick int *retval; 6056254Sroot { 60654620Smckusick struct nargs { 6076254Sroot char *fname; 60842441Smckusick int mode; 60942441Smckusick int crtmode; 61042441Smckusick } openuap; 61142441Smckusick 61242441Smckusick openuap.fname = uap->fname; 61342441Smckusick openuap.crtmode = uap->fmode; 61442441Smckusick openuap.mode = O_WRONLY | O_CREAT | O_TRUNC; 61547540Skarels return (open(p, &openuap, retval)); 61642441Smckusick } 61742955Smckusick #endif /* COMPAT_43 */ 61842441Smckusick 61942441Smckusick /* 62049365Smckusick * Mknod system call. 62142441Smckusick */ 62242441Smckusick /* ARGSUSED */ 62342441Smckusick mknod(p, uap, retval) 62445914Smckusick struct proc *p; 62542441Smckusick register struct args { 62642441Smckusick char *fname; 6276254Sroot int fmode; 6286254Sroot int dev; 62942441Smckusick } *uap; 63042441Smckusick int *retval; 63142441Smckusick { 63237741Smckusick register struct vnode *vp; 63337741Smckusick struct vattr vattr; 63437741Smckusick int error; 63547540Skarels struct nameidata nd; 6366254Sroot 63747540Skarels if (error = suser(p->p_ucred, &p->p_acflag)) 63847540Skarels return (error); 63952322Smckusick NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->fname, p); 64052322Smckusick if (error = namei(&nd)) 64147540Skarels return (error); 64252322Smckusick vp = nd.ni_vp; 64337741Smckusick if (vp != NULL) { 64437741Smckusick error = EEXIST; 64512756Ssam goto out; 6466254Sroot } 64741362Smckusick VATTR_NULL(&vattr); 64840635Smckusick switch (uap->fmode & S_IFMT) { 64912756Ssam 65040635Smckusick case S_IFMT: /* used by badsect to flag bad sectors */ 65137741Smckusick vattr.va_type = VBAD; 65237741Smckusick break; 65340635Smckusick case S_IFCHR: 65437741Smckusick vattr.va_type = VCHR; 65537741Smckusick break; 65640635Smckusick case S_IFBLK: 65737741Smckusick vattr.va_type = VBLK; 65837741Smckusick break; 65937741Smckusick default: 66037741Smckusick error = EINVAL; 66137741Smckusick goto out; 6626254Sroot } 66345914Smckusick vattr.va_mode = (uap->fmode & 07777) &~ p->p_fd->fd_cmask; 66437741Smckusick vattr.va_rdev = uap->dev; 6656254Sroot out: 66642465Smckusick if (!error) { 66752322Smckusick LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 66852322Smckusick error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr); 66942465Smckusick } else { 67052322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 67152322Smckusick if (nd.ni_dvp == vp) 67252322Smckusick vrele(nd.ni_dvp); 67343344Smckusick else 67452322Smckusick vput(nd.ni_dvp); 67542465Smckusick if (vp) 67642465Smckusick vrele(vp); 67742465Smckusick } 67847540Skarels return (error); 6796254Sroot } 6806254Sroot 6816254Sroot /* 68249365Smckusick * Mkfifo system call. 68340285Smckusick */ 68442441Smckusick /* ARGSUSED */ 68542441Smckusick mkfifo(p, uap, retval) 68645914Smckusick struct proc *p; 68742441Smckusick register struct args { 68840285Smckusick char *fname; 68940285Smckusick int fmode; 69042441Smckusick } *uap; 69142441Smckusick int *retval; 69242441Smckusick { 69340285Smckusick struct vattr vattr; 69440285Smckusick int error; 69547540Skarels struct nameidata nd; 69640285Smckusick 69740285Smckusick #ifndef FIFO 69847540Skarels return (EOPNOTSUPP); 69940285Smckusick #else 70052322Smckusick NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->fname, p); 70152322Smckusick if (error = namei(&nd)) 70247540Skarels return (error); 70352322Smckusick if (nd.ni_vp != NULL) { 70452322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 70552322Smckusick if (nd.ni_dvp == nd.ni_vp) 70652322Smckusick vrele(nd.ni_dvp); 70743344Smckusick else 70852322Smckusick vput(nd.ni_dvp); 70952322Smckusick vrele(nd.ni_vp); 71047540Skarels return (EEXIST); 71140285Smckusick } 71245785Sbostic VATTR_NULL(&vattr); 71345785Sbostic vattr.va_type = VFIFO; 71445914Smckusick vattr.va_mode = (uap->fmode & 07777) &~ p->p_fd->fd_cmask; 71552322Smckusick LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 71652322Smckusick return (VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr)); 71740285Smckusick #endif /* FIFO */ 71840285Smckusick } 71940285Smckusick 72040285Smckusick /* 72149365Smckusick * Link system call. 7226254Sroot */ 72342441Smckusick /* ARGSUSED */ 72442441Smckusick link(p, uap, retval) 72545914Smckusick struct proc *p; 72642441Smckusick register struct args { 7276254Sroot char *target; 7286254Sroot char *linkname; 72942441Smckusick } *uap; 73042441Smckusick int *retval; 73142441Smckusick { 73237741Smckusick register struct vnode *vp, *xp; 73337741Smckusick int error; 73447540Skarels struct nameidata nd; 7356254Sroot 73652322Smckusick NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->target, p); 73752322Smckusick if (error = namei(&nd)) 73847540Skarels return (error); 73952322Smckusick vp = nd.ni_vp; 74037741Smckusick if (vp->v_type == VDIR && 74147540Skarels (error = suser(p->p_ucred, &p->p_acflag))) 74237741Smckusick goto out1; 74352322Smckusick nd.ni_cnd.cn_nameiop = CREATE; 74452322Smckusick nd.ni_cnd.cn_flags = LOCKPARENT; 74552322Smckusick nd.ni_dirp = (caddr_t)uap->linkname; 74652322Smckusick if (error = namei(&nd)) 74737741Smckusick goto out1; 74852322Smckusick xp = nd.ni_vp; 7496254Sroot if (xp != NULL) { 75037741Smckusick error = EEXIST; 7516254Sroot goto out; 7526254Sroot } 75352322Smckusick xp = nd.ni_dvp; 7546254Sroot out: 75542465Smckusick if (!error) { 75652192Smckusick LEASE_CHECK(xp, p, p->p_ucred, LEASE_WRITE); 75752192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 75852821Smckusick error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd); 75942465Smckusick } else { 76052322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 76152322Smckusick if (nd.ni_dvp == nd.ni_vp) 76252322Smckusick vrele(nd.ni_dvp); 76343344Smckusick else 76452322Smckusick vput(nd.ni_dvp); 76552322Smckusick if (nd.ni_vp) 76652322Smckusick vrele(nd.ni_vp); 76742465Smckusick } 76837741Smckusick out1: 76937741Smckusick vrele(vp); 77047540Skarels return (error); 7716254Sroot } 7726254Sroot 7736254Sroot /* 77449365Smckusick * Make a symbolic link. 7756254Sroot */ 77642441Smckusick /* ARGSUSED */ 77742441Smckusick symlink(p, uap, retval) 77845914Smckusick struct proc *p; 77942441Smckusick register struct args { 7806254Sroot char *target; 7816254Sroot char *linkname; 78242441Smckusick } *uap; 78342441Smckusick int *retval; 78442441Smckusick { 78537741Smckusick struct vattr vattr; 78637741Smckusick char *target; 78737741Smckusick int error; 78847540Skarels struct nameidata nd; 7896254Sroot 79037741Smckusick MALLOC(target, char *, MAXPATHLEN, M_NAMEI, M_WAITOK); 79137741Smckusick if (error = copyinstr(uap->target, target, MAXPATHLEN, (u_int *)0)) 79242465Smckusick goto out; 79352322Smckusick NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->linkname, p); 79452322Smckusick if (error = namei(&nd)) 79542465Smckusick goto out; 79652322Smckusick if (nd.ni_vp) { 79752322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 79852322Smckusick if (nd.ni_dvp == nd.ni_vp) 79952322Smckusick vrele(nd.ni_dvp); 80043344Smckusick else 80152322Smckusick vput(nd.ni_dvp); 80252322Smckusick vrele(nd.ni_vp); 80337741Smckusick error = EEXIST; 80437741Smckusick goto out; 8056254Sroot } 80641362Smckusick VATTR_NULL(&vattr); 80745914Smckusick vattr.va_mode = 0777 &~ p->p_fd->fd_cmask; 80852322Smckusick LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 80952322Smckusick error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr, target); 81037741Smckusick out: 81137741Smckusick FREE(target, M_NAMEI); 81247540Skarels return (error); 8136254Sroot } 8146254Sroot 8156254Sroot /* 81649365Smckusick * Delete a name from the filesystem. 8176254Sroot */ 81842441Smckusick /* ARGSUSED */ 81942441Smckusick unlink(p, uap, retval) 82045914Smckusick struct proc *p; 82142441Smckusick struct args { 82252322Smckusick char *name; 82342441Smckusick } *uap; 82442441Smckusick int *retval; 8256254Sroot { 82637741Smckusick register struct vnode *vp; 82737741Smckusick int error; 82847540Skarels struct nameidata nd; 8296254Sroot 83052322Smckusick NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE, uap->name, p); 83152322Smckusick if (error = namei(&nd)) 83247540Skarels return (error); 83352322Smckusick vp = nd.ni_vp; 83437741Smckusick if (vp->v_type == VDIR && 83547540Skarels (error = suser(p->p_ucred, &p->p_acflag))) 8366254Sroot goto out; 8376254Sroot /* 83849365Smckusick * The root of a mounted filesystem cannot be deleted. 8396254Sroot */ 84037741Smckusick if (vp->v_flag & VROOT) { 84137741Smckusick error = EBUSY; 8426254Sroot goto out; 8436254Sroot } 84445738Smckusick (void) vnode_pager_uncache(vp); 8456254Sroot out: 84642465Smckusick if (!error) { 84752322Smckusick LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 84852192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 84952322Smckusick error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); 85042465Smckusick } else { 85152322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 85252322Smckusick if (nd.ni_dvp == vp) 85352322Smckusick vrele(nd.ni_dvp); 85443344Smckusick else 85552322Smckusick vput(nd.ni_dvp); 85642465Smckusick vput(vp); 85742465Smckusick } 85847540Skarels return (error); 8596254Sroot } 8606254Sroot 86154348Smckusick #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 8626254Sroot /* 86349365Smckusick * Seek system call. 8646254Sroot */ 86542441Smckusick lseek(p, uap, retval) 86645914Smckusick struct proc *p; 86742441Smckusick register struct args { 86837741Smckusick int fdes; 86953468Smckusick long off; 87053468Smckusick int sbase; 87153468Smckusick } *uap; 87253468Smckusick long *retval; 87353468Smckusick { 87453468Smckusick struct nargs { 87553468Smckusick int fdes; 8766254Sroot off_t off; 8776254Sroot int sbase; 87853468Smckusick } nuap; 87953468Smckusick quad_t qret; 88053468Smckusick int error; 88153468Smckusick 88253468Smckusick nuap.fdes = uap->fdes; 88353468Smckusick nuap.off = uap->off; 88453468Smckusick nuap.sbase = uap->sbase; 88553759Smckusick error = __lseek(p, &nuap, &qret); 88653468Smckusick *retval = qret; 88753468Smckusick return (error); 88853468Smckusick } 88954348Smckusick #endif /* COMPAT_43 || COMPAT_SUNOS */ 89053468Smckusick 89153468Smckusick /* 89253468Smckusick * Seek system call. 89353468Smckusick */ 89453759Smckusick __lseek(p, uap, retval) 89553468Smckusick struct proc *p; 89653468Smckusick register struct args { 89753468Smckusick int fdes; 89853468Smckusick off_t off; 89953468Smckusick int sbase; 90042441Smckusick } *uap; 90142441Smckusick off_t *retval; 90242441Smckusick { 90347540Skarels struct ucred *cred = p->p_ucred; 90445914Smckusick register struct filedesc *fdp = p->p_fd; 90542441Smckusick register struct file *fp; 90637741Smckusick struct vattr vattr; 90737741Smckusick int error; 9086254Sroot 90947540Skarels if ((unsigned)uap->fdes >= fdp->fd_nfiles || 91047688Skarels (fp = fdp->fd_ofiles[uap->fdes]) == NULL) 91147540Skarels return (EBADF); 91237741Smckusick if (fp->f_type != DTYPE_VNODE) 91347540Skarels return (ESPIPE); 91413878Ssam switch (uap->sbase) { 91513878Ssam 91613878Ssam case L_INCR: 91713878Ssam fp->f_offset += uap->off; 91813878Ssam break; 91913878Ssam 92013878Ssam case L_XTND: 92137741Smckusick if (error = VOP_GETATTR((struct vnode *)fp->f_data, 92248026Smckusick &vattr, cred, p)) 92347540Skarels return (error); 92437741Smckusick fp->f_offset = uap->off + vattr.va_size; 92513878Ssam break; 92613878Ssam 92713878Ssam case L_SET: 92813878Ssam fp->f_offset = uap->off; 92913878Ssam break; 93013878Ssam 93113878Ssam default: 93247540Skarels return (EINVAL); 93313878Ssam } 93442441Smckusick *retval = fp->f_offset; 93547540Skarels return (0); 9366254Sroot } 9376254Sroot 9386254Sroot /* 93949365Smckusick * Check access permissions. 9406254Sroot */ 94142441Smckusick /* ARGSUSED */ 94242441Smckusick saccess(p, uap, retval) 94345914Smckusick struct proc *p; 94442441Smckusick register struct args { 9456254Sroot char *fname; 9466254Sroot int fmode; 94742441Smckusick } *uap; 94842441Smckusick int *retval; 94942441Smckusick { 95047540Skarels register struct ucred *cred = p->p_ucred; 95137741Smckusick register struct vnode *vp; 95237741Smckusick int error, mode, svuid, svgid; 95347540Skarels struct nameidata nd; 9546254Sroot 95542441Smckusick svuid = cred->cr_uid; 95642441Smckusick svgid = cred->cr_groups[0]; 95747540Skarels cred->cr_uid = p->p_cred->p_ruid; 95847540Skarels cred->cr_groups[0] = p->p_cred->p_rgid; 95952322Smckusick NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 96052322Smckusick if (error = namei(&nd)) 96137741Smckusick goto out1; 96252322Smckusick vp = nd.ni_vp; 96337741Smckusick /* 96437741Smckusick * fmode == 0 means only check for exist 96537741Smckusick */ 96637741Smckusick if (uap->fmode) { 96737741Smckusick mode = 0; 96837741Smckusick if (uap->fmode & R_OK) 96937741Smckusick mode |= VREAD; 97037741Smckusick if (uap->fmode & W_OK) 97137741Smckusick mode |= VWRITE; 97237741Smckusick if (uap->fmode & X_OK) 97337741Smckusick mode |= VEXEC; 97439543Smckusick if ((mode & VWRITE) == 0 || (error = vn_writechk(vp)) == 0) 97548026Smckusick error = VOP_ACCESS(vp, mode, cred, p); 9766254Sroot } 97737741Smckusick vput(vp); 97837741Smckusick out1: 97942441Smckusick cred->cr_uid = svuid; 98042441Smckusick cred->cr_groups[0] = svgid; 98147540Skarels return (error); 9826254Sroot } 9836254Sroot 98454348Smckusick #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 9856254Sroot /* 98649365Smckusick * Stat system call. 98749365Smckusick * This version follows links. 98837Sbill */ 98942441Smckusick /* ARGSUSED */ 99053759Smckusick ostat(p, uap, retval) 99145914Smckusick struct proc *p; 99242441Smckusick register struct args { 99342441Smckusick char *fname; 99453468Smckusick struct ostat *ub; 99553468Smckusick } *uap; 99653468Smckusick int *retval; 99753468Smckusick { 99853468Smckusick struct stat sb; 99953468Smckusick struct ostat osb; 100053468Smckusick int error; 100153468Smckusick struct nameidata nd; 100253468Smckusick 100353468Smckusick NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 100453468Smckusick if (error = namei(&nd)) 100553468Smckusick return (error); 100653468Smckusick error = vn_stat(nd.ni_vp, &sb, p); 100753468Smckusick vput(nd.ni_vp); 100853468Smckusick if (error) 100953468Smckusick return (error); 101053468Smckusick cvtstat(&sb, &osb); 101153468Smckusick error = copyout((caddr_t)&osb, (caddr_t)uap->ub, sizeof (osb)); 101253468Smckusick return (error); 101353468Smckusick } 101453468Smckusick 101553468Smckusick /* 101653468Smckusick * Lstat system call. 101753468Smckusick * This version does not follow links. 101853468Smckusick */ 101953468Smckusick /* ARGSUSED */ 102053759Smckusick olstat(p, uap, retval) 102153468Smckusick struct proc *p; 102253468Smckusick register struct args { 102353468Smckusick char *fname; 102453468Smckusick struct ostat *ub; 102553468Smckusick } *uap; 102653468Smckusick int *retval; 102753468Smckusick { 102853468Smckusick struct stat sb; 102953468Smckusick struct ostat osb; 103053468Smckusick int error; 103153468Smckusick struct nameidata nd; 103253468Smckusick 103353468Smckusick NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 103453468Smckusick if (error = namei(&nd)) 103553468Smckusick return (error); 103653468Smckusick error = vn_stat(nd.ni_vp, &sb, p); 103753468Smckusick vput(nd.ni_vp); 103853468Smckusick if (error) 103953468Smckusick return (error); 104053468Smckusick cvtstat(&sb, &osb); 104153468Smckusick error = copyout((caddr_t)&osb, (caddr_t)uap->ub, sizeof (osb)); 104253468Smckusick return (error); 104353468Smckusick } 104453468Smckusick 104553468Smckusick /* 104653468Smckusick * convert from an old to a new stat structure. 104753468Smckusick */ 104853468Smckusick cvtstat(st, ost) 104953468Smckusick struct stat *st; 105053468Smckusick struct ostat *ost; 105153468Smckusick { 105253468Smckusick 105353468Smckusick ost->st_dev = st->st_dev; 105453468Smckusick ost->st_ino = st->st_ino; 105553468Smckusick ost->st_mode = st->st_mode; 105653468Smckusick ost->st_nlink = st->st_nlink; 105753468Smckusick ost->st_uid = st->st_uid; 105853468Smckusick ost->st_gid = st->st_gid; 105953468Smckusick ost->st_rdev = st->st_rdev; 106053468Smckusick if (st->st_size < (quad_t)1 << 32) 106153468Smckusick ost->st_size = st->st_size; 106253468Smckusick else 106353468Smckusick ost->st_size = -2; 106453468Smckusick ost->st_atime = st->st_atime; 106553468Smckusick ost->st_mtime = st->st_mtime; 106653468Smckusick ost->st_ctime = st->st_ctime; 106753468Smckusick ost->st_blksize = st->st_blksize; 106853468Smckusick ost->st_blocks = st->st_blocks; 106953468Smckusick ost->st_flags = st->st_flags; 107053468Smckusick ost->st_gen = st->st_gen; 107153468Smckusick } 107254348Smckusick #endif /* COMPAT_43 || COMPAT_SUNOS */ 107353468Smckusick 107453468Smckusick /* 107553468Smckusick * Stat system call. 107653468Smckusick * This version follows links. 107753468Smckusick */ 107853468Smckusick /* ARGSUSED */ 107953759Smckusick stat(p, uap, retval) 108053468Smckusick struct proc *p; 108153468Smckusick register struct args { 108253468Smckusick char *fname; 108342441Smckusick struct stat *ub; 108442441Smckusick } *uap; 108542441Smckusick int *retval; 108637Sbill { 108742441Smckusick struct stat sb; 108842441Smckusick int error; 108947540Skarels struct nameidata nd; 109037Sbill 109152322Smckusick NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 109252322Smckusick if (error = namei(&nd)) 109347540Skarels return (error); 109452322Smckusick error = vn_stat(nd.ni_vp, &sb, p); 109552322Smckusick vput(nd.ni_vp); 109642441Smckusick if (error) 109747540Skarels return (error); 109842441Smckusick error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb)); 109947540Skarels return (error); 110037Sbill } 110137Sbill 110237Sbill /* 110349365Smckusick * Lstat system call. 110449365Smckusick * This version does not follow links. 11055992Swnj */ 110642441Smckusick /* ARGSUSED */ 110753759Smckusick lstat(p, uap, retval) 110845914Smckusick struct proc *p; 110942441Smckusick register struct args { 11105992Swnj char *fname; 111112756Ssam struct stat *ub; 111242441Smckusick } *uap; 111342441Smckusick int *retval; 111442441Smckusick { 111512756Ssam struct stat sb; 111637741Smckusick int error; 111747540Skarels struct nameidata nd; 11185992Swnj 111952322Smckusick NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 112052322Smckusick if (error = namei(&nd)) 112147540Skarels return (error); 112252322Smckusick error = vn_stat(nd.ni_vp, &sb, p); 112352322Smckusick vput(nd.ni_vp); 112437741Smckusick if (error) 112547540Skarels return (error); 112637741Smckusick error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb)); 112747540Skarels return (error); 11285992Swnj } 11295992Swnj 11305992Swnj /* 113149365Smckusick * Return target name of a symbolic link. 113237Sbill */ 113342441Smckusick /* ARGSUSED */ 113442441Smckusick readlink(p, uap, retval) 113545914Smckusick struct proc *p; 113642441Smckusick register struct args { 11375992Swnj char *name; 11385992Swnj char *buf; 11395992Swnj int count; 114042441Smckusick } *uap; 114142441Smckusick int *retval; 114242441Smckusick { 114337741Smckusick register struct vnode *vp; 114437741Smckusick struct iovec aiov; 114537741Smckusick struct uio auio; 114637741Smckusick int error; 114747540Skarels struct nameidata nd; 11485992Swnj 114952322Smckusick NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, uap->name, p); 115052322Smckusick if (error = namei(&nd)) 115147540Skarels return (error); 115252322Smckusick vp = nd.ni_vp; 115337741Smckusick if (vp->v_type != VLNK) { 115437741Smckusick error = EINVAL; 11555992Swnj goto out; 11565992Swnj } 115737741Smckusick aiov.iov_base = uap->buf; 115837741Smckusick aiov.iov_len = uap->count; 115937741Smckusick auio.uio_iov = &aiov; 116037741Smckusick auio.uio_iovcnt = 1; 116137741Smckusick auio.uio_offset = 0; 116237741Smckusick auio.uio_rw = UIO_READ; 116337741Smckusick auio.uio_segflg = UIO_USERSPACE; 116448026Smckusick auio.uio_procp = p; 116537741Smckusick auio.uio_resid = uap->count; 116647540Skarels error = VOP_READLINK(vp, &auio, p->p_ucred); 11675992Swnj out: 116837741Smckusick vput(vp); 116942441Smckusick *retval = uap->count - auio.uio_resid; 117047540Skarels return (error); 11715992Swnj } 11725992Swnj 11739167Ssam /* 117438259Smckusick * Change flags of a file given path name. 117538259Smckusick */ 117642441Smckusick /* ARGSUSED */ 117742441Smckusick chflags(p, uap, retval) 117845914Smckusick struct proc *p; 117942441Smckusick register struct args { 118038259Smckusick char *fname; 118138259Smckusick int flags; 118242441Smckusick } *uap; 118342441Smckusick int *retval; 118442441Smckusick { 118538259Smckusick register struct vnode *vp; 118638259Smckusick struct vattr vattr; 118738259Smckusick int error; 118847540Skarels struct nameidata nd; 118938259Smckusick 119052322Smckusick NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 119152322Smckusick if (error = namei(&nd)) 119247540Skarels return (error); 119352322Smckusick vp = nd.ni_vp; 119441400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 119538259Smckusick error = EROFS; 119638259Smckusick goto out; 119738259Smckusick } 119845785Sbostic VATTR_NULL(&vattr); 119945785Sbostic vattr.va_flags = uap->flags; 120052192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 120148026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 120238259Smckusick out: 120338259Smckusick vput(vp); 120447540Skarels return (error); 120538259Smckusick } 120638259Smckusick 120738259Smckusick /* 120838259Smckusick * Change flags of a file given a file descriptor. 120938259Smckusick */ 121042441Smckusick /* ARGSUSED */ 121142441Smckusick fchflags(p, uap, retval) 121245914Smckusick struct proc *p; 121342441Smckusick register struct args { 121438259Smckusick int fd; 121538259Smckusick int flags; 121642441Smckusick } *uap; 121742441Smckusick int *retval; 121842441Smckusick { 121938259Smckusick struct vattr vattr; 122038259Smckusick struct vnode *vp; 122138259Smckusick struct file *fp; 122238259Smckusick int error; 122338259Smckusick 122445914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 122547540Skarels return (error); 122638259Smckusick vp = (struct vnode *)fp->f_data; 122738259Smckusick VOP_LOCK(vp); 122841400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 122938259Smckusick error = EROFS; 123038259Smckusick goto out; 123138259Smckusick } 123245785Sbostic VATTR_NULL(&vattr); 123345785Sbostic vattr.va_flags = uap->flags; 123452192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 123548026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 123638259Smckusick out: 123738259Smckusick VOP_UNLOCK(vp); 123847540Skarels return (error); 123938259Smckusick } 124038259Smckusick 124138259Smckusick /* 12429167Ssam * Change mode of a file given path name. 12439167Ssam */ 124442441Smckusick /* ARGSUSED */ 124542441Smckusick chmod(p, uap, retval) 124645914Smckusick struct proc *p; 124742441Smckusick register struct args { 12486254Sroot char *fname; 12496254Sroot int fmode; 125042441Smckusick } *uap; 125142441Smckusick int *retval; 125242441Smckusick { 125337741Smckusick register struct vnode *vp; 125437741Smckusick struct vattr vattr; 125537741Smckusick int error; 125647540Skarels struct nameidata nd; 12575992Swnj 125852322Smckusick NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 125952322Smckusick if (error = namei(&nd)) 126047540Skarels return (error); 126152322Smckusick vp = nd.ni_vp; 126241400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 126337741Smckusick error = EROFS; 126437741Smckusick goto out; 126537741Smckusick } 126645785Sbostic VATTR_NULL(&vattr); 126745785Sbostic vattr.va_mode = uap->fmode & 07777; 126852192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 126948026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 127037741Smckusick out: 127137741Smckusick vput(vp); 127247540Skarels return (error); 12737701Ssam } 12747439Sroot 12759167Ssam /* 12769167Ssam * Change mode of a file given a file descriptor. 12779167Ssam */ 127842441Smckusick /* ARGSUSED */ 127942441Smckusick fchmod(p, uap, retval) 128045914Smckusick struct proc *p; 128142441Smckusick register struct args { 12827701Ssam int fd; 12837701Ssam int fmode; 128442441Smckusick } *uap; 128542441Smckusick int *retval; 128642441Smckusick { 128737741Smckusick struct vattr vattr; 128837741Smckusick struct vnode *vp; 128937741Smckusick struct file *fp; 129037741Smckusick int error; 12917701Ssam 129245914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 129347540Skarels return (error); 129437741Smckusick vp = (struct vnode *)fp->f_data; 129537741Smckusick VOP_LOCK(vp); 129641400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 129737741Smckusick error = EROFS; 129837741Smckusick goto out; 12997439Sroot } 130045785Sbostic VATTR_NULL(&vattr); 130145785Sbostic vattr.va_mode = uap->fmode & 07777; 130252192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 130348026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 130437741Smckusick out: 130537741Smckusick VOP_UNLOCK(vp); 130647540Skarels return (error); 13075992Swnj } 13085992Swnj 13099167Ssam /* 13109167Ssam * Set ownership given a path name. 13119167Ssam */ 131242441Smckusick /* ARGSUSED */ 131342441Smckusick chown(p, uap, retval) 131445914Smckusick struct proc *p; 131542441Smckusick register struct args { 13166254Sroot char *fname; 13176254Sroot int uid; 13186254Sroot int gid; 131942441Smckusick } *uap; 132042441Smckusick int *retval; 132142441Smckusick { 132237741Smckusick register struct vnode *vp; 132337741Smckusick struct vattr vattr; 132437741Smckusick int error; 132547540Skarels struct nameidata nd; 132637Sbill 132752322Smckusick NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 132852322Smckusick if (error = namei(&nd)) 132947540Skarels return (error); 133052322Smckusick vp = nd.ni_vp; 133141400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 133237741Smckusick error = EROFS; 133337741Smckusick goto out; 133437741Smckusick } 133545785Sbostic VATTR_NULL(&vattr); 133645785Sbostic vattr.va_uid = uap->uid; 133745785Sbostic vattr.va_gid = uap->gid; 133852192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 133948026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 134037741Smckusick out: 134137741Smckusick vput(vp); 134247540Skarels return (error); 13437701Ssam } 13447439Sroot 13459167Ssam /* 13469167Ssam * Set ownership given a file descriptor. 13479167Ssam */ 134842441Smckusick /* ARGSUSED */ 134942441Smckusick fchown(p, uap, retval) 135045914Smckusick struct proc *p; 135142441Smckusick register struct args { 13527701Ssam int fd; 13537701Ssam int uid; 13547701Ssam int gid; 135542441Smckusick } *uap; 135642441Smckusick int *retval; 135742441Smckusick { 135837741Smckusick struct vattr vattr; 135937741Smckusick struct vnode *vp; 136037741Smckusick struct file *fp; 136137741Smckusick int error; 13627701Ssam 136345914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 136447540Skarels return (error); 136537741Smckusick vp = (struct vnode *)fp->f_data; 136637741Smckusick VOP_LOCK(vp); 136741400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 136837741Smckusick error = EROFS; 136937741Smckusick goto out; 137037741Smckusick } 137145785Sbostic VATTR_NULL(&vattr); 137245785Sbostic vattr.va_uid = uap->uid; 137345785Sbostic vattr.va_gid = uap->gid; 137452192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 137548026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 137637741Smckusick out: 137737741Smckusick VOP_UNLOCK(vp); 137847540Skarels return (error); 13797701Ssam } 13807701Ssam 138142441Smckusick /* 138242441Smckusick * Set the access and modification times of a file. 138342441Smckusick */ 138442441Smckusick /* ARGSUSED */ 138542441Smckusick utimes(p, uap, retval) 138645914Smckusick struct proc *p; 138742441Smckusick register struct args { 138811811Ssam char *fname; 138911811Ssam struct timeval *tptr; 139042441Smckusick } *uap; 139142441Smckusick int *retval; 139242441Smckusick { 139337741Smckusick register struct vnode *vp; 139411811Ssam struct timeval tv[2]; 139537741Smckusick struct vattr vattr; 139637741Smckusick int error; 139747540Skarels struct nameidata nd; 139811811Ssam 139937741Smckusick if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv))) 140047540Skarels return (error); 140152322Smckusick NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 140252322Smckusick if (error = namei(&nd)) 140347540Skarels return (error); 140452322Smckusick vp = nd.ni_vp; 140541400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 140637741Smckusick error = EROFS; 140737741Smckusick goto out; 140821015Smckusick } 140945785Sbostic VATTR_NULL(&vattr); 141054100Smckusick vattr.va_atime.ts_sec = tv[0].tv_sec; 141154100Smckusick vattr.va_atime.ts_nsec = tv[0].tv_usec * 1000; 141254100Smckusick vattr.va_mtime.ts_sec = tv[1].tv_sec; 141354100Smckusick vattr.va_mtime.ts_nsec = tv[1].tv_usec * 1000; 141452192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 141548026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 141637741Smckusick out: 141737741Smckusick vput(vp); 141847540Skarels return (error); 141911811Ssam } 142011811Ssam 142154348Smckusick #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 14229167Ssam /* 14239167Ssam * Truncate a file given its path name. 14249167Ssam */ 142542441Smckusick /* ARGSUSED */ 142642441Smckusick truncate(p, uap, retval) 142745914Smckusick struct proc *p; 142842441Smckusick register struct args { 14297701Ssam char *fname; 143053468Smckusick long length; 143153468Smckusick } *uap; 143253468Smckusick int *retval; 143353468Smckusick { 143453468Smckusick struct nargs { 143553468Smckusick char *fname; 143626473Skarels off_t length; 143753468Smckusick } nuap; 143853468Smckusick 143953468Smckusick nuap.fname = uap->fname; 144053468Smckusick nuap.length = uap->length; 144153759Smckusick return (__truncate(p, &nuap, retval)); 144253468Smckusick } 144353468Smckusick 144453468Smckusick /* 144553468Smckusick * Truncate a file given a file descriptor. 144653468Smckusick */ 144753468Smckusick /* ARGSUSED */ 144853468Smckusick ftruncate(p, uap, retval) 144953468Smckusick struct proc *p; 145053468Smckusick register struct args { 145153468Smckusick int fd; 145253468Smckusick long length; 145342441Smckusick } *uap; 145442441Smckusick int *retval; 145542441Smckusick { 145653468Smckusick struct nargs { 145753468Smckusick int fd; 145853468Smckusick off_t length; 145953468Smckusick } nuap; 146053468Smckusick 146153468Smckusick nuap.fd = uap->fd; 146253468Smckusick nuap.length = uap->length; 146353759Smckusick return (__ftruncate(p, &nuap, retval)); 146453468Smckusick } 146554348Smckusick #endif /* COMPAT_43 || COMPAT_SUNOS */ 146653468Smckusick 146753468Smckusick /* 146853468Smckusick * Truncate a file given its path name. 146953468Smckusick */ 147053468Smckusick /* ARGSUSED */ 147153759Smckusick __truncate(p, uap, retval) 147253468Smckusick struct proc *p; 147353468Smckusick register struct args { 147453468Smckusick char *fname; 147553468Smckusick off_t length; 147653468Smckusick } *uap; 147753468Smckusick int *retval; 147853468Smckusick { 147937741Smckusick register struct vnode *vp; 148037741Smckusick struct vattr vattr; 148137741Smckusick int error; 148247540Skarels struct nameidata nd; 14837701Ssam 148452322Smckusick NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 148552322Smckusick if (error = namei(&nd)) 148647540Skarels return (error); 148752322Smckusick vp = nd.ni_vp; 148837741Smckusick if (vp->v_type == VDIR) { 148937741Smckusick error = EISDIR; 149037741Smckusick goto out; 14917701Ssam } 149238399Smckusick if ((error = vn_writechk(vp)) || 149348026Smckusick (error = VOP_ACCESS(vp, VWRITE, p->p_ucred, p))) 149437741Smckusick goto out; 149545785Sbostic VATTR_NULL(&vattr); 149645785Sbostic vattr.va_size = uap->length; 149752192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 149848026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 149937741Smckusick out: 150037741Smckusick vput(vp); 150147540Skarels return (error); 15027701Ssam } 15037701Ssam 15049167Ssam /* 15059167Ssam * Truncate a file given a file descriptor. 15069167Ssam */ 150742441Smckusick /* ARGSUSED */ 150853759Smckusick __ftruncate(p, uap, retval) 150945914Smckusick struct proc *p; 151042441Smckusick register struct args { 15117701Ssam int fd; 151226473Skarels off_t length; 151342441Smckusick } *uap; 151442441Smckusick int *retval; 151542441Smckusick { 151637741Smckusick struct vattr vattr; 151737741Smckusick struct vnode *vp; 15187701Ssam struct file *fp; 151937741Smckusick int error; 15207701Ssam 152145914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 152247540Skarels return (error); 152337741Smckusick if ((fp->f_flag & FWRITE) == 0) 152447540Skarels return (EINVAL); 152537741Smckusick vp = (struct vnode *)fp->f_data; 152637741Smckusick VOP_LOCK(vp); 152737741Smckusick if (vp->v_type == VDIR) { 152837741Smckusick error = EISDIR; 152937741Smckusick goto out; 15307701Ssam } 153138399Smckusick if (error = vn_writechk(vp)) 153237741Smckusick goto out; 153345785Sbostic VATTR_NULL(&vattr); 153445785Sbostic vattr.va_size = uap->length; 153552192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 153648026Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred, p); 153737741Smckusick out: 153837741Smckusick VOP_UNLOCK(vp); 153947540Skarels return (error); 15407701Ssam } 15417701Ssam 15429167Ssam /* 15439167Ssam * Synch an open file. 15449167Ssam */ 154542441Smckusick /* ARGSUSED */ 154642441Smckusick fsync(p, uap, retval) 154745914Smckusick struct proc *p; 154842441Smckusick struct args { 154942441Smckusick int fd; 155042441Smckusick } *uap; 155142441Smckusick int *retval; 15529167Ssam { 155339592Smckusick register struct vnode *vp; 15549167Ssam struct file *fp; 155537741Smckusick int error; 15569167Ssam 155745914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 155847540Skarels return (error); 155939592Smckusick vp = (struct vnode *)fp->f_data; 156039592Smckusick VOP_LOCK(vp); 156154441Smckusick error = VOP_FSYNC(vp, fp->f_cred, MNT_WAIT, p); 156239592Smckusick VOP_UNLOCK(vp); 156347540Skarels return (error); 15649167Ssam } 15659167Ssam 15669167Ssam /* 15679167Ssam * Rename system call. 15689167Ssam * 15699167Ssam * Source and destination must either both be directories, or both 15709167Ssam * not be directories. If target is a directory, it must be empty. 15719167Ssam */ 157242441Smckusick /* ARGSUSED */ 157342441Smckusick rename(p, uap, retval) 157445914Smckusick struct proc *p; 157542441Smckusick register struct args { 15767701Ssam char *from; 15777701Ssam char *to; 157842441Smckusick } *uap; 157942441Smckusick int *retval; 158042441Smckusick { 158137741Smckusick register struct vnode *tvp, *fvp, *tdvp; 158249735Smckusick struct nameidata fromnd, tond; 158337741Smckusick int error; 15847701Ssam 158552322Smckusick NDINIT(&fromnd, DELETE, WANTPARENT | SAVESTART, UIO_USERSPACE, 158652322Smckusick uap->from, p); 158752322Smckusick if (error = namei(&fromnd)) 158847540Skarels return (error); 158949735Smckusick fvp = fromnd.ni_vp; 159052322Smckusick NDINIT(&tond, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART, 159152322Smckusick UIO_USERSPACE, uap->to, p); 159252322Smckusick if (error = namei(&tond)) { 159352230Sheideman VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 159449735Smckusick vrele(fromnd.ni_dvp); 159542465Smckusick vrele(fvp); 159642465Smckusick goto out1; 159742465Smckusick } 159837741Smckusick tdvp = tond.ni_dvp; 159937741Smckusick tvp = tond.ni_vp; 160037741Smckusick if (tvp != NULL) { 160137741Smckusick if (fvp->v_type == VDIR && tvp->v_type != VDIR) { 160239242Sbostic error = ENOTDIR; 160337741Smckusick goto out; 160437741Smckusick } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) { 160539242Sbostic error = EISDIR; 160637741Smckusick goto out; 16079167Ssam } 16089167Ssam } 160939286Smckusick if (fvp == tdvp) 161037741Smckusick error = EINVAL; 161139286Smckusick /* 161249735Smckusick * If source is the same as the destination (that is the 161349735Smckusick * same inode number with the same name in the same directory), 161439286Smckusick * then there is nothing to do. 161539286Smckusick */ 161649735Smckusick if (fvp == tvp && fromnd.ni_dvp == tdvp && 161752322Smckusick fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen && 161852322Smckusick !bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr, 161952322Smckusick fromnd.ni_cnd.cn_namelen)) 162039286Smckusick error = -1; 162137741Smckusick out: 162242465Smckusick if (!error) { 162352192Smckusick LEASE_CHECK(tdvp, p, p->p_ucred, LEASE_WRITE); 162452192Smckusick if (fromnd.ni_dvp != tdvp) 162552192Smckusick LEASE_CHECK(fromnd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 162652192Smckusick if (tvp) 162752192Smckusick LEASE_CHECK(tvp, p, p->p_ucred, LEASE_WRITE); 162852230Sheideman error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd, 162952230Sheideman tond.ni_dvp, tond.ni_vp, &tond.ni_cnd); 163042465Smckusick } else { 163152230Sheideman VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd); 163243344Smckusick if (tdvp == tvp) 163343344Smckusick vrele(tdvp); 163443344Smckusick else 163543344Smckusick vput(tdvp); 163642465Smckusick if (tvp) 163742465Smckusick vput(tvp); 163852230Sheideman VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 163949735Smckusick vrele(fromnd.ni_dvp); 164042465Smckusick vrele(fvp); 16419167Ssam } 164249735Smckusick vrele(tond.ni_startdir); 164352322Smckusick FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI); 164437741Smckusick out1: 164549735Smckusick vrele(fromnd.ni_startdir); 164652322Smckusick FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI); 164739286Smckusick if (error == -1) 164847540Skarels return (0); 164947540Skarels return (error); 16507701Ssam } 16517701Ssam 16527535Sroot /* 165349365Smckusick * Mkdir system call. 165412756Ssam */ 165542441Smckusick /* ARGSUSED */ 165642441Smckusick mkdir(p, uap, retval) 165745914Smckusick struct proc *p; 165842441Smckusick register struct args { 165912756Ssam char *name; 166012756Ssam int dmode; 166142441Smckusick } *uap; 166242441Smckusick int *retval; 166342441Smckusick { 166437741Smckusick register struct vnode *vp; 166537741Smckusick struct vattr vattr; 166637741Smckusick int error; 166747540Skarels struct nameidata nd; 166812756Ssam 166952322Smckusick NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->name, p); 167052322Smckusick if (error = namei(&nd)) 167147540Skarels return (error); 167252322Smckusick vp = nd.ni_vp; 167337741Smckusick if (vp != NULL) { 167452322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 167552322Smckusick if (nd.ni_dvp == vp) 167652322Smckusick vrele(nd.ni_dvp); 167743344Smckusick else 167852322Smckusick vput(nd.ni_dvp); 167942465Smckusick vrele(vp); 168047540Skarels return (EEXIST); 168112756Ssam } 168241362Smckusick VATTR_NULL(&vattr); 168337741Smckusick vattr.va_type = VDIR; 168445914Smckusick vattr.va_mode = (uap->dmode & 0777) &~ p->p_fd->fd_cmask; 168552322Smckusick LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 168652322Smckusick error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr); 168738145Smckusick if (!error) 168852322Smckusick vput(nd.ni_vp); 168947540Skarels return (error); 169012756Ssam } 169112756Ssam 169212756Ssam /* 169312756Ssam * Rmdir system call. 169412756Ssam */ 169542441Smckusick /* ARGSUSED */ 169642441Smckusick rmdir(p, uap, retval) 169745914Smckusick struct proc *p; 169842441Smckusick struct args { 169942441Smckusick char *name; 170042441Smckusick } *uap; 170142441Smckusick int *retval; 170212756Ssam { 170337741Smckusick register struct vnode *vp; 170437741Smckusick int error; 170547540Skarels struct nameidata nd; 170612756Ssam 170752322Smckusick NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE, uap->name, p); 170852322Smckusick if (error = namei(&nd)) 170947540Skarels return (error); 171052322Smckusick vp = nd.ni_vp; 171137741Smckusick if (vp->v_type != VDIR) { 171237741Smckusick error = ENOTDIR; 171312756Ssam goto out; 171412756Ssam } 171512756Ssam /* 171637741Smckusick * No rmdir "." please. 171712756Ssam */ 171852322Smckusick if (nd.ni_dvp == vp) { 171937741Smckusick error = EINVAL; 172012756Ssam goto out; 172112756Ssam } 172212756Ssam /* 172349365Smckusick * The root of a mounted filesystem cannot be deleted. 172412756Ssam */ 172537741Smckusick if (vp->v_flag & VROOT) 172637741Smckusick error = EBUSY; 172712756Ssam out: 172842465Smckusick if (!error) { 172952322Smckusick LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 173052192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 173152322Smckusick error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); 173242465Smckusick } else { 173352322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 173452322Smckusick if (nd.ni_dvp == vp) 173552322Smckusick vrele(nd.ni_dvp); 173643344Smckusick else 173752322Smckusick vput(nd.ni_dvp); 173842465Smckusick vput(vp); 173942465Smckusick } 174047540Skarels return (error); 174112756Ssam } 174212756Ssam 174354620Smckusick #ifdef COMPAT_43 174437741Smckusick /* 174549365Smckusick * Read a block of directory entries in a file system independent format. 174637741Smckusick */ 174754620Smckusick ogetdirentries(p, uap, retval) 174854620Smckusick struct proc *p; 174954620Smckusick register struct args { 175054620Smckusick int fd; 175154620Smckusick char *buf; 175254620Smckusick unsigned count; 175354620Smckusick long *basep; 175454620Smckusick } *uap; 175554620Smckusick int *retval; 175654620Smckusick { 175754620Smckusick register struct vnode *vp; 175854620Smckusick struct file *fp; 175954620Smckusick struct uio auio, kuio; 176054620Smckusick struct iovec aiov, kiov; 176154620Smckusick struct dirent *dp, *edp; 176254620Smckusick caddr_t dirbuf; 176354620Smckusick int error, readcnt; 176454620Smckusick off_t off; 176554620Smckusick 176654620Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 176754620Smckusick return (error); 176854620Smckusick if ((fp->f_flag & FREAD) == 0) 176954620Smckusick return (EBADF); 177054620Smckusick vp = (struct vnode *)fp->f_data; 177154620Smckusick if (vp->v_type != VDIR) 177254620Smckusick return (EINVAL); 177354620Smckusick aiov.iov_base = uap->buf; 177454620Smckusick aiov.iov_len = uap->count; 177554620Smckusick auio.uio_iov = &aiov; 177654620Smckusick auio.uio_iovcnt = 1; 177754620Smckusick auio.uio_rw = UIO_READ; 177854620Smckusick auio.uio_segflg = UIO_USERSPACE; 177954620Smckusick auio.uio_procp = p; 178054620Smckusick auio.uio_resid = uap->count; 178154620Smckusick VOP_LOCK(vp); 178254620Smckusick auio.uio_offset = off = fp->f_offset; 178354620Smckusick # if (BYTE_ORDER != LITTLE_ENDIAN) 178454620Smckusick if (vp->v_mount->mnt_maxsymlinklen <= 0) 178554620Smckusick error = VOP_READDIR(vp, &auio, fp->f_cred); 178654620Smckusick else 178754620Smckusick # endif 178854620Smckusick { 178954620Smckusick kuio = auio; 179054620Smckusick kuio.uio_iov = &kiov; 179154620Smckusick kuio.uio_segflg = UIO_SYSSPACE; 179254620Smckusick kiov.iov_len = uap->count; 179354620Smckusick MALLOC(dirbuf, caddr_t, uap->count, M_TEMP, M_WAITOK); 179454620Smckusick kiov.iov_base = dirbuf; 179554620Smckusick error = VOP_READDIR(vp, &kuio, fp->f_cred); 179654620Smckusick if (error == 0) { 179754620Smckusick readcnt = uap->count - kuio.uio_resid; 179854620Smckusick edp = (struct dirent *)&dirbuf[readcnt]; 179954620Smckusick for (dp = (struct dirent *)dirbuf; dp < edp; ) { 180054620Smckusick dp->d_type = 0; 180154620Smckusick # if (BYTE_ORDER == LITTLE_ENDIAN) 180254620Smckusick { u_char tmp = dp->d_namlen; 180354620Smckusick dp->d_namlen = dp->d_type; 180454620Smckusick dp->d_type = tmp; } 180554620Smckusick # endif 180654620Smckusick if (dp->d_reclen > 0) { 180754620Smckusick dp = (struct dirent *) 180854620Smckusick ((char *)dp + dp->d_reclen); 180954620Smckusick } else { 181054620Smckusick error = EIO; 181154620Smckusick break; 181254620Smckusick } 181354620Smckusick } 181454620Smckusick if (dp >= edp) 181554620Smckusick error = uiomove(dirbuf, readcnt, &auio); 181654620Smckusick } 181754620Smckusick FREE(dirbuf, M_TEMP); 181854620Smckusick } 181954620Smckusick fp->f_offset = auio.uio_offset; 182054620Smckusick VOP_UNLOCK(vp); 182154620Smckusick if (error) 182254620Smckusick return (error); 182354620Smckusick error = copyout((caddr_t)&off, (caddr_t)uap->basep, sizeof(long)); 182454620Smckusick *retval = uap->count - auio.uio_resid; 182554620Smckusick return (error); 182654620Smckusick } 182754620Smckusick #endif 182854620Smckusick 182954620Smckusick /* 183054620Smckusick * Read a block of directory entries in a file system independent format. 183154620Smckusick */ 183242441Smckusick getdirentries(p, uap, retval) 183345914Smckusick struct proc *p; 183442441Smckusick register struct args { 183537741Smckusick int fd; 183637741Smckusick char *buf; 183737741Smckusick unsigned count; 183837741Smckusick long *basep; 183942441Smckusick } *uap; 184042441Smckusick int *retval; 184142441Smckusick { 184239592Smckusick register struct vnode *vp; 184316540Ssam struct file *fp; 184437741Smckusick struct uio auio; 184537741Smckusick struct iovec aiov; 184638129Smckusick off_t off; 184754441Smckusick int error; 184812756Ssam 184945914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 185047540Skarels return (error); 185137741Smckusick if ((fp->f_flag & FREAD) == 0) 185247540Skarels return (EBADF); 185339592Smckusick vp = (struct vnode *)fp->f_data; 185439592Smckusick if (vp->v_type != VDIR) 185547540Skarels return (EINVAL); 185637741Smckusick aiov.iov_base = uap->buf; 185737741Smckusick aiov.iov_len = uap->count; 185837741Smckusick auio.uio_iov = &aiov; 185937741Smckusick auio.uio_iovcnt = 1; 186037741Smckusick auio.uio_rw = UIO_READ; 186137741Smckusick auio.uio_segflg = UIO_USERSPACE; 186248026Smckusick auio.uio_procp = p; 186337741Smckusick auio.uio_resid = uap->count; 186439592Smckusick VOP_LOCK(vp); 186539592Smckusick auio.uio_offset = off = fp->f_offset; 186654441Smckusick error = VOP_READDIR(vp, &auio, fp->f_cred); 186739592Smckusick fp->f_offset = auio.uio_offset; 186839592Smckusick VOP_UNLOCK(vp); 186939592Smckusick if (error) 187047540Skarels return (error); 187139592Smckusick error = copyout((caddr_t)&off, (caddr_t)uap->basep, sizeof(long)); 187242441Smckusick *retval = uap->count - auio.uio_resid; 187347540Skarels return (error); 187412756Ssam } 187512756Ssam 187612756Ssam /* 187749365Smckusick * Set the mode mask for creation of filesystem nodes. 187812756Ssam */ 187942441Smckusick mode_t 188042441Smckusick umask(p, uap, retval) 188145914Smckusick struct proc *p; 188242441Smckusick struct args { 188342441Smckusick int mask; 188442441Smckusick } *uap; 188542441Smckusick int *retval; 188612756Ssam { 188745914Smckusick register struct filedesc *fdp = p->p_fd; 188812756Ssam 188945914Smckusick *retval = fdp->fd_cmask; 189045914Smckusick fdp->fd_cmask = uap->mask & 07777; 189147540Skarels return (0); 189212756Ssam } 189337741Smckusick 189439566Smarc /* 189539566Smarc * Void all references to file by ripping underlying filesystem 189639566Smarc * away from vnode. 189739566Smarc */ 189842441Smckusick /* ARGSUSED */ 189942441Smckusick revoke(p, uap, retval) 190045914Smckusick struct proc *p; 190142441Smckusick register struct args { 190239566Smarc char *fname; 190342441Smckusick } *uap; 190442441Smckusick int *retval; 190542441Smckusick { 190639566Smarc register struct vnode *vp; 190739566Smarc struct vattr vattr; 190839566Smarc int error; 190947540Skarels struct nameidata nd; 191039566Smarc 191152322Smckusick NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->fname, p); 191252322Smckusick if (error = namei(&nd)) 191347540Skarels return (error); 191452322Smckusick vp = nd.ni_vp; 191539566Smarc if (vp->v_type != VCHR && vp->v_type != VBLK) { 191639566Smarc error = EINVAL; 191739566Smarc goto out; 191839566Smarc } 191948026Smckusick if (error = VOP_GETATTR(vp, &vattr, p->p_ucred, p)) 192039566Smarc goto out; 192147540Skarels if (p->p_ucred->cr_uid != vattr.va_uid && 192247540Skarels (error = suser(p->p_ucred, &p->p_acflag))) 192339566Smarc goto out; 192439805Smckusick if (vp->v_usecount > 1 || (vp->v_flag & VALIASED)) 192539632Smckusick vgoneall(vp); 192639566Smarc out: 192739566Smarc vrele(vp); 192847540Skarels return (error); 192939566Smarc } 193039566Smarc 193149365Smckusick /* 193249365Smckusick * Convert a user file descriptor to a kernel file entry. 193349365Smckusick */ 193445914Smckusick getvnode(fdp, fdes, fpp) 193545914Smckusick struct filedesc *fdp; 193637741Smckusick struct file **fpp; 193737741Smckusick int fdes; 193837741Smckusick { 193937741Smckusick struct file *fp; 194037741Smckusick 194147540Skarels if ((unsigned)fdes >= fdp->fd_nfiles || 194247688Skarels (fp = fdp->fd_ofiles[fdes]) == NULL) 194337741Smckusick return (EBADF); 194437741Smckusick if (fp->f_type != DTYPE_VNODE) 194537741Smckusick return (EINVAL); 194637741Smckusick *fpp = fp; 194737741Smckusick return (0); 194837741Smckusick } 1949