123405Smckusick /* 237741Smckusick * Copyright (c) 1989 The Regents of the University of California. 337741Smckusick * All rights reserved. 423405Smckusick * 544459Sbostic * %sccs.include.redist.c% 637741Smckusick * 7*55009Smckusick * @(#)vfs_syscalls.c 7.95 (Berkeley) 07/12/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 */ 3254916Storek struct mount_args { 3354916Storek int type; 3454916Storek char *dir; 3554916Storek int flags; 3654916Storek caddr_t data; 3754916Storek }; 3842441Smckusick /* ARGSUSED */ 3942441Smckusick mount(p, uap, retval) 4045914Smckusick struct proc *p; 4154916Storek register struct mount_args *uap; 4242441Smckusick int *retval; 4342441Smckusick { 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 */ 17854916Storek struct unmount_args { 17954916Storek char *pathp; 18054916Storek int flags; 18154916Storek }; 18242441Smckusick /* ARGSUSED */ 18342441Smckusick unmount(p, uap, retval) 18445914Smckusick struct proc *p; 18554916Storek register struct unmount_args *uap; 18642441Smckusick int *retval; 18742441Smckusick { 18837741Smckusick register struct vnode *vp; 18939356Smckusick struct mount *mp; 19037741Smckusick int error; 19147540Skarels struct nameidata nd; 1926254Sroot 19337741Smckusick /* 19437741Smckusick * Must be super user 19537741Smckusick */ 19647540Skarels if (error = suser(p->p_ucred, &p->p_acflag)) 19747540Skarels return (error); 19837741Smckusick 19952322Smckusick NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->pathp, p); 20052322Smckusick if (error = namei(&nd)) 20147540Skarels return (error); 20252322Smckusick vp = nd.ni_vp; 20337741Smckusick /* 20437741Smckusick * Must be the root of the filesystem 20537741Smckusick */ 20637741Smckusick if ((vp->v_flag & VROOT) == 0) { 20737741Smckusick vput(vp); 20847540Skarels return (EINVAL); 20937741Smckusick } 21037741Smckusick mp = vp->v_mount; 21137741Smckusick vput(vp); 21248026Smckusick return (dounmount(mp, uap->flags, p)); 21339356Smckusick } 21439356Smckusick 21539356Smckusick /* 21639356Smckusick * Do an unmount. 21739356Smckusick */ 21848026Smckusick dounmount(mp, flags, p) 21939356Smckusick register struct mount *mp; 22039356Smckusick int flags; 22148026Smckusick struct proc *p; 22239356Smckusick { 22339356Smckusick struct vnode *coveredvp; 22439356Smckusick int error; 22539356Smckusick 22641400Smckusick coveredvp = mp->mnt_vnodecovered; 22741298Smckusick if (vfs_busy(mp)) 22841298Smckusick return (EBUSY); 22941400Smckusick mp->mnt_flag |= MNT_UNMOUNT; 23037741Smckusick if (error = vfs_lock(mp)) 23139356Smckusick return (error); 23237741Smckusick 23345738Smckusick vnode_pager_umount(mp); /* release cached vnodes */ 23437741Smckusick cache_purgevfs(mp); /* remove cache entries for this file sys */ 23554441Smckusick if ((error = VFS_SYNC(mp, MNT_WAIT, p->p_ucred, p)) == 0 || 23654441Smckusick (flags & MNT_FORCE)) 23748026Smckusick error = VFS_UNMOUNT(mp, flags, p); 23841400Smckusick mp->mnt_flag &= ~MNT_UNMOUNT; 23941298Smckusick vfs_unbusy(mp); 24037741Smckusick if (error) { 24137741Smckusick vfs_unlock(mp); 24237741Smckusick } else { 24337741Smckusick vrele(coveredvp); 24437741Smckusick vfs_remove(mp); 24552287Smckusick if (mp->mnt_mounth != NULL) 24652287Smckusick panic("unmount: dangling vnode"); 24737741Smckusick free((caddr_t)mp, M_MOUNT); 24837741Smckusick } 24939356Smckusick return (error); 2506254Sroot } 2516254Sroot 2529167Ssam /* 25337741Smckusick * Sync system call. 25437741Smckusick * Sync each mounted filesystem. 2559167Ssam */ 25654916Storek struct sync_args { 25754916Storek int dummy; 25854916Storek }; 25939491Smckusick /* ARGSUSED */ 26042441Smckusick sync(p, uap, retval) 26145914Smckusick struct proc *p; 26254916Storek struct sync_args *uap; 26342441Smckusick int *retval; 2646254Sroot { 26537741Smckusick register struct mount *mp; 26641298Smckusick struct mount *omp; 26737741Smckusick 26837741Smckusick mp = rootfs; 26937741Smckusick do { 27040343Smckusick /* 27140343Smckusick * The lock check below is to avoid races with mount 27240343Smckusick * and unmount. 27340343Smckusick */ 27441400Smckusick if ((mp->mnt_flag & (MNT_MLOCK|MNT_RDONLY|MNT_MPBUSY)) == 0 && 27541298Smckusick !vfs_busy(mp)) { 27654441Smckusick VFS_SYNC(mp, MNT_NOWAIT, p->p_ucred, p); 27741298Smckusick omp = mp; 27841400Smckusick mp = mp->mnt_next; 27941298Smckusick vfs_unbusy(omp); 28041298Smckusick } else 28141400Smckusick mp = mp->mnt_next; 28237741Smckusick } while (mp != rootfs); 28347688Skarels return (0); 28437741Smckusick } 28537741Smckusick 28637741Smckusick /* 28749365Smckusick * Operate on filesystem quotas. 28841298Smckusick */ 28954916Storek struct quotactl_args { 29054916Storek char *path; 29154916Storek int cmd; 29254916Storek int uid; 29354916Storek caddr_t arg; 29454916Storek }; 29542441Smckusick /* ARGSUSED */ 29642441Smckusick quotactl(p, uap, retval) 29745914Smckusick struct proc *p; 29854916Storek register struct quotactl_args *uap; 29942441Smckusick int *retval; 30042441Smckusick { 30141298Smckusick register struct mount *mp; 30241298Smckusick int error; 30347540Skarels struct nameidata nd; 30441298Smckusick 30552322Smckusick NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); 30652322Smckusick if (error = namei(&nd)) 30747540Skarels return (error); 30852322Smckusick mp = nd.ni_vp->v_mount; 30952322Smckusick vrele(nd.ni_vp); 31048026Smckusick return (VFS_QUOTACTL(mp, uap->cmd, uap->uid, uap->arg, p)); 31141298Smckusick } 31241298Smckusick 31341298Smckusick /* 31449365Smckusick * Get filesystem statistics. 31537741Smckusick */ 31654916Storek struct statfs_args { 31754916Storek char *path; 31854916Storek struct statfs *buf; 31954916Storek }; 32042441Smckusick /* ARGSUSED */ 32142441Smckusick statfs(p, uap, retval) 32245914Smckusick struct proc *p; 32354916Storek register struct statfs_args *uap; 32442441Smckusick int *retval; 32542441Smckusick { 32639464Smckusick register struct mount *mp; 32740343Smckusick register struct statfs *sp; 32837741Smckusick int error; 32947540Skarels struct nameidata nd; 33037741Smckusick 33152322Smckusick NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); 33252322Smckusick if (error = namei(&nd)) 33347540Skarels return (error); 33452322Smckusick mp = nd.ni_vp->v_mount; 33541400Smckusick sp = &mp->mnt_stat; 33652322Smckusick vrele(nd.ni_vp); 33748026Smckusick if (error = VFS_STATFS(mp, sp, p)) 33847540Skarels return (error); 33941400Smckusick sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 34047540Skarels return (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp))); 34137741Smckusick } 34237741Smckusick 34342441Smckusick /* 34449365Smckusick * Get filesystem statistics. 34542441Smckusick */ 34654916Storek struct fstatfs_args { 34754916Storek int fd; 34854916Storek struct statfs *buf; 34954916Storek }; 35042441Smckusick /* ARGSUSED */ 35142441Smckusick fstatfs(p, uap, retval) 35245914Smckusick struct proc *p; 35354916Storek register struct fstatfs_args *uap; 35442441Smckusick int *retval; 35542441Smckusick { 35637741Smckusick struct file *fp; 35739464Smckusick struct mount *mp; 35840343Smckusick register struct statfs *sp; 35937741Smckusick int error; 36037741Smckusick 36145914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 36247540Skarels return (error); 36339464Smckusick mp = ((struct vnode *)fp->f_data)->v_mount; 36441400Smckusick sp = &mp->mnt_stat; 36548026Smckusick if (error = VFS_STATFS(mp, sp, p)) 36647540Skarels return (error); 36741400Smckusick sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 36847540Skarels return (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp))); 36937741Smckusick } 37037741Smckusick 37137741Smckusick /* 37249365Smckusick * Get statistics on all filesystems. 37338270Smckusick */ 37454916Storek struct getfsstat_args { 37554916Storek struct statfs *buf; 37654916Storek long bufsize; 37754916Storek int flags; 37854916Storek }; 37942441Smckusick getfsstat(p, uap, retval) 38045914Smckusick struct proc *p; 38154916Storek register struct getfsstat_args *uap; 38242441Smckusick int *retval; 38342441Smckusick { 38438270Smckusick register struct mount *mp; 38540343Smckusick register struct statfs *sp; 38639606Smckusick caddr_t sfsp; 38738270Smckusick long count, maxcount, error; 38838270Smckusick 38938270Smckusick maxcount = uap->bufsize / sizeof(struct statfs); 39039606Smckusick sfsp = (caddr_t)uap->buf; 39138270Smckusick mp = rootfs; 39238270Smckusick count = 0; 39338270Smckusick do { 39441400Smckusick if (sfsp && count < maxcount && 39541400Smckusick ((mp->mnt_flag & MNT_MLOCK) == 0)) { 39641400Smckusick sp = &mp->mnt_stat; 39740343Smckusick /* 39840343Smckusick * If MNT_NOWAIT is specified, do not refresh the 39940343Smckusick * fsstat cache. MNT_WAIT overrides MNT_NOWAIT. 40040343Smckusick */ 40140343Smckusick if (((uap->flags & MNT_NOWAIT) == 0 || 40240343Smckusick (uap->flags & MNT_WAIT)) && 40348026Smckusick (error = VFS_STATFS(mp, sp, p))) { 40441400Smckusick mp = mp->mnt_prev; 40539607Smckusick continue; 40639607Smckusick } 40741400Smckusick sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 40840343Smckusick if (error = copyout((caddr_t)sp, sfsp, sizeof(*sp))) 40947540Skarels return (error); 41040343Smckusick sfsp += sizeof(*sp); 41138270Smckusick } 41239606Smckusick count++; 41341400Smckusick mp = mp->mnt_prev; 41438270Smckusick } while (mp != rootfs); 41538270Smckusick if (sfsp && count > maxcount) 41642441Smckusick *retval = maxcount; 41738270Smckusick else 41842441Smckusick *retval = count; 41947540Skarels return (0); 42038270Smckusick } 42138270Smckusick 42238270Smckusick /* 42338259Smckusick * Change current working directory to a given file descriptor. 42438259Smckusick */ 42554916Storek struct fchdir_args { 42654916Storek int fd; 42754916Storek }; 42842441Smckusick /* ARGSUSED */ 42942441Smckusick fchdir(p, uap, retval) 43045914Smckusick struct proc *p; 43154916Storek struct fchdir_args *uap; 43242441Smckusick int *retval; 43338259Smckusick { 43445914Smckusick register struct filedesc *fdp = p->p_fd; 43538259Smckusick register struct vnode *vp; 43638259Smckusick struct file *fp; 43738259Smckusick int error; 43838259Smckusick 43945914Smckusick if (error = getvnode(fdp, uap->fd, &fp)) 44047540Skarels return (error); 44138259Smckusick vp = (struct vnode *)fp->f_data; 44238259Smckusick VOP_LOCK(vp); 44338259Smckusick if (vp->v_type != VDIR) 44438259Smckusick error = ENOTDIR; 44538259Smckusick else 44648026Smckusick error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p); 44738259Smckusick VOP_UNLOCK(vp); 44839860Smckusick if (error) 44947540Skarels return (error); 45039860Smckusick VREF(vp); 45145914Smckusick vrele(fdp->fd_cdir); 45245914Smckusick fdp->fd_cdir = vp; 45347540Skarels return (0); 45438259Smckusick } 45538259Smckusick 45638259Smckusick /* 45737741Smckusick * Change current working directory (``.''). 45837741Smckusick */ 45954916Storek struct chdir_args { 46054916Storek char *fname; 46154916Storek }; 46242441Smckusick /* ARGSUSED */ 46342441Smckusick chdir(p, uap, retval) 46445914Smckusick struct proc *p; 46554916Storek struct chdir_args *uap; 46642441Smckusick int *retval; 46737741Smckusick { 46845914Smckusick register struct filedesc *fdp = p->p_fd; 46937741Smckusick int error; 47047540Skarels struct nameidata nd; 4716254Sroot 47252322Smckusick NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 47352781Sralph if (error = chdirec(&nd, p)) 47447540Skarels return (error); 47545914Smckusick vrele(fdp->fd_cdir); 47652322Smckusick fdp->fd_cdir = nd.ni_vp; 47747540Skarels return (0); 47837741Smckusick } 4796254Sroot 48037741Smckusick /* 48137741Smckusick * Change notion of root (``/'') directory. 48237741Smckusick */ 48354916Storek struct chroot_args { 48454916Storek char *fname; 48554916Storek }; 48642441Smckusick /* ARGSUSED */ 48742441Smckusick chroot(p, uap, retval) 48845914Smckusick struct proc *p; 48954916Storek struct chroot_args *uap; 49042441Smckusick int *retval; 49137741Smckusick { 49245914Smckusick register struct filedesc *fdp = p->p_fd; 49337741Smckusick int error; 49447540Skarels struct nameidata nd; 49537741Smckusick 49647540Skarels if (error = suser(p->p_ucred, &p->p_acflag)) 49747540Skarels return (error); 49852322Smckusick NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 49952781Sralph if (error = chdirec(&nd, p)) 50047540Skarels return (error); 50145914Smckusick if (fdp->fd_rdir != NULL) 50245914Smckusick vrele(fdp->fd_rdir); 50352322Smckusick fdp->fd_rdir = nd.ni_vp; 50447540Skarels return (0); 5056254Sroot } 5066254Sroot 50737Sbill /* 50837741Smckusick * Common routine for chroot and chdir. 50937741Smckusick */ 51047540Skarels chdirec(ndp, p) 51152322Smckusick register struct nameidata *ndp; 51247540Skarels struct proc *p; 51337741Smckusick { 51437741Smckusick struct vnode *vp; 51537741Smckusick int error; 51637741Smckusick 51752322Smckusick if (error = namei(ndp)) 51837741Smckusick return (error); 51937741Smckusick vp = ndp->ni_vp; 52037741Smckusick if (vp->v_type != VDIR) 52137741Smckusick error = ENOTDIR; 52237741Smckusick else 52348026Smckusick error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p); 52437741Smckusick VOP_UNLOCK(vp); 52537741Smckusick if (error) 52637741Smckusick vrele(vp); 52737741Smckusick return (error); 52837741Smckusick } 52937741Smckusick 53037741Smckusick /* 5316254Sroot * Open system call. 53242441Smckusick * Check permissions, allocate an open file structure, 53342441Smckusick * and call the device open routine if any. 5346254Sroot */ 53554916Storek struct open_args { 53654916Storek char *fname; 53754916Storek int mode; 53854916Storek int crtmode; 53954916Storek }; 54042441Smckusick open(p, uap, retval) 54145914Smckusick struct proc *p; 54254916Storek register struct open_args *uap; 54342441Smckusick int *retval; 5446254Sroot { 54545914Smckusick register struct filedesc *fdp = p->p_fd; 54642441Smckusick register struct file *fp; 54750111Smckusick register struct vnode *vp; 54837741Smckusick int fmode, cmode; 54937741Smckusick struct file *nfp; 55049945Smckusick int type, indx, error; 55149945Smckusick struct flock lf; 55247540Skarels struct nameidata nd; 55337741Smckusick extern struct fileops vnops; 5546254Sroot 55545914Smckusick if (error = falloc(p, &nfp, &indx)) 55647540Skarels return (error); 55737741Smckusick fp = nfp; 55846553Skarels fmode = FFLAGS(uap->mode); 55945914Smckusick cmode = ((uap->crtmode &~ fdp->fd_cmask) & 07777) &~ S_ISVTX; 56052322Smckusick NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->fname, p); 56145202Smckusick p->p_dupfd = -indx - 1; /* XXX check for fdopen */ 56252322Smckusick if (error = vn_open(&nd, fmode, cmode)) { 56349980Smckusick ffree(fp); 56454723Smckusick if ((error == ENODEV || error == ENXIO) && 56554723Smckusick p->p_dupfd >= 0 && /* XXX from fdopen */ 56653828Spendry (error = dupfdopen(fdp, indx, p->p_dupfd, 56753828Spendry fmode, error)) == 0) { 56842441Smckusick *retval = indx; 56947540Skarels return (0); 57042441Smckusick } 57140884Smckusick if (error == ERESTART) 57240884Smckusick error = EINTR; 57347688Skarels fdp->fd_ofiles[indx] = NULL; 57447540Skarels return (error); 57512756Ssam } 57653828Spendry p->p_dupfd = 0; 57752322Smckusick vp = nd.ni_vp; 57849949Smckusick fp->f_flag = fmode & FMASK; 57954348Smckusick fp->f_type = DTYPE_VNODE; 58054348Smckusick fp->f_ops = &vnops; 58154348Smckusick fp->f_data = (caddr_t)vp; 58249945Smckusick if (fmode & (O_EXLOCK | O_SHLOCK)) { 58349945Smckusick lf.l_whence = SEEK_SET; 58449945Smckusick lf.l_start = 0; 58549945Smckusick lf.l_len = 0; 58649945Smckusick if (fmode & O_EXLOCK) 58749945Smckusick lf.l_type = F_WRLCK; 58849945Smckusick else 58949945Smckusick lf.l_type = F_RDLCK; 59049945Smckusick type = F_FLOCK; 59149945Smckusick if ((fmode & FNONBLOCK) == 0) 59249945Smckusick type |= F_WAIT; 59350111Smckusick if (error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, type)) { 59450111Smckusick VOP_UNLOCK(vp); 59550111Smckusick (void) vn_close(vp, fp->f_flag, fp->f_cred, p); 59649980Smckusick ffree(fp); 59749945Smckusick fdp->fd_ofiles[indx] = NULL; 59849945Smckusick return (error); 59949945Smckusick } 60049949Smckusick fp->f_flag |= FHASLOCK; 60149945Smckusick } 60250111Smckusick VOP_UNLOCK(vp); 60342441Smckusick *retval = indx; 60447540Skarels return (0); 6056254Sroot } 6066254Sroot 60742955Smckusick #ifdef COMPAT_43 6086254Sroot /* 60942441Smckusick * Creat system call. 6106254Sroot */ 61154916Storek struct ocreat_args { 61254916Storek char *fname; 61354916Storek int fmode; 61454916Storek }; 61542955Smckusick ocreat(p, uap, retval) 61642441Smckusick struct proc *p; 61754916Storek register struct ocreat_args *uap; 61842441Smckusick int *retval; 6196254Sroot { 62054916Storek struct open_args 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 */ 63254916Storek struct mknod_args { 63354916Storek char *fname; 63454916Storek int fmode; 63554916Storek int dev; 63654916Storek }; 63742441Smckusick /* ARGSUSED */ 63842441Smckusick mknod(p, uap, retval) 63945914Smckusick struct proc *p; 64054916Storek register struct mknod_args *uap; 64142441Smckusick int *retval; 64242441Smckusick { 64337741Smckusick register struct vnode *vp; 64437741Smckusick struct vattr vattr; 64537741Smckusick int error; 64647540Skarels struct nameidata nd; 6476254Sroot 64847540Skarels if (error = suser(p->p_ucred, &p->p_acflag)) 64947540Skarels return (error); 65052322Smckusick NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->fname, p); 65152322Smckusick if (error = namei(&nd)) 65247540Skarels return (error); 65352322Smckusick vp = nd.ni_vp; 65437741Smckusick if (vp != NULL) { 65537741Smckusick error = EEXIST; 65612756Ssam goto out; 6576254Sroot } 65841362Smckusick VATTR_NULL(&vattr); 65940635Smckusick switch (uap->fmode & S_IFMT) { 66012756Ssam 66140635Smckusick case S_IFMT: /* used by badsect to flag bad sectors */ 66237741Smckusick vattr.va_type = VBAD; 66337741Smckusick break; 66440635Smckusick case S_IFCHR: 66537741Smckusick vattr.va_type = VCHR; 66637741Smckusick break; 66740635Smckusick case S_IFBLK: 66837741Smckusick vattr.va_type = VBLK; 66937741Smckusick break; 67037741Smckusick default: 67137741Smckusick error = EINVAL; 67237741Smckusick goto out; 6736254Sroot } 67445914Smckusick vattr.va_mode = (uap->fmode & 07777) &~ p->p_fd->fd_cmask; 67537741Smckusick vattr.va_rdev = uap->dev; 6766254Sroot out: 67742465Smckusick if (!error) { 67852322Smckusick LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 67952322Smckusick error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr); 68042465Smckusick } else { 68152322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 68252322Smckusick if (nd.ni_dvp == vp) 68352322Smckusick vrele(nd.ni_dvp); 68443344Smckusick else 68552322Smckusick vput(nd.ni_dvp); 68642465Smckusick if (vp) 68742465Smckusick vrele(vp); 68842465Smckusick } 68947540Skarels return (error); 6906254Sroot } 6916254Sroot 6926254Sroot /* 69349365Smckusick * Mkfifo system call. 69440285Smckusick */ 69554916Storek struct mkfifo_args { 69654916Storek char *fname; 69754916Storek int fmode; 69854916Storek }; 69942441Smckusick /* ARGSUSED */ 70042441Smckusick mkfifo(p, uap, retval) 70145914Smckusick struct proc *p; 70254916Storek register struct mkfifo_args *uap; 70342441Smckusick int *retval; 70442441Smckusick { 70540285Smckusick struct vattr vattr; 70640285Smckusick int error; 70747540Skarels struct nameidata nd; 70840285Smckusick 70940285Smckusick #ifndef FIFO 71047540Skarels return (EOPNOTSUPP); 71140285Smckusick #else 71252322Smckusick NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->fname, p); 71352322Smckusick if (error = namei(&nd)) 71447540Skarels return (error); 71552322Smckusick if (nd.ni_vp != NULL) { 71652322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 71752322Smckusick if (nd.ni_dvp == nd.ni_vp) 71852322Smckusick vrele(nd.ni_dvp); 71943344Smckusick else 72052322Smckusick vput(nd.ni_dvp); 72152322Smckusick vrele(nd.ni_vp); 72247540Skarels return (EEXIST); 72340285Smckusick } 72445785Sbostic VATTR_NULL(&vattr); 72545785Sbostic vattr.va_type = VFIFO; 72645914Smckusick vattr.va_mode = (uap->fmode & 07777) &~ p->p_fd->fd_cmask; 72752322Smckusick LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 72852322Smckusick return (VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr)); 72940285Smckusick #endif /* FIFO */ 73040285Smckusick } 73140285Smckusick 73240285Smckusick /* 73349365Smckusick * Link system call. 7346254Sroot */ 73554916Storek struct link_args { 73654916Storek char *target; 73754916Storek char *linkname; 73854916Storek }; 73942441Smckusick /* ARGSUSED */ 74042441Smckusick link(p, uap, retval) 74145914Smckusick struct proc *p; 74254916Storek register struct link_args *uap; 74342441Smckusick int *retval; 74442441Smckusick { 74537741Smckusick register struct vnode *vp, *xp; 74637741Smckusick int error; 74747540Skarels struct nameidata nd; 7486254Sroot 74952322Smckusick NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->target, p); 75052322Smckusick if (error = namei(&nd)) 75147540Skarels return (error); 75252322Smckusick vp = nd.ni_vp; 75337741Smckusick if (vp->v_type == VDIR && 75447540Skarels (error = suser(p->p_ucred, &p->p_acflag))) 75537741Smckusick goto out1; 75652322Smckusick nd.ni_cnd.cn_nameiop = CREATE; 75752322Smckusick nd.ni_cnd.cn_flags = LOCKPARENT; 75852322Smckusick nd.ni_dirp = (caddr_t)uap->linkname; 75952322Smckusick if (error = namei(&nd)) 76037741Smckusick goto out1; 76152322Smckusick xp = nd.ni_vp; 7626254Sroot if (xp != NULL) { 76337741Smckusick error = EEXIST; 7646254Sroot goto out; 7656254Sroot } 76652322Smckusick xp = nd.ni_dvp; 7676254Sroot out: 76842465Smckusick if (!error) { 76952192Smckusick LEASE_CHECK(xp, p, p->p_ucred, LEASE_WRITE); 77052192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 77152821Smckusick error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd); 77242465Smckusick } else { 77352322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 77452322Smckusick if (nd.ni_dvp == nd.ni_vp) 77552322Smckusick vrele(nd.ni_dvp); 77643344Smckusick else 77752322Smckusick vput(nd.ni_dvp); 77852322Smckusick if (nd.ni_vp) 77952322Smckusick vrele(nd.ni_vp); 78042465Smckusick } 78137741Smckusick out1: 78237741Smckusick vrele(vp); 78347540Skarels return (error); 7846254Sroot } 7856254Sroot 7866254Sroot /* 78749365Smckusick * Make a symbolic link. 7886254Sroot */ 78954916Storek struct symlink_args { 79054916Storek char *target; 79154916Storek char *linkname; 79254916Storek }; 79342441Smckusick /* ARGSUSED */ 79442441Smckusick symlink(p, uap, retval) 79545914Smckusick struct proc *p; 79654916Storek register struct symlink_args *uap; 79742441Smckusick int *retval; 79842441Smckusick { 79937741Smckusick struct vattr vattr; 80037741Smckusick char *target; 80137741Smckusick int error; 80247540Skarels struct nameidata nd; 8036254Sroot 80437741Smckusick MALLOC(target, char *, MAXPATHLEN, M_NAMEI, M_WAITOK); 80537741Smckusick if (error = copyinstr(uap->target, target, MAXPATHLEN, (u_int *)0)) 80642465Smckusick goto out; 80752322Smckusick NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->linkname, p); 80852322Smckusick if (error = namei(&nd)) 80942465Smckusick goto out; 81052322Smckusick if (nd.ni_vp) { 81152322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 81252322Smckusick if (nd.ni_dvp == nd.ni_vp) 81352322Smckusick vrele(nd.ni_dvp); 81443344Smckusick else 81552322Smckusick vput(nd.ni_dvp); 81652322Smckusick vrele(nd.ni_vp); 81737741Smckusick error = EEXIST; 81837741Smckusick goto out; 8196254Sroot } 82041362Smckusick VATTR_NULL(&vattr); 82145914Smckusick vattr.va_mode = 0777 &~ p->p_fd->fd_cmask; 82252322Smckusick LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 82352322Smckusick error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr, target); 82437741Smckusick out: 82537741Smckusick FREE(target, M_NAMEI); 82647540Skarels return (error); 8276254Sroot } 8286254Sroot 8296254Sroot /* 83049365Smckusick * Delete a name from the filesystem. 8316254Sroot */ 83254916Storek struct unlink_args { 83354916Storek char *name; 83454916Storek }; 83542441Smckusick /* ARGSUSED */ 83642441Smckusick unlink(p, uap, retval) 83745914Smckusick struct proc *p; 83854916Storek struct unlink_args *uap; 83942441Smckusick int *retval; 8406254Sroot { 84137741Smckusick register struct vnode *vp; 84237741Smckusick int error; 84347540Skarels struct nameidata nd; 8446254Sroot 84552322Smckusick NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE, uap->name, p); 84652322Smckusick if (error = namei(&nd)) 84747540Skarels return (error); 84852322Smckusick vp = nd.ni_vp; 84937741Smckusick if (vp->v_type == VDIR && 85047540Skarels (error = suser(p->p_ucred, &p->p_acflag))) 8516254Sroot goto out; 8526254Sroot /* 85349365Smckusick * The root of a mounted filesystem cannot be deleted. 8546254Sroot */ 85537741Smckusick if (vp->v_flag & VROOT) { 85637741Smckusick error = EBUSY; 8576254Sroot goto out; 8586254Sroot } 85945738Smckusick (void) vnode_pager_uncache(vp); 8606254Sroot out: 86142465Smckusick if (!error) { 86252322Smckusick LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 86352192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 86452322Smckusick error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); 86542465Smckusick } else { 86652322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 86752322Smckusick if (nd.ni_dvp == vp) 86852322Smckusick vrele(nd.ni_dvp); 86943344Smckusick else 87052322Smckusick vput(nd.ni_dvp); 87142465Smckusick vput(vp); 87242465Smckusick } 87347540Skarels return (error); 8746254Sroot } 8756254Sroot 87654916Storek struct __lseek_args { 87754863Storek int fdes; 87854863Storek int pad; 87954863Storek off_t off; 88054863Storek int sbase; 88154863Storek }; 88254863Storek 88354348Smckusick #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 8846254Sroot /* 88549365Smckusick * Seek system call. 8866254Sroot */ 88754916Storek struct lseek_args { 88854916Storek int fdes; 88954916Storek long off; 89054916Storek int sbase; 89154916Storek }; 89242441Smckusick lseek(p, uap, retval) 89345914Smckusick struct proc *p; 89454916Storek register struct lseek_args *uap; 89554916Storek int *retval; 89653468Smckusick { 89754916Storek struct __lseek_args nuap; 89854863Storek off_t qret; 89953468Smckusick int error; 90053468Smckusick 90153468Smckusick nuap.fdes = uap->fdes; 90253468Smckusick nuap.off = uap->off; 90353468Smckusick nuap.sbase = uap->sbase; 90453759Smckusick error = __lseek(p, &nuap, &qret); 90554916Storek *(long *)retval = qret; 90653468Smckusick return (error); 90753468Smckusick } 90854348Smckusick #endif /* COMPAT_43 || COMPAT_SUNOS */ 90953468Smckusick 91053468Smckusick /* 91153468Smckusick * Seek system call. 91253468Smckusick */ 91353759Smckusick __lseek(p, uap, retval) 91453468Smckusick struct proc *p; 91554916Storek register struct __lseek_args *uap; 91654916Storek int *retval; 91742441Smckusick { 91847540Skarels struct ucred *cred = p->p_ucred; 91945914Smckusick register struct filedesc *fdp = p->p_fd; 92042441Smckusick register struct file *fp; 92137741Smckusick struct vattr vattr; 92237741Smckusick int error; 9236254Sroot 92447540Skarels if ((unsigned)uap->fdes >= fdp->fd_nfiles || 92547688Skarels (fp = fdp->fd_ofiles[uap->fdes]) == NULL) 92647540Skarels return (EBADF); 92737741Smckusick if (fp->f_type != DTYPE_VNODE) 92847540Skarels return (ESPIPE); 92913878Ssam switch (uap->sbase) { 93013878Ssam 93113878Ssam case L_INCR: 93213878Ssam fp->f_offset += uap->off; 93313878Ssam break; 93413878Ssam 93513878Ssam case L_XTND: 93637741Smckusick if (error = VOP_GETATTR((struct vnode *)fp->f_data, 93748026Smckusick &vattr, cred, p)) 93847540Skarels return (error); 93937741Smckusick fp->f_offset = uap->off + vattr.va_size; 94013878Ssam break; 94113878Ssam 94213878Ssam case L_SET: 94313878Ssam fp->f_offset = uap->off; 94413878Ssam break; 94513878Ssam 94613878Ssam default: 94747540Skarels return (EINVAL); 94813878Ssam } 94954916Storek *(off_t *)retval = fp->f_offset; 95047540Skarels return (0); 9516254Sroot } 9526254Sroot 9536254Sroot /* 95449365Smckusick * Check access permissions. 9556254Sroot */ 95654916Storek struct saccess_args { 95754916Storek char *fname; 95854916Storek int fmode; 95954916Storek }; 96042441Smckusick /* ARGSUSED */ 96142441Smckusick saccess(p, uap, retval) 96245914Smckusick struct proc *p; 96354916Storek register struct saccess_args *uap; 96442441Smckusick int *retval; 96542441Smckusick { 96647540Skarels register struct ucred *cred = p->p_ucred; 96737741Smckusick register struct vnode *vp; 96837741Smckusick int error, mode, svuid, svgid; 96947540Skarels struct nameidata nd; 9706254Sroot 97142441Smckusick svuid = cred->cr_uid; 97242441Smckusick svgid = cred->cr_groups[0]; 97347540Skarels cred->cr_uid = p->p_cred->p_ruid; 97447540Skarels cred->cr_groups[0] = p->p_cred->p_rgid; 97552322Smckusick NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 97652322Smckusick if (error = namei(&nd)) 97737741Smckusick goto out1; 97852322Smckusick vp = nd.ni_vp; 97937741Smckusick /* 98037741Smckusick * fmode == 0 means only check for exist 98137741Smckusick */ 98237741Smckusick if (uap->fmode) { 98337741Smckusick mode = 0; 98437741Smckusick if (uap->fmode & R_OK) 98537741Smckusick mode |= VREAD; 98637741Smckusick if (uap->fmode & W_OK) 98737741Smckusick mode |= VWRITE; 98837741Smckusick if (uap->fmode & X_OK) 98937741Smckusick mode |= VEXEC; 99039543Smckusick if ((mode & VWRITE) == 0 || (error = vn_writechk(vp)) == 0) 99148026Smckusick error = VOP_ACCESS(vp, mode, cred, p); 9926254Sroot } 99337741Smckusick vput(vp); 99437741Smckusick out1: 99542441Smckusick cred->cr_uid = svuid; 99642441Smckusick cred->cr_groups[0] = svgid; 99747540Skarels return (error); 9986254Sroot } 9996254Sroot 100054348Smckusick #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 10016254Sroot /* 100249365Smckusick * Stat system call. 100349365Smckusick * This version follows links. 100437Sbill */ 100554916Storek struct ostat_args { 100654916Storek char *fname; 100754916Storek struct ostat *ub; 100854916Storek }; 100942441Smckusick /* ARGSUSED */ 101053759Smckusick ostat(p, uap, retval) 101145914Smckusick struct proc *p; 101254916Storek register struct ostat_args *uap; 101353468Smckusick int *retval; 101453468Smckusick { 101553468Smckusick struct stat sb; 101653468Smckusick struct ostat osb; 101753468Smckusick int error; 101853468Smckusick struct nameidata nd; 101953468Smckusick 102053468Smckusick NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 102153468Smckusick if (error = namei(&nd)) 102253468Smckusick return (error); 102353468Smckusick error = vn_stat(nd.ni_vp, &sb, p); 102453468Smckusick vput(nd.ni_vp); 102553468Smckusick if (error) 102653468Smckusick return (error); 102753468Smckusick cvtstat(&sb, &osb); 102853468Smckusick error = copyout((caddr_t)&osb, (caddr_t)uap->ub, sizeof (osb)); 102953468Smckusick return (error); 103053468Smckusick } 103153468Smckusick 103253468Smckusick /* 103353468Smckusick * Lstat system call. 103453468Smckusick * This version does not follow links. 103553468Smckusick */ 103654916Storek struct olstat_args { 103754916Storek char *fname; 103854916Storek struct ostat *ub; 103954916Storek }; 104053468Smckusick /* ARGSUSED */ 104153759Smckusick olstat(p, uap, retval) 104253468Smckusick struct proc *p; 104354916Storek register struct olstat_args *uap; 104453468Smckusick int *retval; 104553468Smckusick { 104653468Smckusick struct stat sb; 104753468Smckusick struct ostat osb; 104853468Smckusick int error; 104953468Smckusick struct nameidata nd; 105053468Smckusick 105153468Smckusick NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 105253468Smckusick if (error = namei(&nd)) 105353468Smckusick return (error); 105453468Smckusick error = vn_stat(nd.ni_vp, &sb, p); 105553468Smckusick vput(nd.ni_vp); 105653468Smckusick if (error) 105753468Smckusick return (error); 105853468Smckusick cvtstat(&sb, &osb); 105953468Smckusick error = copyout((caddr_t)&osb, (caddr_t)uap->ub, sizeof (osb)); 106053468Smckusick return (error); 106153468Smckusick } 106253468Smckusick 106353468Smckusick /* 106453468Smckusick * convert from an old to a new stat structure. 106553468Smckusick */ 106653468Smckusick cvtstat(st, ost) 106753468Smckusick struct stat *st; 106853468Smckusick struct ostat *ost; 106953468Smckusick { 107053468Smckusick 107153468Smckusick ost->st_dev = st->st_dev; 107253468Smckusick ost->st_ino = st->st_ino; 107353468Smckusick ost->st_mode = st->st_mode; 107453468Smckusick ost->st_nlink = st->st_nlink; 107553468Smckusick ost->st_uid = st->st_uid; 107653468Smckusick ost->st_gid = st->st_gid; 107753468Smckusick ost->st_rdev = st->st_rdev; 107853468Smckusick if (st->st_size < (quad_t)1 << 32) 107953468Smckusick ost->st_size = st->st_size; 108053468Smckusick else 108153468Smckusick ost->st_size = -2; 108253468Smckusick ost->st_atime = st->st_atime; 108353468Smckusick ost->st_mtime = st->st_mtime; 108453468Smckusick ost->st_ctime = st->st_ctime; 108553468Smckusick ost->st_blksize = st->st_blksize; 108653468Smckusick ost->st_blocks = st->st_blocks; 108753468Smckusick ost->st_flags = st->st_flags; 108853468Smckusick ost->st_gen = st->st_gen; 108953468Smckusick } 109054348Smckusick #endif /* COMPAT_43 || COMPAT_SUNOS */ 109153468Smckusick 109253468Smckusick /* 109353468Smckusick * Stat system call. 109453468Smckusick * This version follows links. 109553468Smckusick */ 109654916Storek struct stat_args { 109754916Storek char *fname; 109854916Storek struct stat *ub; 109954916Storek }; 110053468Smckusick /* ARGSUSED */ 110153759Smckusick stat(p, uap, retval) 110253468Smckusick struct proc *p; 110354916Storek register struct stat_args *uap; 110442441Smckusick int *retval; 110537Sbill { 110642441Smckusick struct stat sb; 110742441Smckusick int error; 110847540Skarels struct nameidata nd; 110937Sbill 111052322Smckusick NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 111152322Smckusick if (error = namei(&nd)) 111247540Skarels return (error); 111352322Smckusick error = vn_stat(nd.ni_vp, &sb, p); 111452322Smckusick vput(nd.ni_vp); 111542441Smckusick if (error) 111647540Skarels return (error); 111742441Smckusick error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb)); 111847540Skarels return (error); 111937Sbill } 112037Sbill 112137Sbill /* 112249365Smckusick * Lstat system call. 112349365Smckusick * This version does not follow links. 11245992Swnj */ 112554916Storek struct lstat_args { 112654916Storek char *fname; 112754916Storek struct stat *ub; 112854916Storek }; 112942441Smckusick /* ARGSUSED */ 113053759Smckusick lstat(p, uap, retval) 113145914Smckusick struct proc *p; 113254916Storek register struct lstat_args *uap; 113342441Smckusick int *retval; 113442441Smckusick { 113512756Ssam struct stat sb; 113637741Smckusick int error; 113747540Skarels struct nameidata nd; 11385992Swnj 113952322Smckusick NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 114052322Smckusick if (error = namei(&nd)) 114147540Skarels return (error); 114252322Smckusick error = vn_stat(nd.ni_vp, &sb, p); 114352322Smckusick vput(nd.ni_vp); 114437741Smckusick if (error) 114547540Skarels return (error); 114637741Smckusick error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb)); 114747540Skarels return (error); 11485992Swnj } 11495992Swnj 11505992Swnj /* 115149365Smckusick * Return target name of a symbolic link. 115237Sbill */ 115354916Storek struct readlink_args { 115454916Storek char *name; 115554916Storek char *buf; 115654916Storek int count; 115754916Storek }; 115842441Smckusick /* ARGSUSED */ 115942441Smckusick readlink(p, uap, retval) 116045914Smckusick struct proc *p; 116154916Storek register struct readlink_args *uap; 116242441Smckusick int *retval; 116342441Smckusick { 116437741Smckusick register struct vnode *vp; 116537741Smckusick struct iovec aiov; 116637741Smckusick struct uio auio; 116737741Smckusick int error; 116847540Skarels struct nameidata nd; 11695992Swnj 117052322Smckusick NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, uap->name, p); 117152322Smckusick if (error = namei(&nd)) 117247540Skarels return (error); 117352322Smckusick vp = nd.ni_vp; 117437741Smckusick if (vp->v_type != VLNK) { 117537741Smckusick error = EINVAL; 11765992Swnj goto out; 11775992Swnj } 117837741Smckusick aiov.iov_base = uap->buf; 117937741Smckusick aiov.iov_len = uap->count; 118037741Smckusick auio.uio_iov = &aiov; 118137741Smckusick auio.uio_iovcnt = 1; 118237741Smckusick auio.uio_offset = 0; 118337741Smckusick auio.uio_rw = UIO_READ; 118437741Smckusick auio.uio_segflg = UIO_USERSPACE; 118548026Smckusick auio.uio_procp = p; 118637741Smckusick auio.uio_resid = uap->count; 118747540Skarels error = VOP_READLINK(vp, &auio, p->p_ucred); 11885992Swnj out: 118937741Smckusick vput(vp); 119042441Smckusick *retval = uap->count - auio.uio_resid; 119147540Skarels return (error); 11925992Swnj } 11935992Swnj 11949167Ssam /* 119538259Smckusick * Change flags of a file given path name. 119638259Smckusick */ 119754916Storek struct chflags_args { 119854916Storek char *fname; 119954916Storek int flags; 120054916Storek }; 120142441Smckusick /* ARGSUSED */ 120242441Smckusick chflags(p, uap, retval) 120345914Smckusick struct proc *p; 120454916Storek register struct chflags_args *uap; 120542441Smckusick int *retval; 120642441Smckusick { 120738259Smckusick register struct vnode *vp; 120838259Smckusick struct vattr vattr; 120938259Smckusick int error; 121047540Skarels struct nameidata nd; 121138259Smckusick 121252322Smckusick NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 121352322Smckusick if (error = namei(&nd)) 121447540Skarels return (error); 121552322Smckusick vp = nd.ni_vp; 121641400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 121738259Smckusick error = EROFS; 121838259Smckusick goto out; 121938259Smckusick } 122045785Sbostic VATTR_NULL(&vattr); 122145785Sbostic vattr.va_flags = uap->flags; 122252192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 122348026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 122438259Smckusick out: 122538259Smckusick vput(vp); 122647540Skarels return (error); 122738259Smckusick } 122838259Smckusick 122938259Smckusick /* 123038259Smckusick * Change flags of a file given a file descriptor. 123138259Smckusick */ 123254916Storek struct fchflags_args { 123354916Storek int fd; 123454916Storek int flags; 123554916Storek }; 123642441Smckusick /* ARGSUSED */ 123742441Smckusick fchflags(p, uap, retval) 123845914Smckusick struct proc *p; 123954916Storek register struct fchflags_args *uap; 124042441Smckusick int *retval; 124142441Smckusick { 124238259Smckusick struct vattr vattr; 124338259Smckusick struct vnode *vp; 124438259Smckusick struct file *fp; 124538259Smckusick int error; 124638259Smckusick 124745914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 124847540Skarels return (error); 124938259Smckusick vp = (struct vnode *)fp->f_data; 125038259Smckusick VOP_LOCK(vp); 125141400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 125238259Smckusick error = EROFS; 125338259Smckusick goto out; 125438259Smckusick } 125545785Sbostic VATTR_NULL(&vattr); 125645785Sbostic vattr.va_flags = uap->flags; 125752192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 125848026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 125938259Smckusick out: 126038259Smckusick VOP_UNLOCK(vp); 126147540Skarels return (error); 126238259Smckusick } 126338259Smckusick 126438259Smckusick /* 12659167Ssam * Change mode of a file given path name. 12669167Ssam */ 126754916Storek struct chmod_args { 126854916Storek char *fname; 126954916Storek int fmode; 127054916Storek }; 127142441Smckusick /* ARGSUSED */ 127242441Smckusick chmod(p, uap, retval) 127345914Smckusick struct proc *p; 127454916Storek register struct chmod_args *uap; 127542441Smckusick int *retval; 127642441Smckusick { 127737741Smckusick register struct vnode *vp; 127837741Smckusick struct vattr vattr; 127937741Smckusick int error; 128047540Skarels struct nameidata nd; 12815992Swnj 128252322Smckusick NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 128352322Smckusick if (error = namei(&nd)) 128447540Skarels return (error); 128552322Smckusick vp = nd.ni_vp; 128641400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 128737741Smckusick error = EROFS; 128837741Smckusick goto out; 128937741Smckusick } 129045785Sbostic VATTR_NULL(&vattr); 129145785Sbostic vattr.va_mode = uap->fmode & 07777; 129252192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 129348026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 129437741Smckusick out: 129537741Smckusick vput(vp); 129647540Skarels return (error); 12977701Ssam } 12987439Sroot 12999167Ssam /* 13009167Ssam * Change mode of a file given a file descriptor. 13019167Ssam */ 130254916Storek struct fchmod_args { 130354916Storek int fd; 130454916Storek int fmode; 130554916Storek }; 130642441Smckusick /* ARGSUSED */ 130742441Smckusick fchmod(p, uap, retval) 130845914Smckusick struct proc *p; 130954916Storek register struct fchmod_args *uap; 131042441Smckusick int *retval; 131142441Smckusick { 131237741Smckusick struct vattr vattr; 131337741Smckusick struct vnode *vp; 131437741Smckusick struct file *fp; 131537741Smckusick int error; 13167701Ssam 131745914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 131847540Skarels return (error); 131937741Smckusick vp = (struct vnode *)fp->f_data; 132037741Smckusick VOP_LOCK(vp); 132141400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 132237741Smckusick error = EROFS; 132337741Smckusick goto out; 13247439Sroot } 132545785Sbostic VATTR_NULL(&vattr); 132645785Sbostic vattr.va_mode = uap->fmode & 07777; 132752192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 132848026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 132937741Smckusick out: 133037741Smckusick VOP_UNLOCK(vp); 133147540Skarels return (error); 13325992Swnj } 13335992Swnj 13349167Ssam /* 13359167Ssam * Set ownership given a path name. 13369167Ssam */ 133754916Storek struct chown_args { 133854916Storek char *fname; 133954916Storek int uid; 134054916Storek int gid; 134154916Storek }; 134242441Smckusick /* ARGSUSED */ 134342441Smckusick chown(p, uap, retval) 134445914Smckusick struct proc *p; 134554916Storek register struct chown_args *uap; 134642441Smckusick int *retval; 134742441Smckusick { 134837741Smckusick register struct vnode *vp; 134937741Smckusick struct vattr vattr; 135037741Smckusick int error; 135147540Skarels struct nameidata nd; 135237Sbill 135352322Smckusick NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 135452322Smckusick if (error = namei(&nd)) 135547540Skarels return (error); 135652322Smckusick vp = nd.ni_vp; 135741400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 135837741Smckusick error = EROFS; 135937741Smckusick goto out; 136037741Smckusick } 136145785Sbostic VATTR_NULL(&vattr); 136245785Sbostic vattr.va_uid = uap->uid; 136345785Sbostic vattr.va_gid = uap->gid; 136452192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 136548026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 136637741Smckusick out: 136737741Smckusick vput(vp); 136847540Skarels return (error); 13697701Ssam } 13707439Sroot 13719167Ssam /* 13729167Ssam * Set ownership given a file descriptor. 13739167Ssam */ 137454916Storek struct fchown_args { 137554916Storek int fd; 137654916Storek int uid; 137754916Storek int gid; 137854916Storek }; 137942441Smckusick /* ARGSUSED */ 138042441Smckusick fchown(p, uap, retval) 138145914Smckusick struct proc *p; 138254916Storek register struct fchown_args *uap; 138342441Smckusick int *retval; 138442441Smckusick { 138537741Smckusick struct vattr vattr; 138637741Smckusick struct vnode *vp; 138737741Smckusick struct file *fp; 138837741Smckusick int error; 13897701Ssam 139045914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 139147540Skarels return (error); 139237741Smckusick vp = (struct vnode *)fp->f_data; 139337741Smckusick VOP_LOCK(vp); 139441400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 139537741Smckusick error = EROFS; 139637741Smckusick goto out; 139737741Smckusick } 139845785Sbostic VATTR_NULL(&vattr); 139945785Sbostic vattr.va_uid = uap->uid; 140045785Sbostic vattr.va_gid = uap->gid; 140152192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 140248026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 140337741Smckusick out: 140437741Smckusick VOP_UNLOCK(vp); 140547540Skarels return (error); 14067701Ssam } 14077701Ssam 140842441Smckusick /* 140942441Smckusick * Set the access and modification times of a file. 141042441Smckusick */ 141154916Storek struct utimes_args { 141254916Storek char *fname; 141354916Storek struct timeval *tptr; 141454916Storek }; 141542441Smckusick /* ARGSUSED */ 141642441Smckusick utimes(p, uap, retval) 141745914Smckusick struct proc *p; 141854916Storek register struct utimes_args *uap; 141942441Smckusick int *retval; 142042441Smckusick { 142137741Smckusick register struct vnode *vp; 142211811Ssam struct timeval tv[2]; 142337741Smckusick struct vattr vattr; 142437741Smckusick int error; 142547540Skarels struct nameidata nd; 142611811Ssam 142737741Smckusick if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv))) 142847540Skarels return (error); 142952322Smckusick NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 143052322Smckusick if (error = namei(&nd)) 143147540Skarels return (error); 143252322Smckusick vp = nd.ni_vp; 143341400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 143437741Smckusick error = EROFS; 143537741Smckusick goto out; 143621015Smckusick } 143745785Sbostic VATTR_NULL(&vattr); 143854100Smckusick vattr.va_atime.ts_sec = tv[0].tv_sec; 143954100Smckusick vattr.va_atime.ts_nsec = tv[0].tv_usec * 1000; 144054100Smckusick vattr.va_mtime.ts_sec = tv[1].tv_sec; 144154100Smckusick vattr.va_mtime.ts_nsec = tv[1].tv_usec * 1000; 144252192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 144348026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 144437741Smckusick out: 144537741Smckusick vput(vp); 144647540Skarels return (error); 144711811Ssam } 144811811Ssam 144954916Storek struct __truncate_args { 145054863Storek char *fname; 145154863Storek int pad; 145254863Storek off_t length; 145354863Storek }; 145453468Smckusick 145553468Smckusick /* 145653468Smckusick * Truncate a file given its path name. 145753468Smckusick */ 145853468Smckusick /* ARGSUSED */ 145953759Smckusick __truncate(p, uap, retval) 146053468Smckusick struct proc *p; 146154916Storek register struct __truncate_args *uap; 146253468Smckusick int *retval; 146353468Smckusick { 146437741Smckusick register struct vnode *vp; 146537741Smckusick struct vattr vattr; 146637741Smckusick int error; 146747540Skarels struct nameidata nd; 14687701Ssam 146952322Smckusick NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 147052322Smckusick if (error = namei(&nd)) 147147540Skarels return (error); 147252322Smckusick vp = nd.ni_vp; 147337741Smckusick if (vp->v_type == VDIR) { 147437741Smckusick error = EISDIR; 147537741Smckusick goto out; 14767701Ssam } 147738399Smckusick if ((error = vn_writechk(vp)) || 147848026Smckusick (error = VOP_ACCESS(vp, VWRITE, p->p_ucred, p))) 147937741Smckusick goto out; 148045785Sbostic VATTR_NULL(&vattr); 148145785Sbostic vattr.va_size = uap->length; 148252192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 148348026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 148437741Smckusick out: 148537741Smckusick vput(vp); 148647540Skarels return (error); 14877701Ssam } 14887701Ssam 148954916Storek struct __ftruncate_args { 149054863Storek int fd; 149154863Storek int pad; 149254863Storek off_t length; 149354863Storek }; 149454863Storek 14959167Ssam /* 14969167Ssam * Truncate a file given a file descriptor. 14979167Ssam */ 149842441Smckusick /* ARGSUSED */ 149953759Smckusick __ftruncate(p, uap, retval) 150045914Smckusick struct proc *p; 150154916Storek register struct __ftruncate_args *uap; 150242441Smckusick int *retval; 150342441Smckusick { 150437741Smckusick struct vattr vattr; 150537741Smckusick struct vnode *vp; 15067701Ssam struct file *fp; 150737741Smckusick int error; 15087701Ssam 150945914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 151047540Skarels return (error); 151137741Smckusick if ((fp->f_flag & FWRITE) == 0) 151247540Skarels return (EINVAL); 151337741Smckusick vp = (struct vnode *)fp->f_data; 151437741Smckusick VOP_LOCK(vp); 151537741Smckusick if (vp->v_type == VDIR) { 151637741Smckusick error = EISDIR; 151737741Smckusick goto out; 15187701Ssam } 151938399Smckusick if (error = vn_writechk(vp)) 152037741Smckusick goto out; 152145785Sbostic VATTR_NULL(&vattr); 152245785Sbostic vattr.va_size = uap->length; 152352192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 152448026Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred, p); 152537741Smckusick out: 152637741Smckusick VOP_UNLOCK(vp); 152747540Skarels return (error); 15287701Ssam } 15297701Ssam 153054863Storek #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 15319167Ssam /* 153254863Storek * Truncate a file given its path name. 153354863Storek */ 153454916Storek struct truncate_args { 153554916Storek char *fname; 153654916Storek long length; 153754916Storek }; 153854863Storek /* ARGSUSED */ 153954863Storek truncate(p, uap, retval) 154054863Storek struct proc *p; 154154916Storek register struct truncate_args *uap; 154254863Storek int *retval; 154354863Storek { 154454916Storek struct __truncate_args nuap; 154554863Storek 154654863Storek nuap.fname = uap->fname; 154754863Storek nuap.length = uap->length; 154854863Storek return (__truncate(p, &nuap, retval)); 154954863Storek } 155054863Storek 155154863Storek /* 155254863Storek * Truncate a file given a file descriptor. 155354863Storek */ 155454916Storek struct ftruncate_args { 155554916Storek int fd; 155654916Storek long length; 155754916Storek }; 155854863Storek /* ARGSUSED */ 155954863Storek ftruncate(p, uap, retval) 156054863Storek struct proc *p; 156154916Storek register struct ftruncate_args *uap; 156254863Storek int *retval; 156354863Storek { 156454969Smckusick struct __ftruncate_args nuap; 156554863Storek 156654863Storek nuap.fd = uap->fd; 156754863Storek nuap.length = uap->length; 156854863Storek return (__ftruncate(p, &nuap, retval)); 156954863Storek } 157054863Storek #endif /* COMPAT_43 || COMPAT_SUNOS */ 157154863Storek 157254863Storek /* 15739167Ssam * Synch an open file. 15749167Ssam */ 157554916Storek struct fsync_args { 157654916Storek int fd; 157754916Storek }; 157842441Smckusick /* ARGSUSED */ 157942441Smckusick fsync(p, uap, retval) 158045914Smckusick struct proc *p; 158154916Storek struct fsync_args *uap; 158242441Smckusick int *retval; 15839167Ssam { 158439592Smckusick register struct vnode *vp; 15859167Ssam struct file *fp; 158637741Smckusick int error; 15879167Ssam 158845914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 158947540Skarels return (error); 159039592Smckusick vp = (struct vnode *)fp->f_data; 159139592Smckusick VOP_LOCK(vp); 159254441Smckusick error = VOP_FSYNC(vp, fp->f_cred, MNT_WAIT, p); 159339592Smckusick VOP_UNLOCK(vp); 159447540Skarels return (error); 15959167Ssam } 15969167Ssam 15979167Ssam /* 15989167Ssam * Rename system call. 15999167Ssam * 16009167Ssam * Source and destination must either both be directories, or both 16019167Ssam * not be directories. If target is a directory, it must be empty. 16029167Ssam */ 160354916Storek struct rename_args { 160454916Storek char *from; 160554916Storek char *to; 160654916Storek }; 160742441Smckusick /* ARGSUSED */ 160842441Smckusick rename(p, uap, retval) 160945914Smckusick struct proc *p; 161054916Storek register struct rename_args *uap; 161142441Smckusick int *retval; 161242441Smckusick { 161337741Smckusick register struct vnode *tvp, *fvp, *tdvp; 161449735Smckusick struct nameidata fromnd, tond; 161537741Smckusick int error; 16167701Ssam 161752322Smckusick NDINIT(&fromnd, DELETE, WANTPARENT | SAVESTART, UIO_USERSPACE, 161852322Smckusick uap->from, p); 161952322Smckusick if (error = namei(&fromnd)) 162047540Skarels return (error); 162149735Smckusick fvp = fromnd.ni_vp; 162252322Smckusick NDINIT(&tond, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART, 162352322Smckusick UIO_USERSPACE, uap->to, p); 162452322Smckusick if (error = namei(&tond)) { 162552230Sheideman VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 162649735Smckusick vrele(fromnd.ni_dvp); 162742465Smckusick vrele(fvp); 162842465Smckusick goto out1; 162942465Smckusick } 163037741Smckusick tdvp = tond.ni_dvp; 163137741Smckusick tvp = tond.ni_vp; 163237741Smckusick if (tvp != NULL) { 163337741Smckusick if (fvp->v_type == VDIR && tvp->v_type != VDIR) { 163439242Sbostic error = ENOTDIR; 163537741Smckusick goto out; 163637741Smckusick } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) { 163739242Sbostic error = EISDIR; 163837741Smckusick goto out; 16399167Ssam } 16409167Ssam } 164139286Smckusick if (fvp == tdvp) 164237741Smckusick error = EINVAL; 164339286Smckusick /* 164449735Smckusick * If source is the same as the destination (that is the 164549735Smckusick * same inode number with the same name in the same directory), 164639286Smckusick * then there is nothing to do. 164739286Smckusick */ 164849735Smckusick if (fvp == tvp && fromnd.ni_dvp == tdvp && 164952322Smckusick fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen && 165052322Smckusick !bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr, 165152322Smckusick fromnd.ni_cnd.cn_namelen)) 165239286Smckusick error = -1; 165337741Smckusick out: 165442465Smckusick if (!error) { 165552192Smckusick LEASE_CHECK(tdvp, p, p->p_ucred, LEASE_WRITE); 165652192Smckusick if (fromnd.ni_dvp != tdvp) 165752192Smckusick LEASE_CHECK(fromnd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 165852192Smckusick if (tvp) 165952192Smckusick LEASE_CHECK(tvp, p, p->p_ucred, LEASE_WRITE); 166052230Sheideman error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd, 166152230Sheideman tond.ni_dvp, tond.ni_vp, &tond.ni_cnd); 166242465Smckusick } else { 166352230Sheideman VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd); 166443344Smckusick if (tdvp == tvp) 166543344Smckusick vrele(tdvp); 166643344Smckusick else 166743344Smckusick vput(tdvp); 166842465Smckusick if (tvp) 166942465Smckusick vput(tvp); 167052230Sheideman VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 167149735Smckusick vrele(fromnd.ni_dvp); 167242465Smckusick vrele(fvp); 16739167Ssam } 167449735Smckusick vrele(tond.ni_startdir); 167552322Smckusick FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI); 167637741Smckusick out1: 167749735Smckusick vrele(fromnd.ni_startdir); 167852322Smckusick FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI); 167939286Smckusick if (error == -1) 168047540Skarels return (0); 168147540Skarels return (error); 16827701Ssam } 16837701Ssam 16847535Sroot /* 168549365Smckusick * Mkdir system call. 168612756Ssam */ 168754916Storek struct mkdir_args { 168854916Storek char *name; 168954916Storek int dmode; 169054916Storek }; 169142441Smckusick /* ARGSUSED */ 169242441Smckusick mkdir(p, uap, retval) 169345914Smckusick struct proc *p; 169454916Storek register struct mkdir_args *uap; 169542441Smckusick int *retval; 169642441Smckusick { 169737741Smckusick register struct vnode *vp; 169837741Smckusick struct vattr vattr; 169937741Smckusick int error; 170047540Skarels struct nameidata nd; 170112756Ssam 170252322Smckusick NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->name, p); 170352322Smckusick if (error = namei(&nd)) 170447540Skarels return (error); 170552322Smckusick vp = nd.ni_vp; 170637741Smckusick if (vp != NULL) { 170752322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 170852322Smckusick if (nd.ni_dvp == vp) 170952322Smckusick vrele(nd.ni_dvp); 171043344Smckusick else 171152322Smckusick vput(nd.ni_dvp); 171242465Smckusick vrele(vp); 171347540Skarels return (EEXIST); 171412756Ssam } 171541362Smckusick VATTR_NULL(&vattr); 171637741Smckusick vattr.va_type = VDIR; 171745914Smckusick vattr.va_mode = (uap->dmode & 0777) &~ p->p_fd->fd_cmask; 171852322Smckusick LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 171952322Smckusick error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr); 172038145Smckusick if (!error) 172152322Smckusick vput(nd.ni_vp); 172247540Skarels return (error); 172312756Ssam } 172412756Ssam 172512756Ssam /* 172612756Ssam * Rmdir system call. 172712756Ssam */ 172854916Storek struct rmdir_args { 172954916Storek char *name; 173054916Storek }; 173142441Smckusick /* ARGSUSED */ 173242441Smckusick rmdir(p, uap, retval) 173345914Smckusick struct proc *p; 173454916Storek struct rmdir_args *uap; 173542441Smckusick int *retval; 173612756Ssam { 173737741Smckusick register struct vnode *vp; 173837741Smckusick int error; 173947540Skarels struct nameidata nd; 174012756Ssam 174152322Smckusick NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE, uap->name, p); 174252322Smckusick if (error = namei(&nd)) 174347540Skarels return (error); 174452322Smckusick vp = nd.ni_vp; 174537741Smckusick if (vp->v_type != VDIR) { 174637741Smckusick error = ENOTDIR; 174712756Ssam goto out; 174812756Ssam } 174912756Ssam /* 175037741Smckusick * No rmdir "." please. 175112756Ssam */ 175252322Smckusick if (nd.ni_dvp == vp) { 175337741Smckusick error = EINVAL; 175412756Ssam goto out; 175512756Ssam } 175612756Ssam /* 175749365Smckusick * The root of a mounted filesystem cannot be deleted. 175812756Ssam */ 175937741Smckusick if (vp->v_flag & VROOT) 176037741Smckusick error = EBUSY; 176112756Ssam out: 176242465Smckusick if (!error) { 176352322Smckusick LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 176452192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 176552322Smckusick error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); 176642465Smckusick } else { 176752322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 176852322Smckusick if (nd.ni_dvp == vp) 176952322Smckusick vrele(nd.ni_dvp); 177043344Smckusick else 177152322Smckusick vput(nd.ni_dvp); 177242465Smckusick vput(vp); 177342465Smckusick } 177447540Skarels return (error); 177512756Ssam } 177612756Ssam 177754620Smckusick #ifdef COMPAT_43 177837741Smckusick /* 177949365Smckusick * Read a block of directory entries in a file system independent format. 178037741Smckusick */ 178154916Storek struct ogetdirentries_args { 178254916Storek int fd; 178354916Storek char *buf; 178454916Storek unsigned count; 178554916Storek long *basep; 178654916Storek }; 178754620Smckusick ogetdirentries(p, uap, retval) 178854620Smckusick struct proc *p; 178954916Storek register struct ogetdirentries_args *uap; 179054620Smckusick int *retval; 179154620Smckusick { 179254620Smckusick register struct vnode *vp; 179354620Smckusick struct file *fp; 179454620Smckusick struct uio auio, kuio; 179554620Smckusick struct iovec aiov, kiov; 179654620Smckusick struct dirent *dp, *edp; 179754620Smckusick caddr_t dirbuf; 179854620Smckusick int error, readcnt; 179954969Smckusick long loff; 180054620Smckusick 180154620Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 180254620Smckusick return (error); 180354620Smckusick if ((fp->f_flag & FREAD) == 0) 180454620Smckusick return (EBADF); 180554620Smckusick vp = (struct vnode *)fp->f_data; 180654620Smckusick if (vp->v_type != VDIR) 180754620Smckusick return (EINVAL); 180854620Smckusick aiov.iov_base = uap->buf; 180954620Smckusick aiov.iov_len = uap->count; 181054620Smckusick auio.uio_iov = &aiov; 181154620Smckusick auio.uio_iovcnt = 1; 181254620Smckusick auio.uio_rw = UIO_READ; 181354620Smckusick auio.uio_segflg = UIO_USERSPACE; 181454620Smckusick auio.uio_procp = p; 181554620Smckusick auio.uio_resid = uap->count; 181654620Smckusick VOP_LOCK(vp); 181754969Smckusick loff = auio.uio_offset = fp->f_offset; 181854620Smckusick # if (BYTE_ORDER != LITTLE_ENDIAN) 181954620Smckusick if (vp->v_mount->mnt_maxsymlinklen <= 0) 182054620Smckusick error = VOP_READDIR(vp, &auio, fp->f_cred); 182154620Smckusick else 182254620Smckusick # endif 182354620Smckusick { 182454620Smckusick kuio = auio; 182554620Smckusick kuio.uio_iov = &kiov; 182654620Smckusick kuio.uio_segflg = UIO_SYSSPACE; 182754620Smckusick kiov.iov_len = uap->count; 182854620Smckusick MALLOC(dirbuf, caddr_t, uap->count, M_TEMP, M_WAITOK); 182954620Smckusick kiov.iov_base = dirbuf; 183054620Smckusick error = VOP_READDIR(vp, &kuio, fp->f_cred); 183154620Smckusick if (error == 0) { 183254620Smckusick readcnt = uap->count - kuio.uio_resid; 183354620Smckusick edp = (struct dirent *)&dirbuf[readcnt]; 183454620Smckusick for (dp = (struct dirent *)dirbuf; dp < edp; ) { 183554620Smckusick # if (BYTE_ORDER == LITTLE_ENDIAN) 183654969Smckusick /* 1837*55009Smckusick * The expected low byte of 1838*55009Smckusick * dp->d_namlen is our dp->d_type. 1839*55009Smckusick * The high MBZ byte of dp->d_namlen 1840*55009Smckusick * is our dp->d_namlen. 184154969Smckusick */ 1842*55009Smckusick dp->d_type = dp->d_namlen; 1843*55009Smckusick dp->d_namlen = 0; 1844*55009Smckusick # else 1845*55009Smckusick /* 1846*55009Smckusick * The dp->d_type is the high byte 1847*55009Smckusick * of the expected dp->d_namlen, 1848*55009Smckusick * so must be zero'ed. 1849*55009Smckusick */ 1850*55009Smckusick dp->d_type = 0; 185154620Smckusick # endif 185254620Smckusick if (dp->d_reclen > 0) { 185354620Smckusick dp = (struct dirent *) 185454620Smckusick ((char *)dp + dp->d_reclen); 185554620Smckusick } else { 185654620Smckusick error = EIO; 185754620Smckusick break; 185854620Smckusick } 185954620Smckusick } 186054620Smckusick if (dp >= edp) 186154620Smckusick error = uiomove(dirbuf, readcnt, &auio); 186254620Smckusick } 186354620Smckusick FREE(dirbuf, M_TEMP); 186454620Smckusick } 186554620Smckusick fp->f_offset = auio.uio_offset; 186654620Smckusick VOP_UNLOCK(vp); 186754620Smckusick if (error) 186854620Smckusick return (error); 186954969Smckusick error = copyout((caddr_t)&loff, (caddr_t)uap->basep, sizeof(long)); 187054620Smckusick *retval = uap->count - auio.uio_resid; 187154620Smckusick return (error); 187254620Smckusick } 187354620Smckusick #endif 187454620Smckusick 187554620Smckusick /* 187654620Smckusick * Read a block of directory entries in a file system independent format. 187754620Smckusick */ 187854916Storek struct getdirentries_args { 187954916Storek int fd; 188054916Storek char *buf; 188154916Storek unsigned count; 188254916Storek long *basep; 188354916Storek }; 188442441Smckusick getdirentries(p, uap, retval) 188545914Smckusick struct proc *p; 188654916Storek register struct getdirentries_args *uap; 188742441Smckusick int *retval; 188842441Smckusick { 188939592Smckusick register struct vnode *vp; 189016540Ssam struct file *fp; 189137741Smckusick struct uio auio; 189237741Smckusick struct iovec aiov; 189354969Smckusick long loff; 189454441Smckusick int error; 189512756Ssam 189645914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 189747540Skarels return (error); 189837741Smckusick if ((fp->f_flag & FREAD) == 0) 189947540Skarels return (EBADF); 190039592Smckusick vp = (struct vnode *)fp->f_data; 190139592Smckusick if (vp->v_type != VDIR) 190247540Skarels return (EINVAL); 190337741Smckusick aiov.iov_base = uap->buf; 190437741Smckusick aiov.iov_len = uap->count; 190537741Smckusick auio.uio_iov = &aiov; 190637741Smckusick auio.uio_iovcnt = 1; 190737741Smckusick auio.uio_rw = UIO_READ; 190837741Smckusick auio.uio_segflg = UIO_USERSPACE; 190948026Smckusick auio.uio_procp = p; 191037741Smckusick auio.uio_resid = uap->count; 191139592Smckusick VOP_LOCK(vp); 191254969Smckusick loff = auio.uio_offset = fp->f_offset; 191354441Smckusick error = VOP_READDIR(vp, &auio, fp->f_cred); 191439592Smckusick fp->f_offset = auio.uio_offset; 191539592Smckusick VOP_UNLOCK(vp); 191639592Smckusick if (error) 191747540Skarels return (error); 191854969Smckusick error = copyout((caddr_t)&loff, (caddr_t)uap->basep, sizeof(long)); 191942441Smckusick *retval = uap->count - auio.uio_resid; 192047540Skarels return (error); 192112756Ssam } 192212756Ssam 192312756Ssam /* 192449365Smckusick * Set the mode mask for creation of filesystem nodes. 192512756Ssam */ 192654916Storek struct umask_args { 192754916Storek int mask; 192854916Storek }; 192954916Storek mode_t /* XXX */ 193042441Smckusick umask(p, uap, retval) 193145914Smckusick struct proc *p; 193254916Storek struct umask_args *uap; 193342441Smckusick int *retval; 193412756Ssam { 193545914Smckusick register struct filedesc *fdp = p->p_fd; 193612756Ssam 193745914Smckusick *retval = fdp->fd_cmask; 193845914Smckusick fdp->fd_cmask = uap->mask & 07777; 193947540Skarels return (0); 194012756Ssam } 194137741Smckusick 194239566Smarc /* 194339566Smarc * Void all references to file by ripping underlying filesystem 194439566Smarc * away from vnode. 194539566Smarc */ 194654916Storek struct revoke_args { 194754916Storek char *fname; 194854916Storek }; 194942441Smckusick /* ARGSUSED */ 195042441Smckusick revoke(p, uap, retval) 195145914Smckusick struct proc *p; 195254916Storek register struct revoke_args *uap; 195342441Smckusick int *retval; 195442441Smckusick { 195539566Smarc register struct vnode *vp; 195639566Smarc struct vattr vattr; 195739566Smarc int error; 195847540Skarels struct nameidata nd; 195939566Smarc 196052322Smckusick NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->fname, p); 196152322Smckusick if (error = namei(&nd)) 196247540Skarels return (error); 196352322Smckusick vp = nd.ni_vp; 196439566Smarc if (vp->v_type != VCHR && vp->v_type != VBLK) { 196539566Smarc error = EINVAL; 196639566Smarc goto out; 196739566Smarc } 196848026Smckusick if (error = VOP_GETATTR(vp, &vattr, p->p_ucred, p)) 196939566Smarc goto out; 197047540Skarels if (p->p_ucred->cr_uid != vattr.va_uid && 197147540Skarels (error = suser(p->p_ucred, &p->p_acflag))) 197239566Smarc goto out; 197339805Smckusick if (vp->v_usecount > 1 || (vp->v_flag & VALIASED)) 197439632Smckusick vgoneall(vp); 197539566Smarc out: 197639566Smarc vrele(vp); 197747540Skarels return (error); 197839566Smarc } 197939566Smarc 198049365Smckusick /* 198149365Smckusick * Convert a user file descriptor to a kernel file entry. 198249365Smckusick */ 198345914Smckusick getvnode(fdp, fdes, fpp) 198445914Smckusick struct filedesc *fdp; 198537741Smckusick struct file **fpp; 198637741Smckusick int fdes; 198737741Smckusick { 198837741Smckusick struct file *fp; 198937741Smckusick 199047540Skarels if ((unsigned)fdes >= fdp->fd_nfiles || 199147688Skarels (fp = fdp->fd_ofiles[fdes]) == NULL) 199237741Smckusick return (EBADF); 199337741Smckusick if (fp->f_type != DTYPE_VNODE) 199437741Smckusick return (EINVAL); 199537741Smckusick *fpp = fp; 199637741Smckusick return (0); 199737741Smckusick } 1998