123405Smckusick /* 237741Smckusick * Copyright (c) 1989 The Regents of the University of California. 337741Smckusick * All rights reserved. 423405Smckusick * 544459Sbostic * %sccs.include.redist.c% 637741Smckusick * 7*45738Smckusick * @(#)vfs_syscalls.c 7.60 (Berkeley) 12/05/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 234*45738Smckusick 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 } else { 69441362Smckusick VATTR_NULL(&vattr); 69540285Smckusick vattr.va_type = VFIFO; 69642441Smckusick vattr.va_mode = (uap->fmode & 07777) &~ u.u_cmask; 69740285Smckusick } 69840285Smckusick RETURN (VOP_MKNOD(ndp, &vattr, ndp->ni_cred)); 69940285Smckusick #endif /* FIFO */ 70040285Smckusick } 70140285Smckusick 70240285Smckusick /* 7036254Sroot * link system call 7046254Sroot */ 70542441Smckusick /* ARGSUSED */ 70642441Smckusick link(p, uap, retval) 70742441Smckusick register struct proc *p; 70842441Smckusick register struct args { 7096254Sroot char *target; 7106254Sroot char *linkname; 71142441Smckusick } *uap; 71242441Smckusick int *retval; 71342441Smckusick { 71442441Smckusick register struct nameidata *ndp = &u.u_nd; 71537741Smckusick register struct vnode *vp, *xp; 71637741Smckusick int error; 7176254Sroot 71816694Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW; 71916694Smckusick ndp->ni_segflg = UIO_USERSPACE; 72016694Smckusick ndp->ni_dirp = uap->target; 72137741Smckusick if (error = namei(ndp)) 72237741Smckusick RETURN (error); 72337741Smckusick vp = ndp->ni_vp; 72437741Smckusick if (vp->v_type == VDIR && 72542441Smckusick (error = suser(ndp->ni_cred, &u.u_acflag))) 72637741Smckusick goto out1; 72737741Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 72816694Smckusick ndp->ni_dirp = (caddr_t)uap->linkname; 72937741Smckusick if (error = namei(ndp)) 73037741Smckusick goto out1; 73137741Smckusick xp = ndp->ni_vp; 7326254Sroot if (xp != NULL) { 73337741Smckusick error = EEXIST; 7346254Sroot goto out; 7356254Sroot } 73637741Smckusick xp = ndp->ni_dvp; 73737741Smckusick if (vp->v_mount != xp->v_mount) 73837741Smckusick error = EXDEV; 7396254Sroot out: 74042465Smckusick if (!error) { 74142465Smckusick error = VOP_LINK(vp, ndp); 74242465Smckusick } else { 74337741Smckusick VOP_ABORTOP(ndp); 74443344Smckusick if (ndp->ni_dvp == ndp->ni_vp) 74543344Smckusick vrele(ndp->ni_dvp); 74643344Smckusick else 74743344Smckusick vput(ndp->ni_dvp); 74842465Smckusick if (ndp->ni_vp) 74942465Smckusick vrele(ndp->ni_vp); 75042465Smckusick } 75137741Smckusick out1: 75237741Smckusick vrele(vp); 75337741Smckusick RETURN (error); 7546254Sroot } 7556254Sroot 7566254Sroot /* 7576254Sroot * symlink -- make a symbolic link 7586254Sroot */ 75942441Smckusick /* ARGSUSED */ 76042441Smckusick symlink(p, uap, retval) 76142441Smckusick register struct proc *p; 76242441Smckusick register struct args { 7636254Sroot char *target; 7646254Sroot char *linkname; 76542441Smckusick } *uap; 76642441Smckusick int *retval; 76742441Smckusick { 76842441Smckusick register struct nameidata *ndp = &u.u_nd; 76937741Smckusick struct vattr vattr; 77037741Smckusick char *target; 77137741Smckusick int error; 7726254Sroot 77316694Smckusick ndp->ni_segflg = UIO_USERSPACE; 77416694Smckusick ndp->ni_dirp = uap->linkname; 77537741Smckusick MALLOC(target, char *, MAXPATHLEN, M_NAMEI, M_WAITOK); 77637741Smckusick if (error = copyinstr(uap->target, target, MAXPATHLEN, (u_int *)0)) 77742465Smckusick goto out; 77837741Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 77937741Smckusick if (error = namei(ndp)) 78042465Smckusick goto out; 78142465Smckusick if (ndp->ni_vp) { 78242465Smckusick VOP_ABORTOP(ndp); 78343344Smckusick if (ndp->ni_dvp == ndp->ni_vp) 78443344Smckusick vrele(ndp->ni_dvp); 78543344Smckusick else 78643344Smckusick vput(ndp->ni_dvp); 78742465Smckusick vrele(ndp->ni_vp); 78837741Smckusick error = EEXIST; 78937741Smckusick goto out; 7906254Sroot } 79141362Smckusick VATTR_NULL(&vattr); 79242441Smckusick vattr.va_mode = 0777 &~ u.u_cmask; 79342465Smckusick error = VOP_SYMLINK(ndp, &vattr, target); 79437741Smckusick out: 79537741Smckusick FREE(target, M_NAMEI); 79637741Smckusick RETURN (error); 7976254Sroot } 7986254Sroot 7996254Sroot /* 8006254Sroot * Unlink system call. 8016254Sroot * Hard to avoid races here, especially 8026254Sroot * in unlinking directories. 8036254Sroot */ 80442441Smckusick /* ARGSUSED */ 80542441Smckusick unlink(p, uap, retval) 80642441Smckusick register struct proc *p; 80742441Smckusick struct args { 80842441Smckusick char *fname; 80942441Smckusick } *uap; 81042441Smckusick int *retval; 8116254Sroot { 81242441Smckusick register struct nameidata *ndp = &u.u_nd; 81337741Smckusick register struct vnode *vp; 81437741Smckusick int error; 8156254Sroot 81637741Smckusick ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF; 81716694Smckusick ndp->ni_segflg = UIO_USERSPACE; 81816694Smckusick ndp->ni_dirp = uap->fname; 81937741Smckusick if (error = namei(ndp)) 82037741Smckusick RETURN (error); 82137741Smckusick vp = ndp->ni_vp; 82237741Smckusick if (vp->v_type == VDIR && 82342441Smckusick (error = suser(ndp->ni_cred, &u.u_acflag))) 8246254Sroot goto out; 8256254Sroot /* 8266254Sroot * Don't unlink a mounted file. 8276254Sroot */ 82837741Smckusick if (vp->v_flag & VROOT) { 82937741Smckusick error = EBUSY; 8306254Sroot goto out; 8316254Sroot } 832*45738Smckusick (void) vnode_pager_uncache(vp); 8336254Sroot out: 83442465Smckusick if (!error) { 83542465Smckusick error = VOP_REMOVE(ndp); 83642465Smckusick } else { 83737741Smckusick VOP_ABORTOP(ndp); 83843344Smckusick if (ndp->ni_dvp == vp) 83943344Smckusick vrele(ndp->ni_dvp); 84043344Smckusick else 84143344Smckusick vput(ndp->ni_dvp); 84242465Smckusick vput(vp); 84342465Smckusick } 84437741Smckusick RETURN (error); 8456254Sroot } 8466254Sroot 8476254Sroot /* 8486254Sroot * Seek system call 8496254Sroot */ 85042441Smckusick lseek(p, uap, retval) 85142441Smckusick register struct proc *p; 85242441Smckusick register struct args { 85337741Smckusick int fdes; 8546254Sroot off_t off; 8556254Sroot int sbase; 85642441Smckusick } *uap; 85742441Smckusick off_t *retval; 85842441Smckusick { 85942441Smckusick struct ucred *cred = u.u_nd.ni_cred; 86042441Smckusick register struct file *fp; 86137741Smckusick struct vattr vattr; 86237741Smckusick int error; 8636254Sroot 86437741Smckusick if ((unsigned)uap->fdes >= NOFILE || 86542441Smckusick (fp = u.u_ofile[uap->fdes]) == NULL) 86637741Smckusick RETURN (EBADF); 86737741Smckusick if (fp->f_type != DTYPE_VNODE) 86837741Smckusick RETURN (ESPIPE); 86913878Ssam switch (uap->sbase) { 87013878Ssam 87113878Ssam case L_INCR: 87213878Ssam fp->f_offset += uap->off; 87313878Ssam break; 87413878Ssam 87513878Ssam case L_XTND: 87637741Smckusick if (error = VOP_GETATTR((struct vnode *)fp->f_data, 87742441Smckusick &vattr, cred)) 87837741Smckusick RETURN (error); 87937741Smckusick fp->f_offset = uap->off + vattr.va_size; 88013878Ssam break; 88113878Ssam 88213878Ssam case L_SET: 88313878Ssam fp->f_offset = uap->off; 88413878Ssam break; 88513878Ssam 88613878Ssam default: 88737741Smckusick RETURN (EINVAL); 88813878Ssam } 88942441Smckusick *retval = fp->f_offset; 89037741Smckusick RETURN (0); 8916254Sroot } 8926254Sroot 8936254Sroot /* 8946254Sroot * Access system call 8956254Sroot */ 89642441Smckusick /* ARGSUSED */ 89742441Smckusick saccess(p, uap, retval) 89842441Smckusick register struct proc *p; 89942441Smckusick register struct args { 9006254Sroot char *fname; 9016254Sroot int fmode; 90242441Smckusick } *uap; 90342441Smckusick int *retval; 90442441Smckusick { 90542441Smckusick register struct nameidata *ndp = &u.u_nd; 90642441Smckusick register struct ucred *cred = ndp->ni_cred; 90737741Smckusick register struct vnode *vp; 90837741Smckusick int error, mode, svuid, svgid; 9096254Sroot 91042441Smckusick svuid = cred->cr_uid; 91142441Smckusick svgid = cred->cr_groups[0]; 91242441Smckusick cred->cr_uid = p->p_ruid; 91342441Smckusick cred->cr_groups[0] = p->p_rgid; 91437741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 91516694Smckusick ndp->ni_segflg = UIO_USERSPACE; 91616694Smckusick ndp->ni_dirp = uap->fname; 91737741Smckusick if (error = namei(ndp)) 91837741Smckusick goto out1; 91937741Smckusick vp = ndp->ni_vp; 92037741Smckusick /* 92137741Smckusick * fmode == 0 means only check for exist 92237741Smckusick */ 92337741Smckusick if (uap->fmode) { 92437741Smckusick mode = 0; 92537741Smckusick if (uap->fmode & R_OK) 92637741Smckusick mode |= VREAD; 92737741Smckusick if (uap->fmode & W_OK) 92837741Smckusick mode |= VWRITE; 92937741Smckusick if (uap->fmode & X_OK) 93037741Smckusick mode |= VEXEC; 93139543Smckusick if ((mode & VWRITE) == 0 || (error = vn_writechk(vp)) == 0) 93238399Smckusick error = VOP_ACCESS(vp, mode, ndp->ni_cred); 9336254Sroot } 93437741Smckusick vput(vp); 93537741Smckusick out1: 93642441Smckusick cred->cr_uid = svuid; 93742441Smckusick cred->cr_groups[0] = svgid; 93837741Smckusick RETURN (error); 9396254Sroot } 9406254Sroot 9416254Sroot /* 9426574Smckusic * Stat system call. This version follows links. 94337Sbill */ 94442441Smckusick /* ARGSUSED */ 94542441Smckusick stat(p, uap, retval) 94642441Smckusick register struct proc *p; 94742441Smckusick register struct args { 94842441Smckusick char *fname; 94942441Smckusick struct stat *ub; 95042441Smckusick } *uap; 95142441Smckusick int *retval; 95237Sbill { 95342441Smckusick register struct nameidata *ndp = &u.u_nd; 95442441Smckusick struct stat sb; 95542441Smckusick int error; 95637Sbill 95742441Smckusick ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW; 95842441Smckusick ndp->ni_segflg = UIO_USERSPACE; 95942441Smckusick ndp->ni_dirp = uap->fname; 96042441Smckusick if (error = namei(ndp)) 96142441Smckusick RETURN (error); 96242441Smckusick error = vn_stat(ndp->ni_vp, &sb); 96342441Smckusick vput(ndp->ni_vp); 96442441Smckusick if (error) 96542441Smckusick RETURN (error); 96642441Smckusick error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb)); 96742441Smckusick RETURN (error); 96837Sbill } 96937Sbill 97037Sbill /* 9716574Smckusic * Lstat system call. This version does not follow links. 9725992Swnj */ 97342441Smckusick /* ARGSUSED */ 97442441Smckusick lstat(p, uap, retval) 97542441Smckusick register struct proc *p; 97642441Smckusick register struct args { 9775992Swnj char *fname; 97812756Ssam struct stat *ub; 97942441Smckusick } *uap; 98042441Smckusick int *retval; 98142441Smckusick { 98242441Smckusick register struct nameidata *ndp = &u.u_nd; 98312756Ssam struct stat sb; 98437741Smckusick int error; 9855992Swnj 98642441Smckusick ndp->ni_nameiop = LOOKUP | LOCKLEAF | NOFOLLOW; 98716694Smckusick ndp->ni_segflg = UIO_USERSPACE; 98816694Smckusick ndp->ni_dirp = uap->fname; 98937741Smckusick if (error = namei(ndp)) 99037741Smckusick RETURN (error); 99137741Smckusick error = vn_stat(ndp->ni_vp, &sb); 99237741Smckusick vput(ndp->ni_vp); 99337741Smckusick if (error) 99437741Smckusick RETURN (error); 99537741Smckusick error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb)); 99637741Smckusick RETURN (error); 9975992Swnj } 9985992Swnj 9995992Swnj /* 10005992Swnj * Return target name of a symbolic link 100137Sbill */ 100242441Smckusick /* ARGSUSED */ 100342441Smckusick readlink(p, uap, retval) 100442441Smckusick register struct proc *p; 100542441Smckusick register struct args { 10065992Swnj char *name; 10075992Swnj char *buf; 10085992Swnj int count; 100942441Smckusick } *uap; 101042441Smckusick int *retval; 101142441Smckusick { 101242441Smckusick register struct nameidata *ndp = &u.u_nd; 101337741Smckusick register struct vnode *vp; 101437741Smckusick struct iovec aiov; 101537741Smckusick struct uio auio; 101637741Smckusick int error; 10175992Swnj 101837741Smckusick ndp->ni_nameiop = LOOKUP | LOCKLEAF; 101916694Smckusick ndp->ni_segflg = UIO_USERSPACE; 102016694Smckusick ndp->ni_dirp = uap->name; 102137741Smckusick if (error = namei(ndp)) 102237741Smckusick RETURN (error); 102337741Smckusick vp = ndp->ni_vp; 102437741Smckusick if (vp->v_type != VLNK) { 102537741Smckusick error = EINVAL; 10265992Swnj goto out; 10275992Swnj } 102837741Smckusick aiov.iov_base = uap->buf; 102937741Smckusick aiov.iov_len = uap->count; 103037741Smckusick auio.uio_iov = &aiov; 103137741Smckusick auio.uio_iovcnt = 1; 103237741Smckusick auio.uio_offset = 0; 103337741Smckusick auio.uio_rw = UIO_READ; 103437741Smckusick auio.uio_segflg = UIO_USERSPACE; 103537741Smckusick auio.uio_resid = uap->count; 103637741Smckusick error = VOP_READLINK(vp, &auio, ndp->ni_cred); 10375992Swnj out: 103837741Smckusick vput(vp); 103942441Smckusick *retval = uap->count - auio.uio_resid; 104037741Smckusick RETURN (error); 10415992Swnj } 10425992Swnj 10439167Ssam /* 104438259Smckusick * Change flags of a file given path name. 104538259Smckusick */ 104642441Smckusick /* ARGSUSED */ 104742441Smckusick chflags(p, uap, retval) 104842441Smckusick register struct proc *p; 104942441Smckusick register struct args { 105038259Smckusick char *fname; 105138259Smckusick int flags; 105242441Smckusick } *uap; 105342441Smckusick int *retval; 105442441Smckusick { 105542441Smckusick register struct nameidata *ndp = &u.u_nd; 105638259Smckusick register struct vnode *vp; 105738259Smckusick struct vattr vattr; 105838259Smckusick int error; 105938259Smckusick 106038259Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 106138259Smckusick ndp->ni_segflg = UIO_USERSPACE; 106238259Smckusick ndp->ni_dirp = uap->fname; 106341362Smckusick VATTR_NULL(&vattr); 106438259Smckusick vattr.va_flags = uap->flags; 106538259Smckusick if (error = namei(ndp)) 106638259Smckusick RETURN (error); 106738259Smckusick vp = ndp->ni_vp; 106841400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 106938259Smckusick error = EROFS; 107038259Smckusick goto out; 107138259Smckusick } 107238259Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 107338259Smckusick out: 107438259Smckusick vput(vp); 107538259Smckusick RETURN (error); 107638259Smckusick } 107738259Smckusick 107838259Smckusick /* 107938259Smckusick * Change flags of a file given a file descriptor. 108038259Smckusick */ 108142441Smckusick /* ARGSUSED */ 108242441Smckusick fchflags(p, uap, retval) 108342441Smckusick register struct proc *p; 108442441Smckusick register struct args { 108538259Smckusick int fd; 108638259Smckusick int flags; 108742441Smckusick } *uap; 108842441Smckusick int *retval; 108942441Smckusick { 109038259Smckusick struct vattr vattr; 109138259Smckusick struct vnode *vp; 109238259Smckusick struct file *fp; 109338259Smckusick int error; 109438259Smckusick 109542441Smckusick if (error = getvnode(u.u_ofile, uap->fd, &fp)) 109638259Smckusick RETURN (error); 109741362Smckusick VATTR_NULL(&vattr); 109838259Smckusick vattr.va_flags = uap->flags; 109938259Smckusick vp = (struct vnode *)fp->f_data; 110038259Smckusick VOP_LOCK(vp); 110141400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 110238259Smckusick error = EROFS; 110338259Smckusick goto out; 110438259Smckusick } 110538259Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred); 110638259Smckusick out: 110738259Smckusick VOP_UNLOCK(vp); 110838259Smckusick RETURN (error); 110938259Smckusick } 111038259Smckusick 111138259Smckusick /* 11129167Ssam * Change mode of a file given path name. 11139167Ssam */ 111442441Smckusick /* ARGSUSED */ 111542441Smckusick chmod(p, uap, retval) 111642441Smckusick register struct proc *p; 111742441Smckusick register struct args { 11186254Sroot char *fname; 11196254Sroot int fmode; 112042441Smckusick } *uap; 112142441Smckusick int *retval; 112242441Smckusick { 112342441Smckusick register struct nameidata *ndp = &u.u_nd; 112437741Smckusick register struct vnode *vp; 112537741Smckusick struct vattr vattr; 112637741Smckusick int error; 11275992Swnj 112837741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 112937741Smckusick ndp->ni_segflg = UIO_USERSPACE; 113037741Smckusick ndp->ni_dirp = uap->fname; 113141362Smckusick VATTR_NULL(&vattr); 113237741Smckusick vattr.va_mode = uap->fmode & 07777; 113337741Smckusick if (error = namei(ndp)) 113437741Smckusick RETURN (error); 113537741Smckusick vp = ndp->ni_vp; 113641400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 113737741Smckusick error = EROFS; 113837741Smckusick goto out; 113937741Smckusick } 114037741Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 114137741Smckusick out: 114237741Smckusick vput(vp); 114337741Smckusick RETURN (error); 11447701Ssam } 11457439Sroot 11469167Ssam /* 11479167Ssam * Change mode of a file given a file descriptor. 11489167Ssam */ 114942441Smckusick /* ARGSUSED */ 115042441Smckusick fchmod(p, uap, retval) 115142441Smckusick register struct proc *p; 115242441Smckusick register struct args { 11537701Ssam int fd; 11547701Ssam int fmode; 115542441Smckusick } *uap; 115642441Smckusick int *retval; 115742441Smckusick { 115837741Smckusick struct vattr vattr; 115937741Smckusick struct vnode *vp; 116037741Smckusick struct file *fp; 116137741Smckusick int error; 11627701Ssam 116342441Smckusick if (error = getvnode(u.u_ofile, uap->fd, &fp)) 116437741Smckusick RETURN (error); 116541362Smckusick VATTR_NULL(&vattr); 116637741Smckusick vattr.va_mode = uap->fmode & 07777; 116737741Smckusick vp = (struct vnode *)fp->f_data; 116837741Smckusick VOP_LOCK(vp); 116941400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 117037741Smckusick error = EROFS; 117137741Smckusick goto out; 11727439Sroot } 117337741Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred); 117437741Smckusick out: 117537741Smckusick VOP_UNLOCK(vp); 117637741Smckusick RETURN (error); 11775992Swnj } 11785992Swnj 11799167Ssam /* 11809167Ssam * Set ownership given a path name. 11819167Ssam */ 118242441Smckusick /* ARGSUSED */ 118342441Smckusick chown(p, uap, retval) 118442441Smckusick register struct proc *p; 118542441Smckusick register struct args { 11866254Sroot char *fname; 11876254Sroot int uid; 11886254Sroot int gid; 118942441Smckusick } *uap; 119042441Smckusick int *retval; 119142441Smckusick { 119242441Smckusick register struct nameidata *ndp = &u.u_nd; 119337741Smckusick register struct vnode *vp; 119437741Smckusick struct vattr vattr; 119537741Smckusick int error; 119637Sbill 119737741Smckusick ndp->ni_nameiop = LOOKUP | NOFOLLOW | LOCKLEAF; 119836614Sbostic ndp->ni_segflg = UIO_USERSPACE; 119936614Sbostic ndp->ni_dirp = uap->fname; 120041362Smckusick VATTR_NULL(&vattr); 120137741Smckusick vattr.va_uid = uap->uid; 120237741Smckusick vattr.va_gid = uap->gid; 120337741Smckusick if (error = namei(ndp)) 120437741Smckusick RETURN (error); 120537741Smckusick vp = ndp->ni_vp; 120641400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 120737741Smckusick error = EROFS; 120837741Smckusick goto out; 120937741Smckusick } 121037741Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 121137741Smckusick out: 121237741Smckusick vput(vp); 121337741Smckusick RETURN (error); 12147701Ssam } 12157439Sroot 12169167Ssam /* 12179167Ssam * Set ownership given a file descriptor. 12189167Ssam */ 121942441Smckusick /* ARGSUSED */ 122042441Smckusick fchown(p, uap, retval) 122142441Smckusick register struct proc *p; 122242441Smckusick register struct args { 12237701Ssam int fd; 12247701Ssam int uid; 12257701Ssam int gid; 122642441Smckusick } *uap; 122742441Smckusick int *retval; 122842441Smckusick { 122937741Smckusick struct vattr vattr; 123037741Smckusick struct vnode *vp; 123137741Smckusick struct file *fp; 123237741Smckusick int error; 12337701Ssam 123442441Smckusick if (error = getvnode(u.u_ofile, uap->fd, &fp)) 123537741Smckusick RETURN (error); 123641362Smckusick VATTR_NULL(&vattr); 123737741Smckusick vattr.va_uid = uap->uid; 123837741Smckusick vattr.va_gid = uap->gid; 123937741Smckusick vp = (struct vnode *)fp->f_data; 124037741Smckusick VOP_LOCK(vp); 124141400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 124237741Smckusick error = EROFS; 124337741Smckusick goto out; 124437741Smckusick } 124537741Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred); 124637741Smckusick out: 124737741Smckusick VOP_UNLOCK(vp); 124837741Smckusick RETURN (error); 12497701Ssam } 12507701Ssam 125142441Smckusick /* 125242441Smckusick * Set the access and modification times of a file. 125342441Smckusick */ 125442441Smckusick /* ARGSUSED */ 125542441Smckusick utimes(p, uap, retval) 125642441Smckusick register struct proc *p; 125742441Smckusick register struct args { 125811811Ssam char *fname; 125911811Ssam struct timeval *tptr; 126042441Smckusick } *uap; 126142441Smckusick int *retval; 126242441Smckusick { 126342441Smckusick register struct nameidata *ndp = &u.u_nd; 126437741Smckusick register struct vnode *vp; 126511811Ssam struct timeval tv[2]; 126637741Smckusick struct vattr vattr; 126737741Smckusick int error; 126811811Ssam 126937741Smckusick if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv))) 127037741Smckusick RETURN (error); 127137741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 127237741Smckusick ndp->ni_segflg = UIO_USERSPACE; 127337741Smckusick ndp->ni_dirp = uap->fname; 127441362Smckusick VATTR_NULL(&vattr); 127537741Smckusick vattr.va_atime = tv[0]; 127637741Smckusick vattr.va_mtime = tv[1]; 127737741Smckusick if (error = namei(ndp)) 127837741Smckusick RETURN (error); 127937741Smckusick vp = ndp->ni_vp; 128041400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 128137741Smckusick error = EROFS; 128237741Smckusick goto out; 128321015Smckusick } 128437741Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 128537741Smckusick out: 128637741Smckusick vput(vp); 128737741Smckusick RETURN (error); 128811811Ssam } 128911811Ssam 12909167Ssam /* 12919167Ssam * Truncate a file given its path name. 12929167Ssam */ 129342441Smckusick /* ARGSUSED */ 129442441Smckusick truncate(p, uap, retval) 129542441Smckusick register struct proc *p; 129642441Smckusick register struct args { 12977701Ssam char *fname; 129826473Skarels off_t length; 129942441Smckusick } *uap; 130042441Smckusick int *retval; 130142441Smckusick { 130242441Smckusick register struct nameidata *ndp = &u.u_nd; 130337741Smckusick register struct vnode *vp; 130437741Smckusick struct vattr vattr; 130537741Smckusick int error; 13067701Ssam 130737741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 130816694Smckusick ndp->ni_segflg = UIO_USERSPACE; 130916694Smckusick ndp->ni_dirp = uap->fname; 131041362Smckusick VATTR_NULL(&vattr); 131137741Smckusick vattr.va_size = uap->length; 131237741Smckusick if (error = namei(ndp)) 131337741Smckusick RETURN (error); 131437741Smckusick vp = ndp->ni_vp; 131537741Smckusick if (vp->v_type == VDIR) { 131637741Smckusick error = EISDIR; 131737741Smckusick goto out; 13187701Ssam } 131938399Smckusick if ((error = vn_writechk(vp)) || 132038399Smckusick (error = VOP_ACCESS(vp, VWRITE, ndp->ni_cred))) 132137741Smckusick goto out; 132237741Smckusick error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 132337741Smckusick out: 132437741Smckusick vput(vp); 132537741Smckusick RETURN (error); 13267701Ssam } 13277701Ssam 13289167Ssam /* 13299167Ssam * Truncate a file given a file descriptor. 13309167Ssam */ 133142441Smckusick /* ARGSUSED */ 133242441Smckusick ftruncate(p, uap, retval) 133342441Smckusick register struct proc *p; 133442441Smckusick register struct args { 13357701Ssam int fd; 133626473Skarels off_t length; 133742441Smckusick } *uap; 133842441Smckusick int *retval; 133942441Smckusick { 134037741Smckusick struct vattr vattr; 134137741Smckusick struct vnode *vp; 13427701Ssam struct file *fp; 134337741Smckusick int error; 13447701Ssam 134542441Smckusick if (error = getvnode(u.u_ofile, uap->fd, &fp)) 134637741Smckusick RETURN (error); 134737741Smckusick if ((fp->f_flag & FWRITE) == 0) 134837741Smckusick RETURN (EINVAL); 134941362Smckusick VATTR_NULL(&vattr); 135037741Smckusick vattr.va_size = uap->length; 135137741Smckusick vp = (struct vnode *)fp->f_data; 135237741Smckusick VOP_LOCK(vp); 135337741Smckusick if (vp->v_type == VDIR) { 135437741Smckusick error = EISDIR; 135537741Smckusick goto out; 13567701Ssam } 135738399Smckusick if (error = vn_writechk(vp)) 135837741Smckusick goto out; 135937741Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred); 136037741Smckusick out: 136137741Smckusick VOP_UNLOCK(vp); 136237741Smckusick RETURN (error); 13637701Ssam } 13647701Ssam 13659167Ssam /* 13669167Ssam * Synch an open file. 13679167Ssam */ 136842441Smckusick /* ARGSUSED */ 136942441Smckusick fsync(p, uap, retval) 137042441Smckusick register struct proc *p; 137142441Smckusick struct args { 137242441Smckusick int fd; 137342441Smckusick } *uap; 137442441Smckusick int *retval; 13759167Ssam { 137639592Smckusick register struct vnode *vp; 13779167Ssam struct file *fp; 137837741Smckusick int error; 13799167Ssam 138042441Smckusick if (error = getvnode(u.u_ofile, uap->fd, &fp)) 138137741Smckusick RETURN (error); 138239592Smckusick vp = (struct vnode *)fp->f_data; 138339592Smckusick VOP_LOCK(vp); 138439592Smckusick error = VOP_FSYNC(vp, fp->f_flag, fp->f_cred, MNT_WAIT); 138539592Smckusick VOP_UNLOCK(vp); 138637741Smckusick RETURN (error); 13879167Ssam } 13889167Ssam 13899167Ssam /* 13909167Ssam * Rename system call. 13919167Ssam * 13929167Ssam * Source and destination must either both be directories, or both 13939167Ssam * not be directories. If target is a directory, it must be empty. 13949167Ssam */ 139542441Smckusick /* ARGSUSED */ 139642441Smckusick rename(p, uap, retval) 139742441Smckusick register struct proc *p; 139842441Smckusick register struct args { 13997701Ssam char *from; 14007701Ssam char *to; 140142441Smckusick } *uap; 140242441Smckusick int *retval; 140342441Smckusick { 140437741Smckusick register struct vnode *tvp, *fvp, *tdvp; 140542441Smckusick register struct nameidata *ndp = &u.u_nd; 140637741Smckusick struct nameidata tond; 140737741Smckusick int error; 14087701Ssam 140937741Smckusick ndp->ni_nameiop = DELETE | WANTPARENT; 141016694Smckusick ndp->ni_segflg = UIO_USERSPACE; 141116694Smckusick ndp->ni_dirp = uap->from; 141237741Smckusick if (error = namei(ndp)) 141337741Smckusick RETURN (error); 141437741Smckusick fvp = ndp->ni_vp; 141538266Smckusick nddup(ndp, &tond); 141637741Smckusick tond.ni_nameiop = RENAME | LOCKPARENT | LOCKLEAF | NOCACHE; 141737741Smckusick tond.ni_segflg = UIO_USERSPACE; 141837741Smckusick tond.ni_dirp = uap->to; 141942465Smckusick if (error = namei(&tond)) { 142042465Smckusick VOP_ABORTOP(ndp); 142142465Smckusick vrele(ndp->ni_dvp); 142242465Smckusick vrele(fvp); 142342465Smckusick goto out1; 142442465Smckusick } 142537741Smckusick tdvp = tond.ni_dvp; 142637741Smckusick tvp = tond.ni_vp; 142737741Smckusick if (tvp != NULL) { 142837741Smckusick if (fvp->v_type == VDIR && tvp->v_type != VDIR) { 142939242Sbostic error = ENOTDIR; 143037741Smckusick goto out; 143137741Smckusick } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) { 143239242Sbostic error = EISDIR; 143337741Smckusick goto out; 14349167Ssam } 143545240Smckusick if (fvp->v_mount != tvp->v_mount) { 143645240Smckusick error = EXDEV; 143745240Smckusick goto out; 143845240Smckusick } 14399167Ssam } 144037741Smckusick if (fvp->v_mount != tdvp->v_mount) { 144137741Smckusick error = EXDEV; 14429167Ssam goto out; 144310051Ssam } 144439286Smckusick if (fvp == tdvp) 144537741Smckusick error = EINVAL; 144639286Smckusick /* 144739286Smckusick * If source is the same as the destination, 144839286Smckusick * then there is nothing to do. 144939286Smckusick */ 145039286Smckusick if (fvp == tvp) 145139286Smckusick error = -1; 145237741Smckusick out: 145342465Smckusick if (!error) { 145442465Smckusick error = VOP_RENAME(ndp, &tond); 145542465Smckusick } else { 145637741Smckusick VOP_ABORTOP(&tond); 145743344Smckusick if (tdvp == tvp) 145843344Smckusick vrele(tdvp); 145943344Smckusick else 146043344Smckusick vput(tdvp); 146142465Smckusick if (tvp) 146242465Smckusick vput(tvp); 146337741Smckusick VOP_ABORTOP(ndp); 146442465Smckusick vrele(ndp->ni_dvp); 146542465Smckusick vrele(fvp); 14669167Ssam } 146737741Smckusick out1: 146838266Smckusick ndrele(&tond); 146939286Smckusick if (error == -1) 147039286Smckusick RETURN (0); 147137741Smckusick RETURN (error); 14727701Ssam } 14737701Ssam 14747535Sroot /* 147512756Ssam * Mkdir system call 147612756Ssam */ 147742441Smckusick /* ARGSUSED */ 147842441Smckusick mkdir(p, uap, retval) 147942441Smckusick register struct proc *p; 148042441Smckusick register struct args { 148112756Ssam char *name; 148212756Ssam int dmode; 148342441Smckusick } *uap; 148442441Smckusick int *retval; 148542441Smckusick { 148642441Smckusick register struct nameidata *ndp = &u.u_nd; 148737741Smckusick register struct vnode *vp; 148837741Smckusick struct vattr vattr; 148937741Smckusick int error; 149012756Ssam 149137741Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 149216694Smckusick ndp->ni_segflg = UIO_USERSPACE; 149316694Smckusick ndp->ni_dirp = uap->name; 149437741Smckusick if (error = namei(ndp)) 149537741Smckusick RETURN (error); 149637741Smckusick vp = ndp->ni_vp; 149737741Smckusick if (vp != NULL) { 149837741Smckusick VOP_ABORTOP(ndp); 149943344Smckusick if (ndp->ni_dvp == vp) 150043344Smckusick vrele(ndp->ni_dvp); 150143344Smckusick else 150243344Smckusick vput(ndp->ni_dvp); 150342465Smckusick vrele(vp); 150437741Smckusick RETURN (EEXIST); 150512756Ssam } 150641362Smckusick VATTR_NULL(&vattr); 150737741Smckusick vattr.va_type = VDIR; 150842441Smckusick vattr.va_mode = (uap->dmode & 0777) &~ u.u_cmask; 150937741Smckusick error = VOP_MKDIR(ndp, &vattr); 151038145Smckusick if (!error) 151138145Smckusick vput(ndp->ni_vp); 151237741Smckusick RETURN (error); 151312756Ssam } 151412756Ssam 151512756Ssam /* 151612756Ssam * Rmdir system call. 151712756Ssam */ 151842441Smckusick /* ARGSUSED */ 151942441Smckusick rmdir(p, uap, retval) 152042441Smckusick register struct proc *p; 152142441Smckusick struct args { 152242441Smckusick char *name; 152342441Smckusick } *uap; 152442441Smckusick int *retval; 152512756Ssam { 152642441Smckusick register struct nameidata *ndp = &u.u_nd; 152737741Smckusick register struct vnode *vp; 152837741Smckusick int error; 152912756Ssam 153037741Smckusick ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF; 153116694Smckusick ndp->ni_segflg = UIO_USERSPACE; 153216694Smckusick ndp->ni_dirp = uap->name; 153337741Smckusick if (error = namei(ndp)) 153437741Smckusick RETURN (error); 153537741Smckusick vp = ndp->ni_vp; 153637741Smckusick if (vp->v_type != VDIR) { 153737741Smckusick error = ENOTDIR; 153812756Ssam goto out; 153912756Ssam } 154012756Ssam /* 154137741Smckusick * No rmdir "." please. 154212756Ssam */ 154337741Smckusick if (ndp->ni_dvp == vp) { 154437741Smckusick error = EINVAL; 154512756Ssam goto out; 154612756Ssam } 154712756Ssam /* 154837741Smckusick * Don't unlink a mounted file. 154912756Ssam */ 155037741Smckusick if (vp->v_flag & VROOT) 155137741Smckusick error = EBUSY; 155212756Ssam out: 155342465Smckusick if (!error) { 155442465Smckusick error = VOP_RMDIR(ndp); 155542465Smckusick } else { 155637741Smckusick VOP_ABORTOP(ndp); 155743344Smckusick if (ndp->ni_dvp == vp) 155843344Smckusick vrele(ndp->ni_dvp); 155943344Smckusick else 156043344Smckusick vput(ndp->ni_dvp); 156142465Smckusick vput(vp); 156242465Smckusick } 156337741Smckusick RETURN (error); 156412756Ssam } 156512756Ssam 156637741Smckusick /* 156737741Smckusick * Read a block of directory entries in a file system independent format 156837741Smckusick */ 156942441Smckusick getdirentries(p, uap, retval) 157042441Smckusick register struct proc *p; 157142441Smckusick register struct args { 157237741Smckusick int fd; 157337741Smckusick char *buf; 157437741Smckusick unsigned count; 157537741Smckusick long *basep; 157642441Smckusick } *uap; 157742441Smckusick int *retval; 157842441Smckusick { 157939592Smckusick register struct vnode *vp; 158016540Ssam struct file *fp; 158137741Smckusick struct uio auio; 158237741Smckusick struct iovec aiov; 158338129Smckusick off_t off; 158440321Smckusick int error, eofflag; 158512756Ssam 158642441Smckusick if (error = getvnode(u.u_ofile, uap->fd, &fp)) 158737741Smckusick RETURN (error); 158837741Smckusick if ((fp->f_flag & FREAD) == 0) 158937741Smckusick RETURN (EBADF); 159039592Smckusick vp = (struct vnode *)fp->f_data; 159139592Smckusick if (vp->v_type != VDIR) 159239592Smckusick RETURN (EINVAL); 159337741Smckusick aiov.iov_base = uap->buf; 159437741Smckusick aiov.iov_len = uap->count; 159537741Smckusick auio.uio_iov = &aiov; 159637741Smckusick auio.uio_iovcnt = 1; 159737741Smckusick auio.uio_rw = UIO_READ; 159837741Smckusick auio.uio_segflg = UIO_USERSPACE; 159937741Smckusick auio.uio_resid = uap->count; 160039592Smckusick VOP_LOCK(vp); 160139592Smckusick auio.uio_offset = off = fp->f_offset; 160240321Smckusick error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag); 160339592Smckusick fp->f_offset = auio.uio_offset; 160439592Smckusick VOP_UNLOCK(vp); 160539592Smckusick if (error) 160637741Smckusick RETURN (error); 160739592Smckusick error = copyout((caddr_t)&off, (caddr_t)uap->basep, sizeof(long)); 160842441Smckusick *retval = uap->count - auio.uio_resid; 160937741Smckusick RETURN (error); 161012756Ssam } 161112756Ssam 161212756Ssam /* 161312756Ssam * mode mask for creation of files 161412756Ssam */ 161542441Smckusick mode_t 161642441Smckusick umask(p, uap, retval) 161742441Smckusick register struct proc *p; 161842441Smckusick struct args { 161942441Smckusick int mask; 162042441Smckusick } *uap; 162142441Smckusick int *retval; 162212756Ssam { 162312756Ssam 162442441Smckusick *retval = u.u_cmask; 162542441Smckusick u.u_cmask = uap->mask & 07777; 162637741Smckusick RETURN (0); 162712756Ssam } 162837741Smckusick 162939566Smarc /* 163039566Smarc * Void all references to file by ripping underlying filesystem 163139566Smarc * away from vnode. 163239566Smarc */ 163342441Smckusick /* ARGSUSED */ 163442441Smckusick revoke(p, uap, retval) 163542441Smckusick register struct proc *p; 163642441Smckusick register struct args { 163739566Smarc char *fname; 163842441Smckusick } *uap; 163942441Smckusick int *retval; 164042441Smckusick { 164142441Smckusick register struct nameidata *ndp = &u.u_nd; 164239566Smarc register struct vnode *vp; 164339566Smarc struct vattr vattr; 164439566Smarc int error; 164539566Smarc 164639566Smarc ndp->ni_nameiop = LOOKUP | FOLLOW; 164739566Smarc ndp->ni_segflg = UIO_USERSPACE; 164839566Smarc ndp->ni_dirp = uap->fname; 164939566Smarc if (error = namei(ndp)) 165039566Smarc RETURN (error); 165139566Smarc vp = ndp->ni_vp; 165239566Smarc if (vp->v_type != VCHR && vp->v_type != VBLK) { 165339566Smarc error = EINVAL; 165439566Smarc goto out; 165539566Smarc } 165642441Smckusick if (error = VOP_GETATTR(vp, &vattr, ndp->ni_cred)) 165739566Smarc goto out; 165842955Smckusick if (ndp->ni_cred->cr_uid != vattr.va_uid && 165942441Smckusick (error = suser(ndp->ni_cred, &u.u_acflag))) 166039566Smarc goto out; 166139805Smckusick if (vp->v_usecount > 1 || (vp->v_flag & VALIASED)) 166239632Smckusick vgoneall(vp); 166339566Smarc out: 166439566Smarc vrele(vp); 166539566Smarc RETURN (error); 166639566Smarc } 166739566Smarc 166838408Smckusick getvnode(ofile, fdes, fpp) 166938408Smckusick struct file *ofile[]; 167037741Smckusick struct file **fpp; 167137741Smckusick int fdes; 167237741Smckusick { 167337741Smckusick struct file *fp; 167437741Smckusick 167538408Smckusick if ((unsigned)fdes >= NOFILE || (fp = ofile[fdes]) == NULL) 167637741Smckusick return (EBADF); 167737741Smckusick if (fp->f_type != DTYPE_VNODE) 167837741Smckusick return (EINVAL); 167937741Smckusick *fpp = fp; 168037741Smckusick return (0); 168137741Smckusick } 1682