123405Smckusick /* 237741Smckusick * Copyright (c) 1989 The Regents of the University of California. 337741Smckusick * All rights reserved. 423405Smckusick * 544459Sbostic * %sccs.include.redist.c% 637741Smckusick * 7*46553Skarels * @(#)vfs_syscalls.c 7.64 (Berkeley) 02/22/91 823405Smckusick */ 937Sbill 1017101Sbloom #include "param.h" 1117101Sbloom #include "systm.h" 1244407Skarels #include "user.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 2343450Smckusick #define RETURN(val) {if (u.u_spare[0] != 0) panic("lock count"); return (val);} 2439797Smckusick 2537741Smckusick /* 2637741Smckusick * Virtual File System System Calls 2737741Smckusick */ 2812756Ssam 299167Ssam /* 3037741Smckusick * mount system call 319167Ssam */ 3242441Smckusick /* ARGSUSED */ 3342441Smckusick mount(p, uap, retval) 3445914Smckusick struct proc *p; 3542441Smckusick register struct args { 3637741Smckusick int type; 3737741Smckusick char *dir; 3837741Smckusick int flags; 3937741Smckusick caddr_t data; 4042441Smckusick } *uap; 4142441Smckusick int *retval; 4242441Smckusick { 4342441Smckusick register struct nameidata *ndp = &u.u_nd; 4439335Smckusick register struct vnode *vp; 4539335Smckusick register struct mount *mp; 4640111Smckusick int error, flag; 476254Sroot 4837741Smckusick /* 4937741Smckusick * Must be super user 5037741Smckusick */ 5142441Smckusick if (error = suser(ndp->ni_cred, &u.u_acflag)) 5237741Smckusick RETURN (error); 5337741Smckusick /* 5437741Smckusick * Get vnode to be covered 5537741Smckusick */ 5637741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 5737741Smckusick ndp->ni_segflg = UIO_USERSPACE; 5837741Smckusick ndp->ni_dirp = uap->dir; 5937741Smckusick if (error = namei(ndp)) 6037741Smckusick RETURN (error); 6137741Smckusick vp = ndp->ni_vp; 6241400Smckusick if (uap->flags & MNT_UPDATE) { 6339335Smckusick if ((vp->v_flag & VROOT) == 0) { 6439335Smckusick vput(vp); 6539335Smckusick 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); 7539335Smckusick 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); 8537741Smckusick RETURN (EBUSY); 8637741Smckusick } 8737741Smckusick if (vp->v_type != VDIR) { 8837741Smckusick vput(vp); 8937741Smckusick RETURN (ENOTDIR); 9037741Smckusick } 9139741Smckusick if ((unsigned long)uap->type > MOUNT_MAXTYPE || 9237741Smckusick vfssw[uap->type] == (struct vfsops *)0) { 9337741Smckusick vput(vp); 9437741Smckusick 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); 10939335Smckusick 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); 11539335Smckusick 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; 15239335Smckusick 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 } 17137741Smckusick 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; 19042441Smckusick register struct nameidata *ndp = &u.u_nd; 19139356Smckusick struct mount *mp; 19237741Smckusick int error; 1936254Sroot 19437741Smckusick /* 19537741Smckusick * Must be super user 19637741Smckusick */ 19742441Smckusick if (error = suser(ndp->ni_cred, &u.u_acflag)) 19837741Smckusick RETURN (error); 19937741Smckusick 20037741Smckusick ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW; 20137741Smckusick ndp->ni_segflg = UIO_USERSPACE; 20237741Smckusick ndp->ni_dirp = uap->pathp; 20337741Smckusick if (error = namei(ndp)) 20437741Smckusick RETURN (error); 20537741Smckusick vp = ndp->ni_vp; 20637741Smckusick /* 20737741Smckusick * Must be the root of the filesystem 20837741Smckusick */ 20937741Smckusick if ((vp->v_flag & VROOT) == 0) { 21037741Smckusick vput(vp); 21137741Smckusick RETURN (EINVAL); 21237741Smckusick } 21337741Smckusick mp = vp->v_mount; 21437741Smckusick vput(vp); 21539356Smckusick RETURN (dounmount(mp, uap->flags)); 21639356Smckusick } 21739356Smckusick 21839356Smckusick /* 21939356Smckusick * Do an unmount. 22039356Smckusick */ 22139356Smckusick dounmount(mp, flags) 22239356Smckusick register struct mount *mp; 22339356Smckusick int flags; 22439356Smckusick { 22539356Smckusick struct vnode *coveredvp; 22639356Smckusick int error; 22739356Smckusick 22841400Smckusick coveredvp = mp->mnt_vnodecovered; 22941298Smckusick if (vfs_busy(mp)) 23041298Smckusick return (EBUSY); 23141400Smckusick mp->mnt_flag |= MNT_UNMOUNT; 23237741Smckusick if (error = vfs_lock(mp)) 23339356Smckusick return (error); 23437741Smckusick 23545922Smckusick #ifdef NVM 23645738Smckusick vnode_pager_umount(mp); /* release cached vnodes */ 23745922Smckusick #else 23845922Smckusick xumount(mp); /* remove unused sticky files from text table */ 23945922Smckusick #endif 24037741Smckusick cache_purgevfs(mp); /* remove cache entries for this file sys */ 24141676Smckusick if ((error = VFS_SYNC(mp, MNT_WAIT)) == 0 || (flags & MNT_FORCE)) 24241676Smckusick error = VFS_UNMOUNT(mp, flags); 24341400Smckusick mp->mnt_flag &= ~MNT_UNMOUNT; 24441298Smckusick vfs_unbusy(mp); 24537741Smckusick if (error) { 24637741Smckusick vfs_unlock(mp); 24737741Smckusick } else { 24837741Smckusick vrele(coveredvp); 24937741Smckusick vfs_remove(mp); 25037741Smckusick free((caddr_t)mp, M_MOUNT); 25137741Smckusick } 25239356Smckusick return (error); 2536254Sroot } 2546254Sroot 2559167Ssam /* 25637741Smckusick * Sync system call. 25737741Smckusick * Sync each mounted filesystem. 2589167Ssam */ 25939491Smckusick /* ARGSUSED */ 26042441Smckusick sync(p, uap, retval) 26145914Smckusick struct proc *p; 26242441Smckusick struct args *uap; 26342441Smckusick int *retval; 2646254Sroot { 26537741Smckusick register struct mount *mp; 26641298Smckusick struct mount *omp; 26737741Smckusick 26837741Smckusick mp = rootfs; 26937741Smckusick do { 27040343Smckusick /* 27140343Smckusick * The lock check below is to avoid races with mount 27240343Smckusick * and unmount. 27340343Smckusick */ 27441400Smckusick if ((mp->mnt_flag & (MNT_MLOCK|MNT_RDONLY|MNT_MPBUSY)) == 0 && 27541298Smckusick !vfs_busy(mp)) { 27637741Smckusick VFS_SYNC(mp, MNT_NOWAIT); 27741298Smckusick omp = mp; 27841400Smckusick mp = mp->mnt_next; 27941298Smckusick vfs_unbusy(omp); 28041298Smckusick } else 28141400Smckusick mp = mp->mnt_next; 28237741Smckusick } while (mp != rootfs); 28337741Smckusick } 28437741Smckusick 28537741Smckusick /* 28641298Smckusick * operate on filesystem quotas 28741298Smckusick */ 28842441Smckusick /* ARGSUSED */ 28942441Smckusick quotactl(p, uap, retval) 29045914Smckusick struct proc *p; 29142441Smckusick register struct args { 29241298Smckusick char *path; 29341298Smckusick int cmd; 29441298Smckusick int uid; 29541298Smckusick caddr_t arg; 29642441Smckusick } *uap; 29742441Smckusick int *retval; 29842441Smckusick { 29941298Smckusick register struct mount *mp; 30042441Smckusick register struct nameidata *ndp = &u.u_nd; 30141298Smckusick int error; 30241298Smckusick 30341298Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW; 30441298Smckusick ndp->ni_segflg = UIO_USERSPACE; 30541298Smckusick ndp->ni_dirp = uap->path; 30641298Smckusick if (error = namei(ndp)) 30741298Smckusick RETURN (error); 30841298Smckusick mp = ndp->ni_vp->v_mount; 30941298Smckusick vrele(ndp->ni_vp); 31041298Smckusick RETURN (VFS_QUOTACTL(mp, uap->cmd, uap->uid, uap->arg)); 31141298Smckusick } 31241298Smckusick 31341298Smckusick /* 31437741Smckusick * get filesystem statistics 31537741Smckusick */ 31642441Smckusick /* ARGSUSED */ 31742441Smckusick statfs(p, uap, retval) 31845914Smckusick struct proc *p; 31942441Smckusick register struct args { 32037741Smckusick char *path; 32137741Smckusick struct statfs *buf; 32242441Smckusick } *uap; 32342441Smckusick int *retval; 32442441Smckusick { 32539464Smckusick register struct mount *mp; 32642441Smckusick register struct nameidata *ndp = &u.u_nd; 32740343Smckusick register struct statfs *sp; 32837741Smckusick int error; 32937741Smckusick 33039544Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW; 33137741Smckusick ndp->ni_segflg = UIO_USERSPACE; 33237741Smckusick ndp->ni_dirp = uap->path; 33337741Smckusick if (error = namei(ndp)) 33437741Smckusick RETURN (error); 33539544Smckusick mp = ndp->ni_vp->v_mount; 33641400Smckusick sp = &mp->mnt_stat; 33739544Smckusick vrele(ndp->ni_vp); 33840343Smckusick if (error = VFS_STATFS(mp, sp)) 33939544Smckusick RETURN (error); 34041400Smckusick sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 34140343Smckusick RETURN (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp))); 34237741Smckusick } 34337741Smckusick 34442441Smckusick /* 34542441Smckusick * get filesystem statistics 34642441Smckusick */ 34742441Smckusick /* ARGSUSED */ 34842441Smckusick fstatfs(p, uap, retval) 34945914Smckusick struct proc *p; 35042441Smckusick register struct args { 35137741Smckusick int fd; 35237741Smckusick struct statfs *buf; 35342441Smckusick } *uap; 35442441Smckusick int *retval; 35542441Smckusick { 35637741Smckusick struct file *fp; 35739464Smckusick struct mount *mp; 35840343Smckusick register struct statfs *sp; 35937741Smckusick int error; 36037741Smckusick 36145914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 36237741Smckusick RETURN (error); 36339464Smckusick mp = ((struct vnode *)fp->f_data)->v_mount; 36441400Smckusick sp = &mp->mnt_stat; 36540343Smckusick if (error = VFS_STATFS(mp, sp)) 36637741Smckusick RETURN (error); 36741400Smckusick sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 36840343Smckusick RETURN (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp))); 36937741Smckusick } 37037741Smckusick 37137741Smckusick /* 37238270Smckusick * get statistics on all filesystems 37338270Smckusick */ 37442441Smckusick getfsstat(p, uap, retval) 37545914Smckusick struct proc *p; 37642441Smckusick register struct args { 37738270Smckusick struct statfs *buf; 37838270Smckusick long bufsize; 37940343Smckusick int flags; 38042441Smckusick } *uap; 38142441Smckusick int *retval; 38242441Smckusick { 38338270Smckusick register struct mount *mp; 38440343Smckusick register struct statfs *sp; 38539606Smckusick caddr_t sfsp; 38638270Smckusick long count, maxcount, error; 38738270Smckusick 38838270Smckusick maxcount = uap->bufsize / sizeof(struct statfs); 38939606Smckusick sfsp = (caddr_t)uap->buf; 39038270Smckusick mp = rootfs; 39138270Smckusick count = 0; 39238270Smckusick do { 39341400Smckusick if (sfsp && count < maxcount && 39441400Smckusick ((mp->mnt_flag & MNT_MLOCK) == 0)) { 39541400Smckusick sp = &mp->mnt_stat; 39640343Smckusick /* 39740343Smckusick * If MNT_NOWAIT is specified, do not refresh the 39840343Smckusick * fsstat cache. MNT_WAIT overrides MNT_NOWAIT. 39940343Smckusick */ 40040343Smckusick if (((uap->flags & MNT_NOWAIT) == 0 || 40140343Smckusick (uap->flags & MNT_WAIT)) && 40240343Smckusick (error = VFS_STATFS(mp, sp))) { 40341400Smckusick mp = mp->mnt_prev; 40439607Smckusick continue; 40539607Smckusick } 40641400Smckusick sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 40740343Smckusick if (error = copyout((caddr_t)sp, sfsp, sizeof(*sp))) 40839606Smckusick RETURN (error); 40940343Smckusick sfsp += sizeof(*sp); 41038270Smckusick } 41139606Smckusick count++; 41241400Smckusick mp = mp->mnt_prev; 41338270Smckusick } while (mp != rootfs); 41438270Smckusick if (sfsp && count > maxcount) 41542441Smckusick *retval = maxcount; 41638270Smckusick else 41742441Smckusick *retval = count; 41838270Smckusick RETURN (0); 41938270Smckusick } 42038270Smckusick 42138270Smckusick /* 42238259Smckusick * Change current working directory to a given file descriptor. 42338259Smckusick */ 42442441Smckusick /* ARGSUSED */ 42542441Smckusick fchdir(p, uap, retval) 42645914Smckusick struct proc *p; 42742441Smckusick struct args { 42842441Smckusick int fd; 42942441Smckusick } *uap; 43042441Smckusick int *retval; 43138259Smckusick { 43242441Smckusick register struct nameidata *ndp = &u.u_nd; 43345914Smckusick register struct filedesc *fdp = p->p_fd; 43438259Smckusick register struct vnode *vp; 43538259Smckusick struct file *fp; 43638259Smckusick int error; 43738259Smckusick 43845914Smckusick if (error = getvnode(fdp, uap->fd, &fp)) 43938259Smckusick RETURN (error); 44038259Smckusick vp = (struct vnode *)fp->f_data; 44138259Smckusick VOP_LOCK(vp); 44238259Smckusick if (vp->v_type != VDIR) 44338259Smckusick error = ENOTDIR; 44438259Smckusick else 44542441Smckusick error = VOP_ACCESS(vp, VEXEC, ndp->ni_cred); 44638259Smckusick VOP_UNLOCK(vp); 44739860Smckusick if (error) 44839860Smckusick RETURN (error); 44939860Smckusick VREF(vp); 45045914Smckusick vrele(fdp->fd_cdir); 45145914Smckusick fdp->fd_cdir = vp; 45239860Smckusick RETURN (0); 45338259Smckusick } 45438259Smckusick 45538259Smckusick /* 45637741Smckusick * Change current working directory (``.''). 45737741Smckusick */ 45842441Smckusick /* ARGSUSED */ 45942441Smckusick chdir(p, uap, retval) 46045914Smckusick struct proc *p; 46142441Smckusick struct args { 46242441Smckusick char *fname; 46342441Smckusick } *uap; 46442441Smckusick int *retval; 46537741Smckusick { 46642441Smckusick register struct nameidata *ndp = &u.u_nd; 46745914Smckusick register struct filedesc *fdp = p->p_fd; 46837741Smckusick int error; 4696254Sroot 47037741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 47116694Smckusick ndp->ni_segflg = UIO_USERSPACE; 47216694Smckusick ndp->ni_dirp = uap->fname; 47337741Smckusick if (error = chdirec(ndp)) 47437741Smckusick RETURN (error); 47545914Smckusick vrele(fdp->fd_cdir); 47645914Smckusick fdp->fd_cdir = ndp->ni_vp; 47737741Smckusick RETURN (0); 47837741Smckusick } 4796254Sroot 48037741Smckusick /* 48137741Smckusick * Change notion of root (``/'') directory. 48237741Smckusick */ 48342441Smckusick /* ARGSUSED */ 48442441Smckusick chroot(p, uap, retval) 48545914Smckusick struct proc *p; 48642441Smckusick struct args { 48742441Smckusick char *fname; 48842441Smckusick } *uap; 48942441Smckusick int *retval; 49037741Smckusick { 49142441Smckusick register struct nameidata *ndp = &u.u_nd; 49245914Smckusick register struct filedesc *fdp = p->p_fd; 49337741Smckusick int error; 49437741Smckusick 49542441Smckusick if (error = suser(ndp->ni_cred, &u.u_acflag)) 49637741Smckusick RETURN (error); 49737741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 49837741Smckusick ndp->ni_segflg = UIO_USERSPACE; 49937741Smckusick ndp->ni_dirp = uap->fname; 50037741Smckusick if (error = chdirec(ndp)) 50137741Smckusick RETURN (error); 50245914Smckusick if (fdp->fd_rdir != NULL) 50345914Smckusick vrele(fdp->fd_rdir); 50445914Smckusick fdp->fd_rdir = ndp->ni_vp; 50537741Smckusick RETURN (0); 5066254Sroot } 5076254Sroot 50837Sbill /* 50937741Smckusick * Common routine for chroot and chdir. 51037741Smckusick */ 51137741Smckusick chdirec(ndp) 51237741Smckusick register struct nameidata *ndp; 51337741Smckusick { 51437741Smckusick struct vnode *vp; 51537741Smckusick int error; 51637741Smckusick 51737741Smckusick if (error = namei(ndp)) 51837741Smckusick return (error); 51937741Smckusick vp = ndp->ni_vp; 52037741Smckusick if (vp->v_type != VDIR) 52137741Smckusick error = ENOTDIR; 52237741Smckusick else 52338399Smckusick error = VOP_ACCESS(vp, VEXEC, ndp->ni_cred); 52437741Smckusick VOP_UNLOCK(vp); 52537741Smckusick if (error) 52637741Smckusick vrele(vp); 52737741Smckusick return (error); 52837741Smckusick } 52937741Smckusick 53037741Smckusick /* 5316254Sroot * Open system call. 53242441Smckusick * Check permissions, allocate an open file structure, 53342441Smckusick * and call the device open routine if any. 5346254Sroot */ 53542441Smckusick open(p, uap, retval) 53645914Smckusick struct proc *p; 53742441Smckusick register struct args { 5386254Sroot char *fname; 5397701Ssam int mode; 54012756Ssam int crtmode; 54142441Smckusick } *uap; 54242441Smckusick int *retval; 5436254Sroot { 54442441Smckusick struct nameidata *ndp = &u.u_nd; 54545914Smckusick register struct filedesc *fdp = p->p_fd; 54642441Smckusick register struct file *fp; 54737741Smckusick int fmode, cmode; 54837741Smckusick struct file *nfp; 54937741Smckusick int indx, error; 55037741Smckusick extern struct fileops vnops; 5516254Sroot 55245914Smckusick if (error = falloc(p, &nfp, &indx)) 55342441Smckusick RETURN (error); 55437741Smckusick fp = nfp; 555*46553Skarels fmode = FFLAGS(uap->mode); 55645914Smckusick cmode = ((uap->crtmode &~ fdp->fd_cmask) & 07777) &~ S_ISVTX; 55742441Smckusick ndp->ni_segflg = UIO_USERSPACE; 55842441Smckusick ndp->ni_dirp = uap->fname; 55945202Smckusick p->p_dupfd = -indx - 1; /* XXX check for fdopen */ 56042441Smckusick if (error = vn_open(ndp, fmode, cmode)) { 56137741Smckusick crfree(fp->f_cred); 56237741Smckusick fp->f_count--; 56343405Smckusick if (error == ENODEV && /* XXX from fdopen */ 56445202Smckusick p->p_dupfd >= 0 && 56545914Smckusick (error = dupfdopen(fdp, indx, p->p_dupfd, fmode)) == 0) { 56642441Smckusick *retval = indx; 56742441Smckusick RETURN (0); 56842441Smckusick } 56940884Smckusick if (error == ERESTART) 57040884Smckusick error = EINTR; 57145914Smckusick OFILE(fdp, indx) = NULL; 57242441Smckusick RETURN (error); 57312756Ssam } 57437741Smckusick fp->f_flag = fmode & FMASK; 57537741Smckusick fp->f_type = DTYPE_VNODE; 57637741Smckusick fp->f_ops = &vnops; 57737741Smckusick fp->f_data = (caddr_t)ndp->ni_vp; 57842441Smckusick *retval = indx; 57942441Smckusick RETURN (0); 5806254Sroot } 5816254Sroot 58242955Smckusick #ifdef COMPAT_43 5836254Sroot /* 58442441Smckusick * Creat system call. 5856254Sroot */ 58642955Smckusick ocreat(p, uap, retval) 58742441Smckusick struct proc *p; 58842441Smckusick register struct args { 58942441Smckusick char *fname; 59042441Smckusick int fmode; 59142441Smckusick } *uap; 59242441Smckusick int *retval; 5936254Sroot { 59442441Smckusick struct args { 5956254Sroot char *fname; 59642441Smckusick int mode; 59742441Smckusick int crtmode; 59842441Smckusick } openuap; 59942441Smckusick 60042441Smckusick openuap.fname = uap->fname; 60142441Smckusick openuap.crtmode = uap->fmode; 60242441Smckusick openuap.mode = O_WRONLY | O_CREAT | O_TRUNC; 60342441Smckusick RETURN (open(p, &openuap, retval)); 60442441Smckusick } 60542955Smckusick #endif /* COMPAT_43 */ 60642441Smckusick 60742441Smckusick /* 60842441Smckusick * Mknod system call 60942441Smckusick */ 61042441Smckusick /* ARGSUSED */ 61142441Smckusick mknod(p, uap, retval) 61245914Smckusick struct proc *p; 61342441Smckusick register struct args { 61442441Smckusick char *fname; 6156254Sroot int fmode; 6166254Sroot int dev; 61742441Smckusick } *uap; 61842441Smckusick int *retval; 61942441Smckusick { 62042441Smckusick register struct nameidata *ndp = &u.u_nd; 62137741Smckusick register struct vnode *vp; 62237741Smckusick struct vattr vattr; 62337741Smckusick int error; 6246254Sroot 62542441Smckusick if (error = suser(ndp->ni_cred, &u.u_acflag)) 62637741Smckusick RETURN (error); 62737741Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 62816694Smckusick ndp->ni_segflg = UIO_USERSPACE; 62916694Smckusick ndp->ni_dirp = uap->fname; 63037741Smckusick if (error = namei(ndp)) 63137741Smckusick RETURN (error); 63237741Smckusick vp = ndp->ni_vp; 63337741Smckusick if (vp != NULL) { 63437741Smckusick error = EEXIST; 63512756Ssam goto out; 6366254Sroot } 63741362Smckusick VATTR_NULL(&vattr); 63840635Smckusick switch (uap->fmode & S_IFMT) { 63912756Ssam 64040635Smckusick case S_IFMT: /* used by badsect to flag bad sectors */ 64137741Smckusick vattr.va_type = VBAD; 64237741Smckusick break; 64340635Smckusick case S_IFCHR: 64437741Smckusick vattr.va_type = VCHR; 64537741Smckusick break; 64640635Smckusick case S_IFBLK: 64737741Smckusick vattr.va_type = VBLK; 64837741Smckusick break; 64937741Smckusick default: 65037741Smckusick error = EINVAL; 65137741Smckusick goto out; 6526254Sroot } 65345914Smckusick vattr.va_mode = (uap->fmode & 07777) &~ p->p_fd->fd_cmask; 65437741Smckusick vattr.va_rdev = uap->dev; 6556254Sroot out: 65642465Smckusick if (!error) { 65742465Smckusick error = VOP_MKNOD(ndp, &vattr, ndp->ni_cred); 65842465Smckusick } else { 65937741Smckusick VOP_ABORTOP(ndp); 66043344Smckusick if (ndp->ni_dvp == vp) 66143344Smckusick vrele(ndp->ni_dvp); 66243344Smckusick else 66343344Smckusick vput(ndp->ni_dvp); 66442465Smckusick if (vp) 66542465Smckusick vrele(vp); 66642465Smckusick } 66737741Smckusick RETURN (error); 6686254Sroot } 6696254Sroot 6706254Sroot /* 67140285Smckusick * Mkfifo system call 67240285Smckusick */ 67342441Smckusick /* ARGSUSED */ 67442441Smckusick mkfifo(p, uap, retval) 67545914Smckusick struct proc *p; 67642441Smckusick register struct args { 67740285Smckusick char *fname; 67840285Smckusick int fmode; 67942441Smckusick } *uap; 68042441Smckusick int *retval; 68142441Smckusick { 68242441Smckusick register struct nameidata *ndp = &u.u_nd; 68340285Smckusick struct vattr vattr; 68440285Smckusick int error; 68540285Smckusick 68640285Smckusick #ifndef FIFO 68740285Smckusick RETURN (EOPNOTSUPP); 68840285Smckusick #else 68940285Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 69040285Smckusick ndp->ni_segflg = UIO_USERSPACE; 69140285Smckusick ndp->ni_dirp = uap->fname; 69240285Smckusick if (error = namei(ndp)) 69340285Smckusick RETURN (error); 69440285Smckusick if (ndp->ni_vp != NULL) { 69540285Smckusick VOP_ABORTOP(ndp); 69643344Smckusick if (ndp->ni_dvp == ndp->ni_vp) 69743344Smckusick vrele(ndp->ni_dvp); 69843344Smckusick else 69943344Smckusick vput(ndp->ni_dvp); 70042465Smckusick vrele(ndp->ni_vp); 70140285Smckusick RETURN (EEXIST); 70240285Smckusick } 70345785Sbostic VATTR_NULL(&vattr); 70445785Sbostic vattr.va_type = VFIFO; 70545914Smckusick vattr.va_mode = (uap->fmode & 07777) &~ p->p_fd->fd_cmask; 70640285Smckusick RETURN (VOP_MKNOD(ndp, &vattr, ndp->ni_cred)); 70740285Smckusick #endif /* FIFO */ 70840285Smckusick } 70940285Smckusick 71040285Smckusick /* 7116254Sroot * link system call 7126254Sroot */ 71342441Smckusick /* ARGSUSED */ 71442441Smckusick link(p, uap, retval) 71545914Smckusick struct proc *p; 71642441Smckusick register struct args { 7176254Sroot char *target; 7186254Sroot char *linkname; 71942441Smckusick } *uap; 72042441Smckusick int *retval; 72142441Smckusick { 72242441Smckusick register struct nameidata *ndp = &u.u_nd; 72337741Smckusick register struct vnode *vp, *xp; 72437741Smckusick int error; 7256254Sroot 72616694Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW; 72716694Smckusick ndp->ni_segflg = UIO_USERSPACE; 72816694Smckusick ndp->ni_dirp = uap->target; 72937741Smckusick if (error = namei(ndp)) 73037741Smckusick RETURN (error); 73137741Smckusick vp = ndp->ni_vp; 73237741Smckusick if (vp->v_type == VDIR && 73342441Smckusick (error = suser(ndp->ni_cred, &u.u_acflag))) 73437741Smckusick goto out1; 73537741Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 73616694Smckusick ndp->ni_dirp = (caddr_t)uap->linkname; 73737741Smckusick if (error = namei(ndp)) 73837741Smckusick goto out1; 73937741Smckusick xp = ndp->ni_vp; 7406254Sroot if (xp != NULL) { 74137741Smckusick error = EEXIST; 7426254Sroot goto out; 7436254Sroot } 74437741Smckusick xp = ndp->ni_dvp; 74537741Smckusick if (vp->v_mount != xp->v_mount) 74637741Smckusick error = EXDEV; 7476254Sroot out: 74842465Smckusick if (!error) { 74942465Smckusick error = VOP_LINK(vp, ndp); 75042465Smckusick } else { 75137741Smckusick VOP_ABORTOP(ndp); 75243344Smckusick if (ndp->ni_dvp == ndp->ni_vp) 75343344Smckusick vrele(ndp->ni_dvp); 75443344Smckusick else 75543344Smckusick vput(ndp->ni_dvp); 75642465Smckusick if (ndp->ni_vp) 75742465Smckusick vrele(ndp->ni_vp); 75842465Smckusick } 75937741Smckusick out1: 76037741Smckusick vrele(vp); 76137741Smckusick RETURN (error); 7626254Sroot } 7636254Sroot 7646254Sroot /* 7656254Sroot * symlink -- make a symbolic link 7666254Sroot */ 76742441Smckusick /* ARGSUSED */ 76842441Smckusick symlink(p, uap, retval) 76945914Smckusick struct proc *p; 77042441Smckusick register struct args { 7716254Sroot char *target; 7726254Sroot char *linkname; 77342441Smckusick } *uap; 77442441Smckusick int *retval; 77542441Smckusick { 77642441Smckusick register struct nameidata *ndp = &u.u_nd; 77737741Smckusick struct vattr vattr; 77837741Smckusick char *target; 77937741Smckusick int error; 7806254Sroot 78116694Smckusick ndp->ni_segflg = UIO_USERSPACE; 78216694Smckusick ndp->ni_dirp = uap->linkname; 78337741Smckusick MALLOC(target, char *, MAXPATHLEN, M_NAMEI, M_WAITOK); 78437741Smckusick if (error = copyinstr(uap->target, target, MAXPATHLEN, (u_int *)0)) 78542465Smckusick goto out; 78637741Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 78737741Smckusick if (error = namei(ndp)) 78842465Smckusick goto out; 78942465Smckusick if (ndp->ni_vp) { 79042465Smckusick VOP_ABORTOP(ndp); 79143344Smckusick if (ndp->ni_dvp == ndp->ni_vp) 79243344Smckusick vrele(ndp->ni_dvp); 79343344Smckusick else 79443344Smckusick vput(ndp->ni_dvp); 79542465Smckusick vrele(ndp->ni_vp); 79637741Smckusick error = EEXIST; 79737741Smckusick goto out; 7986254Sroot } 79941362Smckusick VATTR_NULL(&vattr); 80045914Smckusick vattr.va_mode = 0777 &~ p->p_fd->fd_cmask; 80142465Smckusick error = VOP_SYMLINK(ndp, &vattr, target); 80237741Smckusick out: 80337741Smckusick FREE(target, M_NAMEI); 80437741Smckusick RETURN (error); 8056254Sroot } 8066254Sroot 8076254Sroot /* 8086254Sroot * Unlink system call. 8096254Sroot * Hard to avoid races here, especially 8106254Sroot * in unlinking directories. 8116254Sroot */ 81242441Smckusick /* ARGSUSED */ 81342441Smckusick unlink(p, uap, retval) 81445914Smckusick struct proc *p; 81542441Smckusick struct args { 81642441Smckusick char *fname; 81742441Smckusick } *uap; 81842441Smckusick int *retval; 8196254Sroot { 82042441Smckusick register struct nameidata *ndp = &u.u_nd; 82137741Smckusick register struct vnode *vp; 82237741Smckusick int error; 8236254Sroot 82437741Smckusick ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF; 82516694Smckusick ndp->ni_segflg = UIO_USERSPACE; 82616694Smckusick ndp->ni_dirp = uap->fname; 82737741Smckusick if (error = namei(ndp)) 82837741Smckusick RETURN (error); 82937741Smckusick vp = ndp->ni_vp; 83037741Smckusick if (vp->v_type == VDIR && 83142441Smckusick (error = suser(ndp->ni_cred, &u.u_acflag))) 8326254Sroot goto out; 8336254Sroot /* 8346254Sroot * Don't unlink a mounted file. 8356254Sroot */ 83637741Smckusick if (vp->v_flag & VROOT) { 83737741Smckusick error = EBUSY; 8386254Sroot goto out; 8396254Sroot } 84045922Smckusick #ifdef NVM 84145738Smckusick (void) vnode_pager_uncache(vp); 84245922Smckusick #else 84345922Smckusick if (vp->v_flag & VTEXT) 84445922Smckusick xrele(vp); /* try once to free text */ 84545922Smckusick #endif 8466254Sroot out: 84742465Smckusick if (!error) { 84842465Smckusick error = VOP_REMOVE(ndp); 84942465Smckusick } else { 85037741Smckusick VOP_ABORTOP(ndp); 85143344Smckusick if (ndp->ni_dvp == vp) 85243344Smckusick vrele(ndp->ni_dvp); 85343344Smckusick else 85443344Smckusick vput(ndp->ni_dvp); 85542465Smckusick vput(vp); 85642465Smckusick } 85737741Smckusick RETURN (error); 8586254Sroot } 8596254Sroot 8606254Sroot /* 8616254Sroot * Seek system call 8626254Sroot */ 86342441Smckusick lseek(p, uap, retval) 86445914Smckusick struct proc *p; 86542441Smckusick register struct args { 86637741Smckusick int fdes; 8676254Sroot off_t off; 8686254Sroot int sbase; 86942441Smckusick } *uap; 87042441Smckusick off_t *retval; 87142441Smckusick { 87242441Smckusick struct ucred *cred = u.u_nd.ni_cred; 87345914Smckusick register struct filedesc *fdp = p->p_fd; 87442441Smckusick register struct file *fp; 87537741Smckusick struct vattr vattr; 87637741Smckusick int error; 8776254Sroot 87845914Smckusick if ((unsigned)uap->fdes >= fdp->fd_maxfiles || 87945914Smckusick (fp = OFILE(fdp, uap->fdes)) == NULL) 88037741Smckusick RETURN (EBADF); 88137741Smckusick if (fp->f_type != DTYPE_VNODE) 88237741Smckusick RETURN (ESPIPE); 88313878Ssam switch (uap->sbase) { 88413878Ssam 88513878Ssam case L_INCR: 88613878Ssam fp->f_offset += uap->off; 88713878Ssam break; 88813878Ssam 88913878Ssam case L_XTND: 89037741Smckusick if (error = VOP_GETATTR((struct vnode *)fp->f_data, 89142441Smckusick &vattr, cred)) 89237741Smckusick RETURN (error); 89337741Smckusick fp->f_offset = uap->off + vattr.va_size; 89413878Ssam break; 89513878Ssam 89613878Ssam case L_SET: 89713878Ssam fp->f_offset = uap->off; 89813878Ssam break; 89913878Ssam 90013878Ssam default: 90137741Smckusick RETURN (EINVAL); 90213878Ssam } 90342441Smckusick *retval = fp->f_offset; 90437741Smckusick RETURN (0); 9056254Sroot } 9066254Sroot 9076254Sroot /* 9086254Sroot * Access system call 9096254Sroot */ 91042441Smckusick /* ARGSUSED */ 91142441Smckusick saccess(p, uap, retval) 91245914Smckusick struct proc *p; 91342441Smckusick register struct args { 9146254Sroot char *fname; 9156254Sroot int fmode; 91642441Smckusick } *uap; 91742441Smckusick int *retval; 91842441Smckusick { 91942441Smckusick register struct nameidata *ndp = &u.u_nd; 92042441Smckusick register struct ucred *cred = ndp->ni_cred; 92137741Smckusick register struct vnode *vp; 92237741Smckusick int error, mode, svuid, svgid; 9236254Sroot 92442441Smckusick svuid = cred->cr_uid; 92542441Smckusick svgid = cred->cr_groups[0]; 92642441Smckusick cred->cr_uid = p->p_ruid; 92742441Smckusick cred->cr_groups[0] = p->p_rgid; 92837741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 92916694Smckusick ndp->ni_segflg = UIO_USERSPACE; 93016694Smckusick ndp->ni_dirp = uap->fname; 93137741Smckusick if (error = namei(ndp)) 93237741Smckusick goto out1; 93337741Smckusick vp = ndp->ni_vp; 93437741Smckusick /* 93537741Smckusick * fmode == 0 means only check for exist 93637741Smckusick */ 93737741Smckusick if (uap->fmode) { 93837741Smckusick mode = 0; 93937741Smckusick if (uap->fmode & R_OK) 94037741Smckusick mode |= VREAD; 94137741Smckusick if (uap->fmode & W_OK) 94237741Smckusick mode |= VWRITE; 94337741Smckusick if (uap->fmode & X_OK) 94437741Smckusick mode |= VEXEC; 94539543Smckusick if ((mode & VWRITE) == 0 || (error = vn_writechk(vp)) == 0) 94638399Smckusick error = VOP_ACCESS(vp, mode, ndp->ni_cred); 9476254Sroot } 94837741Smckusick vput(vp); 94937741Smckusick out1: 95042441Smckusick cred->cr_uid = svuid; 95142441Smckusick cred->cr_groups[0] = svgid; 95237741Smckusick RETURN (error); 9536254Sroot } 9546254Sroot 9556254Sroot /* 9566574Smckusic * Stat system call. This version follows links. 95737Sbill */ 95842441Smckusick /* ARGSUSED */ 95942441Smckusick stat(p, uap, retval) 96045914Smckusick struct proc *p; 96142441Smckusick register struct args { 96242441Smckusick char *fname; 96342441Smckusick struct stat *ub; 96442441Smckusick } *uap; 96542441Smckusick int *retval; 96637Sbill { 96742441Smckusick register struct nameidata *ndp = &u.u_nd; 96842441Smckusick struct stat sb; 96942441Smckusick int error; 97037Sbill 97142441Smckusick ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW; 97242441Smckusick ndp->ni_segflg = UIO_USERSPACE; 97342441Smckusick ndp->ni_dirp = uap->fname; 97442441Smckusick if (error = namei(ndp)) 97542441Smckusick RETURN (error); 97642441Smckusick error = vn_stat(ndp->ni_vp, &sb); 97742441Smckusick vput(ndp->ni_vp); 97842441Smckusick if (error) 97942441Smckusick RETURN (error); 98042441Smckusick error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb)); 98142441Smckusick RETURN (error); 98237Sbill } 98337Sbill 98437Sbill /* 9856574Smckusic * Lstat system call. This version does not follow links. 9865992Swnj */ 98742441Smckusick /* ARGSUSED */ 98842441Smckusick lstat(p, uap, retval) 98945914Smckusick struct proc *p; 99042441Smckusick register struct args { 9915992Swnj char *fname; 99212756Ssam struct stat *ub; 99342441Smckusick } *uap; 99442441Smckusick int *retval; 99542441Smckusick { 99642441Smckusick register struct nameidata *ndp = &u.u_nd; 99712756Ssam struct stat sb; 99837741Smckusick int error; 9995992Swnj 100042441Smckusick ndp->ni_nameiop = LOOKUP | LOCKLEAF | NOFOLLOW; 100116694Smckusick ndp->ni_segflg = UIO_USERSPACE; 100216694Smckusick ndp->ni_dirp = uap->fname; 100337741Smckusick if (error = namei(ndp)) 100437741Smckusick RETURN (error); 100537741Smckusick error = vn_stat(ndp->ni_vp, &sb); 100637741Smckusick vput(ndp->ni_vp); 100737741Smckusick if (error) 100837741Smckusick RETURN (error); 100937741Smckusick error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb)); 101037741Smckusick RETURN (error); 10115992Swnj } 10125992Swnj 10135992Swnj /* 10145992Swnj * Return target name of a symbolic link 101537Sbill */ 101642441Smckusick /* ARGSUSED */ 101742441Smckusick readlink(p, uap, retval) 101845914Smckusick struct proc *p; 101942441Smckusick register struct args { 10205992Swnj char *name; 10215992Swnj char *buf; 10225992Swnj int count; 102342441Smckusick } *uap; 102442441Smckusick int *retval; 102542441Smckusick { 102642441Smckusick register struct nameidata *ndp = &u.u_nd; 102737741Smckusick register struct vnode *vp; 102837741Smckusick struct iovec aiov; 102937741Smckusick struct uio auio; 103037741Smckusick int error; 10315992Swnj 103237741Smckusick ndp->ni_nameiop = LOOKUP | LOCKLEAF; 103316694Smckusick ndp->ni_segflg = UIO_USERSPACE; 103416694Smckusick ndp->ni_dirp = uap->name; 103537741Smckusick if (error = namei(ndp)) 103637741Smckusick RETURN (error); 103737741Smckusick vp = ndp->ni_vp; 103837741Smckusick if (vp->v_type != VLNK) { 103937741Smckusick error = EINVAL; 10405992Swnj goto out; 10415992Swnj } 104237741Smckusick aiov.iov_base = uap->buf; 104337741Smckusick aiov.iov_len = uap->count; 104437741Smckusick auio.uio_iov = &aiov; 104537741Smckusick auio.uio_iovcnt = 1; 104637741Smckusick auio.uio_offset = 0; 104737741Smckusick auio.uio_rw = UIO_READ; 104837741Smckusick auio.uio_segflg = UIO_USERSPACE; 104937741Smckusick auio.uio_resid = uap->count; 105037741Smckusick error = VOP_READLINK(vp, &auio, ndp->ni_cred); 10515992Swnj out: 105237741Smckusick vput(vp); 105342441Smckusick *retval = uap->count - auio.uio_resid; 105437741Smckusick RETURN (error); 10555992Swnj } 10565992Swnj 10579167Ssam /* 105838259Smckusick * Change flags of a file given path name. 105938259Smckusick */ 106042441Smckusick /* ARGSUSED */ 106142441Smckusick chflags(p, uap, retval) 106245914Smckusick struct proc *p; 106342441Smckusick register struct args { 106438259Smckusick char *fname; 106538259Smckusick int flags; 106642441Smckusick } *uap; 106742441Smckusick int *retval; 106842441Smckusick { 106942441Smckusick register struct nameidata *ndp = &u.u_nd; 107038259Smckusick register struct vnode *vp; 107138259Smckusick struct vattr vattr; 107238259Smckusick int error; 107338259Smckusick 107438259Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 107538259Smckusick ndp->ni_segflg = UIO_USERSPACE; 107638259Smckusick ndp->ni_dirp = uap->fname; 107738259Smckusick if (error = namei(ndp)) 107838259Smckusick RETURN (error); 107938259Smckusick vp = ndp->ni_vp; 108041400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 108138259Smckusick error = EROFS; 108238259Smckusick goto out; 108338259Smckusick } 108445785Sbostic VATTR_NULL(&vattr); 108545785Sbostic vattr.va_flags = uap->flags; 108638259Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 108738259Smckusick out: 108838259Smckusick vput(vp); 108938259Smckusick RETURN (error); 109038259Smckusick } 109138259Smckusick 109238259Smckusick /* 109338259Smckusick * Change flags of a file given a file descriptor. 109438259Smckusick */ 109542441Smckusick /* ARGSUSED */ 109642441Smckusick fchflags(p, uap, retval) 109745914Smckusick struct proc *p; 109842441Smckusick register struct args { 109938259Smckusick int fd; 110038259Smckusick int flags; 110142441Smckusick } *uap; 110242441Smckusick int *retval; 110342441Smckusick { 110438259Smckusick struct vattr vattr; 110538259Smckusick struct vnode *vp; 110638259Smckusick struct file *fp; 110738259Smckusick int error; 110838259Smckusick 110945914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 111038259Smckusick RETURN (error); 111138259Smckusick vp = (struct vnode *)fp->f_data; 111238259Smckusick VOP_LOCK(vp); 111341400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 111438259Smckusick error = EROFS; 111538259Smckusick goto out; 111638259Smckusick } 111745785Sbostic VATTR_NULL(&vattr); 111845785Sbostic vattr.va_flags = uap->flags; 111938259Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred); 112038259Smckusick out: 112138259Smckusick VOP_UNLOCK(vp); 112238259Smckusick RETURN (error); 112338259Smckusick } 112438259Smckusick 112538259Smckusick /* 11269167Ssam * Change mode of a file given path name. 11279167Ssam */ 112842441Smckusick /* ARGSUSED */ 112942441Smckusick chmod(p, uap, retval) 113045914Smckusick struct proc *p; 113142441Smckusick register struct args { 11326254Sroot char *fname; 11336254Sroot int fmode; 113442441Smckusick } *uap; 113542441Smckusick int *retval; 113642441Smckusick { 113742441Smckusick register struct nameidata *ndp = &u.u_nd; 113837741Smckusick register struct vnode *vp; 113937741Smckusick struct vattr vattr; 114037741Smckusick int error; 11415992Swnj 114237741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 114337741Smckusick ndp->ni_segflg = UIO_USERSPACE; 114437741Smckusick ndp->ni_dirp = uap->fname; 114537741Smckusick if (error = namei(ndp)) 114637741Smckusick RETURN (error); 114737741Smckusick vp = ndp->ni_vp; 114841400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 114937741Smckusick error = EROFS; 115037741Smckusick goto out; 115137741Smckusick } 115245785Sbostic VATTR_NULL(&vattr); 115345785Sbostic vattr.va_mode = uap->fmode & 07777; 115437741Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 115537741Smckusick out: 115637741Smckusick vput(vp); 115737741Smckusick RETURN (error); 11587701Ssam } 11597439Sroot 11609167Ssam /* 11619167Ssam * Change mode of a file given a file descriptor. 11629167Ssam */ 116342441Smckusick /* ARGSUSED */ 116442441Smckusick fchmod(p, uap, retval) 116545914Smckusick struct proc *p; 116642441Smckusick register struct args { 11677701Ssam int fd; 11687701Ssam int fmode; 116942441Smckusick } *uap; 117042441Smckusick int *retval; 117142441Smckusick { 117237741Smckusick struct vattr vattr; 117337741Smckusick struct vnode *vp; 117437741Smckusick struct file *fp; 117537741Smckusick int error; 11767701Ssam 117745914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 117837741Smckusick RETURN (error); 117937741Smckusick vp = (struct vnode *)fp->f_data; 118037741Smckusick VOP_LOCK(vp); 118141400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 118237741Smckusick error = EROFS; 118337741Smckusick goto out; 11847439Sroot } 118545785Sbostic VATTR_NULL(&vattr); 118645785Sbostic vattr.va_mode = uap->fmode & 07777; 118737741Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred); 118837741Smckusick out: 118937741Smckusick VOP_UNLOCK(vp); 119037741Smckusick RETURN (error); 11915992Swnj } 11925992Swnj 11939167Ssam /* 11949167Ssam * Set ownership given a path name. 11959167Ssam */ 119642441Smckusick /* ARGSUSED */ 119742441Smckusick chown(p, uap, retval) 119845914Smckusick struct proc *p; 119942441Smckusick register struct args { 12006254Sroot char *fname; 12016254Sroot int uid; 12026254Sroot int gid; 120342441Smckusick } *uap; 120442441Smckusick int *retval; 120542441Smckusick { 120642441Smckusick register struct nameidata *ndp = &u.u_nd; 120737741Smckusick register struct vnode *vp; 120837741Smckusick struct vattr vattr; 120937741Smckusick int error; 121037Sbill 121137741Smckusick ndp->ni_nameiop = LOOKUP | NOFOLLOW | LOCKLEAF; 121236614Sbostic ndp->ni_segflg = UIO_USERSPACE; 121336614Sbostic ndp->ni_dirp = uap->fname; 121437741Smckusick if (error = namei(ndp)) 121537741Smckusick RETURN (error); 121637741Smckusick vp = ndp->ni_vp; 121741400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 121837741Smckusick error = EROFS; 121937741Smckusick goto out; 122037741Smckusick } 122145785Sbostic VATTR_NULL(&vattr); 122245785Sbostic vattr.va_uid = uap->uid; 122345785Sbostic vattr.va_gid = uap->gid; 122437741Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 122537741Smckusick out: 122637741Smckusick vput(vp); 122737741Smckusick RETURN (error); 12287701Ssam } 12297439Sroot 12309167Ssam /* 12319167Ssam * Set ownership given a file descriptor. 12329167Ssam */ 123342441Smckusick /* ARGSUSED */ 123442441Smckusick fchown(p, uap, retval) 123545914Smckusick struct proc *p; 123642441Smckusick register struct args { 12377701Ssam int fd; 12387701Ssam int uid; 12397701Ssam int gid; 124042441Smckusick } *uap; 124142441Smckusick int *retval; 124242441Smckusick { 124337741Smckusick struct vattr vattr; 124437741Smckusick struct vnode *vp; 124537741Smckusick struct file *fp; 124637741Smckusick int error; 12477701Ssam 124845914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 124937741Smckusick RETURN (error); 125037741Smckusick vp = (struct vnode *)fp->f_data; 125137741Smckusick VOP_LOCK(vp); 125241400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 125337741Smckusick error = EROFS; 125437741Smckusick goto out; 125537741Smckusick } 125645785Sbostic VATTR_NULL(&vattr); 125745785Sbostic vattr.va_uid = uap->uid; 125845785Sbostic vattr.va_gid = uap->gid; 125937741Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred); 126037741Smckusick out: 126137741Smckusick VOP_UNLOCK(vp); 126237741Smckusick RETURN (error); 12637701Ssam } 12647701Ssam 126542441Smckusick /* 126642441Smckusick * Set the access and modification times of a file. 126742441Smckusick */ 126842441Smckusick /* ARGSUSED */ 126942441Smckusick utimes(p, uap, retval) 127045914Smckusick struct proc *p; 127142441Smckusick register struct args { 127211811Ssam char *fname; 127311811Ssam struct timeval *tptr; 127442441Smckusick } *uap; 127542441Smckusick int *retval; 127642441Smckusick { 127742441Smckusick register struct nameidata *ndp = &u.u_nd; 127837741Smckusick register struct vnode *vp; 127911811Ssam struct timeval tv[2]; 128037741Smckusick struct vattr vattr; 128137741Smckusick int error; 128211811Ssam 128337741Smckusick if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv))) 128437741Smckusick RETURN (error); 128537741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 128637741Smckusick ndp->ni_segflg = UIO_USERSPACE; 128737741Smckusick ndp->ni_dirp = uap->fname; 128837741Smckusick if (error = namei(ndp)) 128937741Smckusick RETURN (error); 129037741Smckusick vp = ndp->ni_vp; 129141400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 129237741Smckusick error = EROFS; 129337741Smckusick goto out; 129421015Smckusick } 129545785Sbostic VATTR_NULL(&vattr); 129645785Sbostic vattr.va_atime = tv[0]; 129745785Sbostic vattr.va_mtime = tv[1]; 129837741Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 129937741Smckusick out: 130037741Smckusick vput(vp); 130137741Smckusick RETURN (error); 130211811Ssam } 130311811Ssam 13049167Ssam /* 13059167Ssam * Truncate a file given its path name. 13069167Ssam */ 130742441Smckusick /* ARGSUSED */ 130842441Smckusick truncate(p, uap, retval) 130945914Smckusick struct proc *p; 131042441Smckusick register struct args { 13117701Ssam char *fname; 131226473Skarels off_t length; 131342441Smckusick } *uap; 131442441Smckusick int *retval; 131542441Smckusick { 131642441Smckusick register struct nameidata *ndp = &u.u_nd; 131737741Smckusick register struct vnode *vp; 131837741Smckusick struct vattr vattr; 131937741Smckusick int error; 13207701Ssam 132137741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 132216694Smckusick ndp->ni_segflg = UIO_USERSPACE; 132316694Smckusick ndp->ni_dirp = uap->fname; 132437741Smckusick if (error = namei(ndp)) 132537741Smckusick RETURN (error); 132637741Smckusick vp = ndp->ni_vp; 132737741Smckusick if (vp->v_type == VDIR) { 132837741Smckusick error = EISDIR; 132937741Smckusick goto out; 13307701Ssam } 133138399Smckusick if ((error = vn_writechk(vp)) || 133238399Smckusick (error = VOP_ACCESS(vp, VWRITE, ndp->ni_cred))) 133337741Smckusick goto out; 133445785Sbostic VATTR_NULL(&vattr); 133545785Sbostic vattr.va_size = uap->length; 133637741Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 133737741Smckusick out: 133837741Smckusick vput(vp); 133937741Smckusick RETURN (error); 13407701Ssam } 13417701Ssam 13429167Ssam /* 13439167Ssam * Truncate a file given a file descriptor. 13449167Ssam */ 134542441Smckusick /* ARGSUSED */ 134642441Smckusick ftruncate(p, uap, retval) 134745914Smckusick struct proc *p; 134842441Smckusick register struct args { 13497701Ssam int fd; 135026473Skarels off_t length; 135142441Smckusick } *uap; 135242441Smckusick int *retval; 135342441Smckusick { 135437741Smckusick struct vattr vattr; 135537741Smckusick struct vnode *vp; 13567701Ssam struct file *fp; 135737741Smckusick int error; 13587701Ssam 135945914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 136037741Smckusick RETURN (error); 136137741Smckusick if ((fp->f_flag & FWRITE) == 0) 136237741Smckusick RETURN (EINVAL); 136337741Smckusick vp = (struct vnode *)fp->f_data; 136437741Smckusick VOP_LOCK(vp); 136537741Smckusick if (vp->v_type == VDIR) { 136637741Smckusick error = EISDIR; 136737741Smckusick goto out; 13687701Ssam } 136938399Smckusick if (error = vn_writechk(vp)) 137037741Smckusick goto out; 137145785Sbostic VATTR_NULL(&vattr); 137245785Sbostic vattr.va_size = uap->length; 137337741Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred); 137437741Smckusick out: 137537741Smckusick VOP_UNLOCK(vp); 137637741Smckusick RETURN (error); 13777701Ssam } 13787701Ssam 13799167Ssam /* 13809167Ssam * Synch an open file. 13819167Ssam */ 138242441Smckusick /* ARGSUSED */ 138342441Smckusick fsync(p, uap, retval) 138445914Smckusick struct proc *p; 138542441Smckusick struct args { 138642441Smckusick int fd; 138742441Smckusick } *uap; 138842441Smckusick int *retval; 13899167Ssam { 139039592Smckusick register struct vnode *vp; 13919167Ssam struct file *fp; 139237741Smckusick int error; 13939167Ssam 139445914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 139537741Smckusick RETURN (error); 139639592Smckusick vp = (struct vnode *)fp->f_data; 139739592Smckusick VOP_LOCK(vp); 139839592Smckusick error = VOP_FSYNC(vp, fp->f_flag, fp->f_cred, MNT_WAIT); 139939592Smckusick VOP_UNLOCK(vp); 140037741Smckusick RETURN (error); 14019167Ssam } 14029167Ssam 14039167Ssam /* 14049167Ssam * Rename system call. 14059167Ssam * 14069167Ssam * Source and destination must either both be directories, or both 14079167Ssam * not be directories. If target is a directory, it must be empty. 14089167Ssam */ 140942441Smckusick /* ARGSUSED */ 141042441Smckusick rename(p, uap, retval) 141145914Smckusick struct proc *p; 141242441Smckusick register struct args { 14137701Ssam char *from; 14147701Ssam char *to; 141542441Smckusick } *uap; 141642441Smckusick int *retval; 141742441Smckusick { 141837741Smckusick register struct vnode *tvp, *fvp, *tdvp; 141942441Smckusick register struct nameidata *ndp = &u.u_nd; 142037741Smckusick struct nameidata tond; 142137741Smckusick int error; 14227701Ssam 142337741Smckusick ndp->ni_nameiop = DELETE | WANTPARENT; 142416694Smckusick ndp->ni_segflg = UIO_USERSPACE; 142516694Smckusick ndp->ni_dirp = uap->from; 142637741Smckusick if (error = namei(ndp)) 142737741Smckusick RETURN (error); 142837741Smckusick fvp = ndp->ni_vp; 142938266Smckusick nddup(ndp, &tond); 143037741Smckusick tond.ni_nameiop = RENAME | LOCKPARENT | LOCKLEAF | NOCACHE; 143137741Smckusick tond.ni_segflg = UIO_USERSPACE; 143237741Smckusick tond.ni_dirp = uap->to; 143342465Smckusick if (error = namei(&tond)) { 143442465Smckusick VOP_ABORTOP(ndp); 143542465Smckusick vrele(ndp->ni_dvp); 143642465Smckusick vrele(fvp); 143742465Smckusick goto out1; 143842465Smckusick } 143937741Smckusick tdvp = tond.ni_dvp; 144037741Smckusick tvp = tond.ni_vp; 144137741Smckusick if (tvp != NULL) { 144237741Smckusick if (fvp->v_type == VDIR && tvp->v_type != VDIR) { 144339242Sbostic error = ENOTDIR; 144437741Smckusick goto out; 144537741Smckusick } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) { 144639242Sbostic error = EISDIR; 144737741Smckusick goto out; 14489167Ssam } 144945240Smckusick if (fvp->v_mount != tvp->v_mount) { 145045240Smckusick error = EXDEV; 145145240Smckusick goto out; 145245240Smckusick } 14539167Ssam } 145437741Smckusick if (fvp->v_mount != tdvp->v_mount) { 145537741Smckusick error = EXDEV; 14569167Ssam goto out; 145710051Ssam } 145839286Smckusick if (fvp == tdvp) 145937741Smckusick error = EINVAL; 146039286Smckusick /* 146139286Smckusick * If source is the same as the destination, 146239286Smckusick * then there is nothing to do. 146339286Smckusick */ 146439286Smckusick if (fvp == tvp) 146539286Smckusick error = -1; 146637741Smckusick out: 146742465Smckusick if (!error) { 146842465Smckusick error = VOP_RENAME(ndp, &tond); 146942465Smckusick } else { 147037741Smckusick VOP_ABORTOP(&tond); 147143344Smckusick if (tdvp == tvp) 147243344Smckusick vrele(tdvp); 147343344Smckusick else 147443344Smckusick vput(tdvp); 147542465Smckusick if (tvp) 147642465Smckusick vput(tvp); 147737741Smckusick VOP_ABORTOP(ndp); 147842465Smckusick vrele(ndp->ni_dvp); 147942465Smckusick vrele(fvp); 14809167Ssam } 148137741Smckusick out1: 148238266Smckusick ndrele(&tond); 148339286Smckusick if (error == -1) 148439286Smckusick RETURN (0); 148537741Smckusick RETURN (error); 14867701Ssam } 14877701Ssam 14887535Sroot /* 148912756Ssam * Mkdir system call 149012756Ssam */ 149142441Smckusick /* ARGSUSED */ 149242441Smckusick mkdir(p, uap, retval) 149345914Smckusick struct proc *p; 149442441Smckusick register struct args { 149512756Ssam char *name; 149612756Ssam int dmode; 149742441Smckusick } *uap; 149842441Smckusick int *retval; 149942441Smckusick { 150042441Smckusick register struct nameidata *ndp = &u.u_nd; 150137741Smckusick register struct vnode *vp; 150237741Smckusick struct vattr vattr; 150337741Smckusick int error; 150412756Ssam 150537741Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 150616694Smckusick ndp->ni_segflg = UIO_USERSPACE; 150716694Smckusick ndp->ni_dirp = uap->name; 150837741Smckusick if (error = namei(ndp)) 150937741Smckusick RETURN (error); 151037741Smckusick vp = ndp->ni_vp; 151137741Smckusick if (vp != NULL) { 151237741Smckusick VOP_ABORTOP(ndp); 151343344Smckusick if (ndp->ni_dvp == vp) 151443344Smckusick vrele(ndp->ni_dvp); 151543344Smckusick else 151643344Smckusick vput(ndp->ni_dvp); 151742465Smckusick vrele(vp); 151837741Smckusick RETURN (EEXIST); 151912756Ssam } 152041362Smckusick VATTR_NULL(&vattr); 152137741Smckusick vattr.va_type = VDIR; 152245914Smckusick vattr.va_mode = (uap->dmode & 0777) &~ p->p_fd->fd_cmask; 152337741Smckusick error = VOP_MKDIR(ndp, &vattr); 152438145Smckusick if (!error) 152538145Smckusick vput(ndp->ni_vp); 152637741Smckusick RETURN (error); 152712756Ssam } 152812756Ssam 152912756Ssam /* 153012756Ssam * Rmdir system call. 153112756Ssam */ 153242441Smckusick /* ARGSUSED */ 153342441Smckusick rmdir(p, uap, retval) 153445914Smckusick struct proc *p; 153542441Smckusick struct args { 153642441Smckusick char *name; 153742441Smckusick } *uap; 153842441Smckusick int *retval; 153912756Ssam { 154042441Smckusick register struct nameidata *ndp = &u.u_nd; 154137741Smckusick register struct vnode *vp; 154237741Smckusick int error; 154312756Ssam 154437741Smckusick ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF; 154516694Smckusick ndp->ni_segflg = UIO_USERSPACE; 154616694Smckusick ndp->ni_dirp = uap->name; 154737741Smckusick if (error = namei(ndp)) 154837741Smckusick RETURN (error); 154937741Smckusick vp = ndp->ni_vp; 155037741Smckusick if (vp->v_type != VDIR) { 155137741Smckusick error = ENOTDIR; 155212756Ssam goto out; 155312756Ssam } 155412756Ssam /* 155537741Smckusick * No rmdir "." please. 155612756Ssam */ 155737741Smckusick if (ndp->ni_dvp == vp) { 155837741Smckusick error = EINVAL; 155912756Ssam goto out; 156012756Ssam } 156112756Ssam /* 156237741Smckusick * Don't unlink a mounted file. 156312756Ssam */ 156437741Smckusick if (vp->v_flag & VROOT) 156537741Smckusick error = EBUSY; 156612756Ssam out: 156742465Smckusick if (!error) { 156842465Smckusick error = VOP_RMDIR(ndp); 156942465Smckusick } else { 157037741Smckusick VOP_ABORTOP(ndp); 157143344Smckusick if (ndp->ni_dvp == vp) 157243344Smckusick vrele(ndp->ni_dvp); 157343344Smckusick else 157443344Smckusick vput(ndp->ni_dvp); 157542465Smckusick vput(vp); 157642465Smckusick } 157737741Smckusick RETURN (error); 157812756Ssam } 157912756Ssam 158037741Smckusick /* 158137741Smckusick * Read a block of directory entries in a file system independent format 158237741Smckusick */ 158342441Smckusick getdirentries(p, uap, retval) 158445914Smckusick struct proc *p; 158542441Smckusick register struct args { 158637741Smckusick int fd; 158737741Smckusick char *buf; 158837741Smckusick unsigned count; 158937741Smckusick long *basep; 159042441Smckusick } *uap; 159142441Smckusick int *retval; 159242441Smckusick { 159339592Smckusick register struct vnode *vp; 159416540Ssam struct file *fp; 159537741Smckusick struct uio auio; 159637741Smckusick struct iovec aiov; 159738129Smckusick off_t off; 159840321Smckusick int error, eofflag; 159912756Ssam 160045914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 160137741Smckusick RETURN (error); 160237741Smckusick if ((fp->f_flag & FREAD) == 0) 160337741Smckusick RETURN (EBADF); 160439592Smckusick vp = (struct vnode *)fp->f_data; 160539592Smckusick if (vp->v_type != VDIR) 160639592Smckusick RETURN (EINVAL); 160737741Smckusick aiov.iov_base = uap->buf; 160837741Smckusick aiov.iov_len = uap->count; 160937741Smckusick auio.uio_iov = &aiov; 161037741Smckusick auio.uio_iovcnt = 1; 161137741Smckusick auio.uio_rw = UIO_READ; 161237741Smckusick auio.uio_segflg = UIO_USERSPACE; 161337741Smckusick auio.uio_resid = uap->count; 161439592Smckusick VOP_LOCK(vp); 161539592Smckusick auio.uio_offset = off = fp->f_offset; 161640321Smckusick error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag); 161739592Smckusick fp->f_offset = auio.uio_offset; 161839592Smckusick VOP_UNLOCK(vp); 161939592Smckusick if (error) 162037741Smckusick RETURN (error); 162139592Smckusick error = copyout((caddr_t)&off, (caddr_t)uap->basep, sizeof(long)); 162242441Smckusick *retval = uap->count - auio.uio_resid; 162337741Smckusick RETURN (error); 162412756Ssam } 162512756Ssam 162612756Ssam /* 162712756Ssam * mode mask for creation of files 162812756Ssam */ 162942441Smckusick mode_t 163042441Smckusick umask(p, uap, retval) 163145914Smckusick struct proc *p; 163242441Smckusick struct args { 163342441Smckusick int mask; 163442441Smckusick } *uap; 163542441Smckusick int *retval; 163612756Ssam { 163745914Smckusick register struct filedesc *fdp = p->p_fd; 163812756Ssam 163945914Smckusick *retval = fdp->fd_cmask; 164045914Smckusick fdp->fd_cmask = uap->mask & 07777; 164137741Smckusick RETURN (0); 164212756Ssam } 164337741Smckusick 164439566Smarc /* 164539566Smarc * Void all references to file by ripping underlying filesystem 164639566Smarc * away from vnode. 164739566Smarc */ 164842441Smckusick /* ARGSUSED */ 164942441Smckusick revoke(p, uap, retval) 165045914Smckusick struct proc *p; 165142441Smckusick register struct args { 165239566Smarc char *fname; 165342441Smckusick } *uap; 165442441Smckusick int *retval; 165542441Smckusick { 165642441Smckusick register struct nameidata *ndp = &u.u_nd; 165739566Smarc register struct vnode *vp; 165839566Smarc struct vattr vattr; 165939566Smarc int error; 166039566Smarc 166139566Smarc ndp->ni_nameiop = LOOKUP | FOLLOW; 166239566Smarc ndp->ni_segflg = UIO_USERSPACE; 166339566Smarc ndp->ni_dirp = uap->fname; 166439566Smarc if (error = namei(ndp)) 166539566Smarc RETURN (error); 166639566Smarc vp = ndp->ni_vp; 166739566Smarc if (vp->v_type != VCHR && vp->v_type != VBLK) { 166839566Smarc error = EINVAL; 166939566Smarc goto out; 167039566Smarc } 167142441Smckusick if (error = VOP_GETATTR(vp, &vattr, ndp->ni_cred)) 167239566Smarc goto out; 167342955Smckusick if (ndp->ni_cred->cr_uid != vattr.va_uid && 167442441Smckusick (error = suser(ndp->ni_cred, &u.u_acflag))) 167539566Smarc goto out; 167639805Smckusick if (vp->v_usecount > 1 || (vp->v_flag & VALIASED)) 167739632Smckusick vgoneall(vp); 167839566Smarc out: 167939566Smarc vrele(vp); 168039566Smarc RETURN (error); 168139566Smarc } 168239566Smarc 168345914Smckusick getvnode(fdp, fdes, fpp) 168445914Smckusick struct filedesc *fdp; 168537741Smckusick struct file **fpp; 168637741Smckusick int fdes; 168737741Smckusick { 168837741Smckusick struct file *fp; 168937741Smckusick 169045914Smckusick if ((unsigned)fdes >= fdp->fd_maxfiles || 169145914Smckusick (fp = OFILE(fdp, fdes)) == NULL) 169237741Smckusick return (EBADF); 169337741Smckusick if (fp->f_type != DTYPE_VNODE) 169437741Smckusick return (EINVAL); 169537741Smckusick *fpp = fp; 169637741Smckusick return (0); 169737741Smckusick } 1698