123405Smckusick /* 237741Smckusick * Copyright (c) 1989 The Regents of the University of California. 337741Smckusick * All rights reserved. 423405Smckusick * 544459Sbostic * %sccs.include.redist.c% 637741Smckusick * 7*45914Smckusick * @(#)vfs_syscalls.c 7.62 (Berkeley) 01/10/91 823405Smckusick */ 937Sbill 1017101Sbloom #include "param.h" 1117101Sbloom #include "systm.h" 1244407Skarels #include "user.h" 13*45914Smckusick #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) 34*45914Smckusick 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) 182*45914Smckusick 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 23545738Smckusick vnode_pager_umount(mp); /* release cached vnodes */ 23637741Smckusick cache_purgevfs(mp); /* remove cache entries for this file sys */ 23741676Smckusick if ((error = VFS_SYNC(mp, MNT_WAIT)) == 0 || (flags & MNT_FORCE)) 23841676Smckusick error = VFS_UNMOUNT(mp, flags); 23941400Smckusick mp->mnt_flag &= ~MNT_UNMOUNT; 24041298Smckusick vfs_unbusy(mp); 24137741Smckusick if (error) { 24237741Smckusick vfs_unlock(mp); 24337741Smckusick } else { 24437741Smckusick vrele(coveredvp); 24537741Smckusick vfs_remove(mp); 24637741Smckusick free((caddr_t)mp, M_MOUNT); 24737741Smckusick } 24839356Smckusick return (error); 2496254Sroot } 2506254Sroot 2519167Ssam /* 25237741Smckusick * Sync system call. 25337741Smckusick * Sync each mounted filesystem. 2549167Ssam */ 25539491Smckusick /* ARGSUSED */ 25642441Smckusick sync(p, uap, retval) 257*45914Smckusick struct proc *p; 25842441Smckusick struct args *uap; 25942441Smckusick int *retval; 2606254Sroot { 26137741Smckusick register struct mount *mp; 26241298Smckusick struct mount *omp; 26337741Smckusick 26437741Smckusick mp = rootfs; 26537741Smckusick do { 26640343Smckusick /* 26740343Smckusick * The lock check below is to avoid races with mount 26840343Smckusick * and unmount. 26940343Smckusick */ 27041400Smckusick if ((mp->mnt_flag & (MNT_MLOCK|MNT_RDONLY|MNT_MPBUSY)) == 0 && 27141298Smckusick !vfs_busy(mp)) { 27237741Smckusick VFS_SYNC(mp, MNT_NOWAIT); 27341298Smckusick omp = mp; 27441400Smckusick mp = mp->mnt_next; 27541298Smckusick vfs_unbusy(omp); 27641298Smckusick } else 27741400Smckusick mp = mp->mnt_next; 27837741Smckusick } while (mp != rootfs); 27937741Smckusick } 28037741Smckusick 28137741Smckusick /* 28241298Smckusick * operate on filesystem quotas 28341298Smckusick */ 28442441Smckusick /* ARGSUSED */ 28542441Smckusick quotactl(p, uap, retval) 286*45914Smckusick struct proc *p; 28742441Smckusick register struct args { 28841298Smckusick char *path; 28941298Smckusick int cmd; 29041298Smckusick int uid; 29141298Smckusick caddr_t arg; 29242441Smckusick } *uap; 29342441Smckusick int *retval; 29442441Smckusick { 29541298Smckusick register struct mount *mp; 29642441Smckusick register struct nameidata *ndp = &u.u_nd; 29741298Smckusick int error; 29841298Smckusick 29941298Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW; 30041298Smckusick ndp->ni_segflg = UIO_USERSPACE; 30141298Smckusick ndp->ni_dirp = uap->path; 30241298Smckusick if (error = namei(ndp)) 30341298Smckusick RETURN (error); 30441298Smckusick mp = ndp->ni_vp->v_mount; 30541298Smckusick vrele(ndp->ni_vp); 30641298Smckusick RETURN (VFS_QUOTACTL(mp, uap->cmd, uap->uid, uap->arg)); 30741298Smckusick } 30841298Smckusick 30941298Smckusick /* 31037741Smckusick * get filesystem statistics 31137741Smckusick */ 31242441Smckusick /* ARGSUSED */ 31342441Smckusick statfs(p, uap, retval) 314*45914Smckusick struct proc *p; 31542441Smckusick register struct args { 31637741Smckusick char *path; 31737741Smckusick struct statfs *buf; 31842441Smckusick } *uap; 31942441Smckusick int *retval; 32042441Smckusick { 32139464Smckusick register struct mount *mp; 32242441Smckusick register struct nameidata *ndp = &u.u_nd; 32340343Smckusick register struct statfs *sp; 32437741Smckusick int error; 32537741Smckusick 32639544Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW; 32737741Smckusick ndp->ni_segflg = UIO_USERSPACE; 32837741Smckusick ndp->ni_dirp = uap->path; 32937741Smckusick if (error = namei(ndp)) 33037741Smckusick RETURN (error); 33139544Smckusick mp = ndp->ni_vp->v_mount; 33241400Smckusick sp = &mp->mnt_stat; 33339544Smckusick vrele(ndp->ni_vp); 33440343Smckusick if (error = VFS_STATFS(mp, sp)) 33539544Smckusick RETURN (error); 33641400Smckusick sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 33740343Smckusick RETURN (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp))); 33837741Smckusick } 33937741Smckusick 34042441Smckusick /* 34142441Smckusick * get filesystem statistics 34242441Smckusick */ 34342441Smckusick /* ARGSUSED */ 34442441Smckusick fstatfs(p, uap, retval) 345*45914Smckusick struct proc *p; 34642441Smckusick register struct args { 34737741Smckusick int fd; 34837741Smckusick struct statfs *buf; 34942441Smckusick } *uap; 35042441Smckusick int *retval; 35142441Smckusick { 35237741Smckusick struct file *fp; 35339464Smckusick struct mount *mp; 35440343Smckusick register struct statfs *sp; 35537741Smckusick int error; 35637741Smckusick 357*45914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 35837741Smckusick RETURN (error); 35939464Smckusick mp = ((struct vnode *)fp->f_data)->v_mount; 36041400Smckusick sp = &mp->mnt_stat; 36140343Smckusick if (error = VFS_STATFS(mp, sp)) 36237741Smckusick RETURN (error); 36341400Smckusick sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 36440343Smckusick RETURN (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp))); 36537741Smckusick } 36637741Smckusick 36737741Smckusick /* 36838270Smckusick * get statistics on all filesystems 36938270Smckusick */ 37042441Smckusick getfsstat(p, uap, retval) 371*45914Smckusick struct proc *p; 37242441Smckusick register struct args { 37338270Smckusick struct statfs *buf; 37438270Smckusick long bufsize; 37540343Smckusick int flags; 37642441Smckusick } *uap; 37742441Smckusick int *retval; 37842441Smckusick { 37938270Smckusick register struct mount *mp; 38040343Smckusick register struct statfs *sp; 38139606Smckusick caddr_t sfsp; 38238270Smckusick long count, maxcount, error; 38338270Smckusick 38438270Smckusick maxcount = uap->bufsize / sizeof(struct statfs); 38539606Smckusick sfsp = (caddr_t)uap->buf; 38638270Smckusick mp = rootfs; 38738270Smckusick count = 0; 38838270Smckusick do { 38941400Smckusick if (sfsp && count < maxcount && 39041400Smckusick ((mp->mnt_flag & MNT_MLOCK) == 0)) { 39141400Smckusick sp = &mp->mnt_stat; 39240343Smckusick /* 39340343Smckusick * If MNT_NOWAIT is specified, do not refresh the 39440343Smckusick * fsstat cache. MNT_WAIT overrides MNT_NOWAIT. 39540343Smckusick */ 39640343Smckusick if (((uap->flags & MNT_NOWAIT) == 0 || 39740343Smckusick (uap->flags & MNT_WAIT)) && 39840343Smckusick (error = VFS_STATFS(mp, sp))) { 39941400Smckusick mp = mp->mnt_prev; 40039607Smckusick continue; 40139607Smckusick } 40241400Smckusick sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 40340343Smckusick if (error = copyout((caddr_t)sp, sfsp, sizeof(*sp))) 40439606Smckusick RETURN (error); 40540343Smckusick sfsp += sizeof(*sp); 40638270Smckusick } 40739606Smckusick count++; 40841400Smckusick mp = mp->mnt_prev; 40938270Smckusick } while (mp != rootfs); 41038270Smckusick if (sfsp && count > maxcount) 41142441Smckusick *retval = maxcount; 41238270Smckusick else 41342441Smckusick *retval = count; 41438270Smckusick RETURN (0); 41538270Smckusick } 41638270Smckusick 41738270Smckusick /* 41838259Smckusick * Change current working directory to a given file descriptor. 41938259Smckusick */ 42042441Smckusick /* ARGSUSED */ 42142441Smckusick fchdir(p, uap, retval) 422*45914Smckusick struct proc *p; 42342441Smckusick struct args { 42442441Smckusick int fd; 42542441Smckusick } *uap; 42642441Smckusick int *retval; 42738259Smckusick { 42842441Smckusick register struct nameidata *ndp = &u.u_nd; 429*45914Smckusick register struct filedesc *fdp = p->p_fd; 43038259Smckusick register struct vnode *vp; 43138259Smckusick struct file *fp; 43238259Smckusick int error; 43338259Smckusick 434*45914Smckusick if (error = getvnode(fdp, uap->fd, &fp)) 43538259Smckusick RETURN (error); 43638259Smckusick vp = (struct vnode *)fp->f_data; 43738259Smckusick VOP_LOCK(vp); 43838259Smckusick if (vp->v_type != VDIR) 43938259Smckusick error = ENOTDIR; 44038259Smckusick else 44142441Smckusick error = VOP_ACCESS(vp, VEXEC, ndp->ni_cred); 44238259Smckusick VOP_UNLOCK(vp); 44339860Smckusick if (error) 44439860Smckusick RETURN (error); 44539860Smckusick VREF(vp); 446*45914Smckusick vrele(fdp->fd_cdir); 447*45914Smckusick fdp->fd_cdir = vp; 44839860Smckusick RETURN (0); 44938259Smckusick } 45038259Smckusick 45138259Smckusick /* 45237741Smckusick * Change current working directory (``.''). 45337741Smckusick */ 45442441Smckusick /* ARGSUSED */ 45542441Smckusick chdir(p, uap, retval) 456*45914Smckusick struct proc *p; 45742441Smckusick struct args { 45842441Smckusick char *fname; 45942441Smckusick } *uap; 46042441Smckusick int *retval; 46137741Smckusick { 46242441Smckusick register struct nameidata *ndp = &u.u_nd; 463*45914Smckusick register struct filedesc *fdp = p->p_fd; 46437741Smckusick int error; 4656254Sroot 46637741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 46716694Smckusick ndp->ni_segflg = UIO_USERSPACE; 46816694Smckusick ndp->ni_dirp = uap->fname; 46937741Smckusick if (error = chdirec(ndp)) 47037741Smckusick RETURN (error); 471*45914Smckusick vrele(fdp->fd_cdir); 472*45914Smckusick fdp->fd_cdir = ndp->ni_vp; 47337741Smckusick RETURN (0); 47437741Smckusick } 4756254Sroot 47637741Smckusick /* 47737741Smckusick * Change notion of root (``/'') directory. 47837741Smckusick */ 47942441Smckusick /* ARGSUSED */ 48042441Smckusick chroot(p, uap, retval) 481*45914Smckusick struct proc *p; 48242441Smckusick struct args { 48342441Smckusick char *fname; 48442441Smckusick } *uap; 48542441Smckusick int *retval; 48637741Smckusick { 48742441Smckusick register struct nameidata *ndp = &u.u_nd; 488*45914Smckusick register struct filedesc *fdp = p->p_fd; 48937741Smckusick int error; 49037741Smckusick 49142441Smckusick if (error = suser(ndp->ni_cred, &u.u_acflag)) 49237741Smckusick RETURN (error); 49337741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 49437741Smckusick ndp->ni_segflg = UIO_USERSPACE; 49537741Smckusick ndp->ni_dirp = uap->fname; 49637741Smckusick if (error = chdirec(ndp)) 49737741Smckusick RETURN (error); 498*45914Smckusick if (fdp->fd_rdir != NULL) 499*45914Smckusick vrele(fdp->fd_rdir); 500*45914Smckusick fdp->fd_rdir = ndp->ni_vp; 50137741Smckusick RETURN (0); 5026254Sroot } 5036254Sroot 50437Sbill /* 50537741Smckusick * Common routine for chroot and chdir. 50637741Smckusick */ 50737741Smckusick chdirec(ndp) 50837741Smckusick register struct nameidata *ndp; 50937741Smckusick { 51037741Smckusick struct vnode *vp; 51137741Smckusick int error; 51237741Smckusick 51337741Smckusick if (error = namei(ndp)) 51437741Smckusick return (error); 51537741Smckusick vp = ndp->ni_vp; 51637741Smckusick if (vp->v_type != VDIR) 51737741Smckusick error = ENOTDIR; 51837741Smckusick else 51938399Smckusick error = VOP_ACCESS(vp, VEXEC, ndp->ni_cred); 52037741Smckusick VOP_UNLOCK(vp); 52137741Smckusick if (error) 52237741Smckusick vrele(vp); 52337741Smckusick return (error); 52437741Smckusick } 52537741Smckusick 52637741Smckusick /* 5276254Sroot * Open system call. 52842441Smckusick * Check permissions, allocate an open file structure, 52942441Smckusick * and call the device open routine if any. 5306254Sroot */ 53142441Smckusick open(p, uap, retval) 532*45914Smckusick struct proc *p; 53342441Smckusick register struct args { 5346254Sroot char *fname; 5357701Ssam int mode; 53612756Ssam int crtmode; 53742441Smckusick } *uap; 53842441Smckusick int *retval; 5396254Sroot { 54042441Smckusick struct nameidata *ndp = &u.u_nd; 541*45914Smckusick register struct filedesc *fdp = p->p_fd; 54242441Smckusick register struct file *fp; 54337741Smckusick int fmode, cmode; 54437741Smckusick struct file *nfp; 54537741Smckusick int indx, error; 54637741Smckusick extern struct fileops vnops; 5476254Sroot 548*45914Smckusick if (error = falloc(p, &nfp, &indx)) 54942441Smckusick RETURN (error); 55037741Smckusick fp = nfp; 55142441Smckusick fmode = uap->mode - FOPEN; 552*45914Smckusick cmode = ((uap->crtmode &~ fdp->fd_cmask) & 07777) &~ S_ISVTX; 55342441Smckusick ndp->ni_segflg = UIO_USERSPACE; 55442441Smckusick ndp->ni_dirp = uap->fname; 55545202Smckusick p->p_dupfd = -indx - 1; /* XXX check for fdopen */ 55642441Smckusick if (error = vn_open(ndp, fmode, cmode)) { 55737741Smckusick crfree(fp->f_cred); 55837741Smckusick fp->f_count--; 55943405Smckusick if (error == ENODEV && /* XXX from fdopen */ 56045202Smckusick p->p_dupfd >= 0 && 561*45914Smckusick (error = dupfdopen(fdp, indx, p->p_dupfd, fmode)) == 0) { 56242441Smckusick *retval = indx; 56342441Smckusick RETURN (0); 56442441Smckusick } 56540884Smckusick if (error == ERESTART) 56640884Smckusick error = EINTR; 567*45914Smckusick OFILE(fdp, indx) = NULL; 56842441Smckusick RETURN (error); 56912756Ssam } 57037741Smckusick fp->f_flag = fmode & FMASK; 57137741Smckusick fp->f_type = DTYPE_VNODE; 57237741Smckusick fp->f_ops = &vnops; 57337741Smckusick fp->f_data = (caddr_t)ndp->ni_vp; 57442441Smckusick *retval = indx; 57542441Smckusick RETURN (0); 5766254Sroot } 5776254Sroot 57842955Smckusick #ifdef COMPAT_43 5796254Sroot /* 58042441Smckusick * Creat system call. 5816254Sroot */ 58242955Smckusick ocreat(p, uap, retval) 58342441Smckusick struct proc *p; 58442441Smckusick register struct args { 58542441Smckusick char *fname; 58642441Smckusick int fmode; 58742441Smckusick } *uap; 58842441Smckusick int *retval; 5896254Sroot { 59042441Smckusick struct args { 5916254Sroot char *fname; 59242441Smckusick int mode; 59342441Smckusick int crtmode; 59442441Smckusick } openuap; 59542441Smckusick 59642441Smckusick openuap.fname = uap->fname; 59742441Smckusick openuap.crtmode = uap->fmode; 59842441Smckusick openuap.mode = O_WRONLY | O_CREAT | O_TRUNC; 59942441Smckusick RETURN (open(p, &openuap, retval)); 60042441Smckusick } 60142955Smckusick #endif /* COMPAT_43 */ 60242441Smckusick 60342441Smckusick /* 60442441Smckusick * Mknod system call 60542441Smckusick */ 60642441Smckusick /* ARGSUSED */ 60742441Smckusick mknod(p, uap, retval) 608*45914Smckusick struct proc *p; 60942441Smckusick register struct args { 61042441Smckusick char *fname; 6116254Sroot int fmode; 6126254Sroot int dev; 61342441Smckusick } *uap; 61442441Smckusick int *retval; 61542441Smckusick { 61642441Smckusick register struct nameidata *ndp = &u.u_nd; 61737741Smckusick register struct vnode *vp; 61837741Smckusick struct vattr vattr; 61937741Smckusick int error; 6206254Sroot 62142441Smckusick if (error = suser(ndp->ni_cred, &u.u_acflag)) 62237741Smckusick RETURN (error); 62337741Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 62416694Smckusick ndp->ni_segflg = UIO_USERSPACE; 62516694Smckusick ndp->ni_dirp = uap->fname; 62637741Smckusick if (error = namei(ndp)) 62737741Smckusick RETURN (error); 62837741Smckusick vp = ndp->ni_vp; 62937741Smckusick if (vp != NULL) { 63037741Smckusick error = EEXIST; 63112756Ssam goto out; 6326254Sroot } 63341362Smckusick VATTR_NULL(&vattr); 63440635Smckusick switch (uap->fmode & S_IFMT) { 63512756Ssam 63640635Smckusick case S_IFMT: /* used by badsect to flag bad sectors */ 63737741Smckusick vattr.va_type = VBAD; 63837741Smckusick break; 63940635Smckusick case S_IFCHR: 64037741Smckusick vattr.va_type = VCHR; 64137741Smckusick break; 64240635Smckusick case S_IFBLK: 64337741Smckusick vattr.va_type = VBLK; 64437741Smckusick break; 64537741Smckusick default: 64637741Smckusick error = EINVAL; 64737741Smckusick goto out; 6486254Sroot } 649*45914Smckusick vattr.va_mode = (uap->fmode & 07777) &~ p->p_fd->fd_cmask; 65037741Smckusick vattr.va_rdev = uap->dev; 6516254Sroot out: 65242465Smckusick if (!error) { 65342465Smckusick error = VOP_MKNOD(ndp, &vattr, ndp->ni_cred); 65442465Smckusick } else { 65537741Smckusick VOP_ABORTOP(ndp); 65643344Smckusick if (ndp->ni_dvp == vp) 65743344Smckusick vrele(ndp->ni_dvp); 65843344Smckusick else 65943344Smckusick vput(ndp->ni_dvp); 66042465Smckusick if (vp) 66142465Smckusick vrele(vp); 66242465Smckusick } 66337741Smckusick RETURN (error); 6646254Sroot } 6656254Sroot 6666254Sroot /* 66740285Smckusick * Mkfifo system call 66840285Smckusick */ 66942441Smckusick /* ARGSUSED */ 67042441Smckusick mkfifo(p, uap, retval) 671*45914Smckusick struct proc *p; 67242441Smckusick register struct args { 67340285Smckusick char *fname; 67440285Smckusick int fmode; 67542441Smckusick } *uap; 67642441Smckusick int *retval; 67742441Smckusick { 67842441Smckusick register struct nameidata *ndp = &u.u_nd; 67940285Smckusick struct vattr vattr; 68040285Smckusick int error; 68140285Smckusick 68240285Smckusick #ifndef FIFO 68340285Smckusick RETURN (EOPNOTSUPP); 68440285Smckusick #else 68540285Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 68640285Smckusick ndp->ni_segflg = UIO_USERSPACE; 68740285Smckusick ndp->ni_dirp = uap->fname; 68840285Smckusick if (error = namei(ndp)) 68940285Smckusick RETURN (error); 69040285Smckusick if (ndp->ni_vp != NULL) { 69140285Smckusick VOP_ABORTOP(ndp); 69243344Smckusick if (ndp->ni_dvp == ndp->ni_vp) 69343344Smckusick vrele(ndp->ni_dvp); 69443344Smckusick else 69543344Smckusick vput(ndp->ni_dvp); 69642465Smckusick vrele(ndp->ni_vp); 69740285Smckusick RETURN (EEXIST); 69840285Smckusick } 69945785Sbostic VATTR_NULL(&vattr); 70045785Sbostic vattr.va_type = VFIFO; 701*45914Smckusick vattr.va_mode = (uap->fmode & 07777) &~ p->p_fd->fd_cmask; 70240285Smckusick RETURN (VOP_MKNOD(ndp, &vattr, ndp->ni_cred)); 70340285Smckusick #endif /* FIFO */ 70440285Smckusick } 70540285Smckusick 70640285Smckusick /* 7076254Sroot * link system call 7086254Sroot */ 70942441Smckusick /* ARGSUSED */ 71042441Smckusick link(p, uap, retval) 711*45914Smckusick struct proc *p; 71242441Smckusick register struct args { 7136254Sroot char *target; 7146254Sroot char *linkname; 71542441Smckusick } *uap; 71642441Smckusick int *retval; 71742441Smckusick { 71842441Smckusick register struct nameidata *ndp = &u.u_nd; 71937741Smckusick register struct vnode *vp, *xp; 72037741Smckusick int error; 7216254Sroot 72216694Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW; 72316694Smckusick ndp->ni_segflg = UIO_USERSPACE; 72416694Smckusick ndp->ni_dirp = uap->target; 72537741Smckusick if (error = namei(ndp)) 72637741Smckusick RETURN (error); 72737741Smckusick vp = ndp->ni_vp; 72837741Smckusick if (vp->v_type == VDIR && 72942441Smckusick (error = suser(ndp->ni_cred, &u.u_acflag))) 73037741Smckusick goto out1; 73137741Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 73216694Smckusick ndp->ni_dirp = (caddr_t)uap->linkname; 73337741Smckusick if (error = namei(ndp)) 73437741Smckusick goto out1; 73537741Smckusick xp = ndp->ni_vp; 7366254Sroot if (xp != NULL) { 73737741Smckusick error = EEXIST; 7386254Sroot goto out; 7396254Sroot } 74037741Smckusick xp = ndp->ni_dvp; 74137741Smckusick if (vp->v_mount != xp->v_mount) 74237741Smckusick error = EXDEV; 7436254Sroot out: 74442465Smckusick if (!error) { 74542465Smckusick error = VOP_LINK(vp, ndp); 74642465Smckusick } else { 74737741Smckusick VOP_ABORTOP(ndp); 74843344Smckusick if (ndp->ni_dvp == ndp->ni_vp) 74943344Smckusick vrele(ndp->ni_dvp); 75043344Smckusick else 75143344Smckusick vput(ndp->ni_dvp); 75242465Smckusick if (ndp->ni_vp) 75342465Smckusick vrele(ndp->ni_vp); 75442465Smckusick } 75537741Smckusick out1: 75637741Smckusick vrele(vp); 75737741Smckusick RETURN (error); 7586254Sroot } 7596254Sroot 7606254Sroot /* 7616254Sroot * symlink -- make a symbolic link 7626254Sroot */ 76342441Smckusick /* ARGSUSED */ 76442441Smckusick symlink(p, uap, retval) 765*45914Smckusick struct proc *p; 76642441Smckusick register struct args { 7676254Sroot char *target; 7686254Sroot char *linkname; 76942441Smckusick } *uap; 77042441Smckusick int *retval; 77142441Smckusick { 77242441Smckusick register struct nameidata *ndp = &u.u_nd; 77337741Smckusick struct vattr vattr; 77437741Smckusick char *target; 77537741Smckusick int error; 7766254Sroot 77716694Smckusick ndp->ni_segflg = UIO_USERSPACE; 77816694Smckusick ndp->ni_dirp = uap->linkname; 77937741Smckusick MALLOC(target, char *, MAXPATHLEN, M_NAMEI, M_WAITOK); 78037741Smckusick if (error = copyinstr(uap->target, target, MAXPATHLEN, (u_int *)0)) 78142465Smckusick goto out; 78237741Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 78337741Smckusick if (error = namei(ndp)) 78442465Smckusick goto out; 78542465Smckusick if (ndp->ni_vp) { 78642465Smckusick VOP_ABORTOP(ndp); 78743344Smckusick if (ndp->ni_dvp == ndp->ni_vp) 78843344Smckusick vrele(ndp->ni_dvp); 78943344Smckusick else 79043344Smckusick vput(ndp->ni_dvp); 79142465Smckusick vrele(ndp->ni_vp); 79237741Smckusick error = EEXIST; 79337741Smckusick goto out; 7946254Sroot } 79541362Smckusick VATTR_NULL(&vattr); 796*45914Smckusick vattr.va_mode = 0777 &~ p->p_fd->fd_cmask; 79742465Smckusick error = VOP_SYMLINK(ndp, &vattr, target); 79837741Smckusick out: 79937741Smckusick FREE(target, M_NAMEI); 80037741Smckusick RETURN (error); 8016254Sroot } 8026254Sroot 8036254Sroot /* 8046254Sroot * Unlink system call. 8056254Sroot * Hard to avoid races here, especially 8066254Sroot * in unlinking directories. 8076254Sroot */ 80842441Smckusick /* ARGSUSED */ 80942441Smckusick unlink(p, uap, retval) 810*45914Smckusick struct proc *p; 81142441Smckusick struct args { 81242441Smckusick char *fname; 81342441Smckusick } *uap; 81442441Smckusick int *retval; 8156254Sroot { 81642441Smckusick register struct nameidata *ndp = &u.u_nd; 81737741Smckusick register struct vnode *vp; 81837741Smckusick int error; 8196254Sroot 82037741Smckusick ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF; 82116694Smckusick ndp->ni_segflg = UIO_USERSPACE; 82216694Smckusick ndp->ni_dirp = uap->fname; 82337741Smckusick if (error = namei(ndp)) 82437741Smckusick RETURN (error); 82537741Smckusick vp = ndp->ni_vp; 82637741Smckusick if (vp->v_type == VDIR && 82742441Smckusick (error = suser(ndp->ni_cred, &u.u_acflag))) 8286254Sroot goto out; 8296254Sroot /* 8306254Sroot * Don't unlink a mounted file. 8316254Sroot */ 83237741Smckusick if (vp->v_flag & VROOT) { 83337741Smckusick error = EBUSY; 8346254Sroot goto out; 8356254Sroot } 83645738Smckusick (void) vnode_pager_uncache(vp); 8376254Sroot out: 83842465Smckusick if (!error) { 83942465Smckusick error = VOP_REMOVE(ndp); 84042465Smckusick } else { 84137741Smckusick VOP_ABORTOP(ndp); 84243344Smckusick if (ndp->ni_dvp == vp) 84343344Smckusick vrele(ndp->ni_dvp); 84443344Smckusick else 84543344Smckusick vput(ndp->ni_dvp); 84642465Smckusick vput(vp); 84742465Smckusick } 84837741Smckusick RETURN (error); 8496254Sroot } 8506254Sroot 8516254Sroot /* 8526254Sroot * Seek system call 8536254Sroot */ 85442441Smckusick lseek(p, uap, retval) 855*45914Smckusick struct proc *p; 85642441Smckusick register struct args { 85737741Smckusick int fdes; 8586254Sroot off_t off; 8596254Sroot int sbase; 86042441Smckusick } *uap; 86142441Smckusick off_t *retval; 86242441Smckusick { 86342441Smckusick struct ucred *cred = u.u_nd.ni_cred; 864*45914Smckusick register struct filedesc *fdp = p->p_fd; 86542441Smckusick register struct file *fp; 86637741Smckusick struct vattr vattr; 86737741Smckusick int error; 8686254Sroot 869*45914Smckusick if ((unsigned)uap->fdes >= fdp->fd_maxfiles || 870*45914Smckusick (fp = OFILE(fdp, uap->fdes)) == NULL) 87137741Smckusick RETURN (EBADF); 87237741Smckusick if (fp->f_type != DTYPE_VNODE) 87337741Smckusick RETURN (ESPIPE); 87413878Ssam switch (uap->sbase) { 87513878Ssam 87613878Ssam case L_INCR: 87713878Ssam fp->f_offset += uap->off; 87813878Ssam break; 87913878Ssam 88013878Ssam case L_XTND: 88137741Smckusick if (error = VOP_GETATTR((struct vnode *)fp->f_data, 88242441Smckusick &vattr, cred)) 88337741Smckusick RETURN (error); 88437741Smckusick fp->f_offset = uap->off + vattr.va_size; 88513878Ssam break; 88613878Ssam 88713878Ssam case L_SET: 88813878Ssam fp->f_offset = uap->off; 88913878Ssam break; 89013878Ssam 89113878Ssam default: 89237741Smckusick RETURN (EINVAL); 89313878Ssam } 89442441Smckusick *retval = fp->f_offset; 89537741Smckusick RETURN (0); 8966254Sroot } 8976254Sroot 8986254Sroot /* 8996254Sroot * Access system call 9006254Sroot */ 90142441Smckusick /* ARGSUSED */ 90242441Smckusick saccess(p, uap, retval) 903*45914Smckusick struct proc *p; 90442441Smckusick register struct args { 9056254Sroot char *fname; 9066254Sroot int fmode; 90742441Smckusick } *uap; 90842441Smckusick int *retval; 90942441Smckusick { 91042441Smckusick register struct nameidata *ndp = &u.u_nd; 91142441Smckusick register struct ucred *cred = ndp->ni_cred; 91237741Smckusick register struct vnode *vp; 91337741Smckusick int error, mode, svuid, svgid; 9146254Sroot 91542441Smckusick svuid = cred->cr_uid; 91642441Smckusick svgid = cred->cr_groups[0]; 91742441Smckusick cred->cr_uid = p->p_ruid; 91842441Smckusick cred->cr_groups[0] = p->p_rgid; 91937741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 92016694Smckusick ndp->ni_segflg = UIO_USERSPACE; 92116694Smckusick ndp->ni_dirp = uap->fname; 92237741Smckusick if (error = namei(ndp)) 92337741Smckusick goto out1; 92437741Smckusick vp = ndp->ni_vp; 92537741Smckusick /* 92637741Smckusick * fmode == 0 means only check for exist 92737741Smckusick */ 92837741Smckusick if (uap->fmode) { 92937741Smckusick mode = 0; 93037741Smckusick if (uap->fmode & R_OK) 93137741Smckusick mode |= VREAD; 93237741Smckusick if (uap->fmode & W_OK) 93337741Smckusick mode |= VWRITE; 93437741Smckusick if (uap->fmode & X_OK) 93537741Smckusick mode |= VEXEC; 93639543Smckusick if ((mode & VWRITE) == 0 || (error = vn_writechk(vp)) == 0) 93738399Smckusick error = VOP_ACCESS(vp, mode, ndp->ni_cred); 9386254Sroot } 93937741Smckusick vput(vp); 94037741Smckusick out1: 94142441Smckusick cred->cr_uid = svuid; 94242441Smckusick cred->cr_groups[0] = svgid; 94337741Smckusick RETURN (error); 9446254Sroot } 9456254Sroot 9466254Sroot /* 9476574Smckusic * Stat system call. This version follows links. 94837Sbill */ 94942441Smckusick /* ARGSUSED */ 95042441Smckusick stat(p, uap, retval) 951*45914Smckusick struct proc *p; 95242441Smckusick register struct args { 95342441Smckusick char *fname; 95442441Smckusick struct stat *ub; 95542441Smckusick } *uap; 95642441Smckusick int *retval; 95737Sbill { 95842441Smckusick register struct nameidata *ndp = &u.u_nd; 95942441Smckusick struct stat sb; 96042441Smckusick int error; 96137Sbill 96242441Smckusick ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW; 96342441Smckusick ndp->ni_segflg = UIO_USERSPACE; 96442441Smckusick ndp->ni_dirp = uap->fname; 96542441Smckusick if (error = namei(ndp)) 96642441Smckusick RETURN (error); 96742441Smckusick error = vn_stat(ndp->ni_vp, &sb); 96842441Smckusick vput(ndp->ni_vp); 96942441Smckusick if (error) 97042441Smckusick RETURN (error); 97142441Smckusick error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb)); 97242441Smckusick RETURN (error); 97337Sbill } 97437Sbill 97537Sbill /* 9766574Smckusic * Lstat system call. This version does not follow links. 9775992Swnj */ 97842441Smckusick /* ARGSUSED */ 97942441Smckusick lstat(p, uap, retval) 980*45914Smckusick struct proc *p; 98142441Smckusick register struct args { 9825992Swnj char *fname; 98312756Ssam struct stat *ub; 98442441Smckusick } *uap; 98542441Smckusick int *retval; 98642441Smckusick { 98742441Smckusick register struct nameidata *ndp = &u.u_nd; 98812756Ssam struct stat sb; 98937741Smckusick int error; 9905992Swnj 99142441Smckusick ndp->ni_nameiop = LOOKUP | LOCKLEAF | NOFOLLOW; 99216694Smckusick ndp->ni_segflg = UIO_USERSPACE; 99316694Smckusick ndp->ni_dirp = uap->fname; 99437741Smckusick if (error = namei(ndp)) 99537741Smckusick RETURN (error); 99637741Smckusick error = vn_stat(ndp->ni_vp, &sb); 99737741Smckusick vput(ndp->ni_vp); 99837741Smckusick if (error) 99937741Smckusick RETURN (error); 100037741Smckusick error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb)); 100137741Smckusick RETURN (error); 10025992Swnj } 10035992Swnj 10045992Swnj /* 10055992Swnj * Return target name of a symbolic link 100637Sbill */ 100742441Smckusick /* ARGSUSED */ 100842441Smckusick readlink(p, uap, retval) 1009*45914Smckusick struct proc *p; 101042441Smckusick register struct args { 10115992Swnj char *name; 10125992Swnj char *buf; 10135992Swnj int count; 101442441Smckusick } *uap; 101542441Smckusick int *retval; 101642441Smckusick { 101742441Smckusick register struct nameidata *ndp = &u.u_nd; 101837741Smckusick register struct vnode *vp; 101937741Smckusick struct iovec aiov; 102037741Smckusick struct uio auio; 102137741Smckusick int error; 10225992Swnj 102337741Smckusick ndp->ni_nameiop = LOOKUP | LOCKLEAF; 102416694Smckusick ndp->ni_segflg = UIO_USERSPACE; 102516694Smckusick ndp->ni_dirp = uap->name; 102637741Smckusick if (error = namei(ndp)) 102737741Smckusick RETURN (error); 102837741Smckusick vp = ndp->ni_vp; 102937741Smckusick if (vp->v_type != VLNK) { 103037741Smckusick error = EINVAL; 10315992Swnj goto out; 10325992Swnj } 103337741Smckusick aiov.iov_base = uap->buf; 103437741Smckusick aiov.iov_len = uap->count; 103537741Smckusick auio.uio_iov = &aiov; 103637741Smckusick auio.uio_iovcnt = 1; 103737741Smckusick auio.uio_offset = 0; 103837741Smckusick auio.uio_rw = UIO_READ; 103937741Smckusick auio.uio_segflg = UIO_USERSPACE; 104037741Smckusick auio.uio_resid = uap->count; 104137741Smckusick error = VOP_READLINK(vp, &auio, ndp->ni_cred); 10425992Swnj out: 104337741Smckusick vput(vp); 104442441Smckusick *retval = uap->count - auio.uio_resid; 104537741Smckusick RETURN (error); 10465992Swnj } 10475992Swnj 10489167Ssam /* 104938259Smckusick * Change flags of a file given path name. 105038259Smckusick */ 105142441Smckusick /* ARGSUSED */ 105242441Smckusick chflags(p, uap, retval) 1053*45914Smckusick struct proc *p; 105442441Smckusick register struct args { 105538259Smckusick char *fname; 105638259Smckusick int flags; 105742441Smckusick } *uap; 105842441Smckusick int *retval; 105942441Smckusick { 106042441Smckusick register struct nameidata *ndp = &u.u_nd; 106138259Smckusick register struct vnode *vp; 106238259Smckusick struct vattr vattr; 106338259Smckusick int error; 106438259Smckusick 106538259Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 106638259Smckusick ndp->ni_segflg = UIO_USERSPACE; 106738259Smckusick ndp->ni_dirp = uap->fname; 106838259Smckusick if (error = namei(ndp)) 106938259Smckusick RETURN (error); 107038259Smckusick vp = ndp->ni_vp; 107141400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 107238259Smckusick error = EROFS; 107338259Smckusick goto out; 107438259Smckusick } 107545785Sbostic VATTR_NULL(&vattr); 107645785Sbostic vattr.va_flags = uap->flags; 107738259Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 107838259Smckusick out: 107938259Smckusick vput(vp); 108038259Smckusick RETURN (error); 108138259Smckusick } 108238259Smckusick 108338259Smckusick /* 108438259Smckusick * Change flags of a file given a file descriptor. 108538259Smckusick */ 108642441Smckusick /* ARGSUSED */ 108742441Smckusick fchflags(p, uap, retval) 1088*45914Smckusick struct proc *p; 108942441Smckusick register struct args { 109038259Smckusick int fd; 109138259Smckusick int flags; 109242441Smckusick } *uap; 109342441Smckusick int *retval; 109442441Smckusick { 109538259Smckusick struct vattr vattr; 109638259Smckusick struct vnode *vp; 109738259Smckusick struct file *fp; 109838259Smckusick int error; 109938259Smckusick 1100*45914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 110138259Smckusick RETURN (error); 110238259Smckusick vp = (struct vnode *)fp->f_data; 110338259Smckusick VOP_LOCK(vp); 110441400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 110538259Smckusick error = EROFS; 110638259Smckusick goto out; 110738259Smckusick } 110845785Sbostic VATTR_NULL(&vattr); 110945785Sbostic vattr.va_flags = uap->flags; 111038259Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred); 111138259Smckusick out: 111238259Smckusick VOP_UNLOCK(vp); 111338259Smckusick RETURN (error); 111438259Smckusick } 111538259Smckusick 111638259Smckusick /* 11179167Ssam * Change mode of a file given path name. 11189167Ssam */ 111942441Smckusick /* ARGSUSED */ 112042441Smckusick chmod(p, uap, retval) 1121*45914Smckusick struct proc *p; 112242441Smckusick register struct args { 11236254Sroot char *fname; 11246254Sroot int fmode; 112542441Smckusick } *uap; 112642441Smckusick int *retval; 112742441Smckusick { 112842441Smckusick register struct nameidata *ndp = &u.u_nd; 112937741Smckusick register struct vnode *vp; 113037741Smckusick struct vattr vattr; 113137741Smckusick int error; 11325992Swnj 113337741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 113437741Smckusick ndp->ni_segflg = UIO_USERSPACE; 113537741Smckusick ndp->ni_dirp = uap->fname; 113637741Smckusick if (error = namei(ndp)) 113737741Smckusick RETURN (error); 113837741Smckusick vp = ndp->ni_vp; 113941400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 114037741Smckusick error = EROFS; 114137741Smckusick goto out; 114237741Smckusick } 114345785Sbostic VATTR_NULL(&vattr); 114445785Sbostic vattr.va_mode = uap->fmode & 07777; 114537741Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 114637741Smckusick out: 114737741Smckusick vput(vp); 114837741Smckusick RETURN (error); 11497701Ssam } 11507439Sroot 11519167Ssam /* 11529167Ssam * Change mode of a file given a file descriptor. 11539167Ssam */ 115442441Smckusick /* ARGSUSED */ 115542441Smckusick fchmod(p, uap, retval) 1156*45914Smckusick struct proc *p; 115742441Smckusick register struct args { 11587701Ssam int fd; 11597701Ssam int fmode; 116042441Smckusick } *uap; 116142441Smckusick int *retval; 116242441Smckusick { 116337741Smckusick struct vattr vattr; 116437741Smckusick struct vnode *vp; 116537741Smckusick struct file *fp; 116637741Smckusick int error; 11677701Ssam 1168*45914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 116937741Smckusick RETURN (error); 117037741Smckusick vp = (struct vnode *)fp->f_data; 117137741Smckusick VOP_LOCK(vp); 117241400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 117337741Smckusick error = EROFS; 117437741Smckusick goto out; 11757439Sroot } 117645785Sbostic VATTR_NULL(&vattr); 117745785Sbostic vattr.va_mode = uap->fmode & 07777; 117837741Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred); 117937741Smckusick out: 118037741Smckusick VOP_UNLOCK(vp); 118137741Smckusick RETURN (error); 11825992Swnj } 11835992Swnj 11849167Ssam /* 11859167Ssam * Set ownership given a path name. 11869167Ssam */ 118742441Smckusick /* ARGSUSED */ 118842441Smckusick chown(p, uap, retval) 1189*45914Smckusick struct proc *p; 119042441Smckusick register struct args { 11916254Sroot char *fname; 11926254Sroot int uid; 11936254Sroot int gid; 119442441Smckusick } *uap; 119542441Smckusick int *retval; 119642441Smckusick { 119742441Smckusick register struct nameidata *ndp = &u.u_nd; 119837741Smckusick register struct vnode *vp; 119937741Smckusick struct vattr vattr; 120037741Smckusick int error; 120137Sbill 120237741Smckusick ndp->ni_nameiop = LOOKUP | NOFOLLOW | LOCKLEAF; 120336614Sbostic ndp->ni_segflg = UIO_USERSPACE; 120436614Sbostic ndp->ni_dirp = uap->fname; 120537741Smckusick if (error = namei(ndp)) 120637741Smckusick RETURN (error); 120737741Smckusick vp = ndp->ni_vp; 120841400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 120937741Smckusick error = EROFS; 121037741Smckusick goto out; 121137741Smckusick } 121245785Sbostic VATTR_NULL(&vattr); 121345785Sbostic vattr.va_uid = uap->uid; 121445785Sbostic vattr.va_gid = uap->gid; 121537741Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 121637741Smckusick out: 121737741Smckusick vput(vp); 121837741Smckusick RETURN (error); 12197701Ssam } 12207439Sroot 12219167Ssam /* 12229167Ssam * Set ownership given a file descriptor. 12239167Ssam */ 122442441Smckusick /* ARGSUSED */ 122542441Smckusick fchown(p, uap, retval) 1226*45914Smckusick struct proc *p; 122742441Smckusick register struct args { 12287701Ssam int fd; 12297701Ssam int uid; 12307701Ssam int gid; 123142441Smckusick } *uap; 123242441Smckusick int *retval; 123342441Smckusick { 123437741Smckusick struct vattr vattr; 123537741Smckusick struct vnode *vp; 123637741Smckusick struct file *fp; 123737741Smckusick int error; 12387701Ssam 1239*45914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 124037741Smckusick RETURN (error); 124137741Smckusick vp = (struct vnode *)fp->f_data; 124237741Smckusick VOP_LOCK(vp); 124341400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 124437741Smckusick error = EROFS; 124537741Smckusick goto out; 124637741Smckusick } 124745785Sbostic VATTR_NULL(&vattr); 124845785Sbostic vattr.va_uid = uap->uid; 124945785Sbostic vattr.va_gid = uap->gid; 125037741Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred); 125137741Smckusick out: 125237741Smckusick VOP_UNLOCK(vp); 125337741Smckusick RETURN (error); 12547701Ssam } 12557701Ssam 125642441Smckusick /* 125742441Smckusick * Set the access and modification times of a file. 125842441Smckusick */ 125942441Smckusick /* ARGSUSED */ 126042441Smckusick utimes(p, uap, retval) 1261*45914Smckusick struct proc *p; 126242441Smckusick register struct args { 126311811Ssam char *fname; 126411811Ssam struct timeval *tptr; 126542441Smckusick } *uap; 126642441Smckusick int *retval; 126742441Smckusick { 126842441Smckusick register struct nameidata *ndp = &u.u_nd; 126937741Smckusick register struct vnode *vp; 127011811Ssam struct timeval tv[2]; 127137741Smckusick struct vattr vattr; 127237741Smckusick int error; 127311811Ssam 127437741Smckusick if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv))) 127537741Smckusick RETURN (error); 127637741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 127737741Smckusick ndp->ni_segflg = UIO_USERSPACE; 127837741Smckusick ndp->ni_dirp = uap->fname; 127937741Smckusick if (error = namei(ndp)) 128037741Smckusick RETURN (error); 128137741Smckusick vp = ndp->ni_vp; 128241400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 128337741Smckusick error = EROFS; 128437741Smckusick goto out; 128521015Smckusick } 128645785Sbostic VATTR_NULL(&vattr); 128745785Sbostic vattr.va_atime = tv[0]; 128845785Sbostic vattr.va_mtime = tv[1]; 128937741Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 129037741Smckusick out: 129137741Smckusick vput(vp); 129237741Smckusick RETURN (error); 129311811Ssam } 129411811Ssam 12959167Ssam /* 12969167Ssam * Truncate a file given its path name. 12979167Ssam */ 129842441Smckusick /* ARGSUSED */ 129942441Smckusick truncate(p, uap, retval) 1300*45914Smckusick struct proc *p; 130142441Smckusick register struct args { 13027701Ssam char *fname; 130326473Skarels off_t length; 130442441Smckusick } *uap; 130542441Smckusick int *retval; 130642441Smckusick { 130742441Smckusick register struct nameidata *ndp = &u.u_nd; 130837741Smckusick register struct vnode *vp; 130937741Smckusick struct vattr vattr; 131037741Smckusick int error; 13117701Ssam 131237741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 131316694Smckusick ndp->ni_segflg = UIO_USERSPACE; 131416694Smckusick ndp->ni_dirp = uap->fname; 131537741Smckusick if (error = namei(ndp)) 131637741Smckusick RETURN (error); 131737741Smckusick vp = ndp->ni_vp; 131837741Smckusick if (vp->v_type == VDIR) { 131937741Smckusick error = EISDIR; 132037741Smckusick goto out; 13217701Ssam } 132238399Smckusick if ((error = vn_writechk(vp)) || 132338399Smckusick (error = VOP_ACCESS(vp, VWRITE, ndp->ni_cred))) 132437741Smckusick goto out; 132545785Sbostic VATTR_NULL(&vattr); 132645785Sbostic vattr.va_size = uap->length; 132737741Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 132837741Smckusick out: 132937741Smckusick vput(vp); 133037741Smckusick RETURN (error); 13317701Ssam } 13327701Ssam 13339167Ssam /* 13349167Ssam * Truncate a file given a file descriptor. 13359167Ssam */ 133642441Smckusick /* ARGSUSED */ 133742441Smckusick ftruncate(p, uap, retval) 1338*45914Smckusick struct proc *p; 133942441Smckusick register struct args { 13407701Ssam int fd; 134126473Skarels off_t length; 134242441Smckusick } *uap; 134342441Smckusick int *retval; 134442441Smckusick { 134537741Smckusick struct vattr vattr; 134637741Smckusick struct vnode *vp; 13477701Ssam struct file *fp; 134837741Smckusick int error; 13497701Ssam 1350*45914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 135137741Smckusick RETURN (error); 135237741Smckusick if ((fp->f_flag & FWRITE) == 0) 135337741Smckusick RETURN (EINVAL); 135437741Smckusick vp = (struct vnode *)fp->f_data; 135537741Smckusick VOP_LOCK(vp); 135637741Smckusick if (vp->v_type == VDIR) { 135737741Smckusick error = EISDIR; 135837741Smckusick goto out; 13597701Ssam } 136038399Smckusick if (error = vn_writechk(vp)) 136137741Smckusick goto out; 136245785Sbostic VATTR_NULL(&vattr); 136345785Sbostic vattr.va_size = uap->length; 136437741Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred); 136537741Smckusick out: 136637741Smckusick VOP_UNLOCK(vp); 136737741Smckusick RETURN (error); 13687701Ssam } 13697701Ssam 13709167Ssam /* 13719167Ssam * Synch an open file. 13729167Ssam */ 137342441Smckusick /* ARGSUSED */ 137442441Smckusick fsync(p, uap, retval) 1375*45914Smckusick struct proc *p; 137642441Smckusick struct args { 137742441Smckusick int fd; 137842441Smckusick } *uap; 137942441Smckusick int *retval; 13809167Ssam { 138139592Smckusick register struct vnode *vp; 13829167Ssam struct file *fp; 138337741Smckusick int error; 13849167Ssam 1385*45914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 138637741Smckusick RETURN (error); 138739592Smckusick vp = (struct vnode *)fp->f_data; 138839592Smckusick VOP_LOCK(vp); 138939592Smckusick error = VOP_FSYNC(vp, fp->f_flag, fp->f_cred, MNT_WAIT); 139039592Smckusick VOP_UNLOCK(vp); 139137741Smckusick RETURN (error); 13929167Ssam } 13939167Ssam 13949167Ssam /* 13959167Ssam * Rename system call. 13969167Ssam * 13979167Ssam * Source and destination must either both be directories, or both 13989167Ssam * not be directories. If target is a directory, it must be empty. 13999167Ssam */ 140042441Smckusick /* ARGSUSED */ 140142441Smckusick rename(p, uap, retval) 1402*45914Smckusick struct proc *p; 140342441Smckusick register struct args { 14047701Ssam char *from; 14057701Ssam char *to; 140642441Smckusick } *uap; 140742441Smckusick int *retval; 140842441Smckusick { 140937741Smckusick register struct vnode *tvp, *fvp, *tdvp; 141042441Smckusick register struct nameidata *ndp = &u.u_nd; 141137741Smckusick struct nameidata tond; 141237741Smckusick int error; 14137701Ssam 141437741Smckusick ndp->ni_nameiop = DELETE | WANTPARENT; 141516694Smckusick ndp->ni_segflg = UIO_USERSPACE; 141616694Smckusick ndp->ni_dirp = uap->from; 141737741Smckusick if (error = namei(ndp)) 141837741Smckusick RETURN (error); 141937741Smckusick fvp = ndp->ni_vp; 142038266Smckusick nddup(ndp, &tond); 142137741Smckusick tond.ni_nameiop = RENAME | LOCKPARENT | LOCKLEAF | NOCACHE; 142237741Smckusick tond.ni_segflg = UIO_USERSPACE; 142337741Smckusick tond.ni_dirp = uap->to; 142442465Smckusick if (error = namei(&tond)) { 142542465Smckusick VOP_ABORTOP(ndp); 142642465Smckusick vrele(ndp->ni_dvp); 142742465Smckusick vrele(fvp); 142842465Smckusick goto out1; 142942465Smckusick } 143037741Smckusick tdvp = tond.ni_dvp; 143137741Smckusick tvp = tond.ni_vp; 143237741Smckusick if (tvp != NULL) { 143337741Smckusick if (fvp->v_type == VDIR && tvp->v_type != VDIR) { 143439242Sbostic error = ENOTDIR; 143537741Smckusick goto out; 143637741Smckusick } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) { 143739242Sbostic error = EISDIR; 143837741Smckusick goto out; 14399167Ssam } 144045240Smckusick if (fvp->v_mount != tvp->v_mount) { 144145240Smckusick error = EXDEV; 144245240Smckusick goto out; 144345240Smckusick } 14449167Ssam } 144537741Smckusick if (fvp->v_mount != tdvp->v_mount) { 144637741Smckusick error = EXDEV; 14479167Ssam goto out; 144810051Ssam } 144939286Smckusick if (fvp == tdvp) 145037741Smckusick error = EINVAL; 145139286Smckusick /* 145239286Smckusick * If source is the same as the destination, 145339286Smckusick * then there is nothing to do. 145439286Smckusick */ 145539286Smckusick if (fvp == tvp) 145639286Smckusick error = -1; 145737741Smckusick out: 145842465Smckusick if (!error) { 145942465Smckusick error = VOP_RENAME(ndp, &tond); 146042465Smckusick } else { 146137741Smckusick VOP_ABORTOP(&tond); 146243344Smckusick if (tdvp == tvp) 146343344Smckusick vrele(tdvp); 146443344Smckusick else 146543344Smckusick vput(tdvp); 146642465Smckusick if (tvp) 146742465Smckusick vput(tvp); 146837741Smckusick VOP_ABORTOP(ndp); 146942465Smckusick vrele(ndp->ni_dvp); 147042465Smckusick vrele(fvp); 14719167Ssam } 147237741Smckusick out1: 147338266Smckusick ndrele(&tond); 147439286Smckusick if (error == -1) 147539286Smckusick RETURN (0); 147637741Smckusick RETURN (error); 14777701Ssam } 14787701Ssam 14797535Sroot /* 148012756Ssam * Mkdir system call 148112756Ssam */ 148242441Smckusick /* ARGSUSED */ 148342441Smckusick mkdir(p, uap, retval) 1484*45914Smckusick struct proc *p; 148542441Smckusick register struct args { 148612756Ssam char *name; 148712756Ssam int dmode; 148842441Smckusick } *uap; 148942441Smckusick int *retval; 149042441Smckusick { 149142441Smckusick register struct nameidata *ndp = &u.u_nd; 149237741Smckusick register struct vnode *vp; 149337741Smckusick struct vattr vattr; 149437741Smckusick int error; 149512756Ssam 149637741Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 149716694Smckusick ndp->ni_segflg = UIO_USERSPACE; 149816694Smckusick ndp->ni_dirp = uap->name; 149937741Smckusick if (error = namei(ndp)) 150037741Smckusick RETURN (error); 150137741Smckusick vp = ndp->ni_vp; 150237741Smckusick if (vp != NULL) { 150337741Smckusick VOP_ABORTOP(ndp); 150443344Smckusick if (ndp->ni_dvp == vp) 150543344Smckusick vrele(ndp->ni_dvp); 150643344Smckusick else 150743344Smckusick vput(ndp->ni_dvp); 150842465Smckusick vrele(vp); 150937741Smckusick RETURN (EEXIST); 151012756Ssam } 151141362Smckusick VATTR_NULL(&vattr); 151237741Smckusick vattr.va_type = VDIR; 1513*45914Smckusick vattr.va_mode = (uap->dmode & 0777) &~ p->p_fd->fd_cmask; 151437741Smckusick error = VOP_MKDIR(ndp, &vattr); 151538145Smckusick if (!error) 151638145Smckusick vput(ndp->ni_vp); 151737741Smckusick RETURN (error); 151812756Ssam } 151912756Ssam 152012756Ssam /* 152112756Ssam * Rmdir system call. 152212756Ssam */ 152342441Smckusick /* ARGSUSED */ 152442441Smckusick rmdir(p, uap, retval) 1525*45914Smckusick struct proc *p; 152642441Smckusick struct args { 152742441Smckusick char *name; 152842441Smckusick } *uap; 152942441Smckusick int *retval; 153012756Ssam { 153142441Smckusick register struct nameidata *ndp = &u.u_nd; 153237741Smckusick register struct vnode *vp; 153337741Smckusick int error; 153412756Ssam 153537741Smckusick ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF; 153616694Smckusick ndp->ni_segflg = UIO_USERSPACE; 153716694Smckusick ndp->ni_dirp = uap->name; 153837741Smckusick if (error = namei(ndp)) 153937741Smckusick RETURN (error); 154037741Smckusick vp = ndp->ni_vp; 154137741Smckusick if (vp->v_type != VDIR) { 154237741Smckusick error = ENOTDIR; 154312756Ssam goto out; 154412756Ssam } 154512756Ssam /* 154637741Smckusick * No rmdir "." please. 154712756Ssam */ 154837741Smckusick if (ndp->ni_dvp == vp) { 154937741Smckusick error = EINVAL; 155012756Ssam goto out; 155112756Ssam } 155212756Ssam /* 155337741Smckusick * Don't unlink a mounted file. 155412756Ssam */ 155537741Smckusick if (vp->v_flag & VROOT) 155637741Smckusick error = EBUSY; 155712756Ssam out: 155842465Smckusick if (!error) { 155942465Smckusick error = VOP_RMDIR(ndp); 156042465Smckusick } else { 156137741Smckusick VOP_ABORTOP(ndp); 156243344Smckusick if (ndp->ni_dvp == vp) 156343344Smckusick vrele(ndp->ni_dvp); 156443344Smckusick else 156543344Smckusick vput(ndp->ni_dvp); 156642465Smckusick vput(vp); 156742465Smckusick } 156837741Smckusick RETURN (error); 156912756Ssam } 157012756Ssam 157137741Smckusick /* 157237741Smckusick * Read a block of directory entries in a file system independent format 157337741Smckusick */ 157442441Smckusick getdirentries(p, uap, retval) 1575*45914Smckusick struct proc *p; 157642441Smckusick register struct args { 157737741Smckusick int fd; 157837741Smckusick char *buf; 157937741Smckusick unsigned count; 158037741Smckusick long *basep; 158142441Smckusick } *uap; 158242441Smckusick int *retval; 158342441Smckusick { 158439592Smckusick register struct vnode *vp; 158516540Ssam struct file *fp; 158637741Smckusick struct uio auio; 158737741Smckusick struct iovec aiov; 158838129Smckusick off_t off; 158940321Smckusick int error, eofflag; 159012756Ssam 1591*45914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 159237741Smckusick RETURN (error); 159337741Smckusick if ((fp->f_flag & FREAD) == 0) 159437741Smckusick RETURN (EBADF); 159539592Smckusick vp = (struct vnode *)fp->f_data; 159639592Smckusick if (vp->v_type != VDIR) 159739592Smckusick RETURN (EINVAL); 159837741Smckusick aiov.iov_base = uap->buf; 159937741Smckusick aiov.iov_len = uap->count; 160037741Smckusick auio.uio_iov = &aiov; 160137741Smckusick auio.uio_iovcnt = 1; 160237741Smckusick auio.uio_rw = UIO_READ; 160337741Smckusick auio.uio_segflg = UIO_USERSPACE; 160437741Smckusick auio.uio_resid = uap->count; 160539592Smckusick VOP_LOCK(vp); 160639592Smckusick auio.uio_offset = off = fp->f_offset; 160740321Smckusick error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag); 160839592Smckusick fp->f_offset = auio.uio_offset; 160939592Smckusick VOP_UNLOCK(vp); 161039592Smckusick if (error) 161137741Smckusick RETURN (error); 161239592Smckusick error = copyout((caddr_t)&off, (caddr_t)uap->basep, sizeof(long)); 161342441Smckusick *retval = uap->count - auio.uio_resid; 161437741Smckusick RETURN (error); 161512756Ssam } 161612756Ssam 161712756Ssam /* 161812756Ssam * mode mask for creation of files 161912756Ssam */ 162042441Smckusick mode_t 162142441Smckusick umask(p, uap, retval) 1622*45914Smckusick struct proc *p; 162342441Smckusick struct args { 162442441Smckusick int mask; 162542441Smckusick } *uap; 162642441Smckusick int *retval; 162712756Ssam { 1628*45914Smckusick register struct filedesc *fdp = p->p_fd; 162912756Ssam 1630*45914Smckusick *retval = fdp->fd_cmask; 1631*45914Smckusick fdp->fd_cmask = uap->mask & 07777; 163237741Smckusick RETURN (0); 163312756Ssam } 163437741Smckusick 163539566Smarc /* 163639566Smarc * Void all references to file by ripping underlying filesystem 163739566Smarc * away from vnode. 163839566Smarc */ 163942441Smckusick /* ARGSUSED */ 164042441Smckusick revoke(p, uap, retval) 1641*45914Smckusick struct proc *p; 164242441Smckusick register struct args { 164339566Smarc char *fname; 164442441Smckusick } *uap; 164542441Smckusick int *retval; 164642441Smckusick { 164742441Smckusick register struct nameidata *ndp = &u.u_nd; 164839566Smarc register struct vnode *vp; 164939566Smarc struct vattr vattr; 165039566Smarc int error; 165139566Smarc 165239566Smarc ndp->ni_nameiop = LOOKUP | FOLLOW; 165339566Smarc ndp->ni_segflg = UIO_USERSPACE; 165439566Smarc ndp->ni_dirp = uap->fname; 165539566Smarc if (error = namei(ndp)) 165639566Smarc RETURN (error); 165739566Smarc vp = ndp->ni_vp; 165839566Smarc if (vp->v_type != VCHR && vp->v_type != VBLK) { 165939566Smarc error = EINVAL; 166039566Smarc goto out; 166139566Smarc } 166242441Smckusick if (error = VOP_GETATTR(vp, &vattr, ndp->ni_cred)) 166339566Smarc goto out; 166442955Smckusick if (ndp->ni_cred->cr_uid != vattr.va_uid && 166542441Smckusick (error = suser(ndp->ni_cred, &u.u_acflag))) 166639566Smarc goto out; 166739805Smckusick if (vp->v_usecount > 1 || (vp->v_flag & VALIASED)) 166839632Smckusick vgoneall(vp); 166939566Smarc out: 167039566Smarc vrele(vp); 167139566Smarc RETURN (error); 167239566Smarc } 167339566Smarc 1674*45914Smckusick getvnode(fdp, fdes, fpp) 1675*45914Smckusick struct filedesc *fdp; 167637741Smckusick struct file **fpp; 167737741Smckusick int fdes; 167837741Smckusick { 167937741Smckusick struct file *fp; 168037741Smckusick 1681*45914Smckusick if ((unsigned)fdes >= fdp->fd_maxfiles || 1682*45914Smckusick (fp = OFILE(fdp, fdes)) == NULL) 168337741Smckusick return (EBADF); 168437741Smckusick if (fp->f_type != DTYPE_VNODE) 168537741Smckusick return (EINVAL); 168637741Smckusick *fpp = fp; 168737741Smckusick return (0); 168837741Smckusick } 1689