123405Smckusick /* 237741Smckusick * Copyright (c) 1989 The Regents of the University of California. 337741Smckusick * All rights reserved. 423405Smckusick * 544459Sbostic * %sccs.include.redist.c% 637741Smckusick * 7*52287Smckusick * @(#)vfs_syscalls.c 7.77 (Berkeley) 02/03/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" 2237Sbill 2352230Sheideman /* NEEDSWORK: debugging */ 2452230Sheideman #define CURCOUNT (curproc?curproc->p_spare[2]:0) 2552230Sheideman #define CHECKPOINT int oldrefcount=CURCOUNT; 2652230Sheideman #define CHECKCHECK(F) if (oldrefcount!=CURCOUNT) { printf("REFCOUNT: %s, old=%d, new=%d\n", (F), oldrefcount, CURCOUNT); } 2752230Sheideman 2837741Smckusick /* 2937741Smckusick * Virtual File System System Calls 3037741Smckusick */ 3112756Ssam 329167Ssam /* 3349365Smckusick * Mount system call. 349167Ssam */ 3542441Smckusick /* ARGSUSED */ 3642441Smckusick mount(p, uap, retval) 3745914Smckusick struct proc *p; 3842441Smckusick register struct args { 3937741Smckusick int type; 4037741Smckusick char *dir; 4137741Smckusick int flags; 4237741Smckusick caddr_t data; 4342441Smckusick } *uap; 4442441Smckusick int *retval; 4542441Smckusick { 4647540Skarels register struct nameidata *ndp; 4739335Smckusick register struct vnode *vp; 4839335Smckusick register struct mount *mp; 4940111Smckusick int error, flag; 5047540Skarels struct nameidata nd; 516254Sroot 5237741Smckusick /* 5337741Smckusick * Must be super user 5437741Smckusick */ 5547540Skarels if (error = suser(p->p_ucred, &p->p_acflag)) 5647540Skarels return (error); 5737741Smckusick /* 5837741Smckusick * Get vnode to be covered 5937741Smckusick */ 6047540Skarels ndp = &nd; 6137741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 6237741Smckusick ndp->ni_segflg = UIO_USERSPACE; 6337741Smckusick ndp->ni_dirp = uap->dir; 6447540Skarels if (error = namei(ndp, p)) 6547540Skarels return (error); 6637741Smckusick vp = ndp->ni_vp; 6741400Smckusick if (uap->flags & MNT_UPDATE) { 6839335Smckusick if ((vp->v_flag & VROOT) == 0) { 6939335Smckusick vput(vp); 7047540Skarels return (EINVAL); 7139335Smckusick } 7239335Smckusick mp = vp->v_mount; 7339335Smckusick /* 7439335Smckusick * We allow going from read-only to read-write, 7539335Smckusick * but not from read-write to read-only. 7639335Smckusick */ 7741400Smckusick if ((mp->mnt_flag & MNT_RDONLY) == 0 && 7841400Smckusick (uap->flags & MNT_RDONLY) != 0) { 7939335Smckusick vput(vp); 8047540Skarels return (EOPNOTSUPP); /* Needs translation */ 8139335Smckusick } 8241400Smckusick flag = mp->mnt_flag; 8341400Smckusick mp->mnt_flag |= MNT_UPDATE; 8439335Smckusick VOP_UNLOCK(vp); 8539335Smckusick goto update; 8639335Smckusick } 8739665Smckusick vinvalbuf(vp, 1); 8839805Smckusick if (vp->v_usecount != 1) { 8937741Smckusick vput(vp); 9047540Skarels return (EBUSY); 9137741Smckusick } 9237741Smckusick if (vp->v_type != VDIR) { 9337741Smckusick vput(vp); 9447540Skarels return (ENOTDIR); 9537741Smckusick } 9639741Smckusick if ((unsigned long)uap->type > MOUNT_MAXTYPE || 9737741Smckusick vfssw[uap->type] == (struct vfsops *)0) { 9837741Smckusick vput(vp); 9947540Skarels return (ENODEV); 10037741Smckusick } 10137741Smckusick 10237741Smckusick /* 10339335Smckusick * Allocate and initialize the file system. 10437741Smckusick */ 10537741Smckusick mp = (struct mount *)malloc((u_long)sizeof(struct mount), 10637741Smckusick M_MOUNT, M_WAITOK); 10741400Smckusick mp->mnt_op = vfssw[uap->type]; 10841400Smckusick mp->mnt_flag = 0; 10941400Smckusick mp->mnt_mounth = NULLVP; 11039335Smckusick if (error = vfs_lock(mp)) { 11139335Smckusick free((caddr_t)mp, M_MOUNT); 11239335Smckusick vput(vp); 11347540Skarels return (error); 11439335Smckusick } 11539335Smckusick if (vp->v_mountedhere != (struct mount *)0) { 11639335Smckusick vfs_unlock(mp); 11739335Smckusick free((caddr_t)mp, M_MOUNT); 11839335Smckusick vput(vp); 11947540Skarels return (EBUSY); 12039335Smckusick } 12139335Smckusick vp->v_mountedhere = mp; 12241400Smckusick mp->mnt_vnodecovered = vp; 12339335Smckusick update: 12439335Smckusick /* 12539335Smckusick * Set the mount level flags. 12639335Smckusick */ 12741400Smckusick if (uap->flags & MNT_RDONLY) 12841400Smckusick mp->mnt_flag |= MNT_RDONLY; 12939335Smckusick else 13041400Smckusick mp->mnt_flag &= ~MNT_RDONLY; 13141400Smckusick if (uap->flags & MNT_NOSUID) 13241400Smckusick mp->mnt_flag |= MNT_NOSUID; 13339335Smckusick else 13441400Smckusick mp->mnt_flag &= ~MNT_NOSUID; 13541400Smckusick if (uap->flags & MNT_NOEXEC) 13641400Smckusick mp->mnt_flag |= MNT_NOEXEC; 13739335Smckusick else 13841400Smckusick mp->mnt_flag &= ~MNT_NOEXEC; 13941400Smckusick if (uap->flags & MNT_NODEV) 14041400Smckusick mp->mnt_flag |= MNT_NODEV; 14139335Smckusick else 14241400Smckusick mp->mnt_flag &= ~MNT_NODEV; 14341400Smckusick if (uap->flags & MNT_SYNCHRONOUS) 14441400Smckusick mp->mnt_flag |= MNT_SYNCHRONOUS; 14539335Smckusick else 14641400Smckusick mp->mnt_flag &= ~MNT_SYNCHRONOUS; 14739335Smckusick /* 14839335Smckusick * Mount the filesystem. 14939335Smckusick */ 15048026Smckusick error = VFS_MOUNT(mp, uap->dir, uap->data, ndp, p); 15141400Smckusick if (mp->mnt_flag & MNT_UPDATE) { 15241400Smckusick mp->mnt_flag &= ~MNT_UPDATE; 15339335Smckusick vrele(vp); 15440111Smckusick if (error) 15541400Smckusick mp->mnt_flag = flag; 15647540Skarels return (error); 15739335Smckusick } 15840110Smckusick /* 15940110Smckusick * Put the new filesystem on the mount list after root. 16040110Smckusick */ 16141400Smckusick mp->mnt_next = rootfs->mnt_next; 16241400Smckusick mp->mnt_prev = rootfs; 16341400Smckusick rootfs->mnt_next = mp; 16441400Smckusick mp->mnt_next->mnt_prev = mp; 16537741Smckusick cache_purge(vp); 16637741Smckusick if (!error) { 16739335Smckusick VOP_UNLOCK(vp); 16837741Smckusick vfs_unlock(mp); 16948026Smckusick error = VFS_START(mp, 0, p); 17037741Smckusick } else { 17137741Smckusick vfs_remove(mp); 17237741Smckusick free((caddr_t)mp, M_MOUNT); 17339335Smckusick vput(vp); 17437741Smckusick } 17547540Skarels return (error); 1766254Sroot } 1776254Sroot 1789167Ssam /* 17937741Smckusick * Unmount system call. 18037741Smckusick * 18137741Smckusick * Note: unmount takes a path to the vnode mounted on as argument, 18237741Smckusick * not special file (as before). 1839167Ssam */ 18442441Smckusick /* ARGSUSED */ 18542441Smckusick unmount(p, uap, retval) 18645914Smckusick struct proc *p; 18742441Smckusick register struct args { 18837741Smckusick char *pathp; 18937741Smckusick int flags; 19042441Smckusick } *uap; 19142441Smckusick int *retval; 19242441Smckusick { 19337741Smckusick register struct vnode *vp; 19447540Skarels register struct nameidata *ndp; 19539356Smckusick struct mount *mp; 19637741Smckusick int error; 19747540Skarels struct nameidata nd; 1986254Sroot 19937741Smckusick /* 20037741Smckusick * Must be super user 20137741Smckusick */ 20247540Skarels if (error = suser(p->p_ucred, &p->p_acflag)) 20347540Skarels return (error); 20437741Smckusick 20547540Skarels ndp = &nd; 20637741Smckusick ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW; 20737741Smckusick ndp->ni_segflg = UIO_USERSPACE; 20837741Smckusick ndp->ni_dirp = uap->pathp; 20947540Skarels if (error = namei(ndp, p)) 21047540Skarels return (error); 21137741Smckusick vp = ndp->ni_vp; 21237741Smckusick /* 21337741Smckusick * Must be the root of the filesystem 21437741Smckusick */ 21537741Smckusick if ((vp->v_flag & VROOT) == 0) { 21637741Smckusick vput(vp); 21747540Skarels return (EINVAL); 21837741Smckusick } 21937741Smckusick mp = vp->v_mount; 22037741Smckusick vput(vp); 22148026Smckusick return (dounmount(mp, uap->flags, p)); 22239356Smckusick } 22339356Smckusick 22439356Smckusick /* 22539356Smckusick * Do an unmount. 22639356Smckusick */ 22748026Smckusick dounmount(mp, flags, p) 22839356Smckusick register struct mount *mp; 22939356Smckusick int flags; 23048026Smckusick struct proc *p; 23139356Smckusick { 23239356Smckusick struct vnode *coveredvp; 23339356Smckusick int error; 23439356Smckusick 23541400Smckusick coveredvp = mp->mnt_vnodecovered; 23641298Smckusick if (vfs_busy(mp)) 23741298Smckusick return (EBUSY); 23841400Smckusick mp->mnt_flag |= MNT_UNMOUNT; 23937741Smckusick if (error = vfs_lock(mp)) 24039356Smckusick return (error); 24137741Smckusick 24245738Smckusick vnode_pager_umount(mp); /* release cached vnodes */ 24337741Smckusick cache_purgevfs(mp); /* remove cache entries for this file sys */ 24441676Smckusick if ((error = VFS_SYNC(mp, MNT_WAIT)) == 0 || (flags & MNT_FORCE)) 24548026Smckusick error = VFS_UNMOUNT(mp, flags, p); 24641400Smckusick mp->mnt_flag &= ~MNT_UNMOUNT; 24741298Smckusick vfs_unbusy(mp); 24837741Smckusick if (error) { 24937741Smckusick vfs_unlock(mp); 25037741Smckusick } else { 25137741Smckusick vrele(coveredvp); 25237741Smckusick vfs_remove(mp); 253*52287Smckusick if (mp->mnt_mounth != NULL) 254*52287Smckusick panic("unmount: dangling vnode"); 25537741Smckusick free((caddr_t)mp, M_MOUNT); 25637741Smckusick } 25739356Smckusick return (error); 2586254Sroot } 2596254Sroot 2609167Ssam /* 26137741Smckusick * Sync system call. 26237741Smckusick * Sync each mounted filesystem. 2639167Ssam */ 26439491Smckusick /* ARGSUSED */ 26542441Smckusick sync(p, uap, retval) 26645914Smckusick struct proc *p; 26747540Skarels void *uap; 26842441Smckusick int *retval; 2696254Sroot { 27037741Smckusick register struct mount *mp; 27141298Smckusick struct mount *omp; 27237741Smckusick 27337741Smckusick mp = rootfs; 27437741Smckusick do { 27540343Smckusick /* 27640343Smckusick * The lock check below is to avoid races with mount 27740343Smckusick * and unmount. 27840343Smckusick */ 27941400Smckusick if ((mp->mnt_flag & (MNT_MLOCK|MNT_RDONLY|MNT_MPBUSY)) == 0 && 28041298Smckusick !vfs_busy(mp)) { 28137741Smckusick VFS_SYNC(mp, MNT_NOWAIT); 28241298Smckusick omp = mp; 28341400Smckusick mp = mp->mnt_next; 28441298Smckusick vfs_unbusy(omp); 28541298Smckusick } else 28641400Smckusick mp = mp->mnt_next; 28737741Smckusick } while (mp != rootfs); 28847688Skarels return (0); 28937741Smckusick } 29037741Smckusick 29137741Smckusick /* 29249365Smckusick * Operate on filesystem quotas. 29341298Smckusick */ 29442441Smckusick /* ARGSUSED */ 29542441Smckusick quotactl(p, uap, retval) 29645914Smckusick struct proc *p; 29742441Smckusick register struct args { 29841298Smckusick char *path; 29941298Smckusick int cmd; 30041298Smckusick int uid; 30141298Smckusick caddr_t arg; 30242441Smckusick } *uap; 30342441Smckusick int *retval; 30442441Smckusick { 30541298Smckusick register struct mount *mp; 30647540Skarels register struct nameidata *ndp; 30741298Smckusick int error; 30847540Skarels struct nameidata nd; 30941298Smckusick 31047540Skarels ndp = &nd; 31141298Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW; 31241298Smckusick ndp->ni_segflg = UIO_USERSPACE; 31341298Smckusick ndp->ni_dirp = uap->path; 31447540Skarels if (error = namei(ndp, p)) 31547540Skarels return (error); 31641298Smckusick mp = ndp->ni_vp->v_mount; 31741298Smckusick vrele(ndp->ni_vp); 31848026Smckusick return (VFS_QUOTACTL(mp, uap->cmd, uap->uid, uap->arg, p)); 31941298Smckusick } 32041298Smckusick 32141298Smckusick /* 32249365Smckusick * Get filesystem statistics. 32337741Smckusick */ 32442441Smckusick /* ARGSUSED */ 32542441Smckusick statfs(p, uap, retval) 32645914Smckusick struct proc *p; 32742441Smckusick register struct args { 32837741Smckusick char *path; 32937741Smckusick struct statfs *buf; 33042441Smckusick } *uap; 33142441Smckusick int *retval; 33242441Smckusick { 33339464Smckusick register struct mount *mp; 33447540Skarels register struct nameidata *ndp; 33540343Smckusick register struct statfs *sp; 33637741Smckusick int error; 33747540Skarels struct nameidata nd; 33837741Smckusick 33947540Skarels ndp = &nd; 34039544Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW; 34137741Smckusick ndp->ni_segflg = UIO_USERSPACE; 34237741Smckusick ndp->ni_dirp = uap->path; 34347540Skarels if (error = namei(ndp, p)) 34447540Skarels return (error); 34539544Smckusick mp = ndp->ni_vp->v_mount; 34641400Smckusick sp = &mp->mnt_stat; 34739544Smckusick vrele(ndp->ni_vp); 34848026Smckusick if (error = VFS_STATFS(mp, sp, p)) 34947540Skarels return (error); 35041400Smckusick sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 35147540Skarels return (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp))); 35237741Smckusick } 35337741Smckusick 35442441Smckusick /* 35549365Smckusick * Get filesystem statistics. 35642441Smckusick */ 35742441Smckusick /* ARGSUSED */ 35842441Smckusick fstatfs(p, uap, retval) 35945914Smckusick struct proc *p; 36042441Smckusick register struct args { 36137741Smckusick int fd; 36237741Smckusick struct statfs *buf; 36342441Smckusick } *uap; 36442441Smckusick int *retval; 36542441Smckusick { 36637741Smckusick struct file *fp; 36739464Smckusick struct mount *mp; 36840343Smckusick register struct statfs *sp; 36937741Smckusick int error; 37037741Smckusick 37145914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 37247540Skarels return (error); 37339464Smckusick mp = ((struct vnode *)fp->f_data)->v_mount; 37441400Smckusick sp = &mp->mnt_stat; 37548026Smckusick if (error = VFS_STATFS(mp, sp, p)) 37647540Skarels return (error); 37741400Smckusick sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 37847540Skarels return (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp))); 37937741Smckusick } 38037741Smckusick 38137741Smckusick /* 38249365Smckusick * Get statistics on all filesystems. 38338270Smckusick */ 38442441Smckusick getfsstat(p, uap, retval) 38545914Smckusick struct proc *p; 38642441Smckusick register struct args { 38738270Smckusick struct statfs *buf; 38838270Smckusick long bufsize; 38940343Smckusick int flags; 39042441Smckusick } *uap; 39142441Smckusick int *retval; 39242441Smckusick { 39338270Smckusick register struct mount *mp; 39440343Smckusick register struct statfs *sp; 39539606Smckusick caddr_t sfsp; 39638270Smckusick long count, maxcount, error; 39738270Smckusick 39838270Smckusick maxcount = uap->bufsize / sizeof(struct statfs); 39939606Smckusick sfsp = (caddr_t)uap->buf; 40038270Smckusick mp = rootfs; 40138270Smckusick count = 0; 40238270Smckusick do { 40341400Smckusick if (sfsp && count < maxcount && 40441400Smckusick ((mp->mnt_flag & MNT_MLOCK) == 0)) { 40541400Smckusick sp = &mp->mnt_stat; 40640343Smckusick /* 40740343Smckusick * If MNT_NOWAIT is specified, do not refresh the 40840343Smckusick * fsstat cache. MNT_WAIT overrides MNT_NOWAIT. 40940343Smckusick */ 41040343Smckusick if (((uap->flags & MNT_NOWAIT) == 0 || 41140343Smckusick (uap->flags & MNT_WAIT)) && 41248026Smckusick (error = VFS_STATFS(mp, sp, p))) { 41341400Smckusick mp = mp->mnt_prev; 41439607Smckusick continue; 41539607Smckusick } 41641400Smckusick sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 41740343Smckusick if (error = copyout((caddr_t)sp, sfsp, sizeof(*sp))) 41847540Skarels return (error); 41940343Smckusick sfsp += sizeof(*sp); 42038270Smckusick } 42139606Smckusick count++; 42241400Smckusick mp = mp->mnt_prev; 42338270Smckusick } while (mp != rootfs); 42438270Smckusick if (sfsp && count > maxcount) 42542441Smckusick *retval = maxcount; 42638270Smckusick else 42742441Smckusick *retval = count; 42847540Skarels return (0); 42938270Smckusick } 43038270Smckusick 43138270Smckusick /* 43238259Smckusick * Change current working directory to a given file descriptor. 43338259Smckusick */ 43442441Smckusick /* ARGSUSED */ 43542441Smckusick fchdir(p, uap, retval) 43645914Smckusick struct proc *p; 43742441Smckusick struct args { 43842441Smckusick int fd; 43942441Smckusick } *uap; 44042441Smckusick int *retval; 44138259Smckusick { 44245914Smckusick register struct filedesc *fdp = p->p_fd; 44338259Smckusick register struct vnode *vp; 44438259Smckusick struct file *fp; 44538259Smckusick int error; 44638259Smckusick 44745914Smckusick if (error = getvnode(fdp, uap->fd, &fp)) 44847540Skarels return (error); 44938259Smckusick vp = (struct vnode *)fp->f_data; 45038259Smckusick VOP_LOCK(vp); 45138259Smckusick if (vp->v_type != VDIR) 45238259Smckusick error = ENOTDIR; 45338259Smckusick else 45448026Smckusick error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p); 45538259Smckusick VOP_UNLOCK(vp); 45639860Smckusick if (error) 45747540Skarels return (error); 45839860Smckusick VREF(vp); 45945914Smckusick vrele(fdp->fd_cdir); 46045914Smckusick fdp->fd_cdir = vp; 46147540Skarels return (0); 46238259Smckusick } 46338259Smckusick 46438259Smckusick /* 46537741Smckusick * Change current working directory (``.''). 46637741Smckusick */ 46742441Smckusick /* ARGSUSED */ 46842441Smckusick chdir(p, uap, retval) 46945914Smckusick struct proc *p; 47042441Smckusick struct args { 47142441Smckusick char *fname; 47242441Smckusick } *uap; 47342441Smckusick int *retval; 47437741Smckusick { 47547540Skarels register struct nameidata *ndp; 47645914Smckusick register struct filedesc *fdp = p->p_fd; 47737741Smckusick int error; 47847540Skarels struct nameidata nd; 4796254Sroot 48047540Skarels ndp = &nd; 48137741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 48216694Smckusick ndp->ni_segflg = UIO_USERSPACE; 48316694Smckusick ndp->ni_dirp = uap->fname; 48447540Skarels if (error = chdirec(ndp, p)) 48547540Skarels return (error); 48645914Smckusick vrele(fdp->fd_cdir); 48745914Smckusick fdp->fd_cdir = ndp->ni_vp; 48847540Skarels return (0); 48937741Smckusick } 4906254Sroot 49137741Smckusick /* 49237741Smckusick * Change notion of root (``/'') directory. 49337741Smckusick */ 49442441Smckusick /* ARGSUSED */ 49542441Smckusick chroot(p, uap, retval) 49645914Smckusick struct proc *p; 49742441Smckusick struct args { 49842441Smckusick char *fname; 49942441Smckusick } *uap; 50042441Smckusick int *retval; 50137741Smckusick { 50247540Skarels register struct nameidata *ndp; 50345914Smckusick register struct filedesc *fdp = p->p_fd; 50437741Smckusick int error; 50547540Skarels struct nameidata nd; 50637741Smckusick 50747540Skarels if (error = suser(p->p_ucred, &p->p_acflag)) 50847540Skarels return (error); 50947540Skarels ndp = &nd; 51037741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 51137741Smckusick ndp->ni_segflg = UIO_USERSPACE; 51237741Smckusick ndp->ni_dirp = uap->fname; 51347540Skarels if (error = chdirec(ndp, p)) 51447540Skarels return (error); 51545914Smckusick if (fdp->fd_rdir != NULL) 51645914Smckusick vrele(fdp->fd_rdir); 51745914Smckusick fdp->fd_rdir = ndp->ni_vp; 51847540Skarels return (0); 5196254Sroot } 5206254Sroot 52137Sbill /* 52237741Smckusick * Common routine for chroot and chdir. 52337741Smckusick */ 52447540Skarels chdirec(ndp, p) 52547540Skarels struct nameidata *ndp; 52647540Skarels struct proc *p; 52737741Smckusick { 52837741Smckusick struct vnode *vp; 52937741Smckusick int error; 53037741Smckusick 53147540Skarels if (error = namei(ndp, p)) 53237741Smckusick return (error); 53337741Smckusick vp = ndp->ni_vp; 53437741Smckusick if (vp->v_type != VDIR) 53537741Smckusick error = ENOTDIR; 53637741Smckusick else 53748026Smckusick error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p); 53837741Smckusick VOP_UNLOCK(vp); 53937741Smckusick if (error) 54037741Smckusick vrele(vp); 54137741Smckusick return (error); 54237741Smckusick } 54337741Smckusick 54437741Smckusick /* 5456254Sroot * Open system call. 54642441Smckusick * Check permissions, allocate an open file structure, 54742441Smckusick * and call the device open routine if any. 5486254Sroot */ 54942441Smckusick open(p, uap, retval) 55045914Smckusick struct proc *p; 55142441Smckusick register struct args { 5526254Sroot char *fname; 5537701Ssam int mode; 55412756Ssam int crtmode; 55542441Smckusick } *uap; 55642441Smckusick int *retval; 5576254Sroot { 55847540Skarels struct nameidata *ndp; 55945914Smckusick register struct filedesc *fdp = p->p_fd; 56042441Smckusick register struct file *fp; 56150111Smckusick register struct vnode *vp; 56237741Smckusick int fmode, cmode; 56337741Smckusick struct file *nfp; 56449945Smckusick int type, indx, error; 56549945Smckusick struct flock lf; 56647540Skarels struct nameidata nd; 56737741Smckusick extern struct fileops vnops; 5686254Sroot 56945914Smckusick if (error = falloc(p, &nfp, &indx)) 57047540Skarels return (error); 57137741Smckusick fp = nfp; 57246553Skarels fmode = FFLAGS(uap->mode); 57345914Smckusick cmode = ((uap->crtmode &~ fdp->fd_cmask) & 07777) &~ S_ISVTX; 57447540Skarels ndp = &nd; 57542441Smckusick ndp->ni_segflg = UIO_USERSPACE; 57642441Smckusick ndp->ni_dirp = uap->fname; 57745202Smckusick p->p_dupfd = -indx - 1; /* XXX check for fdopen */ 57847540Skarels if (error = vn_open(ndp, p, fmode, cmode)) { 57949980Smckusick ffree(fp); 58043405Smckusick if (error == ENODEV && /* XXX from fdopen */ 58145202Smckusick p->p_dupfd >= 0 && 58245914Smckusick (error = dupfdopen(fdp, indx, p->p_dupfd, fmode)) == 0) { 58342441Smckusick *retval = indx; 58447540Skarels return (0); 58542441Smckusick } 58640884Smckusick if (error == ERESTART) 58740884Smckusick error = EINTR; 58847688Skarels fdp->fd_ofiles[indx] = NULL; 58947540Skarels return (error); 59012756Ssam } 59150111Smckusick vp = ndp->ni_vp; 59249949Smckusick fp->f_flag = fmode & FMASK; 59349945Smckusick if (fmode & (O_EXLOCK | O_SHLOCK)) { 59449945Smckusick lf.l_whence = SEEK_SET; 59549945Smckusick lf.l_start = 0; 59649945Smckusick lf.l_len = 0; 59749945Smckusick if (fmode & O_EXLOCK) 59849945Smckusick lf.l_type = F_WRLCK; 59949945Smckusick else 60049945Smckusick lf.l_type = F_RDLCK; 60149945Smckusick type = F_FLOCK; 60249945Smckusick if ((fmode & FNONBLOCK) == 0) 60349945Smckusick type |= F_WAIT; 60450111Smckusick if (error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, type)) { 60550111Smckusick VOP_UNLOCK(vp); 60650111Smckusick (void) vn_close(vp, fp->f_flag, fp->f_cred, p); 60749980Smckusick ffree(fp); 60849945Smckusick fdp->fd_ofiles[indx] = NULL; 60949945Smckusick return (error); 61049945Smckusick } 61149949Smckusick fp->f_flag |= FHASLOCK; 61249945Smckusick } 61350111Smckusick VOP_UNLOCK(vp); 61437741Smckusick fp->f_type = DTYPE_VNODE; 61537741Smckusick fp->f_ops = &vnops; 61650111Smckusick fp->f_data = (caddr_t)vp; 61742441Smckusick *retval = indx; 61847540Skarels return (0); 6196254Sroot } 6206254Sroot 62142955Smckusick #ifdef COMPAT_43 6226254Sroot /* 62342441Smckusick * Creat system call. 6246254Sroot */ 62542955Smckusick ocreat(p, uap, retval) 62642441Smckusick struct proc *p; 62742441Smckusick register struct args { 62842441Smckusick char *fname; 62942441Smckusick int fmode; 63042441Smckusick } *uap; 63142441Smckusick int *retval; 6326254Sroot { 63342441Smckusick struct args { 6346254Sroot char *fname; 63542441Smckusick int mode; 63642441Smckusick int crtmode; 63742441Smckusick } openuap; 63842441Smckusick 63942441Smckusick openuap.fname = uap->fname; 64042441Smckusick openuap.crtmode = uap->fmode; 64142441Smckusick openuap.mode = O_WRONLY | O_CREAT | O_TRUNC; 64247540Skarels return (open(p, &openuap, retval)); 64342441Smckusick } 64442955Smckusick #endif /* COMPAT_43 */ 64542441Smckusick 64642441Smckusick /* 64749365Smckusick * Mknod system call. 64842441Smckusick */ 64942441Smckusick /* ARGSUSED */ 65042441Smckusick mknod(p, uap, retval) 65145914Smckusick struct proc *p; 65242441Smckusick register struct args { 65342441Smckusick char *fname; 6546254Sroot int fmode; 6556254Sroot int dev; 65642441Smckusick } *uap; 65742441Smckusick int *retval; 65842441Smckusick { 65947540Skarels register struct nameidata *ndp; 66037741Smckusick register struct vnode *vp; 66137741Smckusick struct vattr vattr; 66237741Smckusick int error; 66347540Skarels struct nameidata nd; 6646254Sroot 66552230Sheideman CHECKPOINT; 66647540Skarels if (error = suser(p->p_ucred, &p->p_acflag)) 66747540Skarels return (error); 66847540Skarels ndp = &nd; 66937741Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 67016694Smckusick ndp->ni_segflg = UIO_USERSPACE; 67116694Smckusick ndp->ni_dirp = uap->fname; 67247540Skarels if (error = namei(ndp, p)) 67347540Skarels return (error); 67437741Smckusick vp = ndp->ni_vp; 67537741Smckusick if (vp != NULL) { 67637741Smckusick error = EEXIST; 67712756Ssam goto out; 6786254Sroot } 67941362Smckusick VATTR_NULL(&vattr); 68040635Smckusick switch (uap->fmode & S_IFMT) { 68112756Ssam 68240635Smckusick case S_IFMT: /* used by badsect to flag bad sectors */ 68337741Smckusick vattr.va_type = VBAD; 68437741Smckusick break; 68540635Smckusick case S_IFCHR: 68637741Smckusick vattr.va_type = VCHR; 68737741Smckusick break; 68840635Smckusick case S_IFBLK: 68937741Smckusick vattr.va_type = VBLK; 69037741Smckusick break; 69137741Smckusick default: 69237741Smckusick error = EINVAL; 69337741Smckusick goto out; 6946254Sroot } 69545914Smckusick vattr.va_mode = (uap->fmode & 07777) &~ p->p_fd->fd_cmask; 69637741Smckusick vattr.va_rdev = uap->dev; 6976254Sroot out: 69842465Smckusick if (!error) { 69952192Smckusick LEASE_CHECK(ndp->ni_dvp, p, p->p_ucred, LEASE_WRITE); 70052230Sheideman error = VOP_MKNOD(ndp->ni_dvp, &ndp->ni_vp, &ndp->ni_cnd, &vattr); 70142465Smckusick } else { 70252230Sheideman VOP_ABORTOP(ndp->ni_dvp, &ndp->ni_cnd); 70343344Smckusick if (ndp->ni_dvp == vp) 70443344Smckusick vrele(ndp->ni_dvp); 70543344Smckusick else 70643344Smckusick vput(ndp->ni_dvp); 70742465Smckusick if (vp) 70842465Smckusick vrele(vp); 70942465Smckusick } 71052230Sheideman CHECKCHECK("mknod"); 71147540Skarels return (error); 7126254Sroot } 7136254Sroot 7146254Sroot /* 71549365Smckusick * Mkfifo system call. 71640285Smckusick */ 71742441Smckusick /* ARGSUSED */ 71842441Smckusick mkfifo(p, uap, retval) 71945914Smckusick struct proc *p; 72042441Smckusick register struct args { 72140285Smckusick char *fname; 72240285Smckusick int fmode; 72342441Smckusick } *uap; 72442441Smckusick int *retval; 72542441Smckusick { 72647540Skarels register struct nameidata *ndp; 72740285Smckusick struct vattr vattr; 72840285Smckusick int error; 72947540Skarels struct nameidata nd; 73040285Smckusick 73140285Smckusick #ifndef FIFO 73247540Skarels return (EOPNOTSUPP); 73340285Smckusick #else 73447540Skarels ndp = &nd; 73540285Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 73640285Smckusick ndp->ni_segflg = UIO_USERSPACE; 73740285Smckusick ndp->ni_dirp = uap->fname; 73847540Skarels if (error = namei(ndp, p)) 73947540Skarels return (error); 74040285Smckusick if (ndp->ni_vp != NULL) { 74152230Sheideman VOP_ABORTOP(ndp->ni_dvp, &ndp->ni_cnd); 74243344Smckusick if (ndp->ni_dvp == ndp->ni_vp) 74343344Smckusick vrele(ndp->ni_dvp); 74443344Smckusick else 74543344Smckusick vput(ndp->ni_dvp); 74642465Smckusick vrele(ndp->ni_vp); 74747540Skarels return (EEXIST); 74840285Smckusick } 74945785Sbostic VATTR_NULL(&vattr); 75045785Sbostic vattr.va_type = VFIFO; 75145914Smckusick vattr.va_mode = (uap->fmode & 07777) &~ p->p_fd->fd_cmask; 75252192Smckusick LEASE_CHECK(ndp->ni_dvp, p, p->p_ucred, LEASE_WRITE); 75352230Sheideman return (VOP_MKNOD(ndp->ni_dvp, &ndp->ni_vp, &ndp->ni_cnd, &vattr)); 75440285Smckusick #endif /* FIFO */ 75540285Smckusick } 75640285Smckusick 75740285Smckusick /* 75849365Smckusick * Link system call. 7596254Sroot */ 76042441Smckusick /* ARGSUSED */ 76142441Smckusick link(p, uap, retval) 76245914Smckusick struct proc *p; 76342441Smckusick register struct args { 7646254Sroot char *target; 7656254Sroot char *linkname; 76642441Smckusick } *uap; 76742441Smckusick int *retval; 76842441Smckusick { 76947540Skarels register struct nameidata *ndp; 77037741Smckusick register struct vnode *vp, *xp; 77137741Smckusick int error; 77247540Skarels struct nameidata nd; 7736254Sroot 77452230Sheideman CHECKPOINT; 77547540Skarels ndp = &nd; 77616694Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW; 77716694Smckusick ndp->ni_segflg = UIO_USERSPACE; 77816694Smckusick ndp->ni_dirp = uap->target; 77947540Skarels if (error = namei(ndp, p)) 78047540Skarels return (error); 78137741Smckusick vp = ndp->ni_vp; 78237741Smckusick if (vp->v_type == VDIR && 78347540Skarels (error = suser(p->p_ucred, &p->p_acflag))) 78437741Smckusick goto out1; 78537741Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 78616694Smckusick ndp->ni_dirp = (caddr_t)uap->linkname; 78747540Skarels if (error = namei(ndp, p)) 78837741Smckusick goto out1; 78937741Smckusick xp = ndp->ni_vp; 7906254Sroot if (xp != NULL) { 79137741Smckusick error = EEXIST; 7926254Sroot goto out; 7936254Sroot } 79437741Smckusick xp = ndp->ni_dvp; 79537741Smckusick if (vp->v_mount != xp->v_mount) 79637741Smckusick error = EXDEV; 7976254Sroot out: 79842465Smckusick if (!error) { 79952192Smckusick LEASE_CHECK(xp, p, p->p_ucred, LEASE_WRITE); 80052192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 80152230Sheideman error = VOP_LINK(vp, ndp->ni_dvp, &ndp->ni_cnd); 80242465Smckusick } else { 80352230Sheideman VOP_ABORTOP(ndp->ni_dvp, &ndp->ni_cnd); 80443344Smckusick if (ndp->ni_dvp == ndp->ni_vp) 80543344Smckusick vrele(ndp->ni_dvp); 80643344Smckusick else 80743344Smckusick vput(ndp->ni_dvp); 80842465Smckusick if (ndp->ni_vp) 80942465Smckusick vrele(ndp->ni_vp); 81042465Smckusick } 81137741Smckusick out1: 81237741Smckusick vrele(vp); 81352230Sheideman CHECKCHECK("link"); 81447540Skarels return (error); 8156254Sroot } 8166254Sroot 8176254Sroot /* 81849365Smckusick * Make a symbolic link. 8196254Sroot */ 82042441Smckusick /* ARGSUSED */ 82142441Smckusick symlink(p, uap, retval) 82245914Smckusick struct proc *p; 82342441Smckusick register struct args { 8246254Sroot char *target; 8256254Sroot char *linkname; 82642441Smckusick } *uap; 82742441Smckusick int *retval; 82842441Smckusick { 82947540Skarels register struct nameidata *ndp; 83037741Smckusick struct vattr vattr; 83137741Smckusick char *target; 83237741Smckusick int error; 83347540Skarels struct nameidata nd; 8346254Sroot 83552230Sheideman CHECKPOINT; 83647540Skarels ndp = &nd; 83716694Smckusick ndp->ni_segflg = UIO_USERSPACE; 83816694Smckusick ndp->ni_dirp = uap->linkname; 83937741Smckusick MALLOC(target, char *, MAXPATHLEN, M_NAMEI, M_WAITOK); 84037741Smckusick if (error = copyinstr(uap->target, target, MAXPATHLEN, (u_int *)0)) 84142465Smckusick goto out; 84237741Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 84347540Skarels if (error = namei(ndp, p)) 84442465Smckusick goto out; 84542465Smckusick if (ndp->ni_vp) { 84652230Sheideman VOP_ABORTOP(ndp->ni_dvp, &ndp->ni_cnd); 84743344Smckusick if (ndp->ni_dvp == ndp->ni_vp) 84843344Smckusick vrele(ndp->ni_dvp); 84943344Smckusick else 85043344Smckusick vput(ndp->ni_dvp); 85142465Smckusick vrele(ndp->ni_vp); 85237741Smckusick error = EEXIST; 85337741Smckusick goto out; 8546254Sroot } 85541362Smckusick VATTR_NULL(&vattr); 85645914Smckusick vattr.va_mode = 0777 &~ p->p_fd->fd_cmask; 85752192Smckusick LEASE_CHECK(ndp->ni_dvp, p, p->p_ucred, LEASE_WRITE); 85852230Sheideman error = VOP_SYMLINK(ndp->ni_dvp, &ndp->ni_vp, &ndp->ni_cnd, &vattr, target); 85937741Smckusick out: 86037741Smckusick FREE(target, M_NAMEI); 86152230Sheideman CHECKCHECK("symlink"); 86247540Skarels return (error); 8636254Sroot } 8646254Sroot 8656254Sroot /* 86649365Smckusick * Delete a name from the filesystem. 8676254Sroot */ 86842441Smckusick /* ARGSUSED */ 86942441Smckusick unlink(p, uap, retval) 87045914Smckusick struct proc *p; 87142441Smckusick struct args { 87242441Smckusick char *fname; 87342441Smckusick } *uap; 87442441Smckusick int *retval; 8756254Sroot { 87647540Skarels register struct nameidata *ndp; 87737741Smckusick register struct vnode *vp; 87837741Smckusick int error; 87947540Skarels struct nameidata nd; 8806254Sroot 88152230Sheideman CHECKPOINT; 88247540Skarels ndp = &nd; 88337741Smckusick ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF; 88416694Smckusick ndp->ni_segflg = UIO_USERSPACE; 88516694Smckusick ndp->ni_dirp = uap->fname; 88647540Skarels if (error = namei(ndp, p)) 88747540Skarels return (error); 88837741Smckusick vp = ndp->ni_vp; 88937741Smckusick if (vp->v_type == VDIR && 89047540Skarels (error = suser(p->p_ucred, &p->p_acflag))) 8916254Sroot goto out; 8926254Sroot /* 89349365Smckusick * The root of a mounted filesystem cannot be deleted. 8946254Sroot */ 89537741Smckusick if (vp->v_flag & VROOT) { 89637741Smckusick error = EBUSY; 8976254Sroot goto out; 8986254Sroot } 89945738Smckusick (void) vnode_pager_uncache(vp); 9006254Sroot out: 90142465Smckusick if (!error) { 90252192Smckusick LEASE_CHECK(ndp->ni_dvp, p, p->p_ucred, LEASE_WRITE); 90352192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 90452230Sheideman error = VOP_REMOVE(ndp->ni_dvp, ndp->ni_vp, &ndp->ni_cnd); 90542465Smckusick } else { 90652230Sheideman VOP_ABORTOP(ndp->ni_dvp, &ndp->ni_cnd); 90743344Smckusick if (ndp->ni_dvp == vp) 90843344Smckusick vrele(ndp->ni_dvp); 90943344Smckusick else 91043344Smckusick vput(ndp->ni_dvp); 91142465Smckusick vput(vp); 91242465Smckusick } 91352230Sheideman CHECKCHECK("unlink"); 91447540Skarels return (error); 9156254Sroot } 9166254Sroot 9176254Sroot /* 91849365Smckusick * Seek system call. 9196254Sroot */ 92042441Smckusick lseek(p, uap, retval) 92145914Smckusick struct proc *p; 92242441Smckusick register struct args { 92337741Smckusick int fdes; 9246254Sroot off_t off; 9256254Sroot int sbase; 92642441Smckusick } *uap; 92742441Smckusick off_t *retval; 92842441Smckusick { 92947540Skarels struct ucred *cred = p->p_ucred; 93045914Smckusick register struct filedesc *fdp = p->p_fd; 93142441Smckusick register struct file *fp; 93237741Smckusick struct vattr vattr; 93337741Smckusick int error; 9346254Sroot 93547540Skarels if ((unsigned)uap->fdes >= fdp->fd_nfiles || 93647688Skarels (fp = fdp->fd_ofiles[uap->fdes]) == NULL) 93747540Skarels return (EBADF); 93837741Smckusick if (fp->f_type != DTYPE_VNODE) 93947540Skarels return (ESPIPE); 94013878Ssam switch (uap->sbase) { 94113878Ssam 94213878Ssam case L_INCR: 94313878Ssam fp->f_offset += uap->off; 94413878Ssam break; 94513878Ssam 94613878Ssam case L_XTND: 94737741Smckusick if (error = VOP_GETATTR((struct vnode *)fp->f_data, 94848026Smckusick &vattr, cred, p)) 94947540Skarels return (error); 95037741Smckusick fp->f_offset = uap->off + vattr.va_size; 95113878Ssam break; 95213878Ssam 95313878Ssam case L_SET: 95413878Ssam fp->f_offset = uap->off; 95513878Ssam break; 95613878Ssam 95713878Ssam default: 95847540Skarels return (EINVAL); 95913878Ssam } 96042441Smckusick *retval = fp->f_offset; 96147540Skarels return (0); 9626254Sroot } 9636254Sroot 9646254Sroot /* 96549365Smckusick * Check access permissions. 9666254Sroot */ 96742441Smckusick /* ARGSUSED */ 96842441Smckusick saccess(p, uap, retval) 96945914Smckusick struct proc *p; 97042441Smckusick register struct args { 9716254Sroot char *fname; 9726254Sroot int fmode; 97342441Smckusick } *uap; 97442441Smckusick int *retval; 97542441Smckusick { 97647540Skarels register struct nameidata *ndp; 97747540Skarels register struct ucred *cred = p->p_ucred; 97837741Smckusick register struct vnode *vp; 97937741Smckusick int error, mode, svuid, svgid; 98047540Skarels struct nameidata nd; 9816254Sroot 98247540Skarels ndp = &nd; 98342441Smckusick svuid = cred->cr_uid; 98442441Smckusick svgid = cred->cr_groups[0]; 98547540Skarels cred->cr_uid = p->p_cred->p_ruid; 98647540Skarels cred->cr_groups[0] = p->p_cred->p_rgid; 98737741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 98816694Smckusick ndp->ni_segflg = UIO_USERSPACE; 98916694Smckusick ndp->ni_dirp = uap->fname; 99047540Skarels if (error = namei(ndp, p)) 99137741Smckusick goto out1; 99237741Smckusick vp = ndp->ni_vp; 99337741Smckusick /* 99437741Smckusick * fmode == 0 means only check for exist 99537741Smckusick */ 99637741Smckusick if (uap->fmode) { 99737741Smckusick mode = 0; 99837741Smckusick if (uap->fmode & R_OK) 99937741Smckusick mode |= VREAD; 100037741Smckusick if (uap->fmode & W_OK) 100137741Smckusick mode |= VWRITE; 100237741Smckusick if (uap->fmode & X_OK) 100337741Smckusick mode |= VEXEC; 100439543Smckusick if ((mode & VWRITE) == 0 || (error = vn_writechk(vp)) == 0) 100548026Smckusick error = VOP_ACCESS(vp, mode, cred, p); 10066254Sroot } 100737741Smckusick vput(vp); 100837741Smckusick out1: 100942441Smckusick cred->cr_uid = svuid; 101042441Smckusick cred->cr_groups[0] = svgid; 101147540Skarels return (error); 10126254Sroot } 10136254Sroot 10146254Sroot /* 101549365Smckusick * Stat system call. 101649365Smckusick * This version follows links. 101737Sbill */ 101842441Smckusick /* ARGSUSED */ 101942441Smckusick stat(p, uap, retval) 102045914Smckusick struct proc *p; 102142441Smckusick register struct args { 102242441Smckusick char *fname; 102342441Smckusick struct stat *ub; 102442441Smckusick } *uap; 102542441Smckusick int *retval; 102637Sbill { 102747540Skarels register struct nameidata *ndp; 102842441Smckusick struct stat sb; 102942441Smckusick int error; 103047540Skarels struct nameidata nd; 103137Sbill 103247540Skarels ndp = &nd; 103342441Smckusick ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW; 103442441Smckusick ndp->ni_segflg = UIO_USERSPACE; 103542441Smckusick ndp->ni_dirp = uap->fname; 103647540Skarels if (error = namei(ndp, p)) 103747540Skarels return (error); 103848026Smckusick error = vn_stat(ndp->ni_vp, &sb, p); 103942441Smckusick vput(ndp->ni_vp); 104042441Smckusick if (error) 104147540Skarels return (error); 104242441Smckusick error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb)); 104347540Skarels return (error); 104437Sbill } 104537Sbill 104637Sbill /* 104749365Smckusick * Lstat system call. 104849365Smckusick * This version does not follow links. 10495992Swnj */ 105042441Smckusick /* ARGSUSED */ 105142441Smckusick lstat(p, uap, retval) 105245914Smckusick struct proc *p; 105342441Smckusick register struct args { 10545992Swnj char *fname; 105512756Ssam struct stat *ub; 105642441Smckusick } *uap; 105742441Smckusick int *retval; 105842441Smckusick { 105947540Skarels register struct nameidata *ndp; 106012756Ssam struct stat sb; 106137741Smckusick int error; 106247540Skarels struct nameidata nd; 10635992Swnj 106447540Skarels ndp = &nd; 106542441Smckusick ndp->ni_nameiop = LOOKUP | LOCKLEAF | NOFOLLOW; 106616694Smckusick ndp->ni_segflg = UIO_USERSPACE; 106716694Smckusick ndp->ni_dirp = uap->fname; 106847540Skarels if (error = namei(ndp, p)) 106947540Skarels return (error); 107048026Smckusick error = vn_stat(ndp->ni_vp, &sb, p); 107137741Smckusick vput(ndp->ni_vp); 107237741Smckusick if (error) 107347540Skarels return (error); 107437741Smckusick error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb)); 107547540Skarels return (error); 10765992Swnj } 10775992Swnj 10785992Swnj /* 107949365Smckusick * Return target name of a symbolic link. 108037Sbill */ 108142441Smckusick /* ARGSUSED */ 108242441Smckusick readlink(p, uap, retval) 108345914Smckusick struct proc *p; 108442441Smckusick register struct args { 10855992Swnj char *name; 10865992Swnj char *buf; 10875992Swnj int count; 108842441Smckusick } *uap; 108942441Smckusick int *retval; 109042441Smckusick { 109147540Skarels register struct nameidata *ndp; 109237741Smckusick register struct vnode *vp; 109337741Smckusick struct iovec aiov; 109437741Smckusick struct uio auio; 109537741Smckusick int error; 109647540Skarels struct nameidata nd; 10975992Swnj 109852230Sheideman CHECKPOINT; 109947540Skarels ndp = &nd; 110037741Smckusick ndp->ni_nameiop = LOOKUP | LOCKLEAF; 110116694Smckusick ndp->ni_segflg = UIO_USERSPACE; 110216694Smckusick ndp->ni_dirp = uap->name; 110347540Skarels if (error = namei(ndp, p)) 110447540Skarels return (error); 110537741Smckusick vp = ndp->ni_vp; 110637741Smckusick if (vp->v_type != VLNK) { 110737741Smckusick error = EINVAL; 11085992Swnj goto out; 11095992Swnj } 111037741Smckusick aiov.iov_base = uap->buf; 111137741Smckusick aiov.iov_len = uap->count; 111237741Smckusick auio.uio_iov = &aiov; 111337741Smckusick auio.uio_iovcnt = 1; 111437741Smckusick auio.uio_offset = 0; 111537741Smckusick auio.uio_rw = UIO_READ; 111637741Smckusick auio.uio_segflg = UIO_USERSPACE; 111748026Smckusick auio.uio_procp = p; 111837741Smckusick auio.uio_resid = uap->count; 111947540Skarels error = VOP_READLINK(vp, &auio, p->p_ucred); 11205992Swnj out: 112137741Smckusick vput(vp); 112242441Smckusick *retval = uap->count - auio.uio_resid; 112352230Sheideman CHECKCHECK("readlink"); 112447540Skarels return (error); 11255992Swnj } 11265992Swnj 11279167Ssam /* 112838259Smckusick * Change flags of a file given path name. 112938259Smckusick */ 113042441Smckusick /* ARGSUSED */ 113142441Smckusick chflags(p, uap, retval) 113245914Smckusick struct proc *p; 113342441Smckusick register struct args { 113438259Smckusick char *fname; 113538259Smckusick int flags; 113642441Smckusick } *uap; 113742441Smckusick int *retval; 113842441Smckusick { 113947540Skarels register struct nameidata *ndp; 114038259Smckusick register struct vnode *vp; 114138259Smckusick struct vattr vattr; 114238259Smckusick int error; 114347540Skarels struct nameidata nd; 114438259Smckusick 114547540Skarels ndp = &nd; 114638259Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 114738259Smckusick ndp->ni_segflg = UIO_USERSPACE; 114838259Smckusick ndp->ni_dirp = uap->fname; 114947540Skarels if (error = namei(ndp, p)) 115047540Skarels return (error); 115138259Smckusick vp = ndp->ni_vp; 115241400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 115338259Smckusick error = EROFS; 115438259Smckusick goto out; 115538259Smckusick } 115645785Sbostic VATTR_NULL(&vattr); 115745785Sbostic vattr.va_flags = uap->flags; 115852192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 115948026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 116038259Smckusick out: 116138259Smckusick vput(vp); 116247540Skarels return (error); 116338259Smckusick } 116438259Smckusick 116538259Smckusick /* 116638259Smckusick * Change flags of a file given a file descriptor. 116738259Smckusick */ 116842441Smckusick /* ARGSUSED */ 116942441Smckusick fchflags(p, uap, retval) 117045914Smckusick struct proc *p; 117142441Smckusick register struct args { 117238259Smckusick int fd; 117338259Smckusick int flags; 117442441Smckusick } *uap; 117542441Smckusick int *retval; 117642441Smckusick { 117738259Smckusick struct vattr vattr; 117838259Smckusick struct vnode *vp; 117938259Smckusick struct file *fp; 118038259Smckusick int error; 118138259Smckusick 118245914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 118347540Skarels return (error); 118438259Smckusick vp = (struct vnode *)fp->f_data; 118538259Smckusick VOP_LOCK(vp); 118641400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 118738259Smckusick error = EROFS; 118838259Smckusick goto out; 118938259Smckusick } 119045785Sbostic VATTR_NULL(&vattr); 119145785Sbostic vattr.va_flags = uap->flags; 119252192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 119348026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 119438259Smckusick out: 119538259Smckusick VOP_UNLOCK(vp); 119647540Skarels return (error); 119738259Smckusick } 119838259Smckusick 119938259Smckusick /* 12009167Ssam * Change mode of a file given path name. 12019167Ssam */ 120242441Smckusick /* ARGSUSED */ 120342441Smckusick chmod(p, uap, retval) 120445914Smckusick struct proc *p; 120542441Smckusick register struct args { 12066254Sroot char *fname; 12076254Sroot int fmode; 120842441Smckusick } *uap; 120942441Smckusick int *retval; 121042441Smckusick { 121147540Skarels register struct nameidata *ndp; 121237741Smckusick register struct vnode *vp; 121337741Smckusick struct vattr vattr; 121437741Smckusick int error; 121547540Skarels struct nameidata nd; 12165992Swnj 121747540Skarels ndp = &nd; 121837741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 121937741Smckusick ndp->ni_segflg = UIO_USERSPACE; 122037741Smckusick ndp->ni_dirp = uap->fname; 122147540Skarels if (error = namei(ndp, p)) 122247540Skarels return (error); 122337741Smckusick vp = ndp->ni_vp; 122441400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 122537741Smckusick error = EROFS; 122637741Smckusick goto out; 122737741Smckusick } 122845785Sbostic VATTR_NULL(&vattr); 122945785Sbostic vattr.va_mode = uap->fmode & 07777; 123052192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 123148026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 123237741Smckusick out: 123337741Smckusick vput(vp); 123447540Skarels return (error); 12357701Ssam } 12367439Sroot 12379167Ssam /* 12389167Ssam * Change mode of a file given a file descriptor. 12399167Ssam */ 124042441Smckusick /* ARGSUSED */ 124142441Smckusick fchmod(p, uap, retval) 124245914Smckusick struct proc *p; 124342441Smckusick register struct args { 12447701Ssam int fd; 12457701Ssam int fmode; 124642441Smckusick } *uap; 124742441Smckusick int *retval; 124842441Smckusick { 124937741Smckusick struct vattr vattr; 125037741Smckusick struct vnode *vp; 125137741Smckusick struct file *fp; 125237741Smckusick int error; 12537701Ssam 125445914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 125547540Skarels return (error); 125637741Smckusick vp = (struct vnode *)fp->f_data; 125737741Smckusick VOP_LOCK(vp); 125841400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 125937741Smckusick error = EROFS; 126037741Smckusick goto out; 12617439Sroot } 126245785Sbostic VATTR_NULL(&vattr); 126345785Sbostic vattr.va_mode = uap->fmode & 07777; 126452192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 126548026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 126637741Smckusick out: 126737741Smckusick VOP_UNLOCK(vp); 126847540Skarels return (error); 12695992Swnj } 12705992Swnj 12719167Ssam /* 12729167Ssam * Set ownership given a path name. 12739167Ssam */ 127442441Smckusick /* ARGSUSED */ 127542441Smckusick chown(p, uap, retval) 127645914Smckusick struct proc *p; 127742441Smckusick register struct args { 12786254Sroot char *fname; 12796254Sroot int uid; 12806254Sroot int gid; 128142441Smckusick } *uap; 128242441Smckusick int *retval; 128342441Smckusick { 128447540Skarels register struct nameidata *ndp; 128537741Smckusick register struct vnode *vp; 128637741Smckusick struct vattr vattr; 128737741Smckusick int error; 128847540Skarels struct nameidata nd; 128937Sbill 129047540Skarels ndp = &nd; 129137741Smckusick ndp->ni_nameiop = LOOKUP | NOFOLLOW | LOCKLEAF; 129236614Sbostic ndp->ni_segflg = UIO_USERSPACE; 129336614Sbostic ndp->ni_dirp = uap->fname; 129447540Skarels if (error = namei(ndp, p)) 129547540Skarels return (error); 129637741Smckusick vp = ndp->ni_vp; 129741400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 129837741Smckusick error = EROFS; 129937741Smckusick goto out; 130037741Smckusick } 130145785Sbostic VATTR_NULL(&vattr); 130245785Sbostic vattr.va_uid = uap->uid; 130345785Sbostic vattr.va_gid = uap->gid; 130452192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 130548026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 130637741Smckusick out: 130737741Smckusick vput(vp); 130847540Skarels return (error); 13097701Ssam } 13107439Sroot 13119167Ssam /* 13129167Ssam * Set ownership given a file descriptor. 13139167Ssam */ 131442441Smckusick /* ARGSUSED */ 131542441Smckusick fchown(p, uap, retval) 131645914Smckusick struct proc *p; 131742441Smckusick register struct args { 13187701Ssam int fd; 13197701Ssam int uid; 13207701Ssam int gid; 132142441Smckusick } *uap; 132242441Smckusick int *retval; 132342441Smckusick { 132437741Smckusick struct vattr vattr; 132537741Smckusick struct vnode *vp; 132637741Smckusick struct file *fp; 132737741Smckusick int error; 13287701Ssam 132945914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 133047540Skarels return (error); 133137741Smckusick vp = (struct vnode *)fp->f_data; 133237741Smckusick VOP_LOCK(vp); 133341400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 133437741Smckusick error = EROFS; 133537741Smckusick goto out; 133637741Smckusick } 133745785Sbostic VATTR_NULL(&vattr); 133845785Sbostic vattr.va_uid = uap->uid; 133945785Sbostic vattr.va_gid = uap->gid; 134052192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 134148026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 134237741Smckusick out: 134337741Smckusick VOP_UNLOCK(vp); 134447540Skarels return (error); 13457701Ssam } 13467701Ssam 134742441Smckusick /* 134842441Smckusick * Set the access and modification times of a file. 134942441Smckusick */ 135042441Smckusick /* ARGSUSED */ 135142441Smckusick utimes(p, uap, retval) 135245914Smckusick struct proc *p; 135342441Smckusick register struct args { 135411811Ssam char *fname; 135511811Ssam struct timeval *tptr; 135642441Smckusick } *uap; 135742441Smckusick int *retval; 135842441Smckusick { 135947540Skarels register struct nameidata *ndp; 136037741Smckusick register struct vnode *vp; 136111811Ssam struct timeval tv[2]; 136237741Smckusick struct vattr vattr; 136337741Smckusick int error; 136447540Skarels struct nameidata nd; 136511811Ssam 136637741Smckusick if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv))) 136747540Skarels return (error); 136847540Skarels ndp = &nd; 136937741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 137037741Smckusick ndp->ni_segflg = UIO_USERSPACE; 137137741Smckusick ndp->ni_dirp = uap->fname; 137247540Skarels if (error = namei(ndp, p)) 137347540Skarels return (error); 137437741Smckusick vp = ndp->ni_vp; 137541400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 137637741Smckusick error = EROFS; 137737741Smckusick goto out; 137821015Smckusick } 137945785Sbostic VATTR_NULL(&vattr); 138045785Sbostic vattr.va_atime = tv[0]; 138145785Sbostic vattr.va_mtime = tv[1]; 138252192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 138348026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 138437741Smckusick out: 138537741Smckusick vput(vp); 138647540Skarels return (error); 138711811Ssam } 138811811Ssam 13899167Ssam /* 13909167Ssam * Truncate a file given its path name. 13919167Ssam */ 139242441Smckusick /* ARGSUSED */ 139342441Smckusick truncate(p, uap, retval) 139445914Smckusick struct proc *p; 139542441Smckusick register struct args { 13967701Ssam char *fname; 139726473Skarels off_t length; 139842441Smckusick } *uap; 139942441Smckusick int *retval; 140042441Smckusick { 140147540Skarels register struct nameidata *ndp; 140237741Smckusick register struct vnode *vp; 140337741Smckusick struct vattr vattr; 140437741Smckusick int error; 140547540Skarels struct nameidata nd; 14067701Ssam 140747540Skarels ndp = &nd; 140837741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 140916694Smckusick ndp->ni_segflg = UIO_USERSPACE; 141016694Smckusick ndp->ni_dirp = uap->fname; 141147540Skarels if (error = namei(ndp, p)) 141247540Skarels return (error); 141337741Smckusick vp = ndp->ni_vp; 141437741Smckusick if (vp->v_type == VDIR) { 141537741Smckusick error = EISDIR; 141637741Smckusick goto out; 14177701Ssam } 141838399Smckusick if ((error = vn_writechk(vp)) || 141948026Smckusick (error = VOP_ACCESS(vp, VWRITE, p->p_ucred, p))) 142037741Smckusick goto out; 142145785Sbostic VATTR_NULL(&vattr); 142245785Sbostic vattr.va_size = uap->length; 142352192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 142448026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 142537741Smckusick out: 142637741Smckusick vput(vp); 142747540Skarels return (error); 14287701Ssam } 14297701Ssam 14309167Ssam /* 14319167Ssam * Truncate a file given a file descriptor. 14329167Ssam */ 143342441Smckusick /* ARGSUSED */ 143442441Smckusick ftruncate(p, uap, retval) 143545914Smckusick struct proc *p; 143642441Smckusick register struct args { 14377701Ssam int fd; 143826473Skarels off_t length; 143942441Smckusick } *uap; 144042441Smckusick int *retval; 144142441Smckusick { 144237741Smckusick struct vattr vattr; 144337741Smckusick struct vnode *vp; 14447701Ssam struct file *fp; 144537741Smckusick int error; 14467701Ssam 144745914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 144847540Skarels return (error); 144937741Smckusick if ((fp->f_flag & FWRITE) == 0) 145047540Skarels return (EINVAL); 145137741Smckusick vp = (struct vnode *)fp->f_data; 145237741Smckusick VOP_LOCK(vp); 145337741Smckusick if (vp->v_type == VDIR) { 145437741Smckusick error = EISDIR; 145537741Smckusick goto out; 14567701Ssam } 145738399Smckusick if (error = vn_writechk(vp)) 145837741Smckusick goto out; 145945785Sbostic VATTR_NULL(&vattr); 146045785Sbostic vattr.va_size = uap->length; 146152192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 146248026Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred, p); 146337741Smckusick out: 146437741Smckusick VOP_UNLOCK(vp); 146547540Skarels return (error); 14667701Ssam } 14677701Ssam 14689167Ssam /* 14699167Ssam * Synch an open file. 14709167Ssam */ 147142441Smckusick /* ARGSUSED */ 147242441Smckusick fsync(p, uap, retval) 147345914Smckusick struct proc *p; 147442441Smckusick struct args { 147542441Smckusick int fd; 147642441Smckusick } *uap; 147742441Smckusick int *retval; 14789167Ssam { 147939592Smckusick register struct vnode *vp; 14809167Ssam struct file *fp; 148137741Smckusick int error; 14829167Ssam 148345914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 148447540Skarels return (error); 148539592Smckusick vp = (struct vnode *)fp->f_data; 148639592Smckusick VOP_LOCK(vp); 148748026Smckusick error = VOP_FSYNC(vp, fp->f_flag, fp->f_cred, MNT_WAIT, p); 148839592Smckusick VOP_UNLOCK(vp); 148947540Skarels return (error); 14909167Ssam } 14919167Ssam 14929167Ssam /* 14939167Ssam * Rename system call. 14949167Ssam * 14959167Ssam * Source and destination must either both be directories, or both 14969167Ssam * not be directories. If target is a directory, it must be empty. 14979167Ssam */ 149842441Smckusick /* ARGSUSED */ 149942441Smckusick rename(p, uap, retval) 150045914Smckusick struct proc *p; 150142441Smckusick register struct args { 15027701Ssam char *from; 15037701Ssam char *to; 150442441Smckusick } *uap; 150542441Smckusick int *retval; 150642441Smckusick { 150737741Smckusick register struct vnode *tvp, *fvp, *tdvp; 150849735Smckusick struct nameidata fromnd, tond; 150937741Smckusick int error; 15107701Ssam 151152230Sheideman CHECKPOINT; 151249735Smckusick fromnd.ni_nameiop = DELETE | WANTPARENT | SAVESTART; 151349735Smckusick fromnd.ni_segflg = UIO_USERSPACE; 151449735Smckusick fromnd.ni_dirp = uap->from; 151549735Smckusick if (error = namei(&fromnd, p)) 151647540Skarels return (error); 151749735Smckusick fvp = fromnd.ni_vp; 151849735Smckusick tond.ni_nameiop = RENAME | LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART; 151937741Smckusick tond.ni_segflg = UIO_USERSPACE; 152037741Smckusick tond.ni_dirp = uap->to; 152147540Skarels if (error = namei(&tond, p)) { 152252230Sheideman VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 152349735Smckusick vrele(fromnd.ni_dvp); 152442465Smckusick vrele(fvp); 152542465Smckusick goto out1; 152642465Smckusick } 152737741Smckusick tdvp = tond.ni_dvp; 152837741Smckusick tvp = tond.ni_vp; 152937741Smckusick if (tvp != NULL) { 153037741Smckusick if (fvp->v_type == VDIR && tvp->v_type != VDIR) { 153139242Sbostic error = ENOTDIR; 153237741Smckusick goto out; 153337741Smckusick } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) { 153439242Sbostic error = EISDIR; 153537741Smckusick goto out; 15369167Ssam } 153745240Smckusick if (fvp->v_mount != tvp->v_mount) { 153845240Smckusick error = EXDEV; 153945240Smckusick goto out; 154045240Smckusick } 15419167Ssam } 154237741Smckusick if (fvp->v_mount != tdvp->v_mount) { 154337741Smckusick error = EXDEV; 15449167Ssam goto out; 154510051Ssam } 154639286Smckusick if (fvp == tdvp) 154737741Smckusick error = EINVAL; 154839286Smckusick /* 154949735Smckusick * If source is the same as the destination (that is the 155049735Smckusick * same inode number with the same name in the same directory), 155139286Smckusick * then there is nothing to do. 155239286Smckusick */ 155349735Smckusick if (fvp == tvp && fromnd.ni_dvp == tdvp && 155449735Smckusick fromnd.ni_namelen == tond.ni_namelen && 155549735Smckusick !bcmp(fromnd.ni_ptr, tond.ni_ptr, fromnd.ni_namelen)) 155639286Smckusick error = -1; 155737741Smckusick out: 155842465Smckusick if (!error) { 155952192Smckusick LEASE_CHECK(tdvp, p, p->p_ucred, LEASE_WRITE); 156052192Smckusick if (fromnd.ni_dvp != tdvp) 156152192Smckusick LEASE_CHECK(fromnd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 156252192Smckusick if (tvp) 156352192Smckusick LEASE_CHECK(tvp, p, p->p_ucred, LEASE_WRITE); 156452230Sheideman if (fromnd.ni_startdir != fromnd.ni_dvp || 156552230Sheideman tond.ni_startdir != tond.ni_dvp) /* NEEDSWORK: debug */ 156652230Sheideman printf ("rename: f.startdir=%x, dvp=%x; t.startdir=%x, dvp=%x\n", fromnd.ni_startdir, fromnd.ni_dvp, tond.ni_startdir, tond.ni_dvp); 156752230Sheideman error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd, 156852230Sheideman tond.ni_dvp, tond.ni_vp, &tond.ni_cnd); 156952230Sheideman if (fromnd.ni_startdir != fromnd.ni_dvp || 157052230Sheideman tond.ni_startdir != tond.ni_dvp) /* NEEDSWORK: debug */ 157152230Sheideman printf ("rename: f.startdir=%x, dvp=%x; t.startdir=%x, dvp=%x\n", fromnd.ni_startdir, fromnd.ni_dvp, tond.ni_startdir, tond.ni_dvp); 157242465Smckusick } else { 157352230Sheideman VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd); 157443344Smckusick if (tdvp == tvp) 157543344Smckusick vrele(tdvp); 157643344Smckusick else 157743344Smckusick vput(tdvp); 157842465Smckusick if (tvp) 157942465Smckusick vput(tvp); 158052230Sheideman VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 158149735Smckusick vrele(fromnd.ni_dvp); 158242465Smckusick vrele(fvp); 15839167Ssam } 158449735Smckusick vrele(tond.ni_startdir); 158549735Smckusick FREE(tond.ni_pnbuf, M_NAMEI); 158637741Smckusick out1: 158749735Smckusick vrele(fromnd.ni_startdir); 158849735Smckusick FREE(fromnd.ni_pnbuf, M_NAMEI); 158952230Sheideman CHECKCHECK("rename"); 159039286Smckusick if (error == -1) 159147540Skarels return (0); 159247540Skarels return (error); 15937701Ssam } 15947701Ssam 15957535Sroot /* 159649365Smckusick * Mkdir system call. 159712756Ssam */ 159842441Smckusick /* ARGSUSED */ 159942441Smckusick mkdir(p, uap, retval) 160045914Smckusick struct proc *p; 160142441Smckusick register struct args { 160212756Ssam char *name; 160312756Ssam int dmode; 160442441Smckusick } *uap; 160542441Smckusick int *retval; 160642441Smckusick { 160747540Skarels register struct nameidata *ndp; 160837741Smckusick register struct vnode *vp; 160937741Smckusick struct vattr vattr; 161037741Smckusick int error; 161147540Skarels struct nameidata nd; 161212756Ssam 161352230Sheideman CHECKPOINT; 161447540Skarels ndp = &nd; 161537741Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 161616694Smckusick ndp->ni_segflg = UIO_USERSPACE; 161716694Smckusick ndp->ni_dirp = uap->name; 161847540Skarels if (error = namei(ndp, p)) 161947540Skarels return (error); 162037741Smckusick vp = ndp->ni_vp; 162137741Smckusick if (vp != NULL) { 162252230Sheideman VOP_ABORTOP(ndp->ni_dvp, &ndp->ni_cnd); 162343344Smckusick if (ndp->ni_dvp == vp) 162443344Smckusick vrele(ndp->ni_dvp); 162543344Smckusick else 162643344Smckusick vput(ndp->ni_dvp); 162742465Smckusick vrele(vp); 162852230Sheideman CHECKCHECK("mkdir1"); 162947540Skarels return (EEXIST); 163012756Ssam } 163141362Smckusick VATTR_NULL(&vattr); 163237741Smckusick vattr.va_type = VDIR; 163345914Smckusick vattr.va_mode = (uap->dmode & 0777) &~ p->p_fd->fd_cmask; 163452192Smckusick LEASE_CHECK(ndp->ni_dvp, p, p->p_ucred, LEASE_WRITE); 163552230Sheideman error = VOP_MKDIR(ndp->ni_dvp, &ndp->ni_vp, &ndp->ni_cnd, &vattr); 163638145Smckusick if (!error) 163738145Smckusick vput(ndp->ni_vp); 163852230Sheideman CHECKCHECK("mkdir2"); 163947540Skarels return (error); 164012756Ssam } 164112756Ssam 164212756Ssam /* 164312756Ssam * Rmdir system call. 164412756Ssam */ 164542441Smckusick /* ARGSUSED */ 164642441Smckusick rmdir(p, uap, retval) 164745914Smckusick struct proc *p; 164842441Smckusick struct args { 164942441Smckusick char *name; 165042441Smckusick } *uap; 165142441Smckusick int *retval; 165212756Ssam { 165347540Skarels register struct nameidata *ndp; 165437741Smckusick register struct vnode *vp; 165537741Smckusick int error; 165647540Skarels struct nameidata nd; 165712756Ssam 165852230Sheideman CHECKPOINT; 165947540Skarels ndp = &nd; 166037741Smckusick ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF; 166116694Smckusick ndp->ni_segflg = UIO_USERSPACE; 166216694Smckusick ndp->ni_dirp = uap->name; 166347540Skarels if (error = namei(ndp, p)) 166447540Skarels return (error); 166537741Smckusick vp = ndp->ni_vp; 166637741Smckusick if (vp->v_type != VDIR) { 166737741Smckusick error = ENOTDIR; 166812756Ssam goto out; 166912756Ssam } 167012756Ssam /* 167137741Smckusick * No rmdir "." please. 167212756Ssam */ 167337741Smckusick if (ndp->ni_dvp == vp) { 167437741Smckusick error = EINVAL; 167512756Ssam goto out; 167612756Ssam } 167712756Ssam /* 167849365Smckusick * The root of a mounted filesystem cannot be deleted. 167912756Ssam */ 168037741Smckusick if (vp->v_flag & VROOT) 168137741Smckusick error = EBUSY; 168212756Ssam out: 168342465Smckusick if (!error) { 168452192Smckusick LEASE_CHECK(ndp->ni_dvp, p, p->p_ucred, LEASE_WRITE); 168552192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 168652230Sheideman error = VOP_RMDIR(ndp->ni_dvp, ndp->ni_vp, &ndp->ni_cnd); 168742465Smckusick } else { 168852230Sheideman VOP_ABORTOP(ndp->ni_dvp, &ndp->ni_cnd); 168943344Smckusick if (ndp->ni_dvp == vp) 169043344Smckusick vrele(ndp->ni_dvp); 169143344Smckusick else 169243344Smckusick vput(ndp->ni_dvp); 169342465Smckusick vput(vp); 169442465Smckusick } 169552230Sheideman CHECKCHECK("rmdir"); 169647540Skarels return (error); 169712756Ssam } 169812756Ssam 169937741Smckusick /* 170049365Smckusick * Read a block of directory entries in a file system independent format. 170137741Smckusick */ 170242441Smckusick getdirentries(p, uap, retval) 170345914Smckusick struct proc *p; 170442441Smckusick register struct args { 170537741Smckusick int fd; 170637741Smckusick char *buf; 170737741Smckusick unsigned count; 170837741Smckusick long *basep; 170942441Smckusick } *uap; 171042441Smckusick int *retval; 171142441Smckusick { 171239592Smckusick register struct vnode *vp; 171316540Ssam struct file *fp; 171437741Smckusick struct uio auio; 171537741Smckusick struct iovec aiov; 171638129Smckusick off_t off; 171740321Smckusick int error, eofflag; 171812756Ssam 171945914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 172047540Skarels return (error); 172137741Smckusick if ((fp->f_flag & FREAD) == 0) 172247540Skarels return (EBADF); 172339592Smckusick vp = (struct vnode *)fp->f_data; 172439592Smckusick if (vp->v_type != VDIR) 172547540Skarels return (EINVAL); 172637741Smckusick aiov.iov_base = uap->buf; 172737741Smckusick aiov.iov_len = uap->count; 172837741Smckusick auio.uio_iov = &aiov; 172937741Smckusick auio.uio_iovcnt = 1; 173037741Smckusick auio.uio_rw = UIO_READ; 173137741Smckusick auio.uio_segflg = UIO_USERSPACE; 173248026Smckusick auio.uio_procp = p; 173337741Smckusick auio.uio_resid = uap->count; 173439592Smckusick VOP_LOCK(vp); 173539592Smckusick auio.uio_offset = off = fp->f_offset; 173640321Smckusick error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag); 173739592Smckusick fp->f_offset = auio.uio_offset; 173839592Smckusick VOP_UNLOCK(vp); 173939592Smckusick if (error) 174047540Skarels return (error); 174139592Smckusick error = copyout((caddr_t)&off, (caddr_t)uap->basep, sizeof(long)); 174242441Smckusick *retval = uap->count - auio.uio_resid; 174347540Skarels return (error); 174412756Ssam } 174512756Ssam 174612756Ssam /* 174749365Smckusick * Set the mode mask for creation of filesystem nodes. 174812756Ssam */ 174942441Smckusick mode_t 175042441Smckusick umask(p, uap, retval) 175145914Smckusick struct proc *p; 175242441Smckusick struct args { 175342441Smckusick int mask; 175442441Smckusick } *uap; 175542441Smckusick int *retval; 175612756Ssam { 175745914Smckusick register struct filedesc *fdp = p->p_fd; 175812756Ssam 175945914Smckusick *retval = fdp->fd_cmask; 176045914Smckusick fdp->fd_cmask = uap->mask & 07777; 176147540Skarels return (0); 176212756Ssam } 176337741Smckusick 176439566Smarc /* 176539566Smarc * Void all references to file by ripping underlying filesystem 176639566Smarc * away from vnode. 176739566Smarc */ 176842441Smckusick /* ARGSUSED */ 176942441Smckusick revoke(p, uap, retval) 177045914Smckusick struct proc *p; 177142441Smckusick register struct args { 177239566Smarc char *fname; 177342441Smckusick } *uap; 177442441Smckusick int *retval; 177542441Smckusick { 177647540Skarels register struct nameidata *ndp; 177739566Smarc register struct vnode *vp; 177839566Smarc struct vattr vattr; 177939566Smarc int error; 178047540Skarels struct nameidata nd; 178139566Smarc 178247540Skarels ndp = &nd; 178339566Smarc ndp->ni_nameiop = LOOKUP | FOLLOW; 178439566Smarc ndp->ni_segflg = UIO_USERSPACE; 178539566Smarc ndp->ni_dirp = uap->fname; 178647540Skarels if (error = namei(ndp, p)) 178747540Skarels return (error); 178839566Smarc vp = ndp->ni_vp; 178939566Smarc if (vp->v_type != VCHR && vp->v_type != VBLK) { 179039566Smarc error = EINVAL; 179139566Smarc goto out; 179239566Smarc } 179348026Smckusick if (error = VOP_GETATTR(vp, &vattr, p->p_ucred, p)) 179439566Smarc goto out; 179547540Skarels if (p->p_ucred->cr_uid != vattr.va_uid && 179647540Skarels (error = suser(p->p_ucred, &p->p_acflag))) 179739566Smarc goto out; 179839805Smckusick if (vp->v_usecount > 1 || (vp->v_flag & VALIASED)) 179939632Smckusick vgoneall(vp); 180039566Smarc out: 180139566Smarc vrele(vp); 180247540Skarels return (error); 180339566Smarc } 180439566Smarc 180549365Smckusick /* 180649365Smckusick * Convert a user file descriptor to a kernel file entry. 180749365Smckusick */ 180845914Smckusick getvnode(fdp, fdes, fpp) 180945914Smckusick struct filedesc *fdp; 181037741Smckusick struct file **fpp; 181137741Smckusick int fdes; 181237741Smckusick { 181337741Smckusick struct file *fp; 181437741Smckusick 181547540Skarels if ((unsigned)fdes >= fdp->fd_nfiles || 181647688Skarels (fp = fdp->fd_ofiles[fdes]) == NULL) 181737741Smckusick return (EBADF); 181837741Smckusick if (fp->f_type != DTYPE_VNODE) 181937741Smckusick return (EINVAL); 182037741Smckusick *fpp = fp; 182137741Smckusick return (0); 182237741Smckusick } 1823