123405Smckusick /* 237741Smckusick * Copyright (c) 1989 The Regents of the University of California. 337741Smckusick * All rights reserved. 423405Smckusick * 544459Sbostic * %sccs.include.redist.c% 637741Smckusick * 7*47540Skarels * @(#)vfs_syscalls.c 7.65 (Berkeley) 03/17/91 823405Smckusick */ 937Sbill 1017101Sbloom #include "param.h" 1117101Sbloom #include "systm.h" 12*47540Skarels #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 2337741Smckusick /* 2437741Smckusick * Virtual File System System Calls 2537741Smckusick */ 2612756Ssam 279167Ssam /* 2837741Smckusick * mount system call 299167Ssam */ 3042441Smckusick /* ARGSUSED */ 3142441Smckusick mount(p, uap, retval) 3245914Smckusick struct proc *p; 3342441Smckusick register struct args { 3437741Smckusick int type; 3537741Smckusick char *dir; 3637741Smckusick int flags; 3737741Smckusick caddr_t data; 3842441Smckusick } *uap; 3942441Smckusick int *retval; 4042441Smckusick { 41*47540Skarels register struct nameidata *ndp; 4239335Smckusick register struct vnode *vp; 4339335Smckusick register struct mount *mp; 4440111Smckusick int error, flag; 45*47540Skarels struct nameidata nd; 466254Sroot 4737741Smckusick /* 4837741Smckusick * Must be super user 4937741Smckusick */ 50*47540Skarels if (error = suser(p->p_ucred, &p->p_acflag)) 51*47540Skarels return (error); 5237741Smckusick /* 5337741Smckusick * Get vnode to be covered 5437741Smckusick */ 55*47540Skarels ndp = &nd; 5637741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 5737741Smckusick ndp->ni_segflg = UIO_USERSPACE; 5837741Smckusick ndp->ni_dirp = uap->dir; 59*47540Skarels if (error = namei(ndp, p)) 60*47540Skarels return (error); 6137741Smckusick vp = ndp->ni_vp; 6241400Smckusick if (uap->flags & MNT_UPDATE) { 6339335Smckusick if ((vp->v_flag & VROOT) == 0) { 6439335Smckusick vput(vp); 65*47540Skarels return (EINVAL); 6639335Smckusick } 6739335Smckusick mp = vp->v_mount; 6839335Smckusick /* 6939335Smckusick * We allow going from read-only to read-write, 7039335Smckusick * but not from read-write to read-only. 7139335Smckusick */ 7241400Smckusick if ((mp->mnt_flag & MNT_RDONLY) == 0 && 7341400Smckusick (uap->flags & MNT_RDONLY) != 0) { 7439335Smckusick vput(vp); 75*47540Skarels return (EOPNOTSUPP); /* Needs translation */ 7639335Smckusick } 7741400Smckusick flag = mp->mnt_flag; 7841400Smckusick mp->mnt_flag |= MNT_UPDATE; 7939335Smckusick VOP_UNLOCK(vp); 8039335Smckusick goto update; 8139335Smckusick } 8239665Smckusick vinvalbuf(vp, 1); 8339805Smckusick if (vp->v_usecount != 1) { 8437741Smckusick vput(vp); 85*47540Skarels return (EBUSY); 8637741Smckusick } 8737741Smckusick if (vp->v_type != VDIR) { 8837741Smckusick vput(vp); 89*47540Skarels return (ENOTDIR); 9037741Smckusick } 9139741Smckusick if ((unsigned long)uap->type > MOUNT_MAXTYPE || 9237741Smckusick vfssw[uap->type] == (struct vfsops *)0) { 9337741Smckusick vput(vp); 94*47540Skarels 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); 10241400Smckusick mp->mnt_op = vfssw[uap->type]; 10341400Smckusick mp->mnt_flag = 0; 10441400Smckusick mp->mnt_exroot = 0; 10541400Smckusick mp->mnt_mounth = NULLVP; 10639335Smckusick if (error = vfs_lock(mp)) { 10739335Smckusick free((caddr_t)mp, M_MOUNT); 10839335Smckusick vput(vp); 109*47540Skarels return (error); 11039335Smckusick } 11139335Smckusick if (vp->v_mountedhere != (struct mount *)0) { 11239335Smckusick vfs_unlock(mp); 11339335Smckusick free((caddr_t)mp, M_MOUNT); 11439335Smckusick vput(vp); 115*47540Skarels return (EBUSY); 11639335Smckusick } 11739335Smckusick vp->v_mountedhere = mp; 11841400Smckusick mp->mnt_vnodecovered = vp; 11939335Smckusick update: 12039335Smckusick /* 12139335Smckusick * Set the mount level flags. 12239335Smckusick */ 12341400Smckusick if (uap->flags & MNT_RDONLY) 12441400Smckusick mp->mnt_flag |= MNT_RDONLY; 12539335Smckusick else 12641400Smckusick mp->mnt_flag &= ~MNT_RDONLY; 12741400Smckusick if (uap->flags & MNT_NOSUID) 12841400Smckusick mp->mnt_flag |= MNT_NOSUID; 12939335Smckusick else 13041400Smckusick mp->mnt_flag &= ~MNT_NOSUID; 13141400Smckusick if (uap->flags & MNT_NOEXEC) 13241400Smckusick mp->mnt_flag |= MNT_NOEXEC; 13339335Smckusick else 13441400Smckusick mp->mnt_flag &= ~MNT_NOEXEC; 13541400Smckusick if (uap->flags & MNT_NODEV) 13641400Smckusick mp->mnt_flag |= MNT_NODEV; 13739335Smckusick else 13841400Smckusick mp->mnt_flag &= ~MNT_NODEV; 13941400Smckusick if (uap->flags & MNT_SYNCHRONOUS) 14041400Smckusick mp->mnt_flag |= MNT_SYNCHRONOUS; 14139335Smckusick else 14241400Smckusick mp->mnt_flag &= ~MNT_SYNCHRONOUS; 14339335Smckusick /* 14439335Smckusick * Mount the filesystem. 14539335Smckusick */ 14639335Smckusick error = VFS_MOUNT(mp, uap->dir, uap->data, ndp); 14741400Smckusick if (mp->mnt_flag & MNT_UPDATE) { 14841400Smckusick mp->mnt_flag &= ~MNT_UPDATE; 14939335Smckusick vrele(vp); 15040111Smckusick if (error) 15141400Smckusick mp->mnt_flag = flag; 152*47540Skarels return (error); 15339335Smckusick } 15440110Smckusick /* 15540110Smckusick * Put the new filesystem on the mount list after root. 15640110Smckusick */ 15741400Smckusick mp->mnt_next = rootfs->mnt_next; 15841400Smckusick mp->mnt_prev = rootfs; 15941400Smckusick rootfs->mnt_next = mp; 16041400Smckusick mp->mnt_next->mnt_prev = mp; 16137741Smckusick cache_purge(vp); 16237741Smckusick if (!error) { 16339335Smckusick VOP_UNLOCK(vp); 16437741Smckusick vfs_unlock(mp); 16539044Smckusick error = VFS_START(mp, 0); 16637741Smckusick } else { 16737741Smckusick vfs_remove(mp); 16837741Smckusick free((caddr_t)mp, M_MOUNT); 16939335Smckusick vput(vp); 17037741Smckusick } 171*47540Skarels return (error); 1726254Sroot } 1736254Sroot 1749167Ssam /* 17537741Smckusick * Unmount system call. 17637741Smckusick * 17737741Smckusick * Note: unmount takes a path to the vnode mounted on as argument, 17837741Smckusick * not special file (as before). 1799167Ssam */ 18042441Smckusick /* ARGSUSED */ 18142441Smckusick unmount(p, uap, retval) 18245914Smckusick struct proc *p; 18342441Smckusick register struct args { 18437741Smckusick char *pathp; 18537741Smckusick int flags; 18642441Smckusick } *uap; 18742441Smckusick int *retval; 18842441Smckusick { 18937741Smckusick register struct vnode *vp; 190*47540Skarels register struct nameidata *ndp; 19139356Smckusick struct mount *mp; 19237741Smckusick int error; 193*47540Skarels struct nameidata nd; 1946254Sroot 19537741Smckusick /* 19637741Smckusick * Must be super user 19737741Smckusick */ 198*47540Skarels if (error = suser(p->p_ucred, &p->p_acflag)) 199*47540Skarels return (error); 20037741Smckusick 201*47540Skarels ndp = &nd; 20237741Smckusick ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW; 20337741Smckusick ndp->ni_segflg = UIO_USERSPACE; 20437741Smckusick ndp->ni_dirp = uap->pathp; 205*47540Skarels if (error = namei(ndp, p)) 206*47540Skarels return (error); 20737741Smckusick vp = ndp->ni_vp; 20837741Smckusick /* 20937741Smckusick * Must be the root of the filesystem 21037741Smckusick */ 21137741Smckusick if ((vp->v_flag & VROOT) == 0) { 21237741Smckusick vput(vp); 213*47540Skarels return (EINVAL); 21437741Smckusick } 21537741Smckusick mp = vp->v_mount; 21637741Smckusick vput(vp); 217*47540Skarels return (dounmount(mp, uap->flags)); 21839356Smckusick } 21939356Smckusick 22039356Smckusick /* 22139356Smckusick * Do an unmount. 22239356Smckusick */ 22339356Smckusick dounmount(mp, flags) 22439356Smckusick register struct mount *mp; 22539356Smckusick int flags; 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 23745922Smckusick #ifdef NVM 23845738Smckusick vnode_pager_umount(mp); /* release cached vnodes */ 23945922Smckusick #else 24045922Smckusick xumount(mp); /* remove unused sticky files from text table */ 24145922Smckusick #endif 24237741Smckusick cache_purgevfs(mp); /* remove cache entries for this file sys */ 24341676Smckusick if ((error = VFS_SYNC(mp, MNT_WAIT)) == 0 || (flags & MNT_FORCE)) 24441676Smckusick error = VFS_UNMOUNT(mp, flags); 24541400Smckusick mp->mnt_flag &= ~MNT_UNMOUNT; 24641298Smckusick vfs_unbusy(mp); 24737741Smckusick if (error) { 24837741Smckusick vfs_unlock(mp); 24937741Smckusick } else { 25037741Smckusick vrele(coveredvp); 25137741Smckusick vfs_remove(mp); 25237741Smckusick free((caddr_t)mp, M_MOUNT); 25337741Smckusick } 25439356Smckusick return (error); 2556254Sroot } 2566254Sroot 2579167Ssam /* 25837741Smckusick * Sync system call. 25937741Smckusick * Sync each mounted filesystem. 2609167Ssam */ 26139491Smckusick /* ARGSUSED */ 26242441Smckusick sync(p, uap, retval) 26345914Smckusick struct proc *p; 264*47540Skarels void *uap; 26542441Smckusick int *retval; 2666254Sroot { 26737741Smckusick register struct mount *mp; 26841298Smckusick struct mount *omp; 26937741Smckusick 27037741Smckusick mp = rootfs; 27137741Smckusick do { 27240343Smckusick /* 27340343Smckusick * The lock check below is to avoid races with mount 27440343Smckusick * and unmount. 27540343Smckusick */ 27641400Smckusick if ((mp->mnt_flag & (MNT_MLOCK|MNT_RDONLY|MNT_MPBUSY)) == 0 && 27741298Smckusick !vfs_busy(mp)) { 27837741Smckusick VFS_SYNC(mp, MNT_NOWAIT); 27941298Smckusick omp = mp; 28041400Smckusick mp = mp->mnt_next; 28141298Smckusick vfs_unbusy(omp); 28241298Smckusick } else 28341400Smckusick mp = mp->mnt_next; 28437741Smckusick } while (mp != rootfs); 28537741Smckusick } 28637741Smckusick 28737741Smckusick /* 28841298Smckusick * operate on filesystem quotas 28941298Smckusick */ 29042441Smckusick /* ARGSUSED */ 29142441Smckusick quotactl(p, uap, retval) 29245914Smckusick struct proc *p; 29342441Smckusick register struct args { 29441298Smckusick char *path; 29541298Smckusick int cmd; 29641298Smckusick int uid; 29741298Smckusick caddr_t arg; 29842441Smckusick } *uap; 29942441Smckusick int *retval; 30042441Smckusick { 30141298Smckusick register struct mount *mp; 302*47540Skarels register struct nameidata *ndp; 30341298Smckusick int error; 304*47540Skarels struct nameidata nd; 30541298Smckusick 306*47540Skarels ndp = &nd; 30741298Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW; 30841298Smckusick ndp->ni_segflg = UIO_USERSPACE; 30941298Smckusick ndp->ni_dirp = uap->path; 310*47540Skarels if (error = namei(ndp, p)) 311*47540Skarels return (error); 31241298Smckusick mp = ndp->ni_vp->v_mount; 31341298Smckusick vrele(ndp->ni_vp); 314*47540Skarels return (VFS_QUOTACTL(mp, uap->cmd, uap->uid, uap->arg)); 31541298Smckusick } 31641298Smckusick 31741298Smckusick /* 31837741Smckusick * get filesystem statistics 31937741Smckusick */ 32042441Smckusick /* ARGSUSED */ 32142441Smckusick statfs(p, uap, retval) 32245914Smckusick struct proc *p; 32342441Smckusick register struct args { 32437741Smckusick char *path; 32537741Smckusick struct statfs *buf; 32642441Smckusick } *uap; 32742441Smckusick int *retval; 32842441Smckusick { 32939464Smckusick register struct mount *mp; 330*47540Skarels register struct nameidata *ndp; 33140343Smckusick register struct statfs *sp; 33237741Smckusick int error; 333*47540Skarels struct nameidata nd; 33437741Smckusick 335*47540Skarels ndp = &nd; 33639544Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW; 33737741Smckusick ndp->ni_segflg = UIO_USERSPACE; 33837741Smckusick ndp->ni_dirp = uap->path; 339*47540Skarels if (error = namei(ndp, p)) 340*47540Skarels return (error); 34139544Smckusick mp = ndp->ni_vp->v_mount; 34241400Smckusick sp = &mp->mnt_stat; 34339544Smckusick vrele(ndp->ni_vp); 34440343Smckusick if (error = VFS_STATFS(mp, sp)) 345*47540Skarels return (error); 34641400Smckusick sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 347*47540Skarels return (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp))); 34837741Smckusick } 34937741Smckusick 35042441Smckusick /* 35142441Smckusick * get filesystem statistics 35242441Smckusick */ 35342441Smckusick /* ARGSUSED */ 35442441Smckusick fstatfs(p, uap, retval) 35545914Smckusick struct proc *p; 35642441Smckusick register struct args { 35737741Smckusick int fd; 35837741Smckusick struct statfs *buf; 35942441Smckusick } *uap; 36042441Smckusick int *retval; 36142441Smckusick { 36237741Smckusick struct file *fp; 36339464Smckusick struct mount *mp; 36440343Smckusick register struct statfs *sp; 36537741Smckusick int error; 36637741Smckusick 36745914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 368*47540Skarels return (error); 36939464Smckusick mp = ((struct vnode *)fp->f_data)->v_mount; 37041400Smckusick sp = &mp->mnt_stat; 37140343Smckusick if (error = VFS_STATFS(mp, sp)) 372*47540Skarels return (error); 37341400Smckusick sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 374*47540Skarels return (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp))); 37537741Smckusick } 37637741Smckusick 37737741Smckusick /* 37838270Smckusick * get statistics on all filesystems 37938270Smckusick */ 38042441Smckusick getfsstat(p, uap, retval) 38145914Smckusick struct proc *p; 38242441Smckusick register struct args { 38338270Smckusick struct statfs *buf; 38438270Smckusick long bufsize; 38540343Smckusick int flags; 38642441Smckusick } *uap; 38742441Smckusick int *retval; 38842441Smckusick { 38938270Smckusick register struct mount *mp; 39040343Smckusick register struct statfs *sp; 39139606Smckusick caddr_t sfsp; 39238270Smckusick long count, maxcount, error; 39338270Smckusick 39438270Smckusick maxcount = uap->bufsize / sizeof(struct statfs); 39539606Smckusick sfsp = (caddr_t)uap->buf; 39638270Smckusick mp = rootfs; 39738270Smckusick count = 0; 39838270Smckusick do { 39941400Smckusick if (sfsp && count < maxcount && 40041400Smckusick ((mp->mnt_flag & MNT_MLOCK) == 0)) { 40141400Smckusick sp = &mp->mnt_stat; 40240343Smckusick /* 40340343Smckusick * If MNT_NOWAIT is specified, do not refresh the 40440343Smckusick * fsstat cache. MNT_WAIT overrides MNT_NOWAIT. 40540343Smckusick */ 40640343Smckusick if (((uap->flags & MNT_NOWAIT) == 0 || 40740343Smckusick (uap->flags & MNT_WAIT)) && 40840343Smckusick (error = VFS_STATFS(mp, sp))) { 40941400Smckusick mp = mp->mnt_prev; 41039607Smckusick continue; 41139607Smckusick } 41241400Smckusick sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 41340343Smckusick if (error = copyout((caddr_t)sp, sfsp, sizeof(*sp))) 414*47540Skarels return (error); 41540343Smckusick sfsp += sizeof(*sp); 41638270Smckusick } 41739606Smckusick count++; 41841400Smckusick mp = mp->mnt_prev; 41938270Smckusick } while (mp != rootfs); 42038270Smckusick if (sfsp && count > maxcount) 42142441Smckusick *retval = maxcount; 42238270Smckusick else 42342441Smckusick *retval = count; 424*47540Skarels return (0); 42538270Smckusick } 42638270Smckusick 42738270Smckusick /* 42838259Smckusick * Change current working directory to a given file descriptor. 42938259Smckusick */ 43042441Smckusick /* ARGSUSED */ 43142441Smckusick fchdir(p, uap, retval) 43245914Smckusick struct proc *p; 43342441Smckusick struct args { 43442441Smckusick int fd; 43542441Smckusick } *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)) 444*47540Skarels return (error); 44538259Smckusick vp = (struct vnode *)fp->f_data; 44638259Smckusick VOP_LOCK(vp); 44738259Smckusick if (vp->v_type != VDIR) 44838259Smckusick error = ENOTDIR; 44938259Smckusick else 450*47540Skarels error = VOP_ACCESS(vp, VEXEC, p->p_ucred); 45138259Smckusick VOP_UNLOCK(vp); 45239860Smckusick if (error) 453*47540Skarels return (error); 45439860Smckusick VREF(vp); 45545914Smckusick vrele(fdp->fd_cdir); 45645914Smckusick fdp->fd_cdir = vp; 457*47540Skarels return (0); 45838259Smckusick } 45938259Smckusick 46038259Smckusick /* 46137741Smckusick * Change current working directory (``.''). 46237741Smckusick */ 46342441Smckusick /* ARGSUSED */ 46442441Smckusick chdir(p, uap, retval) 46545914Smckusick struct proc *p; 46642441Smckusick struct args { 46742441Smckusick char *fname; 46842441Smckusick } *uap; 46942441Smckusick int *retval; 47037741Smckusick { 471*47540Skarels register struct nameidata *ndp; 47245914Smckusick register struct filedesc *fdp = p->p_fd; 47337741Smckusick int error; 474*47540Skarels struct nameidata nd; 4756254Sroot 476*47540Skarels ndp = &nd; 47737741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 47816694Smckusick ndp->ni_segflg = UIO_USERSPACE; 47916694Smckusick ndp->ni_dirp = uap->fname; 480*47540Skarels if (error = chdirec(ndp, p)) 481*47540Skarels return (error); 48245914Smckusick vrele(fdp->fd_cdir); 48345914Smckusick fdp->fd_cdir = ndp->ni_vp; 484*47540Skarels return (0); 48537741Smckusick } 4866254Sroot 48737741Smckusick /* 48837741Smckusick * Change notion of root (``/'') directory. 48937741Smckusick */ 49042441Smckusick /* ARGSUSED */ 49142441Smckusick chroot(p, uap, retval) 49245914Smckusick struct proc *p; 49342441Smckusick struct args { 49442441Smckusick char *fname; 49542441Smckusick } *uap; 49642441Smckusick int *retval; 49737741Smckusick { 498*47540Skarels register struct nameidata *ndp; 49945914Smckusick register struct filedesc *fdp = p->p_fd; 50037741Smckusick int error; 501*47540Skarels struct nameidata nd; 50237741Smckusick 503*47540Skarels if (error = suser(p->p_ucred, &p->p_acflag)) 504*47540Skarels return (error); 505*47540Skarels ndp = &nd; 50637741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 50737741Smckusick ndp->ni_segflg = UIO_USERSPACE; 50837741Smckusick ndp->ni_dirp = uap->fname; 509*47540Skarels if (error = chdirec(ndp, p)) 510*47540Skarels return (error); 51145914Smckusick if (fdp->fd_rdir != NULL) 51245914Smckusick vrele(fdp->fd_rdir); 51345914Smckusick fdp->fd_rdir = ndp->ni_vp; 514*47540Skarels return (0); 5156254Sroot } 5166254Sroot 51737Sbill /* 51837741Smckusick * Common routine for chroot and chdir. 51937741Smckusick */ 520*47540Skarels chdirec(ndp, p) 521*47540Skarels struct nameidata *ndp; 522*47540Skarels struct proc *p; 52337741Smckusick { 52437741Smckusick struct vnode *vp; 52537741Smckusick int error; 52637741Smckusick 527*47540Skarels if (error = namei(ndp, p)) 52837741Smckusick return (error); 52937741Smckusick vp = ndp->ni_vp; 53037741Smckusick if (vp->v_type != VDIR) 53137741Smckusick error = ENOTDIR; 53237741Smckusick else 533*47540Skarels error = VOP_ACCESS(vp, VEXEC, p->p_ucred); 53437741Smckusick VOP_UNLOCK(vp); 53537741Smckusick if (error) 53637741Smckusick vrele(vp); 53737741Smckusick return (error); 53837741Smckusick } 53937741Smckusick 54037741Smckusick /* 5416254Sroot * Open system call. 54242441Smckusick * Check permissions, allocate an open file structure, 54342441Smckusick * and call the device open routine if any. 5446254Sroot */ 54542441Smckusick open(p, uap, retval) 54645914Smckusick struct proc *p; 54742441Smckusick register struct args { 5486254Sroot char *fname; 5497701Ssam int mode; 55012756Ssam int crtmode; 55142441Smckusick } *uap; 55242441Smckusick int *retval; 5536254Sroot { 554*47540Skarels struct nameidata *ndp; 55545914Smckusick register struct filedesc *fdp = p->p_fd; 55642441Smckusick register struct file *fp; 55737741Smckusick int fmode, cmode; 55837741Smckusick struct file *nfp; 55937741Smckusick int indx, error; 560*47540Skarels struct nameidata nd; 56137741Smckusick extern struct fileops vnops; 5626254Sroot 56345914Smckusick if (error = falloc(p, &nfp, &indx)) 564*47540Skarels return (error); 56537741Smckusick fp = nfp; 56646553Skarels fmode = FFLAGS(uap->mode); 56745914Smckusick cmode = ((uap->crtmode &~ fdp->fd_cmask) & 07777) &~ S_ISVTX; 568*47540Skarels ndp = &nd; 56942441Smckusick ndp->ni_segflg = UIO_USERSPACE; 57042441Smckusick ndp->ni_dirp = uap->fname; 57145202Smckusick p->p_dupfd = -indx - 1; /* XXX check for fdopen */ 572*47540Skarels if (error = vn_open(ndp, p, fmode, cmode)) { 57337741Smckusick crfree(fp->f_cred); 57437741Smckusick fp->f_count--; 57543405Smckusick if (error == ENODEV && /* XXX from fdopen */ 57645202Smckusick p->p_dupfd >= 0 && 57745914Smckusick (error = dupfdopen(fdp, indx, p->p_dupfd, fmode)) == 0) { 57842441Smckusick *retval = indx; 579*47540Skarels return (0); 58042441Smckusick } 58140884Smckusick if (error == ERESTART) 58240884Smckusick error = EINTR; 58345914Smckusick OFILE(fdp, indx) = NULL; 584*47540Skarels return (error); 58512756Ssam } 58637741Smckusick fp->f_flag = fmode & FMASK; 58737741Smckusick fp->f_type = DTYPE_VNODE; 58837741Smckusick fp->f_ops = &vnops; 58937741Smckusick fp->f_data = (caddr_t)ndp->ni_vp; 59042441Smckusick *retval = indx; 591*47540Skarels return (0); 5926254Sroot } 5936254Sroot 59442955Smckusick #ifdef COMPAT_43 5956254Sroot /* 59642441Smckusick * Creat system call. 5976254Sroot */ 59842955Smckusick ocreat(p, uap, retval) 59942441Smckusick struct proc *p; 60042441Smckusick register struct args { 60142441Smckusick char *fname; 60242441Smckusick int fmode; 60342441Smckusick } *uap; 60442441Smckusick int *retval; 6056254Sroot { 60642441Smckusick struct args { 6076254Sroot char *fname; 60842441Smckusick int mode; 60942441Smckusick int crtmode; 61042441Smckusick } openuap; 61142441Smckusick 61242441Smckusick openuap.fname = uap->fname; 61342441Smckusick openuap.crtmode = uap->fmode; 61442441Smckusick openuap.mode = O_WRONLY | O_CREAT | O_TRUNC; 615*47540Skarels return (open(p, &openuap, retval)); 61642441Smckusick } 61742955Smckusick #endif /* COMPAT_43 */ 61842441Smckusick 61942441Smckusick /* 62042441Smckusick * Mknod system call 62142441Smckusick */ 62242441Smckusick /* ARGSUSED */ 62342441Smckusick mknod(p, uap, retval) 62445914Smckusick struct proc *p; 62542441Smckusick register struct args { 62642441Smckusick char *fname; 6276254Sroot int fmode; 6286254Sroot int dev; 62942441Smckusick } *uap; 63042441Smckusick int *retval; 63142441Smckusick { 632*47540Skarels register struct nameidata *ndp; 63337741Smckusick register struct vnode *vp; 63437741Smckusick struct vattr vattr; 63537741Smckusick int error; 636*47540Skarels struct nameidata nd; 6376254Sroot 638*47540Skarels if (error = suser(p->p_ucred, &p->p_acflag)) 639*47540Skarels return (error); 640*47540Skarels ndp = &nd; 64137741Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 64216694Smckusick ndp->ni_segflg = UIO_USERSPACE; 64316694Smckusick ndp->ni_dirp = uap->fname; 644*47540Skarels if (error = namei(ndp, p)) 645*47540Skarels return (error); 64637741Smckusick vp = ndp->ni_vp; 64737741Smckusick if (vp != NULL) { 64837741Smckusick error = EEXIST; 64912756Ssam goto out; 6506254Sroot } 65141362Smckusick VATTR_NULL(&vattr); 65240635Smckusick switch (uap->fmode & S_IFMT) { 65312756Ssam 65440635Smckusick case S_IFMT: /* used by badsect to flag bad sectors */ 65537741Smckusick vattr.va_type = VBAD; 65637741Smckusick break; 65740635Smckusick case S_IFCHR: 65837741Smckusick vattr.va_type = VCHR; 65937741Smckusick break; 66040635Smckusick case S_IFBLK: 66137741Smckusick vattr.va_type = VBLK; 66237741Smckusick break; 66337741Smckusick default: 66437741Smckusick error = EINVAL; 66537741Smckusick goto out; 6666254Sroot } 66745914Smckusick vattr.va_mode = (uap->fmode & 07777) &~ p->p_fd->fd_cmask; 66837741Smckusick vattr.va_rdev = uap->dev; 6696254Sroot out: 67042465Smckusick if (!error) { 671*47540Skarels error = VOP_MKNOD(ndp, &vattr, p->p_ucred); 67242465Smckusick } else { 67337741Smckusick VOP_ABORTOP(ndp); 67443344Smckusick if (ndp->ni_dvp == vp) 67543344Smckusick vrele(ndp->ni_dvp); 67643344Smckusick else 67743344Smckusick vput(ndp->ni_dvp); 67842465Smckusick if (vp) 67942465Smckusick vrele(vp); 68042465Smckusick } 681*47540Skarels return (error); 6826254Sroot } 6836254Sroot 6846254Sroot /* 68540285Smckusick * Mkfifo system call 68640285Smckusick */ 68742441Smckusick /* ARGSUSED */ 68842441Smckusick mkfifo(p, uap, retval) 68945914Smckusick struct proc *p; 69042441Smckusick register struct args { 69140285Smckusick char *fname; 69240285Smckusick int fmode; 69342441Smckusick } *uap; 69442441Smckusick int *retval; 69542441Smckusick { 696*47540Skarels register struct nameidata *ndp; 69740285Smckusick struct vattr vattr; 69840285Smckusick int error; 699*47540Skarels struct nameidata nd; 70040285Smckusick 70140285Smckusick #ifndef FIFO 702*47540Skarels return (EOPNOTSUPP); 70340285Smckusick #else 704*47540Skarels ndp = &nd; 70540285Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 70640285Smckusick ndp->ni_segflg = UIO_USERSPACE; 70740285Smckusick ndp->ni_dirp = uap->fname; 708*47540Skarels if (error = namei(ndp, p)) 709*47540Skarels return (error); 71040285Smckusick if (ndp->ni_vp != NULL) { 71140285Smckusick VOP_ABORTOP(ndp); 71243344Smckusick if (ndp->ni_dvp == ndp->ni_vp) 71343344Smckusick vrele(ndp->ni_dvp); 71443344Smckusick else 71543344Smckusick vput(ndp->ni_dvp); 71642465Smckusick vrele(ndp->ni_vp); 717*47540Skarels return (EEXIST); 71840285Smckusick } 71945785Sbostic VATTR_NULL(&vattr); 72045785Sbostic vattr.va_type = VFIFO; 72145914Smckusick vattr.va_mode = (uap->fmode & 07777) &~ p->p_fd->fd_cmask; 722*47540Skarels return (VOP_MKNOD(ndp, &vattr, p->p_ucred)); 72340285Smckusick #endif /* FIFO */ 72440285Smckusick } 72540285Smckusick 72640285Smckusick /* 7276254Sroot * link system call 7286254Sroot */ 72942441Smckusick /* ARGSUSED */ 73042441Smckusick link(p, uap, retval) 73145914Smckusick struct proc *p; 73242441Smckusick register struct args { 7336254Sroot char *target; 7346254Sroot char *linkname; 73542441Smckusick } *uap; 73642441Smckusick int *retval; 73742441Smckusick { 738*47540Skarels register struct nameidata *ndp; 73937741Smckusick register struct vnode *vp, *xp; 74037741Smckusick int error; 741*47540Skarels struct nameidata nd; 7426254Sroot 743*47540Skarels ndp = &nd; 74416694Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW; 74516694Smckusick ndp->ni_segflg = UIO_USERSPACE; 74616694Smckusick ndp->ni_dirp = uap->target; 747*47540Skarels if (error = namei(ndp, p)) 748*47540Skarels return (error); 74937741Smckusick vp = ndp->ni_vp; 75037741Smckusick if (vp->v_type == VDIR && 751*47540Skarels (error = suser(p->p_ucred, &p->p_acflag))) 75237741Smckusick goto out1; 75337741Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 75416694Smckusick ndp->ni_dirp = (caddr_t)uap->linkname; 755*47540Skarels if (error = namei(ndp, p)) 75637741Smckusick goto out1; 75737741Smckusick xp = ndp->ni_vp; 7586254Sroot if (xp != NULL) { 75937741Smckusick error = EEXIST; 7606254Sroot goto out; 7616254Sroot } 76237741Smckusick xp = ndp->ni_dvp; 76337741Smckusick if (vp->v_mount != xp->v_mount) 76437741Smckusick error = EXDEV; 7656254Sroot out: 76642465Smckusick if (!error) { 76742465Smckusick error = VOP_LINK(vp, ndp); 76842465Smckusick } else { 76937741Smckusick VOP_ABORTOP(ndp); 77043344Smckusick if (ndp->ni_dvp == ndp->ni_vp) 77143344Smckusick vrele(ndp->ni_dvp); 77243344Smckusick else 77343344Smckusick vput(ndp->ni_dvp); 77442465Smckusick if (ndp->ni_vp) 77542465Smckusick vrele(ndp->ni_vp); 77642465Smckusick } 77737741Smckusick out1: 77837741Smckusick vrele(vp); 779*47540Skarels return (error); 7806254Sroot } 7816254Sroot 7826254Sroot /* 7836254Sroot * symlink -- make a symbolic link 7846254Sroot */ 78542441Smckusick /* ARGSUSED */ 78642441Smckusick symlink(p, uap, retval) 78745914Smckusick struct proc *p; 78842441Smckusick register struct args { 7896254Sroot char *target; 7906254Sroot char *linkname; 79142441Smckusick } *uap; 79242441Smckusick int *retval; 79342441Smckusick { 794*47540Skarels register struct nameidata *ndp; 79537741Smckusick struct vattr vattr; 79637741Smckusick char *target; 79737741Smckusick int error; 798*47540Skarels struct nameidata nd; 7996254Sroot 800*47540Skarels ndp = &nd; 80116694Smckusick ndp->ni_segflg = UIO_USERSPACE; 80216694Smckusick ndp->ni_dirp = uap->linkname; 80337741Smckusick MALLOC(target, char *, MAXPATHLEN, M_NAMEI, M_WAITOK); 80437741Smckusick if (error = copyinstr(uap->target, target, MAXPATHLEN, (u_int *)0)) 80542465Smckusick goto out; 80637741Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 807*47540Skarels if (error = namei(ndp, p)) 80842465Smckusick goto out; 80942465Smckusick if (ndp->ni_vp) { 81042465Smckusick VOP_ABORTOP(ndp); 81143344Smckusick if (ndp->ni_dvp == ndp->ni_vp) 81243344Smckusick vrele(ndp->ni_dvp); 81343344Smckusick else 81443344Smckusick vput(ndp->ni_dvp); 81542465Smckusick vrele(ndp->ni_vp); 81637741Smckusick error = EEXIST; 81737741Smckusick goto out; 8186254Sroot } 81941362Smckusick VATTR_NULL(&vattr); 82045914Smckusick vattr.va_mode = 0777 &~ p->p_fd->fd_cmask; 82142465Smckusick error = VOP_SYMLINK(ndp, &vattr, target); 82237741Smckusick out: 82337741Smckusick FREE(target, M_NAMEI); 824*47540Skarels return (error); 8256254Sroot } 8266254Sroot 8276254Sroot /* 8286254Sroot * Unlink system call. 8296254Sroot * Hard to avoid races here, especially 8306254Sroot * in unlinking directories. 8316254Sroot */ 83242441Smckusick /* ARGSUSED */ 83342441Smckusick unlink(p, uap, retval) 83445914Smckusick struct proc *p; 83542441Smckusick struct args { 83642441Smckusick char *fname; 83742441Smckusick } *uap; 83842441Smckusick int *retval; 8396254Sroot { 840*47540Skarels register struct nameidata *ndp; 84137741Smckusick register struct vnode *vp; 84237741Smckusick int error; 843*47540Skarels struct nameidata nd; 8446254Sroot 845*47540Skarels ndp = &nd; 84637741Smckusick ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF; 84716694Smckusick ndp->ni_segflg = UIO_USERSPACE; 84816694Smckusick ndp->ni_dirp = uap->fname; 849*47540Skarels if (error = namei(ndp, p)) 850*47540Skarels return (error); 85137741Smckusick vp = ndp->ni_vp; 85237741Smckusick if (vp->v_type == VDIR && 853*47540Skarels (error = suser(p->p_ucred, &p->p_acflag))) 8546254Sroot goto out; 8556254Sroot /* 8566254Sroot * Don't unlink a mounted file. 8576254Sroot */ 85837741Smckusick if (vp->v_flag & VROOT) { 85937741Smckusick error = EBUSY; 8606254Sroot goto out; 8616254Sroot } 86245922Smckusick #ifdef NVM 86345738Smckusick (void) vnode_pager_uncache(vp); 86445922Smckusick #else 86545922Smckusick if (vp->v_flag & VTEXT) 86645922Smckusick xrele(vp); /* try once to free text */ 86745922Smckusick #endif 8686254Sroot out: 86942465Smckusick if (!error) { 87042465Smckusick error = VOP_REMOVE(ndp); 87142465Smckusick } else { 87237741Smckusick VOP_ABORTOP(ndp); 87343344Smckusick if (ndp->ni_dvp == vp) 87443344Smckusick vrele(ndp->ni_dvp); 87543344Smckusick else 87643344Smckusick vput(ndp->ni_dvp); 87742465Smckusick vput(vp); 87842465Smckusick } 879*47540Skarels return (error); 8806254Sroot } 8816254Sroot 8826254Sroot /* 8836254Sroot * Seek system call 8846254Sroot */ 88542441Smckusick lseek(p, uap, retval) 88645914Smckusick struct proc *p; 88742441Smckusick register struct args { 88837741Smckusick int fdes; 8896254Sroot off_t off; 8906254Sroot int sbase; 89142441Smckusick } *uap; 89242441Smckusick off_t *retval; 89342441Smckusick { 894*47540Skarels struct ucred *cred = p->p_ucred; 89545914Smckusick register struct filedesc *fdp = p->p_fd; 89642441Smckusick register struct file *fp; 89737741Smckusick struct vattr vattr; 89837741Smckusick int error; 8996254Sroot 900*47540Skarels if ((unsigned)uap->fdes >= fdp->fd_nfiles || 90145914Smckusick (fp = OFILE(fdp, uap->fdes)) == NULL) 902*47540Skarels return (EBADF); 90337741Smckusick if (fp->f_type != DTYPE_VNODE) 904*47540Skarels return (ESPIPE); 90513878Ssam switch (uap->sbase) { 90613878Ssam 90713878Ssam case L_INCR: 90813878Ssam fp->f_offset += uap->off; 90913878Ssam break; 91013878Ssam 91113878Ssam case L_XTND: 91237741Smckusick if (error = VOP_GETATTR((struct vnode *)fp->f_data, 91342441Smckusick &vattr, cred)) 914*47540Skarels return (error); 91537741Smckusick fp->f_offset = uap->off + vattr.va_size; 91613878Ssam break; 91713878Ssam 91813878Ssam case L_SET: 91913878Ssam fp->f_offset = uap->off; 92013878Ssam break; 92113878Ssam 92213878Ssam default: 923*47540Skarels return (EINVAL); 92413878Ssam } 92542441Smckusick *retval = fp->f_offset; 926*47540Skarels return (0); 9276254Sroot } 9286254Sroot 9296254Sroot /* 9306254Sroot * Access system call 9316254Sroot */ 93242441Smckusick /* ARGSUSED */ 93342441Smckusick saccess(p, uap, retval) 93445914Smckusick struct proc *p; 93542441Smckusick register struct args { 9366254Sroot char *fname; 9376254Sroot int fmode; 93842441Smckusick } *uap; 93942441Smckusick int *retval; 94042441Smckusick { 941*47540Skarels register struct nameidata *ndp; 942*47540Skarels register struct ucred *cred = p->p_ucred; 94337741Smckusick register struct vnode *vp; 94437741Smckusick int error, mode, svuid, svgid; 945*47540Skarels struct nameidata nd; 9466254Sroot 947*47540Skarels ndp = &nd; 94842441Smckusick svuid = cred->cr_uid; 94942441Smckusick svgid = cred->cr_groups[0]; 950*47540Skarels cred->cr_uid = p->p_cred->p_ruid; 951*47540Skarels cred->cr_groups[0] = p->p_cred->p_rgid; 95237741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 95316694Smckusick ndp->ni_segflg = UIO_USERSPACE; 95416694Smckusick ndp->ni_dirp = uap->fname; 955*47540Skarels if (error = namei(ndp, p)) 95637741Smckusick goto out1; 95737741Smckusick vp = ndp->ni_vp; 95837741Smckusick /* 95937741Smckusick * fmode == 0 means only check for exist 96037741Smckusick */ 96137741Smckusick if (uap->fmode) { 96237741Smckusick mode = 0; 96337741Smckusick if (uap->fmode & R_OK) 96437741Smckusick mode |= VREAD; 96537741Smckusick if (uap->fmode & W_OK) 96637741Smckusick mode |= VWRITE; 96737741Smckusick if (uap->fmode & X_OK) 96837741Smckusick mode |= VEXEC; 96939543Smckusick if ((mode & VWRITE) == 0 || (error = vn_writechk(vp)) == 0) 970*47540Skarels error = VOP_ACCESS(vp, mode, cred); 9716254Sroot } 97237741Smckusick vput(vp); 97337741Smckusick out1: 97442441Smckusick cred->cr_uid = svuid; 97542441Smckusick cred->cr_groups[0] = svgid; 976*47540Skarels return (error); 9776254Sroot } 9786254Sroot 9796254Sroot /* 9806574Smckusic * Stat system call. This version follows links. 98137Sbill */ 98242441Smckusick /* ARGSUSED */ 98342441Smckusick stat(p, uap, retval) 98445914Smckusick struct proc *p; 98542441Smckusick register struct args { 98642441Smckusick char *fname; 98742441Smckusick struct stat *ub; 98842441Smckusick } *uap; 98942441Smckusick int *retval; 99037Sbill { 991*47540Skarels register struct nameidata *ndp; 99242441Smckusick struct stat sb; 99342441Smckusick int error; 994*47540Skarels struct nameidata nd; 99537Sbill 996*47540Skarels ndp = &nd; 99742441Smckusick ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW; 99842441Smckusick ndp->ni_segflg = UIO_USERSPACE; 99942441Smckusick ndp->ni_dirp = uap->fname; 1000*47540Skarels if (error = namei(ndp, p)) 1001*47540Skarels return (error); 100242441Smckusick error = vn_stat(ndp->ni_vp, &sb); 100342441Smckusick vput(ndp->ni_vp); 100442441Smckusick if (error) 1005*47540Skarels return (error); 100642441Smckusick error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb)); 1007*47540Skarels return (error); 100837Sbill } 100937Sbill 101037Sbill /* 10116574Smckusic * Lstat system call. This version does not follow links. 10125992Swnj */ 101342441Smckusick /* ARGSUSED */ 101442441Smckusick lstat(p, uap, retval) 101545914Smckusick struct proc *p; 101642441Smckusick register struct args { 10175992Swnj char *fname; 101812756Ssam struct stat *ub; 101942441Smckusick } *uap; 102042441Smckusick int *retval; 102142441Smckusick { 1022*47540Skarels register struct nameidata *ndp; 102312756Ssam struct stat sb; 102437741Smckusick int error; 1025*47540Skarels struct nameidata nd; 10265992Swnj 1027*47540Skarels ndp = &nd; 102842441Smckusick ndp->ni_nameiop = LOOKUP | LOCKLEAF | NOFOLLOW; 102916694Smckusick ndp->ni_segflg = UIO_USERSPACE; 103016694Smckusick ndp->ni_dirp = uap->fname; 1031*47540Skarels if (error = namei(ndp, p)) 1032*47540Skarels return (error); 103337741Smckusick error = vn_stat(ndp->ni_vp, &sb); 103437741Smckusick vput(ndp->ni_vp); 103537741Smckusick if (error) 1036*47540Skarels return (error); 103737741Smckusick error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb)); 1038*47540Skarels return (error); 10395992Swnj } 10405992Swnj 10415992Swnj /* 10425992Swnj * Return target name of a symbolic link 104337Sbill */ 104442441Smckusick /* ARGSUSED */ 104542441Smckusick readlink(p, uap, retval) 104645914Smckusick struct proc *p; 104742441Smckusick register struct args { 10485992Swnj char *name; 10495992Swnj char *buf; 10505992Swnj int count; 105142441Smckusick } *uap; 105242441Smckusick int *retval; 105342441Smckusick { 1054*47540Skarels register struct nameidata *ndp; 105537741Smckusick register struct vnode *vp; 105637741Smckusick struct iovec aiov; 105737741Smckusick struct uio auio; 105837741Smckusick int error; 1059*47540Skarels struct nameidata nd; 10605992Swnj 1061*47540Skarels ndp = &nd; 106237741Smckusick ndp->ni_nameiop = LOOKUP | LOCKLEAF; 106316694Smckusick ndp->ni_segflg = UIO_USERSPACE; 106416694Smckusick ndp->ni_dirp = uap->name; 1065*47540Skarels if (error = namei(ndp, p)) 1066*47540Skarels return (error); 106737741Smckusick vp = ndp->ni_vp; 106837741Smckusick if (vp->v_type != VLNK) { 106937741Smckusick error = EINVAL; 10705992Swnj goto out; 10715992Swnj } 107237741Smckusick aiov.iov_base = uap->buf; 107337741Smckusick aiov.iov_len = uap->count; 107437741Smckusick auio.uio_iov = &aiov; 107537741Smckusick auio.uio_iovcnt = 1; 107637741Smckusick auio.uio_offset = 0; 107737741Smckusick auio.uio_rw = UIO_READ; 107837741Smckusick auio.uio_segflg = UIO_USERSPACE; 107937741Smckusick auio.uio_resid = uap->count; 1080*47540Skarels error = VOP_READLINK(vp, &auio, p->p_ucred); 10815992Swnj out: 108237741Smckusick vput(vp); 108342441Smckusick *retval = uap->count - auio.uio_resid; 1084*47540Skarels return (error); 10855992Swnj } 10865992Swnj 10879167Ssam /* 108838259Smckusick * Change flags of a file given path name. 108938259Smckusick */ 109042441Smckusick /* ARGSUSED */ 109142441Smckusick chflags(p, uap, retval) 109245914Smckusick struct proc *p; 109342441Smckusick register struct args { 109438259Smckusick char *fname; 109538259Smckusick int flags; 109642441Smckusick } *uap; 109742441Smckusick int *retval; 109842441Smckusick { 1099*47540Skarels register struct nameidata *ndp; 110038259Smckusick register struct vnode *vp; 110138259Smckusick struct vattr vattr; 110238259Smckusick int error; 1103*47540Skarels struct nameidata nd; 110438259Smckusick 1105*47540Skarels ndp = &nd; 110638259Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 110738259Smckusick ndp->ni_segflg = UIO_USERSPACE; 110838259Smckusick ndp->ni_dirp = uap->fname; 1109*47540Skarels if (error = namei(ndp, p)) 1110*47540Skarels return (error); 111138259Smckusick vp = ndp->ni_vp; 111241400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 111338259Smckusick error = EROFS; 111438259Smckusick goto out; 111538259Smckusick } 111645785Sbostic VATTR_NULL(&vattr); 111745785Sbostic vattr.va_flags = uap->flags; 1118*47540Skarels error = VOP_SETATTR(vp, &vattr, p->p_ucred); 111938259Smckusick out: 112038259Smckusick vput(vp); 1121*47540Skarels return (error); 112238259Smckusick } 112338259Smckusick 112438259Smckusick /* 112538259Smckusick * Change flags of a file given a file descriptor. 112638259Smckusick */ 112742441Smckusick /* ARGSUSED */ 112842441Smckusick fchflags(p, uap, retval) 112945914Smckusick struct proc *p; 113042441Smckusick register struct args { 113138259Smckusick int fd; 113238259Smckusick int flags; 113342441Smckusick } *uap; 113442441Smckusick int *retval; 113542441Smckusick { 113638259Smckusick struct vattr vattr; 113738259Smckusick struct vnode *vp; 113838259Smckusick struct file *fp; 113938259Smckusick int error; 114038259Smckusick 114145914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 1142*47540Skarels return (error); 114338259Smckusick vp = (struct vnode *)fp->f_data; 114438259Smckusick VOP_LOCK(vp); 114541400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 114638259Smckusick error = EROFS; 114738259Smckusick goto out; 114838259Smckusick } 114945785Sbostic VATTR_NULL(&vattr); 115045785Sbostic vattr.va_flags = uap->flags; 1151*47540Skarels error = VOP_SETATTR(vp, &vattr, p->p_ucred); 115238259Smckusick out: 115338259Smckusick VOP_UNLOCK(vp); 1154*47540Skarels return (error); 115538259Smckusick } 115638259Smckusick 115738259Smckusick /* 11589167Ssam * Change mode of a file given path name. 11599167Ssam */ 116042441Smckusick /* ARGSUSED */ 116142441Smckusick chmod(p, uap, retval) 116245914Smckusick struct proc *p; 116342441Smckusick register struct args { 11646254Sroot char *fname; 11656254Sroot int fmode; 116642441Smckusick } *uap; 116742441Smckusick int *retval; 116842441Smckusick { 1169*47540Skarels register struct nameidata *ndp; 117037741Smckusick register struct vnode *vp; 117137741Smckusick struct vattr vattr; 117237741Smckusick int error; 1173*47540Skarels struct nameidata nd; 11745992Swnj 1175*47540Skarels ndp = &nd; 117637741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 117737741Smckusick ndp->ni_segflg = UIO_USERSPACE; 117837741Smckusick ndp->ni_dirp = uap->fname; 1179*47540Skarels if (error = namei(ndp, p)) 1180*47540Skarels return (error); 118137741Smckusick vp = ndp->ni_vp; 118241400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 118337741Smckusick error = EROFS; 118437741Smckusick goto out; 118537741Smckusick } 118645785Sbostic VATTR_NULL(&vattr); 118745785Sbostic vattr.va_mode = uap->fmode & 07777; 1188*47540Skarels error = VOP_SETATTR(vp, &vattr, p->p_ucred); 118937741Smckusick out: 119037741Smckusick vput(vp); 1191*47540Skarels return (error); 11927701Ssam } 11937439Sroot 11949167Ssam /* 11959167Ssam * Change mode of a file given a file descriptor. 11969167Ssam */ 119742441Smckusick /* ARGSUSED */ 119842441Smckusick fchmod(p, uap, retval) 119945914Smckusick struct proc *p; 120042441Smckusick register struct args { 12017701Ssam int fd; 12027701Ssam int fmode; 120342441Smckusick } *uap; 120442441Smckusick int *retval; 120542441Smckusick { 120637741Smckusick struct vattr vattr; 120737741Smckusick struct vnode *vp; 120837741Smckusick struct file *fp; 120937741Smckusick int error; 12107701Ssam 121145914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 1212*47540Skarels return (error); 121337741Smckusick vp = (struct vnode *)fp->f_data; 121437741Smckusick VOP_LOCK(vp); 121541400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 121637741Smckusick error = EROFS; 121737741Smckusick goto out; 12187439Sroot } 121945785Sbostic VATTR_NULL(&vattr); 122045785Sbostic vattr.va_mode = uap->fmode & 07777; 1221*47540Skarels error = VOP_SETATTR(vp, &vattr, p->p_ucred); 122237741Smckusick out: 122337741Smckusick VOP_UNLOCK(vp); 1224*47540Skarels return (error); 12255992Swnj } 12265992Swnj 12279167Ssam /* 12289167Ssam * Set ownership given a path name. 12299167Ssam */ 123042441Smckusick /* ARGSUSED */ 123142441Smckusick chown(p, uap, retval) 123245914Smckusick struct proc *p; 123342441Smckusick register struct args { 12346254Sroot char *fname; 12356254Sroot int uid; 12366254Sroot int gid; 123742441Smckusick } *uap; 123842441Smckusick int *retval; 123942441Smckusick { 1240*47540Skarels register struct nameidata *ndp; 124137741Smckusick register struct vnode *vp; 124237741Smckusick struct vattr vattr; 124337741Smckusick int error; 1244*47540Skarels struct nameidata nd; 124537Sbill 1246*47540Skarels ndp = &nd; 124737741Smckusick ndp->ni_nameiop = LOOKUP | NOFOLLOW | LOCKLEAF; 124836614Sbostic ndp->ni_segflg = UIO_USERSPACE; 124936614Sbostic ndp->ni_dirp = uap->fname; 1250*47540Skarels if (error = namei(ndp, p)) 1251*47540Skarels return (error); 125237741Smckusick vp = ndp->ni_vp; 125341400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 125437741Smckusick error = EROFS; 125537741Smckusick goto out; 125637741Smckusick } 125745785Sbostic VATTR_NULL(&vattr); 125845785Sbostic vattr.va_uid = uap->uid; 125945785Sbostic vattr.va_gid = uap->gid; 1260*47540Skarels error = VOP_SETATTR(vp, &vattr, p->p_ucred); 126137741Smckusick out: 126237741Smckusick vput(vp); 1263*47540Skarels return (error); 12647701Ssam } 12657439Sroot 12669167Ssam /* 12679167Ssam * Set ownership given a file descriptor. 12689167Ssam */ 126942441Smckusick /* ARGSUSED */ 127042441Smckusick fchown(p, uap, retval) 127145914Smckusick struct proc *p; 127242441Smckusick register struct args { 12737701Ssam int fd; 12747701Ssam int uid; 12757701Ssam int gid; 127642441Smckusick } *uap; 127742441Smckusick int *retval; 127842441Smckusick { 127937741Smckusick struct vattr vattr; 128037741Smckusick struct vnode *vp; 128137741Smckusick struct file *fp; 128237741Smckusick int error; 12837701Ssam 128445914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 1285*47540Skarels return (error); 128637741Smckusick vp = (struct vnode *)fp->f_data; 128737741Smckusick VOP_LOCK(vp); 128841400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 128937741Smckusick error = EROFS; 129037741Smckusick goto out; 129137741Smckusick } 129245785Sbostic VATTR_NULL(&vattr); 129345785Sbostic vattr.va_uid = uap->uid; 129445785Sbostic vattr.va_gid = uap->gid; 1295*47540Skarels error = VOP_SETATTR(vp, &vattr, p->p_ucred); 129637741Smckusick out: 129737741Smckusick VOP_UNLOCK(vp); 1298*47540Skarels return (error); 12997701Ssam } 13007701Ssam 130142441Smckusick /* 130242441Smckusick * Set the access and modification times of a file. 130342441Smckusick */ 130442441Smckusick /* ARGSUSED */ 130542441Smckusick utimes(p, uap, retval) 130645914Smckusick struct proc *p; 130742441Smckusick register struct args { 130811811Ssam char *fname; 130911811Ssam struct timeval *tptr; 131042441Smckusick } *uap; 131142441Smckusick int *retval; 131242441Smckusick { 1313*47540Skarels register struct nameidata *ndp; 131437741Smckusick register struct vnode *vp; 131511811Ssam struct timeval tv[2]; 131637741Smckusick struct vattr vattr; 131737741Smckusick int error; 1318*47540Skarels struct nameidata nd; 131911811Ssam 132037741Smckusick if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv))) 1321*47540Skarels return (error); 1322*47540Skarels ndp = &nd; 132337741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 132437741Smckusick ndp->ni_segflg = UIO_USERSPACE; 132537741Smckusick ndp->ni_dirp = uap->fname; 1326*47540Skarels if (error = namei(ndp, p)) 1327*47540Skarels return (error); 132837741Smckusick vp = ndp->ni_vp; 132941400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 133037741Smckusick error = EROFS; 133137741Smckusick goto out; 133221015Smckusick } 133345785Sbostic VATTR_NULL(&vattr); 133445785Sbostic vattr.va_atime = tv[0]; 133545785Sbostic vattr.va_mtime = tv[1]; 1336*47540Skarels error = VOP_SETATTR(vp, &vattr, p->p_ucred); 133737741Smckusick out: 133837741Smckusick vput(vp); 1339*47540Skarels return (error); 134011811Ssam } 134111811Ssam 13429167Ssam /* 13439167Ssam * Truncate a file given its path name. 13449167Ssam */ 134542441Smckusick /* ARGSUSED */ 134642441Smckusick truncate(p, uap, retval) 134745914Smckusick struct proc *p; 134842441Smckusick register struct args { 13497701Ssam char *fname; 135026473Skarels off_t length; 135142441Smckusick } *uap; 135242441Smckusick int *retval; 135342441Smckusick { 1354*47540Skarels register struct nameidata *ndp; 135537741Smckusick register struct vnode *vp; 135637741Smckusick struct vattr vattr; 135737741Smckusick int error; 1358*47540Skarels struct nameidata nd; 13597701Ssam 1360*47540Skarels ndp = &nd; 136137741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 136216694Smckusick ndp->ni_segflg = UIO_USERSPACE; 136316694Smckusick ndp->ni_dirp = uap->fname; 1364*47540Skarels if (error = namei(ndp, p)) 1365*47540Skarels return (error); 136637741Smckusick vp = ndp->ni_vp; 136737741Smckusick if (vp->v_type == VDIR) { 136837741Smckusick error = EISDIR; 136937741Smckusick goto out; 13707701Ssam } 137138399Smckusick if ((error = vn_writechk(vp)) || 1372*47540Skarels (error = VOP_ACCESS(vp, VWRITE, p->p_ucred))) 137337741Smckusick goto out; 137445785Sbostic VATTR_NULL(&vattr); 137545785Sbostic vattr.va_size = uap->length; 1376*47540Skarels error = VOP_SETATTR(vp, &vattr, p->p_ucred); 137737741Smckusick out: 137837741Smckusick vput(vp); 1379*47540Skarels return (error); 13807701Ssam } 13817701Ssam 13829167Ssam /* 13839167Ssam * Truncate a file given a file descriptor. 13849167Ssam */ 138542441Smckusick /* ARGSUSED */ 138642441Smckusick ftruncate(p, uap, retval) 138745914Smckusick struct proc *p; 138842441Smckusick register struct args { 13897701Ssam int fd; 139026473Skarels off_t length; 139142441Smckusick } *uap; 139242441Smckusick int *retval; 139342441Smckusick { 139437741Smckusick struct vattr vattr; 139537741Smckusick struct vnode *vp; 13967701Ssam struct file *fp; 139737741Smckusick int error; 13987701Ssam 139945914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 1400*47540Skarels return (error); 140137741Smckusick if ((fp->f_flag & FWRITE) == 0) 1402*47540Skarels return (EINVAL); 140337741Smckusick vp = (struct vnode *)fp->f_data; 140437741Smckusick VOP_LOCK(vp); 140537741Smckusick if (vp->v_type == VDIR) { 140637741Smckusick error = EISDIR; 140737741Smckusick goto out; 14087701Ssam } 140938399Smckusick if (error = vn_writechk(vp)) 141037741Smckusick goto out; 141145785Sbostic VATTR_NULL(&vattr); 141245785Sbostic vattr.va_size = uap->length; 141337741Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred); 141437741Smckusick out: 141537741Smckusick VOP_UNLOCK(vp); 1416*47540Skarels return (error); 14177701Ssam } 14187701Ssam 14199167Ssam /* 14209167Ssam * Synch an open file. 14219167Ssam */ 142242441Smckusick /* ARGSUSED */ 142342441Smckusick fsync(p, uap, retval) 142445914Smckusick struct proc *p; 142542441Smckusick struct args { 142642441Smckusick int fd; 142742441Smckusick } *uap; 142842441Smckusick int *retval; 14299167Ssam { 143039592Smckusick register struct vnode *vp; 14319167Ssam struct file *fp; 143237741Smckusick int error; 14339167Ssam 143445914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 1435*47540Skarels return (error); 143639592Smckusick vp = (struct vnode *)fp->f_data; 143739592Smckusick VOP_LOCK(vp); 143839592Smckusick error = VOP_FSYNC(vp, fp->f_flag, fp->f_cred, MNT_WAIT); 143939592Smckusick VOP_UNLOCK(vp); 1440*47540Skarels return (error); 14419167Ssam } 14429167Ssam 14439167Ssam /* 14449167Ssam * Rename system call. 14459167Ssam * 14469167Ssam * Source and destination must either both be directories, or both 14479167Ssam * not be directories. If target is a directory, it must be empty. 14489167Ssam */ 144942441Smckusick /* ARGSUSED */ 145042441Smckusick rename(p, uap, retval) 145145914Smckusick struct proc *p; 145242441Smckusick register struct args { 14537701Ssam char *from; 14547701Ssam char *to; 145542441Smckusick } *uap; 145642441Smckusick int *retval; 145742441Smckusick { 145837741Smckusick register struct vnode *tvp, *fvp, *tdvp; 1459*47540Skarels register struct nameidata *ndp; 146037741Smckusick int error; 1461*47540Skarels struct nameidata nd, tond; 14627701Ssam 1463*47540Skarels ndp = &nd; 146437741Smckusick ndp->ni_nameiop = DELETE | WANTPARENT; 146516694Smckusick ndp->ni_segflg = UIO_USERSPACE; 146616694Smckusick ndp->ni_dirp = uap->from; 1467*47540Skarels if (error = namei(ndp, p)) 1468*47540Skarels return (error); 146937741Smckusick fvp = ndp->ni_vp; 147038266Smckusick nddup(ndp, &tond); 147137741Smckusick tond.ni_nameiop = RENAME | LOCKPARENT | LOCKLEAF | NOCACHE; 147237741Smckusick tond.ni_segflg = UIO_USERSPACE; 147337741Smckusick tond.ni_dirp = uap->to; 1474*47540Skarels if (error = namei(&tond, p)) { 147542465Smckusick VOP_ABORTOP(ndp); 147642465Smckusick vrele(ndp->ni_dvp); 147742465Smckusick vrele(fvp); 147842465Smckusick goto out1; 147942465Smckusick } 148037741Smckusick tdvp = tond.ni_dvp; 148137741Smckusick tvp = tond.ni_vp; 148237741Smckusick if (tvp != NULL) { 148337741Smckusick if (fvp->v_type == VDIR && tvp->v_type != VDIR) { 148439242Sbostic error = ENOTDIR; 148537741Smckusick goto out; 148637741Smckusick } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) { 148739242Sbostic error = EISDIR; 148837741Smckusick goto out; 14899167Ssam } 149045240Smckusick if (fvp->v_mount != tvp->v_mount) { 149145240Smckusick error = EXDEV; 149245240Smckusick goto out; 149345240Smckusick } 14949167Ssam } 149537741Smckusick if (fvp->v_mount != tdvp->v_mount) { 149637741Smckusick error = EXDEV; 14979167Ssam goto out; 149810051Ssam } 149939286Smckusick if (fvp == tdvp) 150037741Smckusick error = EINVAL; 150139286Smckusick /* 150239286Smckusick * If source is the same as the destination, 150339286Smckusick * then there is nothing to do. 150439286Smckusick */ 150539286Smckusick if (fvp == tvp) 150639286Smckusick error = -1; 150737741Smckusick out: 150842465Smckusick if (!error) { 150942465Smckusick error = VOP_RENAME(ndp, &tond); 151042465Smckusick } else { 151137741Smckusick VOP_ABORTOP(&tond); 151243344Smckusick if (tdvp == tvp) 151343344Smckusick vrele(tdvp); 151443344Smckusick else 151543344Smckusick vput(tdvp); 151642465Smckusick if (tvp) 151742465Smckusick vput(tvp); 151837741Smckusick VOP_ABORTOP(ndp); 151942465Smckusick vrele(ndp->ni_dvp); 152042465Smckusick vrele(fvp); 15219167Ssam } 152237741Smckusick out1: 152338266Smckusick ndrele(&tond); 152439286Smckusick if (error == -1) 1525*47540Skarels return (0); 1526*47540Skarels return (error); 15277701Ssam } 15287701Ssam 15297535Sroot /* 153012756Ssam * Mkdir system call 153112756Ssam */ 153242441Smckusick /* ARGSUSED */ 153342441Smckusick mkdir(p, uap, retval) 153445914Smckusick struct proc *p; 153542441Smckusick register struct args { 153612756Ssam char *name; 153712756Ssam int dmode; 153842441Smckusick } *uap; 153942441Smckusick int *retval; 154042441Smckusick { 1541*47540Skarels register struct nameidata *ndp; 154237741Smckusick register struct vnode *vp; 154337741Smckusick struct vattr vattr; 154437741Smckusick int error; 1545*47540Skarels struct nameidata nd; 154612756Ssam 1547*47540Skarels ndp = &nd; 154837741Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 154916694Smckusick ndp->ni_segflg = UIO_USERSPACE; 155016694Smckusick ndp->ni_dirp = uap->name; 1551*47540Skarels if (error = namei(ndp, p)) 1552*47540Skarels return (error); 155337741Smckusick vp = ndp->ni_vp; 155437741Smckusick if (vp != NULL) { 155537741Smckusick VOP_ABORTOP(ndp); 155643344Smckusick if (ndp->ni_dvp == vp) 155743344Smckusick vrele(ndp->ni_dvp); 155843344Smckusick else 155943344Smckusick vput(ndp->ni_dvp); 156042465Smckusick vrele(vp); 1561*47540Skarels return (EEXIST); 156212756Ssam } 156341362Smckusick VATTR_NULL(&vattr); 156437741Smckusick vattr.va_type = VDIR; 156545914Smckusick vattr.va_mode = (uap->dmode & 0777) &~ p->p_fd->fd_cmask; 156637741Smckusick error = VOP_MKDIR(ndp, &vattr); 156738145Smckusick if (!error) 156838145Smckusick vput(ndp->ni_vp); 1569*47540Skarels return (error); 157012756Ssam } 157112756Ssam 157212756Ssam /* 157312756Ssam * Rmdir system call. 157412756Ssam */ 157542441Smckusick /* ARGSUSED */ 157642441Smckusick rmdir(p, uap, retval) 157745914Smckusick struct proc *p; 157842441Smckusick struct args { 157942441Smckusick char *name; 158042441Smckusick } *uap; 158142441Smckusick int *retval; 158212756Ssam { 1583*47540Skarels register struct nameidata *ndp; 158437741Smckusick register struct vnode *vp; 158537741Smckusick int error; 1586*47540Skarels struct nameidata nd; 158712756Ssam 1588*47540Skarels ndp = &nd; 158937741Smckusick ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF; 159016694Smckusick ndp->ni_segflg = UIO_USERSPACE; 159116694Smckusick ndp->ni_dirp = uap->name; 1592*47540Skarels if (error = namei(ndp, p)) 1593*47540Skarels return (error); 159437741Smckusick vp = ndp->ni_vp; 159537741Smckusick if (vp->v_type != VDIR) { 159637741Smckusick error = ENOTDIR; 159712756Ssam goto out; 159812756Ssam } 159912756Ssam /* 160037741Smckusick * No rmdir "." please. 160112756Ssam */ 160237741Smckusick if (ndp->ni_dvp == vp) { 160337741Smckusick error = EINVAL; 160412756Ssam goto out; 160512756Ssam } 160612756Ssam /* 160737741Smckusick * Don't unlink a mounted file. 160812756Ssam */ 160937741Smckusick if (vp->v_flag & VROOT) 161037741Smckusick error = EBUSY; 161112756Ssam out: 161242465Smckusick if (!error) { 161342465Smckusick error = VOP_RMDIR(ndp); 161442465Smckusick } else { 161537741Smckusick VOP_ABORTOP(ndp); 161643344Smckusick if (ndp->ni_dvp == vp) 161743344Smckusick vrele(ndp->ni_dvp); 161843344Smckusick else 161943344Smckusick vput(ndp->ni_dvp); 162042465Smckusick vput(vp); 162142465Smckusick } 1622*47540Skarels return (error); 162312756Ssam } 162412756Ssam 162537741Smckusick /* 162637741Smckusick * Read a block of directory entries in a file system independent format 162737741Smckusick */ 162842441Smckusick getdirentries(p, uap, retval) 162945914Smckusick struct proc *p; 163042441Smckusick register struct args { 163137741Smckusick int fd; 163237741Smckusick char *buf; 163337741Smckusick unsigned count; 163437741Smckusick long *basep; 163542441Smckusick } *uap; 163642441Smckusick int *retval; 163742441Smckusick { 163839592Smckusick register struct vnode *vp; 163916540Ssam struct file *fp; 164037741Smckusick struct uio auio; 164137741Smckusick struct iovec aiov; 164238129Smckusick off_t off; 164340321Smckusick int error, eofflag; 164412756Ssam 164545914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 1646*47540Skarels return (error); 164737741Smckusick if ((fp->f_flag & FREAD) == 0) 1648*47540Skarels return (EBADF); 164939592Smckusick vp = (struct vnode *)fp->f_data; 165039592Smckusick if (vp->v_type != VDIR) 1651*47540Skarels return (EINVAL); 165237741Smckusick aiov.iov_base = uap->buf; 165337741Smckusick aiov.iov_len = uap->count; 165437741Smckusick auio.uio_iov = &aiov; 165537741Smckusick auio.uio_iovcnt = 1; 165637741Smckusick auio.uio_rw = UIO_READ; 165737741Smckusick auio.uio_segflg = UIO_USERSPACE; 165837741Smckusick auio.uio_resid = uap->count; 165939592Smckusick VOP_LOCK(vp); 166039592Smckusick auio.uio_offset = off = fp->f_offset; 166140321Smckusick error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag); 166239592Smckusick fp->f_offset = auio.uio_offset; 166339592Smckusick VOP_UNLOCK(vp); 166439592Smckusick if (error) 1665*47540Skarels return (error); 166639592Smckusick error = copyout((caddr_t)&off, (caddr_t)uap->basep, sizeof(long)); 166742441Smckusick *retval = uap->count - auio.uio_resid; 1668*47540Skarels return (error); 166912756Ssam } 167012756Ssam 167112756Ssam /* 167212756Ssam * mode mask for creation of files 167312756Ssam */ 167442441Smckusick mode_t 167542441Smckusick umask(p, uap, retval) 167645914Smckusick struct proc *p; 167742441Smckusick struct args { 167842441Smckusick int mask; 167942441Smckusick } *uap; 168042441Smckusick int *retval; 168112756Ssam { 168245914Smckusick register struct filedesc *fdp = p->p_fd; 168312756Ssam 168445914Smckusick *retval = fdp->fd_cmask; 168545914Smckusick fdp->fd_cmask = uap->mask & 07777; 1686*47540Skarels return (0); 168712756Ssam } 168837741Smckusick 168939566Smarc /* 169039566Smarc * Void all references to file by ripping underlying filesystem 169139566Smarc * away from vnode. 169239566Smarc */ 169342441Smckusick /* ARGSUSED */ 169442441Smckusick revoke(p, uap, retval) 169545914Smckusick struct proc *p; 169642441Smckusick register struct args { 169739566Smarc char *fname; 169842441Smckusick } *uap; 169942441Smckusick int *retval; 170042441Smckusick { 1701*47540Skarels register struct nameidata *ndp; 170239566Smarc register struct vnode *vp; 170339566Smarc struct vattr vattr; 170439566Smarc int error; 1705*47540Skarels struct nameidata nd; 170639566Smarc 1707*47540Skarels ndp = &nd; 170839566Smarc ndp->ni_nameiop = LOOKUP | FOLLOW; 170939566Smarc ndp->ni_segflg = UIO_USERSPACE; 171039566Smarc ndp->ni_dirp = uap->fname; 1711*47540Skarels if (error = namei(ndp, p)) 1712*47540Skarels return (error); 171339566Smarc vp = ndp->ni_vp; 171439566Smarc if (vp->v_type != VCHR && vp->v_type != VBLK) { 171539566Smarc error = EINVAL; 171639566Smarc goto out; 171739566Smarc } 1718*47540Skarels if (error = VOP_GETATTR(vp, &vattr, p->p_ucred)) 171939566Smarc goto out; 1720*47540Skarels if (p->p_ucred->cr_uid != vattr.va_uid && 1721*47540Skarels (error = suser(p->p_ucred, &p->p_acflag))) 172239566Smarc goto out; 172339805Smckusick if (vp->v_usecount > 1 || (vp->v_flag & VALIASED)) 172439632Smckusick vgoneall(vp); 172539566Smarc out: 172639566Smarc vrele(vp); 1727*47540Skarels return (error); 172839566Smarc } 172939566Smarc 173045914Smckusick getvnode(fdp, fdes, fpp) 173145914Smckusick struct filedesc *fdp; 173237741Smckusick struct file **fpp; 173337741Smckusick int fdes; 173437741Smckusick { 173537741Smckusick struct file *fp; 173637741Smckusick 1737*47540Skarels if ((unsigned)fdes >= fdp->fd_nfiles || 173845914Smckusick (fp = OFILE(fdp, fdes)) == NULL) 173937741Smckusick return (EBADF); 174037741Smckusick if (fp->f_type != DTYPE_VNODE) 174137741Smckusick return (EINVAL); 174237741Smckusick *fpp = fp; 174337741Smckusick return (0); 174437741Smckusick } 1745