123405Smckusick /* 237741Smckusick * Copyright (c) 1989 The Regents of the University of California. 337741Smckusick * All rights reserved. 423405Smckusick * 544459Sbostic * %sccs.include.redist.c% 637741Smckusick * 7*55451Spendry * @(#)vfs_syscalls.c 7.96 (Berkeley) 07/20/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 } 81*55451Spendry if (vp->v_usecount != 1 && (uap->flags & MNT_UNION) == 0) { 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; 141*55451Spendry if (uap->flags & MNT_UNION) 142*55451Spendry mp->mnt_flag |= MNT_UNION; 143*55451Spendry else 144*55451Spendry mp->mnt_flag &= ~MNT_UNION; 14539335Smckusick /* 14639335Smckusick * Mount the filesystem. 14739335Smckusick */ 14852322Smckusick error = VFS_MOUNT(mp, uap->dir, uap->data, &nd, p); 14941400Smckusick if (mp->mnt_flag & MNT_UPDATE) { 15041400Smckusick mp->mnt_flag &= ~MNT_UPDATE; 15139335Smckusick vrele(vp); 15240111Smckusick if (error) 15341400Smckusick mp->mnt_flag = flag; 15447540Skarels return (error); 15539335Smckusick } 15640110Smckusick /* 15740110Smckusick * Put the new filesystem on the mount list after root. 15840110Smckusick */ 15941400Smckusick mp->mnt_next = rootfs->mnt_next; 16041400Smckusick mp->mnt_prev = rootfs; 16141400Smckusick rootfs->mnt_next = mp; 16241400Smckusick mp->mnt_next->mnt_prev = mp; 16337741Smckusick cache_purge(vp); 16437741Smckusick if (!error) { 16539335Smckusick VOP_UNLOCK(vp); 16637741Smckusick vfs_unlock(mp); 16748026Smckusick error = VFS_START(mp, 0, p); 16837741Smckusick } else { 16937741Smckusick vfs_remove(mp); 17037741Smckusick free((caddr_t)mp, M_MOUNT); 17139335Smckusick vput(vp); 17237741Smckusick } 17347540Skarels return (error); 1746254Sroot } 1756254Sroot 1769167Ssam /* 17737741Smckusick * Unmount system call. 17837741Smckusick * 17937741Smckusick * Note: unmount takes a path to the vnode mounted on as argument, 18037741Smckusick * not special file (as before). 1819167Ssam */ 18254916Storek struct unmount_args { 18354916Storek char *pathp; 18454916Storek int flags; 18554916Storek }; 18642441Smckusick /* ARGSUSED */ 18742441Smckusick unmount(p, uap, retval) 18845914Smckusick struct proc *p; 18954916Storek register struct unmount_args *uap; 19042441Smckusick int *retval; 19142441Smckusick { 19237741Smckusick register struct vnode *vp; 19339356Smckusick struct mount *mp; 19437741Smckusick int error; 19547540Skarels struct nameidata nd; 1966254Sroot 19737741Smckusick /* 19837741Smckusick * Must be super user 19937741Smckusick */ 20047540Skarels if (error = suser(p->p_ucred, &p->p_acflag)) 20147540Skarels return (error); 20237741Smckusick 20352322Smckusick NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->pathp, p); 20452322Smckusick if (error = namei(&nd)) 20547540Skarels return (error); 20652322Smckusick vp = nd.ni_vp; 20737741Smckusick /* 20837741Smckusick * Must be the root of the filesystem 20937741Smckusick */ 21037741Smckusick if ((vp->v_flag & VROOT) == 0) { 21137741Smckusick vput(vp); 21247540Skarels return (EINVAL); 21337741Smckusick } 21437741Smckusick mp = vp->v_mount; 21537741Smckusick vput(vp); 21648026Smckusick return (dounmount(mp, uap->flags, p)); 21739356Smckusick } 21839356Smckusick 21939356Smckusick /* 22039356Smckusick * Do an unmount. 22139356Smckusick */ 22248026Smckusick dounmount(mp, flags, p) 22339356Smckusick register struct mount *mp; 22439356Smckusick int flags; 22548026Smckusick struct proc *p; 22639356Smckusick { 22739356Smckusick struct vnode *coveredvp; 22839356Smckusick int error; 22939356Smckusick 23041400Smckusick coveredvp = mp->mnt_vnodecovered; 23141298Smckusick if (vfs_busy(mp)) 23241298Smckusick return (EBUSY); 23341400Smckusick mp->mnt_flag |= MNT_UNMOUNT; 23437741Smckusick if (error = vfs_lock(mp)) 23539356Smckusick return (error); 23637741Smckusick 23745738Smckusick vnode_pager_umount(mp); /* release cached vnodes */ 23837741Smckusick cache_purgevfs(mp); /* remove cache entries for this file sys */ 23954441Smckusick if ((error = VFS_SYNC(mp, MNT_WAIT, p->p_ucred, p)) == 0 || 24054441Smckusick (flags & MNT_FORCE)) 24148026Smckusick error = VFS_UNMOUNT(mp, flags, p); 24241400Smckusick mp->mnt_flag &= ~MNT_UNMOUNT; 24341298Smckusick vfs_unbusy(mp); 24437741Smckusick if (error) { 24537741Smckusick vfs_unlock(mp); 24637741Smckusick } else { 24737741Smckusick vrele(coveredvp); 24837741Smckusick vfs_remove(mp); 24952287Smckusick if (mp->mnt_mounth != NULL) 25052287Smckusick panic("unmount: dangling vnode"); 25137741Smckusick free((caddr_t)mp, M_MOUNT); 25237741Smckusick } 25339356Smckusick return (error); 2546254Sroot } 2556254Sroot 2569167Ssam /* 25737741Smckusick * Sync system call. 25837741Smckusick * Sync each mounted filesystem. 2599167Ssam */ 26054916Storek struct sync_args { 26154916Storek int dummy; 26254916Storek }; 26339491Smckusick /* ARGSUSED */ 26442441Smckusick sync(p, uap, retval) 26545914Smckusick struct proc *p; 26654916Storek struct sync_args *uap; 26742441Smckusick int *retval; 2686254Sroot { 26937741Smckusick register struct mount *mp; 27041298Smckusick struct mount *omp; 27137741Smckusick 27237741Smckusick mp = rootfs; 27337741Smckusick do { 27440343Smckusick /* 27540343Smckusick * The lock check below is to avoid races with mount 27640343Smckusick * and unmount. 27740343Smckusick */ 27841400Smckusick if ((mp->mnt_flag & (MNT_MLOCK|MNT_RDONLY|MNT_MPBUSY)) == 0 && 27941298Smckusick !vfs_busy(mp)) { 28054441Smckusick VFS_SYNC(mp, MNT_NOWAIT, p->p_ucred, p); 28141298Smckusick omp = mp; 28241400Smckusick mp = mp->mnt_next; 28341298Smckusick vfs_unbusy(omp); 28441298Smckusick } else 28541400Smckusick mp = mp->mnt_next; 28637741Smckusick } while (mp != rootfs); 28747688Skarels return (0); 28837741Smckusick } 28937741Smckusick 29037741Smckusick /* 29149365Smckusick * Operate on filesystem quotas. 29241298Smckusick */ 29354916Storek struct quotactl_args { 29454916Storek char *path; 29554916Storek int cmd; 29654916Storek int uid; 29754916Storek caddr_t arg; 29854916Storek }; 29942441Smckusick /* ARGSUSED */ 30042441Smckusick quotactl(p, uap, retval) 30145914Smckusick struct proc *p; 30254916Storek register struct quotactl_args *uap; 30342441Smckusick int *retval; 30442441Smckusick { 30541298Smckusick register struct mount *mp; 30641298Smckusick int error; 30747540Skarels struct nameidata nd; 30841298Smckusick 30952322Smckusick NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); 31052322Smckusick if (error = namei(&nd)) 31147540Skarels return (error); 31252322Smckusick mp = nd.ni_vp->v_mount; 31352322Smckusick vrele(nd.ni_vp); 31448026Smckusick return (VFS_QUOTACTL(mp, uap->cmd, uap->uid, uap->arg, p)); 31541298Smckusick } 31641298Smckusick 31741298Smckusick /* 31849365Smckusick * Get filesystem statistics. 31937741Smckusick */ 32054916Storek struct statfs_args { 32154916Storek char *path; 32254916Storek struct statfs *buf; 32354916Storek }; 32442441Smckusick /* ARGSUSED */ 32542441Smckusick statfs(p, uap, retval) 32645914Smckusick struct proc *p; 32754916Storek register struct statfs_args *uap; 32842441Smckusick int *retval; 32942441Smckusick { 33039464Smckusick register struct mount *mp; 33140343Smckusick register struct statfs *sp; 33237741Smckusick int error; 33347540Skarels struct nameidata nd; 33437741Smckusick 33552322Smckusick NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); 33652322Smckusick if (error = namei(&nd)) 33747540Skarels return (error); 33852322Smckusick mp = nd.ni_vp->v_mount; 33941400Smckusick sp = &mp->mnt_stat; 34052322Smckusick vrele(nd.ni_vp); 34148026Smckusick if (error = VFS_STATFS(mp, sp, p)) 34247540Skarels return (error); 34341400Smckusick sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 34447540Skarels return (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp))); 34537741Smckusick } 34637741Smckusick 34742441Smckusick /* 34849365Smckusick * Get filesystem statistics. 34942441Smckusick */ 35054916Storek struct fstatfs_args { 35154916Storek int fd; 35254916Storek struct statfs *buf; 35354916Storek }; 35442441Smckusick /* ARGSUSED */ 35542441Smckusick fstatfs(p, uap, retval) 35645914Smckusick struct proc *p; 35754916Storek register struct fstatfs_args *uap; 35842441Smckusick int *retval; 35942441Smckusick { 36037741Smckusick struct file *fp; 36139464Smckusick struct mount *mp; 36240343Smckusick register struct statfs *sp; 36337741Smckusick int error; 36437741Smckusick 36545914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 36647540Skarels return (error); 36739464Smckusick mp = ((struct vnode *)fp->f_data)->v_mount; 36841400Smckusick sp = &mp->mnt_stat; 36948026Smckusick if (error = VFS_STATFS(mp, sp, p)) 37047540Skarels return (error); 37141400Smckusick sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 37247540Skarels return (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp))); 37337741Smckusick } 37437741Smckusick 37537741Smckusick /* 37649365Smckusick * Get statistics on all filesystems. 37738270Smckusick */ 37854916Storek struct getfsstat_args { 37954916Storek struct statfs *buf; 38054916Storek long bufsize; 38154916Storek int flags; 38254916Storek }; 38342441Smckusick getfsstat(p, uap, retval) 38445914Smckusick struct proc *p; 38554916Storek register struct getfsstat_args *uap; 38642441Smckusick int *retval; 38742441Smckusick { 38838270Smckusick register struct mount *mp; 38940343Smckusick register struct statfs *sp; 39039606Smckusick caddr_t sfsp; 39138270Smckusick long count, maxcount, error; 39238270Smckusick 39338270Smckusick maxcount = uap->bufsize / sizeof(struct statfs); 39439606Smckusick sfsp = (caddr_t)uap->buf; 39538270Smckusick mp = rootfs; 39638270Smckusick count = 0; 39738270Smckusick do { 39841400Smckusick if (sfsp && count < maxcount && 39941400Smckusick ((mp->mnt_flag & MNT_MLOCK) == 0)) { 40041400Smckusick sp = &mp->mnt_stat; 40140343Smckusick /* 40240343Smckusick * If MNT_NOWAIT is specified, do not refresh the 40340343Smckusick * fsstat cache. MNT_WAIT overrides MNT_NOWAIT. 40440343Smckusick */ 40540343Smckusick if (((uap->flags & MNT_NOWAIT) == 0 || 40640343Smckusick (uap->flags & MNT_WAIT)) && 40748026Smckusick (error = VFS_STATFS(mp, sp, p))) { 40841400Smckusick mp = mp->mnt_prev; 40939607Smckusick continue; 41039607Smckusick } 41141400Smckusick sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 41240343Smckusick if (error = copyout((caddr_t)sp, sfsp, sizeof(*sp))) 41347540Skarels return (error); 41440343Smckusick sfsp += sizeof(*sp); 41538270Smckusick } 41639606Smckusick count++; 41741400Smckusick mp = mp->mnt_prev; 41838270Smckusick } while (mp != rootfs); 41938270Smckusick if (sfsp && count > maxcount) 42042441Smckusick *retval = maxcount; 42138270Smckusick else 42242441Smckusick *retval = count; 42347540Skarels return (0); 42438270Smckusick } 42538270Smckusick 42638270Smckusick /* 42738259Smckusick * Change current working directory to a given file descriptor. 42838259Smckusick */ 42954916Storek struct fchdir_args { 43054916Storek int fd; 43154916Storek }; 43242441Smckusick /* ARGSUSED */ 43342441Smckusick fchdir(p, uap, retval) 43445914Smckusick struct proc *p; 43554916Storek struct fchdir_args *uap; 43642441Smckusick int *retval; 43738259Smckusick { 43845914Smckusick register struct filedesc *fdp = p->p_fd; 43938259Smckusick register struct vnode *vp; 44038259Smckusick struct file *fp; 44138259Smckusick int error; 44238259Smckusick 44345914Smckusick if (error = getvnode(fdp, uap->fd, &fp)) 44447540Skarels return (error); 44538259Smckusick vp = (struct vnode *)fp->f_data; 44638259Smckusick VOP_LOCK(vp); 44738259Smckusick if (vp->v_type != VDIR) 44838259Smckusick error = ENOTDIR; 44938259Smckusick else 45048026Smckusick error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p); 45138259Smckusick VOP_UNLOCK(vp); 45239860Smckusick if (error) 45347540Skarels return (error); 45439860Smckusick VREF(vp); 45545914Smckusick vrele(fdp->fd_cdir); 45645914Smckusick fdp->fd_cdir = vp; 45747540Skarels return (0); 45838259Smckusick } 45938259Smckusick 46038259Smckusick /* 46137741Smckusick * Change current working directory (``.''). 46237741Smckusick */ 46354916Storek struct chdir_args { 46454916Storek char *fname; 46554916Storek }; 46642441Smckusick /* ARGSUSED */ 46742441Smckusick chdir(p, uap, retval) 46845914Smckusick struct proc *p; 46954916Storek struct chdir_args *uap; 47042441Smckusick int *retval; 47137741Smckusick { 47245914Smckusick register struct filedesc *fdp = p->p_fd; 47337741Smckusick int error; 47447540Skarels struct nameidata nd; 4756254Sroot 47652322Smckusick NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 47752781Sralph if (error = chdirec(&nd, p)) 47847540Skarels return (error); 47945914Smckusick vrele(fdp->fd_cdir); 48052322Smckusick fdp->fd_cdir = nd.ni_vp; 48147540Skarels return (0); 48237741Smckusick } 4836254Sroot 48437741Smckusick /* 48537741Smckusick * Change notion of root (``/'') directory. 48637741Smckusick */ 48754916Storek struct chroot_args { 48854916Storek char *fname; 48954916Storek }; 49042441Smckusick /* ARGSUSED */ 49142441Smckusick chroot(p, uap, retval) 49245914Smckusick struct proc *p; 49354916Storek struct chroot_args *uap; 49442441Smckusick int *retval; 49537741Smckusick { 49645914Smckusick register struct filedesc *fdp = p->p_fd; 49737741Smckusick int error; 49847540Skarels struct nameidata nd; 49937741Smckusick 50047540Skarels if (error = suser(p->p_ucred, &p->p_acflag)) 50147540Skarels return (error); 50252322Smckusick NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 50352781Sralph if (error = chdirec(&nd, p)) 50447540Skarels return (error); 50545914Smckusick if (fdp->fd_rdir != NULL) 50645914Smckusick vrele(fdp->fd_rdir); 50752322Smckusick fdp->fd_rdir = nd.ni_vp; 50847540Skarels return (0); 5096254Sroot } 5106254Sroot 51137Sbill /* 51237741Smckusick * Common routine for chroot and chdir. 51337741Smckusick */ 51447540Skarels chdirec(ndp, p) 51552322Smckusick register struct nameidata *ndp; 51647540Skarels struct proc *p; 51737741Smckusick { 51837741Smckusick struct vnode *vp; 51937741Smckusick int error; 52037741Smckusick 52152322Smckusick if (error = namei(ndp)) 52237741Smckusick return (error); 52337741Smckusick vp = ndp->ni_vp; 52437741Smckusick if (vp->v_type != VDIR) 52537741Smckusick error = ENOTDIR; 52637741Smckusick else 52748026Smckusick error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p); 52837741Smckusick VOP_UNLOCK(vp); 52937741Smckusick if (error) 53037741Smckusick vrele(vp); 53137741Smckusick return (error); 53237741Smckusick } 53337741Smckusick 53437741Smckusick /* 5356254Sroot * Open system call. 53642441Smckusick * Check permissions, allocate an open file structure, 53742441Smckusick * and call the device open routine if any. 5386254Sroot */ 53954916Storek struct open_args { 54054916Storek char *fname; 54154916Storek int mode; 54254916Storek int crtmode; 54354916Storek }; 54442441Smckusick open(p, uap, retval) 54545914Smckusick struct proc *p; 54654916Storek register struct open_args *uap; 54742441Smckusick int *retval; 5486254Sroot { 54945914Smckusick register struct filedesc *fdp = p->p_fd; 55042441Smckusick register struct file *fp; 55150111Smckusick register struct vnode *vp; 55237741Smckusick int fmode, cmode; 55337741Smckusick struct file *nfp; 55449945Smckusick int type, indx, error; 55549945Smckusick struct flock lf; 55647540Skarels struct nameidata nd; 55737741Smckusick extern struct fileops vnops; 5586254Sroot 55945914Smckusick if (error = falloc(p, &nfp, &indx)) 56047540Skarels return (error); 56137741Smckusick fp = nfp; 56246553Skarels fmode = FFLAGS(uap->mode); 56345914Smckusick cmode = ((uap->crtmode &~ fdp->fd_cmask) & 07777) &~ S_ISVTX; 56452322Smckusick NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->fname, p); 56545202Smckusick p->p_dupfd = -indx - 1; /* XXX check for fdopen */ 56652322Smckusick if (error = vn_open(&nd, fmode, cmode)) { 56749980Smckusick ffree(fp); 56854723Smckusick if ((error == ENODEV || error == ENXIO) && 56954723Smckusick p->p_dupfd >= 0 && /* XXX from fdopen */ 57053828Spendry (error = dupfdopen(fdp, indx, p->p_dupfd, 57153828Spendry fmode, error)) == 0) { 57242441Smckusick *retval = indx; 57347540Skarels return (0); 57442441Smckusick } 57540884Smckusick if (error == ERESTART) 57640884Smckusick error = EINTR; 57747688Skarels fdp->fd_ofiles[indx] = NULL; 57847540Skarels return (error); 57912756Ssam } 58053828Spendry p->p_dupfd = 0; 58152322Smckusick vp = nd.ni_vp; 58249949Smckusick fp->f_flag = fmode & FMASK; 58354348Smckusick fp->f_type = DTYPE_VNODE; 58454348Smckusick fp->f_ops = &vnops; 58554348Smckusick fp->f_data = (caddr_t)vp; 58649945Smckusick if (fmode & (O_EXLOCK | O_SHLOCK)) { 58749945Smckusick lf.l_whence = SEEK_SET; 58849945Smckusick lf.l_start = 0; 58949945Smckusick lf.l_len = 0; 59049945Smckusick if (fmode & O_EXLOCK) 59149945Smckusick lf.l_type = F_WRLCK; 59249945Smckusick else 59349945Smckusick lf.l_type = F_RDLCK; 59449945Smckusick type = F_FLOCK; 59549945Smckusick if ((fmode & FNONBLOCK) == 0) 59649945Smckusick type |= F_WAIT; 59750111Smckusick if (error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, type)) { 59850111Smckusick VOP_UNLOCK(vp); 59950111Smckusick (void) vn_close(vp, fp->f_flag, fp->f_cred, p); 60049980Smckusick ffree(fp); 60149945Smckusick fdp->fd_ofiles[indx] = NULL; 60249945Smckusick return (error); 60349945Smckusick } 60449949Smckusick fp->f_flag |= FHASLOCK; 60549945Smckusick } 60650111Smckusick VOP_UNLOCK(vp); 60742441Smckusick *retval = indx; 60847540Skarels return (0); 6096254Sroot } 6106254Sroot 61142955Smckusick #ifdef COMPAT_43 6126254Sroot /* 61342441Smckusick * Creat system call. 6146254Sroot */ 61554916Storek struct ocreat_args { 61654916Storek char *fname; 61754916Storek int fmode; 61854916Storek }; 61942955Smckusick ocreat(p, uap, retval) 62042441Smckusick struct proc *p; 62154916Storek register struct ocreat_args *uap; 62242441Smckusick int *retval; 6236254Sroot { 62454916Storek struct open_args openuap; 62542441Smckusick 62642441Smckusick openuap.fname = uap->fname; 62742441Smckusick openuap.crtmode = uap->fmode; 62842441Smckusick openuap.mode = O_WRONLY | O_CREAT | O_TRUNC; 62947540Skarels return (open(p, &openuap, retval)); 63042441Smckusick } 63142955Smckusick #endif /* COMPAT_43 */ 63242441Smckusick 63342441Smckusick /* 63449365Smckusick * Mknod system call. 63542441Smckusick */ 63654916Storek struct mknod_args { 63754916Storek char *fname; 63854916Storek int fmode; 63954916Storek int dev; 64054916Storek }; 64142441Smckusick /* ARGSUSED */ 64242441Smckusick mknod(p, uap, retval) 64345914Smckusick struct proc *p; 64454916Storek register struct mknod_args *uap; 64542441Smckusick int *retval; 64642441Smckusick { 64737741Smckusick register struct vnode *vp; 64837741Smckusick struct vattr vattr; 64937741Smckusick int error; 65047540Skarels struct nameidata nd; 6516254Sroot 65247540Skarels if (error = suser(p->p_ucred, &p->p_acflag)) 65347540Skarels return (error); 65452322Smckusick NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->fname, p); 65552322Smckusick if (error = namei(&nd)) 65647540Skarels return (error); 65752322Smckusick vp = nd.ni_vp; 65837741Smckusick if (vp != NULL) { 65937741Smckusick error = EEXIST; 66012756Ssam goto out; 6616254Sroot } 66241362Smckusick VATTR_NULL(&vattr); 66340635Smckusick switch (uap->fmode & S_IFMT) { 66412756Ssam 66540635Smckusick case S_IFMT: /* used by badsect to flag bad sectors */ 66637741Smckusick vattr.va_type = VBAD; 66737741Smckusick break; 66840635Smckusick case S_IFCHR: 66937741Smckusick vattr.va_type = VCHR; 67037741Smckusick break; 67140635Smckusick case S_IFBLK: 67237741Smckusick vattr.va_type = VBLK; 67337741Smckusick break; 67437741Smckusick default: 67537741Smckusick error = EINVAL; 67637741Smckusick goto out; 6776254Sroot } 67845914Smckusick vattr.va_mode = (uap->fmode & 07777) &~ p->p_fd->fd_cmask; 67937741Smckusick vattr.va_rdev = uap->dev; 6806254Sroot out: 68142465Smckusick if (!error) { 68252322Smckusick LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 68352322Smckusick error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr); 68442465Smckusick } else { 68552322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 68652322Smckusick if (nd.ni_dvp == vp) 68752322Smckusick vrele(nd.ni_dvp); 68843344Smckusick else 68952322Smckusick vput(nd.ni_dvp); 69042465Smckusick if (vp) 69142465Smckusick vrele(vp); 69242465Smckusick } 69347540Skarels return (error); 6946254Sroot } 6956254Sroot 6966254Sroot /* 69749365Smckusick * Mkfifo system call. 69840285Smckusick */ 69954916Storek struct mkfifo_args { 70054916Storek char *fname; 70154916Storek int fmode; 70254916Storek }; 70342441Smckusick /* ARGSUSED */ 70442441Smckusick mkfifo(p, uap, retval) 70545914Smckusick struct proc *p; 70654916Storek register struct mkfifo_args *uap; 70742441Smckusick int *retval; 70842441Smckusick { 70940285Smckusick struct vattr vattr; 71040285Smckusick int error; 71147540Skarels struct nameidata nd; 71240285Smckusick 71340285Smckusick #ifndef FIFO 71447540Skarels return (EOPNOTSUPP); 71540285Smckusick #else 71652322Smckusick NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->fname, p); 71752322Smckusick if (error = namei(&nd)) 71847540Skarels return (error); 71952322Smckusick if (nd.ni_vp != NULL) { 72052322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 72152322Smckusick if (nd.ni_dvp == nd.ni_vp) 72252322Smckusick vrele(nd.ni_dvp); 72343344Smckusick else 72452322Smckusick vput(nd.ni_dvp); 72552322Smckusick vrele(nd.ni_vp); 72647540Skarels return (EEXIST); 72740285Smckusick } 72845785Sbostic VATTR_NULL(&vattr); 72945785Sbostic vattr.va_type = VFIFO; 73045914Smckusick vattr.va_mode = (uap->fmode & 07777) &~ p->p_fd->fd_cmask; 73152322Smckusick LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 73252322Smckusick return (VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr)); 73340285Smckusick #endif /* FIFO */ 73440285Smckusick } 73540285Smckusick 73640285Smckusick /* 73749365Smckusick * Link system call. 7386254Sroot */ 73954916Storek struct link_args { 74054916Storek char *target; 74154916Storek char *linkname; 74254916Storek }; 74342441Smckusick /* ARGSUSED */ 74442441Smckusick link(p, uap, retval) 74545914Smckusick struct proc *p; 74654916Storek register struct link_args *uap; 74742441Smckusick int *retval; 74842441Smckusick { 74937741Smckusick register struct vnode *vp, *xp; 75037741Smckusick int error; 75147540Skarels struct nameidata nd; 7526254Sroot 75352322Smckusick NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->target, p); 75452322Smckusick if (error = namei(&nd)) 75547540Skarels return (error); 75652322Smckusick vp = nd.ni_vp; 75737741Smckusick if (vp->v_type == VDIR && 75847540Skarels (error = suser(p->p_ucred, &p->p_acflag))) 75937741Smckusick goto out1; 76052322Smckusick nd.ni_cnd.cn_nameiop = CREATE; 76152322Smckusick nd.ni_cnd.cn_flags = LOCKPARENT; 76252322Smckusick nd.ni_dirp = (caddr_t)uap->linkname; 76352322Smckusick if (error = namei(&nd)) 76437741Smckusick goto out1; 76552322Smckusick xp = nd.ni_vp; 7666254Sroot if (xp != NULL) { 76737741Smckusick error = EEXIST; 7686254Sroot goto out; 7696254Sroot } 77052322Smckusick xp = nd.ni_dvp; 7716254Sroot out: 77242465Smckusick if (!error) { 77352192Smckusick LEASE_CHECK(xp, p, p->p_ucred, LEASE_WRITE); 77452192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 77552821Smckusick error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd); 77642465Smckusick } else { 77752322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 77852322Smckusick if (nd.ni_dvp == nd.ni_vp) 77952322Smckusick vrele(nd.ni_dvp); 78043344Smckusick else 78152322Smckusick vput(nd.ni_dvp); 78252322Smckusick if (nd.ni_vp) 78352322Smckusick vrele(nd.ni_vp); 78442465Smckusick } 78537741Smckusick out1: 78637741Smckusick vrele(vp); 78747540Skarels return (error); 7886254Sroot } 7896254Sroot 7906254Sroot /* 79149365Smckusick * Make a symbolic link. 7926254Sroot */ 79354916Storek struct symlink_args { 79454916Storek char *target; 79554916Storek char *linkname; 79654916Storek }; 79742441Smckusick /* ARGSUSED */ 79842441Smckusick symlink(p, uap, retval) 79945914Smckusick struct proc *p; 80054916Storek register struct symlink_args *uap; 80142441Smckusick int *retval; 80242441Smckusick { 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 */ 83654916Storek struct unlink_args { 83754916Storek char *name; 83854916Storek }; 83942441Smckusick /* ARGSUSED */ 84042441Smckusick unlink(p, uap, retval) 84145914Smckusick struct proc *p; 84254916Storek struct unlink_args *uap; 84342441Smckusick int *retval; 8446254Sroot { 84537741Smckusick register struct vnode *vp; 84637741Smckusick int error; 84747540Skarels struct nameidata nd; 8486254Sroot 84952322Smckusick NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE, uap->name, p); 85052322Smckusick if (error = namei(&nd)) 85147540Skarels return (error); 85252322Smckusick vp = nd.ni_vp; 85337741Smckusick if (vp->v_type == VDIR && 85447540Skarels (error = suser(p->p_ucred, &p->p_acflag))) 8556254Sroot goto out; 8566254Sroot /* 85749365Smckusick * The root of a mounted filesystem cannot be deleted. 8586254Sroot */ 85937741Smckusick if (vp->v_flag & VROOT) { 86037741Smckusick error = EBUSY; 8616254Sroot goto out; 8626254Sroot } 86345738Smckusick (void) vnode_pager_uncache(vp); 8646254Sroot out: 86542465Smckusick if (!error) { 86652322Smckusick LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 86752192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 86852322Smckusick error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); 86942465Smckusick } else { 87052322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 87152322Smckusick if (nd.ni_dvp == vp) 87252322Smckusick vrele(nd.ni_dvp); 87343344Smckusick else 87452322Smckusick vput(nd.ni_dvp); 87542465Smckusick vput(vp); 87642465Smckusick } 87747540Skarels return (error); 8786254Sroot } 8796254Sroot 88054916Storek struct __lseek_args { 88154863Storek int fdes; 88254863Storek int pad; 88354863Storek off_t off; 88454863Storek int sbase; 88554863Storek }; 88654863Storek 88754348Smckusick #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 8886254Sroot /* 88949365Smckusick * Seek system call. 8906254Sroot */ 89154916Storek struct lseek_args { 89254916Storek int fdes; 89354916Storek long off; 89454916Storek int sbase; 89554916Storek }; 89642441Smckusick lseek(p, uap, retval) 89745914Smckusick struct proc *p; 89854916Storek register struct lseek_args *uap; 89954916Storek int *retval; 90053468Smckusick { 90154916Storek struct __lseek_args nuap; 90254863Storek off_t qret; 90353468Smckusick int error; 90453468Smckusick 90553468Smckusick nuap.fdes = uap->fdes; 90653468Smckusick nuap.off = uap->off; 90753468Smckusick nuap.sbase = uap->sbase; 90853759Smckusick error = __lseek(p, &nuap, &qret); 90954916Storek *(long *)retval = qret; 91053468Smckusick return (error); 91153468Smckusick } 91254348Smckusick #endif /* COMPAT_43 || COMPAT_SUNOS */ 91353468Smckusick 91453468Smckusick /* 91553468Smckusick * Seek system call. 91653468Smckusick */ 91753759Smckusick __lseek(p, uap, retval) 91853468Smckusick struct proc *p; 91954916Storek register struct __lseek_args *uap; 92054916Storek int *retval; 92142441Smckusick { 92247540Skarels struct ucred *cred = p->p_ucred; 92345914Smckusick register struct filedesc *fdp = p->p_fd; 92442441Smckusick register struct file *fp; 92537741Smckusick struct vattr vattr; 92637741Smckusick int error; 9276254Sroot 92847540Skarels if ((unsigned)uap->fdes >= fdp->fd_nfiles || 92947688Skarels (fp = fdp->fd_ofiles[uap->fdes]) == NULL) 93047540Skarels return (EBADF); 93137741Smckusick if (fp->f_type != DTYPE_VNODE) 93247540Skarels return (ESPIPE); 93313878Ssam switch (uap->sbase) { 93413878Ssam 93513878Ssam case L_INCR: 93613878Ssam fp->f_offset += uap->off; 93713878Ssam break; 93813878Ssam 93913878Ssam case L_XTND: 94037741Smckusick if (error = VOP_GETATTR((struct vnode *)fp->f_data, 94148026Smckusick &vattr, cred, p)) 94247540Skarels return (error); 94337741Smckusick fp->f_offset = uap->off + vattr.va_size; 94413878Ssam break; 94513878Ssam 94613878Ssam case L_SET: 94713878Ssam fp->f_offset = uap->off; 94813878Ssam break; 94913878Ssam 95013878Ssam default: 95147540Skarels return (EINVAL); 95213878Ssam } 95354916Storek *(off_t *)retval = fp->f_offset; 95447540Skarels return (0); 9556254Sroot } 9566254Sroot 9576254Sroot /* 95849365Smckusick * Check access permissions. 9596254Sroot */ 96054916Storek struct saccess_args { 96154916Storek char *fname; 96254916Storek int fmode; 96354916Storek }; 96442441Smckusick /* ARGSUSED */ 96542441Smckusick saccess(p, uap, retval) 96645914Smckusick struct proc *p; 96754916Storek register struct saccess_args *uap; 96842441Smckusick int *retval; 96942441Smckusick { 97047540Skarels register struct ucred *cred = p->p_ucred; 97137741Smckusick register struct vnode *vp; 97237741Smckusick int error, mode, svuid, svgid; 97347540Skarels struct nameidata nd; 9746254Sroot 97542441Smckusick svuid = cred->cr_uid; 97642441Smckusick svgid = cred->cr_groups[0]; 97747540Skarels cred->cr_uid = p->p_cred->p_ruid; 97847540Skarels cred->cr_groups[0] = p->p_cred->p_rgid; 97952322Smckusick NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 98052322Smckusick if (error = namei(&nd)) 98137741Smckusick goto out1; 98252322Smckusick vp = nd.ni_vp; 98337741Smckusick /* 98437741Smckusick * fmode == 0 means only check for exist 98537741Smckusick */ 98637741Smckusick if (uap->fmode) { 98737741Smckusick mode = 0; 98837741Smckusick if (uap->fmode & R_OK) 98937741Smckusick mode |= VREAD; 99037741Smckusick if (uap->fmode & W_OK) 99137741Smckusick mode |= VWRITE; 99237741Smckusick if (uap->fmode & X_OK) 99337741Smckusick mode |= VEXEC; 99439543Smckusick if ((mode & VWRITE) == 0 || (error = vn_writechk(vp)) == 0) 99548026Smckusick error = VOP_ACCESS(vp, mode, cred, p); 9966254Sroot } 99737741Smckusick vput(vp); 99837741Smckusick out1: 99942441Smckusick cred->cr_uid = svuid; 100042441Smckusick cred->cr_groups[0] = svgid; 100147540Skarels return (error); 10026254Sroot } 10036254Sroot 100454348Smckusick #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 10056254Sroot /* 100649365Smckusick * Stat system call. 100749365Smckusick * This version follows links. 100837Sbill */ 100954916Storek struct ostat_args { 101054916Storek char *fname; 101154916Storek struct ostat *ub; 101254916Storek }; 101342441Smckusick /* ARGSUSED */ 101453759Smckusick ostat(p, uap, retval) 101545914Smckusick struct proc *p; 101654916Storek register struct ostat_args *uap; 101753468Smckusick int *retval; 101853468Smckusick { 101953468Smckusick struct stat sb; 102053468Smckusick struct ostat osb; 102153468Smckusick int error; 102253468Smckusick struct nameidata nd; 102353468Smckusick 102453468Smckusick NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 102553468Smckusick if (error = namei(&nd)) 102653468Smckusick return (error); 102753468Smckusick error = vn_stat(nd.ni_vp, &sb, p); 102853468Smckusick vput(nd.ni_vp); 102953468Smckusick if (error) 103053468Smckusick return (error); 103153468Smckusick cvtstat(&sb, &osb); 103253468Smckusick error = copyout((caddr_t)&osb, (caddr_t)uap->ub, sizeof (osb)); 103353468Smckusick return (error); 103453468Smckusick } 103553468Smckusick 103653468Smckusick /* 103753468Smckusick * Lstat system call. 103853468Smckusick * This version does not follow links. 103953468Smckusick */ 104054916Storek struct olstat_args { 104154916Storek char *fname; 104254916Storek struct ostat *ub; 104354916Storek }; 104453468Smckusick /* ARGSUSED */ 104553759Smckusick olstat(p, uap, retval) 104653468Smckusick struct proc *p; 104754916Storek register struct olstat_args *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 */ 110054916Storek struct stat_args { 110154916Storek char *fname; 110254916Storek struct stat *ub; 110354916Storek }; 110453468Smckusick /* ARGSUSED */ 110553759Smckusick stat(p, uap, retval) 110653468Smckusick struct proc *p; 110754916Storek register struct stat_args *uap; 110842441Smckusick int *retval; 110937Sbill { 111042441Smckusick struct stat sb; 111142441Smckusick int error; 111247540Skarels struct nameidata nd; 111337Sbill 111452322Smckusick NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 111552322Smckusick if (error = namei(&nd)) 111647540Skarels return (error); 111752322Smckusick error = vn_stat(nd.ni_vp, &sb, p); 111852322Smckusick vput(nd.ni_vp); 111942441Smckusick if (error) 112047540Skarels return (error); 112142441Smckusick error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb)); 112247540Skarels return (error); 112337Sbill } 112437Sbill 112537Sbill /* 112649365Smckusick * Lstat system call. 112749365Smckusick * This version does not follow links. 11285992Swnj */ 112954916Storek struct lstat_args { 113054916Storek char *fname; 113154916Storek struct stat *ub; 113254916Storek }; 113342441Smckusick /* ARGSUSED */ 113453759Smckusick lstat(p, uap, retval) 113545914Smckusick struct proc *p; 113654916Storek register struct lstat_args *uap; 113742441Smckusick int *retval; 113842441Smckusick { 113912756Ssam struct stat sb; 114037741Smckusick int error; 114147540Skarels struct nameidata nd; 11425992Swnj 114352322Smckusick NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 114452322Smckusick if (error = namei(&nd)) 114547540Skarels return (error); 114652322Smckusick error = vn_stat(nd.ni_vp, &sb, p); 114752322Smckusick vput(nd.ni_vp); 114837741Smckusick if (error) 114947540Skarels return (error); 115037741Smckusick error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb)); 115147540Skarels return (error); 11525992Swnj } 11535992Swnj 11545992Swnj /* 115549365Smckusick * Return target name of a symbolic link. 115637Sbill */ 115754916Storek struct readlink_args { 115854916Storek char *name; 115954916Storek char *buf; 116054916Storek int count; 116154916Storek }; 116242441Smckusick /* ARGSUSED */ 116342441Smckusick readlink(p, uap, retval) 116445914Smckusick struct proc *p; 116554916Storek register struct readlink_args *uap; 116642441Smckusick int *retval; 116742441Smckusick { 116837741Smckusick register struct vnode *vp; 116937741Smckusick struct iovec aiov; 117037741Smckusick struct uio auio; 117137741Smckusick int error; 117247540Skarels struct nameidata nd; 11735992Swnj 117452322Smckusick NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, uap->name, p); 117552322Smckusick if (error = namei(&nd)) 117647540Skarels return (error); 117752322Smckusick vp = nd.ni_vp; 117837741Smckusick if (vp->v_type != VLNK) { 117937741Smckusick error = EINVAL; 11805992Swnj goto out; 11815992Swnj } 118237741Smckusick aiov.iov_base = uap->buf; 118337741Smckusick aiov.iov_len = uap->count; 118437741Smckusick auio.uio_iov = &aiov; 118537741Smckusick auio.uio_iovcnt = 1; 118637741Smckusick auio.uio_offset = 0; 118737741Smckusick auio.uio_rw = UIO_READ; 118837741Smckusick auio.uio_segflg = UIO_USERSPACE; 118948026Smckusick auio.uio_procp = p; 119037741Smckusick auio.uio_resid = uap->count; 119147540Skarels error = VOP_READLINK(vp, &auio, p->p_ucred); 11925992Swnj out: 119337741Smckusick vput(vp); 119442441Smckusick *retval = uap->count - auio.uio_resid; 119547540Skarels return (error); 11965992Swnj } 11975992Swnj 11989167Ssam /* 119938259Smckusick * Change flags of a file given path name. 120038259Smckusick */ 120154916Storek struct chflags_args { 120254916Storek char *fname; 120354916Storek int flags; 120454916Storek }; 120542441Smckusick /* ARGSUSED */ 120642441Smckusick chflags(p, uap, retval) 120745914Smckusick struct proc *p; 120854916Storek register struct chflags_args *uap; 120942441Smckusick int *retval; 121042441Smckusick { 121138259Smckusick register struct vnode *vp; 121238259Smckusick struct vattr vattr; 121338259Smckusick int error; 121447540Skarels struct nameidata nd; 121538259Smckusick 121652322Smckusick NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 121752322Smckusick if (error = namei(&nd)) 121847540Skarels return (error); 121952322Smckusick vp = nd.ni_vp; 122041400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 122138259Smckusick error = EROFS; 122238259Smckusick goto out; 122338259Smckusick } 122445785Sbostic VATTR_NULL(&vattr); 122545785Sbostic vattr.va_flags = uap->flags; 122652192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 122748026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 122838259Smckusick out: 122938259Smckusick vput(vp); 123047540Skarels return (error); 123138259Smckusick } 123238259Smckusick 123338259Smckusick /* 123438259Smckusick * Change flags of a file given a file descriptor. 123538259Smckusick */ 123654916Storek struct fchflags_args { 123754916Storek int fd; 123854916Storek int flags; 123954916Storek }; 124042441Smckusick /* ARGSUSED */ 124142441Smckusick fchflags(p, uap, retval) 124245914Smckusick struct proc *p; 124354916Storek register struct fchflags_args *uap; 124442441Smckusick int *retval; 124542441Smckusick { 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 */ 127154916Storek struct chmod_args { 127254916Storek char *fname; 127354916Storek int fmode; 127454916Storek }; 127542441Smckusick /* ARGSUSED */ 127642441Smckusick chmod(p, uap, retval) 127745914Smckusick struct proc *p; 127854916Storek register struct chmod_args *uap; 127942441Smckusick int *retval; 128042441Smckusick { 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 */ 130654916Storek struct fchmod_args { 130754916Storek int fd; 130854916Storek int fmode; 130954916Storek }; 131042441Smckusick /* ARGSUSED */ 131142441Smckusick fchmod(p, uap, retval) 131245914Smckusick struct proc *p; 131354916Storek register struct fchmod_args *uap; 131442441Smckusick int *retval; 131542441Smckusick { 131637741Smckusick struct vattr vattr; 131737741Smckusick struct vnode *vp; 131837741Smckusick struct file *fp; 131937741Smckusick int error; 13207701Ssam 132145914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 132247540Skarels return (error); 132337741Smckusick vp = (struct vnode *)fp->f_data; 132437741Smckusick VOP_LOCK(vp); 132541400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 132637741Smckusick error = EROFS; 132737741Smckusick goto out; 13287439Sroot } 132945785Sbostic VATTR_NULL(&vattr); 133045785Sbostic vattr.va_mode = uap->fmode & 07777; 133152192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 133248026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 133337741Smckusick out: 133437741Smckusick VOP_UNLOCK(vp); 133547540Skarels return (error); 13365992Swnj } 13375992Swnj 13389167Ssam /* 13399167Ssam * Set ownership given a path name. 13409167Ssam */ 134154916Storek struct chown_args { 134254916Storek char *fname; 134354916Storek int uid; 134454916Storek int gid; 134554916Storek }; 134642441Smckusick /* ARGSUSED */ 134742441Smckusick chown(p, uap, retval) 134845914Smckusick struct proc *p; 134954916Storek register struct chown_args *uap; 135042441Smckusick int *retval; 135142441Smckusick { 135237741Smckusick register struct vnode *vp; 135337741Smckusick struct vattr vattr; 135437741Smckusick int error; 135547540Skarels struct nameidata nd; 135637Sbill 135752322Smckusick NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 135852322Smckusick if (error = namei(&nd)) 135947540Skarels return (error); 136052322Smckusick vp = nd.ni_vp; 136141400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 136237741Smckusick error = EROFS; 136337741Smckusick goto out; 136437741Smckusick } 136545785Sbostic VATTR_NULL(&vattr); 136645785Sbostic vattr.va_uid = uap->uid; 136745785Sbostic vattr.va_gid = uap->gid; 136852192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 136948026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 137037741Smckusick out: 137137741Smckusick vput(vp); 137247540Skarels return (error); 13737701Ssam } 13747439Sroot 13759167Ssam /* 13769167Ssam * Set ownership given a file descriptor. 13779167Ssam */ 137854916Storek struct fchown_args { 137954916Storek int fd; 138054916Storek int uid; 138154916Storek int gid; 138254916Storek }; 138342441Smckusick /* ARGSUSED */ 138442441Smckusick fchown(p, uap, retval) 138545914Smckusick struct proc *p; 138654916Storek register struct fchown_args *uap; 138742441Smckusick int *retval; 138842441Smckusick { 138937741Smckusick struct vattr vattr; 139037741Smckusick struct vnode *vp; 139137741Smckusick struct file *fp; 139237741Smckusick int error; 13937701Ssam 139445914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 139547540Skarels return (error); 139637741Smckusick vp = (struct vnode *)fp->f_data; 139737741Smckusick VOP_LOCK(vp); 139841400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 139937741Smckusick error = EROFS; 140037741Smckusick goto out; 140137741Smckusick } 140245785Sbostic VATTR_NULL(&vattr); 140345785Sbostic vattr.va_uid = uap->uid; 140445785Sbostic vattr.va_gid = uap->gid; 140552192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 140648026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 140737741Smckusick out: 140837741Smckusick VOP_UNLOCK(vp); 140947540Skarels return (error); 14107701Ssam } 14117701Ssam 141242441Smckusick /* 141342441Smckusick * Set the access and modification times of a file. 141442441Smckusick */ 141554916Storek struct utimes_args { 141654916Storek char *fname; 141754916Storek struct timeval *tptr; 141854916Storek }; 141942441Smckusick /* ARGSUSED */ 142042441Smckusick utimes(p, uap, retval) 142145914Smckusick struct proc *p; 142254916Storek register struct utimes_args *uap; 142342441Smckusick int *retval; 142442441Smckusick { 142537741Smckusick register struct vnode *vp; 142611811Ssam struct timeval tv[2]; 142737741Smckusick struct vattr vattr; 142837741Smckusick int error; 142947540Skarels struct nameidata nd; 143011811Ssam 143137741Smckusick if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv))) 143247540Skarels return (error); 143352322Smckusick NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 143452322Smckusick if (error = namei(&nd)) 143547540Skarels return (error); 143652322Smckusick vp = nd.ni_vp; 143741400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 143837741Smckusick error = EROFS; 143937741Smckusick goto out; 144021015Smckusick } 144145785Sbostic VATTR_NULL(&vattr); 144254100Smckusick vattr.va_atime.ts_sec = tv[0].tv_sec; 144354100Smckusick vattr.va_atime.ts_nsec = tv[0].tv_usec * 1000; 144454100Smckusick vattr.va_mtime.ts_sec = tv[1].tv_sec; 144554100Smckusick vattr.va_mtime.ts_nsec = tv[1].tv_usec * 1000; 144652192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 144748026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 144837741Smckusick out: 144937741Smckusick vput(vp); 145047540Skarels return (error); 145111811Ssam } 145211811Ssam 145354916Storek struct __truncate_args { 145454863Storek char *fname; 145554863Storek int pad; 145654863Storek off_t length; 145754863Storek }; 145853468Smckusick 145953468Smckusick /* 146053468Smckusick * Truncate a file given its path name. 146153468Smckusick */ 146253468Smckusick /* ARGSUSED */ 146353759Smckusick __truncate(p, uap, retval) 146453468Smckusick struct proc *p; 146554916Storek register struct __truncate_args *uap; 146653468Smckusick int *retval; 146753468Smckusick { 146837741Smckusick register struct vnode *vp; 146937741Smckusick struct vattr vattr; 147037741Smckusick int error; 147147540Skarels struct nameidata nd; 14727701Ssam 147352322Smckusick NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 147452322Smckusick if (error = namei(&nd)) 147547540Skarels return (error); 147652322Smckusick vp = nd.ni_vp; 147737741Smckusick if (vp->v_type == VDIR) { 147837741Smckusick error = EISDIR; 147937741Smckusick goto out; 14807701Ssam } 148138399Smckusick if ((error = vn_writechk(vp)) || 148248026Smckusick (error = VOP_ACCESS(vp, VWRITE, p->p_ucred, p))) 148337741Smckusick goto out; 148445785Sbostic VATTR_NULL(&vattr); 148545785Sbostic vattr.va_size = uap->length; 148652192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 148748026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 148837741Smckusick out: 148937741Smckusick vput(vp); 149047540Skarels return (error); 14917701Ssam } 14927701Ssam 149354916Storek struct __ftruncate_args { 149454863Storek int fd; 149554863Storek int pad; 149654863Storek off_t length; 149754863Storek }; 149854863Storek 14999167Ssam /* 15009167Ssam * Truncate a file given a file descriptor. 15019167Ssam */ 150242441Smckusick /* ARGSUSED */ 150353759Smckusick __ftruncate(p, uap, retval) 150445914Smckusick struct proc *p; 150554916Storek register struct __ftruncate_args *uap; 150642441Smckusick int *retval; 150742441Smckusick { 150837741Smckusick struct vattr vattr; 150937741Smckusick struct vnode *vp; 15107701Ssam struct file *fp; 151137741Smckusick int error; 15127701Ssam 151345914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 151447540Skarels return (error); 151537741Smckusick if ((fp->f_flag & FWRITE) == 0) 151647540Skarels return (EINVAL); 151737741Smckusick vp = (struct vnode *)fp->f_data; 151837741Smckusick VOP_LOCK(vp); 151937741Smckusick if (vp->v_type == VDIR) { 152037741Smckusick error = EISDIR; 152137741Smckusick goto out; 15227701Ssam } 152338399Smckusick if (error = vn_writechk(vp)) 152437741Smckusick goto out; 152545785Sbostic VATTR_NULL(&vattr); 152645785Sbostic vattr.va_size = uap->length; 152752192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 152848026Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred, p); 152937741Smckusick out: 153037741Smckusick VOP_UNLOCK(vp); 153147540Skarels return (error); 15327701Ssam } 15337701Ssam 153454863Storek #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 15359167Ssam /* 153654863Storek * Truncate a file given its path name. 153754863Storek */ 153854916Storek struct truncate_args { 153954916Storek char *fname; 154054916Storek long length; 154154916Storek }; 154254863Storek /* ARGSUSED */ 154354863Storek truncate(p, uap, retval) 154454863Storek struct proc *p; 154554916Storek register struct truncate_args *uap; 154654863Storek int *retval; 154754863Storek { 154854916Storek struct __truncate_args nuap; 154954863Storek 155054863Storek nuap.fname = uap->fname; 155154863Storek nuap.length = uap->length; 155254863Storek return (__truncate(p, &nuap, retval)); 155354863Storek } 155454863Storek 155554863Storek /* 155654863Storek * Truncate a file given a file descriptor. 155754863Storek */ 155854916Storek struct ftruncate_args { 155954916Storek int fd; 156054916Storek long length; 156154916Storek }; 156254863Storek /* ARGSUSED */ 156354863Storek ftruncate(p, uap, retval) 156454863Storek struct proc *p; 156554916Storek register struct ftruncate_args *uap; 156654863Storek int *retval; 156754863Storek { 156854969Smckusick struct __ftruncate_args nuap; 156954863Storek 157054863Storek nuap.fd = uap->fd; 157154863Storek nuap.length = uap->length; 157254863Storek return (__ftruncate(p, &nuap, retval)); 157354863Storek } 157454863Storek #endif /* COMPAT_43 || COMPAT_SUNOS */ 157554863Storek 157654863Storek /* 15779167Ssam * Synch an open file. 15789167Ssam */ 157954916Storek struct fsync_args { 158054916Storek int fd; 158154916Storek }; 158242441Smckusick /* ARGSUSED */ 158342441Smckusick fsync(p, uap, retval) 158445914Smckusick struct proc *p; 158554916Storek struct fsync_args *uap; 158642441Smckusick int *retval; 15879167Ssam { 158839592Smckusick register struct vnode *vp; 15899167Ssam struct file *fp; 159037741Smckusick int error; 15919167Ssam 159245914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 159347540Skarels return (error); 159439592Smckusick vp = (struct vnode *)fp->f_data; 159539592Smckusick VOP_LOCK(vp); 159654441Smckusick error = VOP_FSYNC(vp, fp->f_cred, MNT_WAIT, p); 159739592Smckusick VOP_UNLOCK(vp); 159847540Skarels return (error); 15999167Ssam } 16009167Ssam 16019167Ssam /* 16029167Ssam * Rename system call. 16039167Ssam * 16049167Ssam * Source and destination must either both be directories, or both 16059167Ssam * not be directories. If target is a directory, it must be empty. 16069167Ssam */ 160754916Storek struct rename_args { 160854916Storek char *from; 160954916Storek char *to; 161054916Storek }; 161142441Smckusick /* ARGSUSED */ 161242441Smckusick rename(p, uap, retval) 161345914Smckusick struct proc *p; 161454916Storek register struct rename_args *uap; 161542441Smckusick int *retval; 161642441Smckusick { 161737741Smckusick register struct vnode *tvp, *fvp, *tdvp; 161849735Smckusick struct nameidata fromnd, tond; 161937741Smckusick int error; 16207701Ssam 162152322Smckusick NDINIT(&fromnd, DELETE, WANTPARENT | SAVESTART, UIO_USERSPACE, 162252322Smckusick uap->from, p); 162352322Smckusick if (error = namei(&fromnd)) 162447540Skarels return (error); 162549735Smckusick fvp = fromnd.ni_vp; 162652322Smckusick NDINIT(&tond, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART, 162752322Smckusick UIO_USERSPACE, uap->to, p); 162852322Smckusick if (error = namei(&tond)) { 162952230Sheideman VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 163049735Smckusick vrele(fromnd.ni_dvp); 163142465Smckusick vrele(fvp); 163242465Smckusick goto out1; 163342465Smckusick } 163437741Smckusick tdvp = tond.ni_dvp; 163537741Smckusick tvp = tond.ni_vp; 163637741Smckusick if (tvp != NULL) { 163737741Smckusick if (fvp->v_type == VDIR && tvp->v_type != VDIR) { 163839242Sbostic error = ENOTDIR; 163937741Smckusick goto out; 164037741Smckusick } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) { 164139242Sbostic error = EISDIR; 164237741Smckusick goto out; 16439167Ssam } 16449167Ssam } 164539286Smckusick if (fvp == tdvp) 164637741Smckusick error = EINVAL; 164739286Smckusick /* 164849735Smckusick * If source is the same as the destination (that is the 164949735Smckusick * same inode number with the same name in the same directory), 165039286Smckusick * then there is nothing to do. 165139286Smckusick */ 165249735Smckusick if (fvp == tvp && fromnd.ni_dvp == tdvp && 165352322Smckusick fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen && 165452322Smckusick !bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr, 165552322Smckusick fromnd.ni_cnd.cn_namelen)) 165639286Smckusick error = -1; 165737741Smckusick out: 165842465Smckusick if (!error) { 165952192Smckusick LEASE_CHECK(tdvp, p, p->p_ucred, LEASE_WRITE); 166052192Smckusick if (fromnd.ni_dvp != tdvp) 166152192Smckusick LEASE_CHECK(fromnd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 166252192Smckusick if (tvp) 166352192Smckusick LEASE_CHECK(tvp, p, p->p_ucred, LEASE_WRITE); 166452230Sheideman error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd, 166552230Sheideman tond.ni_dvp, tond.ni_vp, &tond.ni_cnd); 166642465Smckusick } else { 166752230Sheideman VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd); 166843344Smckusick if (tdvp == tvp) 166943344Smckusick vrele(tdvp); 167043344Smckusick else 167143344Smckusick vput(tdvp); 167242465Smckusick if (tvp) 167342465Smckusick vput(tvp); 167452230Sheideman VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 167549735Smckusick vrele(fromnd.ni_dvp); 167642465Smckusick vrele(fvp); 16779167Ssam } 167849735Smckusick vrele(tond.ni_startdir); 167952322Smckusick FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI); 168037741Smckusick out1: 168149735Smckusick vrele(fromnd.ni_startdir); 168252322Smckusick FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI); 168339286Smckusick if (error == -1) 168447540Skarels return (0); 168547540Skarels return (error); 16867701Ssam } 16877701Ssam 16887535Sroot /* 168949365Smckusick * Mkdir system call. 169012756Ssam */ 169154916Storek struct mkdir_args { 169254916Storek char *name; 169354916Storek int dmode; 169454916Storek }; 169542441Smckusick /* ARGSUSED */ 169642441Smckusick mkdir(p, uap, retval) 169745914Smckusick struct proc *p; 169854916Storek register struct mkdir_args *uap; 169942441Smckusick int *retval; 170042441Smckusick { 170137741Smckusick register struct vnode *vp; 170237741Smckusick struct vattr vattr; 170337741Smckusick int error; 170447540Skarels struct nameidata nd; 170512756Ssam 170652322Smckusick NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->name, p); 170752322Smckusick if (error = namei(&nd)) 170847540Skarels return (error); 170952322Smckusick vp = nd.ni_vp; 171037741Smckusick if (vp != NULL) { 171152322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 171252322Smckusick if (nd.ni_dvp == vp) 171352322Smckusick vrele(nd.ni_dvp); 171443344Smckusick else 171552322Smckusick vput(nd.ni_dvp); 171642465Smckusick vrele(vp); 171747540Skarels return (EEXIST); 171812756Ssam } 171941362Smckusick VATTR_NULL(&vattr); 172037741Smckusick vattr.va_type = VDIR; 172145914Smckusick vattr.va_mode = (uap->dmode & 0777) &~ p->p_fd->fd_cmask; 172252322Smckusick LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 172352322Smckusick error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr); 172438145Smckusick if (!error) 172552322Smckusick vput(nd.ni_vp); 172647540Skarels return (error); 172712756Ssam } 172812756Ssam 172912756Ssam /* 173012756Ssam * Rmdir system call. 173112756Ssam */ 173254916Storek struct rmdir_args { 173354916Storek char *name; 173454916Storek }; 173542441Smckusick /* ARGSUSED */ 173642441Smckusick rmdir(p, uap, retval) 173745914Smckusick struct proc *p; 173854916Storek struct rmdir_args *uap; 173942441Smckusick int *retval; 174012756Ssam { 174137741Smckusick register struct vnode *vp; 174237741Smckusick int error; 174347540Skarels struct nameidata nd; 174412756Ssam 174552322Smckusick NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE, uap->name, p); 174652322Smckusick if (error = namei(&nd)) 174747540Skarels return (error); 174852322Smckusick vp = nd.ni_vp; 174937741Smckusick if (vp->v_type != VDIR) { 175037741Smckusick error = ENOTDIR; 175112756Ssam goto out; 175212756Ssam } 175312756Ssam /* 175437741Smckusick * No rmdir "." please. 175512756Ssam */ 175652322Smckusick if (nd.ni_dvp == vp) { 175737741Smckusick error = EINVAL; 175812756Ssam goto out; 175912756Ssam } 176012756Ssam /* 176149365Smckusick * The root of a mounted filesystem cannot be deleted. 176212756Ssam */ 176337741Smckusick if (vp->v_flag & VROOT) 176437741Smckusick error = EBUSY; 176512756Ssam out: 176642465Smckusick if (!error) { 176752322Smckusick LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 176852192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 176952322Smckusick error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); 177042465Smckusick } else { 177152322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 177252322Smckusick if (nd.ni_dvp == vp) 177352322Smckusick vrele(nd.ni_dvp); 177443344Smckusick else 177552322Smckusick vput(nd.ni_dvp); 177642465Smckusick vput(vp); 177742465Smckusick } 177847540Skarels return (error); 177912756Ssam } 178012756Ssam 178154620Smckusick #ifdef COMPAT_43 178237741Smckusick /* 178349365Smckusick * Read a block of directory entries in a file system independent format. 178437741Smckusick */ 178554916Storek struct ogetdirentries_args { 178654916Storek int fd; 178754916Storek char *buf; 178854916Storek unsigned count; 178954916Storek long *basep; 179054916Storek }; 179154620Smckusick ogetdirentries(p, uap, retval) 179254620Smckusick struct proc *p; 179354916Storek register struct ogetdirentries_args *uap; 179454620Smckusick int *retval; 179554620Smckusick { 179654620Smckusick register struct vnode *vp; 179754620Smckusick struct file *fp; 179854620Smckusick struct uio auio, kuio; 179954620Smckusick struct iovec aiov, kiov; 180054620Smckusick struct dirent *dp, *edp; 180154620Smckusick caddr_t dirbuf; 180254620Smckusick int error, readcnt; 180354969Smckusick long loff; 180454620Smckusick 180554620Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 180654620Smckusick return (error); 180754620Smckusick if ((fp->f_flag & FREAD) == 0) 180854620Smckusick return (EBADF); 180954620Smckusick vp = (struct vnode *)fp->f_data; 181054620Smckusick if (vp->v_type != VDIR) 181154620Smckusick return (EINVAL); 181254620Smckusick aiov.iov_base = uap->buf; 181354620Smckusick aiov.iov_len = uap->count; 181454620Smckusick auio.uio_iov = &aiov; 181554620Smckusick auio.uio_iovcnt = 1; 181654620Smckusick auio.uio_rw = UIO_READ; 181754620Smckusick auio.uio_segflg = UIO_USERSPACE; 181854620Smckusick auio.uio_procp = p; 181954620Smckusick auio.uio_resid = uap->count; 182054620Smckusick VOP_LOCK(vp); 182154969Smckusick loff = auio.uio_offset = fp->f_offset; 182254620Smckusick # if (BYTE_ORDER != LITTLE_ENDIAN) 182354620Smckusick if (vp->v_mount->mnt_maxsymlinklen <= 0) 182454620Smckusick error = VOP_READDIR(vp, &auio, fp->f_cred); 182554620Smckusick else 182654620Smckusick # endif 182754620Smckusick { 182854620Smckusick kuio = auio; 182954620Smckusick kuio.uio_iov = &kiov; 183054620Smckusick kuio.uio_segflg = UIO_SYSSPACE; 183154620Smckusick kiov.iov_len = uap->count; 183254620Smckusick MALLOC(dirbuf, caddr_t, uap->count, M_TEMP, M_WAITOK); 183354620Smckusick kiov.iov_base = dirbuf; 183454620Smckusick error = VOP_READDIR(vp, &kuio, fp->f_cred); 183554620Smckusick if (error == 0) { 183654620Smckusick readcnt = uap->count - kuio.uio_resid; 183754620Smckusick edp = (struct dirent *)&dirbuf[readcnt]; 183854620Smckusick for (dp = (struct dirent *)dirbuf; dp < edp; ) { 183954620Smckusick # if (BYTE_ORDER == LITTLE_ENDIAN) 184054969Smckusick /* 184155009Smckusick * The expected low byte of 184255009Smckusick * dp->d_namlen is our dp->d_type. 184355009Smckusick * The high MBZ byte of dp->d_namlen 184455009Smckusick * is our dp->d_namlen. 184554969Smckusick */ 184655009Smckusick dp->d_type = dp->d_namlen; 184755009Smckusick dp->d_namlen = 0; 184855009Smckusick # else 184955009Smckusick /* 185055009Smckusick * The dp->d_type is the high byte 185155009Smckusick * of the expected dp->d_namlen, 185255009Smckusick * so must be zero'ed. 185355009Smckusick */ 185455009Smckusick dp->d_type = 0; 185554620Smckusick # endif 185654620Smckusick if (dp->d_reclen > 0) { 185754620Smckusick dp = (struct dirent *) 185854620Smckusick ((char *)dp + dp->d_reclen); 185954620Smckusick } else { 186054620Smckusick error = EIO; 186154620Smckusick break; 186254620Smckusick } 186354620Smckusick } 186454620Smckusick if (dp >= edp) 186554620Smckusick error = uiomove(dirbuf, readcnt, &auio); 186654620Smckusick } 186754620Smckusick FREE(dirbuf, M_TEMP); 186854620Smckusick } 186954620Smckusick fp->f_offset = auio.uio_offset; 187054620Smckusick VOP_UNLOCK(vp); 187154620Smckusick if (error) 187254620Smckusick return (error); 187354969Smckusick error = copyout((caddr_t)&loff, (caddr_t)uap->basep, sizeof(long)); 187454620Smckusick *retval = uap->count - auio.uio_resid; 187554620Smckusick return (error); 187654620Smckusick } 187754620Smckusick #endif 187854620Smckusick 187954620Smckusick /* 188054620Smckusick * Read a block of directory entries in a file system independent format. 188154620Smckusick */ 188254916Storek struct getdirentries_args { 188354916Storek int fd; 188454916Storek char *buf; 188554916Storek unsigned count; 188654916Storek long *basep; 188754916Storek }; 188842441Smckusick getdirentries(p, uap, retval) 188945914Smckusick struct proc *p; 189054916Storek register struct getdirentries_args *uap; 189142441Smckusick int *retval; 189242441Smckusick { 189339592Smckusick register struct vnode *vp; 189416540Ssam struct file *fp; 189537741Smckusick struct uio auio; 189637741Smckusick struct iovec aiov; 189754969Smckusick long loff; 189854441Smckusick int error; 189912756Ssam 190045914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 190147540Skarels return (error); 190237741Smckusick if ((fp->f_flag & FREAD) == 0) 190347540Skarels return (EBADF); 190439592Smckusick vp = (struct vnode *)fp->f_data; 1905*55451Spendry unionread: 190639592Smckusick if (vp->v_type != VDIR) 190747540Skarels return (EINVAL); 190837741Smckusick aiov.iov_base = uap->buf; 190937741Smckusick aiov.iov_len = uap->count; 191037741Smckusick auio.uio_iov = &aiov; 191137741Smckusick auio.uio_iovcnt = 1; 191237741Smckusick auio.uio_rw = UIO_READ; 191337741Smckusick auio.uio_segflg = UIO_USERSPACE; 191448026Smckusick auio.uio_procp = p; 191537741Smckusick auio.uio_resid = uap->count; 191639592Smckusick VOP_LOCK(vp); 191754969Smckusick loff = auio.uio_offset = fp->f_offset; 191854441Smckusick error = VOP_READDIR(vp, &auio, fp->f_cred); 191939592Smckusick fp->f_offset = auio.uio_offset; 192039592Smckusick VOP_UNLOCK(vp); 192139592Smckusick if (error) 192247540Skarels return (error); 1923*55451Spendry if ((uap->count == auio.uio_resid) && 1924*55451Spendry (vp->v_flag & VROOT) && 1925*55451Spendry (vp->v_mount->mnt_flag & MNT_UNION)) { 1926*55451Spendry struct vnode *tvp = vp; 1927*55451Spendry vp = vp->v_mount->mnt_vnodecovered; 1928*55451Spendry VREF(vp); 1929*55451Spendry fp->f_data = (caddr_t) vp; 1930*55451Spendry fp->f_offset = 0; 1931*55451Spendry vrele(tvp); 1932*55451Spendry goto unionread; 1933*55451Spendry } 193454969Smckusick error = copyout((caddr_t)&loff, (caddr_t)uap->basep, sizeof(long)); 193542441Smckusick *retval = uap->count - auio.uio_resid; 193647540Skarels return (error); 193712756Ssam } 193812756Ssam 193912756Ssam /* 194049365Smckusick * Set the mode mask for creation of filesystem nodes. 194112756Ssam */ 194254916Storek struct umask_args { 194354916Storek int mask; 194454916Storek }; 194554916Storek mode_t /* XXX */ 194642441Smckusick umask(p, uap, retval) 194745914Smckusick struct proc *p; 194854916Storek struct umask_args *uap; 194942441Smckusick int *retval; 195012756Ssam { 195145914Smckusick register struct filedesc *fdp = p->p_fd; 195212756Ssam 195345914Smckusick *retval = fdp->fd_cmask; 195445914Smckusick fdp->fd_cmask = uap->mask & 07777; 195547540Skarels return (0); 195612756Ssam } 195737741Smckusick 195839566Smarc /* 195939566Smarc * Void all references to file by ripping underlying filesystem 196039566Smarc * away from vnode. 196139566Smarc */ 196254916Storek struct revoke_args { 196354916Storek char *fname; 196454916Storek }; 196542441Smckusick /* ARGSUSED */ 196642441Smckusick revoke(p, uap, retval) 196745914Smckusick struct proc *p; 196854916Storek register struct revoke_args *uap; 196942441Smckusick int *retval; 197042441Smckusick { 197139566Smarc register struct vnode *vp; 197239566Smarc struct vattr vattr; 197339566Smarc int error; 197447540Skarels struct nameidata nd; 197539566Smarc 197652322Smckusick NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->fname, p); 197752322Smckusick if (error = namei(&nd)) 197847540Skarels return (error); 197952322Smckusick vp = nd.ni_vp; 198039566Smarc if (vp->v_type != VCHR && vp->v_type != VBLK) { 198139566Smarc error = EINVAL; 198239566Smarc goto out; 198339566Smarc } 198448026Smckusick if (error = VOP_GETATTR(vp, &vattr, p->p_ucred, p)) 198539566Smarc goto out; 198647540Skarels if (p->p_ucred->cr_uid != vattr.va_uid && 198747540Skarels (error = suser(p->p_ucred, &p->p_acflag))) 198839566Smarc goto out; 198939805Smckusick if (vp->v_usecount > 1 || (vp->v_flag & VALIASED)) 199039632Smckusick vgoneall(vp); 199139566Smarc out: 199239566Smarc vrele(vp); 199347540Skarels return (error); 199439566Smarc } 199539566Smarc 199649365Smckusick /* 199749365Smckusick * Convert a user file descriptor to a kernel file entry. 199849365Smckusick */ 199945914Smckusick getvnode(fdp, fdes, fpp) 200045914Smckusick struct filedesc *fdp; 200137741Smckusick struct file **fpp; 200237741Smckusick int fdes; 200337741Smckusick { 200437741Smckusick struct file *fp; 200537741Smckusick 200647540Skarels if ((unsigned)fdes >= fdp->fd_nfiles || 200747688Skarels (fp = fdp->fd_ofiles[fdes]) == NULL) 200837741Smckusick return (EBADF); 200937741Smckusick if (fp->f_type != DTYPE_VNODE) 201037741Smckusick return (EINVAL); 201137741Smckusick *fpp = fp; 201237741Smckusick return (0); 201337741Smckusick } 2014