123405Smckusick /* 237741Smckusick * Copyright (c) 1989 The Regents of the University of California. 337741Smckusick * All rights reserved. 423405Smckusick * 544459Sbostic * %sccs.include.redist.c% 637741Smckusick * 7*48026Smckusick * @(#)vfs_syscalls.c 7.67 (Berkeley) 04/15/91 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 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 { 4147540Skarels register struct nameidata *ndp; 4239335Smckusick register struct vnode *vp; 4339335Smckusick register struct mount *mp; 4440111Smckusick int error, flag; 4547540Skarels struct nameidata nd; 466254Sroot 4737741Smckusick /* 4837741Smckusick * Must be super user 4937741Smckusick */ 5047540Skarels if (error = suser(p->p_ucred, &p->p_acflag)) 5147540Skarels return (error); 5237741Smckusick /* 5337741Smckusick * Get vnode to be covered 5437741Smckusick */ 5547540Skarels ndp = &nd; 5637741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 5737741Smckusick ndp->ni_segflg = UIO_USERSPACE; 5837741Smckusick ndp->ni_dirp = uap->dir; 5947540Skarels if (error = namei(ndp, p)) 6047540Skarels return (error); 6137741Smckusick vp = ndp->ni_vp; 6241400Smckusick if (uap->flags & MNT_UPDATE) { 6339335Smckusick if ((vp->v_flag & VROOT) == 0) { 6439335Smckusick vput(vp); 6547540Skarels 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); 7547540Skarels 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); 8547540Skarels return (EBUSY); 8637741Smckusick } 8737741Smckusick if (vp->v_type != VDIR) { 8837741Smckusick vput(vp); 8947540Skarels return (ENOTDIR); 9037741Smckusick } 9139741Smckusick if ((unsigned long)uap->type > MOUNT_MAXTYPE || 9237741Smckusick vfssw[uap->type] == (struct vfsops *)0) { 9337741Smckusick vput(vp); 9447540Skarels return (ENODEV); 9537741Smckusick } 9637741Smckusick 9737741Smckusick /* 9839335Smckusick * Allocate and initialize the file system. 9937741Smckusick */ 10037741Smckusick mp = (struct mount *)malloc((u_long)sizeof(struct mount), 10137741Smckusick M_MOUNT, M_WAITOK); 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); 10947540Skarels 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); 11547540Skarels 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 */ 146*48026Smckusick error = VFS_MOUNT(mp, uap->dir, uap->data, ndp, p); 14741400Smckusick if (mp->mnt_flag & MNT_UPDATE) { 14841400Smckusick mp->mnt_flag &= ~MNT_UPDATE; 14939335Smckusick vrele(vp); 15040111Smckusick if (error) 15141400Smckusick mp->mnt_flag = flag; 15247540Skarels 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); 165*48026Smckusick error = VFS_START(mp, 0, p); 16637741Smckusick } else { 16737741Smckusick vfs_remove(mp); 16837741Smckusick free((caddr_t)mp, M_MOUNT); 16939335Smckusick vput(vp); 17037741Smckusick } 17147540Skarels 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; 19047540Skarels register struct nameidata *ndp; 19139356Smckusick struct mount *mp; 19237741Smckusick int error; 19347540Skarels struct nameidata nd; 1946254Sroot 19537741Smckusick /* 19637741Smckusick * Must be super user 19737741Smckusick */ 19847540Skarels if (error = suser(p->p_ucred, &p->p_acflag)) 19947540Skarels return (error); 20037741Smckusick 20147540Skarels ndp = &nd; 20237741Smckusick ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW; 20337741Smckusick ndp->ni_segflg = UIO_USERSPACE; 20437741Smckusick ndp->ni_dirp = uap->pathp; 20547540Skarels if (error = namei(ndp, p)) 20647540Skarels 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); 21347540Skarels return (EINVAL); 21437741Smckusick } 21537741Smckusick mp = vp->v_mount; 21637741Smckusick vput(vp); 217*48026Smckusick return (dounmount(mp, uap->flags, p)); 21839356Smckusick } 21939356Smckusick 22039356Smckusick /* 22139356Smckusick * Do an unmount. 22239356Smckusick */ 223*48026Smckusick dounmount(mp, flags, p) 22439356Smckusick register struct mount *mp; 22539356Smckusick int flags; 226*48026Smckusick struct proc *p; 22739356Smckusick { 22839356Smckusick struct vnode *coveredvp; 22939356Smckusick int error; 23039356Smckusick 23141400Smckusick coveredvp = mp->mnt_vnodecovered; 23241298Smckusick if (vfs_busy(mp)) 23341298Smckusick return (EBUSY); 23441400Smckusick mp->mnt_flag |= MNT_UNMOUNT; 23537741Smckusick if (error = vfs_lock(mp)) 23639356Smckusick return (error); 23737741Smckusick 23845922Smckusick #ifdef NVM 23945738Smckusick vnode_pager_umount(mp); /* release cached vnodes */ 24045922Smckusick #else 24145922Smckusick xumount(mp); /* remove unused sticky files from text table */ 24245922Smckusick #endif 24337741Smckusick cache_purgevfs(mp); /* remove cache entries for this file sys */ 24441676Smckusick if ((error = VFS_SYNC(mp, MNT_WAIT)) == 0 || (flags & MNT_FORCE)) 245*48026Smckusick 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); 25337741Smckusick free((caddr_t)mp, M_MOUNT); 25437741Smckusick } 25539356Smckusick return (error); 2566254Sroot } 2576254Sroot 2589167Ssam /* 25937741Smckusick * Sync system call. 26037741Smckusick * Sync each mounted filesystem. 2619167Ssam */ 26239491Smckusick /* ARGSUSED */ 26342441Smckusick sync(p, uap, retval) 26445914Smckusick struct proc *p; 26547540Skarels void *uap; 26642441Smckusick int *retval; 2676254Sroot { 26837741Smckusick register struct mount *mp; 26941298Smckusick struct mount *omp; 27037741Smckusick 27137741Smckusick mp = rootfs; 27237741Smckusick do { 27340343Smckusick /* 27440343Smckusick * The lock check below is to avoid races with mount 27540343Smckusick * and unmount. 27640343Smckusick */ 27741400Smckusick if ((mp->mnt_flag & (MNT_MLOCK|MNT_RDONLY|MNT_MPBUSY)) == 0 && 27841298Smckusick !vfs_busy(mp)) { 27937741Smckusick VFS_SYNC(mp, MNT_NOWAIT); 28041298Smckusick omp = mp; 28141400Smckusick mp = mp->mnt_next; 28241298Smckusick vfs_unbusy(omp); 28341298Smckusick } else 28441400Smckusick mp = mp->mnt_next; 28537741Smckusick } while (mp != rootfs); 28647688Skarels return (0); 28737741Smckusick } 28837741Smckusick 28937741Smckusick /* 29041298Smckusick * operate on filesystem quotas 29141298Smckusick */ 29242441Smckusick /* ARGSUSED */ 29342441Smckusick quotactl(p, uap, retval) 29445914Smckusick struct proc *p; 29542441Smckusick register struct args { 29641298Smckusick char *path; 29741298Smckusick int cmd; 29841298Smckusick int uid; 29941298Smckusick caddr_t arg; 30042441Smckusick } *uap; 30142441Smckusick int *retval; 30242441Smckusick { 30341298Smckusick register struct mount *mp; 30447540Skarels register struct nameidata *ndp; 30541298Smckusick int error; 30647540Skarels struct nameidata nd; 30741298Smckusick 30847540Skarels ndp = &nd; 30941298Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW; 31041298Smckusick ndp->ni_segflg = UIO_USERSPACE; 31141298Smckusick ndp->ni_dirp = uap->path; 31247540Skarels if (error = namei(ndp, p)) 31347540Skarels return (error); 31441298Smckusick mp = ndp->ni_vp->v_mount; 31541298Smckusick vrele(ndp->ni_vp); 316*48026Smckusick return (VFS_QUOTACTL(mp, uap->cmd, uap->uid, uap->arg, p)); 31741298Smckusick } 31841298Smckusick 31941298Smckusick /* 32037741Smckusick * get filesystem statistics 32137741Smckusick */ 32242441Smckusick /* ARGSUSED */ 32342441Smckusick statfs(p, uap, retval) 32445914Smckusick struct proc *p; 32542441Smckusick register struct args { 32637741Smckusick char *path; 32737741Smckusick struct statfs *buf; 32842441Smckusick } *uap; 32942441Smckusick int *retval; 33042441Smckusick { 33139464Smckusick register struct mount *mp; 33247540Skarels register struct nameidata *ndp; 33340343Smckusick register struct statfs *sp; 33437741Smckusick int error; 33547540Skarels struct nameidata nd; 33637741Smckusick 33747540Skarels ndp = &nd; 33839544Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW; 33937741Smckusick ndp->ni_segflg = UIO_USERSPACE; 34037741Smckusick ndp->ni_dirp = uap->path; 34147540Skarels if (error = namei(ndp, p)) 34247540Skarels return (error); 34339544Smckusick mp = ndp->ni_vp->v_mount; 34441400Smckusick sp = &mp->mnt_stat; 34539544Smckusick vrele(ndp->ni_vp); 346*48026Smckusick if (error = VFS_STATFS(mp, sp, p)) 34747540Skarels return (error); 34841400Smckusick sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 34947540Skarels return (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp))); 35037741Smckusick } 35137741Smckusick 35242441Smckusick /* 35342441Smckusick * get filesystem statistics 35442441Smckusick */ 35542441Smckusick /* ARGSUSED */ 35642441Smckusick fstatfs(p, uap, retval) 35745914Smckusick struct proc *p; 35842441Smckusick register struct args { 35937741Smckusick int fd; 36037741Smckusick struct statfs *buf; 36142441Smckusick } *uap; 36242441Smckusick int *retval; 36342441Smckusick { 36437741Smckusick struct file *fp; 36539464Smckusick struct mount *mp; 36640343Smckusick register struct statfs *sp; 36737741Smckusick int error; 36837741Smckusick 36945914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 37047540Skarels return (error); 37139464Smckusick mp = ((struct vnode *)fp->f_data)->v_mount; 37241400Smckusick sp = &mp->mnt_stat; 373*48026Smckusick if (error = VFS_STATFS(mp, sp, p)) 37447540Skarels return (error); 37541400Smckusick sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 37647540Skarels return (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp))); 37737741Smckusick } 37837741Smckusick 37937741Smckusick /* 38038270Smckusick * get statistics on all filesystems 38138270Smckusick */ 38242441Smckusick getfsstat(p, uap, retval) 38345914Smckusick struct proc *p; 38442441Smckusick register struct args { 38538270Smckusick struct statfs *buf; 38638270Smckusick long bufsize; 38740343Smckusick int flags; 38842441Smckusick } *uap; 38942441Smckusick int *retval; 39042441Smckusick { 39138270Smckusick register struct mount *mp; 39240343Smckusick register struct statfs *sp; 39339606Smckusick caddr_t sfsp; 39438270Smckusick long count, maxcount, error; 39538270Smckusick 39638270Smckusick maxcount = uap->bufsize / sizeof(struct statfs); 39739606Smckusick sfsp = (caddr_t)uap->buf; 39838270Smckusick mp = rootfs; 39938270Smckusick count = 0; 40038270Smckusick do { 40141400Smckusick if (sfsp && count < maxcount && 40241400Smckusick ((mp->mnt_flag & MNT_MLOCK) == 0)) { 40341400Smckusick sp = &mp->mnt_stat; 40440343Smckusick /* 40540343Smckusick * If MNT_NOWAIT is specified, do not refresh the 40640343Smckusick * fsstat cache. MNT_WAIT overrides MNT_NOWAIT. 40740343Smckusick */ 40840343Smckusick if (((uap->flags & MNT_NOWAIT) == 0 || 40940343Smckusick (uap->flags & MNT_WAIT)) && 410*48026Smckusick (error = VFS_STATFS(mp, sp, p))) { 41141400Smckusick mp = mp->mnt_prev; 41239607Smckusick continue; 41339607Smckusick } 41441400Smckusick sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 41540343Smckusick if (error = copyout((caddr_t)sp, sfsp, sizeof(*sp))) 41647540Skarels return (error); 41740343Smckusick sfsp += sizeof(*sp); 41838270Smckusick } 41939606Smckusick count++; 42041400Smckusick mp = mp->mnt_prev; 42138270Smckusick } while (mp != rootfs); 42238270Smckusick if (sfsp && count > maxcount) 42342441Smckusick *retval = maxcount; 42438270Smckusick else 42542441Smckusick *retval = count; 42647540Skarels return (0); 42738270Smckusick } 42838270Smckusick 42938270Smckusick /* 43038259Smckusick * Change current working directory to a given file descriptor. 43138259Smckusick */ 43242441Smckusick /* ARGSUSED */ 43342441Smckusick fchdir(p, uap, retval) 43445914Smckusick struct proc *p; 43542441Smckusick struct args { 43642441Smckusick int fd; 43742441Smckusick } *uap; 43842441Smckusick int *retval; 43938259Smckusick { 44045914Smckusick register struct filedesc *fdp = p->p_fd; 44138259Smckusick register struct vnode *vp; 44238259Smckusick struct file *fp; 44338259Smckusick int error; 44438259Smckusick 44545914Smckusick if (error = getvnode(fdp, uap->fd, &fp)) 44647540Skarels return (error); 44738259Smckusick vp = (struct vnode *)fp->f_data; 44838259Smckusick VOP_LOCK(vp); 44938259Smckusick if (vp->v_type != VDIR) 45038259Smckusick error = ENOTDIR; 45138259Smckusick else 452*48026Smckusick error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p); 45338259Smckusick VOP_UNLOCK(vp); 45439860Smckusick if (error) 45547540Skarels return (error); 45639860Smckusick VREF(vp); 45745914Smckusick vrele(fdp->fd_cdir); 45845914Smckusick fdp->fd_cdir = vp; 45947540Skarels return (0); 46038259Smckusick } 46138259Smckusick 46238259Smckusick /* 46337741Smckusick * Change current working directory (``.''). 46437741Smckusick */ 46542441Smckusick /* ARGSUSED */ 46642441Smckusick chdir(p, uap, retval) 46745914Smckusick struct proc *p; 46842441Smckusick struct args { 46942441Smckusick char *fname; 47042441Smckusick } *uap; 47142441Smckusick int *retval; 47237741Smckusick { 47347540Skarels register struct nameidata *ndp; 47445914Smckusick register struct filedesc *fdp = p->p_fd; 47537741Smckusick int error; 47647540Skarels struct nameidata nd; 4776254Sroot 47847540Skarels ndp = &nd; 47937741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 48016694Smckusick ndp->ni_segflg = UIO_USERSPACE; 48116694Smckusick ndp->ni_dirp = uap->fname; 48247540Skarels if (error = chdirec(ndp, p)) 48347540Skarels return (error); 48445914Smckusick vrele(fdp->fd_cdir); 48545914Smckusick fdp->fd_cdir = ndp->ni_vp; 48647540Skarels return (0); 48737741Smckusick } 4886254Sroot 48937741Smckusick /* 49037741Smckusick * Change notion of root (``/'') directory. 49137741Smckusick */ 49242441Smckusick /* ARGSUSED */ 49342441Smckusick chroot(p, uap, retval) 49445914Smckusick struct proc *p; 49542441Smckusick struct args { 49642441Smckusick char *fname; 49742441Smckusick } *uap; 49842441Smckusick int *retval; 49937741Smckusick { 50047540Skarels register struct nameidata *ndp; 50145914Smckusick register struct filedesc *fdp = p->p_fd; 50237741Smckusick int error; 50347540Skarels struct nameidata nd; 50437741Smckusick 50547540Skarels if (error = suser(p->p_ucred, &p->p_acflag)) 50647540Skarels return (error); 50747540Skarels ndp = &nd; 50837741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 50937741Smckusick ndp->ni_segflg = UIO_USERSPACE; 51037741Smckusick ndp->ni_dirp = uap->fname; 51147540Skarels if (error = chdirec(ndp, p)) 51247540Skarels return (error); 51345914Smckusick if (fdp->fd_rdir != NULL) 51445914Smckusick vrele(fdp->fd_rdir); 51545914Smckusick fdp->fd_rdir = ndp->ni_vp; 51647540Skarels return (0); 5176254Sroot } 5186254Sroot 51937Sbill /* 52037741Smckusick * Common routine for chroot and chdir. 52137741Smckusick */ 52247540Skarels chdirec(ndp, p) 52347540Skarels struct nameidata *ndp; 52447540Skarels struct proc *p; 52537741Smckusick { 52637741Smckusick struct vnode *vp; 52737741Smckusick int error; 52837741Smckusick 52947540Skarels if (error = namei(ndp, p)) 53037741Smckusick return (error); 53137741Smckusick vp = ndp->ni_vp; 53237741Smckusick if (vp->v_type != VDIR) 53337741Smckusick error = ENOTDIR; 53437741Smckusick else 535*48026Smckusick error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p); 53637741Smckusick VOP_UNLOCK(vp); 53737741Smckusick if (error) 53837741Smckusick vrele(vp); 53937741Smckusick return (error); 54037741Smckusick } 54137741Smckusick 54237741Smckusick /* 5436254Sroot * Open system call. 54442441Smckusick * Check permissions, allocate an open file structure, 54542441Smckusick * and call the device open routine if any. 5466254Sroot */ 54742441Smckusick open(p, uap, retval) 54845914Smckusick struct proc *p; 54942441Smckusick register struct args { 5506254Sroot char *fname; 5517701Ssam int mode; 55212756Ssam int crtmode; 55342441Smckusick } *uap; 55442441Smckusick int *retval; 5556254Sroot { 55647540Skarels struct nameidata *ndp; 55745914Smckusick register struct filedesc *fdp = p->p_fd; 55842441Smckusick register struct file *fp; 55937741Smckusick int fmode, cmode; 56037741Smckusick struct file *nfp; 56137741Smckusick int indx, error; 56247540Skarels struct nameidata nd; 56337741Smckusick extern struct fileops vnops; 5646254Sroot 56545914Smckusick if (error = falloc(p, &nfp, &indx)) 56647540Skarels return (error); 56737741Smckusick fp = nfp; 56846553Skarels fmode = FFLAGS(uap->mode); 56945914Smckusick cmode = ((uap->crtmode &~ fdp->fd_cmask) & 07777) &~ S_ISVTX; 57047540Skarels ndp = &nd; 57142441Smckusick ndp->ni_segflg = UIO_USERSPACE; 57242441Smckusick ndp->ni_dirp = uap->fname; 57345202Smckusick p->p_dupfd = -indx - 1; /* XXX check for fdopen */ 57447540Skarels if (error = vn_open(ndp, p, fmode, cmode)) { 57537741Smckusick crfree(fp->f_cred); 57637741Smckusick fp->f_count--; 57743405Smckusick if (error == ENODEV && /* XXX from fdopen */ 57845202Smckusick p->p_dupfd >= 0 && 57945914Smckusick (error = dupfdopen(fdp, indx, p->p_dupfd, fmode)) == 0) { 58042441Smckusick *retval = indx; 58147540Skarels return (0); 58242441Smckusick } 58340884Smckusick if (error == ERESTART) 58440884Smckusick error = EINTR; 58547688Skarels fdp->fd_ofiles[indx] = NULL; 58647540Skarels return (error); 58712756Ssam } 58837741Smckusick fp->f_flag = fmode & FMASK; 58937741Smckusick fp->f_type = DTYPE_VNODE; 59037741Smckusick fp->f_ops = &vnops; 59137741Smckusick fp->f_data = (caddr_t)ndp->ni_vp; 59242441Smckusick *retval = indx; 59347540Skarels return (0); 5946254Sroot } 5956254Sroot 59642955Smckusick #ifdef COMPAT_43 5976254Sroot /* 59842441Smckusick * Creat system call. 5996254Sroot */ 60042955Smckusick ocreat(p, uap, retval) 60142441Smckusick struct proc *p; 60242441Smckusick register struct args { 60342441Smckusick char *fname; 60442441Smckusick int fmode; 60542441Smckusick } *uap; 60642441Smckusick int *retval; 6076254Sroot { 60842441Smckusick struct args { 6096254Sroot char *fname; 61042441Smckusick int mode; 61142441Smckusick int crtmode; 61242441Smckusick } openuap; 61342441Smckusick 61442441Smckusick openuap.fname = uap->fname; 61542441Smckusick openuap.crtmode = uap->fmode; 61642441Smckusick openuap.mode = O_WRONLY | O_CREAT | O_TRUNC; 61747540Skarels return (open(p, &openuap, retval)); 61842441Smckusick } 61942955Smckusick #endif /* COMPAT_43 */ 62042441Smckusick 62142441Smckusick /* 62242441Smckusick * Mknod system call 62342441Smckusick */ 62442441Smckusick /* ARGSUSED */ 62542441Smckusick mknod(p, uap, retval) 62645914Smckusick struct proc *p; 62742441Smckusick register struct args { 62842441Smckusick char *fname; 6296254Sroot int fmode; 6306254Sroot int dev; 63142441Smckusick } *uap; 63242441Smckusick int *retval; 63342441Smckusick { 63447540Skarels register struct nameidata *ndp; 63537741Smckusick register struct vnode *vp; 63637741Smckusick struct vattr vattr; 63737741Smckusick int error; 63847540Skarels struct nameidata nd; 6396254Sroot 64047540Skarels if (error = suser(p->p_ucred, &p->p_acflag)) 64147540Skarels return (error); 64247540Skarels ndp = &nd; 64337741Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 64416694Smckusick ndp->ni_segflg = UIO_USERSPACE; 64516694Smckusick ndp->ni_dirp = uap->fname; 64647540Skarels if (error = namei(ndp, p)) 64747540Skarels return (error); 64837741Smckusick vp = ndp->ni_vp; 64937741Smckusick if (vp != NULL) { 65037741Smckusick error = EEXIST; 65112756Ssam goto out; 6526254Sroot } 65341362Smckusick VATTR_NULL(&vattr); 65440635Smckusick switch (uap->fmode & S_IFMT) { 65512756Ssam 65640635Smckusick case S_IFMT: /* used by badsect to flag bad sectors */ 65737741Smckusick vattr.va_type = VBAD; 65837741Smckusick break; 65940635Smckusick case S_IFCHR: 66037741Smckusick vattr.va_type = VCHR; 66137741Smckusick break; 66240635Smckusick case S_IFBLK: 66337741Smckusick vattr.va_type = VBLK; 66437741Smckusick break; 66537741Smckusick default: 66637741Smckusick error = EINVAL; 66737741Smckusick goto out; 6686254Sroot } 66945914Smckusick vattr.va_mode = (uap->fmode & 07777) &~ p->p_fd->fd_cmask; 67037741Smckusick vattr.va_rdev = uap->dev; 6716254Sroot out: 67242465Smckusick if (!error) { 673*48026Smckusick error = VOP_MKNOD(ndp, &vattr, p->p_ucred, p); 67442465Smckusick } else { 67537741Smckusick VOP_ABORTOP(ndp); 67643344Smckusick if (ndp->ni_dvp == vp) 67743344Smckusick vrele(ndp->ni_dvp); 67843344Smckusick else 67943344Smckusick vput(ndp->ni_dvp); 68042465Smckusick if (vp) 68142465Smckusick vrele(vp); 68242465Smckusick } 68347540Skarels return (error); 6846254Sroot } 6856254Sroot 6866254Sroot /* 68740285Smckusick * Mkfifo system call 68840285Smckusick */ 68942441Smckusick /* ARGSUSED */ 69042441Smckusick mkfifo(p, uap, retval) 69145914Smckusick struct proc *p; 69242441Smckusick register struct args { 69340285Smckusick char *fname; 69440285Smckusick int fmode; 69542441Smckusick } *uap; 69642441Smckusick int *retval; 69742441Smckusick { 69847540Skarels register struct nameidata *ndp; 69940285Smckusick struct vattr vattr; 70040285Smckusick int error; 70147540Skarels struct nameidata nd; 70240285Smckusick 70340285Smckusick #ifndef FIFO 70447540Skarels return (EOPNOTSUPP); 70540285Smckusick #else 70647540Skarels ndp = &nd; 70740285Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 70840285Smckusick ndp->ni_segflg = UIO_USERSPACE; 70940285Smckusick ndp->ni_dirp = uap->fname; 71047540Skarels if (error = namei(ndp, p)) 71147540Skarels return (error); 71240285Smckusick if (ndp->ni_vp != NULL) { 71340285Smckusick VOP_ABORTOP(ndp); 71443344Smckusick if (ndp->ni_dvp == ndp->ni_vp) 71543344Smckusick vrele(ndp->ni_dvp); 71643344Smckusick else 71743344Smckusick vput(ndp->ni_dvp); 71842465Smckusick vrele(ndp->ni_vp); 71947540Skarels return (EEXIST); 72040285Smckusick } 72145785Sbostic VATTR_NULL(&vattr); 72245785Sbostic vattr.va_type = VFIFO; 72345914Smckusick vattr.va_mode = (uap->fmode & 07777) &~ p->p_fd->fd_cmask; 724*48026Smckusick return (VOP_MKNOD(ndp, &vattr, p->p_ucred, p)); 72540285Smckusick #endif /* FIFO */ 72640285Smckusick } 72740285Smckusick 72840285Smckusick /* 7296254Sroot * link system call 7306254Sroot */ 73142441Smckusick /* ARGSUSED */ 73242441Smckusick link(p, uap, retval) 73345914Smckusick struct proc *p; 73442441Smckusick register struct args { 7356254Sroot char *target; 7366254Sroot char *linkname; 73742441Smckusick } *uap; 73842441Smckusick int *retval; 73942441Smckusick { 74047540Skarels register struct nameidata *ndp; 74137741Smckusick register struct vnode *vp, *xp; 74237741Smckusick int error; 74347540Skarels struct nameidata nd; 7446254Sroot 74547540Skarels ndp = &nd; 74616694Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW; 74716694Smckusick ndp->ni_segflg = UIO_USERSPACE; 74816694Smckusick ndp->ni_dirp = uap->target; 74947540Skarels if (error = namei(ndp, p)) 75047540Skarels return (error); 75137741Smckusick vp = ndp->ni_vp; 75237741Smckusick if (vp->v_type == VDIR && 75347540Skarels (error = suser(p->p_ucred, &p->p_acflag))) 75437741Smckusick goto out1; 75537741Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 75616694Smckusick ndp->ni_dirp = (caddr_t)uap->linkname; 75747540Skarels if (error = namei(ndp, p)) 75837741Smckusick goto out1; 75937741Smckusick xp = ndp->ni_vp; 7606254Sroot if (xp != NULL) { 76137741Smckusick error = EEXIST; 7626254Sroot goto out; 7636254Sroot } 76437741Smckusick xp = ndp->ni_dvp; 76537741Smckusick if (vp->v_mount != xp->v_mount) 76637741Smckusick error = EXDEV; 7676254Sroot out: 76842465Smckusick if (!error) { 769*48026Smckusick error = VOP_LINK(vp, ndp, p); 77042465Smckusick } else { 77137741Smckusick VOP_ABORTOP(ndp); 77243344Smckusick if (ndp->ni_dvp == ndp->ni_vp) 77343344Smckusick vrele(ndp->ni_dvp); 77443344Smckusick else 77543344Smckusick vput(ndp->ni_dvp); 77642465Smckusick if (ndp->ni_vp) 77742465Smckusick vrele(ndp->ni_vp); 77842465Smckusick } 77937741Smckusick out1: 78037741Smckusick vrele(vp); 78147540Skarels return (error); 7826254Sroot } 7836254Sroot 7846254Sroot /* 7856254Sroot * symlink -- make a symbolic link 7866254Sroot */ 78742441Smckusick /* ARGSUSED */ 78842441Smckusick symlink(p, uap, retval) 78945914Smckusick struct proc *p; 79042441Smckusick register struct args { 7916254Sroot char *target; 7926254Sroot char *linkname; 79342441Smckusick } *uap; 79442441Smckusick int *retval; 79542441Smckusick { 79647540Skarels register struct nameidata *ndp; 79737741Smckusick struct vattr vattr; 79837741Smckusick char *target; 79937741Smckusick int error; 80047540Skarels struct nameidata nd; 8016254Sroot 80247540Skarels ndp = &nd; 80316694Smckusick ndp->ni_segflg = UIO_USERSPACE; 80416694Smckusick ndp->ni_dirp = uap->linkname; 80537741Smckusick MALLOC(target, char *, MAXPATHLEN, M_NAMEI, M_WAITOK); 80637741Smckusick if (error = copyinstr(uap->target, target, MAXPATHLEN, (u_int *)0)) 80742465Smckusick goto out; 80837741Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 80947540Skarels if (error = namei(ndp, p)) 81042465Smckusick goto out; 81142465Smckusick if (ndp->ni_vp) { 81242465Smckusick VOP_ABORTOP(ndp); 81343344Smckusick if (ndp->ni_dvp == ndp->ni_vp) 81443344Smckusick vrele(ndp->ni_dvp); 81543344Smckusick else 81643344Smckusick vput(ndp->ni_dvp); 81742465Smckusick vrele(ndp->ni_vp); 81837741Smckusick error = EEXIST; 81937741Smckusick goto out; 8206254Sroot } 82141362Smckusick VATTR_NULL(&vattr); 82245914Smckusick vattr.va_mode = 0777 &~ p->p_fd->fd_cmask; 823*48026Smckusick error = VOP_SYMLINK(ndp, &vattr, target, p); 82437741Smckusick out: 82537741Smckusick FREE(target, M_NAMEI); 82647540Skarels return (error); 8276254Sroot } 8286254Sroot 8296254Sroot /* 8306254Sroot * Unlink system call. 8316254Sroot * Hard to avoid races here, especially 8326254Sroot * in unlinking directories. 8336254Sroot */ 83442441Smckusick /* ARGSUSED */ 83542441Smckusick unlink(p, uap, retval) 83645914Smckusick struct proc *p; 83742441Smckusick struct args { 83842441Smckusick char *fname; 83942441Smckusick } *uap; 84042441Smckusick int *retval; 8416254Sroot { 84247540Skarels register struct nameidata *ndp; 84337741Smckusick register struct vnode *vp; 84437741Smckusick int error; 84547540Skarels struct nameidata nd; 8466254Sroot 84747540Skarels ndp = &nd; 84837741Smckusick ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF; 84916694Smckusick ndp->ni_segflg = UIO_USERSPACE; 85016694Smckusick ndp->ni_dirp = uap->fname; 85147540Skarels if (error = namei(ndp, p)) 85247540Skarels return (error); 85337741Smckusick vp = ndp->ni_vp; 85437741Smckusick if (vp->v_type == VDIR && 85547540Skarels (error = suser(p->p_ucred, &p->p_acflag))) 8566254Sroot goto out; 8576254Sroot /* 8586254Sroot * Don't unlink a mounted file. 8596254Sroot */ 86037741Smckusick if (vp->v_flag & VROOT) { 86137741Smckusick error = EBUSY; 8626254Sroot goto out; 8636254Sroot } 86445922Smckusick #ifdef NVM 86545738Smckusick (void) vnode_pager_uncache(vp); 86645922Smckusick #else 86745922Smckusick if (vp->v_flag & VTEXT) 86845922Smckusick xrele(vp); /* try once to free text */ 86945922Smckusick #endif 8706254Sroot out: 87142465Smckusick if (!error) { 872*48026Smckusick error = VOP_REMOVE(ndp, p); 87342465Smckusick } else { 87437741Smckusick VOP_ABORTOP(ndp); 87543344Smckusick if (ndp->ni_dvp == vp) 87643344Smckusick vrele(ndp->ni_dvp); 87743344Smckusick else 87843344Smckusick vput(ndp->ni_dvp); 87942465Smckusick vput(vp); 88042465Smckusick } 88147540Skarels return (error); 8826254Sroot } 8836254Sroot 8846254Sroot /* 8856254Sroot * Seek system call 8866254Sroot */ 88742441Smckusick lseek(p, uap, retval) 88845914Smckusick struct proc *p; 88942441Smckusick register struct args { 89037741Smckusick int fdes; 8916254Sroot off_t off; 8926254Sroot int sbase; 89342441Smckusick } *uap; 89442441Smckusick off_t *retval; 89542441Smckusick { 89647540Skarels struct ucred *cred = p->p_ucred; 89745914Smckusick register struct filedesc *fdp = p->p_fd; 89842441Smckusick register struct file *fp; 89937741Smckusick struct vattr vattr; 90037741Smckusick int error; 9016254Sroot 90247540Skarels if ((unsigned)uap->fdes >= fdp->fd_nfiles || 90347688Skarels (fp = fdp->fd_ofiles[uap->fdes]) == NULL) 90447540Skarels return (EBADF); 90537741Smckusick if (fp->f_type != DTYPE_VNODE) 90647540Skarels return (ESPIPE); 90713878Ssam switch (uap->sbase) { 90813878Ssam 90913878Ssam case L_INCR: 91013878Ssam fp->f_offset += uap->off; 91113878Ssam break; 91213878Ssam 91313878Ssam case L_XTND: 91437741Smckusick if (error = VOP_GETATTR((struct vnode *)fp->f_data, 915*48026Smckusick &vattr, cred, p)) 91647540Skarels return (error); 91737741Smckusick fp->f_offset = uap->off + vattr.va_size; 91813878Ssam break; 91913878Ssam 92013878Ssam case L_SET: 92113878Ssam fp->f_offset = uap->off; 92213878Ssam break; 92313878Ssam 92413878Ssam default: 92547540Skarels return (EINVAL); 92613878Ssam } 92742441Smckusick *retval = fp->f_offset; 92847540Skarels return (0); 9296254Sroot } 9306254Sroot 9316254Sroot /* 9326254Sroot * Access system call 9336254Sroot */ 93442441Smckusick /* ARGSUSED */ 93542441Smckusick saccess(p, uap, retval) 93645914Smckusick struct proc *p; 93742441Smckusick register struct args { 9386254Sroot char *fname; 9396254Sroot int fmode; 94042441Smckusick } *uap; 94142441Smckusick int *retval; 94242441Smckusick { 94347540Skarels register struct nameidata *ndp; 94447540Skarels register struct ucred *cred = p->p_ucred; 94537741Smckusick register struct vnode *vp; 94637741Smckusick int error, mode, svuid, svgid; 94747540Skarels struct nameidata nd; 9486254Sroot 94947540Skarels ndp = &nd; 95042441Smckusick svuid = cred->cr_uid; 95142441Smckusick svgid = cred->cr_groups[0]; 95247540Skarels cred->cr_uid = p->p_cred->p_ruid; 95347540Skarels cred->cr_groups[0] = p->p_cred->p_rgid; 95437741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 95516694Smckusick ndp->ni_segflg = UIO_USERSPACE; 95616694Smckusick ndp->ni_dirp = uap->fname; 95747540Skarels if (error = namei(ndp, p)) 95837741Smckusick goto out1; 95937741Smckusick vp = ndp->ni_vp; 96037741Smckusick /* 96137741Smckusick * fmode == 0 means only check for exist 96237741Smckusick */ 96337741Smckusick if (uap->fmode) { 96437741Smckusick mode = 0; 96537741Smckusick if (uap->fmode & R_OK) 96637741Smckusick mode |= VREAD; 96737741Smckusick if (uap->fmode & W_OK) 96837741Smckusick mode |= VWRITE; 96937741Smckusick if (uap->fmode & X_OK) 97037741Smckusick mode |= VEXEC; 97139543Smckusick if ((mode & VWRITE) == 0 || (error = vn_writechk(vp)) == 0) 972*48026Smckusick error = VOP_ACCESS(vp, mode, cred, p); 9736254Sroot } 97437741Smckusick vput(vp); 97537741Smckusick out1: 97642441Smckusick cred->cr_uid = svuid; 97742441Smckusick cred->cr_groups[0] = svgid; 97847540Skarels return (error); 9796254Sroot } 9806254Sroot 9816254Sroot /* 9826574Smckusic * Stat system call. This version follows links. 98337Sbill */ 98442441Smckusick /* ARGSUSED */ 98542441Smckusick stat(p, uap, retval) 98645914Smckusick struct proc *p; 98742441Smckusick register struct args { 98842441Smckusick char *fname; 98942441Smckusick struct stat *ub; 99042441Smckusick } *uap; 99142441Smckusick int *retval; 99237Sbill { 99347540Skarels register struct nameidata *ndp; 99442441Smckusick struct stat sb; 99542441Smckusick int error; 99647540Skarels struct nameidata nd; 99737Sbill 99847540Skarels ndp = &nd; 99942441Smckusick ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW; 100042441Smckusick ndp->ni_segflg = UIO_USERSPACE; 100142441Smckusick ndp->ni_dirp = uap->fname; 100247540Skarels if (error = namei(ndp, p)) 100347540Skarels return (error); 1004*48026Smckusick error = vn_stat(ndp->ni_vp, &sb, p); 100542441Smckusick vput(ndp->ni_vp); 100642441Smckusick if (error) 100747540Skarels return (error); 100842441Smckusick error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb)); 100947540Skarels return (error); 101037Sbill } 101137Sbill 101237Sbill /* 10136574Smckusic * Lstat system call. This version does not follow links. 10145992Swnj */ 101542441Smckusick /* ARGSUSED */ 101642441Smckusick lstat(p, uap, retval) 101745914Smckusick struct proc *p; 101842441Smckusick register struct args { 10195992Swnj char *fname; 102012756Ssam struct stat *ub; 102142441Smckusick } *uap; 102242441Smckusick int *retval; 102342441Smckusick { 102447540Skarels register struct nameidata *ndp; 102512756Ssam struct stat sb; 102637741Smckusick int error; 102747540Skarels struct nameidata nd; 10285992Swnj 102947540Skarels ndp = &nd; 103042441Smckusick ndp->ni_nameiop = LOOKUP | LOCKLEAF | NOFOLLOW; 103116694Smckusick ndp->ni_segflg = UIO_USERSPACE; 103216694Smckusick ndp->ni_dirp = uap->fname; 103347540Skarels if (error = namei(ndp, p)) 103447540Skarels return (error); 1035*48026Smckusick error = vn_stat(ndp->ni_vp, &sb, p); 103637741Smckusick vput(ndp->ni_vp); 103737741Smckusick if (error) 103847540Skarels return (error); 103937741Smckusick error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb)); 104047540Skarels return (error); 10415992Swnj } 10425992Swnj 10435992Swnj /* 10445992Swnj * Return target name of a symbolic link 104537Sbill */ 104642441Smckusick /* ARGSUSED */ 104742441Smckusick readlink(p, uap, retval) 104845914Smckusick struct proc *p; 104942441Smckusick register struct args { 10505992Swnj char *name; 10515992Swnj char *buf; 10525992Swnj int count; 105342441Smckusick } *uap; 105442441Smckusick int *retval; 105542441Smckusick { 105647540Skarels register struct nameidata *ndp; 105737741Smckusick register struct vnode *vp; 105837741Smckusick struct iovec aiov; 105937741Smckusick struct uio auio; 106037741Smckusick int error; 106147540Skarels struct nameidata nd; 10625992Swnj 106347540Skarels ndp = &nd; 106437741Smckusick ndp->ni_nameiop = LOOKUP | LOCKLEAF; 106516694Smckusick ndp->ni_segflg = UIO_USERSPACE; 106616694Smckusick ndp->ni_dirp = uap->name; 106747540Skarels if (error = namei(ndp, p)) 106847540Skarels return (error); 106937741Smckusick vp = ndp->ni_vp; 107037741Smckusick if (vp->v_type != VLNK) { 107137741Smckusick error = EINVAL; 10725992Swnj goto out; 10735992Swnj } 107437741Smckusick aiov.iov_base = uap->buf; 107537741Smckusick aiov.iov_len = uap->count; 107637741Smckusick auio.uio_iov = &aiov; 107737741Smckusick auio.uio_iovcnt = 1; 107837741Smckusick auio.uio_offset = 0; 107937741Smckusick auio.uio_rw = UIO_READ; 108037741Smckusick auio.uio_segflg = UIO_USERSPACE; 1081*48026Smckusick auio.uio_procp = p; 108237741Smckusick auio.uio_resid = uap->count; 108347540Skarels error = VOP_READLINK(vp, &auio, p->p_ucred); 10845992Swnj out: 108537741Smckusick vput(vp); 108642441Smckusick *retval = uap->count - auio.uio_resid; 108747540Skarels return (error); 10885992Swnj } 10895992Swnj 10909167Ssam /* 109138259Smckusick * Change flags of a file given path name. 109238259Smckusick */ 109342441Smckusick /* ARGSUSED */ 109442441Smckusick chflags(p, uap, retval) 109545914Smckusick struct proc *p; 109642441Smckusick register struct args { 109738259Smckusick char *fname; 109838259Smckusick int flags; 109942441Smckusick } *uap; 110042441Smckusick int *retval; 110142441Smckusick { 110247540Skarels register struct nameidata *ndp; 110338259Smckusick register struct vnode *vp; 110438259Smckusick struct vattr vattr; 110538259Smckusick int error; 110647540Skarels struct nameidata nd; 110738259Smckusick 110847540Skarels ndp = &nd; 110938259Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 111038259Smckusick ndp->ni_segflg = UIO_USERSPACE; 111138259Smckusick ndp->ni_dirp = uap->fname; 111247540Skarels if (error = namei(ndp, p)) 111347540Skarels return (error); 111438259Smckusick vp = ndp->ni_vp; 111541400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 111638259Smckusick error = EROFS; 111738259Smckusick goto out; 111838259Smckusick } 111945785Sbostic VATTR_NULL(&vattr); 112045785Sbostic vattr.va_flags = uap->flags; 1121*48026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 112238259Smckusick out: 112338259Smckusick vput(vp); 112447540Skarels return (error); 112538259Smckusick } 112638259Smckusick 112738259Smckusick /* 112838259Smckusick * Change flags of a file given a file descriptor. 112938259Smckusick */ 113042441Smckusick /* ARGSUSED */ 113142441Smckusick fchflags(p, uap, retval) 113245914Smckusick struct proc *p; 113342441Smckusick register struct args { 113438259Smckusick int fd; 113538259Smckusick int flags; 113642441Smckusick } *uap; 113742441Smckusick int *retval; 113842441Smckusick { 113938259Smckusick struct vattr vattr; 114038259Smckusick struct vnode *vp; 114138259Smckusick struct file *fp; 114238259Smckusick int error; 114338259Smckusick 114445914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 114547540Skarels return (error); 114638259Smckusick vp = (struct vnode *)fp->f_data; 114738259Smckusick VOP_LOCK(vp); 114841400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 114938259Smckusick error = EROFS; 115038259Smckusick goto out; 115138259Smckusick } 115245785Sbostic VATTR_NULL(&vattr); 115345785Sbostic vattr.va_flags = uap->flags; 1154*48026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 115538259Smckusick out: 115638259Smckusick VOP_UNLOCK(vp); 115747540Skarels return (error); 115838259Smckusick } 115938259Smckusick 116038259Smckusick /* 11619167Ssam * Change mode of a file given path name. 11629167Ssam */ 116342441Smckusick /* ARGSUSED */ 116442441Smckusick chmod(p, uap, retval) 116545914Smckusick struct proc *p; 116642441Smckusick register struct args { 11676254Sroot char *fname; 11686254Sroot int fmode; 116942441Smckusick } *uap; 117042441Smckusick int *retval; 117142441Smckusick { 117247540Skarels register struct nameidata *ndp; 117337741Smckusick register struct vnode *vp; 117437741Smckusick struct vattr vattr; 117537741Smckusick int error; 117647540Skarels struct nameidata nd; 11775992Swnj 117847540Skarels ndp = &nd; 117937741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 118037741Smckusick ndp->ni_segflg = UIO_USERSPACE; 118137741Smckusick ndp->ni_dirp = uap->fname; 118247540Skarels if (error = namei(ndp, p)) 118347540Skarels return (error); 118437741Smckusick vp = ndp->ni_vp; 118541400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 118637741Smckusick error = EROFS; 118737741Smckusick goto out; 118837741Smckusick } 118945785Sbostic VATTR_NULL(&vattr); 119045785Sbostic vattr.va_mode = uap->fmode & 07777; 1191*48026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 119237741Smckusick out: 119337741Smckusick vput(vp); 119447540Skarels return (error); 11957701Ssam } 11967439Sroot 11979167Ssam /* 11989167Ssam * Change mode of a file given a file descriptor. 11999167Ssam */ 120042441Smckusick /* ARGSUSED */ 120142441Smckusick fchmod(p, uap, retval) 120245914Smckusick struct proc *p; 120342441Smckusick register struct args { 12047701Ssam int fd; 12057701Ssam int fmode; 120642441Smckusick } *uap; 120742441Smckusick int *retval; 120842441Smckusick { 120937741Smckusick struct vattr vattr; 121037741Smckusick struct vnode *vp; 121137741Smckusick struct file *fp; 121237741Smckusick int error; 12137701Ssam 121445914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 121547540Skarels return (error); 121637741Smckusick vp = (struct vnode *)fp->f_data; 121737741Smckusick VOP_LOCK(vp); 121841400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 121937741Smckusick error = EROFS; 122037741Smckusick goto out; 12217439Sroot } 122245785Sbostic VATTR_NULL(&vattr); 122345785Sbostic vattr.va_mode = uap->fmode & 07777; 1224*48026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 122537741Smckusick out: 122637741Smckusick VOP_UNLOCK(vp); 122747540Skarels return (error); 12285992Swnj } 12295992Swnj 12309167Ssam /* 12319167Ssam * Set ownership given a path name. 12329167Ssam */ 123342441Smckusick /* ARGSUSED */ 123442441Smckusick chown(p, uap, retval) 123545914Smckusick struct proc *p; 123642441Smckusick register struct args { 12376254Sroot char *fname; 12386254Sroot int uid; 12396254Sroot int gid; 124042441Smckusick } *uap; 124142441Smckusick int *retval; 124242441Smckusick { 124347540Skarels register struct nameidata *ndp; 124437741Smckusick register struct vnode *vp; 124537741Smckusick struct vattr vattr; 124637741Smckusick int error; 124747540Skarels struct nameidata nd; 124837Sbill 124947540Skarels ndp = &nd; 125037741Smckusick ndp->ni_nameiop = LOOKUP | NOFOLLOW | LOCKLEAF; 125136614Sbostic ndp->ni_segflg = UIO_USERSPACE; 125236614Sbostic ndp->ni_dirp = uap->fname; 125347540Skarels if (error = namei(ndp, p)) 125447540Skarels return (error); 125537741Smckusick vp = ndp->ni_vp; 125641400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 125737741Smckusick error = EROFS; 125837741Smckusick goto out; 125937741Smckusick } 126045785Sbostic VATTR_NULL(&vattr); 126145785Sbostic vattr.va_uid = uap->uid; 126245785Sbostic vattr.va_gid = uap->gid; 1263*48026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 126437741Smckusick out: 126537741Smckusick vput(vp); 126647540Skarels return (error); 12677701Ssam } 12687439Sroot 12699167Ssam /* 12709167Ssam * Set ownership given a file descriptor. 12719167Ssam */ 127242441Smckusick /* ARGSUSED */ 127342441Smckusick fchown(p, uap, retval) 127445914Smckusick struct proc *p; 127542441Smckusick register struct args { 12767701Ssam int fd; 12777701Ssam int uid; 12787701Ssam int gid; 127942441Smckusick } *uap; 128042441Smckusick int *retval; 128142441Smckusick { 128237741Smckusick struct vattr vattr; 128337741Smckusick struct vnode *vp; 128437741Smckusick struct file *fp; 128537741Smckusick int error; 12867701Ssam 128745914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 128847540Skarels return (error); 128937741Smckusick vp = (struct vnode *)fp->f_data; 129037741Smckusick VOP_LOCK(vp); 129141400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 129237741Smckusick error = EROFS; 129337741Smckusick goto out; 129437741Smckusick } 129545785Sbostic VATTR_NULL(&vattr); 129645785Sbostic vattr.va_uid = uap->uid; 129745785Sbostic vattr.va_gid = uap->gid; 1298*48026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 129937741Smckusick out: 130037741Smckusick VOP_UNLOCK(vp); 130147540Skarels return (error); 13027701Ssam } 13037701Ssam 130442441Smckusick /* 130542441Smckusick * Set the access and modification times of a file. 130642441Smckusick */ 130742441Smckusick /* ARGSUSED */ 130842441Smckusick utimes(p, uap, retval) 130945914Smckusick struct proc *p; 131042441Smckusick register struct args { 131111811Ssam char *fname; 131211811Ssam struct timeval *tptr; 131342441Smckusick } *uap; 131442441Smckusick int *retval; 131542441Smckusick { 131647540Skarels register struct nameidata *ndp; 131737741Smckusick register struct vnode *vp; 131811811Ssam struct timeval tv[2]; 131937741Smckusick struct vattr vattr; 132037741Smckusick int error; 132147540Skarels struct nameidata nd; 132211811Ssam 132337741Smckusick if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv))) 132447540Skarels return (error); 132547540Skarels ndp = &nd; 132637741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 132737741Smckusick ndp->ni_segflg = UIO_USERSPACE; 132837741Smckusick ndp->ni_dirp = uap->fname; 132947540Skarels if (error = namei(ndp, p)) 133047540Skarels return (error); 133137741Smckusick vp = ndp->ni_vp; 133241400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 133337741Smckusick error = EROFS; 133437741Smckusick goto out; 133521015Smckusick } 133645785Sbostic VATTR_NULL(&vattr); 133745785Sbostic vattr.va_atime = tv[0]; 133845785Sbostic vattr.va_mtime = tv[1]; 1339*48026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 134037741Smckusick out: 134137741Smckusick vput(vp); 134247540Skarels return (error); 134311811Ssam } 134411811Ssam 13459167Ssam /* 13469167Ssam * Truncate a file given its path name. 13479167Ssam */ 134842441Smckusick /* ARGSUSED */ 134942441Smckusick truncate(p, uap, retval) 135045914Smckusick struct proc *p; 135142441Smckusick register struct args { 13527701Ssam char *fname; 135326473Skarels off_t length; 135442441Smckusick } *uap; 135542441Smckusick int *retval; 135642441Smckusick { 135747540Skarels register struct nameidata *ndp; 135837741Smckusick register struct vnode *vp; 135937741Smckusick struct vattr vattr; 136037741Smckusick int error; 136147540Skarels struct nameidata nd; 13627701Ssam 136347540Skarels ndp = &nd; 136437741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 136516694Smckusick ndp->ni_segflg = UIO_USERSPACE; 136616694Smckusick ndp->ni_dirp = uap->fname; 136747540Skarels if (error = namei(ndp, p)) 136847540Skarels return (error); 136937741Smckusick vp = ndp->ni_vp; 137037741Smckusick if (vp->v_type == VDIR) { 137137741Smckusick error = EISDIR; 137237741Smckusick goto out; 13737701Ssam } 137438399Smckusick if ((error = vn_writechk(vp)) || 1375*48026Smckusick (error = VOP_ACCESS(vp, VWRITE, p->p_ucred, p))) 137637741Smckusick goto out; 137745785Sbostic VATTR_NULL(&vattr); 137845785Sbostic vattr.va_size = uap->length; 1379*48026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 138037741Smckusick out: 138137741Smckusick vput(vp); 138247540Skarels return (error); 13837701Ssam } 13847701Ssam 13859167Ssam /* 13869167Ssam * Truncate a file given a file descriptor. 13879167Ssam */ 138842441Smckusick /* ARGSUSED */ 138942441Smckusick ftruncate(p, uap, retval) 139045914Smckusick struct proc *p; 139142441Smckusick register struct args { 13927701Ssam int fd; 139326473Skarels off_t length; 139442441Smckusick } *uap; 139542441Smckusick int *retval; 139642441Smckusick { 139737741Smckusick struct vattr vattr; 139837741Smckusick struct vnode *vp; 13997701Ssam struct file *fp; 140037741Smckusick int error; 14017701Ssam 140245914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 140347540Skarels return (error); 140437741Smckusick if ((fp->f_flag & FWRITE) == 0) 140547540Skarels return (EINVAL); 140637741Smckusick vp = (struct vnode *)fp->f_data; 140737741Smckusick VOP_LOCK(vp); 140837741Smckusick if (vp->v_type == VDIR) { 140937741Smckusick error = EISDIR; 141037741Smckusick goto out; 14117701Ssam } 141238399Smckusick if (error = vn_writechk(vp)) 141337741Smckusick goto out; 141445785Sbostic VATTR_NULL(&vattr); 141545785Sbostic vattr.va_size = uap->length; 1416*48026Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred, p); 141737741Smckusick out: 141837741Smckusick VOP_UNLOCK(vp); 141947540Skarels return (error); 14207701Ssam } 14217701Ssam 14229167Ssam /* 14239167Ssam * Synch an open file. 14249167Ssam */ 142542441Smckusick /* ARGSUSED */ 142642441Smckusick fsync(p, uap, retval) 142745914Smckusick struct proc *p; 142842441Smckusick struct args { 142942441Smckusick int fd; 143042441Smckusick } *uap; 143142441Smckusick int *retval; 14329167Ssam { 143339592Smckusick register struct vnode *vp; 14349167Ssam struct file *fp; 143537741Smckusick int error; 14369167Ssam 143745914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 143847540Skarels return (error); 143939592Smckusick vp = (struct vnode *)fp->f_data; 144039592Smckusick VOP_LOCK(vp); 1441*48026Smckusick error = VOP_FSYNC(vp, fp->f_flag, fp->f_cred, MNT_WAIT, p); 144239592Smckusick VOP_UNLOCK(vp); 144347540Skarels return (error); 14449167Ssam } 14459167Ssam 14469167Ssam /* 14479167Ssam * Rename system call. 14489167Ssam * 14499167Ssam * Source and destination must either both be directories, or both 14509167Ssam * not be directories. If target is a directory, it must be empty. 14519167Ssam */ 145242441Smckusick /* ARGSUSED */ 145342441Smckusick rename(p, uap, retval) 145445914Smckusick struct proc *p; 145542441Smckusick register struct args { 14567701Ssam char *from; 14577701Ssam char *to; 145842441Smckusick } *uap; 145942441Smckusick int *retval; 146042441Smckusick { 146137741Smckusick register struct vnode *tvp, *fvp, *tdvp; 146247540Skarels register struct nameidata *ndp; 146337741Smckusick int error; 146447540Skarels struct nameidata nd, tond; 14657701Ssam 146647540Skarels ndp = &nd; 146737741Smckusick ndp->ni_nameiop = DELETE | WANTPARENT; 146816694Smckusick ndp->ni_segflg = UIO_USERSPACE; 146916694Smckusick ndp->ni_dirp = uap->from; 147047540Skarels if (error = namei(ndp, p)) 147147540Skarels return (error); 147237741Smckusick fvp = ndp->ni_vp; 147338266Smckusick nddup(ndp, &tond); 147437741Smckusick tond.ni_nameiop = RENAME | LOCKPARENT | LOCKLEAF | NOCACHE; 147537741Smckusick tond.ni_segflg = UIO_USERSPACE; 147637741Smckusick tond.ni_dirp = uap->to; 147747540Skarels if (error = namei(&tond, p)) { 147842465Smckusick VOP_ABORTOP(ndp); 147942465Smckusick vrele(ndp->ni_dvp); 148042465Smckusick vrele(fvp); 148142465Smckusick goto out1; 148242465Smckusick } 148337741Smckusick tdvp = tond.ni_dvp; 148437741Smckusick tvp = tond.ni_vp; 148537741Smckusick if (tvp != NULL) { 148637741Smckusick if (fvp->v_type == VDIR && tvp->v_type != VDIR) { 148739242Sbostic error = ENOTDIR; 148837741Smckusick goto out; 148937741Smckusick } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) { 149039242Sbostic error = EISDIR; 149137741Smckusick goto out; 14929167Ssam } 149345240Smckusick if (fvp->v_mount != tvp->v_mount) { 149445240Smckusick error = EXDEV; 149545240Smckusick goto out; 149645240Smckusick } 14979167Ssam } 149837741Smckusick if (fvp->v_mount != tdvp->v_mount) { 149937741Smckusick error = EXDEV; 15009167Ssam goto out; 150110051Ssam } 150239286Smckusick if (fvp == tdvp) 150337741Smckusick error = EINVAL; 150439286Smckusick /* 150539286Smckusick * If source is the same as the destination, 150639286Smckusick * then there is nothing to do. 150739286Smckusick */ 150839286Smckusick if (fvp == tvp) 150939286Smckusick error = -1; 151037741Smckusick out: 151142465Smckusick if (!error) { 1512*48026Smckusick error = VOP_RENAME(ndp, &tond, p); 151342465Smckusick } else { 151437741Smckusick VOP_ABORTOP(&tond); 151543344Smckusick if (tdvp == tvp) 151643344Smckusick vrele(tdvp); 151743344Smckusick else 151843344Smckusick vput(tdvp); 151942465Smckusick if (tvp) 152042465Smckusick vput(tvp); 152137741Smckusick VOP_ABORTOP(ndp); 152242465Smckusick vrele(ndp->ni_dvp); 152342465Smckusick vrele(fvp); 15249167Ssam } 152537741Smckusick out1: 152638266Smckusick ndrele(&tond); 152739286Smckusick if (error == -1) 152847540Skarels return (0); 152947540Skarels return (error); 15307701Ssam } 15317701Ssam 15327535Sroot /* 153312756Ssam * Mkdir system call 153412756Ssam */ 153542441Smckusick /* ARGSUSED */ 153642441Smckusick mkdir(p, uap, retval) 153745914Smckusick struct proc *p; 153842441Smckusick register struct args { 153912756Ssam char *name; 154012756Ssam int dmode; 154142441Smckusick } *uap; 154242441Smckusick int *retval; 154342441Smckusick { 154447540Skarels register struct nameidata *ndp; 154537741Smckusick register struct vnode *vp; 154637741Smckusick struct vattr vattr; 154737741Smckusick int error; 154847540Skarels struct nameidata nd; 154912756Ssam 155047540Skarels ndp = &nd; 155137741Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 155216694Smckusick ndp->ni_segflg = UIO_USERSPACE; 155316694Smckusick ndp->ni_dirp = uap->name; 155447540Skarels if (error = namei(ndp, p)) 155547540Skarels return (error); 155637741Smckusick vp = ndp->ni_vp; 155737741Smckusick if (vp != NULL) { 155837741Smckusick VOP_ABORTOP(ndp); 155943344Smckusick if (ndp->ni_dvp == vp) 156043344Smckusick vrele(ndp->ni_dvp); 156143344Smckusick else 156243344Smckusick vput(ndp->ni_dvp); 156342465Smckusick vrele(vp); 156447540Skarels return (EEXIST); 156512756Ssam } 156641362Smckusick VATTR_NULL(&vattr); 156737741Smckusick vattr.va_type = VDIR; 156845914Smckusick vattr.va_mode = (uap->dmode & 0777) &~ p->p_fd->fd_cmask; 1569*48026Smckusick error = VOP_MKDIR(ndp, &vattr, p); 157038145Smckusick if (!error) 157138145Smckusick vput(ndp->ni_vp); 157247540Skarels return (error); 157312756Ssam } 157412756Ssam 157512756Ssam /* 157612756Ssam * Rmdir system call. 157712756Ssam */ 157842441Smckusick /* ARGSUSED */ 157942441Smckusick rmdir(p, uap, retval) 158045914Smckusick struct proc *p; 158142441Smckusick struct args { 158242441Smckusick char *name; 158342441Smckusick } *uap; 158442441Smckusick int *retval; 158512756Ssam { 158647540Skarels register struct nameidata *ndp; 158737741Smckusick register struct vnode *vp; 158837741Smckusick int error; 158947540Skarels struct nameidata nd; 159012756Ssam 159147540Skarels ndp = &nd; 159237741Smckusick ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF; 159316694Smckusick ndp->ni_segflg = UIO_USERSPACE; 159416694Smckusick ndp->ni_dirp = uap->name; 159547540Skarels if (error = namei(ndp, p)) 159647540Skarels return (error); 159737741Smckusick vp = ndp->ni_vp; 159837741Smckusick if (vp->v_type != VDIR) { 159937741Smckusick error = ENOTDIR; 160012756Ssam goto out; 160112756Ssam } 160212756Ssam /* 160337741Smckusick * No rmdir "." please. 160412756Ssam */ 160537741Smckusick if (ndp->ni_dvp == vp) { 160637741Smckusick error = EINVAL; 160712756Ssam goto out; 160812756Ssam } 160912756Ssam /* 161037741Smckusick * Don't unlink a mounted file. 161112756Ssam */ 161237741Smckusick if (vp->v_flag & VROOT) 161337741Smckusick error = EBUSY; 161412756Ssam out: 161542465Smckusick if (!error) { 1616*48026Smckusick error = VOP_RMDIR(ndp, p); 161742465Smckusick } else { 161837741Smckusick VOP_ABORTOP(ndp); 161943344Smckusick if (ndp->ni_dvp == vp) 162043344Smckusick vrele(ndp->ni_dvp); 162143344Smckusick else 162243344Smckusick vput(ndp->ni_dvp); 162342465Smckusick vput(vp); 162442465Smckusick } 162547540Skarels return (error); 162612756Ssam } 162712756Ssam 162837741Smckusick /* 162937741Smckusick * Read a block of directory entries in a file system independent format 163037741Smckusick */ 163142441Smckusick getdirentries(p, uap, retval) 163245914Smckusick struct proc *p; 163342441Smckusick register struct args { 163437741Smckusick int fd; 163537741Smckusick char *buf; 163637741Smckusick unsigned count; 163737741Smckusick long *basep; 163842441Smckusick } *uap; 163942441Smckusick int *retval; 164042441Smckusick { 164139592Smckusick register struct vnode *vp; 164216540Ssam struct file *fp; 164337741Smckusick struct uio auio; 164437741Smckusick struct iovec aiov; 164538129Smckusick off_t off; 164640321Smckusick int error, eofflag; 164712756Ssam 164845914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 164947540Skarels return (error); 165037741Smckusick if ((fp->f_flag & FREAD) == 0) 165147540Skarels return (EBADF); 165239592Smckusick vp = (struct vnode *)fp->f_data; 165339592Smckusick if (vp->v_type != VDIR) 165447540Skarels return (EINVAL); 165537741Smckusick aiov.iov_base = uap->buf; 165637741Smckusick aiov.iov_len = uap->count; 165737741Smckusick auio.uio_iov = &aiov; 165837741Smckusick auio.uio_iovcnt = 1; 165937741Smckusick auio.uio_rw = UIO_READ; 166037741Smckusick auio.uio_segflg = UIO_USERSPACE; 1661*48026Smckusick auio.uio_procp = p; 166237741Smckusick auio.uio_resid = uap->count; 166339592Smckusick VOP_LOCK(vp); 166439592Smckusick auio.uio_offset = off = fp->f_offset; 166540321Smckusick error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag); 166639592Smckusick fp->f_offset = auio.uio_offset; 166739592Smckusick VOP_UNLOCK(vp); 166839592Smckusick if (error) 166947540Skarels return (error); 167039592Smckusick error = copyout((caddr_t)&off, (caddr_t)uap->basep, sizeof(long)); 167142441Smckusick *retval = uap->count - auio.uio_resid; 167247540Skarels return (error); 167312756Ssam } 167412756Ssam 167512756Ssam /* 167612756Ssam * mode mask for creation of files 167712756Ssam */ 167842441Smckusick mode_t 167942441Smckusick umask(p, uap, retval) 168045914Smckusick struct proc *p; 168142441Smckusick struct args { 168242441Smckusick int mask; 168342441Smckusick } *uap; 168442441Smckusick int *retval; 168512756Ssam { 168645914Smckusick register struct filedesc *fdp = p->p_fd; 168712756Ssam 168845914Smckusick *retval = fdp->fd_cmask; 168945914Smckusick fdp->fd_cmask = uap->mask & 07777; 169047540Skarels return (0); 169112756Ssam } 169237741Smckusick 169339566Smarc /* 169439566Smarc * Void all references to file by ripping underlying filesystem 169539566Smarc * away from vnode. 169639566Smarc */ 169742441Smckusick /* ARGSUSED */ 169842441Smckusick revoke(p, uap, retval) 169945914Smckusick struct proc *p; 170042441Smckusick register struct args { 170139566Smarc char *fname; 170242441Smckusick } *uap; 170342441Smckusick int *retval; 170442441Smckusick { 170547540Skarels register struct nameidata *ndp; 170639566Smarc register struct vnode *vp; 170739566Smarc struct vattr vattr; 170839566Smarc int error; 170947540Skarels struct nameidata nd; 171039566Smarc 171147540Skarels ndp = &nd; 171239566Smarc ndp->ni_nameiop = LOOKUP | FOLLOW; 171339566Smarc ndp->ni_segflg = UIO_USERSPACE; 171439566Smarc ndp->ni_dirp = uap->fname; 171547540Skarels if (error = namei(ndp, p)) 171647540Skarels return (error); 171739566Smarc vp = ndp->ni_vp; 171839566Smarc if (vp->v_type != VCHR && vp->v_type != VBLK) { 171939566Smarc error = EINVAL; 172039566Smarc goto out; 172139566Smarc } 1722*48026Smckusick if (error = VOP_GETATTR(vp, &vattr, p->p_ucred, p)) 172339566Smarc goto out; 172447540Skarels if (p->p_ucred->cr_uid != vattr.va_uid && 172547540Skarels (error = suser(p->p_ucred, &p->p_acflag))) 172639566Smarc goto out; 172739805Smckusick if (vp->v_usecount > 1 || (vp->v_flag & VALIASED)) 172839632Smckusick vgoneall(vp); 172939566Smarc out: 173039566Smarc vrele(vp); 173147540Skarels return (error); 173239566Smarc } 173339566Smarc 173445914Smckusick getvnode(fdp, fdes, fpp) 173545914Smckusick struct filedesc *fdp; 173637741Smckusick struct file **fpp; 173737741Smckusick int fdes; 173837741Smckusick { 173937741Smckusick struct file *fp; 174037741Smckusick 174147540Skarels if ((unsigned)fdes >= fdp->fd_nfiles || 174247688Skarels (fp = fdp->fd_ofiles[fdes]) == NULL) 174337741Smckusick return (EBADF); 174437741Smckusick if (fp->f_type != DTYPE_VNODE) 174537741Smckusick return (EINVAL); 174637741Smckusick *fpp = fp; 174737741Smckusick return (0); 174837741Smckusick } 1749