123405Smckusick /* 237741Smckusick * Copyright (c) 1989 The Regents of the University of California. 337741Smckusick * All rights reserved. 423405Smckusick * 544459Sbostic * %sccs.include.redist.c% 637741Smckusick * 7*54620Smckusick * @(#)vfs_syscalls.c 7.89 (Berkeley) 07/02/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" 22*54620Smckusick #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 { 4353548Sheideman USES_VOP_UNLOCK; 4439335Smckusick register struct vnode *vp; 4539335Smckusick register struct mount *mp; 4640111Smckusick int error, flag; 4747540Skarels struct nameidata nd; 486254Sroot 4937741Smckusick /* 5037741Smckusick * Must be super user 5137741Smckusick */ 5247540Skarels if (error = suser(p->p_ucred, &p->p_acflag)) 5347540Skarels return (error); 5437741Smckusick /* 5537741Smckusick * Get vnode to be covered 5637741Smckusick */ 5752322Smckusick NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->dir, p); 5852322Smckusick if (error = namei(&nd)) 5947540Skarels return (error); 6052322Smckusick vp = nd.ni_vp; 6141400Smckusick if (uap->flags & MNT_UPDATE) { 6239335Smckusick if ((vp->v_flag & VROOT) == 0) { 6339335Smckusick vput(vp); 6447540Skarels return (EINVAL); 6539335Smckusick } 6639335Smckusick mp = vp->v_mount; 6739335Smckusick /* 6839335Smckusick * We allow going from read-only to read-write, 6939335Smckusick * but not from read-write to read-only. 7039335Smckusick */ 7141400Smckusick if ((mp->mnt_flag & MNT_RDONLY) == 0 && 7241400Smckusick (uap->flags & MNT_RDONLY) != 0) { 7339335Smckusick vput(vp); 7447540Skarels return (EOPNOTSUPP); /* Needs translation */ 7539335Smckusick } 7641400Smckusick flag = mp->mnt_flag; 7741400Smckusick mp->mnt_flag |= MNT_UPDATE; 7839335Smckusick VOP_UNLOCK(vp); 7939335Smckusick goto update; 8039335Smckusick } 8139805Smckusick if (vp->v_usecount != 1) { 8237741Smckusick vput(vp); 8347540Skarels return (EBUSY); 8437741Smckusick } 8554441Smckusick if (error = vinvalbuf(vp, 1, p->p_ucred, p)) 8654441Smckusick return (error); 8737741Smckusick if (vp->v_type != VDIR) { 8837741Smckusick vput(vp); 8947540Skarels return (ENOTDIR); 9037741Smckusick } 9139741Smckusick if ((unsigned long)uap->type > MOUNT_MAXTYPE || 9237741Smckusick vfssw[uap->type] == (struct vfsops *)0) { 9337741Smckusick vput(vp); 9447540Skarels return (ENODEV); 9537741Smckusick } 9637741Smckusick 9737741Smckusick /* 9839335Smckusick * Allocate and initialize the file system. 9937741Smckusick */ 10037741Smckusick mp = (struct mount *)malloc((u_long)sizeof(struct mount), 10137741Smckusick M_MOUNT, M_WAITOK); 10254172Smckusick bzero((char *)mp, (u_long)sizeof(struct mount)); 10341400Smckusick mp->mnt_op = vfssw[uap->type]; 10439335Smckusick if (error = vfs_lock(mp)) { 10539335Smckusick free((caddr_t)mp, M_MOUNT); 10639335Smckusick vput(vp); 10747540Skarels return (error); 10839335Smckusick } 10939335Smckusick if (vp->v_mountedhere != (struct mount *)0) { 11039335Smckusick vfs_unlock(mp); 11139335Smckusick free((caddr_t)mp, M_MOUNT); 11239335Smckusick vput(vp); 11347540Skarels return (EBUSY); 11439335Smckusick } 11539335Smckusick vp->v_mountedhere = mp; 11641400Smckusick mp->mnt_vnodecovered = vp; 11739335Smckusick update: 11839335Smckusick /* 11939335Smckusick * Set the mount level flags. 12039335Smckusick */ 12141400Smckusick if (uap->flags & MNT_RDONLY) 12241400Smckusick mp->mnt_flag |= MNT_RDONLY; 12339335Smckusick else 12441400Smckusick mp->mnt_flag &= ~MNT_RDONLY; 12541400Smckusick if (uap->flags & MNT_NOSUID) 12641400Smckusick mp->mnt_flag |= MNT_NOSUID; 12739335Smckusick else 12841400Smckusick mp->mnt_flag &= ~MNT_NOSUID; 12941400Smckusick if (uap->flags & MNT_NOEXEC) 13041400Smckusick mp->mnt_flag |= MNT_NOEXEC; 13139335Smckusick else 13241400Smckusick mp->mnt_flag &= ~MNT_NOEXEC; 13341400Smckusick if (uap->flags & MNT_NODEV) 13441400Smckusick mp->mnt_flag |= MNT_NODEV; 13539335Smckusick else 13641400Smckusick mp->mnt_flag &= ~MNT_NODEV; 13741400Smckusick if (uap->flags & MNT_SYNCHRONOUS) 13841400Smckusick mp->mnt_flag |= MNT_SYNCHRONOUS; 13939335Smckusick else 14041400Smckusick mp->mnt_flag &= ~MNT_SYNCHRONOUS; 14139335Smckusick /* 14239335Smckusick * Mount the filesystem. 14339335Smckusick */ 14452322Smckusick error = VFS_MOUNT(mp, uap->dir, uap->data, &nd, p); 14541400Smckusick if (mp->mnt_flag & MNT_UPDATE) { 14641400Smckusick mp->mnt_flag &= ~MNT_UPDATE; 14739335Smckusick vrele(vp); 14840111Smckusick if (error) 14941400Smckusick mp->mnt_flag = flag; 15047540Skarels return (error); 15139335Smckusick } 15240110Smckusick /* 15340110Smckusick * Put the new filesystem on the mount list after root. 15440110Smckusick */ 15541400Smckusick mp->mnt_next = rootfs->mnt_next; 15641400Smckusick mp->mnt_prev = rootfs; 15741400Smckusick rootfs->mnt_next = mp; 15841400Smckusick mp->mnt_next->mnt_prev = mp; 15937741Smckusick cache_purge(vp); 16037741Smckusick if (!error) { 16139335Smckusick VOP_UNLOCK(vp); 16237741Smckusick vfs_unlock(mp); 16348026Smckusick error = VFS_START(mp, 0, p); 16437741Smckusick } else { 16537741Smckusick vfs_remove(mp); 16637741Smckusick free((caddr_t)mp, M_MOUNT); 16739335Smckusick vput(vp); 16837741Smckusick } 16947540Skarels return (error); 1706254Sroot } 1716254Sroot 1729167Ssam /* 17337741Smckusick * Unmount system call. 17437741Smckusick * 17537741Smckusick * Note: unmount takes a path to the vnode mounted on as argument, 17637741Smckusick * not special file (as before). 1779167Ssam */ 17842441Smckusick /* ARGSUSED */ 17942441Smckusick unmount(p, uap, retval) 18045914Smckusick struct proc *p; 18142441Smckusick register struct args { 18237741Smckusick char *pathp; 18337741Smckusick int flags; 18442441Smckusick } *uap; 18542441Smckusick int *retval; 18642441Smckusick { 18737741Smckusick register struct vnode *vp; 18839356Smckusick struct mount *mp; 18937741Smckusick int error; 19047540Skarels struct nameidata nd; 1916254Sroot 19237741Smckusick /* 19337741Smckusick * Must be super user 19437741Smckusick */ 19547540Skarels if (error = suser(p->p_ucred, &p->p_acflag)) 19647540Skarels return (error); 19737741Smckusick 19852322Smckusick NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->pathp, p); 19952322Smckusick if (error = namei(&nd)) 20047540Skarels return (error); 20152322Smckusick vp = nd.ni_vp; 20237741Smckusick /* 20337741Smckusick * Must be the root of the filesystem 20437741Smckusick */ 20537741Smckusick if ((vp->v_flag & VROOT) == 0) { 20637741Smckusick vput(vp); 20747540Skarels return (EINVAL); 20837741Smckusick } 20937741Smckusick mp = vp->v_mount; 21037741Smckusick vput(vp); 21148026Smckusick return (dounmount(mp, uap->flags, p)); 21239356Smckusick } 21339356Smckusick 21439356Smckusick /* 21539356Smckusick * Do an unmount. 21639356Smckusick */ 21748026Smckusick dounmount(mp, flags, p) 21839356Smckusick register struct mount *mp; 21939356Smckusick int flags; 22048026Smckusick struct proc *p; 22139356Smckusick { 22239356Smckusick struct vnode *coveredvp; 22339356Smckusick int error; 22439356Smckusick 22541400Smckusick coveredvp = mp->mnt_vnodecovered; 22641298Smckusick if (vfs_busy(mp)) 22741298Smckusick return (EBUSY); 22841400Smckusick mp->mnt_flag |= MNT_UNMOUNT; 22937741Smckusick if (error = vfs_lock(mp)) 23039356Smckusick return (error); 23137741Smckusick 23245738Smckusick vnode_pager_umount(mp); /* release cached vnodes */ 23337741Smckusick cache_purgevfs(mp); /* remove cache entries for this file sys */ 23454441Smckusick if ((error = VFS_SYNC(mp, MNT_WAIT, p->p_ucred, p)) == 0 || 23554441Smckusick (flags & MNT_FORCE)) 23648026Smckusick error = VFS_UNMOUNT(mp, flags, p); 23741400Smckusick mp->mnt_flag &= ~MNT_UNMOUNT; 23841298Smckusick vfs_unbusy(mp); 23937741Smckusick if (error) { 24037741Smckusick vfs_unlock(mp); 24137741Smckusick } else { 24237741Smckusick vrele(coveredvp); 24337741Smckusick vfs_remove(mp); 24452287Smckusick if (mp->mnt_mounth != NULL) 24552287Smckusick panic("unmount: dangling vnode"); 24637741Smckusick free((caddr_t)mp, M_MOUNT); 24737741Smckusick } 24839356Smckusick return (error); 2496254Sroot } 2506254Sroot 2519167Ssam /* 25237741Smckusick * Sync system call. 25337741Smckusick * Sync each mounted filesystem. 2549167Ssam */ 25539491Smckusick /* ARGSUSED */ 25642441Smckusick sync(p, uap, retval) 25745914Smckusick struct proc *p; 25847540Skarels void *uap; 25942441Smckusick int *retval; 2606254Sroot { 26137741Smckusick register struct mount *mp; 26241298Smckusick struct mount *omp; 26337741Smckusick 26437741Smckusick mp = rootfs; 26537741Smckusick do { 26640343Smckusick /* 26740343Smckusick * The lock check below is to avoid races with mount 26840343Smckusick * and unmount. 26940343Smckusick */ 27041400Smckusick if ((mp->mnt_flag & (MNT_MLOCK|MNT_RDONLY|MNT_MPBUSY)) == 0 && 27141298Smckusick !vfs_busy(mp)) { 27254441Smckusick VFS_SYNC(mp, MNT_NOWAIT, p->p_ucred, p); 27341298Smckusick omp = mp; 27441400Smckusick mp = mp->mnt_next; 27541298Smckusick vfs_unbusy(omp); 27641298Smckusick } else 27741400Smckusick mp = mp->mnt_next; 27837741Smckusick } while (mp != rootfs); 27947688Skarels return (0); 28037741Smckusick } 28137741Smckusick 28237741Smckusick /* 28349365Smckusick * Operate on filesystem quotas. 28441298Smckusick */ 28542441Smckusick /* ARGSUSED */ 28642441Smckusick quotactl(p, uap, retval) 28745914Smckusick struct proc *p; 28842441Smckusick register struct args { 28941298Smckusick char *path; 29041298Smckusick int cmd; 29141298Smckusick int uid; 29241298Smckusick caddr_t arg; 29342441Smckusick } *uap; 29442441Smckusick int *retval; 29542441Smckusick { 29641298Smckusick register struct mount *mp; 29741298Smckusick int error; 29847540Skarels struct nameidata nd; 29941298Smckusick 30052322Smckusick NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); 30152322Smckusick if (error = namei(&nd)) 30247540Skarels return (error); 30352322Smckusick mp = nd.ni_vp->v_mount; 30452322Smckusick vrele(nd.ni_vp); 30548026Smckusick return (VFS_QUOTACTL(mp, uap->cmd, uap->uid, uap->arg, p)); 30641298Smckusick } 30741298Smckusick 30841298Smckusick /* 30949365Smckusick * Get filesystem statistics. 31037741Smckusick */ 31142441Smckusick /* ARGSUSED */ 31242441Smckusick statfs(p, uap, retval) 31345914Smckusick struct proc *p; 31442441Smckusick register struct args { 31537741Smckusick char *path; 31637741Smckusick struct statfs *buf; 31742441Smckusick } *uap; 31842441Smckusick int *retval; 31942441Smckusick { 32039464Smckusick register struct mount *mp; 32140343Smckusick register struct statfs *sp; 32237741Smckusick int error; 32347540Skarels struct nameidata nd; 32437741Smckusick 32552322Smckusick NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); 32652322Smckusick if (error = namei(&nd)) 32747540Skarels return (error); 32852322Smckusick mp = nd.ni_vp->v_mount; 32941400Smckusick sp = &mp->mnt_stat; 33052322Smckusick vrele(nd.ni_vp); 33148026Smckusick if (error = VFS_STATFS(mp, sp, p)) 33247540Skarels return (error); 33341400Smckusick sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 33447540Skarels return (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp))); 33537741Smckusick } 33637741Smckusick 33742441Smckusick /* 33849365Smckusick * Get filesystem statistics. 33942441Smckusick */ 34042441Smckusick /* ARGSUSED */ 34142441Smckusick fstatfs(p, uap, retval) 34245914Smckusick struct proc *p; 34342441Smckusick register struct args { 34437741Smckusick int fd; 34537741Smckusick struct statfs *buf; 34642441Smckusick } *uap; 34742441Smckusick int *retval; 34842441Smckusick { 34937741Smckusick struct file *fp; 35039464Smckusick struct mount *mp; 35140343Smckusick register struct statfs *sp; 35237741Smckusick int error; 35337741Smckusick 35445914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 35547540Skarels return (error); 35639464Smckusick mp = ((struct vnode *)fp->f_data)->v_mount; 35741400Smckusick sp = &mp->mnt_stat; 35848026Smckusick if (error = VFS_STATFS(mp, sp, p)) 35947540Skarels return (error); 36041400Smckusick sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 36147540Skarels return (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp))); 36237741Smckusick } 36337741Smckusick 36437741Smckusick /* 36549365Smckusick * Get statistics on all filesystems. 36638270Smckusick */ 36742441Smckusick getfsstat(p, uap, retval) 36845914Smckusick struct proc *p; 36942441Smckusick register struct args { 37038270Smckusick struct statfs *buf; 37138270Smckusick long bufsize; 37240343Smckusick int flags; 37342441Smckusick } *uap; 37442441Smckusick int *retval; 37542441Smckusick { 37638270Smckusick register struct mount *mp; 37740343Smckusick register struct statfs *sp; 37839606Smckusick caddr_t sfsp; 37938270Smckusick long count, maxcount, error; 38038270Smckusick 38138270Smckusick maxcount = uap->bufsize / sizeof(struct statfs); 38239606Smckusick sfsp = (caddr_t)uap->buf; 38338270Smckusick mp = rootfs; 38438270Smckusick count = 0; 38538270Smckusick do { 38641400Smckusick if (sfsp && count < maxcount && 38741400Smckusick ((mp->mnt_flag & MNT_MLOCK) == 0)) { 38841400Smckusick sp = &mp->mnt_stat; 38940343Smckusick /* 39040343Smckusick * If MNT_NOWAIT is specified, do not refresh the 39140343Smckusick * fsstat cache. MNT_WAIT overrides MNT_NOWAIT. 39240343Smckusick */ 39340343Smckusick if (((uap->flags & MNT_NOWAIT) == 0 || 39440343Smckusick (uap->flags & MNT_WAIT)) && 39548026Smckusick (error = VFS_STATFS(mp, sp, p))) { 39641400Smckusick mp = mp->mnt_prev; 39739607Smckusick continue; 39839607Smckusick } 39941400Smckusick sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 40040343Smckusick if (error = copyout((caddr_t)sp, sfsp, sizeof(*sp))) 40147540Skarels return (error); 40240343Smckusick sfsp += sizeof(*sp); 40338270Smckusick } 40439606Smckusick count++; 40541400Smckusick mp = mp->mnt_prev; 40638270Smckusick } while (mp != rootfs); 40738270Smckusick if (sfsp && count > maxcount) 40842441Smckusick *retval = maxcount; 40938270Smckusick else 41042441Smckusick *retval = count; 41147540Skarels return (0); 41238270Smckusick } 41338270Smckusick 41438270Smckusick /* 41538259Smckusick * Change current working directory to a given file descriptor. 41638259Smckusick */ 41742441Smckusick /* ARGSUSED */ 41842441Smckusick fchdir(p, uap, retval) 41945914Smckusick struct proc *p; 42042441Smckusick struct args { 42142441Smckusick int fd; 42242441Smckusick } *uap; 42342441Smckusick int *retval; 42438259Smckusick { 42553548Sheideman USES_VOP_ACCESS; 42653548Sheideman USES_VOP_LOCK; 42753548Sheideman USES_VOP_UNLOCK; 42845914Smckusick register struct filedesc *fdp = p->p_fd; 42938259Smckusick register struct vnode *vp; 43038259Smckusick struct file *fp; 43138259Smckusick int error; 43238259Smckusick 43345914Smckusick if (error = getvnode(fdp, uap->fd, &fp)) 43447540Skarels return (error); 43538259Smckusick vp = (struct vnode *)fp->f_data; 43638259Smckusick VOP_LOCK(vp); 43738259Smckusick if (vp->v_type != VDIR) 43838259Smckusick error = ENOTDIR; 43938259Smckusick else 44048026Smckusick error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p); 44138259Smckusick VOP_UNLOCK(vp); 44239860Smckusick if (error) 44347540Skarels return (error); 44439860Smckusick VREF(vp); 44545914Smckusick vrele(fdp->fd_cdir); 44645914Smckusick fdp->fd_cdir = vp; 44747540Skarels return (0); 44838259Smckusick } 44938259Smckusick 45038259Smckusick /* 45137741Smckusick * Change current working directory (``.''). 45237741Smckusick */ 45342441Smckusick /* ARGSUSED */ 45442441Smckusick chdir(p, uap, retval) 45545914Smckusick struct proc *p; 45642441Smckusick struct args { 45742441Smckusick char *fname; 45842441Smckusick } *uap; 45942441Smckusick int *retval; 46037741Smckusick { 46145914Smckusick register struct filedesc *fdp = p->p_fd; 46237741Smckusick int error; 46347540Skarels struct nameidata nd; 4646254Sroot 46552322Smckusick NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 46652781Sralph if (error = chdirec(&nd, p)) 46747540Skarels return (error); 46845914Smckusick vrele(fdp->fd_cdir); 46952322Smckusick fdp->fd_cdir = nd.ni_vp; 47047540Skarels return (0); 47137741Smckusick } 4726254Sroot 47337741Smckusick /* 47437741Smckusick * Change notion of root (``/'') directory. 47537741Smckusick */ 47642441Smckusick /* ARGSUSED */ 47742441Smckusick chroot(p, uap, retval) 47845914Smckusick struct proc *p; 47942441Smckusick struct args { 48042441Smckusick char *fname; 48142441Smckusick } *uap; 48242441Smckusick int *retval; 48337741Smckusick { 48445914Smckusick register struct filedesc *fdp = p->p_fd; 48537741Smckusick int error; 48647540Skarels struct nameidata nd; 48737741Smckusick 48847540Skarels if (error = suser(p->p_ucred, &p->p_acflag)) 48947540Skarels return (error); 49052322Smckusick NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 49152781Sralph if (error = chdirec(&nd, p)) 49247540Skarels return (error); 49345914Smckusick if (fdp->fd_rdir != NULL) 49445914Smckusick vrele(fdp->fd_rdir); 49552322Smckusick fdp->fd_rdir = nd.ni_vp; 49647540Skarels return (0); 4976254Sroot } 4986254Sroot 49937Sbill /* 50037741Smckusick * Common routine for chroot and chdir. 50137741Smckusick */ 50247540Skarels chdirec(ndp, p) 50352322Smckusick register struct nameidata *ndp; 50447540Skarels struct proc *p; 50537741Smckusick { 50653548Sheideman USES_VOP_ACCESS; 50753548Sheideman USES_VOP_UNLOCK; 50837741Smckusick struct vnode *vp; 50937741Smckusick int error; 51037741Smckusick 51152322Smckusick if (error = namei(ndp)) 51237741Smckusick return (error); 51337741Smckusick vp = ndp->ni_vp; 51437741Smckusick if (vp->v_type != VDIR) 51537741Smckusick error = ENOTDIR; 51637741Smckusick else 51748026Smckusick error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p); 51837741Smckusick VOP_UNLOCK(vp); 51937741Smckusick if (error) 52037741Smckusick vrele(vp); 52137741Smckusick return (error); 52237741Smckusick } 52337741Smckusick 52437741Smckusick /* 5256254Sroot * Open system call. 52642441Smckusick * Check permissions, allocate an open file structure, 52742441Smckusick * and call the device open routine if any. 5286254Sroot */ 52942441Smckusick open(p, uap, retval) 53045914Smckusick struct proc *p; 53142441Smckusick register struct args { 5326254Sroot char *fname; 5337701Ssam int mode; 53412756Ssam int crtmode; 53542441Smckusick } *uap; 53642441Smckusick int *retval; 5376254Sroot { 53853548Sheideman USES_VOP_ADVLOCK; 53953548Sheideman USES_VOP_UNLOCK; 54045914Smckusick register struct filedesc *fdp = p->p_fd; 54142441Smckusick register struct file *fp; 54250111Smckusick register struct vnode *vp; 54337741Smckusick int fmode, cmode; 54437741Smckusick struct file *nfp; 54549945Smckusick int type, indx, error; 54649945Smckusick struct flock lf; 54747540Skarels struct nameidata nd; 54837741Smckusick extern struct fileops vnops; 5496254Sroot 55045914Smckusick if (error = falloc(p, &nfp, &indx)) 55147540Skarels return (error); 55237741Smckusick fp = nfp; 55346553Skarels fmode = FFLAGS(uap->mode); 55445914Smckusick cmode = ((uap->crtmode &~ fdp->fd_cmask) & 07777) &~ S_ISVTX; 55552322Smckusick NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->fname, p); 55645202Smckusick p->p_dupfd = -indx - 1; /* XXX check for fdopen */ 55752322Smckusick if (error = vn_open(&nd, fmode, cmode)) { 55853828Spendry int dfd = p->p_dupfd; 55953828Spendry p->p_dupfd = 0; 56049980Smckusick ffree(fp); 56153828Spendry if ((error == ENODEV || error == ENXIO) && /* XXX from fdopen */ 56253828Spendry dfd >= 0 && 56353828Spendry (error = dupfdopen(fdp, indx, p->p_dupfd, 56453828Spendry fmode, error)) == 0) { 56542441Smckusick *retval = indx; 56647540Skarels return (0); 56742441Smckusick } 56840884Smckusick if (error == ERESTART) 56940884Smckusick error = EINTR; 57047688Skarels fdp->fd_ofiles[indx] = NULL; 57147540Skarels return (error); 57212756Ssam } 57353828Spendry p->p_dupfd = 0; 57452322Smckusick vp = nd.ni_vp; 57549949Smckusick fp->f_flag = fmode & FMASK; 57654348Smckusick fp->f_type = DTYPE_VNODE; 57754348Smckusick fp->f_ops = &vnops; 57854348Smckusick fp->f_data = (caddr_t)vp; 57949945Smckusick if (fmode & (O_EXLOCK | O_SHLOCK)) { 58049945Smckusick lf.l_whence = SEEK_SET; 58149945Smckusick lf.l_start = 0; 58249945Smckusick lf.l_len = 0; 58349945Smckusick if (fmode & O_EXLOCK) 58449945Smckusick lf.l_type = F_WRLCK; 58549945Smckusick else 58649945Smckusick lf.l_type = F_RDLCK; 58749945Smckusick type = F_FLOCK; 58849945Smckusick if ((fmode & FNONBLOCK) == 0) 58949945Smckusick type |= F_WAIT; 59050111Smckusick if (error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, type)) { 59150111Smckusick VOP_UNLOCK(vp); 59250111Smckusick (void) vn_close(vp, fp->f_flag, fp->f_cred, p); 59349980Smckusick ffree(fp); 59449945Smckusick fdp->fd_ofiles[indx] = NULL; 59549945Smckusick return (error); 59649945Smckusick } 59749949Smckusick fp->f_flag |= FHASLOCK; 59849945Smckusick } 59950111Smckusick VOP_UNLOCK(vp); 60042441Smckusick *retval = indx; 60147540Skarels return (0); 6026254Sroot } 6036254Sroot 60442955Smckusick #ifdef COMPAT_43 6056254Sroot /* 60642441Smckusick * Creat system call. 6076254Sroot */ 60842955Smckusick ocreat(p, uap, retval) 60942441Smckusick struct proc *p; 61042441Smckusick register struct args { 61142441Smckusick char *fname; 61242441Smckusick int fmode; 61342441Smckusick } *uap; 61442441Smckusick int *retval; 6156254Sroot { 616*54620Smckusick struct nargs { 6176254Sroot char *fname; 61842441Smckusick int mode; 61942441Smckusick int crtmode; 62042441Smckusick } openuap; 62142441Smckusick 62242441Smckusick openuap.fname = uap->fname; 62342441Smckusick openuap.crtmode = uap->fmode; 62442441Smckusick openuap.mode = O_WRONLY | O_CREAT | O_TRUNC; 62547540Skarels return (open(p, &openuap, retval)); 62642441Smckusick } 62742955Smckusick #endif /* COMPAT_43 */ 62842441Smckusick 62942441Smckusick /* 63049365Smckusick * Mknod system call. 63142441Smckusick */ 63242441Smckusick /* ARGSUSED */ 63342441Smckusick mknod(p, uap, retval) 63445914Smckusick struct proc *p; 63542441Smckusick register struct args { 63642441Smckusick char *fname; 6376254Sroot int fmode; 6386254Sroot int dev; 63942441Smckusick } *uap; 64042441Smckusick int *retval; 64142441Smckusick { 64253548Sheideman USES_VOP_ABORTOP; 64353548Sheideman USES_VOP_MKNOD; 64437741Smckusick register struct vnode *vp; 64537741Smckusick struct vattr vattr; 64637741Smckusick int error; 64747540Skarels struct nameidata nd; 6486254Sroot 64947540Skarels if (error = suser(p->p_ucred, &p->p_acflag)) 65047540Skarels return (error); 65152322Smckusick NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->fname, p); 65252322Smckusick if (error = namei(&nd)) 65347540Skarels return (error); 65452322Smckusick vp = nd.ni_vp; 65537741Smckusick if (vp != NULL) { 65637741Smckusick error = EEXIST; 65712756Ssam goto out; 6586254Sroot } 65941362Smckusick VATTR_NULL(&vattr); 66040635Smckusick switch (uap->fmode & S_IFMT) { 66112756Ssam 66240635Smckusick case S_IFMT: /* used by badsect to flag bad sectors */ 66337741Smckusick vattr.va_type = VBAD; 66437741Smckusick break; 66540635Smckusick case S_IFCHR: 66637741Smckusick vattr.va_type = VCHR; 66737741Smckusick break; 66840635Smckusick case S_IFBLK: 66937741Smckusick vattr.va_type = VBLK; 67037741Smckusick break; 67137741Smckusick default: 67237741Smckusick error = EINVAL; 67337741Smckusick goto out; 6746254Sroot } 67545914Smckusick vattr.va_mode = (uap->fmode & 07777) &~ p->p_fd->fd_cmask; 67637741Smckusick vattr.va_rdev = uap->dev; 6776254Sroot out: 67842465Smckusick if (!error) { 67952322Smckusick LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 68052322Smckusick error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr); 68142465Smckusick } else { 68252322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 68352322Smckusick if (nd.ni_dvp == vp) 68452322Smckusick vrele(nd.ni_dvp); 68543344Smckusick else 68652322Smckusick vput(nd.ni_dvp); 68742465Smckusick if (vp) 68842465Smckusick vrele(vp); 68942465Smckusick } 69047540Skarels return (error); 6916254Sroot } 6926254Sroot 6936254Sroot /* 69449365Smckusick * Mkfifo system call. 69540285Smckusick */ 69642441Smckusick /* ARGSUSED */ 69742441Smckusick mkfifo(p, uap, retval) 69845914Smckusick struct proc *p; 69942441Smckusick register struct args { 70040285Smckusick char *fname; 70140285Smckusick int fmode; 70242441Smckusick } *uap; 70342441Smckusick int *retval; 70442441Smckusick { 70553548Sheideman USES_VOP_ABORTOP; 70653548Sheideman USES_VOP_MKNOD; 70740285Smckusick struct vattr vattr; 70840285Smckusick int error; 70947540Skarels struct nameidata nd; 71040285Smckusick 71140285Smckusick #ifndef FIFO 71247540Skarels return (EOPNOTSUPP); 71340285Smckusick #else 71452322Smckusick NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->fname, p); 71552322Smckusick if (error = namei(&nd)) 71647540Skarels return (error); 71752322Smckusick if (nd.ni_vp != NULL) { 71852322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 71952322Smckusick if (nd.ni_dvp == nd.ni_vp) 72052322Smckusick vrele(nd.ni_dvp); 72143344Smckusick else 72252322Smckusick vput(nd.ni_dvp); 72352322Smckusick vrele(nd.ni_vp); 72447540Skarels return (EEXIST); 72540285Smckusick } 72645785Sbostic VATTR_NULL(&vattr); 72745785Sbostic vattr.va_type = VFIFO; 72845914Smckusick vattr.va_mode = (uap->fmode & 07777) &~ p->p_fd->fd_cmask; 72952322Smckusick LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 73052322Smckusick return (VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr)); 73140285Smckusick #endif /* FIFO */ 73240285Smckusick } 73340285Smckusick 73440285Smckusick /* 73549365Smckusick * Link system call. 7366254Sroot */ 73742441Smckusick /* ARGSUSED */ 73842441Smckusick link(p, uap, retval) 73945914Smckusick struct proc *p; 74042441Smckusick register struct args { 7416254Sroot char *target; 7426254Sroot char *linkname; 74342441Smckusick } *uap; 74442441Smckusick int *retval; 74542441Smckusick { 74653548Sheideman USES_VOP_ABORTOP; 74753548Sheideman USES_VOP_LINK; 74837741Smckusick register struct vnode *vp, *xp; 74937741Smckusick int error; 75047540Skarels struct nameidata nd; 7516254Sroot 75252322Smckusick NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->target, p); 75352322Smckusick if (error = namei(&nd)) 75447540Skarels return (error); 75552322Smckusick vp = nd.ni_vp; 75637741Smckusick if (vp->v_type == VDIR && 75747540Skarels (error = suser(p->p_ucred, &p->p_acflag))) 75837741Smckusick goto out1; 75952322Smckusick nd.ni_cnd.cn_nameiop = CREATE; 76052322Smckusick nd.ni_cnd.cn_flags = LOCKPARENT; 76152322Smckusick nd.ni_dirp = (caddr_t)uap->linkname; 76252322Smckusick if (error = namei(&nd)) 76337741Smckusick goto out1; 76452322Smckusick xp = nd.ni_vp; 7656254Sroot if (xp != NULL) { 76637741Smckusick error = EEXIST; 7676254Sroot goto out; 7686254Sroot } 76952322Smckusick xp = nd.ni_dvp; 7706254Sroot out: 77142465Smckusick if (!error) { 77252192Smckusick LEASE_CHECK(xp, p, p->p_ucred, LEASE_WRITE); 77352192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 77452821Smckusick error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd); 77542465Smckusick } else { 77652322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 77752322Smckusick if (nd.ni_dvp == nd.ni_vp) 77852322Smckusick vrele(nd.ni_dvp); 77943344Smckusick else 78052322Smckusick vput(nd.ni_dvp); 78152322Smckusick if (nd.ni_vp) 78252322Smckusick vrele(nd.ni_vp); 78342465Smckusick } 78437741Smckusick out1: 78537741Smckusick vrele(vp); 78647540Skarels return (error); 7876254Sroot } 7886254Sroot 7896254Sroot /* 79049365Smckusick * Make a symbolic link. 7916254Sroot */ 79242441Smckusick /* ARGSUSED */ 79342441Smckusick symlink(p, uap, retval) 79445914Smckusick struct proc *p; 79542441Smckusick register struct args { 7966254Sroot char *target; 7976254Sroot char *linkname; 79842441Smckusick } *uap; 79942441Smckusick int *retval; 80042441Smckusick { 80153548Sheideman USES_VOP_ABORTOP; 80253548Sheideman USES_VOP_SYMLINK; 80337741Smckusick struct vattr vattr; 80437741Smckusick char *target; 80537741Smckusick int error; 80647540Skarels struct nameidata nd; 8076254Sroot 80837741Smckusick MALLOC(target, char *, MAXPATHLEN, M_NAMEI, M_WAITOK); 80937741Smckusick if (error = copyinstr(uap->target, target, MAXPATHLEN, (u_int *)0)) 81042465Smckusick goto out; 81152322Smckusick NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->linkname, p); 81252322Smckusick if (error = namei(&nd)) 81342465Smckusick goto out; 81452322Smckusick if (nd.ni_vp) { 81552322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 81652322Smckusick if (nd.ni_dvp == nd.ni_vp) 81752322Smckusick vrele(nd.ni_dvp); 81843344Smckusick else 81952322Smckusick vput(nd.ni_dvp); 82052322Smckusick vrele(nd.ni_vp); 82137741Smckusick error = EEXIST; 82237741Smckusick goto out; 8236254Sroot } 82441362Smckusick VATTR_NULL(&vattr); 82545914Smckusick vattr.va_mode = 0777 &~ p->p_fd->fd_cmask; 82652322Smckusick LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 82752322Smckusick error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr, target); 82837741Smckusick out: 82937741Smckusick FREE(target, M_NAMEI); 83047540Skarels return (error); 8316254Sroot } 8326254Sroot 8336254Sroot /* 83449365Smckusick * Delete a name from the filesystem. 8356254Sroot */ 83642441Smckusick /* ARGSUSED */ 83742441Smckusick unlink(p, uap, retval) 83845914Smckusick struct proc *p; 83942441Smckusick struct args { 84052322Smckusick char *name; 84142441Smckusick } *uap; 84242441Smckusick int *retval; 8436254Sroot { 84453548Sheideman USES_VOP_ABORTOP; 84553548Sheideman USES_VOP_REMOVE; 84637741Smckusick register struct vnode *vp; 84737741Smckusick int error; 84847540Skarels struct nameidata nd; 8496254Sroot 85052322Smckusick NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE, uap->name, p); 85152322Smckusick if (error = namei(&nd)) 85247540Skarels return (error); 85352322Smckusick vp = nd.ni_vp; 85437741Smckusick if (vp->v_type == VDIR && 85547540Skarels (error = suser(p->p_ucred, &p->p_acflag))) 8566254Sroot goto out; 8576254Sroot /* 85849365Smckusick * The root of a mounted filesystem cannot be deleted. 8596254Sroot */ 86037741Smckusick if (vp->v_flag & VROOT) { 86137741Smckusick error = EBUSY; 8626254Sroot goto out; 8636254Sroot } 86445738Smckusick (void) vnode_pager_uncache(vp); 8656254Sroot out: 86642465Smckusick if (!error) { 86752322Smckusick LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 86852192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 86952322Smckusick error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); 87042465Smckusick } else { 87152322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 87252322Smckusick if (nd.ni_dvp == vp) 87352322Smckusick vrele(nd.ni_dvp); 87443344Smckusick else 87552322Smckusick vput(nd.ni_dvp); 87642465Smckusick vput(vp); 87742465Smckusick } 87847540Skarels return (error); 8796254Sroot } 8806254Sroot 88154348Smckusick #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 8826254Sroot /* 88349365Smckusick * Seek system call. 8846254Sroot */ 88542441Smckusick lseek(p, uap, retval) 88645914Smckusick struct proc *p; 88742441Smckusick register struct args { 88837741Smckusick int fdes; 88953468Smckusick long off; 89053468Smckusick int sbase; 89153468Smckusick } *uap; 89253468Smckusick long *retval; 89353468Smckusick { 89453468Smckusick struct nargs { 89553468Smckusick int fdes; 8966254Sroot off_t off; 8976254Sroot int sbase; 89853468Smckusick } nuap; 89953468Smckusick quad_t qret; 90053468Smckusick int error; 90153468Smckusick 90253468Smckusick nuap.fdes = uap->fdes; 90353468Smckusick nuap.off = uap->off; 90453468Smckusick nuap.sbase = uap->sbase; 90553759Smckusick error = __lseek(p, &nuap, &qret); 90653468Smckusick *retval = qret; 90753468Smckusick return (error); 90853468Smckusick } 90954348Smckusick #endif /* COMPAT_43 || COMPAT_SUNOS */ 91053468Smckusick 91153468Smckusick /* 91253468Smckusick * Seek system call. 91353468Smckusick */ 91453759Smckusick __lseek(p, uap, retval) 91553468Smckusick struct proc *p; 91653468Smckusick register struct args { 91753468Smckusick int fdes; 91853468Smckusick off_t off; 91953468Smckusick int sbase; 92042441Smckusick } *uap; 92142441Smckusick off_t *retval; 92242441Smckusick { 92353548Sheideman USES_VOP_GETATTR; 92447540Skarels struct ucred *cred = p->p_ucred; 92545914Smckusick register struct filedesc *fdp = p->p_fd; 92642441Smckusick register struct file *fp; 92737741Smckusick struct vattr vattr; 92837741Smckusick int error; 9296254Sroot 93047540Skarels if ((unsigned)uap->fdes >= fdp->fd_nfiles || 93147688Skarels (fp = fdp->fd_ofiles[uap->fdes]) == NULL) 93247540Skarels return (EBADF); 93337741Smckusick if (fp->f_type != DTYPE_VNODE) 93447540Skarels return (ESPIPE); 93513878Ssam switch (uap->sbase) { 93613878Ssam 93713878Ssam case L_INCR: 93813878Ssam fp->f_offset += uap->off; 93913878Ssam break; 94013878Ssam 94113878Ssam case L_XTND: 94237741Smckusick if (error = VOP_GETATTR((struct vnode *)fp->f_data, 94348026Smckusick &vattr, cred, p)) 94447540Skarels return (error); 94537741Smckusick fp->f_offset = uap->off + vattr.va_size; 94613878Ssam break; 94713878Ssam 94813878Ssam case L_SET: 94913878Ssam fp->f_offset = uap->off; 95013878Ssam break; 95113878Ssam 95213878Ssam default: 95347540Skarels return (EINVAL); 95413878Ssam } 95542441Smckusick *retval = fp->f_offset; 95647540Skarels return (0); 9576254Sroot } 9586254Sroot 9596254Sroot /* 96049365Smckusick * Check access permissions. 9616254Sroot */ 96242441Smckusick /* ARGSUSED */ 96342441Smckusick saccess(p, uap, retval) 96445914Smckusick struct proc *p; 96542441Smckusick register struct args { 9666254Sroot char *fname; 9676254Sroot int fmode; 96842441Smckusick } *uap; 96942441Smckusick int *retval; 97042441Smckusick { 97153548Sheideman USES_VOP_ACCESS; 97247540Skarels register struct ucred *cred = p->p_ucred; 97337741Smckusick register struct vnode *vp; 97437741Smckusick int error, mode, svuid, svgid; 97547540Skarels struct nameidata nd; 9766254Sroot 97742441Smckusick svuid = cred->cr_uid; 97842441Smckusick svgid = cred->cr_groups[0]; 97947540Skarels cred->cr_uid = p->p_cred->p_ruid; 98047540Skarels cred->cr_groups[0] = p->p_cred->p_rgid; 98152322Smckusick NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 98252322Smckusick if (error = namei(&nd)) 98337741Smckusick goto out1; 98452322Smckusick vp = nd.ni_vp; 98537741Smckusick /* 98637741Smckusick * fmode == 0 means only check for exist 98737741Smckusick */ 98837741Smckusick if (uap->fmode) { 98937741Smckusick mode = 0; 99037741Smckusick if (uap->fmode & R_OK) 99137741Smckusick mode |= VREAD; 99237741Smckusick if (uap->fmode & W_OK) 99337741Smckusick mode |= VWRITE; 99437741Smckusick if (uap->fmode & X_OK) 99537741Smckusick mode |= VEXEC; 99639543Smckusick if ((mode & VWRITE) == 0 || (error = vn_writechk(vp)) == 0) 99748026Smckusick error = VOP_ACCESS(vp, mode, cred, p); 9986254Sroot } 99937741Smckusick vput(vp); 100037741Smckusick out1: 100142441Smckusick cred->cr_uid = svuid; 100242441Smckusick cred->cr_groups[0] = svgid; 100347540Skarels return (error); 10046254Sroot } 10056254Sroot 100654348Smckusick #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 10076254Sroot /* 100849365Smckusick * Stat system call. 100949365Smckusick * This version follows links. 101037Sbill */ 101142441Smckusick /* ARGSUSED */ 101253759Smckusick ostat(p, uap, retval) 101345914Smckusick struct proc *p; 101442441Smckusick register struct args { 101542441Smckusick char *fname; 101653468Smckusick struct ostat *ub; 101753468Smckusick } *uap; 101853468Smckusick int *retval; 101953468Smckusick { 102053468Smckusick struct stat sb; 102153468Smckusick struct ostat osb; 102253468Smckusick int error; 102353468Smckusick struct nameidata nd; 102453468Smckusick 102553468Smckusick NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 102653468Smckusick if (error = namei(&nd)) 102753468Smckusick return (error); 102853468Smckusick error = vn_stat(nd.ni_vp, &sb, p); 102953468Smckusick vput(nd.ni_vp); 103053468Smckusick if (error) 103153468Smckusick return (error); 103253468Smckusick cvtstat(&sb, &osb); 103353468Smckusick error = copyout((caddr_t)&osb, (caddr_t)uap->ub, sizeof (osb)); 103453468Smckusick return (error); 103553468Smckusick } 103653468Smckusick 103753468Smckusick /* 103853468Smckusick * Lstat system call. 103953468Smckusick * This version does not follow links. 104053468Smckusick */ 104153468Smckusick /* ARGSUSED */ 104253759Smckusick olstat(p, uap, retval) 104353468Smckusick struct proc *p; 104453468Smckusick register struct args { 104553468Smckusick char *fname; 104653468Smckusick struct ostat *ub; 104753468Smckusick } *uap; 104853468Smckusick int *retval; 104953468Smckusick { 105053468Smckusick struct stat sb; 105153468Smckusick struct ostat osb; 105253468Smckusick int error; 105353468Smckusick struct nameidata nd; 105453468Smckusick 105553468Smckusick NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 105653468Smckusick if (error = namei(&nd)) 105753468Smckusick return (error); 105853468Smckusick error = vn_stat(nd.ni_vp, &sb, p); 105953468Smckusick vput(nd.ni_vp); 106053468Smckusick if (error) 106153468Smckusick return (error); 106253468Smckusick cvtstat(&sb, &osb); 106353468Smckusick error = copyout((caddr_t)&osb, (caddr_t)uap->ub, sizeof (osb)); 106453468Smckusick return (error); 106553468Smckusick } 106653468Smckusick 106753468Smckusick /* 106853468Smckusick * convert from an old to a new stat structure. 106953468Smckusick */ 107053468Smckusick cvtstat(st, ost) 107153468Smckusick struct stat *st; 107253468Smckusick struct ostat *ost; 107353468Smckusick { 107453468Smckusick 107553468Smckusick ost->st_dev = st->st_dev; 107653468Smckusick ost->st_ino = st->st_ino; 107753468Smckusick ost->st_mode = st->st_mode; 107853468Smckusick ost->st_nlink = st->st_nlink; 107953468Smckusick ost->st_uid = st->st_uid; 108053468Smckusick ost->st_gid = st->st_gid; 108153468Smckusick ost->st_rdev = st->st_rdev; 108253468Smckusick if (st->st_size < (quad_t)1 << 32) 108353468Smckusick ost->st_size = st->st_size; 108453468Smckusick else 108553468Smckusick ost->st_size = -2; 108653468Smckusick ost->st_atime = st->st_atime; 108753468Smckusick ost->st_mtime = st->st_mtime; 108853468Smckusick ost->st_ctime = st->st_ctime; 108953468Smckusick ost->st_blksize = st->st_blksize; 109053468Smckusick ost->st_blocks = st->st_blocks; 109153468Smckusick ost->st_flags = st->st_flags; 109253468Smckusick ost->st_gen = st->st_gen; 109353468Smckusick } 109454348Smckusick #endif /* COMPAT_43 || COMPAT_SUNOS */ 109553468Smckusick 109653468Smckusick /* 109753468Smckusick * Stat system call. 109853468Smckusick * This version follows links. 109953468Smckusick */ 110053468Smckusick /* ARGSUSED */ 110153759Smckusick stat(p, uap, retval) 110253468Smckusick struct proc *p; 110353468Smckusick register struct args { 110453468Smckusick char *fname; 110542441Smckusick struct stat *ub; 110642441Smckusick } *uap; 110742441Smckusick int *retval; 110837Sbill { 110942441Smckusick struct stat sb; 111042441Smckusick int error; 111147540Skarels struct nameidata nd; 111237Sbill 111352322Smckusick NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 111452322Smckusick if (error = namei(&nd)) 111547540Skarels return (error); 111652322Smckusick error = vn_stat(nd.ni_vp, &sb, p); 111752322Smckusick vput(nd.ni_vp); 111842441Smckusick if (error) 111947540Skarels return (error); 112042441Smckusick error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb)); 112147540Skarels return (error); 112237Sbill } 112337Sbill 112437Sbill /* 112549365Smckusick * Lstat system call. 112649365Smckusick * This version does not follow links. 11275992Swnj */ 112842441Smckusick /* ARGSUSED */ 112953759Smckusick lstat(p, uap, retval) 113045914Smckusick struct proc *p; 113142441Smckusick register struct args { 11325992Swnj char *fname; 113312756Ssam struct stat *ub; 113442441Smckusick } *uap; 113542441Smckusick int *retval; 113642441Smckusick { 113712756Ssam struct stat sb; 113837741Smckusick int error; 113947540Skarels struct nameidata nd; 11405992Swnj 114152322Smckusick NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 114252322Smckusick if (error = namei(&nd)) 114347540Skarels return (error); 114452322Smckusick error = vn_stat(nd.ni_vp, &sb, p); 114552322Smckusick vput(nd.ni_vp); 114637741Smckusick if (error) 114747540Skarels return (error); 114837741Smckusick error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb)); 114947540Skarels return (error); 11505992Swnj } 11515992Swnj 11525992Swnj /* 115349365Smckusick * Return target name of a symbolic link. 115437Sbill */ 115542441Smckusick /* ARGSUSED */ 115642441Smckusick readlink(p, uap, retval) 115745914Smckusick struct proc *p; 115842441Smckusick register struct args { 11595992Swnj char *name; 11605992Swnj char *buf; 11615992Swnj int count; 116242441Smckusick } *uap; 116342441Smckusick int *retval; 116442441Smckusick { 116553548Sheideman USES_VOP_READLINK; 116637741Smckusick register struct vnode *vp; 116737741Smckusick struct iovec aiov; 116837741Smckusick struct uio auio; 116937741Smckusick int error; 117047540Skarels struct nameidata nd; 11715992Swnj 117252322Smckusick NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, uap->name, p); 117352322Smckusick if (error = namei(&nd)) 117447540Skarels return (error); 117552322Smckusick vp = nd.ni_vp; 117637741Smckusick if (vp->v_type != VLNK) { 117737741Smckusick error = EINVAL; 11785992Swnj goto out; 11795992Swnj } 118037741Smckusick aiov.iov_base = uap->buf; 118137741Smckusick aiov.iov_len = uap->count; 118237741Smckusick auio.uio_iov = &aiov; 118337741Smckusick auio.uio_iovcnt = 1; 118437741Smckusick auio.uio_offset = 0; 118537741Smckusick auio.uio_rw = UIO_READ; 118637741Smckusick auio.uio_segflg = UIO_USERSPACE; 118748026Smckusick auio.uio_procp = p; 118837741Smckusick auio.uio_resid = uap->count; 118947540Skarels error = VOP_READLINK(vp, &auio, p->p_ucred); 11905992Swnj out: 119137741Smckusick vput(vp); 119242441Smckusick *retval = uap->count - auio.uio_resid; 119347540Skarels return (error); 11945992Swnj } 11955992Swnj 11969167Ssam /* 119738259Smckusick * Change flags of a file given path name. 119838259Smckusick */ 119942441Smckusick /* ARGSUSED */ 120042441Smckusick chflags(p, uap, retval) 120145914Smckusick struct proc *p; 120242441Smckusick register struct args { 120338259Smckusick char *fname; 120438259Smckusick int flags; 120542441Smckusick } *uap; 120642441Smckusick int *retval; 120742441Smckusick { 120853548Sheideman USES_VOP_SETATTR; 120938259Smckusick register struct vnode *vp; 121038259Smckusick struct vattr vattr; 121138259Smckusick int error; 121247540Skarels struct nameidata nd; 121338259Smckusick 121452322Smckusick NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 121552322Smckusick if (error = namei(&nd)) 121647540Skarels return (error); 121752322Smckusick vp = nd.ni_vp; 121841400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 121938259Smckusick error = EROFS; 122038259Smckusick goto out; 122138259Smckusick } 122245785Sbostic VATTR_NULL(&vattr); 122345785Sbostic vattr.va_flags = uap->flags; 122452192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 122548026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 122638259Smckusick out: 122738259Smckusick vput(vp); 122847540Skarels return (error); 122938259Smckusick } 123038259Smckusick 123138259Smckusick /* 123238259Smckusick * Change flags of a file given a file descriptor. 123338259Smckusick */ 123442441Smckusick /* ARGSUSED */ 123542441Smckusick fchflags(p, uap, retval) 123645914Smckusick struct proc *p; 123742441Smckusick register struct args { 123838259Smckusick int fd; 123938259Smckusick int flags; 124042441Smckusick } *uap; 124142441Smckusick int *retval; 124242441Smckusick { 124353548Sheideman USES_VOP_LOCK; 124453548Sheideman USES_VOP_SETATTR; 124553548Sheideman USES_VOP_UNLOCK; 124638259Smckusick struct vattr vattr; 124738259Smckusick struct vnode *vp; 124838259Smckusick struct file *fp; 124938259Smckusick int error; 125038259Smckusick 125145914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 125247540Skarels return (error); 125338259Smckusick vp = (struct vnode *)fp->f_data; 125438259Smckusick VOP_LOCK(vp); 125541400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 125638259Smckusick error = EROFS; 125738259Smckusick goto out; 125838259Smckusick } 125945785Sbostic VATTR_NULL(&vattr); 126045785Sbostic vattr.va_flags = uap->flags; 126152192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 126248026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 126338259Smckusick out: 126438259Smckusick VOP_UNLOCK(vp); 126547540Skarels return (error); 126638259Smckusick } 126738259Smckusick 126838259Smckusick /* 12699167Ssam * Change mode of a file given path name. 12709167Ssam */ 127142441Smckusick /* ARGSUSED */ 127242441Smckusick chmod(p, uap, retval) 127345914Smckusick struct proc *p; 127442441Smckusick register struct args { 12756254Sroot char *fname; 12766254Sroot int fmode; 127742441Smckusick } *uap; 127842441Smckusick int *retval; 127942441Smckusick { 128053548Sheideman USES_VOP_SETATTR; 128137741Smckusick register struct vnode *vp; 128237741Smckusick struct vattr vattr; 128337741Smckusick int error; 128447540Skarels struct nameidata nd; 12855992Swnj 128652322Smckusick NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 128752322Smckusick if (error = namei(&nd)) 128847540Skarels return (error); 128952322Smckusick vp = nd.ni_vp; 129041400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 129137741Smckusick error = EROFS; 129237741Smckusick goto out; 129337741Smckusick } 129445785Sbostic VATTR_NULL(&vattr); 129545785Sbostic vattr.va_mode = uap->fmode & 07777; 129652192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 129748026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 129837741Smckusick out: 129937741Smckusick vput(vp); 130047540Skarels return (error); 13017701Ssam } 13027439Sroot 13039167Ssam /* 13049167Ssam * Change mode of a file given a file descriptor. 13059167Ssam */ 130642441Smckusick /* ARGSUSED */ 130742441Smckusick fchmod(p, uap, retval) 130845914Smckusick struct proc *p; 130942441Smckusick register struct args { 13107701Ssam int fd; 13117701Ssam int fmode; 131242441Smckusick } *uap; 131342441Smckusick int *retval; 131442441Smckusick { 131553548Sheideman USES_VOP_LOCK; 131653548Sheideman USES_VOP_SETATTR; 131753548Sheideman USES_VOP_UNLOCK; 131837741Smckusick struct vattr vattr; 131937741Smckusick struct vnode *vp; 132037741Smckusick struct file *fp; 132137741Smckusick int error; 13227701Ssam 132345914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 132447540Skarels return (error); 132537741Smckusick vp = (struct vnode *)fp->f_data; 132637741Smckusick VOP_LOCK(vp); 132741400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 132837741Smckusick error = EROFS; 132937741Smckusick goto out; 13307439Sroot } 133145785Sbostic VATTR_NULL(&vattr); 133245785Sbostic vattr.va_mode = uap->fmode & 07777; 133352192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 133448026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 133537741Smckusick out: 133637741Smckusick VOP_UNLOCK(vp); 133747540Skarels return (error); 13385992Swnj } 13395992Swnj 13409167Ssam /* 13419167Ssam * Set ownership given a path name. 13429167Ssam */ 134342441Smckusick /* ARGSUSED */ 134442441Smckusick chown(p, uap, retval) 134545914Smckusick struct proc *p; 134642441Smckusick register struct args { 13476254Sroot char *fname; 13486254Sroot int uid; 13496254Sroot int gid; 135042441Smckusick } *uap; 135142441Smckusick int *retval; 135242441Smckusick { 135353548Sheideman USES_VOP_SETATTR; 135437741Smckusick register struct vnode *vp; 135537741Smckusick struct vattr vattr; 135637741Smckusick int error; 135747540Skarels struct nameidata nd; 135837Sbill 135952322Smckusick NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 136052322Smckusick if (error = namei(&nd)) 136147540Skarels return (error); 136252322Smckusick vp = nd.ni_vp; 136341400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 136437741Smckusick error = EROFS; 136537741Smckusick goto out; 136637741Smckusick } 136745785Sbostic VATTR_NULL(&vattr); 136845785Sbostic vattr.va_uid = uap->uid; 136945785Sbostic vattr.va_gid = uap->gid; 137052192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 137148026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 137237741Smckusick out: 137337741Smckusick vput(vp); 137447540Skarels return (error); 13757701Ssam } 13767439Sroot 13779167Ssam /* 13789167Ssam * Set ownership given a file descriptor. 13799167Ssam */ 138042441Smckusick /* ARGSUSED */ 138142441Smckusick fchown(p, uap, retval) 138245914Smckusick struct proc *p; 138342441Smckusick register struct args { 13847701Ssam int fd; 13857701Ssam int uid; 13867701Ssam int gid; 138742441Smckusick } *uap; 138842441Smckusick int *retval; 138942441Smckusick { 139053548Sheideman USES_VOP_LOCK; 139153548Sheideman USES_VOP_SETATTR; 139253548Sheideman USES_VOP_UNLOCK; 139337741Smckusick struct vattr vattr; 139437741Smckusick struct vnode *vp; 139537741Smckusick struct file *fp; 139637741Smckusick int error; 13977701Ssam 139845914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 139947540Skarels return (error); 140037741Smckusick vp = (struct vnode *)fp->f_data; 140137741Smckusick VOP_LOCK(vp); 140241400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 140337741Smckusick error = EROFS; 140437741Smckusick goto out; 140537741Smckusick } 140645785Sbostic VATTR_NULL(&vattr); 140745785Sbostic vattr.va_uid = uap->uid; 140845785Sbostic vattr.va_gid = uap->gid; 140952192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 141048026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 141137741Smckusick out: 141237741Smckusick VOP_UNLOCK(vp); 141347540Skarels return (error); 14147701Ssam } 14157701Ssam 141642441Smckusick /* 141742441Smckusick * Set the access and modification times of a file. 141842441Smckusick */ 141942441Smckusick /* ARGSUSED */ 142042441Smckusick utimes(p, uap, retval) 142145914Smckusick struct proc *p; 142242441Smckusick register struct args { 142311811Ssam char *fname; 142411811Ssam struct timeval *tptr; 142542441Smckusick } *uap; 142642441Smckusick int *retval; 142742441Smckusick { 142853548Sheideman USES_VOP_SETATTR; 142937741Smckusick register struct vnode *vp; 143011811Ssam struct timeval tv[2]; 143137741Smckusick struct vattr vattr; 143237741Smckusick int error; 143347540Skarels struct nameidata nd; 143411811Ssam 143537741Smckusick if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv))) 143647540Skarels return (error); 143752322Smckusick NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 143852322Smckusick if (error = namei(&nd)) 143947540Skarels return (error); 144052322Smckusick vp = nd.ni_vp; 144141400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 144237741Smckusick error = EROFS; 144337741Smckusick goto out; 144421015Smckusick } 144545785Sbostic VATTR_NULL(&vattr); 144654100Smckusick vattr.va_atime.ts_sec = tv[0].tv_sec; 144754100Smckusick vattr.va_atime.ts_nsec = tv[0].tv_usec * 1000; 144854100Smckusick vattr.va_mtime.ts_sec = tv[1].tv_sec; 144954100Smckusick vattr.va_mtime.ts_nsec = tv[1].tv_usec * 1000; 145052192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 145148026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 145237741Smckusick out: 145337741Smckusick vput(vp); 145447540Skarels return (error); 145511811Ssam } 145611811Ssam 145754348Smckusick #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 14589167Ssam /* 14599167Ssam * Truncate a file given its path name. 14609167Ssam */ 146142441Smckusick /* ARGSUSED */ 146242441Smckusick truncate(p, uap, retval) 146345914Smckusick struct proc *p; 146442441Smckusick register struct args { 14657701Ssam char *fname; 146653468Smckusick long length; 146753468Smckusick } *uap; 146853468Smckusick int *retval; 146953468Smckusick { 147053468Smckusick struct nargs { 147153468Smckusick char *fname; 147226473Skarels off_t length; 147353468Smckusick } nuap; 147453468Smckusick 147553468Smckusick nuap.fname = uap->fname; 147653468Smckusick nuap.length = uap->length; 147753759Smckusick return (__truncate(p, &nuap, retval)); 147853468Smckusick } 147953468Smckusick 148053468Smckusick /* 148153468Smckusick * Truncate a file given a file descriptor. 148253468Smckusick */ 148353468Smckusick /* ARGSUSED */ 148453468Smckusick ftruncate(p, uap, retval) 148553468Smckusick struct proc *p; 148653468Smckusick register struct args { 148753468Smckusick int fd; 148853468Smckusick long length; 148942441Smckusick } *uap; 149042441Smckusick int *retval; 149142441Smckusick { 149253468Smckusick struct nargs { 149353468Smckusick int fd; 149453468Smckusick off_t length; 149553468Smckusick } nuap; 149653468Smckusick 149753468Smckusick nuap.fd = uap->fd; 149853468Smckusick nuap.length = uap->length; 149953759Smckusick return (__ftruncate(p, &nuap, retval)); 150053468Smckusick } 150154348Smckusick #endif /* COMPAT_43 || COMPAT_SUNOS */ 150253468Smckusick 150353468Smckusick /* 150453468Smckusick * Truncate a file given its path name. 150553468Smckusick */ 150653468Smckusick /* ARGSUSED */ 150753759Smckusick __truncate(p, uap, retval) 150853468Smckusick struct proc *p; 150953468Smckusick register struct args { 151053468Smckusick char *fname; 151153468Smckusick off_t length; 151253468Smckusick } *uap; 151353468Smckusick int *retval; 151453468Smckusick { 151553548Sheideman USES_VOP_ACCESS; 151653548Sheideman USES_VOP_SETATTR; 151737741Smckusick register struct vnode *vp; 151837741Smckusick struct vattr vattr; 151937741Smckusick int error; 152047540Skarels struct nameidata nd; 15217701Ssam 152252322Smckusick NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 152352322Smckusick if (error = namei(&nd)) 152447540Skarels return (error); 152552322Smckusick vp = nd.ni_vp; 152637741Smckusick if (vp->v_type == VDIR) { 152737741Smckusick error = EISDIR; 152837741Smckusick goto out; 15297701Ssam } 153038399Smckusick if ((error = vn_writechk(vp)) || 153148026Smckusick (error = VOP_ACCESS(vp, VWRITE, p->p_ucred, p))) 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, p->p_ucred, p); 153737741Smckusick out: 153837741Smckusick vput(vp); 153947540Skarels return (error); 15407701Ssam } 15417701Ssam 15429167Ssam /* 15439167Ssam * Truncate a file given a file descriptor. 15449167Ssam */ 154542441Smckusick /* ARGSUSED */ 154653759Smckusick __ftruncate(p, uap, retval) 154745914Smckusick struct proc *p; 154842441Smckusick register struct args { 15497701Ssam int fd; 155026473Skarels off_t length; 155142441Smckusick } *uap; 155242441Smckusick int *retval; 155342441Smckusick { 155453548Sheideman USES_VOP_LOCK; 155553548Sheideman USES_VOP_SETATTR; 155653548Sheideman USES_VOP_UNLOCK; 155737741Smckusick struct vattr vattr; 155837741Smckusick struct vnode *vp; 15597701Ssam struct file *fp; 156037741Smckusick int error; 15617701Ssam 156245914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 156347540Skarels return (error); 156437741Smckusick if ((fp->f_flag & FWRITE) == 0) 156547540Skarels return (EINVAL); 156637741Smckusick vp = (struct vnode *)fp->f_data; 156737741Smckusick VOP_LOCK(vp); 156837741Smckusick if (vp->v_type == VDIR) { 156937741Smckusick error = EISDIR; 157037741Smckusick goto out; 15717701Ssam } 157238399Smckusick if (error = vn_writechk(vp)) 157337741Smckusick goto out; 157445785Sbostic VATTR_NULL(&vattr); 157545785Sbostic vattr.va_size = uap->length; 157652192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 157748026Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred, p); 157837741Smckusick out: 157937741Smckusick VOP_UNLOCK(vp); 158047540Skarels return (error); 15817701Ssam } 15827701Ssam 15839167Ssam /* 15849167Ssam * Synch an open file. 15859167Ssam */ 158642441Smckusick /* ARGSUSED */ 158742441Smckusick fsync(p, uap, retval) 158845914Smckusick struct proc *p; 158942441Smckusick struct args { 159042441Smckusick int fd; 159142441Smckusick } *uap; 159242441Smckusick int *retval; 15939167Ssam { 159453548Sheideman USES_VOP_FSYNC; 159553548Sheideman USES_VOP_LOCK; 159653548Sheideman USES_VOP_UNLOCK; 159739592Smckusick register struct vnode *vp; 15989167Ssam struct file *fp; 159937741Smckusick int error; 16009167Ssam 160145914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 160247540Skarels return (error); 160339592Smckusick vp = (struct vnode *)fp->f_data; 160439592Smckusick VOP_LOCK(vp); 160554441Smckusick error = VOP_FSYNC(vp, fp->f_cred, MNT_WAIT, p); 160639592Smckusick VOP_UNLOCK(vp); 160747540Skarels return (error); 16089167Ssam } 16099167Ssam 16109167Ssam /* 16119167Ssam * Rename system call. 16129167Ssam * 16139167Ssam * Source and destination must either both be directories, or both 16149167Ssam * not be directories. If target is a directory, it must be empty. 16159167Ssam */ 161642441Smckusick /* ARGSUSED */ 161742441Smckusick rename(p, uap, retval) 161845914Smckusick struct proc *p; 161942441Smckusick register struct args { 16207701Ssam char *from; 16217701Ssam char *to; 162242441Smckusick } *uap; 162342441Smckusick int *retval; 162442441Smckusick { 162553548Sheideman USES_VOP_ABORTOP; 162653548Sheideman USES_VOP_RENAME; 162737741Smckusick register struct vnode *tvp, *fvp, *tdvp; 162849735Smckusick struct nameidata fromnd, tond; 162937741Smckusick int error; 16307701Ssam 163152322Smckusick NDINIT(&fromnd, DELETE, WANTPARENT | SAVESTART, UIO_USERSPACE, 163252322Smckusick uap->from, p); 163352322Smckusick if (error = namei(&fromnd)) 163447540Skarels return (error); 163549735Smckusick fvp = fromnd.ni_vp; 163652322Smckusick NDINIT(&tond, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART, 163752322Smckusick UIO_USERSPACE, uap->to, p); 163852322Smckusick if (error = namei(&tond)) { 163952230Sheideman VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 164049735Smckusick vrele(fromnd.ni_dvp); 164142465Smckusick vrele(fvp); 164242465Smckusick goto out1; 164342465Smckusick } 164437741Smckusick tdvp = tond.ni_dvp; 164537741Smckusick tvp = tond.ni_vp; 164637741Smckusick if (tvp != NULL) { 164737741Smckusick if (fvp->v_type == VDIR && tvp->v_type != VDIR) { 164839242Sbostic error = ENOTDIR; 164937741Smckusick goto out; 165037741Smckusick } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) { 165139242Sbostic error = EISDIR; 165237741Smckusick goto out; 16539167Ssam } 16549167Ssam } 165539286Smckusick if (fvp == tdvp) 165637741Smckusick error = EINVAL; 165739286Smckusick /* 165849735Smckusick * If source is the same as the destination (that is the 165949735Smckusick * same inode number with the same name in the same directory), 166039286Smckusick * then there is nothing to do. 166139286Smckusick */ 166249735Smckusick if (fvp == tvp && fromnd.ni_dvp == tdvp && 166352322Smckusick fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen && 166452322Smckusick !bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr, 166552322Smckusick fromnd.ni_cnd.cn_namelen)) 166639286Smckusick error = -1; 166737741Smckusick out: 166842465Smckusick if (!error) { 166952192Smckusick LEASE_CHECK(tdvp, p, p->p_ucred, LEASE_WRITE); 167052192Smckusick if (fromnd.ni_dvp != tdvp) 167152192Smckusick LEASE_CHECK(fromnd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 167252192Smckusick if (tvp) 167352192Smckusick LEASE_CHECK(tvp, p, p->p_ucred, LEASE_WRITE); 167452230Sheideman error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd, 167552230Sheideman tond.ni_dvp, tond.ni_vp, &tond.ni_cnd); 167642465Smckusick } else { 167752230Sheideman VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd); 167843344Smckusick if (tdvp == tvp) 167943344Smckusick vrele(tdvp); 168043344Smckusick else 168143344Smckusick vput(tdvp); 168242465Smckusick if (tvp) 168342465Smckusick vput(tvp); 168452230Sheideman VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 168549735Smckusick vrele(fromnd.ni_dvp); 168642465Smckusick vrele(fvp); 16879167Ssam } 168849735Smckusick vrele(tond.ni_startdir); 168952322Smckusick FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI); 169037741Smckusick out1: 169149735Smckusick vrele(fromnd.ni_startdir); 169252322Smckusick FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI); 169339286Smckusick if (error == -1) 169447540Skarels return (0); 169547540Skarels return (error); 16967701Ssam } 16977701Ssam 16987535Sroot /* 169949365Smckusick * Mkdir system call. 170012756Ssam */ 170142441Smckusick /* ARGSUSED */ 170242441Smckusick mkdir(p, uap, retval) 170345914Smckusick struct proc *p; 170442441Smckusick register struct args { 170512756Ssam char *name; 170612756Ssam int dmode; 170742441Smckusick } *uap; 170842441Smckusick int *retval; 170942441Smckusick { 171053548Sheideman USES_VOP_ABORTOP; 171153548Sheideman USES_VOP_MKDIR; 171237741Smckusick register struct vnode *vp; 171337741Smckusick struct vattr vattr; 171437741Smckusick int error; 171547540Skarels struct nameidata nd; 171612756Ssam 171752322Smckusick NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->name, p); 171852322Smckusick if (error = namei(&nd)) 171947540Skarels return (error); 172052322Smckusick vp = nd.ni_vp; 172137741Smckusick if (vp != NULL) { 172252322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 172352322Smckusick if (nd.ni_dvp == vp) 172452322Smckusick vrele(nd.ni_dvp); 172543344Smckusick else 172652322Smckusick vput(nd.ni_dvp); 172742465Smckusick vrele(vp); 172847540Skarels return (EEXIST); 172912756Ssam } 173041362Smckusick VATTR_NULL(&vattr); 173137741Smckusick vattr.va_type = VDIR; 173245914Smckusick vattr.va_mode = (uap->dmode & 0777) &~ p->p_fd->fd_cmask; 173352322Smckusick LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 173452322Smckusick error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr); 173538145Smckusick if (!error) 173652322Smckusick vput(nd.ni_vp); 173747540Skarels return (error); 173812756Ssam } 173912756Ssam 174012756Ssam /* 174112756Ssam * Rmdir system call. 174212756Ssam */ 174342441Smckusick /* ARGSUSED */ 174442441Smckusick rmdir(p, uap, retval) 174545914Smckusick struct proc *p; 174642441Smckusick struct args { 174742441Smckusick char *name; 174842441Smckusick } *uap; 174942441Smckusick int *retval; 175012756Ssam { 175153548Sheideman USES_VOP_ABORTOP; 175253548Sheideman USES_VOP_RMDIR; 175337741Smckusick register struct vnode *vp; 175437741Smckusick int error; 175547540Skarels struct nameidata nd; 175612756Ssam 175752322Smckusick NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE, uap->name, p); 175852322Smckusick if (error = namei(&nd)) 175947540Skarels return (error); 176052322Smckusick vp = nd.ni_vp; 176137741Smckusick if (vp->v_type != VDIR) { 176237741Smckusick error = ENOTDIR; 176312756Ssam goto out; 176412756Ssam } 176512756Ssam /* 176637741Smckusick * No rmdir "." please. 176712756Ssam */ 176852322Smckusick if (nd.ni_dvp == vp) { 176937741Smckusick error = EINVAL; 177012756Ssam goto out; 177112756Ssam } 177212756Ssam /* 177349365Smckusick * The root of a mounted filesystem cannot be deleted. 177412756Ssam */ 177537741Smckusick if (vp->v_flag & VROOT) 177637741Smckusick error = EBUSY; 177712756Ssam out: 177842465Smckusick if (!error) { 177952322Smckusick LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 178052192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 178152322Smckusick error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); 178242465Smckusick } else { 178352322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 178452322Smckusick if (nd.ni_dvp == vp) 178552322Smckusick vrele(nd.ni_dvp); 178643344Smckusick else 178752322Smckusick vput(nd.ni_dvp); 178842465Smckusick vput(vp); 178942465Smckusick } 179047540Skarels return (error); 179112756Ssam } 179212756Ssam 1793*54620Smckusick #ifdef COMPAT_43 179437741Smckusick /* 179549365Smckusick * Read a block of directory entries in a file system independent format. 179637741Smckusick */ 1797*54620Smckusick ogetdirentries(p, uap, retval) 1798*54620Smckusick struct proc *p; 1799*54620Smckusick register struct args { 1800*54620Smckusick int fd; 1801*54620Smckusick char *buf; 1802*54620Smckusick unsigned count; 1803*54620Smckusick long *basep; 1804*54620Smckusick } *uap; 1805*54620Smckusick int *retval; 1806*54620Smckusick { 1807*54620Smckusick USES_VOP_LOCK; 1808*54620Smckusick USES_VOP_READDIR; 1809*54620Smckusick USES_VOP_UNLOCK; 1810*54620Smckusick register struct vnode *vp; 1811*54620Smckusick struct file *fp; 1812*54620Smckusick struct uio auio, kuio; 1813*54620Smckusick struct iovec aiov, kiov; 1814*54620Smckusick struct dirent *dp, *edp; 1815*54620Smckusick caddr_t dirbuf; 1816*54620Smckusick int error, readcnt; 1817*54620Smckusick off_t off; 1818*54620Smckusick 1819*54620Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 1820*54620Smckusick return (error); 1821*54620Smckusick if ((fp->f_flag & FREAD) == 0) 1822*54620Smckusick return (EBADF); 1823*54620Smckusick vp = (struct vnode *)fp->f_data; 1824*54620Smckusick if (vp->v_type != VDIR) 1825*54620Smckusick return (EINVAL); 1826*54620Smckusick aiov.iov_base = uap->buf; 1827*54620Smckusick aiov.iov_len = uap->count; 1828*54620Smckusick auio.uio_iov = &aiov; 1829*54620Smckusick auio.uio_iovcnt = 1; 1830*54620Smckusick auio.uio_rw = UIO_READ; 1831*54620Smckusick auio.uio_segflg = UIO_USERSPACE; 1832*54620Smckusick auio.uio_procp = p; 1833*54620Smckusick auio.uio_resid = uap->count; 1834*54620Smckusick VOP_LOCK(vp); 1835*54620Smckusick auio.uio_offset = off = fp->f_offset; 1836*54620Smckusick # if (BYTE_ORDER != LITTLE_ENDIAN) 1837*54620Smckusick if (vp->v_mount->mnt_maxsymlinklen <= 0) 1838*54620Smckusick error = VOP_READDIR(vp, &auio, fp->f_cred); 1839*54620Smckusick else 1840*54620Smckusick # endif 1841*54620Smckusick { 1842*54620Smckusick kuio = auio; 1843*54620Smckusick kuio.uio_iov = &kiov; 1844*54620Smckusick kuio.uio_segflg = UIO_SYSSPACE; 1845*54620Smckusick kiov.iov_len = uap->count; 1846*54620Smckusick MALLOC(dirbuf, caddr_t, uap->count, M_TEMP, M_WAITOK); 1847*54620Smckusick kiov.iov_base = dirbuf; 1848*54620Smckusick error = VOP_READDIR(vp, &kuio, fp->f_cred); 1849*54620Smckusick if (error == 0) { 1850*54620Smckusick readcnt = uap->count - kuio.uio_resid; 1851*54620Smckusick edp = (struct dirent *)&dirbuf[readcnt]; 1852*54620Smckusick for (dp = (struct dirent *)dirbuf; dp < edp; ) { 1853*54620Smckusick dp->d_type = 0; 1854*54620Smckusick # if (BYTE_ORDER == LITTLE_ENDIAN) 1855*54620Smckusick { u_char tmp = dp->d_namlen; 1856*54620Smckusick dp->d_namlen = dp->d_type; 1857*54620Smckusick dp->d_type = tmp; } 1858*54620Smckusick # endif 1859*54620Smckusick if (dp->d_reclen > 0) { 1860*54620Smckusick dp = (struct dirent *) 1861*54620Smckusick ((char *)dp + dp->d_reclen); 1862*54620Smckusick } else { 1863*54620Smckusick error = EIO; 1864*54620Smckusick break; 1865*54620Smckusick } 1866*54620Smckusick } 1867*54620Smckusick if (dp >= edp) 1868*54620Smckusick error = uiomove(dirbuf, readcnt, &auio); 1869*54620Smckusick } 1870*54620Smckusick FREE(dirbuf, M_TEMP); 1871*54620Smckusick } 1872*54620Smckusick fp->f_offset = auio.uio_offset; 1873*54620Smckusick VOP_UNLOCK(vp); 1874*54620Smckusick if (error) 1875*54620Smckusick return (error); 1876*54620Smckusick error = copyout((caddr_t)&off, (caddr_t)uap->basep, sizeof(long)); 1877*54620Smckusick *retval = uap->count - auio.uio_resid; 1878*54620Smckusick return (error); 1879*54620Smckusick } 1880*54620Smckusick #endif 1881*54620Smckusick 1882*54620Smckusick /* 1883*54620Smckusick * Read a block of directory entries in a file system independent format. 1884*54620Smckusick */ 188542441Smckusick getdirentries(p, uap, retval) 188645914Smckusick struct proc *p; 188742441Smckusick register struct args { 188837741Smckusick int fd; 188937741Smckusick char *buf; 189037741Smckusick unsigned count; 189137741Smckusick long *basep; 189242441Smckusick } *uap; 189342441Smckusick int *retval; 189442441Smckusick { 189553548Sheideman USES_VOP_LOCK; 189653548Sheideman USES_VOP_READDIR; 189753548Sheideman USES_VOP_UNLOCK; 189839592Smckusick register struct vnode *vp; 189916540Ssam struct file *fp; 190037741Smckusick struct uio auio; 190137741Smckusick struct iovec aiov; 190238129Smckusick off_t off; 190354441Smckusick int error; 190412756Ssam 190545914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 190647540Skarels return (error); 190737741Smckusick if ((fp->f_flag & FREAD) == 0) 190847540Skarels return (EBADF); 190939592Smckusick vp = (struct vnode *)fp->f_data; 191039592Smckusick if (vp->v_type != VDIR) 191147540Skarels return (EINVAL); 191237741Smckusick aiov.iov_base = uap->buf; 191337741Smckusick aiov.iov_len = uap->count; 191437741Smckusick auio.uio_iov = &aiov; 191537741Smckusick auio.uio_iovcnt = 1; 191637741Smckusick auio.uio_rw = UIO_READ; 191737741Smckusick auio.uio_segflg = UIO_USERSPACE; 191848026Smckusick auio.uio_procp = p; 191937741Smckusick auio.uio_resid = uap->count; 192039592Smckusick VOP_LOCK(vp); 192139592Smckusick auio.uio_offset = off = fp->f_offset; 192254441Smckusick error = VOP_READDIR(vp, &auio, fp->f_cred); 192339592Smckusick fp->f_offset = auio.uio_offset; 192439592Smckusick VOP_UNLOCK(vp); 192539592Smckusick if (error) 192647540Skarels return (error); 192739592Smckusick error = copyout((caddr_t)&off, (caddr_t)uap->basep, sizeof(long)); 192842441Smckusick *retval = uap->count - auio.uio_resid; 192947540Skarels return (error); 193012756Ssam } 193112756Ssam 193212756Ssam /* 193349365Smckusick * Set the mode mask for creation of filesystem nodes. 193412756Ssam */ 193542441Smckusick mode_t 193642441Smckusick umask(p, uap, retval) 193745914Smckusick struct proc *p; 193842441Smckusick struct args { 193942441Smckusick int mask; 194042441Smckusick } *uap; 194142441Smckusick int *retval; 194212756Ssam { 194345914Smckusick register struct filedesc *fdp = p->p_fd; 194412756Ssam 194545914Smckusick *retval = fdp->fd_cmask; 194645914Smckusick fdp->fd_cmask = uap->mask & 07777; 194747540Skarels return (0); 194812756Ssam } 194937741Smckusick 195039566Smarc /* 195139566Smarc * Void all references to file by ripping underlying filesystem 195239566Smarc * away from vnode. 195339566Smarc */ 195442441Smckusick /* ARGSUSED */ 195542441Smckusick revoke(p, uap, retval) 195645914Smckusick struct proc *p; 195742441Smckusick register struct args { 195839566Smarc char *fname; 195942441Smckusick } *uap; 196042441Smckusick int *retval; 196142441Smckusick { 196253548Sheideman USES_VOP_GETATTR; 196339566Smarc register struct vnode *vp; 196439566Smarc struct vattr vattr; 196539566Smarc int error; 196647540Skarels struct nameidata nd; 196739566Smarc 196852322Smckusick NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->fname, p); 196952322Smckusick if (error = namei(&nd)) 197047540Skarels return (error); 197152322Smckusick vp = nd.ni_vp; 197239566Smarc if (vp->v_type != VCHR && vp->v_type != VBLK) { 197339566Smarc error = EINVAL; 197439566Smarc goto out; 197539566Smarc } 197648026Smckusick if (error = VOP_GETATTR(vp, &vattr, p->p_ucred, p)) 197739566Smarc goto out; 197847540Skarels if (p->p_ucred->cr_uid != vattr.va_uid && 197947540Skarels (error = suser(p->p_ucred, &p->p_acflag))) 198039566Smarc goto out; 198139805Smckusick if (vp->v_usecount > 1 || (vp->v_flag & VALIASED)) 198239632Smckusick vgoneall(vp); 198339566Smarc out: 198439566Smarc vrele(vp); 198547540Skarels return (error); 198639566Smarc } 198739566Smarc 198849365Smckusick /* 198949365Smckusick * Convert a user file descriptor to a kernel file entry. 199049365Smckusick */ 199145914Smckusick getvnode(fdp, fdes, fpp) 199245914Smckusick struct filedesc *fdp; 199337741Smckusick struct file **fpp; 199437741Smckusick int fdes; 199537741Smckusick { 199637741Smckusick struct file *fp; 199737741Smckusick 199847540Skarels if ((unsigned)fdes >= fdp->fd_nfiles || 199947688Skarels (fp = fdp->fd_ofiles[fdes]) == NULL) 200037741Smckusick return (EBADF); 200137741Smckusick if (fp->f_type != DTYPE_VNODE) 200237741Smckusick return (EINVAL); 200337741Smckusick *fpp = fp; 200437741Smckusick return (0); 200537741Smckusick } 2006