123405Smckusick /* 237741Smckusick * Copyright (c) 1989 The Regents of the University of California. 337741Smckusick * All rights reserved. 423405Smckusick * 537741Smckusick * Redistribution and use in source and binary forms are permitted 637741Smckusick * provided that the above copyright notice and this paragraph are 737741Smckusick * duplicated in all such forms and that any documentation, 837741Smckusick * advertising materials, and other materials related to such 937741Smckusick * distribution and use acknowledge that the software was developed 1037741Smckusick * by the University of California, Berkeley. The name of the 1137741Smckusick * University may not be used to endorse or promote products derived 1237741Smckusick * from this software without specific prior written permission. 1337741Smckusick * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1437741Smckusick * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1537741Smckusick * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1637741Smckusick * 17*44407Skarels * @(#)vfs_syscalls.c 7.55 (Berkeley) 06/28/90 1823405Smckusick */ 1937Sbill 2017101Sbloom #include "param.h" 2117101Sbloom #include "systm.h" 22*44407Skarels #include "user.h" 2317101Sbloom #include "kernel.h" 2417101Sbloom #include "file.h" 2517101Sbloom #include "stat.h" 2637741Smckusick #include "vnode.h" 2737741Smckusick #include "mount.h" 2817101Sbloom #include "proc.h" 2917101Sbloom #include "uio.h" 3037741Smckusick #include "malloc.h" 3137Sbill 3243450Smckusick #define RETURN(val) {if (u.u_spare[0] != 0) panic("lock count"); return (val);} 3339797Smckusick 3437741Smckusick /* 3537741Smckusick * Virtual File System System Calls 3637741Smckusick */ 3712756Ssam 389167Ssam /* 3937741Smckusick * mount system call 409167Ssam */ 4142441Smckusick /* ARGSUSED */ 4242441Smckusick mount(p, uap, retval) 4342441Smckusick register struct proc *p; 4442441Smckusick register struct args { 4537741Smckusick int type; 4637741Smckusick char *dir; 4737741Smckusick int flags; 4837741Smckusick caddr_t data; 4942441Smckusick } *uap; 5042441Smckusick int *retval; 5142441Smckusick { 5242441Smckusick register struct nameidata *ndp = &u.u_nd; 5339335Smckusick register struct vnode *vp; 5439335Smckusick register struct mount *mp; 5540111Smckusick int error, flag; 566254Sroot 5737741Smckusick /* 5837741Smckusick * Must be super user 5937741Smckusick */ 6042441Smckusick if (error = suser(ndp->ni_cred, &u.u_acflag)) 6137741Smckusick RETURN (error); 6237741Smckusick /* 6337741Smckusick * Get vnode to be covered 6437741Smckusick */ 6537741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 6637741Smckusick ndp->ni_segflg = UIO_USERSPACE; 6737741Smckusick ndp->ni_dirp = uap->dir; 6837741Smckusick if (error = namei(ndp)) 6937741Smckusick RETURN (error); 7037741Smckusick vp = ndp->ni_vp; 7141400Smckusick if (uap->flags & MNT_UPDATE) { 7239335Smckusick if ((vp->v_flag & VROOT) == 0) { 7339335Smckusick vput(vp); 7439335Smckusick RETURN (EINVAL); 7539335Smckusick } 7639335Smckusick mp = vp->v_mount; 7739335Smckusick /* 7839335Smckusick * We allow going from read-only to read-write, 7939335Smckusick * but not from read-write to read-only. 8039335Smckusick */ 8141400Smckusick if ((mp->mnt_flag & MNT_RDONLY) == 0 && 8241400Smckusick (uap->flags & MNT_RDONLY) != 0) { 8339335Smckusick vput(vp); 8439335Smckusick RETURN (EOPNOTSUPP); /* Needs translation */ 8539335Smckusick } 8641400Smckusick flag = mp->mnt_flag; 8741400Smckusick mp->mnt_flag |= MNT_UPDATE; 8839335Smckusick VOP_UNLOCK(vp); 8939335Smckusick goto update; 9039335Smckusick } 9139665Smckusick vinvalbuf(vp, 1); 9239805Smckusick if (vp->v_usecount != 1) { 9337741Smckusick vput(vp); 9437741Smckusick RETURN (EBUSY); 9537741Smckusick } 9637741Smckusick if (vp->v_type != VDIR) { 9737741Smckusick vput(vp); 9837741Smckusick RETURN (ENOTDIR); 9937741Smckusick } 10039741Smckusick if ((unsigned long)uap->type > MOUNT_MAXTYPE || 10137741Smckusick vfssw[uap->type] == (struct vfsops *)0) { 10237741Smckusick vput(vp); 10337741Smckusick RETURN (ENODEV); 10437741Smckusick } 10537741Smckusick 10637741Smckusick /* 10739335Smckusick * Allocate and initialize the file system. 10837741Smckusick */ 10937741Smckusick mp = (struct mount *)malloc((u_long)sizeof(struct mount), 11037741Smckusick M_MOUNT, M_WAITOK); 11141400Smckusick mp->mnt_op = vfssw[uap->type]; 11241400Smckusick mp->mnt_flag = 0; 11341400Smckusick mp->mnt_exroot = 0; 11441400Smckusick mp->mnt_mounth = NULLVP; 11539335Smckusick if (error = vfs_lock(mp)) { 11639335Smckusick free((caddr_t)mp, M_MOUNT); 11739335Smckusick vput(vp); 11839335Smckusick RETURN (error); 11939335Smckusick } 12039335Smckusick if (vp->v_mountedhere != (struct mount *)0) { 12139335Smckusick vfs_unlock(mp); 12239335Smckusick free((caddr_t)mp, M_MOUNT); 12339335Smckusick vput(vp); 12439335Smckusick RETURN (EBUSY); 12539335Smckusick } 12639335Smckusick vp->v_mountedhere = mp; 12741400Smckusick mp->mnt_vnodecovered = vp; 12839335Smckusick update: 12939335Smckusick /* 13039335Smckusick * Set the mount level flags. 13139335Smckusick */ 13241400Smckusick if (uap->flags & MNT_RDONLY) 13341400Smckusick mp->mnt_flag |= MNT_RDONLY; 13439335Smckusick else 13541400Smckusick mp->mnt_flag &= ~MNT_RDONLY; 13641400Smckusick if (uap->flags & MNT_NOSUID) 13741400Smckusick mp->mnt_flag |= MNT_NOSUID; 13839335Smckusick else 13941400Smckusick mp->mnt_flag &= ~MNT_NOSUID; 14041400Smckusick if (uap->flags & MNT_NOEXEC) 14141400Smckusick mp->mnt_flag |= MNT_NOEXEC; 14239335Smckusick else 14341400Smckusick mp->mnt_flag &= ~MNT_NOEXEC; 14441400Smckusick if (uap->flags & MNT_NODEV) 14541400Smckusick mp->mnt_flag |= MNT_NODEV; 14639335Smckusick else 14741400Smckusick mp->mnt_flag &= ~MNT_NODEV; 14841400Smckusick if (uap->flags & MNT_SYNCHRONOUS) 14941400Smckusick mp->mnt_flag |= MNT_SYNCHRONOUS; 15039335Smckusick else 15141400Smckusick mp->mnt_flag &= ~MNT_SYNCHRONOUS; 15239335Smckusick /* 15339335Smckusick * Mount the filesystem. 15439335Smckusick */ 15539335Smckusick error = VFS_MOUNT(mp, uap->dir, uap->data, ndp); 15641400Smckusick if (mp->mnt_flag & MNT_UPDATE) { 15741400Smckusick mp->mnt_flag &= ~MNT_UPDATE; 15839335Smckusick vrele(vp); 15940111Smckusick if (error) 16041400Smckusick mp->mnt_flag = flag; 16139335Smckusick RETURN (error); 16239335Smckusick } 16340110Smckusick /* 16440110Smckusick * Put the new filesystem on the mount list after root. 16540110Smckusick */ 16641400Smckusick mp->mnt_next = rootfs->mnt_next; 16741400Smckusick mp->mnt_prev = rootfs; 16841400Smckusick rootfs->mnt_next = mp; 16941400Smckusick mp->mnt_next->mnt_prev = mp; 17037741Smckusick cache_purge(vp); 17137741Smckusick if (!error) { 17239335Smckusick VOP_UNLOCK(vp); 17337741Smckusick vfs_unlock(mp); 17439044Smckusick error = VFS_START(mp, 0); 17537741Smckusick } else { 17637741Smckusick vfs_remove(mp); 17737741Smckusick free((caddr_t)mp, M_MOUNT); 17839335Smckusick vput(vp); 17937741Smckusick } 18037741Smckusick RETURN (error); 1816254Sroot } 1826254Sroot 1839167Ssam /* 18437741Smckusick * Unmount system call. 18537741Smckusick * 18637741Smckusick * Note: unmount takes a path to the vnode mounted on as argument, 18737741Smckusick * not special file (as before). 1889167Ssam */ 18942441Smckusick /* ARGSUSED */ 19042441Smckusick unmount(p, uap, retval) 19142441Smckusick register struct proc *p; 19242441Smckusick register struct args { 19337741Smckusick char *pathp; 19437741Smckusick int flags; 19542441Smckusick } *uap; 19642441Smckusick int *retval; 19742441Smckusick { 19837741Smckusick register struct vnode *vp; 19942441Smckusick register struct nameidata *ndp = &u.u_nd; 20039356Smckusick struct mount *mp; 20137741Smckusick int error; 2026254Sroot 20337741Smckusick /* 20437741Smckusick * Must be super user 20537741Smckusick */ 20642441Smckusick if (error = suser(ndp->ni_cred, &u.u_acflag)) 20737741Smckusick RETURN (error); 20837741Smckusick 20937741Smckusick ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW; 21037741Smckusick ndp->ni_segflg = UIO_USERSPACE; 21137741Smckusick ndp->ni_dirp = uap->pathp; 21237741Smckusick if (error = namei(ndp)) 21337741Smckusick RETURN (error); 21437741Smckusick vp = ndp->ni_vp; 21537741Smckusick /* 21637741Smckusick * Must be the root of the filesystem 21737741Smckusick */ 21837741Smckusick if ((vp->v_flag & VROOT) == 0) { 21937741Smckusick vput(vp); 22037741Smckusick RETURN (EINVAL); 22137741Smckusick } 22237741Smckusick mp = vp->v_mount; 22337741Smckusick vput(vp); 22439356Smckusick RETURN (dounmount(mp, uap->flags)); 22539356Smckusick } 22639356Smckusick 22739356Smckusick /* 22839356Smckusick * Do an unmount. 22939356Smckusick */ 23039356Smckusick dounmount(mp, flags) 23139356Smckusick register struct mount *mp; 23239356Smckusick int flags; 23339356Smckusick { 23439356Smckusick struct vnode *coveredvp; 23539356Smckusick int error; 23639356Smckusick 23741400Smckusick coveredvp = mp->mnt_vnodecovered; 23841298Smckusick if (vfs_busy(mp)) 23941298Smckusick return (EBUSY); 24041400Smckusick mp->mnt_flag |= MNT_UNMOUNT; 24137741Smckusick if (error = vfs_lock(mp)) 24239356Smckusick return (error); 24337741Smckusick 24437741Smckusick xumount(mp); /* remove unused sticky files from text table */ 24537741Smckusick cache_purgevfs(mp); /* remove cache entries for this file sys */ 24641676Smckusick if ((error = VFS_SYNC(mp, MNT_WAIT)) == 0 || (flags & MNT_FORCE)) 24741676Smckusick error = VFS_UNMOUNT(mp, flags); 24841400Smckusick mp->mnt_flag &= ~MNT_UNMOUNT; 24941298Smckusick vfs_unbusy(mp); 25037741Smckusick if (error) { 25137741Smckusick vfs_unlock(mp); 25237741Smckusick } else { 25337741Smckusick vrele(coveredvp); 25437741Smckusick vfs_remove(mp); 25537741Smckusick free((caddr_t)mp, M_MOUNT); 25637741Smckusick } 25739356Smckusick return (error); 2586254Sroot } 2596254Sroot 2609167Ssam /* 26137741Smckusick * Sync system call. 26237741Smckusick * Sync each mounted filesystem. 2639167Ssam */ 26439491Smckusick /* ARGSUSED */ 26542441Smckusick sync(p, uap, retval) 26642441Smckusick register struct proc *p; 26742441Smckusick struct args *uap; 26842441Smckusick int *retval; 2696254Sroot { 27037741Smckusick register struct mount *mp; 27141298Smckusick struct mount *omp; 27237741Smckusick 27337741Smckusick mp = rootfs; 27437741Smckusick do { 27540343Smckusick /* 27640343Smckusick * The lock check below is to avoid races with mount 27740343Smckusick * and unmount. 27840343Smckusick */ 27941400Smckusick if ((mp->mnt_flag & (MNT_MLOCK|MNT_RDONLY|MNT_MPBUSY)) == 0 && 28041298Smckusick !vfs_busy(mp)) { 28137741Smckusick VFS_SYNC(mp, MNT_NOWAIT); 28241298Smckusick omp = mp; 28341400Smckusick mp = mp->mnt_next; 28441298Smckusick vfs_unbusy(omp); 28541298Smckusick } else 28641400Smckusick mp = mp->mnt_next; 28737741Smckusick } while (mp != rootfs); 28837741Smckusick } 28937741Smckusick 29037741Smckusick /* 29141298Smckusick * operate on filesystem quotas 29241298Smckusick */ 29342441Smckusick /* ARGSUSED */ 29442441Smckusick quotactl(p, uap, retval) 29542441Smckusick register struct proc *p; 29642441Smckusick register struct args { 29741298Smckusick char *path; 29841298Smckusick int cmd; 29941298Smckusick int uid; 30041298Smckusick caddr_t arg; 30142441Smckusick } *uap; 30242441Smckusick int *retval; 30342441Smckusick { 30441298Smckusick register struct mount *mp; 30542441Smckusick register struct nameidata *ndp = &u.u_nd; 30641298Smckusick int error; 30741298Smckusick 30841298Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW; 30941298Smckusick ndp->ni_segflg = UIO_USERSPACE; 31041298Smckusick ndp->ni_dirp = uap->path; 31141298Smckusick if (error = namei(ndp)) 31241298Smckusick RETURN (error); 31341298Smckusick mp = ndp->ni_vp->v_mount; 31441298Smckusick vrele(ndp->ni_vp); 31541298Smckusick RETURN (VFS_QUOTACTL(mp, uap->cmd, uap->uid, uap->arg)); 31641298Smckusick } 31741298Smckusick 31841298Smckusick /* 31937741Smckusick * get filesystem statistics 32037741Smckusick */ 32142441Smckusick /* ARGSUSED */ 32242441Smckusick statfs(p, uap, retval) 32342441Smckusick register struct proc *p; 32442441Smckusick register struct args { 32537741Smckusick char *path; 32637741Smckusick struct statfs *buf; 32742441Smckusick } *uap; 32842441Smckusick int *retval; 32942441Smckusick { 33039464Smckusick register struct mount *mp; 33142441Smckusick register struct nameidata *ndp = &u.u_nd; 33240343Smckusick register struct statfs *sp; 33337741Smckusick int error; 33437741Smckusick 33539544Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW; 33637741Smckusick ndp->ni_segflg = UIO_USERSPACE; 33737741Smckusick ndp->ni_dirp = uap->path; 33837741Smckusick if (error = namei(ndp)) 33937741Smckusick RETURN (error); 34039544Smckusick mp = ndp->ni_vp->v_mount; 34141400Smckusick sp = &mp->mnt_stat; 34239544Smckusick vrele(ndp->ni_vp); 34340343Smckusick if (error = VFS_STATFS(mp, sp)) 34439544Smckusick RETURN (error); 34541400Smckusick sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 34640343Smckusick RETURN (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp))); 34737741Smckusick } 34837741Smckusick 34942441Smckusick /* 35042441Smckusick * get filesystem statistics 35142441Smckusick */ 35242441Smckusick /* ARGSUSED */ 35342441Smckusick fstatfs(p, uap, retval) 35442441Smckusick register struct proc *p; 35542441Smckusick register struct args { 35637741Smckusick int fd; 35737741Smckusick struct statfs *buf; 35842441Smckusick } *uap; 35942441Smckusick int *retval; 36042441Smckusick { 36137741Smckusick struct file *fp; 36239464Smckusick struct mount *mp; 36340343Smckusick register struct statfs *sp; 36437741Smckusick int error; 36537741Smckusick 36642441Smckusick if (error = getvnode(u.u_ofile, uap->fd, &fp)) 36737741Smckusick RETURN (error); 36839464Smckusick mp = ((struct vnode *)fp->f_data)->v_mount; 36941400Smckusick sp = &mp->mnt_stat; 37040343Smckusick if (error = VFS_STATFS(mp, sp)) 37137741Smckusick RETURN (error); 37241400Smckusick sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 37340343Smckusick RETURN (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp))); 37437741Smckusick } 37537741Smckusick 37637741Smckusick /* 37738270Smckusick * get statistics on all filesystems 37838270Smckusick */ 37942441Smckusick getfsstat(p, uap, retval) 38042441Smckusick register struct proc *p; 38142441Smckusick register struct args { 38238270Smckusick struct statfs *buf; 38338270Smckusick long bufsize; 38440343Smckusick int flags; 38542441Smckusick } *uap; 38642441Smckusick int *retval; 38742441Smckusick { 38838270Smckusick register struct mount *mp; 38940343Smckusick register struct statfs *sp; 39039606Smckusick caddr_t sfsp; 39138270Smckusick long count, maxcount, error; 39238270Smckusick 39338270Smckusick maxcount = uap->bufsize / sizeof(struct statfs); 39439606Smckusick sfsp = (caddr_t)uap->buf; 39538270Smckusick mp = rootfs; 39638270Smckusick count = 0; 39738270Smckusick do { 39841400Smckusick if (sfsp && count < maxcount && 39941400Smckusick ((mp->mnt_flag & MNT_MLOCK) == 0)) { 40041400Smckusick sp = &mp->mnt_stat; 40140343Smckusick /* 40240343Smckusick * If MNT_NOWAIT is specified, do not refresh the 40340343Smckusick * fsstat cache. MNT_WAIT overrides MNT_NOWAIT. 40440343Smckusick */ 40540343Smckusick if (((uap->flags & MNT_NOWAIT) == 0 || 40640343Smckusick (uap->flags & MNT_WAIT)) && 40740343Smckusick (error = VFS_STATFS(mp, sp))) { 40841400Smckusick mp = mp->mnt_prev; 40939607Smckusick continue; 41039607Smckusick } 41141400Smckusick sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 41240343Smckusick if (error = copyout((caddr_t)sp, sfsp, sizeof(*sp))) 41339606Smckusick RETURN (error); 41440343Smckusick sfsp += sizeof(*sp); 41538270Smckusick } 41639606Smckusick count++; 41741400Smckusick mp = mp->mnt_prev; 41838270Smckusick } while (mp != rootfs); 41938270Smckusick if (sfsp && count > maxcount) 42042441Smckusick *retval = maxcount; 42138270Smckusick else 42242441Smckusick *retval = count; 42338270Smckusick RETURN (0); 42438270Smckusick } 42538270Smckusick 42638270Smckusick /* 42738259Smckusick * Change current working directory to a given file descriptor. 42838259Smckusick */ 42942441Smckusick /* ARGSUSED */ 43042441Smckusick fchdir(p, uap, retval) 43142441Smckusick register struct proc *p; 43242441Smckusick struct args { 43342441Smckusick int fd; 43442441Smckusick } *uap; 43542441Smckusick int *retval; 43638259Smckusick { 43742441Smckusick register struct nameidata *ndp = &u.u_nd; 43838259Smckusick register struct vnode *vp; 43938259Smckusick struct file *fp; 44038259Smckusick int error; 44138259Smckusick 44242441Smckusick if (error = getvnode(u.u_ofile, uap->fd, &fp)) 44338259Smckusick RETURN (error); 44438259Smckusick vp = (struct vnode *)fp->f_data; 44538259Smckusick VOP_LOCK(vp); 44638259Smckusick if (vp->v_type != VDIR) 44738259Smckusick error = ENOTDIR; 44838259Smckusick else 44942441Smckusick error = VOP_ACCESS(vp, VEXEC, ndp->ni_cred); 45038259Smckusick VOP_UNLOCK(vp); 45139860Smckusick if (error) 45239860Smckusick RETURN (error); 45339860Smckusick VREF(vp); 45442441Smckusick vrele(ndp->ni_cdir); 45542441Smckusick ndp->ni_cdir = vp; 45639860Smckusick RETURN (0); 45738259Smckusick } 45838259Smckusick 45938259Smckusick /* 46037741Smckusick * Change current working directory (``.''). 46137741Smckusick */ 46242441Smckusick /* ARGSUSED */ 46342441Smckusick chdir(p, uap, retval) 46442441Smckusick register struct proc *p; 46542441Smckusick struct args { 46642441Smckusick char *fname; 46742441Smckusick } *uap; 46842441Smckusick int *retval; 46937741Smckusick { 47042441Smckusick register struct nameidata *ndp = &u.u_nd; 47137741Smckusick int error; 4726254Sroot 47337741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 47416694Smckusick ndp->ni_segflg = UIO_USERSPACE; 47516694Smckusick ndp->ni_dirp = uap->fname; 47637741Smckusick if (error = chdirec(ndp)) 47737741Smckusick RETURN (error); 47842441Smckusick vrele(ndp->ni_cdir); 47942441Smckusick ndp->ni_cdir = ndp->ni_vp; 48037741Smckusick RETURN (0); 48137741Smckusick } 4826254Sroot 48337741Smckusick /* 48437741Smckusick * Change notion of root (``/'') directory. 48537741Smckusick */ 48642441Smckusick /* ARGSUSED */ 48742441Smckusick chroot(p, uap, retval) 48842441Smckusick register struct proc *p; 48942441Smckusick struct args { 49042441Smckusick char *fname; 49142441Smckusick } *uap; 49242441Smckusick int *retval; 49337741Smckusick { 49442441Smckusick register struct nameidata *ndp = &u.u_nd; 49537741Smckusick int error; 49637741Smckusick 49742441Smckusick if (error = suser(ndp->ni_cred, &u.u_acflag)) 49837741Smckusick RETURN (error); 49937741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 50037741Smckusick ndp->ni_segflg = UIO_USERSPACE; 50137741Smckusick ndp->ni_dirp = uap->fname; 50237741Smckusick if (error = chdirec(ndp)) 50337741Smckusick RETURN (error); 50442441Smckusick if (ndp->ni_rdir != NULL) 50542441Smckusick vrele(ndp->ni_rdir); 50642441Smckusick ndp->ni_rdir = ndp->ni_vp; 50737741Smckusick RETURN (0); 5086254Sroot } 5096254Sroot 51037Sbill /* 51137741Smckusick * Common routine for chroot and chdir. 51237741Smckusick */ 51337741Smckusick chdirec(ndp) 51437741Smckusick register struct nameidata *ndp; 51537741Smckusick { 51637741Smckusick struct vnode *vp; 51737741Smckusick int error; 51837741Smckusick 51937741Smckusick if (error = namei(ndp)) 52037741Smckusick return (error); 52137741Smckusick vp = ndp->ni_vp; 52237741Smckusick if (vp->v_type != VDIR) 52337741Smckusick error = ENOTDIR; 52437741Smckusick else 52538399Smckusick error = VOP_ACCESS(vp, VEXEC, ndp->ni_cred); 52637741Smckusick VOP_UNLOCK(vp); 52737741Smckusick if (error) 52837741Smckusick vrele(vp); 52937741Smckusick return (error); 53037741Smckusick } 53137741Smckusick 53237741Smckusick /* 5336254Sroot * Open system call. 53442441Smckusick * Check permissions, allocate an open file structure, 53542441Smckusick * and call the device open routine if any. 5366254Sroot */ 53742441Smckusick open(p, uap, retval) 53842441Smckusick register struct proc *p; 53942441Smckusick register struct args { 5406254Sroot char *fname; 5417701Ssam int mode; 54212756Ssam int crtmode; 54342441Smckusick } *uap; 54442441Smckusick int *retval; 5456254Sroot { 54642441Smckusick struct nameidata *ndp = &u.u_nd; 54742441Smckusick register struct file *fp; 54837741Smckusick int fmode, cmode; 54937741Smckusick struct file *nfp; 55037741Smckusick int indx, error; 55137741Smckusick extern struct fileops vnops; 5526254Sroot 55337741Smckusick if (error = falloc(&nfp, &indx)) 55442441Smckusick RETURN (error); 55537741Smckusick fp = nfp; 55642441Smckusick fmode = uap->mode - FOPEN; 55742441Smckusick cmode = ((uap->crtmode &~ u.u_cmask) & 07777) &~ S_ISVTX; 55842441Smckusick ndp->ni_segflg = UIO_USERSPACE; 55942441Smckusick ndp->ni_dirp = uap->fname; 56043450Smckusick p->p_dupfd = -1; /* XXX check for fdopen */ 56142441Smckusick if (error = vn_open(ndp, fmode, cmode)) { 56237741Smckusick crfree(fp->f_cred); 56337741Smckusick fp->f_count--; 56443405Smckusick if (error == ENODEV && /* XXX from fdopen */ 56543450Smckusick p->p_dupfd >= 0 && 56643450Smckusick (error = dupfdopen(indx, p->p_dupfd, fmode)) == 0) { 56742441Smckusick *retval = indx; 56842441Smckusick RETURN (0); 56942441Smckusick } 57040884Smckusick if (error == ERESTART) 57140884Smckusick error = EINTR; 57242441Smckusick u.u_ofile[indx] = NULL; 57342441Smckusick RETURN (error); 57412756Ssam } 57537741Smckusick fp->f_flag = fmode & FMASK; 57637741Smckusick fp->f_type = DTYPE_VNODE; 57737741Smckusick fp->f_ops = &vnops; 57837741Smckusick fp->f_data = (caddr_t)ndp->ni_vp; 57942441Smckusick *retval = indx; 58042441Smckusick RETURN (0); 5816254Sroot } 5826254Sroot 58342955Smckusick #ifdef COMPAT_43 5846254Sroot /* 58542441Smckusick * Creat system call. 5866254Sroot */ 58742955Smckusick ocreat(p, uap, retval) 58842441Smckusick struct proc *p; 58942441Smckusick register struct args { 59042441Smckusick char *fname; 59142441Smckusick int fmode; 59242441Smckusick } *uap; 59342441Smckusick int *retval; 5946254Sroot { 59542441Smckusick struct args { 5966254Sroot char *fname; 59742441Smckusick int mode; 59842441Smckusick int crtmode; 59942441Smckusick } openuap; 60042441Smckusick 60142441Smckusick openuap.fname = uap->fname; 60242441Smckusick openuap.crtmode = uap->fmode; 60342441Smckusick openuap.mode = O_WRONLY | O_CREAT | O_TRUNC; 60442441Smckusick RETURN (open(p, &openuap, retval)); 60542441Smckusick } 60642955Smckusick #endif /* COMPAT_43 */ 60742441Smckusick 60842441Smckusick /* 60942441Smckusick * Mknod system call 61042441Smckusick */ 61142441Smckusick /* ARGSUSED */ 61242441Smckusick mknod(p, uap, retval) 61342441Smckusick register struct proc *p; 61442441Smckusick register struct args { 61542441Smckusick char *fname; 6166254Sroot int fmode; 6176254Sroot int dev; 61842441Smckusick } *uap; 61942441Smckusick int *retval; 62042441Smckusick { 62142441Smckusick register struct nameidata *ndp = &u.u_nd; 62237741Smckusick register struct vnode *vp; 62337741Smckusick struct vattr vattr; 62437741Smckusick int error; 6256254Sroot 62642441Smckusick if (error = suser(ndp->ni_cred, &u.u_acflag)) 62737741Smckusick RETURN (error); 62837741Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 62916694Smckusick ndp->ni_segflg = UIO_USERSPACE; 63016694Smckusick ndp->ni_dirp = uap->fname; 63137741Smckusick if (error = namei(ndp)) 63237741Smckusick RETURN (error); 63337741Smckusick vp = ndp->ni_vp; 63437741Smckusick if (vp != NULL) { 63537741Smckusick error = EEXIST; 63612756Ssam goto out; 6376254Sroot } 63841362Smckusick VATTR_NULL(&vattr); 63940635Smckusick switch (uap->fmode & S_IFMT) { 64012756Ssam 64140635Smckusick case S_IFMT: /* used by badsect to flag bad sectors */ 64237741Smckusick vattr.va_type = VBAD; 64337741Smckusick break; 64440635Smckusick case S_IFCHR: 64537741Smckusick vattr.va_type = VCHR; 64637741Smckusick break; 64740635Smckusick case S_IFBLK: 64837741Smckusick vattr.va_type = VBLK; 64937741Smckusick break; 65037741Smckusick default: 65137741Smckusick error = EINVAL; 65237741Smckusick goto out; 6536254Sroot } 65442441Smckusick vattr.va_mode = (uap->fmode & 07777) &~ u.u_cmask; 65537741Smckusick vattr.va_rdev = uap->dev; 6566254Sroot out: 65742465Smckusick if (!error) { 65842465Smckusick error = VOP_MKNOD(ndp, &vattr, ndp->ni_cred); 65942465Smckusick } else { 66037741Smckusick VOP_ABORTOP(ndp); 66143344Smckusick if (ndp->ni_dvp == vp) 66243344Smckusick vrele(ndp->ni_dvp); 66343344Smckusick else 66443344Smckusick vput(ndp->ni_dvp); 66542465Smckusick if (vp) 66642465Smckusick vrele(vp); 66742465Smckusick } 66837741Smckusick RETURN (error); 6696254Sroot } 6706254Sroot 6716254Sroot /* 67240285Smckusick * Mkfifo system call 67340285Smckusick */ 67442441Smckusick /* ARGSUSED */ 67542441Smckusick mkfifo(p, uap, retval) 67642441Smckusick register struct proc *p; 67742441Smckusick register struct args { 67840285Smckusick char *fname; 67940285Smckusick int fmode; 68042441Smckusick } *uap; 68142441Smckusick int *retval; 68242441Smckusick { 68342441Smckusick register struct nameidata *ndp = &u.u_nd; 68440285Smckusick struct vattr vattr; 68540285Smckusick int error; 68640285Smckusick 68740285Smckusick #ifndef FIFO 68840285Smckusick RETURN (EOPNOTSUPP); 68940285Smckusick #else 69040285Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 69140285Smckusick ndp->ni_segflg = UIO_USERSPACE; 69240285Smckusick ndp->ni_dirp = uap->fname; 69340285Smckusick if (error = namei(ndp)) 69440285Smckusick RETURN (error); 69540285Smckusick if (ndp->ni_vp != NULL) { 69640285Smckusick VOP_ABORTOP(ndp); 69743344Smckusick if (ndp->ni_dvp == ndp->ni_vp) 69843344Smckusick vrele(ndp->ni_dvp); 69943344Smckusick else 70043344Smckusick vput(ndp->ni_dvp); 70142465Smckusick vrele(ndp->ni_vp); 70240285Smckusick RETURN (EEXIST); 70340285Smckusick } else { 70441362Smckusick VATTR_NULL(&vattr); 70540285Smckusick vattr.va_type = VFIFO; 70642441Smckusick vattr.va_mode = (uap->fmode & 07777) &~ u.u_cmask; 70740285Smckusick } 70840285Smckusick RETURN (VOP_MKNOD(ndp, &vattr, ndp->ni_cred)); 70940285Smckusick #endif /* FIFO */ 71040285Smckusick } 71140285Smckusick 71240285Smckusick /* 7136254Sroot * link system call 7146254Sroot */ 71542441Smckusick /* ARGSUSED */ 71642441Smckusick link(p, uap, retval) 71742441Smckusick register struct proc *p; 71842441Smckusick register struct args { 7196254Sroot char *target; 7206254Sroot char *linkname; 72142441Smckusick } *uap; 72242441Smckusick int *retval; 72342441Smckusick { 72442441Smckusick register struct nameidata *ndp = &u.u_nd; 72537741Smckusick register struct vnode *vp, *xp; 72637741Smckusick int error; 7276254Sroot 72816694Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW; 72916694Smckusick ndp->ni_segflg = UIO_USERSPACE; 73016694Smckusick ndp->ni_dirp = uap->target; 73137741Smckusick if (error = namei(ndp)) 73237741Smckusick RETURN (error); 73337741Smckusick vp = ndp->ni_vp; 73437741Smckusick if (vp->v_type == VDIR && 73542441Smckusick (error = suser(ndp->ni_cred, &u.u_acflag))) 73637741Smckusick goto out1; 73737741Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 73816694Smckusick ndp->ni_dirp = (caddr_t)uap->linkname; 73937741Smckusick if (error = namei(ndp)) 74037741Smckusick goto out1; 74137741Smckusick xp = ndp->ni_vp; 7426254Sroot if (xp != NULL) { 74337741Smckusick error = EEXIST; 7446254Sroot goto out; 7456254Sroot } 74637741Smckusick xp = ndp->ni_dvp; 74737741Smckusick if (vp->v_mount != xp->v_mount) 74837741Smckusick error = EXDEV; 7496254Sroot out: 75042465Smckusick if (!error) { 75142465Smckusick error = VOP_LINK(vp, ndp); 75242465Smckusick } else { 75337741Smckusick VOP_ABORTOP(ndp); 75443344Smckusick if (ndp->ni_dvp == ndp->ni_vp) 75543344Smckusick vrele(ndp->ni_dvp); 75643344Smckusick else 75743344Smckusick vput(ndp->ni_dvp); 75842465Smckusick if (ndp->ni_vp) 75942465Smckusick vrele(ndp->ni_vp); 76042465Smckusick } 76137741Smckusick out1: 76237741Smckusick vrele(vp); 76337741Smckusick RETURN (error); 7646254Sroot } 7656254Sroot 7666254Sroot /* 7676254Sroot * symlink -- make a symbolic link 7686254Sroot */ 76942441Smckusick /* ARGSUSED */ 77042441Smckusick symlink(p, uap, retval) 77142441Smckusick register struct proc *p; 77242441Smckusick register struct args { 7736254Sroot char *target; 7746254Sroot char *linkname; 77542441Smckusick } *uap; 77642441Smckusick int *retval; 77742441Smckusick { 77842441Smckusick register struct nameidata *ndp = &u.u_nd; 77937741Smckusick struct vattr vattr; 78037741Smckusick char *target; 78137741Smckusick int error; 7826254Sroot 78316694Smckusick ndp->ni_segflg = UIO_USERSPACE; 78416694Smckusick ndp->ni_dirp = uap->linkname; 78537741Smckusick MALLOC(target, char *, MAXPATHLEN, M_NAMEI, M_WAITOK); 78637741Smckusick if (error = copyinstr(uap->target, target, MAXPATHLEN, (u_int *)0)) 78742465Smckusick goto out; 78837741Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 78937741Smckusick if (error = namei(ndp)) 79042465Smckusick goto out; 79142465Smckusick if (ndp->ni_vp) { 79242465Smckusick VOP_ABORTOP(ndp); 79343344Smckusick if (ndp->ni_dvp == ndp->ni_vp) 79443344Smckusick vrele(ndp->ni_dvp); 79543344Smckusick else 79643344Smckusick vput(ndp->ni_dvp); 79742465Smckusick vrele(ndp->ni_vp); 79837741Smckusick error = EEXIST; 79937741Smckusick goto out; 8006254Sroot } 80141362Smckusick VATTR_NULL(&vattr); 80242441Smckusick vattr.va_mode = 0777 &~ u.u_cmask; 80342465Smckusick error = VOP_SYMLINK(ndp, &vattr, target); 80437741Smckusick out: 80537741Smckusick FREE(target, M_NAMEI); 80637741Smckusick RETURN (error); 8076254Sroot } 8086254Sroot 8096254Sroot /* 8106254Sroot * Unlink system call. 8116254Sroot * Hard to avoid races here, especially 8126254Sroot * in unlinking directories. 8136254Sroot */ 81442441Smckusick /* ARGSUSED */ 81542441Smckusick unlink(p, uap, retval) 81642441Smckusick register struct proc *p; 81742441Smckusick struct args { 81842441Smckusick char *fname; 81942441Smckusick } *uap; 82042441Smckusick int *retval; 8216254Sroot { 82242441Smckusick register struct nameidata *ndp = &u.u_nd; 82337741Smckusick register struct vnode *vp; 82437741Smckusick int error; 8256254Sroot 82637741Smckusick ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF; 82716694Smckusick ndp->ni_segflg = UIO_USERSPACE; 82816694Smckusick ndp->ni_dirp = uap->fname; 82937741Smckusick if (error = namei(ndp)) 83037741Smckusick RETURN (error); 83137741Smckusick vp = ndp->ni_vp; 83237741Smckusick if (vp->v_type == VDIR && 83342441Smckusick (error = suser(ndp->ni_cred, &u.u_acflag))) 8346254Sroot goto out; 8356254Sroot /* 8366254Sroot * Don't unlink a mounted file. 8376254Sroot */ 83837741Smckusick if (vp->v_flag & VROOT) { 83937741Smckusick error = EBUSY; 8406254Sroot goto out; 8416254Sroot } 84237741Smckusick if (vp->v_flag & VTEXT) 84337741Smckusick xrele(vp); /* try once to free text */ 8446254Sroot out: 84542465Smckusick if (!error) { 84642465Smckusick error = VOP_REMOVE(ndp); 84742465Smckusick } else { 84837741Smckusick VOP_ABORTOP(ndp); 84943344Smckusick if (ndp->ni_dvp == vp) 85043344Smckusick vrele(ndp->ni_dvp); 85143344Smckusick else 85243344Smckusick vput(ndp->ni_dvp); 85342465Smckusick vput(vp); 85442465Smckusick } 85537741Smckusick RETURN (error); 8566254Sroot } 8576254Sroot 8586254Sroot /* 8596254Sroot * Seek system call 8606254Sroot */ 86142441Smckusick lseek(p, uap, retval) 86242441Smckusick register struct proc *p; 86342441Smckusick register struct args { 86437741Smckusick int fdes; 8656254Sroot off_t off; 8666254Sroot int sbase; 86742441Smckusick } *uap; 86842441Smckusick off_t *retval; 86942441Smckusick { 87042441Smckusick struct ucred *cred = u.u_nd.ni_cred; 87142441Smckusick register struct file *fp; 87237741Smckusick struct vattr vattr; 87337741Smckusick int error; 8746254Sroot 87537741Smckusick if ((unsigned)uap->fdes >= NOFILE || 87642441Smckusick (fp = u.u_ofile[uap->fdes]) == NULL) 87737741Smckusick RETURN (EBADF); 87837741Smckusick if (fp->f_type != DTYPE_VNODE) 87937741Smckusick RETURN (ESPIPE); 88013878Ssam switch (uap->sbase) { 88113878Ssam 88213878Ssam case L_INCR: 88313878Ssam fp->f_offset += uap->off; 88413878Ssam break; 88513878Ssam 88613878Ssam case L_XTND: 88737741Smckusick if (error = VOP_GETATTR((struct vnode *)fp->f_data, 88842441Smckusick &vattr, cred)) 88937741Smckusick RETURN (error); 89037741Smckusick fp->f_offset = uap->off + vattr.va_size; 89113878Ssam break; 89213878Ssam 89313878Ssam case L_SET: 89413878Ssam fp->f_offset = uap->off; 89513878Ssam break; 89613878Ssam 89713878Ssam default: 89837741Smckusick RETURN (EINVAL); 89913878Ssam } 90042441Smckusick *retval = fp->f_offset; 90137741Smckusick RETURN (0); 9026254Sroot } 9036254Sroot 9046254Sroot /* 9056254Sroot * Access system call 9066254Sroot */ 90742441Smckusick /* ARGSUSED */ 90842441Smckusick saccess(p, uap, retval) 90942441Smckusick register struct proc *p; 91042441Smckusick register struct args { 9116254Sroot char *fname; 9126254Sroot int fmode; 91342441Smckusick } *uap; 91442441Smckusick int *retval; 91542441Smckusick { 91642441Smckusick register struct nameidata *ndp = &u.u_nd; 91742441Smckusick register struct ucred *cred = ndp->ni_cred; 91837741Smckusick register struct vnode *vp; 91937741Smckusick int error, mode, svuid, svgid; 9206254Sroot 92142441Smckusick svuid = cred->cr_uid; 92242441Smckusick svgid = cred->cr_groups[0]; 92342441Smckusick cred->cr_uid = p->p_ruid; 92442441Smckusick cred->cr_groups[0] = p->p_rgid; 92537741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 92616694Smckusick ndp->ni_segflg = UIO_USERSPACE; 92716694Smckusick ndp->ni_dirp = uap->fname; 92837741Smckusick if (error = namei(ndp)) 92937741Smckusick goto out1; 93037741Smckusick vp = ndp->ni_vp; 93137741Smckusick /* 93237741Smckusick * fmode == 0 means only check for exist 93337741Smckusick */ 93437741Smckusick if (uap->fmode) { 93537741Smckusick mode = 0; 93637741Smckusick if (uap->fmode & R_OK) 93737741Smckusick mode |= VREAD; 93837741Smckusick if (uap->fmode & W_OK) 93937741Smckusick mode |= VWRITE; 94037741Smckusick if (uap->fmode & X_OK) 94137741Smckusick mode |= VEXEC; 94239543Smckusick if ((mode & VWRITE) == 0 || (error = vn_writechk(vp)) == 0) 94338399Smckusick error = VOP_ACCESS(vp, mode, ndp->ni_cred); 9446254Sroot } 94537741Smckusick vput(vp); 94637741Smckusick out1: 94742441Smckusick cred->cr_uid = svuid; 94842441Smckusick cred->cr_groups[0] = svgid; 94937741Smckusick RETURN (error); 9506254Sroot } 9516254Sroot 9526254Sroot /* 9536574Smckusic * Stat system call. This version follows links. 95437Sbill */ 95542441Smckusick /* ARGSUSED */ 95642441Smckusick stat(p, uap, retval) 95742441Smckusick register struct proc *p; 95842441Smckusick register struct args { 95942441Smckusick char *fname; 96042441Smckusick struct stat *ub; 96142441Smckusick } *uap; 96242441Smckusick int *retval; 96337Sbill { 96442441Smckusick register struct nameidata *ndp = &u.u_nd; 96542441Smckusick struct stat sb; 96642441Smckusick int error; 96737Sbill 96842441Smckusick ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW; 96942441Smckusick ndp->ni_segflg = UIO_USERSPACE; 97042441Smckusick ndp->ni_dirp = uap->fname; 97142441Smckusick if (error = namei(ndp)) 97242441Smckusick RETURN (error); 97342441Smckusick error = vn_stat(ndp->ni_vp, &sb); 97442441Smckusick vput(ndp->ni_vp); 97542441Smckusick if (error) 97642441Smckusick RETURN (error); 97742441Smckusick error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb)); 97842441Smckusick RETURN (error); 97937Sbill } 98037Sbill 98137Sbill /* 9826574Smckusic * Lstat system call. This version does not follow links. 9835992Swnj */ 98442441Smckusick /* ARGSUSED */ 98542441Smckusick lstat(p, uap, retval) 98642441Smckusick register struct proc *p; 98742441Smckusick register struct args { 9885992Swnj char *fname; 98912756Ssam struct stat *ub; 99042441Smckusick } *uap; 99142441Smckusick int *retval; 99242441Smckusick { 99342441Smckusick register struct nameidata *ndp = &u.u_nd; 99412756Ssam struct stat sb; 99537741Smckusick int error; 9965992Swnj 99742441Smckusick ndp->ni_nameiop = LOOKUP | LOCKLEAF | NOFOLLOW; 99816694Smckusick ndp->ni_segflg = UIO_USERSPACE; 99916694Smckusick ndp->ni_dirp = uap->fname; 100037741Smckusick if (error = namei(ndp)) 100137741Smckusick RETURN (error); 100237741Smckusick error = vn_stat(ndp->ni_vp, &sb); 100337741Smckusick vput(ndp->ni_vp); 100437741Smckusick if (error) 100537741Smckusick RETURN (error); 100637741Smckusick error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb)); 100737741Smckusick RETURN (error); 10085992Swnj } 10095992Swnj 10105992Swnj /* 10115992Swnj * Return target name of a symbolic link 101237Sbill */ 101342441Smckusick /* ARGSUSED */ 101442441Smckusick readlink(p, uap, retval) 101542441Smckusick register struct proc *p; 101642441Smckusick register struct args { 10175992Swnj char *name; 10185992Swnj char *buf; 10195992Swnj int count; 102042441Smckusick } *uap; 102142441Smckusick int *retval; 102242441Smckusick { 102342441Smckusick register struct nameidata *ndp = &u.u_nd; 102437741Smckusick register struct vnode *vp; 102537741Smckusick struct iovec aiov; 102637741Smckusick struct uio auio; 102737741Smckusick int error; 10285992Swnj 102937741Smckusick ndp->ni_nameiop = LOOKUP | LOCKLEAF; 103016694Smckusick ndp->ni_segflg = UIO_USERSPACE; 103116694Smckusick ndp->ni_dirp = uap->name; 103237741Smckusick if (error = namei(ndp)) 103337741Smckusick RETURN (error); 103437741Smckusick vp = ndp->ni_vp; 103537741Smckusick if (vp->v_type != VLNK) { 103637741Smckusick error = EINVAL; 10375992Swnj goto out; 10385992Swnj } 103937741Smckusick aiov.iov_base = uap->buf; 104037741Smckusick aiov.iov_len = uap->count; 104137741Smckusick auio.uio_iov = &aiov; 104237741Smckusick auio.uio_iovcnt = 1; 104337741Smckusick auio.uio_offset = 0; 104437741Smckusick auio.uio_rw = UIO_READ; 104537741Smckusick auio.uio_segflg = UIO_USERSPACE; 104637741Smckusick auio.uio_resid = uap->count; 104737741Smckusick error = VOP_READLINK(vp, &auio, ndp->ni_cred); 10485992Swnj out: 104937741Smckusick vput(vp); 105042441Smckusick *retval = uap->count - auio.uio_resid; 105137741Smckusick RETURN (error); 10525992Swnj } 10535992Swnj 10549167Ssam /* 105538259Smckusick * Change flags of a file given path name. 105638259Smckusick */ 105742441Smckusick /* ARGSUSED */ 105842441Smckusick chflags(p, uap, retval) 105942441Smckusick register struct proc *p; 106042441Smckusick register struct args { 106138259Smckusick char *fname; 106238259Smckusick int flags; 106342441Smckusick } *uap; 106442441Smckusick int *retval; 106542441Smckusick { 106642441Smckusick register struct nameidata *ndp = &u.u_nd; 106738259Smckusick register struct vnode *vp; 106838259Smckusick struct vattr vattr; 106938259Smckusick int error; 107038259Smckusick 107138259Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 107238259Smckusick ndp->ni_segflg = UIO_USERSPACE; 107338259Smckusick ndp->ni_dirp = uap->fname; 107441362Smckusick VATTR_NULL(&vattr); 107538259Smckusick vattr.va_flags = uap->flags; 107638259Smckusick if (error = namei(ndp)) 107738259Smckusick RETURN (error); 107838259Smckusick vp = ndp->ni_vp; 107941400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 108038259Smckusick error = EROFS; 108138259Smckusick goto out; 108238259Smckusick } 108338259Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 108438259Smckusick out: 108538259Smckusick vput(vp); 108638259Smckusick RETURN (error); 108738259Smckusick } 108838259Smckusick 108938259Smckusick /* 109038259Smckusick * Change flags of a file given a file descriptor. 109138259Smckusick */ 109242441Smckusick /* ARGSUSED */ 109342441Smckusick fchflags(p, uap, retval) 109442441Smckusick register struct proc *p; 109542441Smckusick register struct args { 109638259Smckusick int fd; 109738259Smckusick int flags; 109842441Smckusick } *uap; 109942441Smckusick int *retval; 110042441Smckusick { 110138259Smckusick struct vattr vattr; 110238259Smckusick struct vnode *vp; 110338259Smckusick struct file *fp; 110438259Smckusick int error; 110538259Smckusick 110642441Smckusick if (error = getvnode(u.u_ofile, uap->fd, &fp)) 110738259Smckusick RETURN (error); 110841362Smckusick VATTR_NULL(&vattr); 110938259Smckusick vattr.va_flags = uap->flags; 111038259Smckusick vp = (struct vnode *)fp->f_data; 111138259Smckusick VOP_LOCK(vp); 111241400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 111338259Smckusick error = EROFS; 111438259Smckusick goto out; 111538259Smckusick } 111638259Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred); 111738259Smckusick out: 111838259Smckusick VOP_UNLOCK(vp); 111938259Smckusick RETURN (error); 112038259Smckusick } 112138259Smckusick 112238259Smckusick /* 11239167Ssam * Change mode of a file given path name. 11249167Ssam */ 112542441Smckusick /* ARGSUSED */ 112642441Smckusick chmod(p, uap, retval) 112742441Smckusick register struct proc *p; 112842441Smckusick register struct args { 11296254Sroot char *fname; 11306254Sroot int fmode; 113142441Smckusick } *uap; 113242441Smckusick int *retval; 113342441Smckusick { 113442441Smckusick register struct nameidata *ndp = &u.u_nd; 113537741Smckusick register struct vnode *vp; 113637741Smckusick struct vattr vattr; 113737741Smckusick int error; 11385992Swnj 113937741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 114037741Smckusick ndp->ni_segflg = UIO_USERSPACE; 114137741Smckusick ndp->ni_dirp = uap->fname; 114241362Smckusick VATTR_NULL(&vattr); 114337741Smckusick vattr.va_mode = uap->fmode & 07777; 114437741Smckusick if (error = namei(ndp)) 114537741Smckusick RETURN (error); 114637741Smckusick vp = ndp->ni_vp; 114741400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 114837741Smckusick error = EROFS; 114937741Smckusick goto out; 115037741Smckusick } 115137741Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 115237741Smckusick out: 115337741Smckusick vput(vp); 115437741Smckusick RETURN (error); 11557701Ssam } 11567439Sroot 11579167Ssam /* 11589167Ssam * Change mode of a file given a file descriptor. 11599167Ssam */ 116042441Smckusick /* ARGSUSED */ 116142441Smckusick fchmod(p, uap, retval) 116242441Smckusick register struct proc *p; 116342441Smckusick register struct args { 11647701Ssam int fd; 11657701Ssam int fmode; 116642441Smckusick } *uap; 116742441Smckusick int *retval; 116842441Smckusick { 116937741Smckusick struct vattr vattr; 117037741Smckusick struct vnode *vp; 117137741Smckusick struct file *fp; 117237741Smckusick int error; 11737701Ssam 117442441Smckusick if (error = getvnode(u.u_ofile, uap->fd, &fp)) 117537741Smckusick RETURN (error); 117641362Smckusick VATTR_NULL(&vattr); 117737741Smckusick vattr.va_mode = uap->fmode & 07777; 117837741Smckusick vp = (struct vnode *)fp->f_data; 117937741Smckusick VOP_LOCK(vp); 118041400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 118137741Smckusick error = EROFS; 118237741Smckusick goto out; 11837439Sroot } 118437741Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred); 118537741Smckusick out: 118637741Smckusick VOP_UNLOCK(vp); 118737741Smckusick RETURN (error); 11885992Swnj } 11895992Swnj 11909167Ssam /* 11919167Ssam * Set ownership given a path name. 11929167Ssam */ 119342441Smckusick /* ARGSUSED */ 119442441Smckusick chown(p, uap, retval) 119542441Smckusick register struct proc *p; 119642441Smckusick register struct args { 11976254Sroot char *fname; 11986254Sroot int uid; 11996254Sroot int gid; 120042441Smckusick } *uap; 120142441Smckusick int *retval; 120242441Smckusick { 120342441Smckusick register struct nameidata *ndp = &u.u_nd; 120437741Smckusick register struct vnode *vp; 120537741Smckusick struct vattr vattr; 120637741Smckusick int error; 120737Sbill 120837741Smckusick ndp->ni_nameiop = LOOKUP | NOFOLLOW | LOCKLEAF; 120936614Sbostic ndp->ni_segflg = UIO_USERSPACE; 121036614Sbostic ndp->ni_dirp = uap->fname; 121141362Smckusick VATTR_NULL(&vattr); 121237741Smckusick vattr.va_uid = uap->uid; 121337741Smckusick vattr.va_gid = uap->gid; 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 } 122137741Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 122237741Smckusick out: 122337741Smckusick vput(vp); 122437741Smckusick RETURN (error); 12257701Ssam } 12267439Sroot 12279167Ssam /* 12289167Ssam * Set ownership given a file descriptor. 12299167Ssam */ 123042441Smckusick /* ARGSUSED */ 123142441Smckusick fchown(p, uap, retval) 123242441Smckusick register struct proc *p; 123342441Smckusick register struct args { 12347701Ssam int fd; 12357701Ssam int uid; 12367701Ssam int gid; 123742441Smckusick } *uap; 123842441Smckusick int *retval; 123942441Smckusick { 124037741Smckusick struct vattr vattr; 124137741Smckusick struct vnode *vp; 124237741Smckusick struct file *fp; 124337741Smckusick int error; 12447701Ssam 124542441Smckusick if (error = getvnode(u.u_ofile, uap->fd, &fp)) 124637741Smckusick RETURN (error); 124741362Smckusick VATTR_NULL(&vattr); 124837741Smckusick vattr.va_uid = uap->uid; 124937741Smckusick vattr.va_gid = uap->gid; 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 } 125637741Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred); 125737741Smckusick out: 125837741Smckusick VOP_UNLOCK(vp); 125937741Smckusick RETURN (error); 12607701Ssam } 12617701Ssam 126242441Smckusick /* 126342441Smckusick * Set the access and modification times of a file. 126442441Smckusick */ 126542441Smckusick /* ARGSUSED */ 126642441Smckusick utimes(p, uap, retval) 126742441Smckusick register struct proc *p; 126842441Smckusick register struct args { 126911811Ssam char *fname; 127011811Ssam struct timeval *tptr; 127142441Smckusick } *uap; 127242441Smckusick int *retval; 127342441Smckusick { 127442441Smckusick register struct nameidata *ndp = &u.u_nd; 127537741Smckusick register struct vnode *vp; 127611811Ssam struct timeval tv[2]; 127737741Smckusick struct vattr vattr; 127837741Smckusick int error; 127911811Ssam 128037741Smckusick if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv))) 128137741Smckusick RETURN (error); 128237741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 128337741Smckusick ndp->ni_segflg = UIO_USERSPACE; 128437741Smckusick ndp->ni_dirp = uap->fname; 128541362Smckusick VATTR_NULL(&vattr); 128637741Smckusick vattr.va_atime = tv[0]; 128737741Smckusick vattr.va_mtime = tv[1]; 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 } 129537741Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 129637741Smckusick out: 129737741Smckusick vput(vp); 129837741Smckusick RETURN (error); 129911811Ssam } 130011811Ssam 13019167Ssam /* 13029167Ssam * Truncate a file given its path name. 13039167Ssam */ 130442441Smckusick /* ARGSUSED */ 130542441Smckusick truncate(p, uap, retval) 130642441Smckusick register struct proc *p; 130742441Smckusick register struct args { 13087701Ssam char *fname; 130926473Skarels off_t length; 131042441Smckusick } *uap; 131142441Smckusick int *retval; 131242441Smckusick { 131342441Smckusick register struct nameidata *ndp = &u.u_nd; 131437741Smckusick register struct vnode *vp; 131537741Smckusick struct vattr vattr; 131637741Smckusick int error; 13177701Ssam 131837741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 131916694Smckusick ndp->ni_segflg = UIO_USERSPACE; 132016694Smckusick ndp->ni_dirp = uap->fname; 132141362Smckusick VATTR_NULL(&vattr); 132237741Smckusick vattr.va_size = uap->length; 132337741Smckusick if (error = namei(ndp)) 132437741Smckusick RETURN (error); 132537741Smckusick vp = ndp->ni_vp; 132637741Smckusick if (vp->v_type == VDIR) { 132737741Smckusick error = EISDIR; 132837741Smckusick goto out; 13297701Ssam } 133038399Smckusick if ((error = vn_writechk(vp)) || 133138399Smckusick (error = VOP_ACCESS(vp, VWRITE, ndp->ni_cred))) 133237741Smckusick goto out; 133337741Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 133437741Smckusick out: 133537741Smckusick vput(vp); 133637741Smckusick RETURN (error); 13377701Ssam } 13387701Ssam 13399167Ssam /* 13409167Ssam * Truncate a file given a file descriptor. 13419167Ssam */ 134242441Smckusick /* ARGSUSED */ 134342441Smckusick ftruncate(p, uap, retval) 134442441Smckusick register struct proc *p; 134542441Smckusick register struct args { 13467701Ssam int fd; 134726473Skarels off_t length; 134842441Smckusick } *uap; 134942441Smckusick int *retval; 135042441Smckusick { 135137741Smckusick struct vattr vattr; 135237741Smckusick struct vnode *vp; 13537701Ssam struct file *fp; 135437741Smckusick int error; 13557701Ssam 135642441Smckusick if (error = getvnode(u.u_ofile, uap->fd, &fp)) 135737741Smckusick RETURN (error); 135837741Smckusick if ((fp->f_flag & FWRITE) == 0) 135937741Smckusick RETURN (EINVAL); 136041362Smckusick VATTR_NULL(&vattr); 136137741Smckusick vattr.va_size = uap->length; 136237741Smckusick vp = (struct vnode *)fp->f_data; 136337741Smckusick VOP_LOCK(vp); 136437741Smckusick if (vp->v_type == VDIR) { 136537741Smckusick error = EISDIR; 136637741Smckusick goto out; 13677701Ssam } 136838399Smckusick if (error = vn_writechk(vp)) 136937741Smckusick goto out; 137037741Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred); 137137741Smckusick out: 137237741Smckusick VOP_UNLOCK(vp); 137337741Smckusick RETURN (error); 13747701Ssam } 13757701Ssam 13769167Ssam /* 13779167Ssam * Synch an open file. 13789167Ssam */ 137942441Smckusick /* ARGSUSED */ 138042441Smckusick fsync(p, uap, retval) 138142441Smckusick register struct proc *p; 138242441Smckusick struct args { 138342441Smckusick int fd; 138442441Smckusick } *uap; 138542441Smckusick int *retval; 13869167Ssam { 138739592Smckusick register struct vnode *vp; 13889167Ssam struct file *fp; 138937741Smckusick int error; 13909167Ssam 139142441Smckusick if (error = getvnode(u.u_ofile, uap->fd, &fp)) 139237741Smckusick RETURN (error); 139339592Smckusick vp = (struct vnode *)fp->f_data; 139439592Smckusick VOP_LOCK(vp); 139539592Smckusick error = VOP_FSYNC(vp, fp->f_flag, fp->f_cred, MNT_WAIT); 139639592Smckusick VOP_UNLOCK(vp); 139737741Smckusick RETURN (error); 13989167Ssam } 13999167Ssam 14009167Ssam /* 14019167Ssam * Rename system call. 14029167Ssam * 14039167Ssam * Source and destination must either both be directories, or both 14049167Ssam * not be directories. If target is a directory, it must be empty. 14059167Ssam */ 140642441Smckusick /* ARGSUSED */ 140742441Smckusick rename(p, uap, retval) 140842441Smckusick register struct proc *p; 140942441Smckusick register struct args { 14107701Ssam char *from; 14117701Ssam char *to; 141242441Smckusick } *uap; 141342441Smckusick int *retval; 141442441Smckusick { 141537741Smckusick register struct vnode *tvp, *fvp, *tdvp; 141642441Smckusick register struct nameidata *ndp = &u.u_nd; 141737741Smckusick struct nameidata tond; 141837741Smckusick int error; 14197701Ssam 142037741Smckusick ndp->ni_nameiop = DELETE | WANTPARENT; 142116694Smckusick ndp->ni_segflg = UIO_USERSPACE; 142216694Smckusick ndp->ni_dirp = uap->from; 142337741Smckusick if (error = namei(ndp)) 142437741Smckusick RETURN (error); 142537741Smckusick fvp = ndp->ni_vp; 142638266Smckusick nddup(ndp, &tond); 142737741Smckusick tond.ni_nameiop = RENAME | LOCKPARENT | LOCKLEAF | NOCACHE; 142837741Smckusick tond.ni_segflg = UIO_USERSPACE; 142937741Smckusick tond.ni_dirp = uap->to; 143042465Smckusick if (error = namei(&tond)) { 143142465Smckusick VOP_ABORTOP(ndp); 143242465Smckusick vrele(ndp->ni_dvp); 143342465Smckusick vrele(fvp); 143442465Smckusick goto out1; 143542465Smckusick } 143637741Smckusick tdvp = tond.ni_dvp; 143737741Smckusick tvp = tond.ni_vp; 143837741Smckusick if (tvp != NULL) { 143937741Smckusick if (fvp->v_type == VDIR && tvp->v_type != VDIR) { 144039242Sbostic error = ENOTDIR; 144137741Smckusick goto out; 144237741Smckusick } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) { 144339242Sbostic error = EISDIR; 144437741Smckusick goto out; 14459167Ssam } 14469167Ssam } 144737741Smckusick if (fvp->v_mount != tdvp->v_mount) { 144837741Smckusick error = EXDEV; 14499167Ssam goto out; 145010051Ssam } 145139286Smckusick if (fvp == tdvp) 145237741Smckusick error = EINVAL; 145339286Smckusick /* 145439286Smckusick * If source is the same as the destination, 145539286Smckusick * then there is nothing to do. 145639286Smckusick */ 145739286Smckusick if (fvp == tvp) 145839286Smckusick error = -1; 145937741Smckusick out: 146042465Smckusick if (!error) { 146142465Smckusick error = VOP_RENAME(ndp, &tond); 146242465Smckusick } else { 146337741Smckusick VOP_ABORTOP(&tond); 146443344Smckusick if (tdvp == tvp) 146543344Smckusick vrele(tdvp); 146643344Smckusick else 146743344Smckusick vput(tdvp); 146842465Smckusick if (tvp) 146942465Smckusick vput(tvp); 147037741Smckusick VOP_ABORTOP(ndp); 147142465Smckusick vrele(ndp->ni_dvp); 147242465Smckusick vrele(fvp); 14739167Ssam } 147437741Smckusick out1: 147538266Smckusick ndrele(&tond); 147639286Smckusick if (error == -1) 147739286Smckusick RETURN (0); 147837741Smckusick RETURN (error); 14797701Ssam } 14807701Ssam 14817535Sroot /* 148212756Ssam * Mkdir system call 148312756Ssam */ 148442441Smckusick /* ARGSUSED */ 148542441Smckusick mkdir(p, uap, retval) 148642441Smckusick register struct proc *p; 148742441Smckusick register struct args { 148812756Ssam char *name; 148912756Ssam int dmode; 149042441Smckusick } *uap; 149142441Smckusick int *retval; 149242441Smckusick { 149342441Smckusick register struct nameidata *ndp = &u.u_nd; 149437741Smckusick register struct vnode *vp; 149537741Smckusick struct vattr vattr; 149637741Smckusick int error; 149712756Ssam 149837741Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 149916694Smckusick ndp->ni_segflg = UIO_USERSPACE; 150016694Smckusick ndp->ni_dirp = uap->name; 150137741Smckusick if (error = namei(ndp)) 150237741Smckusick RETURN (error); 150337741Smckusick vp = ndp->ni_vp; 150437741Smckusick if (vp != NULL) { 150537741Smckusick VOP_ABORTOP(ndp); 150643344Smckusick if (ndp->ni_dvp == vp) 150743344Smckusick vrele(ndp->ni_dvp); 150843344Smckusick else 150943344Smckusick vput(ndp->ni_dvp); 151042465Smckusick vrele(vp); 151137741Smckusick RETURN (EEXIST); 151212756Ssam } 151341362Smckusick VATTR_NULL(&vattr); 151437741Smckusick vattr.va_type = VDIR; 151542441Smckusick vattr.va_mode = (uap->dmode & 0777) &~ u.u_cmask; 151637741Smckusick error = VOP_MKDIR(ndp, &vattr); 151738145Smckusick if (!error) 151838145Smckusick vput(ndp->ni_vp); 151937741Smckusick RETURN (error); 152012756Ssam } 152112756Ssam 152212756Ssam /* 152312756Ssam * Rmdir system call. 152412756Ssam */ 152542441Smckusick /* ARGSUSED */ 152642441Smckusick rmdir(p, uap, retval) 152742441Smckusick register struct proc *p; 152842441Smckusick struct args { 152942441Smckusick char *name; 153042441Smckusick } *uap; 153142441Smckusick int *retval; 153212756Ssam { 153342441Smckusick register struct nameidata *ndp = &u.u_nd; 153437741Smckusick register struct vnode *vp; 153537741Smckusick int error; 153612756Ssam 153737741Smckusick ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF; 153816694Smckusick ndp->ni_segflg = UIO_USERSPACE; 153916694Smckusick ndp->ni_dirp = uap->name; 154037741Smckusick if (error = namei(ndp)) 154137741Smckusick RETURN (error); 154237741Smckusick vp = ndp->ni_vp; 154337741Smckusick if (vp->v_type != VDIR) { 154437741Smckusick error = ENOTDIR; 154512756Ssam goto out; 154612756Ssam } 154712756Ssam /* 154837741Smckusick * No rmdir "." please. 154912756Ssam */ 155037741Smckusick if (ndp->ni_dvp == vp) { 155137741Smckusick error = EINVAL; 155212756Ssam goto out; 155312756Ssam } 155412756Ssam /* 155537741Smckusick * Don't unlink a mounted file. 155612756Ssam */ 155737741Smckusick if (vp->v_flag & VROOT) 155837741Smckusick error = EBUSY; 155912756Ssam out: 156042465Smckusick if (!error) { 156142465Smckusick error = VOP_RMDIR(ndp); 156242465Smckusick } else { 156337741Smckusick VOP_ABORTOP(ndp); 156443344Smckusick if (ndp->ni_dvp == vp) 156543344Smckusick vrele(ndp->ni_dvp); 156643344Smckusick else 156743344Smckusick vput(ndp->ni_dvp); 156842465Smckusick vput(vp); 156942465Smckusick } 157037741Smckusick RETURN (error); 157112756Ssam } 157212756Ssam 157337741Smckusick /* 157437741Smckusick * Read a block of directory entries in a file system independent format 157537741Smckusick */ 157642441Smckusick getdirentries(p, uap, retval) 157742441Smckusick register struct proc *p; 157842441Smckusick register struct args { 157937741Smckusick int fd; 158037741Smckusick char *buf; 158137741Smckusick unsigned count; 158237741Smckusick long *basep; 158342441Smckusick } *uap; 158442441Smckusick int *retval; 158542441Smckusick { 158639592Smckusick register struct vnode *vp; 158716540Ssam struct file *fp; 158837741Smckusick struct uio auio; 158937741Smckusick struct iovec aiov; 159038129Smckusick off_t off; 159140321Smckusick int error, eofflag; 159212756Ssam 159342441Smckusick if (error = getvnode(u.u_ofile, uap->fd, &fp)) 159437741Smckusick RETURN (error); 159537741Smckusick if ((fp->f_flag & FREAD) == 0) 159637741Smckusick RETURN (EBADF); 159739592Smckusick vp = (struct vnode *)fp->f_data; 159839592Smckusick if (vp->v_type != VDIR) 159939592Smckusick RETURN (EINVAL); 160037741Smckusick aiov.iov_base = uap->buf; 160137741Smckusick aiov.iov_len = uap->count; 160237741Smckusick auio.uio_iov = &aiov; 160337741Smckusick auio.uio_iovcnt = 1; 160437741Smckusick auio.uio_rw = UIO_READ; 160537741Smckusick auio.uio_segflg = UIO_USERSPACE; 160637741Smckusick auio.uio_resid = uap->count; 160739592Smckusick VOP_LOCK(vp); 160839592Smckusick auio.uio_offset = off = fp->f_offset; 160940321Smckusick error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag); 161039592Smckusick fp->f_offset = auio.uio_offset; 161139592Smckusick VOP_UNLOCK(vp); 161239592Smckusick if (error) 161337741Smckusick RETURN (error); 161439592Smckusick error = copyout((caddr_t)&off, (caddr_t)uap->basep, sizeof(long)); 161542441Smckusick *retval = uap->count - auio.uio_resid; 161637741Smckusick RETURN (error); 161712756Ssam } 161812756Ssam 161912756Ssam /* 162012756Ssam * mode mask for creation of files 162112756Ssam */ 162242441Smckusick mode_t 162342441Smckusick umask(p, uap, retval) 162442441Smckusick register struct proc *p; 162542441Smckusick struct args { 162642441Smckusick int mask; 162742441Smckusick } *uap; 162842441Smckusick int *retval; 162912756Ssam { 163012756Ssam 163142441Smckusick *retval = u.u_cmask; 163242441Smckusick u.u_cmask = uap->mask & 07777; 163337741Smckusick RETURN (0); 163412756Ssam } 163537741Smckusick 163639566Smarc /* 163739566Smarc * Void all references to file by ripping underlying filesystem 163839566Smarc * away from vnode. 163939566Smarc */ 164042441Smckusick /* ARGSUSED */ 164142441Smckusick revoke(p, uap, retval) 164242441Smckusick register struct proc *p; 164342441Smckusick register struct args { 164439566Smarc char *fname; 164542441Smckusick } *uap; 164642441Smckusick int *retval; 164742441Smckusick { 164842441Smckusick register struct nameidata *ndp = &u.u_nd; 164939566Smarc register struct vnode *vp; 165039566Smarc struct vattr vattr; 165139566Smarc int error; 165239566Smarc 165339566Smarc ndp->ni_nameiop = LOOKUP | FOLLOW; 165439566Smarc ndp->ni_segflg = UIO_USERSPACE; 165539566Smarc ndp->ni_dirp = uap->fname; 165639566Smarc if (error = namei(ndp)) 165739566Smarc RETURN (error); 165839566Smarc vp = ndp->ni_vp; 165939566Smarc if (vp->v_type != VCHR && vp->v_type != VBLK) { 166039566Smarc error = EINVAL; 166139566Smarc goto out; 166239566Smarc } 166342441Smckusick if (error = VOP_GETATTR(vp, &vattr, ndp->ni_cred)) 166439566Smarc goto out; 166542955Smckusick if (ndp->ni_cred->cr_uid != vattr.va_uid && 166642441Smckusick (error = suser(ndp->ni_cred, &u.u_acflag))) 166739566Smarc goto out; 166839805Smckusick if (vp->v_usecount > 1 || (vp->v_flag & VALIASED)) 166939632Smckusick vgoneall(vp); 167039566Smarc out: 167139566Smarc vrele(vp); 167239566Smarc RETURN (error); 167339566Smarc } 167439566Smarc 167538408Smckusick getvnode(ofile, fdes, fpp) 167638408Smckusick struct file *ofile[]; 167737741Smckusick struct file **fpp; 167837741Smckusick int fdes; 167937741Smckusick { 168037741Smckusick struct file *fp; 168137741Smckusick 168238408Smckusick if ((unsigned)fdes >= NOFILE || (fp = ofile[fdes]) == NULL) 168337741Smckusick return (EBADF); 168437741Smckusick if (fp->f_type != DTYPE_VNODE) 168537741Smckusick return (EINVAL); 168637741Smckusick *fpp = fp; 168737741Smckusick return (0); 168837741Smckusick } 1689