123405Smckusick /* 237741Smckusick * Copyright (c) 1989 The Regents of the University of California. 337741Smckusick * All rights reserved. 423405Smckusick * 544459Sbostic * %sccs.include.redist.c% 637741Smckusick * 7*54172Smckusick * @(#)vfs_syscalls.c 7.86 (Berkeley) 06/20/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" 2253468Smckusick #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 { 4253548Sheideman USES_VOP_UNLOCK; 4339335Smckusick register struct vnode *vp; 4439335Smckusick register struct mount *mp; 4540111Smckusick int error, flag; 4647540Skarels struct nameidata nd; 476254Sroot 4837741Smckusick /* 4937741Smckusick * Must be super user 5037741Smckusick */ 5147540Skarels if (error = suser(p->p_ucred, &p->p_acflag)) 5247540Skarels return (error); 5337741Smckusick /* 5437741Smckusick * Get vnode to be covered 5537741Smckusick */ 5652322Smckusick NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->dir, p); 5752322Smckusick if (error = namei(&nd)) 5847540Skarels return (error); 5952322Smckusick vp = nd.ni_vp; 6041400Smckusick if (uap->flags & MNT_UPDATE) { 6139335Smckusick if ((vp->v_flag & VROOT) == 0) { 6239335Smckusick vput(vp); 6347540Skarels return (EINVAL); 6439335Smckusick } 6539335Smckusick mp = vp->v_mount; 6639335Smckusick /* 6739335Smckusick * We allow going from read-only to read-write, 6839335Smckusick * but not from read-write to read-only. 6939335Smckusick */ 7041400Smckusick if ((mp->mnt_flag & MNT_RDONLY) == 0 && 7141400Smckusick (uap->flags & MNT_RDONLY) != 0) { 7239335Smckusick vput(vp); 7347540Skarels return (EOPNOTSUPP); /* Needs translation */ 7439335Smckusick } 7541400Smckusick flag = mp->mnt_flag; 7641400Smckusick mp->mnt_flag |= MNT_UPDATE; 7739335Smckusick VOP_UNLOCK(vp); 7839335Smckusick goto update; 7939335Smckusick } 8039665Smckusick vinvalbuf(vp, 1); 8139805Smckusick if (vp->v_usecount != 1) { 8237741Smckusick vput(vp); 8347540Skarels return (EBUSY); 8437741Smckusick } 8537741Smckusick if (vp->v_type != VDIR) { 8637741Smckusick vput(vp); 8747540Skarels return (ENOTDIR); 8837741Smckusick } 8939741Smckusick if ((unsigned long)uap->type > MOUNT_MAXTYPE || 9037741Smckusick vfssw[uap->type] == (struct vfsops *)0) { 9137741Smckusick vput(vp); 9247540Skarels return (ENODEV); 9337741Smckusick } 9437741Smckusick 9537741Smckusick /* 9639335Smckusick * Allocate and initialize the file system. 9737741Smckusick */ 9837741Smckusick mp = (struct mount *)malloc((u_long)sizeof(struct mount), 9937741Smckusick M_MOUNT, M_WAITOK); 100*54172Smckusick bzero((char *)mp, (u_long)sizeof(struct mount)); 10141400Smckusick mp->mnt_op = vfssw[uap->type]; 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 { 42253548Sheideman USES_VOP_ACCESS; 42353548Sheideman USES_VOP_LOCK; 42453548Sheideman USES_VOP_UNLOCK; 42545914Smckusick register struct filedesc *fdp = p->p_fd; 42638259Smckusick register struct vnode *vp; 42738259Smckusick struct file *fp; 42838259Smckusick int error; 42938259Smckusick 43045914Smckusick if (error = getvnode(fdp, uap->fd, &fp)) 43147540Skarels return (error); 43238259Smckusick vp = (struct vnode *)fp->f_data; 43338259Smckusick VOP_LOCK(vp); 43438259Smckusick if (vp->v_type != VDIR) 43538259Smckusick error = ENOTDIR; 43638259Smckusick else 43748026Smckusick error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p); 43838259Smckusick VOP_UNLOCK(vp); 43939860Smckusick if (error) 44047540Skarels return (error); 44139860Smckusick VREF(vp); 44245914Smckusick vrele(fdp->fd_cdir); 44345914Smckusick fdp->fd_cdir = vp; 44447540Skarels return (0); 44538259Smckusick } 44638259Smckusick 44738259Smckusick /* 44837741Smckusick * Change current working directory (``.''). 44937741Smckusick */ 45042441Smckusick /* ARGSUSED */ 45142441Smckusick chdir(p, uap, retval) 45245914Smckusick struct proc *p; 45342441Smckusick struct args { 45442441Smckusick char *fname; 45542441Smckusick } *uap; 45642441Smckusick int *retval; 45737741Smckusick { 45845914Smckusick register struct filedesc *fdp = p->p_fd; 45937741Smckusick int error; 46047540Skarels struct nameidata nd; 4616254Sroot 46252322Smckusick NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 46352781Sralph if (error = chdirec(&nd, p)) 46447540Skarels return (error); 46545914Smckusick vrele(fdp->fd_cdir); 46652322Smckusick fdp->fd_cdir = nd.ni_vp; 46747540Skarels return (0); 46837741Smckusick } 4696254Sroot 47037741Smckusick /* 47137741Smckusick * Change notion of root (``/'') directory. 47237741Smckusick */ 47342441Smckusick /* ARGSUSED */ 47442441Smckusick chroot(p, uap, retval) 47545914Smckusick struct proc *p; 47642441Smckusick struct args { 47742441Smckusick char *fname; 47842441Smckusick } *uap; 47942441Smckusick int *retval; 48037741Smckusick { 48145914Smckusick register struct filedesc *fdp = p->p_fd; 48237741Smckusick int error; 48347540Skarels struct nameidata nd; 48437741Smckusick 48547540Skarels if (error = suser(p->p_ucred, &p->p_acflag)) 48647540Skarels return (error); 48752322Smckusick NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 48852781Sralph if (error = chdirec(&nd, p)) 48947540Skarels return (error); 49045914Smckusick if (fdp->fd_rdir != NULL) 49145914Smckusick vrele(fdp->fd_rdir); 49252322Smckusick fdp->fd_rdir = nd.ni_vp; 49347540Skarels return (0); 4946254Sroot } 4956254Sroot 49637Sbill /* 49737741Smckusick * Common routine for chroot and chdir. 49837741Smckusick */ 49947540Skarels chdirec(ndp, p) 50052322Smckusick register struct nameidata *ndp; 50147540Skarels struct proc *p; 50237741Smckusick { 50353548Sheideman USES_VOP_ACCESS; 50453548Sheideman USES_VOP_UNLOCK; 50537741Smckusick struct vnode *vp; 50637741Smckusick int error; 50737741Smckusick 50852322Smckusick if (error = namei(ndp)) 50937741Smckusick return (error); 51037741Smckusick vp = ndp->ni_vp; 51137741Smckusick if (vp->v_type != VDIR) 51237741Smckusick error = ENOTDIR; 51337741Smckusick else 51448026Smckusick error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p); 51537741Smckusick VOP_UNLOCK(vp); 51637741Smckusick if (error) 51737741Smckusick vrele(vp); 51837741Smckusick return (error); 51937741Smckusick } 52037741Smckusick 52137741Smckusick /* 5226254Sroot * Open system call. 52342441Smckusick * Check permissions, allocate an open file structure, 52442441Smckusick * and call the device open routine if any. 5256254Sroot */ 52642441Smckusick open(p, uap, retval) 52745914Smckusick struct proc *p; 52842441Smckusick register struct args { 5296254Sroot char *fname; 5307701Ssam int mode; 53112756Ssam int crtmode; 53242441Smckusick } *uap; 53342441Smckusick int *retval; 5346254Sroot { 53553548Sheideman USES_VOP_ADVLOCK; 53653548Sheideman USES_VOP_UNLOCK; 53745914Smckusick register struct filedesc *fdp = p->p_fd; 53842441Smckusick register struct file *fp; 53950111Smckusick register struct vnode *vp; 54037741Smckusick int fmode, cmode; 54137741Smckusick struct file *nfp; 54249945Smckusick int type, indx, error; 54349945Smckusick struct flock lf; 54447540Skarels struct nameidata nd; 54537741Smckusick extern struct fileops vnops; 5466254Sroot 54745914Smckusick if (error = falloc(p, &nfp, &indx)) 54847540Skarels return (error); 54937741Smckusick fp = nfp; 55046553Skarels fmode = FFLAGS(uap->mode); 55145914Smckusick cmode = ((uap->crtmode &~ fdp->fd_cmask) & 07777) &~ S_ISVTX; 55252322Smckusick NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->fname, p); 55345202Smckusick p->p_dupfd = -indx - 1; /* XXX check for fdopen */ 55452322Smckusick if (error = vn_open(&nd, fmode, cmode)) { 55553828Spendry int dfd = p->p_dupfd; 55653828Spendry p->p_dupfd = 0; 55749980Smckusick ffree(fp); 55853828Spendry if ((error == ENODEV || error == ENXIO) && /* XXX from fdopen */ 55953828Spendry dfd >= 0 && 56053828Spendry (error = dupfdopen(fdp, indx, p->p_dupfd, 56153828Spendry fmode, error)) == 0) { 56242441Smckusick *retval = indx; 56347540Skarels return (0); 56442441Smckusick } 56540884Smckusick if (error == ERESTART) 56640884Smckusick error = EINTR; 56747688Skarels fdp->fd_ofiles[indx] = NULL; 56847540Skarels return (error); 56912756Ssam } 57053828Spendry p->p_dupfd = 0; 57152322Smckusick vp = nd.ni_vp; 57249949Smckusick fp->f_flag = fmode & FMASK; 57349945Smckusick if (fmode & (O_EXLOCK | O_SHLOCK)) { 57449945Smckusick lf.l_whence = SEEK_SET; 57549945Smckusick lf.l_start = 0; 57649945Smckusick lf.l_len = 0; 57749945Smckusick if (fmode & O_EXLOCK) 57849945Smckusick lf.l_type = F_WRLCK; 57949945Smckusick else 58049945Smckusick lf.l_type = F_RDLCK; 58149945Smckusick type = F_FLOCK; 58249945Smckusick if ((fmode & FNONBLOCK) == 0) 58349945Smckusick type |= F_WAIT; 58450111Smckusick if (error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, type)) { 58550111Smckusick VOP_UNLOCK(vp); 58650111Smckusick (void) vn_close(vp, fp->f_flag, fp->f_cred, p); 58749980Smckusick ffree(fp); 58849945Smckusick fdp->fd_ofiles[indx] = NULL; 58949945Smckusick return (error); 59049945Smckusick } 59149949Smckusick fp->f_flag |= FHASLOCK; 59249945Smckusick } 59350111Smckusick VOP_UNLOCK(vp); 59437741Smckusick fp->f_type = DTYPE_VNODE; 59537741Smckusick fp->f_ops = &vnops; 59650111Smckusick fp->f_data = (caddr_t)vp; 59742441Smckusick *retval = indx; 59847540Skarels return (0); 5996254Sroot } 6006254Sroot 60142955Smckusick #ifdef COMPAT_43 6026254Sroot /* 60342441Smckusick * Creat system call. 6046254Sroot */ 60542955Smckusick ocreat(p, uap, retval) 60642441Smckusick struct proc *p; 60742441Smckusick register struct args { 60842441Smckusick char *fname; 60942441Smckusick int fmode; 61042441Smckusick } *uap; 61142441Smckusick int *retval; 6126254Sroot { 61342441Smckusick struct args { 6146254Sroot char *fname; 61542441Smckusick int mode; 61642441Smckusick int crtmode; 61742441Smckusick } openuap; 61842441Smckusick 61942441Smckusick openuap.fname = uap->fname; 62042441Smckusick openuap.crtmode = uap->fmode; 62142441Smckusick openuap.mode = O_WRONLY | O_CREAT | O_TRUNC; 62247540Skarels return (open(p, &openuap, retval)); 62342441Smckusick } 62442955Smckusick #endif /* COMPAT_43 */ 62542441Smckusick 62642441Smckusick /* 62749365Smckusick * Mknod system call. 62842441Smckusick */ 62942441Smckusick /* ARGSUSED */ 63042441Smckusick mknod(p, uap, retval) 63145914Smckusick struct proc *p; 63242441Smckusick register struct args { 63342441Smckusick char *fname; 6346254Sroot int fmode; 6356254Sroot int dev; 63642441Smckusick } *uap; 63742441Smckusick int *retval; 63842441Smckusick { 63953548Sheideman USES_VOP_ABORTOP; 64053548Sheideman USES_VOP_MKNOD; 64137741Smckusick register struct vnode *vp; 64237741Smckusick struct vattr vattr; 64337741Smckusick int error; 64447540Skarels struct nameidata nd; 6456254Sroot 64647540Skarels if (error = suser(p->p_ucred, &p->p_acflag)) 64747540Skarels return (error); 64852322Smckusick NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->fname, p); 64952322Smckusick if (error = namei(&nd)) 65047540Skarels return (error); 65152322Smckusick vp = nd.ni_vp; 65237741Smckusick if (vp != NULL) { 65337741Smckusick error = EEXIST; 65412756Ssam goto out; 6556254Sroot } 65641362Smckusick VATTR_NULL(&vattr); 65740635Smckusick switch (uap->fmode & S_IFMT) { 65812756Ssam 65940635Smckusick case S_IFMT: /* used by badsect to flag bad sectors */ 66037741Smckusick vattr.va_type = VBAD; 66137741Smckusick break; 66240635Smckusick case S_IFCHR: 66337741Smckusick vattr.va_type = VCHR; 66437741Smckusick break; 66540635Smckusick case S_IFBLK: 66637741Smckusick vattr.va_type = VBLK; 66737741Smckusick break; 66837741Smckusick default: 66937741Smckusick error = EINVAL; 67037741Smckusick goto out; 6716254Sroot } 67245914Smckusick vattr.va_mode = (uap->fmode & 07777) &~ p->p_fd->fd_cmask; 67337741Smckusick vattr.va_rdev = uap->dev; 6746254Sroot out: 67542465Smckusick if (!error) { 67652322Smckusick LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 67752322Smckusick error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr); 67842465Smckusick } else { 67952322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 68052322Smckusick if (nd.ni_dvp == vp) 68152322Smckusick vrele(nd.ni_dvp); 68243344Smckusick else 68352322Smckusick vput(nd.ni_dvp); 68442465Smckusick if (vp) 68542465Smckusick vrele(vp); 68642465Smckusick } 68747540Skarels return (error); 6886254Sroot } 6896254Sroot 6906254Sroot /* 69149365Smckusick * Mkfifo system call. 69240285Smckusick */ 69342441Smckusick /* ARGSUSED */ 69442441Smckusick mkfifo(p, uap, retval) 69545914Smckusick struct proc *p; 69642441Smckusick register struct args { 69740285Smckusick char *fname; 69840285Smckusick int fmode; 69942441Smckusick } *uap; 70042441Smckusick int *retval; 70142441Smckusick { 70253548Sheideman USES_VOP_ABORTOP; 70353548Sheideman USES_VOP_MKNOD; 70440285Smckusick struct vattr vattr; 70540285Smckusick int error; 70647540Skarels struct nameidata nd; 70740285Smckusick 70840285Smckusick #ifndef FIFO 70947540Skarels return (EOPNOTSUPP); 71040285Smckusick #else 71152322Smckusick NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->fname, p); 71252322Smckusick if (error = namei(&nd)) 71347540Skarels return (error); 71452322Smckusick if (nd.ni_vp != NULL) { 71552322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 71652322Smckusick if (nd.ni_dvp == nd.ni_vp) 71752322Smckusick vrele(nd.ni_dvp); 71843344Smckusick else 71952322Smckusick vput(nd.ni_dvp); 72052322Smckusick vrele(nd.ni_vp); 72147540Skarels return (EEXIST); 72240285Smckusick } 72345785Sbostic VATTR_NULL(&vattr); 72445785Sbostic vattr.va_type = VFIFO; 72545914Smckusick vattr.va_mode = (uap->fmode & 07777) &~ p->p_fd->fd_cmask; 72652322Smckusick LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 72752322Smckusick return (VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr)); 72840285Smckusick #endif /* FIFO */ 72940285Smckusick } 73040285Smckusick 73140285Smckusick /* 73249365Smckusick * Link system call. 7336254Sroot */ 73442441Smckusick /* ARGSUSED */ 73542441Smckusick link(p, uap, retval) 73645914Smckusick struct proc *p; 73742441Smckusick register struct args { 7386254Sroot char *target; 7396254Sroot char *linkname; 74042441Smckusick } *uap; 74142441Smckusick int *retval; 74242441Smckusick { 74353548Sheideman USES_VOP_ABORTOP; 74453548Sheideman USES_VOP_LINK; 74537741Smckusick register struct vnode *vp, *xp; 74637741Smckusick int error; 74747540Skarels struct nameidata nd; 7486254Sroot 74952322Smckusick NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->target, p); 75052322Smckusick if (error = namei(&nd)) 75147540Skarels return (error); 75252322Smckusick vp = nd.ni_vp; 75337741Smckusick if (vp->v_type == VDIR && 75447540Skarels (error = suser(p->p_ucred, &p->p_acflag))) 75537741Smckusick goto out1; 75652322Smckusick nd.ni_cnd.cn_nameiop = CREATE; 75752322Smckusick nd.ni_cnd.cn_flags = LOCKPARENT; 75852322Smckusick nd.ni_dirp = (caddr_t)uap->linkname; 75952322Smckusick if (error = namei(&nd)) 76037741Smckusick goto out1; 76152322Smckusick xp = nd.ni_vp; 7626254Sroot if (xp != NULL) { 76337741Smckusick error = EEXIST; 7646254Sroot goto out; 7656254Sroot } 76652322Smckusick xp = nd.ni_dvp; 7676254Sroot out: 76842465Smckusick if (!error) { 76952192Smckusick LEASE_CHECK(xp, p, p->p_ucred, LEASE_WRITE); 77052192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 77152821Smckusick error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd); 77242465Smckusick } else { 77352322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 77452322Smckusick if (nd.ni_dvp == nd.ni_vp) 77552322Smckusick vrele(nd.ni_dvp); 77643344Smckusick else 77752322Smckusick vput(nd.ni_dvp); 77852322Smckusick if (nd.ni_vp) 77952322Smckusick vrele(nd.ni_vp); 78042465Smckusick } 78137741Smckusick out1: 78237741Smckusick vrele(vp); 78347540Skarels return (error); 7846254Sroot } 7856254Sroot 7866254Sroot /* 78749365Smckusick * Make a symbolic link. 7886254Sroot */ 78942441Smckusick /* ARGSUSED */ 79042441Smckusick symlink(p, uap, retval) 79145914Smckusick struct proc *p; 79242441Smckusick register struct args { 7936254Sroot char *target; 7946254Sroot char *linkname; 79542441Smckusick } *uap; 79642441Smckusick int *retval; 79742441Smckusick { 79853548Sheideman USES_VOP_ABORTOP; 79953548Sheideman USES_VOP_SYMLINK; 80037741Smckusick struct vattr vattr; 80137741Smckusick char *target; 80237741Smckusick int error; 80347540Skarels struct nameidata nd; 8046254Sroot 80537741Smckusick MALLOC(target, char *, MAXPATHLEN, M_NAMEI, M_WAITOK); 80637741Smckusick if (error = copyinstr(uap->target, target, MAXPATHLEN, (u_int *)0)) 80742465Smckusick goto out; 80852322Smckusick NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->linkname, p); 80952322Smckusick if (error = namei(&nd)) 81042465Smckusick goto out; 81152322Smckusick if (nd.ni_vp) { 81252322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 81352322Smckusick if (nd.ni_dvp == nd.ni_vp) 81452322Smckusick vrele(nd.ni_dvp); 81543344Smckusick else 81652322Smckusick vput(nd.ni_dvp); 81752322Smckusick vrele(nd.ni_vp); 81837741Smckusick error = EEXIST; 81937741Smckusick goto out; 8206254Sroot } 82141362Smckusick VATTR_NULL(&vattr); 82245914Smckusick vattr.va_mode = 0777 &~ p->p_fd->fd_cmask; 82352322Smckusick LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 82452322Smckusick error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr, target); 82537741Smckusick out: 82637741Smckusick FREE(target, M_NAMEI); 82747540Skarels return (error); 8286254Sroot } 8296254Sroot 8306254Sroot /* 83149365Smckusick * Delete a name from the filesystem. 8326254Sroot */ 83342441Smckusick /* ARGSUSED */ 83442441Smckusick unlink(p, uap, retval) 83545914Smckusick struct proc *p; 83642441Smckusick struct args { 83752322Smckusick char *name; 83842441Smckusick } *uap; 83942441Smckusick int *retval; 8406254Sroot { 84153548Sheideman USES_VOP_ABORTOP; 84253548Sheideman USES_VOP_REMOVE; 84337741Smckusick register struct vnode *vp; 84437741Smckusick int error; 84547540Skarels struct nameidata nd; 8466254Sroot 84752322Smckusick NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE, uap->name, p); 84852322Smckusick if (error = namei(&nd)) 84947540Skarels return (error); 85052322Smckusick vp = nd.ni_vp; 85137741Smckusick if (vp->v_type == VDIR && 85247540Skarels (error = suser(p->p_ucred, &p->p_acflag))) 8536254Sroot goto out; 8546254Sroot /* 85549365Smckusick * The root of a mounted filesystem cannot be deleted. 8566254Sroot */ 85737741Smckusick if (vp->v_flag & VROOT) { 85837741Smckusick error = EBUSY; 8596254Sroot goto out; 8606254Sroot } 86145738Smckusick (void) vnode_pager_uncache(vp); 8626254Sroot out: 86342465Smckusick if (!error) { 86452322Smckusick LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 86552192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 86652322Smckusick error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); 86742465Smckusick } else { 86852322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 86952322Smckusick if (nd.ni_dvp == vp) 87052322Smckusick vrele(nd.ni_dvp); 87143344Smckusick else 87252322Smckusick vput(nd.ni_dvp); 87342465Smckusick vput(vp); 87442465Smckusick } 87547540Skarels return (error); 8766254Sroot } 8776254Sroot 87853468Smckusick #ifdef COMPAT_43 8796254Sroot /* 88049365Smckusick * Seek system call. 8816254Sroot */ 88242441Smckusick lseek(p, uap, retval) 88345914Smckusick struct proc *p; 88442441Smckusick register struct args { 88537741Smckusick int fdes; 88653468Smckusick long off; 88753468Smckusick int sbase; 88853468Smckusick } *uap; 88953468Smckusick long *retval; 89053468Smckusick { 89153468Smckusick struct nargs { 89253468Smckusick int fdes; 8936254Sroot off_t off; 8946254Sroot int sbase; 89553468Smckusick } nuap; 89653468Smckusick quad_t qret; 89753468Smckusick int error; 89853468Smckusick 89953468Smckusick nuap.fdes = uap->fdes; 90053468Smckusick nuap.off = uap->off; 90153468Smckusick nuap.sbase = uap->sbase; 90253759Smckusick error = __lseek(p, &nuap, &qret); 90353468Smckusick *retval = qret; 90453468Smckusick return (error); 90553468Smckusick } 90653468Smckusick #endif /* COMPAT_43 */ 90753468Smckusick 90853468Smckusick /* 90953468Smckusick * Seek system call. 91053468Smckusick */ 91153759Smckusick __lseek(p, uap, retval) 91253468Smckusick struct proc *p; 91353468Smckusick register struct args { 91453468Smckusick int fdes; 91553468Smckusick off_t off; 91653468Smckusick int sbase; 91742441Smckusick } *uap; 91842441Smckusick off_t *retval; 91942441Smckusick { 92053548Sheideman USES_VOP_GETATTR; 92147540Skarels struct ucred *cred = p->p_ucred; 92245914Smckusick register struct filedesc *fdp = p->p_fd; 92342441Smckusick register struct file *fp; 92437741Smckusick struct vattr vattr; 92537741Smckusick int error; 9266254Sroot 92747540Skarels if ((unsigned)uap->fdes >= fdp->fd_nfiles || 92847688Skarels (fp = fdp->fd_ofiles[uap->fdes]) == NULL) 92947540Skarels return (EBADF); 93037741Smckusick if (fp->f_type != DTYPE_VNODE) 93147540Skarels return (ESPIPE); 93213878Ssam switch (uap->sbase) { 93313878Ssam 93413878Ssam case L_INCR: 93513878Ssam fp->f_offset += uap->off; 93613878Ssam break; 93713878Ssam 93813878Ssam case L_XTND: 93937741Smckusick if (error = VOP_GETATTR((struct vnode *)fp->f_data, 94048026Smckusick &vattr, cred, p)) 94147540Skarels return (error); 94237741Smckusick fp->f_offset = uap->off + vattr.va_size; 94313878Ssam break; 94413878Ssam 94513878Ssam case L_SET: 94613878Ssam fp->f_offset = uap->off; 94713878Ssam break; 94813878Ssam 94913878Ssam default: 95047540Skarels return (EINVAL); 95113878Ssam } 95242441Smckusick *retval = fp->f_offset; 95347540Skarels return (0); 9546254Sroot } 9556254Sroot 9566254Sroot /* 95749365Smckusick * Check access permissions. 9586254Sroot */ 95942441Smckusick /* ARGSUSED */ 96042441Smckusick saccess(p, uap, retval) 96145914Smckusick struct proc *p; 96242441Smckusick register struct args { 9636254Sroot char *fname; 9646254Sroot int fmode; 96542441Smckusick } *uap; 96642441Smckusick int *retval; 96742441Smckusick { 96853548Sheideman USES_VOP_ACCESS; 96947540Skarels register struct ucred *cred = p->p_ucred; 97037741Smckusick register struct vnode *vp; 97137741Smckusick int error, mode, svuid, svgid; 97247540Skarels struct nameidata nd; 9736254Sroot 97442441Smckusick svuid = cred->cr_uid; 97542441Smckusick svgid = cred->cr_groups[0]; 97647540Skarels cred->cr_uid = p->p_cred->p_ruid; 97747540Skarels cred->cr_groups[0] = p->p_cred->p_rgid; 97852322Smckusick NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 97952322Smckusick if (error = namei(&nd)) 98037741Smckusick goto out1; 98152322Smckusick vp = nd.ni_vp; 98237741Smckusick /* 98337741Smckusick * fmode == 0 means only check for exist 98437741Smckusick */ 98537741Smckusick if (uap->fmode) { 98637741Smckusick mode = 0; 98737741Smckusick if (uap->fmode & R_OK) 98837741Smckusick mode |= VREAD; 98937741Smckusick if (uap->fmode & W_OK) 99037741Smckusick mode |= VWRITE; 99137741Smckusick if (uap->fmode & X_OK) 99237741Smckusick mode |= VEXEC; 99339543Smckusick if ((mode & VWRITE) == 0 || (error = vn_writechk(vp)) == 0) 99448026Smckusick error = VOP_ACCESS(vp, mode, cred, p); 9956254Sroot } 99637741Smckusick vput(vp); 99737741Smckusick out1: 99842441Smckusick cred->cr_uid = svuid; 99942441Smckusick cred->cr_groups[0] = svgid; 100047540Skarels return (error); 10016254Sroot } 10026254Sroot 100353468Smckusick #ifdef COMPAT_43 10046254Sroot /* 100549365Smckusick * Stat system call. 100649365Smckusick * This version follows links. 100737Sbill */ 100842441Smckusick /* ARGSUSED */ 100953759Smckusick ostat(p, uap, retval) 101045914Smckusick struct proc *p; 101142441Smckusick register struct args { 101242441Smckusick char *fname; 101353468Smckusick struct ostat *ub; 101453468Smckusick } *uap; 101553468Smckusick int *retval; 101653468Smckusick { 101753468Smckusick struct stat sb; 101853468Smckusick struct ostat osb; 101953468Smckusick int error; 102053468Smckusick struct nameidata nd; 102153468Smckusick 102253468Smckusick NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 102353468Smckusick if (error = namei(&nd)) 102453468Smckusick return (error); 102553468Smckusick error = vn_stat(nd.ni_vp, &sb, p); 102653468Smckusick vput(nd.ni_vp); 102753468Smckusick if (error) 102853468Smckusick return (error); 102953468Smckusick cvtstat(&sb, &osb); 103053468Smckusick error = copyout((caddr_t)&osb, (caddr_t)uap->ub, sizeof (osb)); 103153468Smckusick return (error); 103253468Smckusick } 103353468Smckusick 103453468Smckusick /* 103553468Smckusick * Lstat system call. 103653468Smckusick * This version does not follow links. 103753468Smckusick */ 103853468Smckusick /* ARGSUSED */ 103953759Smckusick olstat(p, uap, retval) 104053468Smckusick struct proc *p; 104153468Smckusick register struct args { 104253468Smckusick char *fname; 104353468Smckusick struct ostat *ub; 104453468Smckusick } *uap; 104553468Smckusick int *retval; 104653468Smckusick { 104753468Smckusick struct stat sb; 104853468Smckusick struct ostat osb; 104953468Smckusick int error; 105053468Smckusick struct nameidata nd; 105153468Smckusick 105253468Smckusick NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 105353468Smckusick if (error = namei(&nd)) 105453468Smckusick return (error); 105553468Smckusick error = vn_stat(nd.ni_vp, &sb, p); 105653468Smckusick vput(nd.ni_vp); 105753468Smckusick if (error) 105853468Smckusick return (error); 105953468Smckusick cvtstat(&sb, &osb); 106053468Smckusick error = copyout((caddr_t)&osb, (caddr_t)uap->ub, sizeof (osb)); 106153468Smckusick return (error); 106253468Smckusick } 106353468Smckusick 106453468Smckusick /* 106553468Smckusick * convert from an old to a new stat structure. 106653468Smckusick */ 106753468Smckusick cvtstat(st, ost) 106853468Smckusick struct stat *st; 106953468Smckusick struct ostat *ost; 107053468Smckusick { 107153468Smckusick 107253468Smckusick ost->st_dev = st->st_dev; 107353468Smckusick ost->st_ino = st->st_ino; 107453468Smckusick ost->st_mode = st->st_mode; 107553468Smckusick ost->st_nlink = st->st_nlink; 107653468Smckusick ost->st_uid = st->st_uid; 107753468Smckusick ost->st_gid = st->st_gid; 107853468Smckusick ost->st_rdev = st->st_rdev; 107953468Smckusick if (st->st_size < (quad_t)1 << 32) 108053468Smckusick ost->st_size = st->st_size; 108153468Smckusick else 108253468Smckusick ost->st_size = -2; 108353468Smckusick ost->st_atime = st->st_atime; 108453468Smckusick ost->st_mtime = st->st_mtime; 108553468Smckusick ost->st_ctime = st->st_ctime; 108653468Smckusick ost->st_blksize = st->st_blksize; 108753468Smckusick ost->st_blocks = st->st_blocks; 108853468Smckusick ost->st_flags = st->st_flags; 108953468Smckusick ost->st_gen = st->st_gen; 109053468Smckusick } 109153468Smckusick #endif /* COMPAT_43 */ 109253468Smckusick 109353468Smckusick /* 109453468Smckusick * Stat system call. 109553468Smckusick * This version follows links. 109653468Smckusick */ 109753468Smckusick /* ARGSUSED */ 109853759Smckusick stat(p, uap, retval) 109953468Smckusick struct proc *p; 110053468Smckusick register struct args { 110153468Smckusick char *fname; 110242441Smckusick struct stat *ub; 110342441Smckusick } *uap; 110442441Smckusick int *retval; 110537Sbill { 110642441Smckusick struct stat sb; 110742441Smckusick int error; 110847540Skarels struct nameidata nd; 110937Sbill 111052322Smckusick NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 111152322Smckusick if (error = namei(&nd)) 111247540Skarels return (error); 111352322Smckusick error = vn_stat(nd.ni_vp, &sb, p); 111452322Smckusick vput(nd.ni_vp); 111542441Smckusick if (error) 111647540Skarels return (error); 111742441Smckusick error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb)); 111847540Skarels return (error); 111937Sbill } 112037Sbill 112137Sbill /* 112249365Smckusick * Lstat system call. 112349365Smckusick * This version does not follow links. 11245992Swnj */ 112542441Smckusick /* ARGSUSED */ 112653759Smckusick lstat(p, uap, retval) 112745914Smckusick struct proc *p; 112842441Smckusick register struct args { 11295992Swnj char *fname; 113012756Ssam struct stat *ub; 113142441Smckusick } *uap; 113242441Smckusick int *retval; 113342441Smckusick { 113412756Ssam struct stat sb; 113537741Smckusick int error; 113647540Skarels struct nameidata nd; 11375992Swnj 113852322Smckusick NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 113952322Smckusick if (error = namei(&nd)) 114047540Skarels return (error); 114152322Smckusick error = vn_stat(nd.ni_vp, &sb, p); 114252322Smckusick vput(nd.ni_vp); 114337741Smckusick if (error) 114447540Skarels return (error); 114537741Smckusick error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb)); 114647540Skarels return (error); 11475992Swnj } 11485992Swnj 11495992Swnj /* 115049365Smckusick * Return target name of a symbolic link. 115137Sbill */ 115242441Smckusick /* ARGSUSED */ 115342441Smckusick readlink(p, uap, retval) 115445914Smckusick struct proc *p; 115542441Smckusick register struct args { 11565992Swnj char *name; 11575992Swnj char *buf; 11585992Swnj int count; 115942441Smckusick } *uap; 116042441Smckusick int *retval; 116142441Smckusick { 116253548Sheideman USES_VOP_READLINK; 116337741Smckusick register struct vnode *vp; 116437741Smckusick struct iovec aiov; 116537741Smckusick struct uio auio; 116637741Smckusick int error; 116747540Skarels struct nameidata nd; 11685992Swnj 116952322Smckusick NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, uap->name, p); 117052322Smckusick if (error = namei(&nd)) 117147540Skarels return (error); 117252322Smckusick vp = nd.ni_vp; 117337741Smckusick if (vp->v_type != VLNK) { 117437741Smckusick error = EINVAL; 11755992Swnj goto out; 11765992Swnj } 117737741Smckusick aiov.iov_base = uap->buf; 117837741Smckusick aiov.iov_len = uap->count; 117937741Smckusick auio.uio_iov = &aiov; 118037741Smckusick auio.uio_iovcnt = 1; 118137741Smckusick auio.uio_offset = 0; 118237741Smckusick auio.uio_rw = UIO_READ; 118337741Smckusick auio.uio_segflg = UIO_USERSPACE; 118448026Smckusick auio.uio_procp = p; 118537741Smckusick auio.uio_resid = uap->count; 118647540Skarels error = VOP_READLINK(vp, &auio, p->p_ucred); 11875992Swnj out: 118837741Smckusick vput(vp); 118942441Smckusick *retval = uap->count - auio.uio_resid; 119047540Skarels return (error); 11915992Swnj } 11925992Swnj 11939167Ssam /* 119438259Smckusick * Change flags of a file given path name. 119538259Smckusick */ 119642441Smckusick /* ARGSUSED */ 119742441Smckusick chflags(p, uap, retval) 119845914Smckusick struct proc *p; 119942441Smckusick register struct args { 120038259Smckusick char *fname; 120138259Smckusick int flags; 120242441Smckusick } *uap; 120342441Smckusick int *retval; 120442441Smckusick { 120553548Sheideman USES_VOP_SETATTR; 120638259Smckusick register struct vnode *vp; 120738259Smckusick struct vattr vattr; 120838259Smckusick int error; 120947540Skarels struct nameidata nd; 121038259Smckusick 121152322Smckusick NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 121252322Smckusick if (error = namei(&nd)) 121347540Skarels return (error); 121452322Smckusick vp = nd.ni_vp; 121541400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 121638259Smckusick error = EROFS; 121738259Smckusick goto out; 121838259Smckusick } 121945785Sbostic VATTR_NULL(&vattr); 122045785Sbostic vattr.va_flags = uap->flags; 122152192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 122248026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 122338259Smckusick out: 122438259Smckusick vput(vp); 122547540Skarels return (error); 122638259Smckusick } 122738259Smckusick 122838259Smckusick /* 122938259Smckusick * Change flags of a file given a file descriptor. 123038259Smckusick */ 123142441Smckusick /* ARGSUSED */ 123242441Smckusick fchflags(p, uap, retval) 123345914Smckusick struct proc *p; 123442441Smckusick register struct args { 123538259Smckusick int fd; 123638259Smckusick int flags; 123742441Smckusick } *uap; 123842441Smckusick int *retval; 123942441Smckusick { 124053548Sheideman USES_VOP_LOCK; 124153548Sheideman USES_VOP_SETATTR; 124253548Sheideman USES_VOP_UNLOCK; 124338259Smckusick struct vattr vattr; 124438259Smckusick struct vnode *vp; 124538259Smckusick struct file *fp; 124638259Smckusick int error; 124738259Smckusick 124845914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 124947540Skarels return (error); 125038259Smckusick vp = (struct vnode *)fp->f_data; 125138259Smckusick VOP_LOCK(vp); 125241400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 125338259Smckusick error = EROFS; 125438259Smckusick goto out; 125538259Smckusick } 125645785Sbostic VATTR_NULL(&vattr); 125745785Sbostic vattr.va_flags = uap->flags; 125852192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 125948026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 126038259Smckusick out: 126138259Smckusick VOP_UNLOCK(vp); 126247540Skarels return (error); 126338259Smckusick } 126438259Smckusick 126538259Smckusick /* 12669167Ssam * Change mode of a file given path name. 12679167Ssam */ 126842441Smckusick /* ARGSUSED */ 126942441Smckusick chmod(p, uap, retval) 127045914Smckusick struct proc *p; 127142441Smckusick register struct args { 12726254Sroot char *fname; 12736254Sroot int fmode; 127442441Smckusick } *uap; 127542441Smckusick int *retval; 127642441Smckusick { 127753548Sheideman USES_VOP_SETATTR; 127837741Smckusick register struct vnode *vp; 127937741Smckusick struct vattr vattr; 128037741Smckusick int error; 128147540Skarels struct nameidata nd; 12825992Swnj 128352322Smckusick NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 128452322Smckusick if (error = namei(&nd)) 128547540Skarels return (error); 128652322Smckusick vp = nd.ni_vp; 128741400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 128837741Smckusick error = EROFS; 128937741Smckusick goto out; 129037741Smckusick } 129145785Sbostic VATTR_NULL(&vattr); 129245785Sbostic vattr.va_mode = uap->fmode & 07777; 129352192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 129448026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 129537741Smckusick out: 129637741Smckusick vput(vp); 129747540Skarels return (error); 12987701Ssam } 12997439Sroot 13009167Ssam /* 13019167Ssam * Change mode of a file given a file descriptor. 13029167Ssam */ 130342441Smckusick /* ARGSUSED */ 130442441Smckusick fchmod(p, uap, retval) 130545914Smckusick struct proc *p; 130642441Smckusick register struct args { 13077701Ssam int fd; 13087701Ssam int fmode; 130942441Smckusick } *uap; 131042441Smckusick int *retval; 131142441Smckusick { 131253548Sheideman USES_VOP_LOCK; 131353548Sheideman USES_VOP_SETATTR; 131453548Sheideman USES_VOP_UNLOCK; 131537741Smckusick struct vattr vattr; 131637741Smckusick struct vnode *vp; 131737741Smckusick struct file *fp; 131837741Smckusick int error; 13197701Ssam 132045914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 132147540Skarels return (error); 132237741Smckusick vp = (struct vnode *)fp->f_data; 132337741Smckusick VOP_LOCK(vp); 132441400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 132537741Smckusick error = EROFS; 132637741Smckusick goto out; 13277439Sroot } 132845785Sbostic VATTR_NULL(&vattr); 132945785Sbostic vattr.va_mode = uap->fmode & 07777; 133052192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 133148026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 133237741Smckusick out: 133337741Smckusick VOP_UNLOCK(vp); 133447540Skarels return (error); 13355992Swnj } 13365992Swnj 13379167Ssam /* 13389167Ssam * Set ownership given a path name. 13399167Ssam */ 134042441Smckusick /* ARGSUSED */ 134142441Smckusick chown(p, uap, retval) 134245914Smckusick struct proc *p; 134342441Smckusick register struct args { 13446254Sroot char *fname; 13456254Sroot int uid; 13466254Sroot int gid; 134742441Smckusick } *uap; 134842441Smckusick int *retval; 134942441Smckusick { 135053548Sheideman USES_VOP_SETATTR; 135137741Smckusick register struct vnode *vp; 135237741Smckusick struct vattr vattr; 135337741Smckusick int error; 135447540Skarels struct nameidata nd; 135537Sbill 135652322Smckusick NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 135752322Smckusick if (error = namei(&nd)) 135847540Skarels return (error); 135952322Smckusick vp = nd.ni_vp; 136041400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 136137741Smckusick error = EROFS; 136237741Smckusick goto out; 136337741Smckusick } 136445785Sbostic VATTR_NULL(&vattr); 136545785Sbostic vattr.va_uid = uap->uid; 136645785Sbostic vattr.va_gid = uap->gid; 136752192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 136848026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 136937741Smckusick out: 137037741Smckusick vput(vp); 137147540Skarels return (error); 13727701Ssam } 13737439Sroot 13749167Ssam /* 13759167Ssam * Set ownership given a file descriptor. 13769167Ssam */ 137742441Smckusick /* ARGSUSED */ 137842441Smckusick fchown(p, uap, retval) 137945914Smckusick struct proc *p; 138042441Smckusick register struct args { 13817701Ssam int fd; 13827701Ssam int uid; 13837701Ssam int gid; 138442441Smckusick } *uap; 138542441Smckusick int *retval; 138642441Smckusick { 138753548Sheideman USES_VOP_LOCK; 138853548Sheideman USES_VOP_SETATTR; 138953548Sheideman USES_VOP_UNLOCK; 139037741Smckusick struct vattr vattr; 139137741Smckusick struct vnode *vp; 139237741Smckusick struct file *fp; 139337741Smckusick int error; 13947701Ssam 139545914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 139647540Skarels return (error); 139737741Smckusick vp = (struct vnode *)fp->f_data; 139837741Smckusick VOP_LOCK(vp); 139941400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 140037741Smckusick error = EROFS; 140137741Smckusick goto out; 140237741Smckusick } 140345785Sbostic VATTR_NULL(&vattr); 140445785Sbostic vattr.va_uid = uap->uid; 140545785Sbostic vattr.va_gid = uap->gid; 140652192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 140748026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 140837741Smckusick out: 140937741Smckusick VOP_UNLOCK(vp); 141047540Skarels return (error); 14117701Ssam } 14127701Ssam 141342441Smckusick /* 141442441Smckusick * Set the access and modification times of a file. 141542441Smckusick */ 141642441Smckusick /* ARGSUSED */ 141742441Smckusick utimes(p, uap, retval) 141845914Smckusick struct proc *p; 141942441Smckusick register struct args { 142011811Ssam char *fname; 142111811Ssam struct timeval *tptr; 142242441Smckusick } *uap; 142342441Smckusick int *retval; 142442441Smckusick { 142553548Sheideman USES_VOP_SETATTR; 142637741Smckusick register struct vnode *vp; 142711811Ssam struct timeval tv[2]; 142837741Smckusick struct vattr vattr; 142937741Smckusick int error; 143047540Skarels struct nameidata nd; 143111811Ssam 143237741Smckusick if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv))) 143347540Skarels return (error); 143452322Smckusick NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 143552322Smckusick if (error = namei(&nd)) 143647540Skarels return (error); 143752322Smckusick vp = nd.ni_vp; 143841400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 143937741Smckusick error = EROFS; 144037741Smckusick goto out; 144121015Smckusick } 144245785Sbostic VATTR_NULL(&vattr); 144354100Smckusick vattr.va_atime.ts_sec = tv[0].tv_sec; 144454100Smckusick vattr.va_atime.ts_nsec = tv[0].tv_usec * 1000; 144554100Smckusick vattr.va_mtime.ts_sec = tv[1].tv_sec; 144654100Smckusick vattr.va_mtime.ts_nsec = tv[1].tv_usec * 1000; 144752192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 144848026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 144937741Smckusick out: 145037741Smckusick vput(vp); 145147540Skarels return (error); 145211811Ssam } 145311811Ssam 145453468Smckusick #ifdef COMPAT_43 14559167Ssam /* 14569167Ssam * Truncate a file given its path name. 14579167Ssam */ 145842441Smckusick /* ARGSUSED */ 145942441Smckusick truncate(p, uap, retval) 146045914Smckusick struct proc *p; 146142441Smckusick register struct args { 14627701Ssam char *fname; 146353468Smckusick long length; 146453468Smckusick } *uap; 146553468Smckusick int *retval; 146653468Smckusick { 146753468Smckusick struct nargs { 146853468Smckusick char *fname; 146926473Skarels off_t length; 147053468Smckusick } nuap; 147153468Smckusick 147253468Smckusick nuap.fname = uap->fname; 147353468Smckusick nuap.length = uap->length; 147453759Smckusick return (__truncate(p, &nuap, retval)); 147553468Smckusick } 147653468Smckusick 147753468Smckusick /* 147853468Smckusick * Truncate a file given a file descriptor. 147953468Smckusick */ 148053468Smckusick /* ARGSUSED */ 148153468Smckusick ftruncate(p, uap, retval) 148253468Smckusick struct proc *p; 148353468Smckusick register struct args { 148453468Smckusick int fd; 148553468Smckusick long length; 148642441Smckusick } *uap; 148742441Smckusick int *retval; 148842441Smckusick { 148953468Smckusick struct nargs { 149053468Smckusick int fd; 149153468Smckusick off_t length; 149253468Smckusick } nuap; 149353468Smckusick 149453468Smckusick nuap.fd = uap->fd; 149553468Smckusick nuap.length = uap->length; 149653759Smckusick return (__ftruncate(p, &nuap, retval)); 149753468Smckusick } 149853468Smckusick #endif /* COMPAT_43 */ 149953468Smckusick 150053468Smckusick /* 150153468Smckusick * Truncate a file given its path name. 150253468Smckusick */ 150353468Smckusick /* ARGSUSED */ 150453759Smckusick __truncate(p, uap, retval) 150553468Smckusick struct proc *p; 150653468Smckusick register struct args { 150753468Smckusick char *fname; 150853468Smckusick off_t length; 150953468Smckusick } *uap; 151053468Smckusick int *retval; 151153468Smckusick { 151253548Sheideman USES_VOP_ACCESS; 151353548Sheideman USES_VOP_SETATTR; 151437741Smckusick register struct vnode *vp; 151537741Smckusick struct vattr vattr; 151637741Smckusick int error; 151747540Skarels struct nameidata nd; 15187701Ssam 151952322Smckusick NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 152052322Smckusick if (error = namei(&nd)) 152147540Skarels return (error); 152252322Smckusick vp = nd.ni_vp; 152337741Smckusick if (vp->v_type == VDIR) { 152437741Smckusick error = EISDIR; 152537741Smckusick goto out; 15267701Ssam } 152738399Smckusick if ((error = vn_writechk(vp)) || 152848026Smckusick (error = VOP_ACCESS(vp, VWRITE, p->p_ucred, p))) 152937741Smckusick goto out; 153045785Sbostic VATTR_NULL(&vattr); 153145785Sbostic vattr.va_size = uap->length; 153252192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 153348026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 153437741Smckusick out: 153537741Smckusick vput(vp); 153647540Skarels return (error); 15377701Ssam } 15387701Ssam 15399167Ssam /* 15409167Ssam * Truncate a file given a file descriptor. 15419167Ssam */ 154242441Smckusick /* ARGSUSED */ 154353759Smckusick __ftruncate(p, uap, retval) 154445914Smckusick struct proc *p; 154542441Smckusick register struct args { 15467701Ssam int fd; 154726473Skarels off_t length; 154842441Smckusick } *uap; 154942441Smckusick int *retval; 155042441Smckusick { 155153548Sheideman USES_VOP_LOCK; 155253548Sheideman USES_VOP_SETATTR; 155353548Sheideman USES_VOP_UNLOCK; 155437741Smckusick struct vattr vattr; 155537741Smckusick struct vnode *vp; 15567701Ssam struct file *fp; 155737741Smckusick int error; 15587701Ssam 155945914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 156047540Skarels return (error); 156137741Smckusick if ((fp->f_flag & FWRITE) == 0) 156247540Skarels return (EINVAL); 156337741Smckusick vp = (struct vnode *)fp->f_data; 156437741Smckusick VOP_LOCK(vp); 156537741Smckusick if (vp->v_type == VDIR) { 156637741Smckusick error = EISDIR; 156737741Smckusick goto out; 15687701Ssam } 156938399Smckusick if (error = vn_writechk(vp)) 157037741Smckusick goto out; 157145785Sbostic VATTR_NULL(&vattr); 157245785Sbostic vattr.va_size = uap->length; 157352192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 157448026Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred, p); 157537741Smckusick out: 157637741Smckusick VOP_UNLOCK(vp); 157747540Skarels return (error); 15787701Ssam } 15797701Ssam 15809167Ssam /* 15819167Ssam * Synch an open file. 15829167Ssam */ 158342441Smckusick /* ARGSUSED */ 158442441Smckusick fsync(p, uap, retval) 158545914Smckusick struct proc *p; 158642441Smckusick struct args { 158742441Smckusick int fd; 158842441Smckusick } *uap; 158942441Smckusick int *retval; 15909167Ssam { 159153548Sheideman USES_VOP_FSYNC; 159253548Sheideman USES_VOP_LOCK; 159353548Sheideman USES_VOP_UNLOCK; 159439592Smckusick register struct vnode *vp; 15959167Ssam struct file *fp; 159637741Smckusick int error; 15979167Ssam 159845914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 159947540Skarels return (error); 160039592Smckusick vp = (struct vnode *)fp->f_data; 160139592Smckusick VOP_LOCK(vp); 160248026Smckusick error = VOP_FSYNC(vp, fp->f_flag, fp->f_cred, MNT_WAIT, p); 160339592Smckusick VOP_UNLOCK(vp); 160447540Skarels return (error); 16059167Ssam } 16069167Ssam 16079167Ssam /* 16089167Ssam * Rename system call. 16099167Ssam * 16109167Ssam * Source and destination must either both be directories, or both 16119167Ssam * not be directories. If target is a directory, it must be empty. 16129167Ssam */ 161342441Smckusick /* ARGSUSED */ 161442441Smckusick rename(p, uap, retval) 161545914Smckusick struct proc *p; 161642441Smckusick register struct args { 16177701Ssam char *from; 16187701Ssam char *to; 161942441Smckusick } *uap; 162042441Smckusick int *retval; 162142441Smckusick { 162253548Sheideman USES_VOP_ABORTOP; 162353548Sheideman USES_VOP_RENAME; 162437741Smckusick register struct vnode *tvp, *fvp, *tdvp; 162549735Smckusick struct nameidata fromnd, tond; 162637741Smckusick int error; 16277701Ssam 162852322Smckusick NDINIT(&fromnd, DELETE, WANTPARENT | SAVESTART, UIO_USERSPACE, 162952322Smckusick uap->from, p); 163052322Smckusick if (error = namei(&fromnd)) 163147540Skarels return (error); 163249735Smckusick fvp = fromnd.ni_vp; 163352322Smckusick NDINIT(&tond, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART, 163452322Smckusick UIO_USERSPACE, uap->to, p); 163552322Smckusick if (error = namei(&tond)) { 163652230Sheideman VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 163749735Smckusick vrele(fromnd.ni_dvp); 163842465Smckusick vrele(fvp); 163942465Smckusick goto out1; 164042465Smckusick } 164137741Smckusick tdvp = tond.ni_dvp; 164237741Smckusick tvp = tond.ni_vp; 164337741Smckusick if (tvp != NULL) { 164437741Smckusick if (fvp->v_type == VDIR && tvp->v_type != VDIR) { 164539242Sbostic error = ENOTDIR; 164637741Smckusick goto out; 164737741Smckusick } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) { 164839242Sbostic error = EISDIR; 164937741Smckusick goto out; 16509167Ssam } 16519167Ssam } 165239286Smckusick if (fvp == tdvp) 165337741Smckusick error = EINVAL; 165439286Smckusick /* 165549735Smckusick * If source is the same as the destination (that is the 165649735Smckusick * same inode number with the same name in the same directory), 165739286Smckusick * then there is nothing to do. 165839286Smckusick */ 165949735Smckusick if (fvp == tvp && fromnd.ni_dvp == tdvp && 166052322Smckusick fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen && 166152322Smckusick !bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr, 166252322Smckusick fromnd.ni_cnd.cn_namelen)) 166339286Smckusick error = -1; 166437741Smckusick out: 166542465Smckusick if (!error) { 166652192Smckusick LEASE_CHECK(tdvp, p, p->p_ucred, LEASE_WRITE); 166752192Smckusick if (fromnd.ni_dvp != tdvp) 166852192Smckusick LEASE_CHECK(fromnd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 166952192Smckusick if (tvp) 167052192Smckusick LEASE_CHECK(tvp, p, p->p_ucred, LEASE_WRITE); 167152230Sheideman error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd, 167252230Sheideman tond.ni_dvp, tond.ni_vp, &tond.ni_cnd); 167342465Smckusick } else { 167452230Sheideman VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd); 167543344Smckusick if (tdvp == tvp) 167643344Smckusick vrele(tdvp); 167743344Smckusick else 167843344Smckusick vput(tdvp); 167942465Smckusick if (tvp) 168042465Smckusick vput(tvp); 168152230Sheideman VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 168249735Smckusick vrele(fromnd.ni_dvp); 168342465Smckusick vrele(fvp); 16849167Ssam } 168549735Smckusick vrele(tond.ni_startdir); 168652322Smckusick FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI); 168737741Smckusick out1: 168849735Smckusick vrele(fromnd.ni_startdir); 168952322Smckusick FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI); 169039286Smckusick if (error == -1) 169147540Skarels return (0); 169247540Skarels return (error); 16937701Ssam } 16947701Ssam 16957535Sroot /* 169649365Smckusick * Mkdir system call. 169712756Ssam */ 169842441Smckusick /* ARGSUSED */ 169942441Smckusick mkdir(p, uap, retval) 170045914Smckusick struct proc *p; 170142441Smckusick register struct args { 170212756Ssam char *name; 170312756Ssam int dmode; 170442441Smckusick } *uap; 170542441Smckusick int *retval; 170642441Smckusick { 170753548Sheideman USES_VOP_ABORTOP; 170853548Sheideman USES_VOP_MKDIR; 170937741Smckusick register struct vnode *vp; 171037741Smckusick struct vattr vattr; 171137741Smckusick int error; 171247540Skarels struct nameidata nd; 171312756Ssam 171452322Smckusick NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->name, p); 171552322Smckusick if (error = namei(&nd)) 171647540Skarels return (error); 171752322Smckusick vp = nd.ni_vp; 171837741Smckusick if (vp != NULL) { 171952322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 172052322Smckusick if (nd.ni_dvp == vp) 172152322Smckusick vrele(nd.ni_dvp); 172243344Smckusick else 172352322Smckusick vput(nd.ni_dvp); 172442465Smckusick vrele(vp); 172547540Skarels return (EEXIST); 172612756Ssam } 172741362Smckusick VATTR_NULL(&vattr); 172837741Smckusick vattr.va_type = VDIR; 172945914Smckusick vattr.va_mode = (uap->dmode & 0777) &~ p->p_fd->fd_cmask; 173052322Smckusick LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 173152322Smckusick error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr); 173238145Smckusick if (!error) 173352322Smckusick vput(nd.ni_vp); 173447540Skarels return (error); 173512756Ssam } 173612756Ssam 173712756Ssam /* 173812756Ssam * Rmdir system call. 173912756Ssam */ 174042441Smckusick /* ARGSUSED */ 174142441Smckusick rmdir(p, uap, retval) 174245914Smckusick struct proc *p; 174342441Smckusick struct args { 174442441Smckusick char *name; 174542441Smckusick } *uap; 174642441Smckusick int *retval; 174712756Ssam { 174853548Sheideman USES_VOP_ABORTOP; 174953548Sheideman USES_VOP_RMDIR; 175037741Smckusick register struct vnode *vp; 175137741Smckusick int error; 175247540Skarels struct nameidata nd; 175312756Ssam 175452322Smckusick NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE, uap->name, p); 175552322Smckusick if (error = namei(&nd)) 175647540Skarels return (error); 175752322Smckusick vp = nd.ni_vp; 175837741Smckusick if (vp->v_type != VDIR) { 175937741Smckusick error = ENOTDIR; 176012756Ssam goto out; 176112756Ssam } 176212756Ssam /* 176337741Smckusick * No rmdir "." please. 176412756Ssam */ 176552322Smckusick if (nd.ni_dvp == vp) { 176637741Smckusick error = EINVAL; 176712756Ssam goto out; 176812756Ssam } 176912756Ssam /* 177049365Smckusick * The root of a mounted filesystem cannot be deleted. 177112756Ssam */ 177237741Smckusick if (vp->v_flag & VROOT) 177337741Smckusick error = EBUSY; 177412756Ssam out: 177542465Smckusick if (!error) { 177652322Smckusick LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 177752192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 177852322Smckusick error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); 177942465Smckusick } else { 178052322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 178152322Smckusick if (nd.ni_dvp == vp) 178252322Smckusick vrele(nd.ni_dvp); 178343344Smckusick else 178452322Smckusick vput(nd.ni_dvp); 178542465Smckusick vput(vp); 178642465Smckusick } 178747540Skarels return (error); 178812756Ssam } 178912756Ssam 179037741Smckusick /* 179149365Smckusick * Read a block of directory entries in a file system independent format. 179237741Smckusick */ 179342441Smckusick getdirentries(p, uap, retval) 179445914Smckusick struct proc *p; 179542441Smckusick register struct args { 179637741Smckusick int fd; 179737741Smckusick char *buf; 179837741Smckusick unsigned count; 179937741Smckusick long *basep; 180042441Smckusick } *uap; 180142441Smckusick int *retval; 180242441Smckusick { 180353548Sheideman USES_VOP_LOCK; 180453548Sheideman USES_VOP_READDIR; 180553548Sheideman USES_VOP_UNLOCK; 180639592Smckusick register struct vnode *vp; 180716540Ssam struct file *fp; 180837741Smckusick struct uio auio; 180937741Smckusick struct iovec aiov; 181038129Smckusick off_t off; 181140321Smckusick int error, eofflag; 181212756Ssam 181345914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 181447540Skarels return (error); 181537741Smckusick if ((fp->f_flag & FREAD) == 0) 181647540Skarels return (EBADF); 181739592Smckusick vp = (struct vnode *)fp->f_data; 181839592Smckusick if (vp->v_type != VDIR) 181947540Skarels return (EINVAL); 182037741Smckusick aiov.iov_base = uap->buf; 182137741Smckusick aiov.iov_len = uap->count; 182237741Smckusick auio.uio_iov = &aiov; 182337741Smckusick auio.uio_iovcnt = 1; 182437741Smckusick auio.uio_rw = UIO_READ; 182537741Smckusick auio.uio_segflg = UIO_USERSPACE; 182648026Smckusick auio.uio_procp = p; 182737741Smckusick auio.uio_resid = uap->count; 182839592Smckusick VOP_LOCK(vp); 182939592Smckusick auio.uio_offset = off = fp->f_offset; 183040321Smckusick error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag); 183139592Smckusick fp->f_offset = auio.uio_offset; 183239592Smckusick VOP_UNLOCK(vp); 183339592Smckusick if (error) 183447540Skarels return (error); 183539592Smckusick error = copyout((caddr_t)&off, (caddr_t)uap->basep, sizeof(long)); 183642441Smckusick *retval = uap->count - auio.uio_resid; 183747540Skarels return (error); 183812756Ssam } 183912756Ssam 184012756Ssam /* 184149365Smckusick * Set the mode mask for creation of filesystem nodes. 184212756Ssam */ 184342441Smckusick mode_t 184442441Smckusick umask(p, uap, retval) 184545914Smckusick struct proc *p; 184642441Smckusick struct args { 184742441Smckusick int mask; 184842441Smckusick } *uap; 184942441Smckusick int *retval; 185012756Ssam { 185145914Smckusick register struct filedesc *fdp = p->p_fd; 185212756Ssam 185345914Smckusick *retval = fdp->fd_cmask; 185445914Smckusick fdp->fd_cmask = uap->mask & 07777; 185547540Skarels return (0); 185612756Ssam } 185737741Smckusick 185839566Smarc /* 185939566Smarc * Void all references to file by ripping underlying filesystem 186039566Smarc * away from vnode. 186139566Smarc */ 186242441Smckusick /* ARGSUSED */ 186342441Smckusick revoke(p, uap, retval) 186445914Smckusick struct proc *p; 186542441Smckusick register struct args { 186639566Smarc char *fname; 186742441Smckusick } *uap; 186842441Smckusick int *retval; 186942441Smckusick { 187053548Sheideman USES_VOP_GETATTR; 187139566Smarc register struct vnode *vp; 187239566Smarc struct vattr vattr; 187339566Smarc int error; 187447540Skarels struct nameidata nd; 187539566Smarc 187652322Smckusick NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->fname, p); 187752322Smckusick if (error = namei(&nd)) 187847540Skarels return (error); 187952322Smckusick vp = nd.ni_vp; 188039566Smarc if (vp->v_type != VCHR && vp->v_type != VBLK) { 188139566Smarc error = EINVAL; 188239566Smarc goto out; 188339566Smarc } 188448026Smckusick if (error = VOP_GETATTR(vp, &vattr, p->p_ucred, p)) 188539566Smarc goto out; 188647540Skarels if (p->p_ucred->cr_uid != vattr.va_uid && 188747540Skarels (error = suser(p->p_ucred, &p->p_acflag))) 188839566Smarc goto out; 188939805Smckusick if (vp->v_usecount > 1 || (vp->v_flag & VALIASED)) 189039632Smckusick vgoneall(vp); 189139566Smarc out: 189239566Smarc vrele(vp); 189347540Skarels return (error); 189439566Smarc } 189539566Smarc 189649365Smckusick /* 189749365Smckusick * Convert a user file descriptor to a kernel file entry. 189849365Smckusick */ 189945914Smckusick getvnode(fdp, fdes, fpp) 190045914Smckusick struct filedesc *fdp; 190137741Smckusick struct file **fpp; 190237741Smckusick int fdes; 190337741Smckusick { 190437741Smckusick struct file *fp; 190537741Smckusick 190647540Skarels if ((unsigned)fdes >= fdp->fd_nfiles || 190747688Skarels (fp = fdp->fd_ofiles[fdes]) == NULL) 190837741Smckusick return (EBADF); 190937741Smckusick if (fp->f_type != DTYPE_VNODE) 191037741Smckusick return (EINVAL); 191137741Smckusick *fpp = fp; 191237741Smckusick return (0); 191337741Smckusick } 1914