123405Smckusick /* 237741Smckusick * Copyright (c) 1989 The Regents of the University of California. 337741Smckusick * All rights reserved. 423405Smckusick * 544459Sbostic * %sccs.include.redist.c% 637741Smckusick * 7*53468Smckusick * @(#)vfs_syscalls.c 7.81 (Berkeley) 05/13/92 823405Smckusick */ 937Sbill 1017101Sbloom #include "param.h" 1117101Sbloom #include "systm.h" 1247540Skarels #include "namei.h" 1345914Smckusick #include "filedesc.h" 1417101Sbloom #include "kernel.h" 1517101Sbloom #include "file.h" 1617101Sbloom #include "stat.h" 1737741Smckusick #include "vnode.h" 1837741Smckusick #include "mount.h" 1917101Sbloom #include "proc.h" 2017101Sbloom #include "uio.h" 2137741Smckusick #include "malloc.h" 22*53468Smckusick #include <vm/vm.h> 2337Sbill 2437741Smckusick /* 2537741Smckusick * Virtual File System System Calls 2637741Smckusick */ 2712756Ssam 289167Ssam /* 2949365Smckusick * Mount system call. 309167Ssam */ 3142441Smckusick /* ARGSUSED */ 3242441Smckusick mount(p, uap, retval) 3345914Smckusick 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 { 4239335Smckusick register struct vnode *vp; 4339335Smckusick register struct mount *mp; 4440111Smckusick int error, flag; 4547540Skarels struct nameidata nd; 466254Sroot 4737741Smckusick /* 4837741Smckusick * Must be super user 4937741Smckusick */ 5047540Skarels if (error = suser(p->p_ucred, &p->p_acflag)) 5147540Skarels return (error); 5237741Smckusick /* 5337741Smckusick * Get vnode to be covered 5437741Smckusick */ 5552322Smckusick NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->dir, p); 5652322Smckusick if (error = namei(&nd)) 5747540Skarels return (error); 5852322Smckusick vp = nd.ni_vp; 5941400Smckusick if (uap->flags & MNT_UPDATE) { 6039335Smckusick if ((vp->v_flag & VROOT) == 0) { 6139335Smckusick vput(vp); 6247540Skarels return (EINVAL); 6339335Smckusick } 6439335Smckusick mp = vp->v_mount; 6539335Smckusick /* 6639335Smckusick * We allow going from read-only to read-write, 6739335Smckusick * but not from read-write to read-only. 6839335Smckusick */ 6941400Smckusick if ((mp->mnt_flag & MNT_RDONLY) == 0 && 7041400Smckusick (uap->flags & MNT_RDONLY) != 0) { 7139335Smckusick vput(vp); 7247540Skarels return (EOPNOTSUPP); /* Needs translation */ 7339335Smckusick } 7441400Smckusick flag = mp->mnt_flag; 7541400Smckusick mp->mnt_flag |= MNT_UPDATE; 7639335Smckusick VOP_UNLOCK(vp); 7739335Smckusick goto update; 7839335Smckusick } 7939665Smckusick vinvalbuf(vp, 1); 8039805Smckusick if (vp->v_usecount != 1) { 8137741Smckusick vput(vp); 8247540Skarels return (EBUSY); 8337741Smckusick } 8437741Smckusick if (vp->v_type != VDIR) { 8537741Smckusick vput(vp); 8647540Skarels return (ENOTDIR); 8737741Smckusick } 8839741Smckusick if ((unsigned long)uap->type > MOUNT_MAXTYPE || 8937741Smckusick vfssw[uap->type] == (struct vfsops *)0) { 9037741Smckusick vput(vp); 9147540Skarels return (ENODEV); 9237741Smckusick } 9337741Smckusick 9437741Smckusick /* 9539335Smckusick * Allocate and initialize the file system. 9637741Smckusick */ 9737741Smckusick mp = (struct mount *)malloc((u_long)sizeof(struct mount), 9837741Smckusick M_MOUNT, M_WAITOK); 9941400Smckusick mp->mnt_op = vfssw[uap->type]; 10041400Smckusick mp->mnt_flag = 0; 10141400Smckusick mp->mnt_mounth = NULLVP; 10239335Smckusick if (error = vfs_lock(mp)) { 10339335Smckusick free((caddr_t)mp, M_MOUNT); 10439335Smckusick vput(vp); 10547540Skarels return (error); 10639335Smckusick } 10739335Smckusick if (vp->v_mountedhere != (struct mount *)0) { 10839335Smckusick vfs_unlock(mp); 10939335Smckusick free((caddr_t)mp, M_MOUNT); 11039335Smckusick vput(vp); 11147540Skarels return (EBUSY); 11239335Smckusick } 11339335Smckusick vp->v_mountedhere = mp; 11441400Smckusick mp->mnt_vnodecovered = vp; 11539335Smckusick update: 11639335Smckusick /* 11739335Smckusick * Set the mount level flags. 11839335Smckusick */ 11941400Smckusick if (uap->flags & MNT_RDONLY) 12041400Smckusick mp->mnt_flag |= MNT_RDONLY; 12139335Smckusick else 12241400Smckusick mp->mnt_flag &= ~MNT_RDONLY; 12341400Smckusick if (uap->flags & MNT_NOSUID) 12441400Smckusick mp->mnt_flag |= MNT_NOSUID; 12539335Smckusick else 12641400Smckusick mp->mnt_flag &= ~MNT_NOSUID; 12741400Smckusick if (uap->flags & MNT_NOEXEC) 12841400Smckusick mp->mnt_flag |= MNT_NOEXEC; 12939335Smckusick else 13041400Smckusick mp->mnt_flag &= ~MNT_NOEXEC; 13141400Smckusick if (uap->flags & MNT_NODEV) 13241400Smckusick mp->mnt_flag |= MNT_NODEV; 13339335Smckusick else 13441400Smckusick mp->mnt_flag &= ~MNT_NODEV; 13541400Smckusick if (uap->flags & MNT_SYNCHRONOUS) 13641400Smckusick mp->mnt_flag |= MNT_SYNCHRONOUS; 13739335Smckusick else 13841400Smckusick mp->mnt_flag &= ~MNT_SYNCHRONOUS; 13939335Smckusick /* 14039335Smckusick * Mount the filesystem. 14139335Smckusick */ 14252322Smckusick error = VFS_MOUNT(mp, uap->dir, uap->data, &nd, p); 14341400Smckusick if (mp->mnt_flag & MNT_UPDATE) { 14441400Smckusick mp->mnt_flag &= ~MNT_UPDATE; 14539335Smckusick vrele(vp); 14640111Smckusick if (error) 14741400Smckusick mp->mnt_flag = flag; 14847540Skarels return (error); 14939335Smckusick } 15040110Smckusick /* 15140110Smckusick * Put the new filesystem on the mount list after root. 15240110Smckusick */ 15341400Smckusick mp->mnt_next = rootfs->mnt_next; 15441400Smckusick mp->mnt_prev = rootfs; 15541400Smckusick rootfs->mnt_next = mp; 15641400Smckusick mp->mnt_next->mnt_prev = mp; 15737741Smckusick cache_purge(vp); 15837741Smckusick if (!error) { 15939335Smckusick VOP_UNLOCK(vp); 16037741Smckusick vfs_unlock(mp); 16148026Smckusick error = VFS_START(mp, 0, p); 16237741Smckusick } else { 16337741Smckusick vfs_remove(mp); 16437741Smckusick free((caddr_t)mp, M_MOUNT); 16539335Smckusick vput(vp); 16637741Smckusick } 16747540Skarels return (error); 1686254Sroot } 1696254Sroot 1709167Ssam /* 17137741Smckusick * Unmount system call. 17237741Smckusick * 17337741Smckusick * Note: unmount takes a path to the vnode mounted on as argument, 17437741Smckusick * not special file (as before). 1759167Ssam */ 17642441Smckusick /* ARGSUSED */ 17742441Smckusick unmount(p, uap, retval) 17845914Smckusick struct proc *p; 17942441Smckusick register struct args { 18037741Smckusick char *pathp; 18137741Smckusick int flags; 18242441Smckusick } *uap; 18342441Smckusick int *retval; 18442441Smckusick { 18537741Smckusick register struct vnode *vp; 18639356Smckusick struct mount *mp; 18737741Smckusick int error; 18847540Skarels struct nameidata nd; 1896254Sroot 19037741Smckusick /* 19137741Smckusick * Must be super user 19237741Smckusick */ 19347540Skarels if (error = suser(p->p_ucred, &p->p_acflag)) 19447540Skarels return (error); 19537741Smckusick 19652322Smckusick NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->pathp, p); 19752322Smckusick if (error = namei(&nd)) 19847540Skarels return (error); 19952322Smckusick vp = nd.ni_vp; 20037741Smckusick /* 20137741Smckusick * Must be the root of the filesystem 20237741Smckusick */ 20337741Smckusick if ((vp->v_flag & VROOT) == 0) { 20437741Smckusick vput(vp); 20547540Skarels return (EINVAL); 20637741Smckusick } 20737741Smckusick mp = vp->v_mount; 20837741Smckusick vput(vp); 20948026Smckusick return (dounmount(mp, uap->flags, p)); 21039356Smckusick } 21139356Smckusick 21239356Smckusick /* 21339356Smckusick * Do an unmount. 21439356Smckusick */ 21548026Smckusick dounmount(mp, flags, p) 21639356Smckusick register struct mount *mp; 21739356Smckusick int flags; 21848026Smckusick struct proc *p; 21939356Smckusick { 22039356Smckusick struct vnode *coveredvp; 22139356Smckusick int error; 22239356Smckusick 22341400Smckusick coveredvp = mp->mnt_vnodecovered; 22441298Smckusick if (vfs_busy(mp)) 22541298Smckusick return (EBUSY); 22641400Smckusick mp->mnt_flag |= MNT_UNMOUNT; 22737741Smckusick if (error = vfs_lock(mp)) 22839356Smckusick return (error); 22937741Smckusick 23045738Smckusick vnode_pager_umount(mp); /* release cached vnodes */ 23137741Smckusick cache_purgevfs(mp); /* remove cache entries for this file sys */ 23241676Smckusick if ((error = VFS_SYNC(mp, MNT_WAIT)) == 0 || (flags & MNT_FORCE)) 23348026Smckusick error = VFS_UNMOUNT(mp, flags, p); 23441400Smckusick mp->mnt_flag &= ~MNT_UNMOUNT; 23541298Smckusick vfs_unbusy(mp); 23637741Smckusick if (error) { 23737741Smckusick vfs_unlock(mp); 23837741Smckusick } else { 23937741Smckusick vrele(coveredvp); 24037741Smckusick vfs_remove(mp); 24152287Smckusick if (mp->mnt_mounth != NULL) 24252287Smckusick panic("unmount: dangling vnode"); 24337741Smckusick free((caddr_t)mp, M_MOUNT); 24437741Smckusick } 24539356Smckusick return (error); 2466254Sroot } 2476254Sroot 2489167Ssam /* 24937741Smckusick * Sync system call. 25037741Smckusick * Sync each mounted filesystem. 2519167Ssam */ 25239491Smckusick /* ARGSUSED */ 25342441Smckusick sync(p, uap, retval) 25445914Smckusick struct proc *p; 25547540Skarels void *uap; 25642441Smckusick int *retval; 2576254Sroot { 25837741Smckusick register struct mount *mp; 25941298Smckusick struct mount *omp; 26037741Smckusick 26137741Smckusick mp = rootfs; 26237741Smckusick do { 26340343Smckusick /* 26440343Smckusick * The lock check below is to avoid races with mount 26540343Smckusick * and unmount. 26640343Smckusick */ 26741400Smckusick if ((mp->mnt_flag & (MNT_MLOCK|MNT_RDONLY|MNT_MPBUSY)) == 0 && 26841298Smckusick !vfs_busy(mp)) { 26937741Smckusick VFS_SYNC(mp, MNT_NOWAIT); 27041298Smckusick omp = mp; 27141400Smckusick mp = mp->mnt_next; 27241298Smckusick vfs_unbusy(omp); 27341298Smckusick } else 27441400Smckusick mp = mp->mnt_next; 27537741Smckusick } while (mp != rootfs); 27647688Skarels return (0); 27737741Smckusick } 27837741Smckusick 27937741Smckusick /* 28049365Smckusick * Operate on filesystem quotas. 28141298Smckusick */ 28242441Smckusick /* ARGSUSED */ 28342441Smckusick quotactl(p, uap, retval) 28445914Smckusick struct proc *p; 28542441Smckusick register struct args { 28641298Smckusick char *path; 28741298Smckusick int cmd; 28841298Smckusick int uid; 28941298Smckusick caddr_t arg; 29042441Smckusick } *uap; 29142441Smckusick int *retval; 29242441Smckusick { 29341298Smckusick register struct mount *mp; 29441298Smckusick int error; 29547540Skarels struct nameidata nd; 29641298Smckusick 29752322Smckusick NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); 29852322Smckusick if (error = namei(&nd)) 29947540Skarels return (error); 30052322Smckusick mp = nd.ni_vp->v_mount; 30152322Smckusick vrele(nd.ni_vp); 30248026Smckusick return (VFS_QUOTACTL(mp, uap->cmd, uap->uid, uap->arg, p)); 30341298Smckusick } 30441298Smckusick 30541298Smckusick /* 30649365Smckusick * Get filesystem statistics. 30737741Smckusick */ 30842441Smckusick /* ARGSUSED */ 30942441Smckusick statfs(p, uap, retval) 31045914Smckusick struct proc *p; 31142441Smckusick register struct args { 31237741Smckusick char *path; 31337741Smckusick struct statfs *buf; 31442441Smckusick } *uap; 31542441Smckusick int *retval; 31642441Smckusick { 31739464Smckusick register struct mount *mp; 31840343Smckusick register struct statfs *sp; 31937741Smckusick int error; 32047540Skarels struct nameidata nd; 32137741Smckusick 32252322Smckusick NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); 32352322Smckusick if (error = namei(&nd)) 32447540Skarels return (error); 32552322Smckusick mp = nd.ni_vp->v_mount; 32641400Smckusick sp = &mp->mnt_stat; 32752322Smckusick vrele(nd.ni_vp); 32848026Smckusick if (error = VFS_STATFS(mp, sp, p)) 32947540Skarels return (error); 33041400Smckusick sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 33147540Skarels return (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp))); 33237741Smckusick } 33337741Smckusick 33442441Smckusick /* 33549365Smckusick * Get filesystem statistics. 33642441Smckusick */ 33742441Smckusick /* ARGSUSED */ 33842441Smckusick fstatfs(p, uap, retval) 33945914Smckusick struct proc *p; 34042441Smckusick register struct args { 34137741Smckusick int fd; 34237741Smckusick struct statfs *buf; 34342441Smckusick } *uap; 34442441Smckusick int *retval; 34542441Smckusick { 34637741Smckusick struct file *fp; 34739464Smckusick struct mount *mp; 34840343Smckusick register struct statfs *sp; 34937741Smckusick int error; 35037741Smckusick 35145914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 35247540Skarels return (error); 35339464Smckusick mp = ((struct vnode *)fp->f_data)->v_mount; 35441400Smckusick sp = &mp->mnt_stat; 35548026Smckusick if (error = VFS_STATFS(mp, sp, p)) 35647540Skarels return (error); 35741400Smckusick sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 35847540Skarels return (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp))); 35937741Smckusick } 36037741Smckusick 36137741Smckusick /* 36249365Smckusick * Get statistics on all filesystems. 36338270Smckusick */ 36442441Smckusick getfsstat(p, uap, retval) 36545914Smckusick struct proc *p; 36642441Smckusick register struct args { 36738270Smckusick struct statfs *buf; 36838270Smckusick long bufsize; 36940343Smckusick int flags; 37042441Smckusick } *uap; 37142441Smckusick int *retval; 37242441Smckusick { 37338270Smckusick register struct mount *mp; 37440343Smckusick register struct statfs *sp; 37539606Smckusick caddr_t sfsp; 37638270Smckusick long count, maxcount, error; 37738270Smckusick 37838270Smckusick maxcount = uap->bufsize / sizeof(struct statfs); 37939606Smckusick sfsp = (caddr_t)uap->buf; 38038270Smckusick mp = rootfs; 38138270Smckusick count = 0; 38238270Smckusick do { 38341400Smckusick if (sfsp && count < maxcount && 38441400Smckusick ((mp->mnt_flag & MNT_MLOCK) == 0)) { 38541400Smckusick sp = &mp->mnt_stat; 38640343Smckusick /* 38740343Smckusick * If MNT_NOWAIT is specified, do not refresh the 38840343Smckusick * fsstat cache. MNT_WAIT overrides MNT_NOWAIT. 38940343Smckusick */ 39040343Smckusick if (((uap->flags & MNT_NOWAIT) == 0 || 39140343Smckusick (uap->flags & MNT_WAIT)) && 39248026Smckusick (error = VFS_STATFS(mp, sp, p))) { 39341400Smckusick mp = mp->mnt_prev; 39439607Smckusick continue; 39539607Smckusick } 39641400Smckusick sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 39740343Smckusick if (error = copyout((caddr_t)sp, sfsp, sizeof(*sp))) 39847540Skarels return (error); 39940343Smckusick sfsp += sizeof(*sp); 40038270Smckusick } 40139606Smckusick count++; 40241400Smckusick mp = mp->mnt_prev; 40338270Smckusick } while (mp != rootfs); 40438270Smckusick if (sfsp && count > maxcount) 40542441Smckusick *retval = maxcount; 40638270Smckusick else 40742441Smckusick *retval = count; 40847540Skarels return (0); 40938270Smckusick } 41038270Smckusick 41138270Smckusick /* 41238259Smckusick * Change current working directory to a given file descriptor. 41338259Smckusick */ 41442441Smckusick /* ARGSUSED */ 41542441Smckusick fchdir(p, uap, retval) 41645914Smckusick struct proc *p; 41742441Smckusick struct args { 41842441Smckusick int fd; 41942441Smckusick } *uap; 42042441Smckusick int *retval; 42138259Smckusick { 42245914Smckusick register struct filedesc *fdp = p->p_fd; 42338259Smckusick register struct vnode *vp; 42438259Smckusick struct file *fp; 42538259Smckusick int error; 42638259Smckusick 42745914Smckusick if (error = getvnode(fdp, uap->fd, &fp)) 42847540Skarels return (error); 42938259Smckusick vp = (struct vnode *)fp->f_data; 43038259Smckusick VOP_LOCK(vp); 43138259Smckusick if (vp->v_type != VDIR) 43238259Smckusick error = ENOTDIR; 43338259Smckusick else 43448026Smckusick error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p); 43538259Smckusick VOP_UNLOCK(vp); 43639860Smckusick if (error) 43747540Skarels return (error); 43839860Smckusick VREF(vp); 43945914Smckusick vrele(fdp->fd_cdir); 44045914Smckusick fdp->fd_cdir = vp; 44147540Skarels return (0); 44238259Smckusick } 44338259Smckusick 44438259Smckusick /* 44537741Smckusick * Change current working directory (``.''). 44637741Smckusick */ 44742441Smckusick /* ARGSUSED */ 44842441Smckusick chdir(p, uap, retval) 44945914Smckusick struct proc *p; 45042441Smckusick struct args { 45142441Smckusick char *fname; 45242441Smckusick } *uap; 45342441Smckusick int *retval; 45437741Smckusick { 45545914Smckusick register struct filedesc *fdp = p->p_fd; 45637741Smckusick int error; 45747540Skarels struct nameidata nd; 4586254Sroot 45952322Smckusick NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 46052781Sralph if (error = chdirec(&nd, p)) 46147540Skarels return (error); 46245914Smckusick vrele(fdp->fd_cdir); 46352322Smckusick fdp->fd_cdir = nd.ni_vp; 46447540Skarels return (0); 46537741Smckusick } 4666254Sroot 46737741Smckusick /* 46837741Smckusick * Change notion of root (``/'') directory. 46937741Smckusick */ 47042441Smckusick /* ARGSUSED */ 47142441Smckusick chroot(p, uap, retval) 47245914Smckusick struct proc *p; 47342441Smckusick struct args { 47442441Smckusick char *fname; 47542441Smckusick } *uap; 47642441Smckusick int *retval; 47737741Smckusick { 47845914Smckusick register struct filedesc *fdp = p->p_fd; 47937741Smckusick int error; 48047540Skarels struct nameidata nd; 48137741Smckusick 48247540Skarels if (error = suser(p->p_ucred, &p->p_acflag)) 48347540Skarels return (error); 48452322Smckusick NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 48552781Sralph if (error = chdirec(&nd, p)) 48647540Skarels return (error); 48745914Smckusick if (fdp->fd_rdir != NULL) 48845914Smckusick vrele(fdp->fd_rdir); 48952322Smckusick fdp->fd_rdir = nd.ni_vp; 49047540Skarels return (0); 4916254Sroot } 4926254Sroot 49337Sbill /* 49437741Smckusick * Common routine for chroot and chdir. 49537741Smckusick */ 49647540Skarels chdirec(ndp, p) 49752322Smckusick register struct nameidata *ndp; 49847540Skarels struct proc *p; 49937741Smckusick { 50037741Smckusick struct vnode *vp; 50137741Smckusick int error; 50237741Smckusick 50352322Smckusick if (error = namei(ndp)) 50437741Smckusick return (error); 50537741Smckusick vp = ndp->ni_vp; 50637741Smckusick if (vp->v_type != VDIR) 50737741Smckusick error = ENOTDIR; 50837741Smckusick else 50948026Smckusick error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p); 51037741Smckusick VOP_UNLOCK(vp); 51137741Smckusick if (error) 51237741Smckusick vrele(vp); 51337741Smckusick return (error); 51437741Smckusick } 51537741Smckusick 51637741Smckusick /* 5176254Sroot * Open system call. 51842441Smckusick * Check permissions, allocate an open file structure, 51942441Smckusick * and call the device open routine if any. 5206254Sroot */ 52142441Smckusick open(p, uap, retval) 52245914Smckusick struct proc *p; 52342441Smckusick register struct args { 5246254Sroot char *fname; 5257701Ssam int mode; 52612756Ssam int crtmode; 52742441Smckusick } *uap; 52842441Smckusick int *retval; 5296254Sroot { 53045914Smckusick register struct filedesc *fdp = p->p_fd; 53142441Smckusick register struct file *fp; 53250111Smckusick register struct vnode *vp; 53337741Smckusick int fmode, cmode; 53437741Smckusick struct file *nfp; 53549945Smckusick int type, indx, error; 53649945Smckusick struct flock lf; 53747540Skarels struct nameidata nd; 53837741Smckusick extern struct fileops vnops; 5396254Sroot 54045914Smckusick if (error = falloc(p, &nfp, &indx)) 54147540Skarels return (error); 54237741Smckusick fp = nfp; 54346553Skarels fmode = FFLAGS(uap->mode); 54445914Smckusick cmode = ((uap->crtmode &~ fdp->fd_cmask) & 07777) &~ S_ISVTX; 54552322Smckusick NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->fname, p); 54645202Smckusick p->p_dupfd = -indx - 1; /* XXX check for fdopen */ 54752322Smckusick if (error = vn_open(&nd, fmode, cmode)) { 54849980Smckusick ffree(fp); 54943405Smckusick if (error == ENODEV && /* XXX from fdopen */ 55045202Smckusick p->p_dupfd >= 0 && 55145914Smckusick (error = dupfdopen(fdp, indx, p->p_dupfd, fmode)) == 0) { 55242441Smckusick *retval = indx; 55347540Skarels return (0); 55442441Smckusick } 55540884Smckusick if (error == ERESTART) 55640884Smckusick error = EINTR; 55747688Skarels fdp->fd_ofiles[indx] = NULL; 55847540Skarels return (error); 55912756Ssam } 56052322Smckusick vp = nd.ni_vp; 56149949Smckusick fp->f_flag = fmode & FMASK; 56249945Smckusick if (fmode & (O_EXLOCK | O_SHLOCK)) { 56349945Smckusick lf.l_whence = SEEK_SET; 56449945Smckusick lf.l_start = 0; 56549945Smckusick lf.l_len = 0; 56649945Smckusick if (fmode & O_EXLOCK) 56749945Smckusick lf.l_type = F_WRLCK; 56849945Smckusick else 56949945Smckusick lf.l_type = F_RDLCK; 57049945Smckusick type = F_FLOCK; 57149945Smckusick if ((fmode & FNONBLOCK) == 0) 57249945Smckusick type |= F_WAIT; 57350111Smckusick if (error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, type)) { 57450111Smckusick VOP_UNLOCK(vp); 57550111Smckusick (void) vn_close(vp, fp->f_flag, fp->f_cred, p); 57649980Smckusick ffree(fp); 57749945Smckusick fdp->fd_ofiles[indx] = NULL; 57849945Smckusick return (error); 57949945Smckusick } 58049949Smckusick fp->f_flag |= FHASLOCK; 58149945Smckusick } 58250111Smckusick VOP_UNLOCK(vp); 58337741Smckusick fp->f_type = DTYPE_VNODE; 58437741Smckusick fp->f_ops = &vnops; 58550111Smckusick fp->f_data = (caddr_t)vp; 58642441Smckusick *retval = indx; 58747540Skarels return (0); 5886254Sroot } 5896254Sroot 59042955Smckusick #ifdef COMPAT_43 5916254Sroot /* 59242441Smckusick * Creat system call. 5936254Sroot */ 59442955Smckusick ocreat(p, uap, retval) 59542441Smckusick struct proc *p; 59642441Smckusick register struct args { 59742441Smckusick char *fname; 59842441Smckusick int fmode; 59942441Smckusick } *uap; 60042441Smckusick int *retval; 6016254Sroot { 60242441Smckusick struct args { 6036254Sroot char *fname; 60442441Smckusick int mode; 60542441Smckusick int crtmode; 60642441Smckusick } openuap; 60742441Smckusick 60842441Smckusick openuap.fname = uap->fname; 60942441Smckusick openuap.crtmode = uap->fmode; 61042441Smckusick openuap.mode = O_WRONLY | O_CREAT | O_TRUNC; 61147540Skarels return (open(p, &openuap, retval)); 61242441Smckusick } 61342955Smckusick #endif /* COMPAT_43 */ 61442441Smckusick 61542441Smckusick /* 61649365Smckusick * Mknod system call. 61742441Smckusick */ 61842441Smckusick /* ARGSUSED */ 61942441Smckusick mknod(p, uap, retval) 62045914Smckusick struct proc *p; 62142441Smckusick register struct args { 62242441Smckusick char *fname; 6236254Sroot int fmode; 6246254Sroot int dev; 62542441Smckusick } *uap; 62642441Smckusick int *retval; 62742441Smckusick { 62837741Smckusick register struct vnode *vp; 62937741Smckusick struct vattr vattr; 63037741Smckusick int error; 63147540Skarels struct nameidata nd; 6326254Sroot 63347540Skarels if (error = suser(p->p_ucred, &p->p_acflag)) 63447540Skarels return (error); 63552322Smckusick NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->fname, p); 63652322Smckusick if (error = namei(&nd)) 63747540Skarels return (error); 63852322Smckusick vp = nd.ni_vp; 63937741Smckusick if (vp != NULL) { 64037741Smckusick error = EEXIST; 64112756Ssam goto out; 6426254Sroot } 64341362Smckusick VATTR_NULL(&vattr); 64440635Smckusick switch (uap->fmode & S_IFMT) { 64512756Ssam 64640635Smckusick case S_IFMT: /* used by badsect to flag bad sectors */ 64737741Smckusick vattr.va_type = VBAD; 64837741Smckusick break; 64940635Smckusick case S_IFCHR: 65037741Smckusick vattr.va_type = VCHR; 65137741Smckusick break; 65240635Smckusick case S_IFBLK: 65337741Smckusick vattr.va_type = VBLK; 65437741Smckusick break; 65537741Smckusick default: 65637741Smckusick error = EINVAL; 65737741Smckusick goto out; 6586254Sroot } 65945914Smckusick vattr.va_mode = (uap->fmode & 07777) &~ p->p_fd->fd_cmask; 66037741Smckusick vattr.va_rdev = uap->dev; 6616254Sroot out: 66242465Smckusick if (!error) { 66352322Smckusick LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 66452322Smckusick error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr); 66542465Smckusick } else { 66652322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 66752322Smckusick if (nd.ni_dvp == vp) 66852322Smckusick vrele(nd.ni_dvp); 66943344Smckusick else 67052322Smckusick vput(nd.ni_dvp); 67142465Smckusick if (vp) 67242465Smckusick vrele(vp); 67342465Smckusick } 67447540Skarels return (error); 6756254Sroot } 6766254Sroot 6776254Sroot /* 67849365Smckusick * Mkfifo system call. 67940285Smckusick */ 68042441Smckusick /* ARGSUSED */ 68142441Smckusick mkfifo(p, uap, retval) 68245914Smckusick struct proc *p; 68342441Smckusick register struct args { 68440285Smckusick char *fname; 68540285Smckusick int fmode; 68642441Smckusick } *uap; 68742441Smckusick int *retval; 68842441Smckusick { 68940285Smckusick struct vattr vattr; 69040285Smckusick int error; 69147540Skarels struct nameidata nd; 69240285Smckusick 69340285Smckusick #ifndef FIFO 69447540Skarels return (EOPNOTSUPP); 69540285Smckusick #else 69652322Smckusick NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->fname, p); 69752322Smckusick if (error = namei(&nd)) 69847540Skarels return (error); 69952322Smckusick if (nd.ni_vp != NULL) { 70052322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 70152322Smckusick if (nd.ni_dvp == nd.ni_vp) 70252322Smckusick vrele(nd.ni_dvp); 70343344Smckusick else 70452322Smckusick vput(nd.ni_dvp); 70552322Smckusick vrele(nd.ni_vp); 70647540Skarels return (EEXIST); 70740285Smckusick } 70845785Sbostic VATTR_NULL(&vattr); 70945785Sbostic vattr.va_type = VFIFO; 71045914Smckusick vattr.va_mode = (uap->fmode & 07777) &~ p->p_fd->fd_cmask; 71152322Smckusick LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 71252322Smckusick return (VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr)); 71340285Smckusick #endif /* FIFO */ 71440285Smckusick } 71540285Smckusick 71640285Smckusick /* 71749365Smckusick * Link system call. 7186254Sroot */ 71942441Smckusick /* ARGSUSED */ 72042441Smckusick link(p, uap, retval) 72145914Smckusick struct proc *p; 72242441Smckusick register struct args { 7236254Sroot char *target; 7246254Sroot char *linkname; 72542441Smckusick } *uap; 72642441Smckusick int *retval; 72742441Smckusick { 72837741Smckusick register struct vnode *vp, *xp; 72937741Smckusick int error; 73047540Skarels struct nameidata nd; 7316254Sroot 73252322Smckusick NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->target, p); 73352322Smckusick if (error = namei(&nd)) 73447540Skarels return (error); 73552322Smckusick vp = nd.ni_vp; 73637741Smckusick if (vp->v_type == VDIR && 73747540Skarels (error = suser(p->p_ucred, &p->p_acflag))) 73837741Smckusick goto out1; 73952322Smckusick nd.ni_cnd.cn_nameiop = CREATE; 74052322Smckusick nd.ni_cnd.cn_flags = LOCKPARENT; 74152322Smckusick nd.ni_dirp = (caddr_t)uap->linkname; 74252322Smckusick if (error = namei(&nd)) 74337741Smckusick goto out1; 74452322Smckusick xp = nd.ni_vp; 7456254Sroot if (xp != NULL) { 74637741Smckusick error = EEXIST; 7476254Sroot goto out; 7486254Sroot } 74952322Smckusick xp = nd.ni_dvp; 75037741Smckusick if (vp->v_mount != xp->v_mount) 75137741Smckusick error = EXDEV; 7526254Sroot out: 75342465Smckusick if (!error) { 75452192Smckusick LEASE_CHECK(xp, p, p->p_ucred, LEASE_WRITE); 75552192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 75652821Smckusick error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd); 75742465Smckusick } else { 75852322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 75952322Smckusick if (nd.ni_dvp == nd.ni_vp) 76052322Smckusick vrele(nd.ni_dvp); 76143344Smckusick else 76252322Smckusick vput(nd.ni_dvp); 76352322Smckusick if (nd.ni_vp) 76452322Smckusick vrele(nd.ni_vp); 76542465Smckusick } 76637741Smckusick out1: 76737741Smckusick vrele(vp); 76847540Skarels return (error); 7696254Sroot } 7706254Sroot 7716254Sroot /* 77249365Smckusick * Make a symbolic link. 7736254Sroot */ 77442441Smckusick /* ARGSUSED */ 77542441Smckusick symlink(p, uap, retval) 77645914Smckusick struct proc *p; 77742441Smckusick register struct args { 7786254Sroot char *target; 7796254Sroot char *linkname; 78042441Smckusick } *uap; 78142441Smckusick int *retval; 78242441Smckusick { 78337741Smckusick struct vattr vattr; 78437741Smckusick char *target; 78537741Smckusick int error; 78647540Skarels struct nameidata nd; 7876254Sroot 78837741Smckusick MALLOC(target, char *, MAXPATHLEN, M_NAMEI, M_WAITOK); 78937741Smckusick if (error = copyinstr(uap->target, target, MAXPATHLEN, (u_int *)0)) 79042465Smckusick goto out; 79152322Smckusick NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->linkname, p); 79252322Smckusick if (error = namei(&nd)) 79342465Smckusick goto out; 79452322Smckusick if (nd.ni_vp) { 79552322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 79652322Smckusick if (nd.ni_dvp == nd.ni_vp) 79752322Smckusick vrele(nd.ni_dvp); 79843344Smckusick else 79952322Smckusick vput(nd.ni_dvp); 80052322Smckusick vrele(nd.ni_vp); 80137741Smckusick error = EEXIST; 80237741Smckusick goto out; 8036254Sroot } 80441362Smckusick VATTR_NULL(&vattr); 80545914Smckusick vattr.va_mode = 0777 &~ p->p_fd->fd_cmask; 80652322Smckusick LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 80752322Smckusick error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr, target); 80837741Smckusick out: 80937741Smckusick FREE(target, M_NAMEI); 81047540Skarels return (error); 8116254Sroot } 8126254Sroot 8136254Sroot /* 81449365Smckusick * Delete a name from the filesystem. 8156254Sroot */ 81642441Smckusick /* ARGSUSED */ 81742441Smckusick unlink(p, uap, retval) 81845914Smckusick struct proc *p; 81942441Smckusick struct args { 82052322Smckusick char *name; 82142441Smckusick } *uap; 82242441Smckusick int *retval; 8236254Sroot { 82437741Smckusick register struct vnode *vp; 82537741Smckusick int error; 82647540Skarels struct nameidata nd; 8276254Sroot 82852322Smckusick NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE, uap->name, p); 82952322Smckusick if (error = namei(&nd)) 83047540Skarels return (error); 83152322Smckusick vp = nd.ni_vp; 83237741Smckusick if (vp->v_type == VDIR && 83347540Skarels (error = suser(p->p_ucred, &p->p_acflag))) 8346254Sroot goto out; 8356254Sroot /* 83649365Smckusick * The root of a mounted filesystem cannot be deleted. 8376254Sroot */ 83837741Smckusick if (vp->v_flag & VROOT) { 83937741Smckusick error = EBUSY; 8406254Sroot goto out; 8416254Sroot } 84245738Smckusick (void) vnode_pager_uncache(vp); 8436254Sroot out: 84442465Smckusick if (!error) { 84552322Smckusick LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 84652192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 84752322Smckusick error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); 84842465Smckusick } else { 84952322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 85052322Smckusick if (nd.ni_dvp == vp) 85152322Smckusick vrele(nd.ni_dvp); 85243344Smckusick else 85352322Smckusick vput(nd.ni_dvp); 85442465Smckusick vput(vp); 85542465Smckusick } 85647540Skarels return (error); 8576254Sroot } 8586254Sroot 859*53468Smckusick #ifdef COMPAT_43 8606254Sroot /* 86149365Smckusick * Seek system call. 8626254Sroot */ 86342441Smckusick lseek(p, uap, retval) 86445914Smckusick struct proc *p; 86542441Smckusick register struct args { 86637741Smckusick int fdes; 867*53468Smckusick long off; 868*53468Smckusick int sbase; 869*53468Smckusick } *uap; 870*53468Smckusick long *retval; 871*53468Smckusick { 872*53468Smckusick struct nargs { 873*53468Smckusick int fdes; 8746254Sroot off_t off; 8756254Sroot int sbase; 876*53468Smckusick } nuap; 877*53468Smckusick quad_t qret; 878*53468Smckusick int error; 879*53468Smckusick 880*53468Smckusick nuap.fdes = uap->fdes; 881*53468Smckusick nuap.off = uap->off; 882*53468Smckusick nuap.sbase = uap->sbase; 883*53468Smckusick error = qseek(p, &nuap, &qret); 884*53468Smckusick *retval = qret; 885*53468Smckusick return (error); 886*53468Smckusick } 887*53468Smckusick #endif /* COMPAT_43 */ 888*53468Smckusick 889*53468Smckusick /* 890*53468Smckusick * Seek system call. 891*53468Smckusick */ 892*53468Smckusick qseek(p, uap, retval) 893*53468Smckusick struct proc *p; 894*53468Smckusick register struct args { 895*53468Smckusick int fdes; 896*53468Smckusick off_t off; 897*53468Smckusick int sbase; 89842441Smckusick } *uap; 89942441Smckusick off_t *retval; 90042441Smckusick { 90147540Skarels struct ucred *cred = p->p_ucred; 90245914Smckusick register struct filedesc *fdp = p->p_fd; 90342441Smckusick register struct file *fp; 90437741Smckusick struct vattr vattr; 90537741Smckusick int error; 9066254Sroot 90747540Skarels if ((unsigned)uap->fdes >= fdp->fd_nfiles || 90847688Skarels (fp = fdp->fd_ofiles[uap->fdes]) == NULL) 90947540Skarels return (EBADF); 91037741Smckusick if (fp->f_type != DTYPE_VNODE) 91147540Skarels return (ESPIPE); 91213878Ssam switch (uap->sbase) { 91313878Ssam 91413878Ssam case L_INCR: 91513878Ssam fp->f_offset += uap->off; 91613878Ssam break; 91713878Ssam 91813878Ssam case L_XTND: 91937741Smckusick if (error = VOP_GETATTR((struct vnode *)fp->f_data, 92048026Smckusick &vattr, cred, p)) 92147540Skarels return (error); 92237741Smckusick fp->f_offset = uap->off + vattr.va_size; 92313878Ssam break; 92413878Ssam 92513878Ssam case L_SET: 92613878Ssam fp->f_offset = uap->off; 92713878Ssam break; 92813878Ssam 92913878Ssam default: 93047540Skarels return (EINVAL); 93113878Ssam } 93242441Smckusick *retval = fp->f_offset; 93347540Skarels return (0); 9346254Sroot } 9356254Sroot 9366254Sroot /* 93749365Smckusick * Check access permissions. 9386254Sroot */ 93942441Smckusick /* ARGSUSED */ 94042441Smckusick saccess(p, uap, retval) 94145914Smckusick struct proc *p; 94242441Smckusick register struct args { 9436254Sroot char *fname; 9446254Sroot int fmode; 94542441Smckusick } *uap; 94642441Smckusick int *retval; 94742441Smckusick { 94847540Skarels register struct ucred *cred = p->p_ucred; 94937741Smckusick register struct vnode *vp; 95037741Smckusick int error, mode, svuid, svgid; 95147540Skarels struct nameidata nd; 9526254Sroot 95342441Smckusick svuid = cred->cr_uid; 95442441Smckusick svgid = cred->cr_groups[0]; 95547540Skarels cred->cr_uid = p->p_cred->p_ruid; 95647540Skarels cred->cr_groups[0] = p->p_cred->p_rgid; 95752322Smckusick NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 95852322Smckusick if (error = namei(&nd)) 95937741Smckusick goto out1; 96052322Smckusick vp = nd.ni_vp; 96137741Smckusick /* 96237741Smckusick * fmode == 0 means only check for exist 96337741Smckusick */ 96437741Smckusick if (uap->fmode) { 96537741Smckusick mode = 0; 96637741Smckusick if (uap->fmode & R_OK) 96737741Smckusick mode |= VREAD; 96837741Smckusick if (uap->fmode & W_OK) 96937741Smckusick mode |= VWRITE; 97037741Smckusick if (uap->fmode & X_OK) 97137741Smckusick mode |= VEXEC; 97239543Smckusick if ((mode & VWRITE) == 0 || (error = vn_writechk(vp)) == 0) 97348026Smckusick error = VOP_ACCESS(vp, mode, cred, p); 9746254Sroot } 97537741Smckusick vput(vp); 97637741Smckusick out1: 97742441Smckusick cred->cr_uid = svuid; 97842441Smckusick cred->cr_groups[0] = svgid; 97947540Skarels return (error); 9806254Sroot } 9816254Sroot 982*53468Smckusick #ifdef COMPAT_43 9836254Sroot /* 98449365Smckusick * Stat system call. 98549365Smckusick * This version follows links. 98637Sbill */ 98742441Smckusick /* ARGSUSED */ 98842441Smckusick stat(p, uap, retval) 98945914Smckusick struct proc *p; 99042441Smckusick register struct args { 99142441Smckusick char *fname; 992*53468Smckusick struct ostat *ub; 993*53468Smckusick } *uap; 994*53468Smckusick int *retval; 995*53468Smckusick { 996*53468Smckusick struct stat sb; 997*53468Smckusick struct ostat osb; 998*53468Smckusick int error; 999*53468Smckusick struct nameidata nd; 1000*53468Smckusick 1001*53468Smckusick NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 1002*53468Smckusick if (error = namei(&nd)) 1003*53468Smckusick return (error); 1004*53468Smckusick error = vn_stat(nd.ni_vp, &sb, p); 1005*53468Smckusick vput(nd.ni_vp); 1006*53468Smckusick if (error) 1007*53468Smckusick return (error); 1008*53468Smckusick cvtstat(&sb, &osb); 1009*53468Smckusick error = copyout((caddr_t)&osb, (caddr_t)uap->ub, sizeof (osb)); 1010*53468Smckusick return (error); 1011*53468Smckusick } 1012*53468Smckusick 1013*53468Smckusick /* 1014*53468Smckusick * Lstat system call. 1015*53468Smckusick * This version does not follow links. 1016*53468Smckusick */ 1017*53468Smckusick /* ARGSUSED */ 1018*53468Smckusick lstat(p, uap, retval) 1019*53468Smckusick struct proc *p; 1020*53468Smckusick register struct args { 1021*53468Smckusick char *fname; 1022*53468Smckusick struct ostat *ub; 1023*53468Smckusick } *uap; 1024*53468Smckusick int *retval; 1025*53468Smckusick { 1026*53468Smckusick struct stat sb; 1027*53468Smckusick struct ostat osb; 1028*53468Smckusick int error; 1029*53468Smckusick struct nameidata nd; 1030*53468Smckusick 1031*53468Smckusick NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 1032*53468Smckusick if (error = namei(&nd)) 1033*53468Smckusick return (error); 1034*53468Smckusick error = vn_stat(nd.ni_vp, &sb, p); 1035*53468Smckusick vput(nd.ni_vp); 1036*53468Smckusick if (error) 1037*53468Smckusick return (error); 1038*53468Smckusick cvtstat(&sb, &osb); 1039*53468Smckusick error = copyout((caddr_t)&osb, (caddr_t)uap->ub, sizeof (osb)); 1040*53468Smckusick return (error); 1041*53468Smckusick } 1042*53468Smckusick 1043*53468Smckusick /* 1044*53468Smckusick * convert from an old to a new stat structure. 1045*53468Smckusick */ 1046*53468Smckusick cvtstat(st, ost) 1047*53468Smckusick struct stat *st; 1048*53468Smckusick struct ostat *ost; 1049*53468Smckusick { 1050*53468Smckusick 1051*53468Smckusick ost->st_dev = st->st_dev; 1052*53468Smckusick ost->st_ino = st->st_ino; 1053*53468Smckusick ost->st_mode = st->st_mode; 1054*53468Smckusick ost->st_nlink = st->st_nlink; 1055*53468Smckusick ost->st_uid = st->st_uid; 1056*53468Smckusick ost->st_gid = st->st_gid; 1057*53468Smckusick ost->st_rdev = st->st_rdev; 1058*53468Smckusick if (st->st_size < (quad_t)1 << 32) 1059*53468Smckusick ost->st_size = st->st_size; 1060*53468Smckusick else 1061*53468Smckusick ost->st_size = -2; 1062*53468Smckusick ost->st_atime = st->st_atime; 1063*53468Smckusick ost->st_mtime = st->st_mtime; 1064*53468Smckusick ost->st_ctime = st->st_ctime; 1065*53468Smckusick ost->st_blksize = st->st_blksize; 1066*53468Smckusick ost->st_blocks = st->st_blocks; 1067*53468Smckusick ost->st_flags = st->st_flags; 1068*53468Smckusick ost->st_gen = st->st_gen; 1069*53468Smckusick } 1070*53468Smckusick #endif /* COMPAT_43 */ 1071*53468Smckusick 1072*53468Smckusick /* 1073*53468Smckusick * Stat system call. 1074*53468Smckusick * This version follows links. 1075*53468Smckusick */ 1076*53468Smckusick /* ARGSUSED */ 1077*53468Smckusick qstat(p, uap, retval) 1078*53468Smckusick struct proc *p; 1079*53468Smckusick register struct args { 1080*53468Smckusick char *fname; 108142441Smckusick struct stat *ub; 108242441Smckusick } *uap; 108342441Smckusick int *retval; 108437Sbill { 108542441Smckusick struct stat sb; 108642441Smckusick int error; 108747540Skarels struct nameidata nd; 108837Sbill 108952322Smckusick NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 109052322Smckusick if (error = namei(&nd)) 109147540Skarels return (error); 109252322Smckusick error = vn_stat(nd.ni_vp, &sb, p); 109352322Smckusick vput(nd.ni_vp); 109442441Smckusick if (error) 109547540Skarels return (error); 109642441Smckusick error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb)); 109747540Skarels return (error); 109837Sbill } 109937Sbill 110037Sbill /* 110149365Smckusick * Lstat system call. 110249365Smckusick * This version does not follow links. 11035992Swnj */ 110442441Smckusick /* ARGSUSED */ 1105*53468Smckusick lqstat(p, uap, retval) 110645914Smckusick struct proc *p; 110742441Smckusick register struct args { 11085992Swnj char *fname; 110912756Ssam struct stat *ub; 111042441Smckusick } *uap; 111142441Smckusick int *retval; 111242441Smckusick { 111312756Ssam struct stat sb; 111437741Smckusick int error; 111547540Skarels struct nameidata nd; 11165992Swnj 111752322Smckusick NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 111852322Smckusick if (error = namei(&nd)) 111947540Skarels return (error); 112052322Smckusick error = vn_stat(nd.ni_vp, &sb, p); 112152322Smckusick vput(nd.ni_vp); 112237741Smckusick if (error) 112347540Skarels return (error); 112437741Smckusick error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb)); 112547540Skarels return (error); 11265992Swnj } 11275992Swnj 11285992Swnj /* 112949365Smckusick * Return target name of a symbolic link. 113037Sbill */ 113142441Smckusick /* ARGSUSED */ 113242441Smckusick readlink(p, uap, retval) 113345914Smckusick struct proc *p; 113442441Smckusick register struct args { 11355992Swnj char *name; 11365992Swnj char *buf; 11375992Swnj int count; 113842441Smckusick } *uap; 113942441Smckusick int *retval; 114042441Smckusick { 114137741Smckusick register struct vnode *vp; 114237741Smckusick struct iovec aiov; 114337741Smckusick struct uio auio; 114437741Smckusick int error; 114547540Skarels struct nameidata nd; 11465992Swnj 114752322Smckusick NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, uap->name, p); 114852322Smckusick if (error = namei(&nd)) 114947540Skarels return (error); 115052322Smckusick vp = nd.ni_vp; 115137741Smckusick if (vp->v_type != VLNK) { 115237741Smckusick error = EINVAL; 11535992Swnj goto out; 11545992Swnj } 115537741Smckusick aiov.iov_base = uap->buf; 115637741Smckusick aiov.iov_len = uap->count; 115737741Smckusick auio.uio_iov = &aiov; 115837741Smckusick auio.uio_iovcnt = 1; 115937741Smckusick auio.uio_offset = 0; 116037741Smckusick auio.uio_rw = UIO_READ; 116137741Smckusick auio.uio_segflg = UIO_USERSPACE; 116248026Smckusick auio.uio_procp = p; 116337741Smckusick auio.uio_resid = uap->count; 116447540Skarels error = VOP_READLINK(vp, &auio, p->p_ucred); 11655992Swnj out: 116637741Smckusick vput(vp); 116742441Smckusick *retval = uap->count - auio.uio_resid; 116847540Skarels return (error); 11695992Swnj } 11705992Swnj 11719167Ssam /* 117238259Smckusick * Change flags of a file given path name. 117338259Smckusick */ 117442441Smckusick /* ARGSUSED */ 117542441Smckusick chflags(p, uap, retval) 117645914Smckusick struct proc *p; 117742441Smckusick register struct args { 117838259Smckusick char *fname; 117938259Smckusick int flags; 118042441Smckusick } *uap; 118142441Smckusick int *retval; 118242441Smckusick { 118338259Smckusick register struct vnode *vp; 118438259Smckusick struct vattr vattr; 118538259Smckusick int error; 118647540Skarels struct nameidata nd; 118738259Smckusick 118852322Smckusick NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 118952322Smckusick if (error = namei(&nd)) 119047540Skarels return (error); 119152322Smckusick vp = nd.ni_vp; 119241400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 119338259Smckusick error = EROFS; 119438259Smckusick goto out; 119538259Smckusick } 119645785Sbostic VATTR_NULL(&vattr); 119745785Sbostic vattr.va_flags = uap->flags; 119852192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 119948026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 120038259Smckusick out: 120138259Smckusick vput(vp); 120247540Skarels return (error); 120338259Smckusick } 120438259Smckusick 120538259Smckusick /* 120638259Smckusick * Change flags of a file given a file descriptor. 120738259Smckusick */ 120842441Smckusick /* ARGSUSED */ 120942441Smckusick fchflags(p, uap, retval) 121045914Smckusick struct proc *p; 121142441Smckusick register struct args { 121238259Smckusick int fd; 121338259Smckusick int flags; 121442441Smckusick } *uap; 121542441Smckusick int *retval; 121642441Smckusick { 121738259Smckusick struct vattr vattr; 121838259Smckusick struct vnode *vp; 121938259Smckusick struct file *fp; 122038259Smckusick int error; 122138259Smckusick 122245914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 122347540Skarels return (error); 122438259Smckusick vp = (struct vnode *)fp->f_data; 122538259Smckusick VOP_LOCK(vp); 122641400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 122738259Smckusick error = EROFS; 122838259Smckusick goto out; 122938259Smckusick } 123045785Sbostic VATTR_NULL(&vattr); 123145785Sbostic vattr.va_flags = uap->flags; 123252192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 123348026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 123438259Smckusick out: 123538259Smckusick VOP_UNLOCK(vp); 123647540Skarels return (error); 123738259Smckusick } 123838259Smckusick 123938259Smckusick /* 12409167Ssam * Change mode of a file given path name. 12419167Ssam */ 124242441Smckusick /* ARGSUSED */ 124342441Smckusick chmod(p, uap, retval) 124445914Smckusick struct proc *p; 124542441Smckusick register struct args { 12466254Sroot char *fname; 12476254Sroot int fmode; 124842441Smckusick } *uap; 124942441Smckusick int *retval; 125042441Smckusick { 125137741Smckusick register struct vnode *vp; 125237741Smckusick struct vattr vattr; 125337741Smckusick int error; 125447540Skarels struct nameidata nd; 12555992Swnj 125652322Smckusick NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 125752322Smckusick if (error = namei(&nd)) 125847540Skarels return (error); 125952322Smckusick vp = nd.ni_vp; 126041400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 126137741Smckusick error = EROFS; 126237741Smckusick goto out; 126337741Smckusick } 126445785Sbostic VATTR_NULL(&vattr); 126545785Sbostic vattr.va_mode = uap->fmode & 07777; 126652192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 126748026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 126837741Smckusick out: 126937741Smckusick vput(vp); 127047540Skarels return (error); 12717701Ssam } 12727439Sroot 12739167Ssam /* 12749167Ssam * Change mode of a file given a file descriptor. 12759167Ssam */ 127642441Smckusick /* ARGSUSED */ 127742441Smckusick fchmod(p, uap, retval) 127845914Smckusick struct proc *p; 127942441Smckusick register struct args { 12807701Ssam int fd; 12817701Ssam int fmode; 128242441Smckusick } *uap; 128342441Smckusick int *retval; 128442441Smckusick { 128537741Smckusick struct vattr vattr; 128637741Smckusick struct vnode *vp; 128737741Smckusick struct file *fp; 128837741Smckusick int error; 12897701Ssam 129045914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 129147540Skarels return (error); 129237741Smckusick vp = (struct vnode *)fp->f_data; 129337741Smckusick VOP_LOCK(vp); 129441400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 129537741Smckusick error = EROFS; 129637741Smckusick goto out; 12977439Sroot } 129845785Sbostic VATTR_NULL(&vattr); 129945785Sbostic vattr.va_mode = uap->fmode & 07777; 130052192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 130148026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 130237741Smckusick out: 130337741Smckusick VOP_UNLOCK(vp); 130447540Skarels return (error); 13055992Swnj } 13065992Swnj 13079167Ssam /* 13089167Ssam * Set ownership given a path name. 13099167Ssam */ 131042441Smckusick /* ARGSUSED */ 131142441Smckusick chown(p, uap, retval) 131245914Smckusick struct proc *p; 131342441Smckusick register struct args { 13146254Sroot char *fname; 13156254Sroot int uid; 13166254Sroot int gid; 131742441Smckusick } *uap; 131842441Smckusick int *retval; 131942441Smckusick { 132037741Smckusick register struct vnode *vp; 132137741Smckusick struct vattr vattr; 132237741Smckusick int error; 132347540Skarels struct nameidata nd; 132437Sbill 132552322Smckusick NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 132652322Smckusick if (error = namei(&nd)) 132747540Skarels return (error); 132852322Smckusick vp = nd.ni_vp; 132941400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 133037741Smckusick error = EROFS; 133137741Smckusick goto out; 133237741Smckusick } 133345785Sbostic VATTR_NULL(&vattr); 133445785Sbostic vattr.va_uid = uap->uid; 133545785Sbostic vattr.va_gid = uap->gid; 133652192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 133748026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 133837741Smckusick out: 133937741Smckusick vput(vp); 134047540Skarels return (error); 13417701Ssam } 13427439Sroot 13439167Ssam /* 13449167Ssam * Set ownership given a file descriptor. 13459167Ssam */ 134642441Smckusick /* ARGSUSED */ 134742441Smckusick fchown(p, uap, retval) 134845914Smckusick struct proc *p; 134942441Smckusick register struct args { 13507701Ssam int fd; 13517701Ssam int uid; 13527701Ssam int gid; 135342441Smckusick } *uap; 135442441Smckusick int *retval; 135542441Smckusick { 135637741Smckusick struct vattr vattr; 135737741Smckusick struct vnode *vp; 135837741Smckusick struct file *fp; 135937741Smckusick int error; 13607701Ssam 136145914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 136247540Skarels return (error); 136337741Smckusick vp = (struct vnode *)fp->f_data; 136437741Smckusick VOP_LOCK(vp); 136541400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 136637741Smckusick error = EROFS; 136737741Smckusick goto out; 136837741Smckusick } 136945785Sbostic VATTR_NULL(&vattr); 137045785Sbostic vattr.va_uid = uap->uid; 137145785Sbostic vattr.va_gid = uap->gid; 137252192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 137348026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 137437741Smckusick out: 137537741Smckusick VOP_UNLOCK(vp); 137647540Skarels return (error); 13777701Ssam } 13787701Ssam 137942441Smckusick /* 138042441Smckusick * Set the access and modification times of a file. 138142441Smckusick */ 138242441Smckusick /* ARGSUSED */ 138342441Smckusick utimes(p, uap, retval) 138445914Smckusick struct proc *p; 138542441Smckusick register struct args { 138611811Ssam char *fname; 138711811Ssam struct timeval *tptr; 138842441Smckusick } *uap; 138942441Smckusick int *retval; 139042441Smckusick { 139137741Smckusick register struct vnode *vp; 139211811Ssam struct timeval tv[2]; 139337741Smckusick struct vattr vattr; 139437741Smckusick int error; 139547540Skarels struct nameidata nd; 139611811Ssam 139737741Smckusick if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv))) 139847540Skarels return (error); 139952322Smckusick NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 140052322Smckusick if (error = namei(&nd)) 140147540Skarels return (error); 140252322Smckusick vp = nd.ni_vp; 140341400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 140437741Smckusick error = EROFS; 140537741Smckusick goto out; 140621015Smckusick } 140745785Sbostic VATTR_NULL(&vattr); 1408*53468Smckusick vattr.va_atime.tv_sec = tv[0].tv_sec; 1409*53468Smckusick vattr.va_mtime.tv_sec = tv[1].tv_sec; 141052192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 141148026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 141237741Smckusick out: 141337741Smckusick vput(vp); 141447540Skarels return (error); 141511811Ssam } 141611811Ssam 1417*53468Smckusick #ifdef COMPAT_43 14189167Ssam /* 14199167Ssam * Truncate a file given its path name. 14209167Ssam */ 142142441Smckusick /* ARGSUSED */ 142242441Smckusick truncate(p, uap, retval) 142345914Smckusick struct proc *p; 142442441Smckusick register struct args { 14257701Ssam char *fname; 1426*53468Smckusick long length; 1427*53468Smckusick } *uap; 1428*53468Smckusick int *retval; 1429*53468Smckusick { 1430*53468Smckusick struct nargs { 1431*53468Smckusick char *fname; 143226473Skarels off_t length; 1433*53468Smckusick } nuap; 1434*53468Smckusick 1435*53468Smckusick nuap.fname = uap->fname; 1436*53468Smckusick nuap.length = uap->length; 1437*53468Smckusick return (qtruncate(p, &nuap, retval)); 1438*53468Smckusick } 1439*53468Smckusick 1440*53468Smckusick /* 1441*53468Smckusick * Truncate a file given a file descriptor. 1442*53468Smckusick */ 1443*53468Smckusick /* ARGSUSED */ 1444*53468Smckusick ftruncate(p, uap, retval) 1445*53468Smckusick struct proc *p; 1446*53468Smckusick register struct args { 1447*53468Smckusick int fd; 1448*53468Smckusick long length; 144942441Smckusick } *uap; 145042441Smckusick int *retval; 145142441Smckusick { 1452*53468Smckusick struct nargs { 1453*53468Smckusick int fd; 1454*53468Smckusick off_t length; 1455*53468Smckusick } nuap; 1456*53468Smckusick 1457*53468Smckusick nuap.fd = uap->fd; 1458*53468Smckusick nuap.length = uap->length; 1459*53468Smckusick return (fqtruncate(p, &nuap, retval)); 1460*53468Smckusick } 1461*53468Smckusick #endif /* COMPAT_43 */ 1462*53468Smckusick 1463*53468Smckusick /* 1464*53468Smckusick * Truncate a file given its path name. 1465*53468Smckusick */ 1466*53468Smckusick /* ARGSUSED */ 1467*53468Smckusick qtruncate(p, uap, retval) 1468*53468Smckusick struct proc *p; 1469*53468Smckusick register struct args { 1470*53468Smckusick char *fname; 1471*53468Smckusick off_t length; 1472*53468Smckusick } *uap; 1473*53468Smckusick int *retval; 1474*53468Smckusick { 147537741Smckusick register struct vnode *vp; 147637741Smckusick struct vattr vattr; 147737741Smckusick int error; 147847540Skarels struct nameidata nd; 14797701Ssam 148052322Smckusick NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 148152322Smckusick if (error = namei(&nd)) 148247540Skarels return (error); 148352322Smckusick vp = nd.ni_vp; 148437741Smckusick if (vp->v_type == VDIR) { 148537741Smckusick error = EISDIR; 148637741Smckusick goto out; 14877701Ssam } 148838399Smckusick if ((error = vn_writechk(vp)) || 148948026Smckusick (error = VOP_ACCESS(vp, VWRITE, p->p_ucred, p))) 149037741Smckusick goto out; 149145785Sbostic VATTR_NULL(&vattr); 149245785Sbostic vattr.va_size = uap->length; 149352192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 149448026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 149537741Smckusick out: 149637741Smckusick vput(vp); 149747540Skarels return (error); 14987701Ssam } 14997701Ssam 15009167Ssam /* 15019167Ssam * Truncate a file given a file descriptor. 15029167Ssam */ 150342441Smckusick /* ARGSUSED */ 1504*53468Smckusick fqtruncate(p, uap, retval) 150545914Smckusick struct proc *p; 150642441Smckusick register struct args { 15077701Ssam int fd; 150826473Skarels off_t length; 150942441Smckusick } *uap; 151042441Smckusick int *retval; 151142441Smckusick { 151237741Smckusick struct vattr vattr; 151337741Smckusick struct vnode *vp; 15147701Ssam struct file *fp; 151537741Smckusick int error; 15167701Ssam 151745914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 151847540Skarels return (error); 151937741Smckusick if ((fp->f_flag & FWRITE) == 0) 152047540Skarels return (EINVAL); 152137741Smckusick vp = (struct vnode *)fp->f_data; 152237741Smckusick VOP_LOCK(vp); 152337741Smckusick if (vp->v_type == VDIR) { 152437741Smckusick error = EISDIR; 152537741Smckusick goto out; 15267701Ssam } 152738399Smckusick if (error = vn_writechk(vp)) 152837741Smckusick goto out; 152945785Sbostic VATTR_NULL(&vattr); 153045785Sbostic vattr.va_size = uap->length; 153152192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 153248026Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred, p); 153337741Smckusick out: 153437741Smckusick VOP_UNLOCK(vp); 153547540Skarels return (error); 15367701Ssam } 15377701Ssam 15389167Ssam /* 15399167Ssam * Synch an open file. 15409167Ssam */ 154142441Smckusick /* ARGSUSED */ 154242441Smckusick fsync(p, uap, retval) 154345914Smckusick struct proc *p; 154442441Smckusick struct args { 154542441Smckusick int fd; 154642441Smckusick } *uap; 154742441Smckusick int *retval; 15489167Ssam { 154939592Smckusick register struct vnode *vp; 15509167Ssam struct file *fp; 155137741Smckusick int error; 15529167Ssam 155345914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 155447540Skarels return (error); 155539592Smckusick vp = (struct vnode *)fp->f_data; 155639592Smckusick VOP_LOCK(vp); 155748026Smckusick error = VOP_FSYNC(vp, fp->f_flag, fp->f_cred, MNT_WAIT, p); 155839592Smckusick VOP_UNLOCK(vp); 155947540Skarels return (error); 15609167Ssam } 15619167Ssam 15629167Ssam /* 15639167Ssam * Rename system call. 15649167Ssam * 15659167Ssam * Source and destination must either both be directories, or both 15669167Ssam * not be directories. If target is a directory, it must be empty. 15679167Ssam */ 156842441Smckusick /* ARGSUSED */ 156942441Smckusick rename(p, uap, retval) 157045914Smckusick struct proc *p; 157142441Smckusick register struct args { 15727701Ssam char *from; 15737701Ssam char *to; 157442441Smckusick } *uap; 157542441Smckusick int *retval; 157642441Smckusick { 157737741Smckusick register struct vnode *tvp, *fvp, *tdvp; 157849735Smckusick struct nameidata fromnd, tond; 157937741Smckusick int error; 15807701Ssam 158152322Smckusick NDINIT(&fromnd, DELETE, WANTPARENT | SAVESTART, UIO_USERSPACE, 158252322Smckusick uap->from, p); 158352322Smckusick if (error = namei(&fromnd)) 158447540Skarels return (error); 158549735Smckusick fvp = fromnd.ni_vp; 158652322Smckusick NDINIT(&tond, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART, 158752322Smckusick UIO_USERSPACE, uap->to, p); 158852322Smckusick if (error = namei(&tond)) { 158952230Sheideman VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 159049735Smckusick vrele(fromnd.ni_dvp); 159142465Smckusick vrele(fvp); 159242465Smckusick goto out1; 159342465Smckusick } 159437741Smckusick tdvp = tond.ni_dvp; 159537741Smckusick tvp = tond.ni_vp; 159637741Smckusick if (tvp != NULL) { 159737741Smckusick if (fvp->v_type == VDIR && tvp->v_type != VDIR) { 159839242Sbostic error = ENOTDIR; 159937741Smckusick goto out; 160037741Smckusick } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) { 160139242Sbostic error = EISDIR; 160237741Smckusick goto out; 16039167Ssam } 160445240Smckusick if (fvp->v_mount != tvp->v_mount) { 160545240Smckusick error = EXDEV; 160645240Smckusick goto out; 160745240Smckusick } 16089167Ssam } 160937741Smckusick if (fvp->v_mount != tdvp->v_mount) { 161037741Smckusick error = EXDEV; 16119167Ssam goto out; 161210051Ssam } 161339286Smckusick if (fvp == tdvp) 161437741Smckusick error = EINVAL; 161539286Smckusick /* 161649735Smckusick * If source is the same as the destination (that is the 161749735Smckusick * same inode number with the same name in the same directory), 161839286Smckusick * then there is nothing to do. 161939286Smckusick */ 162049735Smckusick if (fvp == tvp && fromnd.ni_dvp == tdvp && 162152322Smckusick fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen && 162252322Smckusick !bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr, 162352322Smckusick fromnd.ni_cnd.cn_namelen)) 162439286Smckusick error = -1; 162537741Smckusick out: 162642465Smckusick if (!error) { 162752192Smckusick LEASE_CHECK(tdvp, p, p->p_ucred, LEASE_WRITE); 162852192Smckusick if (fromnd.ni_dvp != tdvp) 162952192Smckusick LEASE_CHECK(fromnd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 163052192Smckusick if (tvp) 163152192Smckusick LEASE_CHECK(tvp, p, p->p_ucred, LEASE_WRITE); 163252230Sheideman error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd, 163352230Sheideman tond.ni_dvp, tond.ni_vp, &tond.ni_cnd); 163442465Smckusick } else { 163552230Sheideman VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd); 163643344Smckusick if (tdvp == tvp) 163743344Smckusick vrele(tdvp); 163843344Smckusick else 163943344Smckusick vput(tdvp); 164042465Smckusick if (tvp) 164142465Smckusick vput(tvp); 164252230Sheideman VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 164349735Smckusick vrele(fromnd.ni_dvp); 164442465Smckusick vrele(fvp); 16459167Ssam } 164649735Smckusick vrele(tond.ni_startdir); 164752322Smckusick FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI); 164837741Smckusick out1: 164949735Smckusick vrele(fromnd.ni_startdir); 165052322Smckusick FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI); 165139286Smckusick if (error == -1) 165247540Skarels return (0); 165347540Skarels return (error); 16547701Ssam } 16557701Ssam 16567535Sroot /* 165749365Smckusick * Mkdir system call. 165812756Ssam */ 165942441Smckusick /* ARGSUSED */ 166042441Smckusick mkdir(p, uap, retval) 166145914Smckusick struct proc *p; 166242441Smckusick register struct args { 166312756Ssam char *name; 166412756Ssam int dmode; 166542441Smckusick } *uap; 166642441Smckusick int *retval; 166742441Smckusick { 166837741Smckusick register struct vnode *vp; 166937741Smckusick struct vattr vattr; 167037741Smckusick int error; 167147540Skarels struct nameidata nd; 167212756Ssam 167352322Smckusick NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->name, p); 167452322Smckusick if (error = namei(&nd)) 167547540Skarels return (error); 167652322Smckusick vp = nd.ni_vp; 167737741Smckusick if (vp != NULL) { 167852322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 167952322Smckusick if (nd.ni_dvp == vp) 168052322Smckusick vrele(nd.ni_dvp); 168143344Smckusick else 168252322Smckusick vput(nd.ni_dvp); 168342465Smckusick vrele(vp); 168447540Skarels return (EEXIST); 168512756Ssam } 168641362Smckusick VATTR_NULL(&vattr); 168737741Smckusick vattr.va_type = VDIR; 168845914Smckusick vattr.va_mode = (uap->dmode & 0777) &~ p->p_fd->fd_cmask; 168952322Smckusick LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 169052322Smckusick error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr); 169138145Smckusick if (!error) 169252322Smckusick vput(nd.ni_vp); 169347540Skarels return (error); 169412756Ssam } 169512756Ssam 169612756Ssam /* 169712756Ssam * Rmdir system call. 169812756Ssam */ 169942441Smckusick /* ARGSUSED */ 170042441Smckusick rmdir(p, uap, retval) 170145914Smckusick struct proc *p; 170242441Smckusick struct args { 170342441Smckusick char *name; 170442441Smckusick } *uap; 170542441Smckusick int *retval; 170612756Ssam { 170737741Smckusick register struct vnode *vp; 170837741Smckusick int error; 170947540Skarels struct nameidata nd; 171012756Ssam 171152322Smckusick NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE, uap->name, p); 171252322Smckusick if (error = namei(&nd)) 171347540Skarels return (error); 171452322Smckusick vp = nd.ni_vp; 171537741Smckusick if (vp->v_type != VDIR) { 171637741Smckusick error = ENOTDIR; 171712756Ssam goto out; 171812756Ssam } 171912756Ssam /* 172037741Smckusick * No rmdir "." please. 172112756Ssam */ 172252322Smckusick if (nd.ni_dvp == vp) { 172337741Smckusick error = EINVAL; 172412756Ssam goto out; 172512756Ssam } 172612756Ssam /* 172749365Smckusick * The root of a mounted filesystem cannot be deleted. 172812756Ssam */ 172937741Smckusick if (vp->v_flag & VROOT) 173037741Smckusick error = EBUSY; 173112756Ssam out: 173242465Smckusick if (!error) { 173352322Smckusick LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 173452192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 173552322Smckusick error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); 173642465Smckusick } else { 173752322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 173852322Smckusick if (nd.ni_dvp == vp) 173952322Smckusick vrele(nd.ni_dvp); 174043344Smckusick else 174152322Smckusick vput(nd.ni_dvp); 174242465Smckusick vput(vp); 174342465Smckusick } 174447540Skarels return (error); 174512756Ssam } 174612756Ssam 174737741Smckusick /* 174849365Smckusick * Read a block of directory entries in a file system independent format. 174937741Smckusick */ 175042441Smckusick getdirentries(p, uap, retval) 175145914Smckusick struct proc *p; 175242441Smckusick register struct args { 175337741Smckusick int fd; 175437741Smckusick char *buf; 175537741Smckusick unsigned count; 175637741Smckusick long *basep; 175742441Smckusick } *uap; 175842441Smckusick int *retval; 175942441Smckusick { 176039592Smckusick register struct vnode *vp; 176116540Ssam struct file *fp; 176237741Smckusick struct uio auio; 176337741Smckusick struct iovec aiov; 176438129Smckusick off_t off; 176540321Smckusick int error, eofflag; 176612756Ssam 176745914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 176847540Skarels return (error); 176937741Smckusick if ((fp->f_flag & FREAD) == 0) 177047540Skarels return (EBADF); 177139592Smckusick vp = (struct vnode *)fp->f_data; 177239592Smckusick if (vp->v_type != VDIR) 177347540Skarels return (EINVAL); 177437741Smckusick aiov.iov_base = uap->buf; 177537741Smckusick aiov.iov_len = uap->count; 177637741Smckusick auio.uio_iov = &aiov; 177737741Smckusick auio.uio_iovcnt = 1; 177837741Smckusick auio.uio_rw = UIO_READ; 177937741Smckusick auio.uio_segflg = UIO_USERSPACE; 178048026Smckusick auio.uio_procp = p; 178137741Smckusick auio.uio_resid = uap->count; 178239592Smckusick VOP_LOCK(vp); 178339592Smckusick auio.uio_offset = off = fp->f_offset; 178440321Smckusick error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag); 178539592Smckusick fp->f_offset = auio.uio_offset; 178639592Smckusick VOP_UNLOCK(vp); 178739592Smckusick if (error) 178847540Skarels return (error); 178939592Smckusick error = copyout((caddr_t)&off, (caddr_t)uap->basep, sizeof(long)); 179042441Smckusick *retval = uap->count - auio.uio_resid; 179147540Skarels return (error); 179212756Ssam } 179312756Ssam 179412756Ssam /* 179549365Smckusick * Set the mode mask for creation of filesystem nodes. 179612756Ssam */ 179742441Smckusick mode_t 179842441Smckusick umask(p, uap, retval) 179945914Smckusick struct proc *p; 180042441Smckusick struct args { 180142441Smckusick int mask; 180242441Smckusick } *uap; 180342441Smckusick int *retval; 180412756Ssam { 180545914Smckusick register struct filedesc *fdp = p->p_fd; 180612756Ssam 180745914Smckusick *retval = fdp->fd_cmask; 180845914Smckusick fdp->fd_cmask = uap->mask & 07777; 180947540Skarels return (0); 181012756Ssam } 181137741Smckusick 181239566Smarc /* 181339566Smarc * Void all references to file by ripping underlying filesystem 181439566Smarc * away from vnode. 181539566Smarc */ 181642441Smckusick /* ARGSUSED */ 181742441Smckusick revoke(p, uap, retval) 181845914Smckusick struct proc *p; 181942441Smckusick register struct args { 182039566Smarc char *fname; 182142441Smckusick } *uap; 182242441Smckusick int *retval; 182342441Smckusick { 182439566Smarc register struct vnode *vp; 182539566Smarc struct vattr vattr; 182639566Smarc int error; 182747540Skarels struct nameidata nd; 182839566Smarc 182952322Smckusick NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->fname, p); 183052322Smckusick if (error = namei(&nd)) 183147540Skarels return (error); 183252322Smckusick vp = nd.ni_vp; 183339566Smarc if (vp->v_type != VCHR && vp->v_type != VBLK) { 183439566Smarc error = EINVAL; 183539566Smarc goto out; 183639566Smarc } 183748026Smckusick if (error = VOP_GETATTR(vp, &vattr, p->p_ucred, p)) 183839566Smarc goto out; 183947540Skarels if (p->p_ucred->cr_uid != vattr.va_uid && 184047540Skarels (error = suser(p->p_ucred, &p->p_acflag))) 184139566Smarc goto out; 184239805Smckusick if (vp->v_usecount > 1 || (vp->v_flag & VALIASED)) 184339632Smckusick vgoneall(vp); 184439566Smarc out: 184539566Smarc vrele(vp); 184647540Skarels return (error); 184739566Smarc } 184839566Smarc 184949365Smckusick /* 185049365Smckusick * Convert a user file descriptor to a kernel file entry. 185149365Smckusick */ 185245914Smckusick getvnode(fdp, fdes, fpp) 185345914Smckusick struct filedesc *fdp; 185437741Smckusick struct file **fpp; 185537741Smckusick int fdes; 185637741Smckusick { 185737741Smckusick struct file *fp; 185837741Smckusick 185947540Skarels if ((unsigned)fdes >= fdp->fd_nfiles || 186047688Skarels (fp = fdp->fd_ofiles[fdes]) == NULL) 186137741Smckusick return (EBADF); 186237741Smckusick if (fp->f_type != DTYPE_VNODE) 186337741Smckusick return (EINVAL); 186437741Smckusick *fpp = fp; 186537741Smckusick return (0); 186637741Smckusick } 1867