123405Smckusick /* 237741Smckusick * Copyright (c) 1989 The Regents of the University of California. 337741Smckusick * All rights reserved. 423405Smckusick * 544459Sbostic * %sccs.include.redist.c% 637741Smckusick * 7*45785Sbostic * @(#)vfs_syscalls.c 7.61 (Berkeley) 12/14/90 823405Smckusick */ 937Sbill 1017101Sbloom #include "param.h" 1117101Sbloom #include "systm.h" 1244407Skarels #include "user.h" 1317101Sbloom #include "kernel.h" 1417101Sbloom #include "file.h" 1517101Sbloom #include "stat.h" 1637741Smckusick #include "vnode.h" 1737741Smckusick #include "mount.h" 1817101Sbloom #include "proc.h" 1917101Sbloom #include "uio.h" 2037741Smckusick #include "malloc.h" 2137Sbill 2243450Smckusick #define RETURN(val) {if (u.u_spare[0] != 0) panic("lock count"); return (val);} 2339797Smckusick 2437741Smckusick /* 2537741Smckusick * Virtual File System System Calls 2637741Smckusick */ 2712756Ssam 289167Ssam /* 2937741Smckusick * mount system call 309167Ssam */ 3142441Smckusick /* ARGSUSED */ 3242441Smckusick mount(p, uap, retval) 3342441Smckusick register struct proc *p; 3442441Smckusick register struct args { 3537741Smckusick int type; 3637741Smckusick char *dir; 3737741Smckusick int flags; 3837741Smckusick caddr_t data; 3942441Smckusick } *uap; 4042441Smckusick int *retval; 4142441Smckusick { 4242441Smckusick register struct nameidata *ndp = &u.u_nd; 4339335Smckusick register struct vnode *vp; 4439335Smckusick register struct mount *mp; 4540111Smckusick int error, flag; 466254Sroot 4737741Smckusick /* 4837741Smckusick * Must be super user 4937741Smckusick */ 5042441Smckusick if (error = suser(ndp->ni_cred, &u.u_acflag)) 5137741Smckusick RETURN (error); 5237741Smckusick /* 5337741Smckusick * Get vnode to be covered 5437741Smckusick */ 5537741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 5637741Smckusick ndp->ni_segflg = UIO_USERSPACE; 5737741Smckusick ndp->ni_dirp = uap->dir; 5837741Smckusick if (error = namei(ndp)) 5937741Smckusick RETURN (error); 6037741Smckusick vp = ndp->ni_vp; 6141400Smckusick if (uap->flags & MNT_UPDATE) { 6239335Smckusick if ((vp->v_flag & VROOT) == 0) { 6339335Smckusick vput(vp); 6439335Smckusick RETURN (EINVAL); 6539335Smckusick } 6639335Smckusick mp = vp->v_mount; 6739335Smckusick /* 6839335Smckusick * We allow going from read-only to read-write, 6939335Smckusick * but not from read-write to read-only. 7039335Smckusick */ 7141400Smckusick if ((mp->mnt_flag & MNT_RDONLY) == 0 && 7241400Smckusick (uap->flags & MNT_RDONLY) != 0) { 7339335Smckusick vput(vp); 7439335Smckusick RETURN (EOPNOTSUPP); /* Needs translation */ 7539335Smckusick } 7641400Smckusick flag = mp->mnt_flag; 7741400Smckusick mp->mnt_flag |= MNT_UPDATE; 7839335Smckusick VOP_UNLOCK(vp); 7939335Smckusick goto update; 8039335Smckusick } 8139665Smckusick vinvalbuf(vp, 1); 8239805Smckusick if (vp->v_usecount != 1) { 8337741Smckusick vput(vp); 8437741Smckusick RETURN (EBUSY); 8537741Smckusick } 8637741Smckusick if (vp->v_type != VDIR) { 8737741Smckusick vput(vp); 8837741Smckusick RETURN (ENOTDIR); 8937741Smckusick } 9039741Smckusick if ((unsigned long)uap->type > MOUNT_MAXTYPE || 9137741Smckusick vfssw[uap->type] == (struct vfsops *)0) { 9237741Smckusick vput(vp); 9337741Smckusick RETURN (ENODEV); 9437741Smckusick } 9537741Smckusick 9637741Smckusick /* 9739335Smckusick * Allocate and initialize the file system. 9837741Smckusick */ 9937741Smckusick mp = (struct mount *)malloc((u_long)sizeof(struct mount), 10037741Smckusick M_MOUNT, M_WAITOK); 10141400Smckusick mp->mnt_op = vfssw[uap->type]; 10241400Smckusick mp->mnt_flag = 0; 10341400Smckusick mp->mnt_exroot = 0; 10441400Smckusick mp->mnt_mounth = NULLVP; 10539335Smckusick if (error = vfs_lock(mp)) { 10639335Smckusick free((caddr_t)mp, M_MOUNT); 10739335Smckusick vput(vp); 10839335Smckusick RETURN (error); 10939335Smckusick } 11039335Smckusick if (vp->v_mountedhere != (struct mount *)0) { 11139335Smckusick vfs_unlock(mp); 11239335Smckusick free((caddr_t)mp, M_MOUNT); 11339335Smckusick vput(vp); 11439335Smckusick RETURN (EBUSY); 11539335Smckusick } 11639335Smckusick vp->v_mountedhere = mp; 11741400Smckusick mp->mnt_vnodecovered = vp; 11839335Smckusick update: 11939335Smckusick /* 12039335Smckusick * Set the mount level flags. 12139335Smckusick */ 12241400Smckusick if (uap->flags & MNT_RDONLY) 12341400Smckusick mp->mnt_flag |= MNT_RDONLY; 12439335Smckusick else 12541400Smckusick mp->mnt_flag &= ~MNT_RDONLY; 12641400Smckusick if (uap->flags & MNT_NOSUID) 12741400Smckusick mp->mnt_flag |= MNT_NOSUID; 12839335Smckusick else 12941400Smckusick mp->mnt_flag &= ~MNT_NOSUID; 13041400Smckusick if (uap->flags & MNT_NOEXEC) 13141400Smckusick mp->mnt_flag |= MNT_NOEXEC; 13239335Smckusick else 13341400Smckusick mp->mnt_flag &= ~MNT_NOEXEC; 13441400Smckusick if (uap->flags & MNT_NODEV) 13541400Smckusick mp->mnt_flag |= MNT_NODEV; 13639335Smckusick else 13741400Smckusick mp->mnt_flag &= ~MNT_NODEV; 13841400Smckusick if (uap->flags & MNT_SYNCHRONOUS) 13941400Smckusick mp->mnt_flag |= MNT_SYNCHRONOUS; 14039335Smckusick else 14141400Smckusick mp->mnt_flag &= ~MNT_SYNCHRONOUS; 14239335Smckusick /* 14339335Smckusick * Mount the filesystem. 14439335Smckusick */ 14539335Smckusick error = VFS_MOUNT(mp, uap->dir, uap->data, ndp); 14641400Smckusick if (mp->mnt_flag & MNT_UPDATE) { 14741400Smckusick mp->mnt_flag &= ~MNT_UPDATE; 14839335Smckusick vrele(vp); 14940111Smckusick if (error) 15041400Smckusick mp->mnt_flag = flag; 15139335Smckusick RETURN (error); 15239335Smckusick } 15340110Smckusick /* 15440110Smckusick * Put the new filesystem on the mount list after root. 15540110Smckusick */ 15641400Smckusick mp->mnt_next = rootfs->mnt_next; 15741400Smckusick mp->mnt_prev = rootfs; 15841400Smckusick rootfs->mnt_next = mp; 15941400Smckusick mp->mnt_next->mnt_prev = mp; 16037741Smckusick cache_purge(vp); 16137741Smckusick if (!error) { 16239335Smckusick VOP_UNLOCK(vp); 16337741Smckusick vfs_unlock(mp); 16439044Smckusick error = VFS_START(mp, 0); 16537741Smckusick } else { 16637741Smckusick vfs_remove(mp); 16737741Smckusick free((caddr_t)mp, M_MOUNT); 16839335Smckusick vput(vp); 16937741Smckusick } 17037741Smckusick RETURN (error); 1716254Sroot } 1726254Sroot 1739167Ssam /* 17437741Smckusick * Unmount system call. 17537741Smckusick * 17637741Smckusick * Note: unmount takes a path to the vnode mounted on as argument, 17737741Smckusick * not special file (as before). 1789167Ssam */ 17942441Smckusick /* ARGSUSED */ 18042441Smckusick unmount(p, uap, retval) 18142441Smckusick register struct proc *p; 18242441Smckusick register struct args { 18337741Smckusick char *pathp; 18437741Smckusick int flags; 18542441Smckusick } *uap; 18642441Smckusick int *retval; 18742441Smckusick { 18837741Smckusick register struct vnode *vp; 18942441Smckusick register struct nameidata *ndp = &u.u_nd; 19039356Smckusick struct mount *mp; 19137741Smckusick int error; 1926254Sroot 19337741Smckusick /* 19437741Smckusick * Must be super user 19537741Smckusick */ 19642441Smckusick if (error = suser(ndp->ni_cred, &u.u_acflag)) 19737741Smckusick RETURN (error); 19837741Smckusick 19937741Smckusick ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW; 20037741Smckusick ndp->ni_segflg = UIO_USERSPACE; 20137741Smckusick ndp->ni_dirp = uap->pathp; 20237741Smckusick if (error = namei(ndp)) 20337741Smckusick RETURN (error); 20437741Smckusick vp = ndp->ni_vp; 20537741Smckusick /* 20637741Smckusick * Must be the root of the filesystem 20737741Smckusick */ 20837741Smckusick if ((vp->v_flag & VROOT) == 0) { 20937741Smckusick vput(vp); 21037741Smckusick RETURN (EINVAL); 21137741Smckusick } 21237741Smckusick mp = vp->v_mount; 21337741Smckusick vput(vp); 21439356Smckusick RETURN (dounmount(mp, uap->flags)); 21539356Smckusick } 21639356Smckusick 21739356Smckusick /* 21839356Smckusick * Do an unmount. 21939356Smckusick */ 22039356Smckusick dounmount(mp, flags) 22139356Smckusick register struct mount *mp; 22239356Smckusick int flags; 22339356Smckusick { 22439356Smckusick struct vnode *coveredvp; 22539356Smckusick int error; 22639356Smckusick 22741400Smckusick coveredvp = mp->mnt_vnodecovered; 22841298Smckusick if (vfs_busy(mp)) 22941298Smckusick return (EBUSY); 23041400Smckusick mp->mnt_flag |= MNT_UNMOUNT; 23137741Smckusick if (error = vfs_lock(mp)) 23239356Smckusick return (error); 23337741Smckusick 23445738Smckusick vnode_pager_umount(mp); /* release cached vnodes */ 23537741Smckusick cache_purgevfs(mp); /* remove cache entries for this file sys */ 23641676Smckusick if ((error = VFS_SYNC(mp, MNT_WAIT)) == 0 || (flags & MNT_FORCE)) 23741676Smckusick error = VFS_UNMOUNT(mp, flags); 23841400Smckusick mp->mnt_flag &= ~MNT_UNMOUNT; 23941298Smckusick vfs_unbusy(mp); 24037741Smckusick if (error) { 24137741Smckusick vfs_unlock(mp); 24237741Smckusick } else { 24337741Smckusick vrele(coveredvp); 24437741Smckusick vfs_remove(mp); 24537741Smckusick free((caddr_t)mp, M_MOUNT); 24637741Smckusick } 24739356Smckusick return (error); 2486254Sroot } 2496254Sroot 2509167Ssam /* 25137741Smckusick * Sync system call. 25237741Smckusick * Sync each mounted filesystem. 2539167Ssam */ 25439491Smckusick /* ARGSUSED */ 25542441Smckusick sync(p, uap, retval) 25642441Smckusick register struct proc *p; 25742441Smckusick struct args *uap; 25842441Smckusick int *retval; 2596254Sroot { 26037741Smckusick register struct mount *mp; 26141298Smckusick struct mount *omp; 26237741Smckusick 26337741Smckusick mp = rootfs; 26437741Smckusick do { 26540343Smckusick /* 26640343Smckusick * The lock check below is to avoid races with mount 26740343Smckusick * and unmount. 26840343Smckusick */ 26941400Smckusick if ((mp->mnt_flag & (MNT_MLOCK|MNT_RDONLY|MNT_MPBUSY)) == 0 && 27041298Smckusick !vfs_busy(mp)) { 27137741Smckusick VFS_SYNC(mp, MNT_NOWAIT); 27241298Smckusick omp = mp; 27341400Smckusick mp = mp->mnt_next; 27441298Smckusick vfs_unbusy(omp); 27541298Smckusick } else 27641400Smckusick mp = mp->mnt_next; 27737741Smckusick } while (mp != rootfs); 27837741Smckusick } 27937741Smckusick 28037741Smckusick /* 28141298Smckusick * operate on filesystem quotas 28241298Smckusick */ 28342441Smckusick /* ARGSUSED */ 28442441Smckusick quotactl(p, uap, retval) 28542441Smckusick register struct proc *p; 28642441Smckusick register struct args { 28741298Smckusick char *path; 28841298Smckusick int cmd; 28941298Smckusick int uid; 29041298Smckusick caddr_t arg; 29142441Smckusick } *uap; 29242441Smckusick int *retval; 29342441Smckusick { 29441298Smckusick register struct mount *mp; 29542441Smckusick register struct nameidata *ndp = &u.u_nd; 29641298Smckusick int error; 29741298Smckusick 29841298Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW; 29941298Smckusick ndp->ni_segflg = UIO_USERSPACE; 30041298Smckusick ndp->ni_dirp = uap->path; 30141298Smckusick if (error = namei(ndp)) 30241298Smckusick RETURN (error); 30341298Smckusick mp = ndp->ni_vp->v_mount; 30441298Smckusick vrele(ndp->ni_vp); 30541298Smckusick RETURN (VFS_QUOTACTL(mp, uap->cmd, uap->uid, uap->arg)); 30641298Smckusick } 30741298Smckusick 30841298Smckusick /* 30937741Smckusick * get filesystem statistics 31037741Smckusick */ 31142441Smckusick /* ARGSUSED */ 31242441Smckusick statfs(p, uap, retval) 31342441Smckusick register struct proc *p; 31442441Smckusick register struct args { 31537741Smckusick char *path; 31637741Smckusick struct statfs *buf; 31742441Smckusick } *uap; 31842441Smckusick int *retval; 31942441Smckusick { 32039464Smckusick register struct mount *mp; 32142441Smckusick register struct nameidata *ndp = &u.u_nd; 32240343Smckusick register struct statfs *sp; 32337741Smckusick int error; 32437741Smckusick 32539544Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW; 32637741Smckusick ndp->ni_segflg = UIO_USERSPACE; 32737741Smckusick ndp->ni_dirp = uap->path; 32837741Smckusick if (error = namei(ndp)) 32937741Smckusick RETURN (error); 33039544Smckusick mp = ndp->ni_vp->v_mount; 33141400Smckusick sp = &mp->mnt_stat; 33239544Smckusick vrele(ndp->ni_vp); 33340343Smckusick if (error = VFS_STATFS(mp, sp)) 33439544Smckusick RETURN (error); 33541400Smckusick sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 33640343Smckusick RETURN (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp))); 33737741Smckusick } 33837741Smckusick 33942441Smckusick /* 34042441Smckusick * get filesystem statistics 34142441Smckusick */ 34242441Smckusick /* ARGSUSED */ 34342441Smckusick fstatfs(p, uap, retval) 34442441Smckusick register struct proc *p; 34542441Smckusick register struct args { 34637741Smckusick int fd; 34737741Smckusick struct statfs *buf; 34842441Smckusick } *uap; 34942441Smckusick int *retval; 35042441Smckusick { 35137741Smckusick struct file *fp; 35239464Smckusick struct mount *mp; 35340343Smckusick register struct statfs *sp; 35437741Smckusick int error; 35537741Smckusick 35642441Smckusick if (error = getvnode(u.u_ofile, uap->fd, &fp)) 35737741Smckusick RETURN (error); 35839464Smckusick mp = ((struct vnode *)fp->f_data)->v_mount; 35941400Smckusick sp = &mp->mnt_stat; 36040343Smckusick if (error = VFS_STATFS(mp, sp)) 36137741Smckusick RETURN (error); 36241400Smckusick sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 36340343Smckusick RETURN (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp))); 36437741Smckusick } 36537741Smckusick 36637741Smckusick /* 36738270Smckusick * get statistics on all filesystems 36838270Smckusick */ 36942441Smckusick getfsstat(p, uap, retval) 37042441Smckusick register struct proc *p; 37142441Smckusick register struct args { 37238270Smckusick struct statfs *buf; 37338270Smckusick long bufsize; 37440343Smckusick int flags; 37542441Smckusick } *uap; 37642441Smckusick int *retval; 37742441Smckusick { 37838270Smckusick register struct mount *mp; 37940343Smckusick register struct statfs *sp; 38039606Smckusick caddr_t sfsp; 38138270Smckusick long count, maxcount, error; 38238270Smckusick 38338270Smckusick maxcount = uap->bufsize / sizeof(struct statfs); 38439606Smckusick sfsp = (caddr_t)uap->buf; 38538270Smckusick mp = rootfs; 38638270Smckusick count = 0; 38738270Smckusick do { 38841400Smckusick if (sfsp && count < maxcount && 38941400Smckusick ((mp->mnt_flag & MNT_MLOCK) == 0)) { 39041400Smckusick sp = &mp->mnt_stat; 39140343Smckusick /* 39240343Smckusick * If MNT_NOWAIT is specified, do not refresh the 39340343Smckusick * fsstat cache. MNT_WAIT overrides MNT_NOWAIT. 39440343Smckusick */ 39540343Smckusick if (((uap->flags & MNT_NOWAIT) == 0 || 39640343Smckusick (uap->flags & MNT_WAIT)) && 39740343Smckusick (error = VFS_STATFS(mp, sp))) { 39841400Smckusick mp = mp->mnt_prev; 39939607Smckusick continue; 40039607Smckusick } 40141400Smckusick sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 40240343Smckusick if (error = copyout((caddr_t)sp, sfsp, sizeof(*sp))) 40339606Smckusick RETURN (error); 40440343Smckusick sfsp += sizeof(*sp); 40538270Smckusick } 40639606Smckusick count++; 40741400Smckusick mp = mp->mnt_prev; 40838270Smckusick } while (mp != rootfs); 40938270Smckusick if (sfsp && count > maxcount) 41042441Smckusick *retval = maxcount; 41138270Smckusick else 41242441Smckusick *retval = count; 41338270Smckusick RETURN (0); 41438270Smckusick } 41538270Smckusick 41638270Smckusick /* 41738259Smckusick * Change current working directory to a given file descriptor. 41838259Smckusick */ 41942441Smckusick /* ARGSUSED */ 42042441Smckusick fchdir(p, uap, retval) 42142441Smckusick register struct proc *p; 42242441Smckusick struct args { 42342441Smckusick int fd; 42442441Smckusick } *uap; 42542441Smckusick int *retval; 42638259Smckusick { 42742441Smckusick register struct nameidata *ndp = &u.u_nd; 42838259Smckusick register struct vnode *vp; 42938259Smckusick struct file *fp; 43038259Smckusick int error; 43138259Smckusick 43242441Smckusick if (error = getvnode(u.u_ofile, uap->fd, &fp)) 43338259Smckusick RETURN (error); 43438259Smckusick vp = (struct vnode *)fp->f_data; 43538259Smckusick VOP_LOCK(vp); 43638259Smckusick if (vp->v_type != VDIR) 43738259Smckusick error = ENOTDIR; 43838259Smckusick else 43942441Smckusick error = VOP_ACCESS(vp, VEXEC, ndp->ni_cred); 44038259Smckusick VOP_UNLOCK(vp); 44139860Smckusick if (error) 44239860Smckusick RETURN (error); 44339860Smckusick VREF(vp); 44442441Smckusick vrele(ndp->ni_cdir); 44542441Smckusick ndp->ni_cdir = vp; 44639860Smckusick RETURN (0); 44738259Smckusick } 44838259Smckusick 44938259Smckusick /* 45037741Smckusick * Change current working directory (``.''). 45137741Smckusick */ 45242441Smckusick /* ARGSUSED */ 45342441Smckusick chdir(p, uap, retval) 45442441Smckusick register struct proc *p; 45542441Smckusick struct args { 45642441Smckusick char *fname; 45742441Smckusick } *uap; 45842441Smckusick int *retval; 45937741Smckusick { 46042441Smckusick register struct nameidata *ndp = &u.u_nd; 46137741Smckusick int error; 4626254Sroot 46337741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 46416694Smckusick ndp->ni_segflg = UIO_USERSPACE; 46516694Smckusick ndp->ni_dirp = uap->fname; 46637741Smckusick if (error = chdirec(ndp)) 46737741Smckusick RETURN (error); 46842441Smckusick vrele(ndp->ni_cdir); 46942441Smckusick ndp->ni_cdir = ndp->ni_vp; 47037741Smckusick RETURN (0); 47137741Smckusick } 4726254Sroot 47337741Smckusick /* 47437741Smckusick * Change notion of root (``/'') directory. 47537741Smckusick */ 47642441Smckusick /* ARGSUSED */ 47742441Smckusick chroot(p, uap, retval) 47842441Smckusick register struct proc *p; 47942441Smckusick struct args { 48042441Smckusick char *fname; 48142441Smckusick } *uap; 48242441Smckusick int *retval; 48337741Smckusick { 48442441Smckusick register struct nameidata *ndp = &u.u_nd; 48537741Smckusick int error; 48637741Smckusick 48742441Smckusick if (error = suser(ndp->ni_cred, &u.u_acflag)) 48837741Smckusick RETURN (error); 48937741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 49037741Smckusick ndp->ni_segflg = UIO_USERSPACE; 49137741Smckusick ndp->ni_dirp = uap->fname; 49237741Smckusick if (error = chdirec(ndp)) 49337741Smckusick RETURN (error); 49442441Smckusick if (ndp->ni_rdir != NULL) 49542441Smckusick vrele(ndp->ni_rdir); 49642441Smckusick ndp->ni_rdir = ndp->ni_vp; 49737741Smckusick RETURN (0); 4986254Sroot } 4996254Sroot 50037Sbill /* 50137741Smckusick * Common routine for chroot and chdir. 50237741Smckusick */ 50337741Smckusick chdirec(ndp) 50437741Smckusick register struct nameidata *ndp; 50537741Smckusick { 50637741Smckusick struct vnode *vp; 50737741Smckusick int error; 50837741Smckusick 50937741Smckusick if (error = namei(ndp)) 51037741Smckusick return (error); 51137741Smckusick vp = ndp->ni_vp; 51237741Smckusick if (vp->v_type != VDIR) 51337741Smckusick error = ENOTDIR; 51437741Smckusick else 51538399Smckusick error = VOP_ACCESS(vp, VEXEC, ndp->ni_cred); 51637741Smckusick VOP_UNLOCK(vp); 51737741Smckusick if (error) 51837741Smckusick vrele(vp); 51937741Smckusick return (error); 52037741Smckusick } 52137741Smckusick 52237741Smckusick /* 5236254Sroot * Open system call. 52442441Smckusick * Check permissions, allocate an open file structure, 52542441Smckusick * and call the device open routine if any. 5266254Sroot */ 52742441Smckusick open(p, uap, retval) 52842441Smckusick register struct proc *p; 52942441Smckusick register struct args { 5306254Sroot char *fname; 5317701Ssam int mode; 53212756Ssam int crtmode; 53342441Smckusick } *uap; 53442441Smckusick int *retval; 5356254Sroot { 53642441Smckusick struct nameidata *ndp = &u.u_nd; 53742441Smckusick register struct file *fp; 53837741Smckusick int fmode, cmode; 53937741Smckusick struct file *nfp; 54037741Smckusick int indx, error; 54137741Smckusick extern struct fileops vnops; 5426254Sroot 54337741Smckusick if (error = falloc(&nfp, &indx)) 54442441Smckusick RETURN (error); 54537741Smckusick fp = nfp; 54642441Smckusick fmode = uap->mode - FOPEN; 54742441Smckusick cmode = ((uap->crtmode &~ u.u_cmask) & 07777) &~ S_ISVTX; 54842441Smckusick ndp->ni_segflg = UIO_USERSPACE; 54942441Smckusick ndp->ni_dirp = uap->fname; 55045202Smckusick p->p_dupfd = -indx - 1; /* XXX check for fdopen */ 55142441Smckusick if (error = vn_open(ndp, fmode, cmode)) { 55237741Smckusick crfree(fp->f_cred); 55337741Smckusick fp->f_count--; 55443405Smckusick if (error == ENODEV && /* XXX from fdopen */ 55545202Smckusick p->p_dupfd >= 0 && 55643450Smckusick (error = dupfdopen(indx, p->p_dupfd, fmode)) == 0) { 55742441Smckusick *retval = indx; 55842441Smckusick RETURN (0); 55942441Smckusick } 56040884Smckusick if (error == ERESTART) 56140884Smckusick error = EINTR; 56242441Smckusick u.u_ofile[indx] = NULL; 56342441Smckusick RETURN (error); 56412756Ssam } 56537741Smckusick fp->f_flag = fmode & FMASK; 56637741Smckusick fp->f_type = DTYPE_VNODE; 56737741Smckusick fp->f_ops = &vnops; 56837741Smckusick fp->f_data = (caddr_t)ndp->ni_vp; 56942441Smckusick *retval = indx; 57042441Smckusick RETURN (0); 5716254Sroot } 5726254Sroot 57342955Smckusick #ifdef COMPAT_43 5746254Sroot /* 57542441Smckusick * Creat system call. 5766254Sroot */ 57742955Smckusick ocreat(p, uap, retval) 57842441Smckusick struct proc *p; 57942441Smckusick register struct args { 58042441Smckusick char *fname; 58142441Smckusick int fmode; 58242441Smckusick } *uap; 58342441Smckusick int *retval; 5846254Sroot { 58542441Smckusick struct args { 5866254Sroot char *fname; 58742441Smckusick int mode; 58842441Smckusick int crtmode; 58942441Smckusick } openuap; 59042441Smckusick 59142441Smckusick openuap.fname = uap->fname; 59242441Smckusick openuap.crtmode = uap->fmode; 59342441Smckusick openuap.mode = O_WRONLY | O_CREAT | O_TRUNC; 59442441Smckusick RETURN (open(p, &openuap, retval)); 59542441Smckusick } 59642955Smckusick #endif /* COMPAT_43 */ 59742441Smckusick 59842441Smckusick /* 59942441Smckusick * Mknod system call 60042441Smckusick */ 60142441Smckusick /* ARGSUSED */ 60242441Smckusick mknod(p, uap, retval) 60342441Smckusick register struct proc *p; 60442441Smckusick register struct args { 60542441Smckusick char *fname; 6066254Sroot int fmode; 6076254Sroot int dev; 60842441Smckusick } *uap; 60942441Smckusick int *retval; 61042441Smckusick { 61142441Smckusick register struct nameidata *ndp = &u.u_nd; 61237741Smckusick register struct vnode *vp; 61337741Smckusick struct vattr vattr; 61437741Smckusick int error; 6156254Sroot 61642441Smckusick if (error = suser(ndp->ni_cred, &u.u_acflag)) 61737741Smckusick RETURN (error); 61837741Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 61916694Smckusick ndp->ni_segflg = UIO_USERSPACE; 62016694Smckusick ndp->ni_dirp = uap->fname; 62137741Smckusick if (error = namei(ndp)) 62237741Smckusick RETURN (error); 62337741Smckusick vp = ndp->ni_vp; 62437741Smckusick if (vp != NULL) { 62537741Smckusick error = EEXIST; 62612756Ssam goto out; 6276254Sroot } 62841362Smckusick VATTR_NULL(&vattr); 62940635Smckusick switch (uap->fmode & S_IFMT) { 63012756Ssam 63140635Smckusick case S_IFMT: /* used by badsect to flag bad sectors */ 63237741Smckusick vattr.va_type = VBAD; 63337741Smckusick break; 63440635Smckusick case S_IFCHR: 63537741Smckusick vattr.va_type = VCHR; 63637741Smckusick break; 63740635Smckusick case S_IFBLK: 63837741Smckusick vattr.va_type = VBLK; 63937741Smckusick break; 64037741Smckusick default: 64137741Smckusick error = EINVAL; 64237741Smckusick goto out; 6436254Sroot } 64442441Smckusick vattr.va_mode = (uap->fmode & 07777) &~ u.u_cmask; 64537741Smckusick vattr.va_rdev = uap->dev; 6466254Sroot out: 64742465Smckusick if (!error) { 64842465Smckusick error = VOP_MKNOD(ndp, &vattr, ndp->ni_cred); 64942465Smckusick } else { 65037741Smckusick VOP_ABORTOP(ndp); 65143344Smckusick if (ndp->ni_dvp == vp) 65243344Smckusick vrele(ndp->ni_dvp); 65343344Smckusick else 65443344Smckusick vput(ndp->ni_dvp); 65542465Smckusick if (vp) 65642465Smckusick vrele(vp); 65742465Smckusick } 65837741Smckusick RETURN (error); 6596254Sroot } 6606254Sroot 6616254Sroot /* 66240285Smckusick * Mkfifo system call 66340285Smckusick */ 66442441Smckusick /* ARGSUSED */ 66542441Smckusick mkfifo(p, uap, retval) 66642441Smckusick register struct proc *p; 66742441Smckusick register struct args { 66840285Smckusick char *fname; 66940285Smckusick int fmode; 67042441Smckusick } *uap; 67142441Smckusick int *retval; 67242441Smckusick { 67342441Smckusick register struct nameidata *ndp = &u.u_nd; 67440285Smckusick struct vattr vattr; 67540285Smckusick int error; 67640285Smckusick 67740285Smckusick #ifndef FIFO 67840285Smckusick RETURN (EOPNOTSUPP); 67940285Smckusick #else 68040285Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 68140285Smckusick ndp->ni_segflg = UIO_USERSPACE; 68240285Smckusick ndp->ni_dirp = uap->fname; 68340285Smckusick if (error = namei(ndp)) 68440285Smckusick RETURN (error); 68540285Smckusick if (ndp->ni_vp != NULL) { 68640285Smckusick VOP_ABORTOP(ndp); 68743344Smckusick if (ndp->ni_dvp == ndp->ni_vp) 68843344Smckusick vrele(ndp->ni_dvp); 68943344Smckusick else 69043344Smckusick vput(ndp->ni_dvp); 69142465Smckusick vrele(ndp->ni_vp); 69240285Smckusick RETURN (EEXIST); 69340285Smckusick } 694*45785Sbostic VATTR_NULL(&vattr); 695*45785Sbostic vattr.va_type = VFIFO; 696*45785Sbostic vattr.va_mode = (uap->fmode & 07777) &~ u.u_cmask; 69740285Smckusick RETURN (VOP_MKNOD(ndp, &vattr, ndp->ni_cred)); 69840285Smckusick #endif /* FIFO */ 69940285Smckusick } 70040285Smckusick 70140285Smckusick /* 7026254Sroot * link system call 7036254Sroot */ 70442441Smckusick /* ARGSUSED */ 70542441Smckusick link(p, uap, retval) 70642441Smckusick register struct proc *p; 70742441Smckusick register struct args { 7086254Sroot char *target; 7096254Sroot char *linkname; 71042441Smckusick } *uap; 71142441Smckusick int *retval; 71242441Smckusick { 71342441Smckusick register struct nameidata *ndp = &u.u_nd; 71437741Smckusick register struct vnode *vp, *xp; 71537741Smckusick int error; 7166254Sroot 71716694Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW; 71816694Smckusick ndp->ni_segflg = UIO_USERSPACE; 71916694Smckusick ndp->ni_dirp = uap->target; 72037741Smckusick if (error = namei(ndp)) 72137741Smckusick RETURN (error); 72237741Smckusick vp = ndp->ni_vp; 72337741Smckusick if (vp->v_type == VDIR && 72442441Smckusick (error = suser(ndp->ni_cred, &u.u_acflag))) 72537741Smckusick goto out1; 72637741Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 72716694Smckusick ndp->ni_dirp = (caddr_t)uap->linkname; 72837741Smckusick if (error = namei(ndp)) 72937741Smckusick goto out1; 73037741Smckusick xp = ndp->ni_vp; 7316254Sroot if (xp != NULL) { 73237741Smckusick error = EEXIST; 7336254Sroot goto out; 7346254Sroot } 73537741Smckusick xp = ndp->ni_dvp; 73637741Smckusick if (vp->v_mount != xp->v_mount) 73737741Smckusick error = EXDEV; 7386254Sroot out: 73942465Smckusick if (!error) { 74042465Smckusick error = VOP_LINK(vp, ndp); 74142465Smckusick } else { 74237741Smckusick VOP_ABORTOP(ndp); 74343344Smckusick if (ndp->ni_dvp == ndp->ni_vp) 74443344Smckusick vrele(ndp->ni_dvp); 74543344Smckusick else 74643344Smckusick vput(ndp->ni_dvp); 74742465Smckusick if (ndp->ni_vp) 74842465Smckusick vrele(ndp->ni_vp); 74942465Smckusick } 75037741Smckusick out1: 75137741Smckusick vrele(vp); 75237741Smckusick RETURN (error); 7536254Sroot } 7546254Sroot 7556254Sroot /* 7566254Sroot * symlink -- make a symbolic link 7576254Sroot */ 75842441Smckusick /* ARGSUSED */ 75942441Smckusick symlink(p, uap, retval) 76042441Smckusick register struct proc *p; 76142441Smckusick register struct args { 7626254Sroot char *target; 7636254Sroot char *linkname; 76442441Smckusick } *uap; 76542441Smckusick int *retval; 76642441Smckusick { 76742441Smckusick register struct nameidata *ndp = &u.u_nd; 76837741Smckusick struct vattr vattr; 76937741Smckusick char *target; 77037741Smckusick int error; 7716254Sroot 77216694Smckusick ndp->ni_segflg = UIO_USERSPACE; 77316694Smckusick ndp->ni_dirp = uap->linkname; 77437741Smckusick MALLOC(target, char *, MAXPATHLEN, M_NAMEI, M_WAITOK); 77537741Smckusick if (error = copyinstr(uap->target, target, MAXPATHLEN, (u_int *)0)) 77642465Smckusick goto out; 77737741Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 77837741Smckusick if (error = namei(ndp)) 77942465Smckusick goto out; 78042465Smckusick if (ndp->ni_vp) { 78142465Smckusick VOP_ABORTOP(ndp); 78243344Smckusick if (ndp->ni_dvp == ndp->ni_vp) 78343344Smckusick vrele(ndp->ni_dvp); 78443344Smckusick else 78543344Smckusick vput(ndp->ni_dvp); 78642465Smckusick vrele(ndp->ni_vp); 78737741Smckusick error = EEXIST; 78837741Smckusick goto out; 7896254Sroot } 79041362Smckusick VATTR_NULL(&vattr); 79142441Smckusick vattr.va_mode = 0777 &~ u.u_cmask; 79242465Smckusick error = VOP_SYMLINK(ndp, &vattr, target); 79337741Smckusick out: 79437741Smckusick FREE(target, M_NAMEI); 79537741Smckusick RETURN (error); 7966254Sroot } 7976254Sroot 7986254Sroot /* 7996254Sroot * Unlink system call. 8006254Sroot * Hard to avoid races here, especially 8016254Sroot * in unlinking directories. 8026254Sroot */ 80342441Smckusick /* ARGSUSED */ 80442441Smckusick unlink(p, uap, retval) 80542441Smckusick register struct proc *p; 80642441Smckusick struct args { 80742441Smckusick char *fname; 80842441Smckusick } *uap; 80942441Smckusick int *retval; 8106254Sroot { 81142441Smckusick register struct nameidata *ndp = &u.u_nd; 81237741Smckusick register struct vnode *vp; 81337741Smckusick int error; 8146254Sroot 81537741Smckusick ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF; 81616694Smckusick ndp->ni_segflg = UIO_USERSPACE; 81716694Smckusick ndp->ni_dirp = uap->fname; 81837741Smckusick if (error = namei(ndp)) 81937741Smckusick RETURN (error); 82037741Smckusick vp = ndp->ni_vp; 82137741Smckusick if (vp->v_type == VDIR && 82242441Smckusick (error = suser(ndp->ni_cred, &u.u_acflag))) 8236254Sroot goto out; 8246254Sroot /* 8256254Sroot * Don't unlink a mounted file. 8266254Sroot */ 82737741Smckusick if (vp->v_flag & VROOT) { 82837741Smckusick error = EBUSY; 8296254Sroot goto out; 8306254Sroot } 83145738Smckusick (void) vnode_pager_uncache(vp); 8326254Sroot out: 83342465Smckusick if (!error) { 83442465Smckusick error = VOP_REMOVE(ndp); 83542465Smckusick } else { 83637741Smckusick VOP_ABORTOP(ndp); 83743344Smckusick if (ndp->ni_dvp == vp) 83843344Smckusick vrele(ndp->ni_dvp); 83943344Smckusick else 84043344Smckusick vput(ndp->ni_dvp); 84142465Smckusick vput(vp); 84242465Smckusick } 84337741Smckusick RETURN (error); 8446254Sroot } 8456254Sroot 8466254Sroot /* 8476254Sroot * Seek system call 8486254Sroot */ 84942441Smckusick lseek(p, uap, retval) 85042441Smckusick register struct proc *p; 85142441Smckusick register struct args { 85237741Smckusick int fdes; 8536254Sroot off_t off; 8546254Sroot int sbase; 85542441Smckusick } *uap; 85642441Smckusick off_t *retval; 85742441Smckusick { 85842441Smckusick struct ucred *cred = u.u_nd.ni_cred; 85942441Smckusick register struct file *fp; 86037741Smckusick struct vattr vattr; 86137741Smckusick int error; 8626254Sroot 86337741Smckusick if ((unsigned)uap->fdes >= NOFILE || 86442441Smckusick (fp = u.u_ofile[uap->fdes]) == NULL) 86537741Smckusick RETURN (EBADF); 86637741Smckusick if (fp->f_type != DTYPE_VNODE) 86737741Smckusick RETURN (ESPIPE); 86813878Ssam switch (uap->sbase) { 86913878Ssam 87013878Ssam case L_INCR: 87113878Ssam fp->f_offset += uap->off; 87213878Ssam break; 87313878Ssam 87413878Ssam case L_XTND: 87537741Smckusick if (error = VOP_GETATTR((struct vnode *)fp->f_data, 87642441Smckusick &vattr, cred)) 87737741Smckusick RETURN (error); 87837741Smckusick fp->f_offset = uap->off + vattr.va_size; 87913878Ssam break; 88013878Ssam 88113878Ssam case L_SET: 88213878Ssam fp->f_offset = uap->off; 88313878Ssam break; 88413878Ssam 88513878Ssam default: 88637741Smckusick RETURN (EINVAL); 88713878Ssam } 88842441Smckusick *retval = fp->f_offset; 88937741Smckusick RETURN (0); 8906254Sroot } 8916254Sroot 8926254Sroot /* 8936254Sroot * Access system call 8946254Sroot */ 89542441Smckusick /* ARGSUSED */ 89642441Smckusick saccess(p, uap, retval) 89742441Smckusick register struct proc *p; 89842441Smckusick register struct args { 8996254Sroot char *fname; 9006254Sroot int fmode; 90142441Smckusick } *uap; 90242441Smckusick int *retval; 90342441Smckusick { 90442441Smckusick register struct nameidata *ndp = &u.u_nd; 90542441Smckusick register struct ucred *cred = ndp->ni_cred; 90637741Smckusick register struct vnode *vp; 90737741Smckusick int error, mode, svuid, svgid; 9086254Sroot 90942441Smckusick svuid = cred->cr_uid; 91042441Smckusick svgid = cred->cr_groups[0]; 91142441Smckusick cred->cr_uid = p->p_ruid; 91242441Smckusick cred->cr_groups[0] = p->p_rgid; 91337741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 91416694Smckusick ndp->ni_segflg = UIO_USERSPACE; 91516694Smckusick ndp->ni_dirp = uap->fname; 91637741Smckusick if (error = namei(ndp)) 91737741Smckusick goto out1; 91837741Smckusick vp = ndp->ni_vp; 91937741Smckusick /* 92037741Smckusick * fmode == 0 means only check for exist 92137741Smckusick */ 92237741Smckusick if (uap->fmode) { 92337741Smckusick mode = 0; 92437741Smckusick if (uap->fmode & R_OK) 92537741Smckusick mode |= VREAD; 92637741Smckusick if (uap->fmode & W_OK) 92737741Smckusick mode |= VWRITE; 92837741Smckusick if (uap->fmode & X_OK) 92937741Smckusick mode |= VEXEC; 93039543Smckusick if ((mode & VWRITE) == 0 || (error = vn_writechk(vp)) == 0) 93138399Smckusick error = VOP_ACCESS(vp, mode, ndp->ni_cred); 9326254Sroot } 93337741Smckusick vput(vp); 93437741Smckusick out1: 93542441Smckusick cred->cr_uid = svuid; 93642441Smckusick cred->cr_groups[0] = svgid; 93737741Smckusick RETURN (error); 9386254Sroot } 9396254Sroot 9406254Sroot /* 9416574Smckusic * Stat system call. This version follows links. 94237Sbill */ 94342441Smckusick /* ARGSUSED */ 94442441Smckusick stat(p, uap, retval) 94542441Smckusick register struct proc *p; 94642441Smckusick register struct args { 94742441Smckusick char *fname; 94842441Smckusick struct stat *ub; 94942441Smckusick } *uap; 95042441Smckusick int *retval; 95137Sbill { 95242441Smckusick register struct nameidata *ndp = &u.u_nd; 95342441Smckusick struct stat sb; 95442441Smckusick int error; 95537Sbill 95642441Smckusick ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW; 95742441Smckusick ndp->ni_segflg = UIO_USERSPACE; 95842441Smckusick ndp->ni_dirp = uap->fname; 95942441Smckusick if (error = namei(ndp)) 96042441Smckusick RETURN (error); 96142441Smckusick error = vn_stat(ndp->ni_vp, &sb); 96242441Smckusick vput(ndp->ni_vp); 96342441Smckusick if (error) 96442441Smckusick RETURN (error); 96542441Smckusick error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb)); 96642441Smckusick RETURN (error); 96737Sbill } 96837Sbill 96937Sbill /* 9706574Smckusic * Lstat system call. This version does not follow links. 9715992Swnj */ 97242441Smckusick /* ARGSUSED */ 97342441Smckusick lstat(p, uap, retval) 97442441Smckusick register struct proc *p; 97542441Smckusick register struct args { 9765992Swnj char *fname; 97712756Ssam struct stat *ub; 97842441Smckusick } *uap; 97942441Smckusick int *retval; 98042441Smckusick { 98142441Smckusick register struct nameidata *ndp = &u.u_nd; 98212756Ssam struct stat sb; 98337741Smckusick int error; 9845992Swnj 98542441Smckusick ndp->ni_nameiop = LOOKUP | LOCKLEAF | NOFOLLOW; 98616694Smckusick ndp->ni_segflg = UIO_USERSPACE; 98716694Smckusick ndp->ni_dirp = uap->fname; 98837741Smckusick if (error = namei(ndp)) 98937741Smckusick RETURN (error); 99037741Smckusick error = vn_stat(ndp->ni_vp, &sb); 99137741Smckusick vput(ndp->ni_vp); 99237741Smckusick if (error) 99337741Smckusick RETURN (error); 99437741Smckusick error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb)); 99537741Smckusick RETURN (error); 9965992Swnj } 9975992Swnj 9985992Swnj /* 9995992Swnj * Return target name of a symbolic link 100037Sbill */ 100142441Smckusick /* ARGSUSED */ 100242441Smckusick readlink(p, uap, retval) 100342441Smckusick register struct proc *p; 100442441Smckusick register struct args { 10055992Swnj char *name; 10065992Swnj char *buf; 10075992Swnj int count; 100842441Smckusick } *uap; 100942441Smckusick int *retval; 101042441Smckusick { 101142441Smckusick register struct nameidata *ndp = &u.u_nd; 101237741Smckusick register struct vnode *vp; 101337741Smckusick struct iovec aiov; 101437741Smckusick struct uio auio; 101537741Smckusick int error; 10165992Swnj 101737741Smckusick ndp->ni_nameiop = LOOKUP | LOCKLEAF; 101816694Smckusick ndp->ni_segflg = UIO_USERSPACE; 101916694Smckusick ndp->ni_dirp = uap->name; 102037741Smckusick if (error = namei(ndp)) 102137741Smckusick RETURN (error); 102237741Smckusick vp = ndp->ni_vp; 102337741Smckusick if (vp->v_type != VLNK) { 102437741Smckusick error = EINVAL; 10255992Swnj goto out; 10265992Swnj } 102737741Smckusick aiov.iov_base = uap->buf; 102837741Smckusick aiov.iov_len = uap->count; 102937741Smckusick auio.uio_iov = &aiov; 103037741Smckusick auio.uio_iovcnt = 1; 103137741Smckusick auio.uio_offset = 0; 103237741Smckusick auio.uio_rw = UIO_READ; 103337741Smckusick auio.uio_segflg = UIO_USERSPACE; 103437741Smckusick auio.uio_resid = uap->count; 103537741Smckusick error = VOP_READLINK(vp, &auio, ndp->ni_cred); 10365992Swnj out: 103737741Smckusick vput(vp); 103842441Smckusick *retval = uap->count - auio.uio_resid; 103937741Smckusick RETURN (error); 10405992Swnj } 10415992Swnj 10429167Ssam /* 104338259Smckusick * Change flags of a file given path name. 104438259Smckusick */ 104542441Smckusick /* ARGSUSED */ 104642441Smckusick chflags(p, uap, retval) 104742441Smckusick register struct proc *p; 104842441Smckusick register struct args { 104938259Smckusick char *fname; 105038259Smckusick int flags; 105142441Smckusick } *uap; 105242441Smckusick int *retval; 105342441Smckusick { 105442441Smckusick register struct nameidata *ndp = &u.u_nd; 105538259Smckusick register struct vnode *vp; 105638259Smckusick struct vattr vattr; 105738259Smckusick int error; 105838259Smckusick 105938259Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 106038259Smckusick ndp->ni_segflg = UIO_USERSPACE; 106138259Smckusick ndp->ni_dirp = uap->fname; 106238259Smckusick if (error = namei(ndp)) 106338259Smckusick RETURN (error); 106438259Smckusick vp = ndp->ni_vp; 106541400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 106638259Smckusick error = EROFS; 106738259Smckusick goto out; 106838259Smckusick } 1069*45785Sbostic VATTR_NULL(&vattr); 1070*45785Sbostic vattr.va_flags = uap->flags; 107138259Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 107238259Smckusick out: 107338259Smckusick vput(vp); 107438259Smckusick RETURN (error); 107538259Smckusick } 107638259Smckusick 107738259Smckusick /* 107838259Smckusick * Change flags of a file given a file descriptor. 107938259Smckusick */ 108042441Smckusick /* ARGSUSED */ 108142441Smckusick fchflags(p, uap, retval) 108242441Smckusick register struct proc *p; 108342441Smckusick register struct args { 108438259Smckusick int fd; 108538259Smckusick int flags; 108642441Smckusick } *uap; 108742441Smckusick int *retval; 108842441Smckusick { 108938259Smckusick struct vattr vattr; 109038259Smckusick struct vnode *vp; 109138259Smckusick struct file *fp; 109238259Smckusick int error; 109338259Smckusick 109442441Smckusick if (error = getvnode(u.u_ofile, uap->fd, &fp)) 109538259Smckusick RETURN (error); 109638259Smckusick vp = (struct vnode *)fp->f_data; 109738259Smckusick VOP_LOCK(vp); 109841400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 109938259Smckusick error = EROFS; 110038259Smckusick goto out; 110138259Smckusick } 1102*45785Sbostic VATTR_NULL(&vattr); 1103*45785Sbostic vattr.va_flags = uap->flags; 110438259Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred); 110538259Smckusick out: 110638259Smckusick VOP_UNLOCK(vp); 110738259Smckusick RETURN (error); 110838259Smckusick } 110938259Smckusick 111038259Smckusick /* 11119167Ssam * Change mode of a file given path name. 11129167Ssam */ 111342441Smckusick /* ARGSUSED */ 111442441Smckusick chmod(p, uap, retval) 111542441Smckusick register struct proc *p; 111642441Smckusick register struct args { 11176254Sroot char *fname; 11186254Sroot int fmode; 111942441Smckusick } *uap; 112042441Smckusick int *retval; 112142441Smckusick { 112242441Smckusick register struct nameidata *ndp = &u.u_nd; 112337741Smckusick register struct vnode *vp; 112437741Smckusick struct vattr vattr; 112537741Smckusick int error; 11265992Swnj 112737741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 112837741Smckusick ndp->ni_segflg = UIO_USERSPACE; 112937741Smckusick ndp->ni_dirp = uap->fname; 113037741Smckusick if (error = namei(ndp)) 113137741Smckusick RETURN (error); 113237741Smckusick vp = ndp->ni_vp; 113341400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 113437741Smckusick error = EROFS; 113537741Smckusick goto out; 113637741Smckusick } 1137*45785Sbostic VATTR_NULL(&vattr); 1138*45785Sbostic vattr.va_mode = uap->fmode & 07777; 113937741Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 114037741Smckusick out: 114137741Smckusick vput(vp); 114237741Smckusick RETURN (error); 11437701Ssam } 11447439Sroot 11459167Ssam /* 11469167Ssam * Change mode of a file given a file descriptor. 11479167Ssam */ 114842441Smckusick /* ARGSUSED */ 114942441Smckusick fchmod(p, uap, retval) 115042441Smckusick register struct proc *p; 115142441Smckusick register struct args { 11527701Ssam int fd; 11537701Ssam int fmode; 115442441Smckusick } *uap; 115542441Smckusick int *retval; 115642441Smckusick { 115737741Smckusick struct vattr vattr; 115837741Smckusick struct vnode *vp; 115937741Smckusick struct file *fp; 116037741Smckusick int error; 11617701Ssam 116242441Smckusick if (error = getvnode(u.u_ofile, uap->fd, &fp)) 116337741Smckusick RETURN (error); 116437741Smckusick vp = (struct vnode *)fp->f_data; 116537741Smckusick VOP_LOCK(vp); 116641400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 116737741Smckusick error = EROFS; 116837741Smckusick goto out; 11697439Sroot } 1170*45785Sbostic VATTR_NULL(&vattr); 1171*45785Sbostic vattr.va_mode = uap->fmode & 07777; 117237741Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred); 117337741Smckusick out: 117437741Smckusick VOP_UNLOCK(vp); 117537741Smckusick RETURN (error); 11765992Swnj } 11775992Swnj 11789167Ssam /* 11799167Ssam * Set ownership given a path name. 11809167Ssam */ 118142441Smckusick /* ARGSUSED */ 118242441Smckusick chown(p, uap, retval) 118342441Smckusick register struct proc *p; 118442441Smckusick register struct args { 11856254Sroot char *fname; 11866254Sroot int uid; 11876254Sroot int gid; 118842441Smckusick } *uap; 118942441Smckusick int *retval; 119042441Smckusick { 119142441Smckusick register struct nameidata *ndp = &u.u_nd; 119237741Smckusick register struct vnode *vp; 119337741Smckusick struct vattr vattr; 119437741Smckusick int error; 119537Sbill 119637741Smckusick ndp->ni_nameiop = LOOKUP | NOFOLLOW | LOCKLEAF; 119736614Sbostic ndp->ni_segflg = UIO_USERSPACE; 119836614Sbostic ndp->ni_dirp = uap->fname; 119937741Smckusick if (error = namei(ndp)) 120037741Smckusick RETURN (error); 120137741Smckusick vp = ndp->ni_vp; 120241400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 120337741Smckusick error = EROFS; 120437741Smckusick goto out; 120537741Smckusick } 1206*45785Sbostic VATTR_NULL(&vattr); 1207*45785Sbostic vattr.va_uid = uap->uid; 1208*45785Sbostic vattr.va_gid = uap->gid; 120937741Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 121037741Smckusick out: 121137741Smckusick vput(vp); 121237741Smckusick RETURN (error); 12137701Ssam } 12147439Sroot 12159167Ssam /* 12169167Ssam * Set ownership given a file descriptor. 12179167Ssam */ 121842441Smckusick /* ARGSUSED */ 121942441Smckusick fchown(p, uap, retval) 122042441Smckusick register struct proc *p; 122142441Smckusick register struct args { 12227701Ssam int fd; 12237701Ssam int uid; 12247701Ssam int gid; 122542441Smckusick } *uap; 122642441Smckusick int *retval; 122742441Smckusick { 122837741Smckusick struct vattr vattr; 122937741Smckusick struct vnode *vp; 123037741Smckusick struct file *fp; 123137741Smckusick int error; 12327701Ssam 123342441Smckusick if (error = getvnode(u.u_ofile, uap->fd, &fp)) 123437741Smckusick RETURN (error); 123537741Smckusick vp = (struct vnode *)fp->f_data; 123637741Smckusick VOP_LOCK(vp); 123741400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 123837741Smckusick error = EROFS; 123937741Smckusick goto out; 124037741Smckusick } 1241*45785Sbostic VATTR_NULL(&vattr); 1242*45785Sbostic vattr.va_uid = uap->uid; 1243*45785Sbostic vattr.va_gid = uap->gid; 124437741Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred); 124537741Smckusick out: 124637741Smckusick VOP_UNLOCK(vp); 124737741Smckusick RETURN (error); 12487701Ssam } 12497701Ssam 125042441Smckusick /* 125142441Smckusick * Set the access and modification times of a file. 125242441Smckusick */ 125342441Smckusick /* ARGSUSED */ 125442441Smckusick utimes(p, uap, retval) 125542441Smckusick register struct proc *p; 125642441Smckusick register struct args { 125711811Ssam char *fname; 125811811Ssam struct timeval *tptr; 125942441Smckusick } *uap; 126042441Smckusick int *retval; 126142441Smckusick { 126242441Smckusick register struct nameidata *ndp = &u.u_nd; 126337741Smckusick register struct vnode *vp; 126411811Ssam struct timeval tv[2]; 126537741Smckusick struct vattr vattr; 126637741Smckusick int error; 126711811Ssam 126837741Smckusick if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv))) 126937741Smckusick RETURN (error); 127037741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 127137741Smckusick ndp->ni_segflg = UIO_USERSPACE; 127237741Smckusick ndp->ni_dirp = uap->fname; 127337741Smckusick if (error = namei(ndp)) 127437741Smckusick RETURN (error); 127537741Smckusick vp = ndp->ni_vp; 127641400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 127737741Smckusick error = EROFS; 127837741Smckusick goto out; 127921015Smckusick } 1280*45785Sbostic VATTR_NULL(&vattr); 1281*45785Sbostic vattr.va_atime = tv[0]; 1282*45785Sbostic vattr.va_mtime = tv[1]; 128337741Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 128437741Smckusick out: 128537741Smckusick vput(vp); 128637741Smckusick RETURN (error); 128711811Ssam } 128811811Ssam 12899167Ssam /* 12909167Ssam * Truncate a file given its path name. 12919167Ssam */ 129242441Smckusick /* ARGSUSED */ 129342441Smckusick truncate(p, uap, retval) 129442441Smckusick register struct proc *p; 129542441Smckusick register struct args { 12967701Ssam char *fname; 129726473Skarels off_t length; 129842441Smckusick } *uap; 129942441Smckusick int *retval; 130042441Smckusick { 130142441Smckusick register struct nameidata *ndp = &u.u_nd; 130237741Smckusick register struct vnode *vp; 130337741Smckusick struct vattr vattr; 130437741Smckusick int error; 13057701Ssam 130637741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 130716694Smckusick ndp->ni_segflg = UIO_USERSPACE; 130816694Smckusick ndp->ni_dirp = uap->fname; 130937741Smckusick if (error = namei(ndp)) 131037741Smckusick RETURN (error); 131137741Smckusick vp = ndp->ni_vp; 131237741Smckusick if (vp->v_type == VDIR) { 131337741Smckusick error = EISDIR; 131437741Smckusick goto out; 13157701Ssam } 131638399Smckusick if ((error = vn_writechk(vp)) || 131738399Smckusick (error = VOP_ACCESS(vp, VWRITE, ndp->ni_cred))) 131837741Smckusick goto out; 1319*45785Sbostic VATTR_NULL(&vattr); 1320*45785Sbostic vattr.va_size = uap->length; 132137741Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 132237741Smckusick out: 132337741Smckusick vput(vp); 132437741Smckusick RETURN (error); 13257701Ssam } 13267701Ssam 13279167Ssam /* 13289167Ssam * Truncate a file given a file descriptor. 13299167Ssam */ 133042441Smckusick /* ARGSUSED */ 133142441Smckusick ftruncate(p, uap, retval) 133242441Smckusick register struct proc *p; 133342441Smckusick register struct args { 13347701Ssam int fd; 133526473Skarels off_t length; 133642441Smckusick } *uap; 133742441Smckusick int *retval; 133842441Smckusick { 133937741Smckusick struct vattr vattr; 134037741Smckusick struct vnode *vp; 13417701Ssam struct file *fp; 134237741Smckusick int error; 13437701Ssam 134442441Smckusick if (error = getvnode(u.u_ofile, uap->fd, &fp)) 134537741Smckusick RETURN (error); 134637741Smckusick if ((fp->f_flag & FWRITE) == 0) 134737741Smckusick RETURN (EINVAL); 134837741Smckusick vp = (struct vnode *)fp->f_data; 134937741Smckusick VOP_LOCK(vp); 135037741Smckusick if (vp->v_type == VDIR) { 135137741Smckusick error = EISDIR; 135237741Smckusick goto out; 13537701Ssam } 135438399Smckusick if (error = vn_writechk(vp)) 135537741Smckusick goto out; 1356*45785Sbostic VATTR_NULL(&vattr); 1357*45785Sbostic vattr.va_size = uap->length; 135837741Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred); 135937741Smckusick out: 136037741Smckusick VOP_UNLOCK(vp); 136137741Smckusick RETURN (error); 13627701Ssam } 13637701Ssam 13649167Ssam /* 13659167Ssam * Synch an open file. 13669167Ssam */ 136742441Smckusick /* ARGSUSED */ 136842441Smckusick fsync(p, uap, retval) 136942441Smckusick register struct proc *p; 137042441Smckusick struct args { 137142441Smckusick int fd; 137242441Smckusick } *uap; 137342441Smckusick int *retval; 13749167Ssam { 137539592Smckusick register struct vnode *vp; 13769167Ssam struct file *fp; 137737741Smckusick int error; 13789167Ssam 137942441Smckusick if (error = getvnode(u.u_ofile, uap->fd, &fp)) 138037741Smckusick RETURN (error); 138139592Smckusick vp = (struct vnode *)fp->f_data; 138239592Smckusick VOP_LOCK(vp); 138339592Smckusick error = VOP_FSYNC(vp, fp->f_flag, fp->f_cred, MNT_WAIT); 138439592Smckusick VOP_UNLOCK(vp); 138537741Smckusick RETURN (error); 13869167Ssam } 13879167Ssam 13889167Ssam /* 13899167Ssam * Rename system call. 13909167Ssam * 13919167Ssam * Source and destination must either both be directories, or both 13929167Ssam * not be directories. If target is a directory, it must be empty. 13939167Ssam */ 139442441Smckusick /* ARGSUSED */ 139542441Smckusick rename(p, uap, retval) 139642441Smckusick register struct proc *p; 139742441Smckusick register struct args { 13987701Ssam char *from; 13997701Ssam char *to; 140042441Smckusick } *uap; 140142441Smckusick int *retval; 140242441Smckusick { 140337741Smckusick register struct vnode *tvp, *fvp, *tdvp; 140442441Smckusick register struct nameidata *ndp = &u.u_nd; 140537741Smckusick struct nameidata tond; 140637741Smckusick int error; 14077701Ssam 140837741Smckusick ndp->ni_nameiop = DELETE | WANTPARENT; 140916694Smckusick ndp->ni_segflg = UIO_USERSPACE; 141016694Smckusick ndp->ni_dirp = uap->from; 141137741Smckusick if (error = namei(ndp)) 141237741Smckusick RETURN (error); 141337741Smckusick fvp = ndp->ni_vp; 141438266Smckusick nddup(ndp, &tond); 141537741Smckusick tond.ni_nameiop = RENAME | LOCKPARENT | LOCKLEAF | NOCACHE; 141637741Smckusick tond.ni_segflg = UIO_USERSPACE; 141737741Smckusick tond.ni_dirp = uap->to; 141842465Smckusick if (error = namei(&tond)) { 141942465Smckusick VOP_ABORTOP(ndp); 142042465Smckusick vrele(ndp->ni_dvp); 142142465Smckusick vrele(fvp); 142242465Smckusick goto out1; 142342465Smckusick } 142437741Smckusick tdvp = tond.ni_dvp; 142537741Smckusick tvp = tond.ni_vp; 142637741Smckusick if (tvp != NULL) { 142737741Smckusick if (fvp->v_type == VDIR && tvp->v_type != VDIR) { 142839242Sbostic error = ENOTDIR; 142937741Smckusick goto out; 143037741Smckusick } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) { 143139242Sbostic error = EISDIR; 143237741Smckusick goto out; 14339167Ssam } 143445240Smckusick if (fvp->v_mount != tvp->v_mount) { 143545240Smckusick error = EXDEV; 143645240Smckusick goto out; 143745240Smckusick } 14389167Ssam } 143937741Smckusick if (fvp->v_mount != tdvp->v_mount) { 144037741Smckusick error = EXDEV; 14419167Ssam goto out; 144210051Ssam } 144339286Smckusick if (fvp == tdvp) 144437741Smckusick error = EINVAL; 144539286Smckusick /* 144639286Smckusick * If source is the same as the destination, 144739286Smckusick * then there is nothing to do. 144839286Smckusick */ 144939286Smckusick if (fvp == tvp) 145039286Smckusick error = -1; 145137741Smckusick out: 145242465Smckusick if (!error) { 145342465Smckusick error = VOP_RENAME(ndp, &tond); 145442465Smckusick } else { 145537741Smckusick VOP_ABORTOP(&tond); 145643344Smckusick if (tdvp == tvp) 145743344Smckusick vrele(tdvp); 145843344Smckusick else 145943344Smckusick vput(tdvp); 146042465Smckusick if (tvp) 146142465Smckusick vput(tvp); 146237741Smckusick VOP_ABORTOP(ndp); 146342465Smckusick vrele(ndp->ni_dvp); 146442465Smckusick vrele(fvp); 14659167Ssam } 146637741Smckusick out1: 146738266Smckusick ndrele(&tond); 146839286Smckusick if (error == -1) 146939286Smckusick RETURN (0); 147037741Smckusick RETURN (error); 14717701Ssam } 14727701Ssam 14737535Sroot /* 147412756Ssam * Mkdir system call 147512756Ssam */ 147642441Smckusick /* ARGSUSED */ 147742441Smckusick mkdir(p, uap, retval) 147842441Smckusick register struct proc *p; 147942441Smckusick register struct args { 148012756Ssam char *name; 148112756Ssam int dmode; 148242441Smckusick } *uap; 148342441Smckusick int *retval; 148442441Smckusick { 148542441Smckusick register struct nameidata *ndp = &u.u_nd; 148637741Smckusick register struct vnode *vp; 148737741Smckusick struct vattr vattr; 148837741Smckusick int error; 148912756Ssam 149037741Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 149116694Smckusick ndp->ni_segflg = UIO_USERSPACE; 149216694Smckusick ndp->ni_dirp = uap->name; 149337741Smckusick if (error = namei(ndp)) 149437741Smckusick RETURN (error); 149537741Smckusick vp = ndp->ni_vp; 149637741Smckusick if (vp != NULL) { 149737741Smckusick VOP_ABORTOP(ndp); 149843344Smckusick if (ndp->ni_dvp == vp) 149943344Smckusick vrele(ndp->ni_dvp); 150043344Smckusick else 150143344Smckusick vput(ndp->ni_dvp); 150242465Smckusick vrele(vp); 150337741Smckusick RETURN (EEXIST); 150412756Ssam } 150541362Smckusick VATTR_NULL(&vattr); 150637741Smckusick vattr.va_type = VDIR; 150742441Smckusick vattr.va_mode = (uap->dmode & 0777) &~ u.u_cmask; 150837741Smckusick error = VOP_MKDIR(ndp, &vattr); 150938145Smckusick if (!error) 151038145Smckusick vput(ndp->ni_vp); 151137741Smckusick RETURN (error); 151212756Ssam } 151312756Ssam 151412756Ssam /* 151512756Ssam * Rmdir system call. 151612756Ssam */ 151742441Smckusick /* ARGSUSED */ 151842441Smckusick rmdir(p, uap, retval) 151942441Smckusick register struct proc *p; 152042441Smckusick struct args { 152142441Smckusick char *name; 152242441Smckusick } *uap; 152342441Smckusick int *retval; 152412756Ssam { 152542441Smckusick register struct nameidata *ndp = &u.u_nd; 152637741Smckusick register struct vnode *vp; 152737741Smckusick int error; 152812756Ssam 152937741Smckusick ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF; 153016694Smckusick ndp->ni_segflg = UIO_USERSPACE; 153116694Smckusick ndp->ni_dirp = uap->name; 153237741Smckusick if (error = namei(ndp)) 153337741Smckusick RETURN (error); 153437741Smckusick vp = ndp->ni_vp; 153537741Smckusick if (vp->v_type != VDIR) { 153637741Smckusick error = ENOTDIR; 153712756Ssam goto out; 153812756Ssam } 153912756Ssam /* 154037741Smckusick * No rmdir "." please. 154112756Ssam */ 154237741Smckusick if (ndp->ni_dvp == vp) { 154337741Smckusick error = EINVAL; 154412756Ssam goto out; 154512756Ssam } 154612756Ssam /* 154737741Smckusick * Don't unlink a mounted file. 154812756Ssam */ 154937741Smckusick if (vp->v_flag & VROOT) 155037741Smckusick error = EBUSY; 155112756Ssam out: 155242465Smckusick if (!error) { 155342465Smckusick error = VOP_RMDIR(ndp); 155442465Smckusick } else { 155537741Smckusick VOP_ABORTOP(ndp); 155643344Smckusick if (ndp->ni_dvp == vp) 155743344Smckusick vrele(ndp->ni_dvp); 155843344Smckusick else 155943344Smckusick vput(ndp->ni_dvp); 156042465Smckusick vput(vp); 156142465Smckusick } 156237741Smckusick RETURN (error); 156312756Ssam } 156412756Ssam 156537741Smckusick /* 156637741Smckusick * Read a block of directory entries in a file system independent format 156737741Smckusick */ 156842441Smckusick getdirentries(p, uap, retval) 156942441Smckusick register struct proc *p; 157042441Smckusick register struct args { 157137741Smckusick int fd; 157237741Smckusick char *buf; 157337741Smckusick unsigned count; 157437741Smckusick long *basep; 157542441Smckusick } *uap; 157642441Smckusick int *retval; 157742441Smckusick { 157839592Smckusick register struct vnode *vp; 157916540Ssam struct file *fp; 158037741Smckusick struct uio auio; 158137741Smckusick struct iovec aiov; 158238129Smckusick off_t off; 158340321Smckusick int error, eofflag; 158412756Ssam 158542441Smckusick if (error = getvnode(u.u_ofile, uap->fd, &fp)) 158637741Smckusick RETURN (error); 158737741Smckusick if ((fp->f_flag & FREAD) == 0) 158837741Smckusick RETURN (EBADF); 158939592Smckusick vp = (struct vnode *)fp->f_data; 159039592Smckusick if (vp->v_type != VDIR) 159139592Smckusick RETURN (EINVAL); 159237741Smckusick aiov.iov_base = uap->buf; 159337741Smckusick aiov.iov_len = uap->count; 159437741Smckusick auio.uio_iov = &aiov; 159537741Smckusick auio.uio_iovcnt = 1; 159637741Smckusick auio.uio_rw = UIO_READ; 159737741Smckusick auio.uio_segflg = UIO_USERSPACE; 159837741Smckusick auio.uio_resid = uap->count; 159939592Smckusick VOP_LOCK(vp); 160039592Smckusick auio.uio_offset = off = fp->f_offset; 160140321Smckusick error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag); 160239592Smckusick fp->f_offset = auio.uio_offset; 160339592Smckusick VOP_UNLOCK(vp); 160439592Smckusick if (error) 160537741Smckusick RETURN (error); 160639592Smckusick error = copyout((caddr_t)&off, (caddr_t)uap->basep, sizeof(long)); 160742441Smckusick *retval = uap->count - auio.uio_resid; 160837741Smckusick RETURN (error); 160912756Ssam } 161012756Ssam 161112756Ssam /* 161212756Ssam * mode mask for creation of files 161312756Ssam */ 161442441Smckusick mode_t 161542441Smckusick umask(p, uap, retval) 161642441Smckusick register struct proc *p; 161742441Smckusick struct args { 161842441Smckusick int mask; 161942441Smckusick } *uap; 162042441Smckusick int *retval; 162112756Ssam { 162212756Ssam 162342441Smckusick *retval = u.u_cmask; 162442441Smckusick u.u_cmask = uap->mask & 07777; 162537741Smckusick RETURN (0); 162612756Ssam } 162737741Smckusick 162839566Smarc /* 162939566Smarc * Void all references to file by ripping underlying filesystem 163039566Smarc * away from vnode. 163139566Smarc */ 163242441Smckusick /* ARGSUSED */ 163342441Smckusick revoke(p, uap, retval) 163442441Smckusick register struct proc *p; 163542441Smckusick register struct args { 163639566Smarc char *fname; 163742441Smckusick } *uap; 163842441Smckusick int *retval; 163942441Smckusick { 164042441Smckusick register struct nameidata *ndp = &u.u_nd; 164139566Smarc register struct vnode *vp; 164239566Smarc struct vattr vattr; 164339566Smarc int error; 164439566Smarc 164539566Smarc ndp->ni_nameiop = LOOKUP | FOLLOW; 164639566Smarc ndp->ni_segflg = UIO_USERSPACE; 164739566Smarc ndp->ni_dirp = uap->fname; 164839566Smarc if (error = namei(ndp)) 164939566Smarc RETURN (error); 165039566Smarc vp = ndp->ni_vp; 165139566Smarc if (vp->v_type != VCHR && vp->v_type != VBLK) { 165239566Smarc error = EINVAL; 165339566Smarc goto out; 165439566Smarc } 165542441Smckusick if (error = VOP_GETATTR(vp, &vattr, ndp->ni_cred)) 165639566Smarc goto out; 165742955Smckusick if (ndp->ni_cred->cr_uid != vattr.va_uid && 165842441Smckusick (error = suser(ndp->ni_cred, &u.u_acflag))) 165939566Smarc goto out; 166039805Smckusick if (vp->v_usecount > 1 || (vp->v_flag & VALIASED)) 166139632Smckusick vgoneall(vp); 166239566Smarc out: 166339566Smarc vrele(vp); 166439566Smarc RETURN (error); 166539566Smarc } 166639566Smarc 166738408Smckusick getvnode(ofile, fdes, fpp) 166838408Smckusick struct file *ofile[]; 166937741Smckusick struct file **fpp; 167037741Smckusick int fdes; 167137741Smckusick { 167237741Smckusick struct file *fp; 167337741Smckusick 167438408Smckusick if ((unsigned)fdes >= NOFILE || (fp = ofile[fdes]) == NULL) 167537741Smckusick return (EBADF); 167637741Smckusick if (fp->f_type != DTYPE_VNODE) 167737741Smckusick return (EINVAL); 167837741Smckusick *fpp = fp; 167937741Smckusick return (0); 168037741Smckusick } 1681