123405Smckusick /* 237741Smckusick * Copyright (c) 1989 The Regents of the University of California. 337741Smckusick * All rights reserved. 423405Smckusick * 544459Sbostic * %sccs.include.redist.c% 637741Smckusick * 7*52230Sheideman * @(#)vfs_syscalls.c 7.76 (Berkeley) 01/22/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" 2237Sbill 23*52230Sheideman /* NEEDSWORK: debugging */ 24*52230Sheideman #define CURCOUNT (curproc?curproc->p_spare[2]:0) 25*52230Sheideman #define CHECKPOINT int oldrefcount=CURCOUNT; 26*52230Sheideman #define CHECKCHECK(F) if (oldrefcount!=CURCOUNT) { printf("REFCOUNT: %s, old=%d, new=%d\n", (F), oldrefcount, CURCOUNT); } 27*52230Sheideman 2837741Smckusick /* 2937741Smckusick * Virtual File System System Calls 3037741Smckusick */ 3112756Ssam 329167Ssam /* 3349365Smckusick * Mount system call. 349167Ssam */ 3542441Smckusick /* ARGSUSED */ 3642441Smckusick mount(p, uap, retval) 3745914Smckusick struct proc *p; 3842441Smckusick register struct args { 3937741Smckusick int type; 4037741Smckusick char *dir; 4137741Smckusick int flags; 4237741Smckusick caddr_t data; 4342441Smckusick } *uap; 4442441Smckusick int *retval; 4542441Smckusick { 4647540Skarels register struct nameidata *ndp; 4739335Smckusick register struct vnode *vp; 4839335Smckusick register struct mount *mp; 4940111Smckusick int error, flag; 5047540Skarels struct nameidata nd; 516254Sroot 5237741Smckusick /* 5337741Smckusick * Must be super user 5437741Smckusick */ 5547540Skarels if (error = suser(p->p_ucred, &p->p_acflag)) 5647540Skarels return (error); 5737741Smckusick /* 5837741Smckusick * Get vnode to be covered 5937741Smckusick */ 6047540Skarels ndp = &nd; 6137741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 6237741Smckusick ndp->ni_segflg = UIO_USERSPACE; 6337741Smckusick ndp->ni_dirp = uap->dir; 6447540Skarels if (error = namei(ndp, p)) 6547540Skarels return (error); 6637741Smckusick vp = ndp->ni_vp; 6741400Smckusick if (uap->flags & MNT_UPDATE) { 6839335Smckusick if ((vp->v_flag & VROOT) == 0) { 6939335Smckusick vput(vp); 7047540Skarels return (EINVAL); 7139335Smckusick } 7239335Smckusick mp = vp->v_mount; 7339335Smckusick /* 7439335Smckusick * We allow going from read-only to read-write, 7539335Smckusick * but not from read-write to read-only. 7639335Smckusick */ 7741400Smckusick if ((mp->mnt_flag & MNT_RDONLY) == 0 && 7841400Smckusick (uap->flags & MNT_RDONLY) != 0) { 7939335Smckusick vput(vp); 8047540Skarels return (EOPNOTSUPP); /* Needs translation */ 8139335Smckusick } 8241400Smckusick flag = mp->mnt_flag; 8341400Smckusick mp->mnt_flag |= MNT_UPDATE; 8439335Smckusick VOP_UNLOCK(vp); 8539335Smckusick goto update; 8639335Smckusick } 8739665Smckusick vinvalbuf(vp, 1); 8839805Smckusick if (vp->v_usecount != 1) { 8937741Smckusick vput(vp); 9047540Skarels return (EBUSY); 9137741Smckusick } 9237741Smckusick if (vp->v_type != VDIR) { 9337741Smckusick vput(vp); 9447540Skarels return (ENOTDIR); 9537741Smckusick } 9639741Smckusick if ((unsigned long)uap->type > MOUNT_MAXTYPE || 9737741Smckusick vfssw[uap->type] == (struct vfsops *)0) { 9837741Smckusick vput(vp); 9947540Skarels return (ENODEV); 10037741Smckusick } 10137741Smckusick 10237741Smckusick /* 10339335Smckusick * Allocate and initialize the file system. 10437741Smckusick */ 10537741Smckusick mp = (struct mount *)malloc((u_long)sizeof(struct mount), 10637741Smckusick M_MOUNT, M_WAITOK); 10741400Smckusick mp->mnt_op = vfssw[uap->type]; 10841400Smckusick mp->mnt_flag = 0; 10941400Smckusick mp->mnt_mounth = NULLVP; 11039335Smckusick if (error = vfs_lock(mp)) { 11139335Smckusick free((caddr_t)mp, M_MOUNT); 11239335Smckusick vput(vp); 11347540Skarels return (error); 11439335Smckusick } 11539335Smckusick if (vp->v_mountedhere != (struct mount *)0) { 11639335Smckusick vfs_unlock(mp); 11739335Smckusick free((caddr_t)mp, M_MOUNT); 11839335Smckusick vput(vp); 11947540Skarels return (EBUSY); 12039335Smckusick } 12139335Smckusick vp->v_mountedhere = mp; 12241400Smckusick mp->mnt_vnodecovered = vp; 12339335Smckusick update: 12439335Smckusick /* 12539335Smckusick * Set the mount level flags. 12639335Smckusick */ 12741400Smckusick if (uap->flags & MNT_RDONLY) 12841400Smckusick mp->mnt_flag |= MNT_RDONLY; 12939335Smckusick else 13041400Smckusick mp->mnt_flag &= ~MNT_RDONLY; 13141400Smckusick if (uap->flags & MNT_NOSUID) 13241400Smckusick mp->mnt_flag |= MNT_NOSUID; 13339335Smckusick else 13441400Smckusick mp->mnt_flag &= ~MNT_NOSUID; 13541400Smckusick if (uap->flags & MNT_NOEXEC) 13641400Smckusick mp->mnt_flag |= MNT_NOEXEC; 13739335Smckusick else 13841400Smckusick mp->mnt_flag &= ~MNT_NOEXEC; 13941400Smckusick if (uap->flags & MNT_NODEV) 14041400Smckusick mp->mnt_flag |= MNT_NODEV; 14139335Smckusick else 14241400Smckusick mp->mnt_flag &= ~MNT_NODEV; 14341400Smckusick if (uap->flags & MNT_SYNCHRONOUS) 14441400Smckusick mp->mnt_flag |= MNT_SYNCHRONOUS; 14539335Smckusick else 14641400Smckusick mp->mnt_flag &= ~MNT_SYNCHRONOUS; 14739335Smckusick /* 14839335Smckusick * Mount the filesystem. 14939335Smckusick */ 15048026Smckusick error = VFS_MOUNT(mp, uap->dir, uap->data, ndp, p); 15141400Smckusick if (mp->mnt_flag & MNT_UPDATE) { 15241400Smckusick mp->mnt_flag &= ~MNT_UPDATE; 15339335Smckusick vrele(vp); 15440111Smckusick if (error) 15541400Smckusick mp->mnt_flag = flag; 15647540Skarels return (error); 15739335Smckusick } 15840110Smckusick /* 15940110Smckusick * Put the new filesystem on the mount list after root. 16040110Smckusick */ 16141400Smckusick mp->mnt_next = rootfs->mnt_next; 16241400Smckusick mp->mnt_prev = rootfs; 16341400Smckusick rootfs->mnt_next = mp; 16441400Smckusick mp->mnt_next->mnt_prev = mp; 16537741Smckusick cache_purge(vp); 16637741Smckusick if (!error) { 16739335Smckusick VOP_UNLOCK(vp); 16837741Smckusick vfs_unlock(mp); 16948026Smckusick error = VFS_START(mp, 0, p); 17037741Smckusick } else { 17137741Smckusick vfs_remove(mp); 17237741Smckusick free((caddr_t)mp, M_MOUNT); 17339335Smckusick vput(vp); 17437741Smckusick } 17547540Skarels return (error); 1766254Sroot } 1776254Sroot 1789167Ssam /* 17937741Smckusick * Unmount system call. 18037741Smckusick * 18137741Smckusick * Note: unmount takes a path to the vnode mounted on as argument, 18237741Smckusick * not special file (as before). 1839167Ssam */ 18442441Smckusick /* ARGSUSED */ 18542441Smckusick unmount(p, uap, retval) 18645914Smckusick struct proc *p; 18742441Smckusick register struct args { 18837741Smckusick char *pathp; 18937741Smckusick int flags; 19042441Smckusick } *uap; 19142441Smckusick int *retval; 19242441Smckusick { 19337741Smckusick register struct vnode *vp; 19447540Skarels register struct nameidata *ndp; 19539356Smckusick struct mount *mp; 19637741Smckusick int error; 19747540Skarels struct nameidata nd; 1986254Sroot 19937741Smckusick /* 20037741Smckusick * Must be super user 20137741Smckusick */ 20247540Skarels if (error = suser(p->p_ucred, &p->p_acflag)) 20347540Skarels return (error); 20437741Smckusick 20547540Skarels ndp = &nd; 20637741Smckusick ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW; 20737741Smckusick ndp->ni_segflg = UIO_USERSPACE; 20837741Smckusick ndp->ni_dirp = uap->pathp; 20947540Skarels if (error = namei(ndp, p)) 21047540Skarels return (error); 21137741Smckusick vp = ndp->ni_vp; 21237741Smckusick /* 21337741Smckusick * Must be the root of the filesystem 21437741Smckusick */ 21537741Smckusick if ((vp->v_flag & VROOT) == 0) { 21637741Smckusick vput(vp); 21747540Skarels return (EINVAL); 21837741Smckusick } 21937741Smckusick mp = vp->v_mount; 22037741Smckusick vput(vp); 22148026Smckusick return (dounmount(mp, uap->flags, p)); 22239356Smckusick } 22339356Smckusick 22439356Smckusick /* 22539356Smckusick * Do an unmount. 22639356Smckusick */ 22748026Smckusick dounmount(mp, flags, p) 22839356Smckusick register struct mount *mp; 22939356Smckusick int flags; 23048026Smckusick struct proc *p; 23139356Smckusick { 23239356Smckusick struct vnode *coveredvp; 23339356Smckusick int error; 23439356Smckusick 23541400Smckusick coveredvp = mp->mnt_vnodecovered; 23641298Smckusick if (vfs_busy(mp)) 23741298Smckusick return (EBUSY); 23841400Smckusick mp->mnt_flag |= MNT_UNMOUNT; 23937741Smckusick if (error = vfs_lock(mp)) 24039356Smckusick return (error); 24137741Smckusick 24245738Smckusick vnode_pager_umount(mp); /* release cached vnodes */ 24337741Smckusick cache_purgevfs(mp); /* remove cache entries for this file sys */ 24441676Smckusick if ((error = VFS_SYNC(mp, MNT_WAIT)) == 0 || (flags & MNT_FORCE)) 24548026Smckusick error = VFS_UNMOUNT(mp, flags, p); 24641400Smckusick mp->mnt_flag &= ~MNT_UNMOUNT; 24741298Smckusick vfs_unbusy(mp); 24837741Smckusick if (error) { 24937741Smckusick vfs_unlock(mp); 25037741Smckusick } else { 25137741Smckusick vrele(coveredvp); 25237741Smckusick vfs_remove(mp); 25337741Smckusick free((caddr_t)mp, M_MOUNT); 25437741Smckusick } 25539356Smckusick return (error); 2566254Sroot } 2576254Sroot 2589167Ssam /* 25937741Smckusick * Sync system call. 26037741Smckusick * Sync each mounted filesystem. 2619167Ssam */ 26239491Smckusick /* ARGSUSED */ 26342441Smckusick sync(p, uap, retval) 26445914Smckusick struct proc *p; 26547540Skarels void *uap; 26642441Smckusick int *retval; 2676254Sroot { 26837741Smckusick register struct mount *mp; 26941298Smckusick struct mount *omp; 27037741Smckusick 27137741Smckusick mp = rootfs; 27237741Smckusick do { 27340343Smckusick /* 27440343Smckusick * The lock check below is to avoid races with mount 27540343Smckusick * and unmount. 27640343Smckusick */ 27741400Smckusick if ((mp->mnt_flag & (MNT_MLOCK|MNT_RDONLY|MNT_MPBUSY)) == 0 && 27841298Smckusick !vfs_busy(mp)) { 27937741Smckusick VFS_SYNC(mp, MNT_NOWAIT); 28041298Smckusick omp = mp; 28141400Smckusick mp = mp->mnt_next; 28241298Smckusick vfs_unbusy(omp); 28341298Smckusick } else 28441400Smckusick mp = mp->mnt_next; 28537741Smckusick } while (mp != rootfs); 28647688Skarels return (0); 28737741Smckusick } 28837741Smckusick 28937741Smckusick /* 29049365Smckusick * Operate on filesystem quotas. 29141298Smckusick */ 29242441Smckusick /* ARGSUSED */ 29342441Smckusick quotactl(p, uap, retval) 29445914Smckusick struct proc *p; 29542441Smckusick register struct args { 29641298Smckusick char *path; 29741298Smckusick int cmd; 29841298Smckusick int uid; 29941298Smckusick caddr_t arg; 30042441Smckusick } *uap; 30142441Smckusick int *retval; 30242441Smckusick { 30341298Smckusick register struct mount *mp; 30447540Skarels register struct nameidata *ndp; 30541298Smckusick int error; 30647540Skarels struct nameidata nd; 30741298Smckusick 30847540Skarels ndp = &nd; 30941298Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW; 31041298Smckusick ndp->ni_segflg = UIO_USERSPACE; 31141298Smckusick ndp->ni_dirp = uap->path; 31247540Skarels if (error = namei(ndp, p)) 31347540Skarels return (error); 31441298Smckusick mp = ndp->ni_vp->v_mount; 31541298Smckusick vrele(ndp->ni_vp); 31648026Smckusick return (VFS_QUOTACTL(mp, uap->cmd, uap->uid, uap->arg, p)); 31741298Smckusick } 31841298Smckusick 31941298Smckusick /* 32049365Smckusick * Get filesystem statistics. 32137741Smckusick */ 32242441Smckusick /* ARGSUSED */ 32342441Smckusick statfs(p, uap, retval) 32445914Smckusick struct proc *p; 32542441Smckusick register struct args { 32637741Smckusick char *path; 32737741Smckusick struct statfs *buf; 32842441Smckusick } *uap; 32942441Smckusick int *retval; 33042441Smckusick { 33139464Smckusick register struct mount *mp; 33247540Skarels register struct nameidata *ndp; 33340343Smckusick register struct statfs *sp; 33437741Smckusick int error; 33547540Skarels struct nameidata nd; 33637741Smckusick 33747540Skarels ndp = &nd; 33839544Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW; 33937741Smckusick ndp->ni_segflg = UIO_USERSPACE; 34037741Smckusick ndp->ni_dirp = uap->path; 34147540Skarels if (error = namei(ndp, p)) 34247540Skarels return (error); 34339544Smckusick mp = ndp->ni_vp->v_mount; 34441400Smckusick sp = &mp->mnt_stat; 34539544Smckusick vrele(ndp->ni_vp); 34648026Smckusick if (error = VFS_STATFS(mp, sp, p)) 34747540Skarels return (error); 34841400Smckusick sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 34947540Skarels return (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp))); 35037741Smckusick } 35137741Smckusick 35242441Smckusick /* 35349365Smckusick * Get filesystem statistics. 35442441Smckusick */ 35542441Smckusick /* ARGSUSED */ 35642441Smckusick fstatfs(p, uap, retval) 35745914Smckusick struct proc *p; 35842441Smckusick register struct args { 35937741Smckusick int fd; 36037741Smckusick struct statfs *buf; 36142441Smckusick } *uap; 36242441Smckusick int *retval; 36342441Smckusick { 36437741Smckusick struct file *fp; 36539464Smckusick struct mount *mp; 36640343Smckusick register struct statfs *sp; 36737741Smckusick int error; 36837741Smckusick 36945914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 37047540Skarels return (error); 37139464Smckusick mp = ((struct vnode *)fp->f_data)->v_mount; 37241400Smckusick sp = &mp->mnt_stat; 37348026Smckusick if (error = VFS_STATFS(mp, sp, p)) 37447540Skarels return (error); 37541400Smckusick sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 37647540Skarels return (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp))); 37737741Smckusick } 37837741Smckusick 37937741Smckusick /* 38049365Smckusick * Get statistics on all filesystems. 38138270Smckusick */ 38242441Smckusick getfsstat(p, uap, retval) 38345914Smckusick struct proc *p; 38442441Smckusick register struct args { 38538270Smckusick struct statfs *buf; 38638270Smckusick long bufsize; 38740343Smckusick int flags; 38842441Smckusick } *uap; 38942441Smckusick int *retval; 39042441Smckusick { 39138270Smckusick register struct mount *mp; 39240343Smckusick register struct statfs *sp; 39339606Smckusick caddr_t sfsp; 39438270Smckusick long count, maxcount, error; 39538270Smckusick 39638270Smckusick maxcount = uap->bufsize / sizeof(struct statfs); 39739606Smckusick sfsp = (caddr_t)uap->buf; 39838270Smckusick mp = rootfs; 39938270Smckusick count = 0; 40038270Smckusick do { 40141400Smckusick if (sfsp && count < maxcount && 40241400Smckusick ((mp->mnt_flag & MNT_MLOCK) == 0)) { 40341400Smckusick sp = &mp->mnt_stat; 40440343Smckusick /* 40540343Smckusick * If MNT_NOWAIT is specified, do not refresh the 40640343Smckusick * fsstat cache. MNT_WAIT overrides MNT_NOWAIT. 40740343Smckusick */ 40840343Smckusick if (((uap->flags & MNT_NOWAIT) == 0 || 40940343Smckusick (uap->flags & MNT_WAIT)) && 41048026Smckusick (error = VFS_STATFS(mp, sp, p))) { 41141400Smckusick mp = mp->mnt_prev; 41239607Smckusick continue; 41339607Smckusick } 41441400Smckusick sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 41540343Smckusick if (error = copyout((caddr_t)sp, sfsp, sizeof(*sp))) 41647540Skarels return (error); 41740343Smckusick sfsp += sizeof(*sp); 41838270Smckusick } 41939606Smckusick count++; 42041400Smckusick mp = mp->mnt_prev; 42138270Smckusick } while (mp != rootfs); 42238270Smckusick if (sfsp && count > maxcount) 42342441Smckusick *retval = maxcount; 42438270Smckusick else 42542441Smckusick *retval = count; 42647540Skarels return (0); 42738270Smckusick } 42838270Smckusick 42938270Smckusick /* 43038259Smckusick * Change current working directory to a given file descriptor. 43138259Smckusick */ 43242441Smckusick /* ARGSUSED */ 43342441Smckusick fchdir(p, uap, retval) 43445914Smckusick struct proc *p; 43542441Smckusick struct args { 43642441Smckusick int fd; 43742441Smckusick } *uap; 43842441Smckusick int *retval; 43938259Smckusick { 44045914Smckusick register struct filedesc *fdp = p->p_fd; 44138259Smckusick register struct vnode *vp; 44238259Smckusick struct file *fp; 44338259Smckusick int error; 44438259Smckusick 44545914Smckusick if (error = getvnode(fdp, uap->fd, &fp)) 44647540Skarels return (error); 44738259Smckusick vp = (struct vnode *)fp->f_data; 44838259Smckusick VOP_LOCK(vp); 44938259Smckusick if (vp->v_type != VDIR) 45038259Smckusick error = ENOTDIR; 45138259Smckusick else 45248026Smckusick error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p); 45338259Smckusick VOP_UNLOCK(vp); 45439860Smckusick if (error) 45547540Skarels return (error); 45639860Smckusick VREF(vp); 45745914Smckusick vrele(fdp->fd_cdir); 45845914Smckusick fdp->fd_cdir = vp; 45947540Skarels return (0); 46038259Smckusick } 46138259Smckusick 46238259Smckusick /* 46337741Smckusick * Change current working directory (``.''). 46437741Smckusick */ 46542441Smckusick /* ARGSUSED */ 46642441Smckusick chdir(p, uap, retval) 46745914Smckusick struct proc *p; 46842441Smckusick struct args { 46942441Smckusick char *fname; 47042441Smckusick } *uap; 47142441Smckusick int *retval; 47237741Smckusick { 47347540Skarels register struct nameidata *ndp; 47445914Smckusick register struct filedesc *fdp = p->p_fd; 47537741Smckusick int error; 47647540Skarels struct nameidata nd; 4776254Sroot 47847540Skarels ndp = &nd; 47937741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 48016694Smckusick ndp->ni_segflg = UIO_USERSPACE; 48116694Smckusick ndp->ni_dirp = uap->fname; 48247540Skarels if (error = chdirec(ndp, p)) 48347540Skarels return (error); 48445914Smckusick vrele(fdp->fd_cdir); 48545914Smckusick fdp->fd_cdir = ndp->ni_vp; 48647540Skarels return (0); 48737741Smckusick } 4886254Sroot 48937741Smckusick /* 49037741Smckusick * Change notion of root (``/'') directory. 49137741Smckusick */ 49242441Smckusick /* ARGSUSED */ 49342441Smckusick chroot(p, uap, retval) 49445914Smckusick struct proc *p; 49542441Smckusick struct args { 49642441Smckusick char *fname; 49742441Smckusick } *uap; 49842441Smckusick int *retval; 49937741Smckusick { 50047540Skarels register struct nameidata *ndp; 50145914Smckusick register struct filedesc *fdp = p->p_fd; 50237741Smckusick int error; 50347540Skarels struct nameidata nd; 50437741Smckusick 50547540Skarels if (error = suser(p->p_ucred, &p->p_acflag)) 50647540Skarels return (error); 50747540Skarels ndp = &nd; 50837741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 50937741Smckusick ndp->ni_segflg = UIO_USERSPACE; 51037741Smckusick ndp->ni_dirp = uap->fname; 51147540Skarels if (error = chdirec(ndp, p)) 51247540Skarels return (error); 51345914Smckusick if (fdp->fd_rdir != NULL) 51445914Smckusick vrele(fdp->fd_rdir); 51545914Smckusick fdp->fd_rdir = ndp->ni_vp; 51647540Skarels return (0); 5176254Sroot } 5186254Sroot 51937Sbill /* 52037741Smckusick * Common routine for chroot and chdir. 52137741Smckusick */ 52247540Skarels chdirec(ndp, p) 52347540Skarels struct nameidata *ndp; 52447540Skarels struct proc *p; 52537741Smckusick { 52637741Smckusick struct vnode *vp; 52737741Smckusick int error; 52837741Smckusick 52947540Skarels if (error = namei(ndp, p)) 53037741Smckusick return (error); 53137741Smckusick vp = ndp->ni_vp; 53237741Smckusick if (vp->v_type != VDIR) 53337741Smckusick error = ENOTDIR; 53437741Smckusick else 53548026Smckusick error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p); 53637741Smckusick VOP_UNLOCK(vp); 53737741Smckusick if (error) 53837741Smckusick vrele(vp); 53937741Smckusick return (error); 54037741Smckusick } 54137741Smckusick 54237741Smckusick /* 5436254Sroot * Open system call. 54442441Smckusick * Check permissions, allocate an open file structure, 54542441Smckusick * and call the device open routine if any. 5466254Sroot */ 54742441Smckusick open(p, uap, retval) 54845914Smckusick struct proc *p; 54942441Smckusick register struct args { 5506254Sroot char *fname; 5517701Ssam int mode; 55212756Ssam int crtmode; 55342441Smckusick } *uap; 55442441Smckusick int *retval; 5556254Sroot { 55647540Skarels struct nameidata *ndp; 55745914Smckusick register struct filedesc *fdp = p->p_fd; 55842441Smckusick register struct file *fp; 55950111Smckusick register struct vnode *vp; 56037741Smckusick int fmode, cmode; 56137741Smckusick struct file *nfp; 56249945Smckusick int type, indx, error; 56349945Smckusick struct flock lf; 56447540Skarels struct nameidata nd; 56537741Smckusick extern struct fileops vnops; 5666254Sroot 56745914Smckusick if (error = falloc(p, &nfp, &indx)) 56847540Skarels return (error); 56937741Smckusick fp = nfp; 57046553Skarels fmode = FFLAGS(uap->mode); 57145914Smckusick cmode = ((uap->crtmode &~ fdp->fd_cmask) & 07777) &~ S_ISVTX; 57247540Skarels ndp = &nd; 57342441Smckusick ndp->ni_segflg = UIO_USERSPACE; 57442441Smckusick ndp->ni_dirp = uap->fname; 57545202Smckusick p->p_dupfd = -indx - 1; /* XXX check for fdopen */ 57647540Skarels if (error = vn_open(ndp, p, fmode, cmode)) { 57749980Smckusick ffree(fp); 57843405Smckusick if (error == ENODEV && /* XXX from fdopen */ 57945202Smckusick p->p_dupfd >= 0 && 58045914Smckusick (error = dupfdopen(fdp, indx, p->p_dupfd, fmode)) == 0) { 58142441Smckusick *retval = indx; 58247540Skarels return (0); 58342441Smckusick } 58440884Smckusick if (error == ERESTART) 58540884Smckusick error = EINTR; 58647688Skarels fdp->fd_ofiles[indx] = NULL; 58747540Skarels return (error); 58812756Ssam } 58950111Smckusick vp = ndp->ni_vp; 59049949Smckusick fp->f_flag = fmode & FMASK; 59149945Smckusick if (fmode & (O_EXLOCK | O_SHLOCK)) { 59249945Smckusick lf.l_whence = SEEK_SET; 59349945Smckusick lf.l_start = 0; 59449945Smckusick lf.l_len = 0; 59549945Smckusick if (fmode & O_EXLOCK) 59649945Smckusick lf.l_type = F_WRLCK; 59749945Smckusick else 59849945Smckusick lf.l_type = F_RDLCK; 59949945Smckusick type = F_FLOCK; 60049945Smckusick if ((fmode & FNONBLOCK) == 0) 60149945Smckusick type |= F_WAIT; 60250111Smckusick if (error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, type)) { 60350111Smckusick VOP_UNLOCK(vp); 60450111Smckusick (void) vn_close(vp, fp->f_flag, fp->f_cred, p); 60549980Smckusick ffree(fp); 60649945Smckusick fdp->fd_ofiles[indx] = NULL; 60749945Smckusick return (error); 60849945Smckusick } 60949949Smckusick fp->f_flag |= FHASLOCK; 61049945Smckusick } 61150111Smckusick VOP_UNLOCK(vp); 61237741Smckusick fp->f_type = DTYPE_VNODE; 61337741Smckusick fp->f_ops = &vnops; 61450111Smckusick fp->f_data = (caddr_t)vp; 61542441Smckusick *retval = indx; 61647540Skarels return (0); 6176254Sroot } 6186254Sroot 61942955Smckusick #ifdef COMPAT_43 6206254Sroot /* 62142441Smckusick * Creat system call. 6226254Sroot */ 62342955Smckusick ocreat(p, uap, retval) 62442441Smckusick struct proc *p; 62542441Smckusick register struct args { 62642441Smckusick char *fname; 62742441Smckusick int fmode; 62842441Smckusick } *uap; 62942441Smckusick int *retval; 6306254Sroot { 63142441Smckusick struct args { 6326254Sroot char *fname; 63342441Smckusick int mode; 63442441Smckusick int crtmode; 63542441Smckusick } openuap; 63642441Smckusick 63742441Smckusick openuap.fname = uap->fname; 63842441Smckusick openuap.crtmode = uap->fmode; 63942441Smckusick openuap.mode = O_WRONLY | O_CREAT | O_TRUNC; 64047540Skarels return (open(p, &openuap, retval)); 64142441Smckusick } 64242955Smckusick #endif /* COMPAT_43 */ 64342441Smckusick 64442441Smckusick /* 64549365Smckusick * Mknod system call. 64642441Smckusick */ 64742441Smckusick /* ARGSUSED */ 64842441Smckusick mknod(p, uap, retval) 64945914Smckusick struct proc *p; 65042441Smckusick register struct args { 65142441Smckusick char *fname; 6526254Sroot int fmode; 6536254Sroot int dev; 65442441Smckusick } *uap; 65542441Smckusick int *retval; 65642441Smckusick { 65747540Skarels register struct nameidata *ndp; 65837741Smckusick register struct vnode *vp; 65937741Smckusick struct vattr vattr; 66037741Smckusick int error; 66147540Skarels struct nameidata nd; 6626254Sroot 663*52230Sheideman CHECKPOINT; 66447540Skarels if (error = suser(p->p_ucred, &p->p_acflag)) 66547540Skarels return (error); 66647540Skarels ndp = &nd; 66737741Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 66816694Smckusick ndp->ni_segflg = UIO_USERSPACE; 66916694Smckusick ndp->ni_dirp = uap->fname; 67047540Skarels if (error = namei(ndp, p)) 67147540Skarels return (error); 67237741Smckusick vp = ndp->ni_vp; 67337741Smckusick if (vp != NULL) { 67437741Smckusick error = EEXIST; 67512756Ssam goto out; 6766254Sroot } 67741362Smckusick VATTR_NULL(&vattr); 67840635Smckusick switch (uap->fmode & S_IFMT) { 67912756Ssam 68040635Smckusick case S_IFMT: /* used by badsect to flag bad sectors */ 68137741Smckusick vattr.va_type = VBAD; 68237741Smckusick break; 68340635Smckusick case S_IFCHR: 68437741Smckusick vattr.va_type = VCHR; 68537741Smckusick break; 68640635Smckusick case S_IFBLK: 68737741Smckusick vattr.va_type = VBLK; 68837741Smckusick break; 68937741Smckusick default: 69037741Smckusick error = EINVAL; 69137741Smckusick goto out; 6926254Sroot } 69345914Smckusick vattr.va_mode = (uap->fmode & 07777) &~ p->p_fd->fd_cmask; 69437741Smckusick vattr.va_rdev = uap->dev; 6956254Sroot out: 69642465Smckusick if (!error) { 69752192Smckusick LEASE_CHECK(ndp->ni_dvp, p, p->p_ucred, LEASE_WRITE); 698*52230Sheideman error = VOP_MKNOD(ndp->ni_dvp, &ndp->ni_vp, &ndp->ni_cnd, &vattr); 69942465Smckusick } else { 700*52230Sheideman VOP_ABORTOP(ndp->ni_dvp, &ndp->ni_cnd); 70143344Smckusick if (ndp->ni_dvp == vp) 70243344Smckusick vrele(ndp->ni_dvp); 70343344Smckusick else 70443344Smckusick vput(ndp->ni_dvp); 70542465Smckusick if (vp) 70642465Smckusick vrele(vp); 70742465Smckusick } 708*52230Sheideman CHECKCHECK("mknod"); 70947540Skarels return (error); 7106254Sroot } 7116254Sroot 7126254Sroot /* 71349365Smckusick * Mkfifo system call. 71440285Smckusick */ 71542441Smckusick /* ARGSUSED */ 71642441Smckusick mkfifo(p, uap, retval) 71745914Smckusick struct proc *p; 71842441Smckusick register struct args { 71940285Smckusick char *fname; 72040285Smckusick int fmode; 72142441Smckusick } *uap; 72242441Smckusick int *retval; 72342441Smckusick { 72447540Skarels register struct nameidata *ndp; 72540285Smckusick struct vattr vattr; 72640285Smckusick int error; 72747540Skarels struct nameidata nd; 72840285Smckusick 72940285Smckusick #ifndef FIFO 73047540Skarels return (EOPNOTSUPP); 73140285Smckusick #else 73247540Skarels ndp = &nd; 73340285Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 73440285Smckusick ndp->ni_segflg = UIO_USERSPACE; 73540285Smckusick ndp->ni_dirp = uap->fname; 73647540Skarels if (error = namei(ndp, p)) 73747540Skarels return (error); 73840285Smckusick if (ndp->ni_vp != NULL) { 739*52230Sheideman VOP_ABORTOP(ndp->ni_dvp, &ndp->ni_cnd); 74043344Smckusick if (ndp->ni_dvp == ndp->ni_vp) 74143344Smckusick vrele(ndp->ni_dvp); 74243344Smckusick else 74343344Smckusick vput(ndp->ni_dvp); 74442465Smckusick vrele(ndp->ni_vp); 74547540Skarels return (EEXIST); 74640285Smckusick } 74745785Sbostic VATTR_NULL(&vattr); 74845785Sbostic vattr.va_type = VFIFO; 74945914Smckusick vattr.va_mode = (uap->fmode & 07777) &~ p->p_fd->fd_cmask; 75052192Smckusick LEASE_CHECK(ndp->ni_dvp, p, p->p_ucred, LEASE_WRITE); 751*52230Sheideman return (VOP_MKNOD(ndp->ni_dvp, &ndp->ni_vp, &ndp->ni_cnd, &vattr)); 75240285Smckusick #endif /* FIFO */ 75340285Smckusick } 75440285Smckusick 75540285Smckusick /* 75649365Smckusick * Link system call. 7576254Sroot */ 75842441Smckusick /* ARGSUSED */ 75942441Smckusick link(p, uap, retval) 76045914Smckusick struct proc *p; 76142441Smckusick register struct args { 7626254Sroot char *target; 7636254Sroot char *linkname; 76442441Smckusick } *uap; 76542441Smckusick int *retval; 76642441Smckusick { 76747540Skarels register struct nameidata *ndp; 76837741Smckusick register struct vnode *vp, *xp; 76937741Smckusick int error; 77047540Skarels struct nameidata nd; 7716254Sroot 772*52230Sheideman CHECKPOINT; 77347540Skarels ndp = &nd; 77416694Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW; 77516694Smckusick ndp->ni_segflg = UIO_USERSPACE; 77616694Smckusick ndp->ni_dirp = uap->target; 77747540Skarels if (error = namei(ndp, p)) 77847540Skarels return (error); 77937741Smckusick vp = ndp->ni_vp; 78037741Smckusick if (vp->v_type == VDIR && 78147540Skarels (error = suser(p->p_ucred, &p->p_acflag))) 78237741Smckusick goto out1; 78337741Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 78416694Smckusick ndp->ni_dirp = (caddr_t)uap->linkname; 78547540Skarels if (error = namei(ndp, p)) 78637741Smckusick goto out1; 78737741Smckusick xp = ndp->ni_vp; 7886254Sroot if (xp != NULL) { 78937741Smckusick error = EEXIST; 7906254Sroot goto out; 7916254Sroot } 79237741Smckusick xp = ndp->ni_dvp; 79337741Smckusick if (vp->v_mount != xp->v_mount) 79437741Smckusick error = EXDEV; 7956254Sroot out: 79642465Smckusick if (!error) { 79752192Smckusick LEASE_CHECK(xp, p, p->p_ucred, LEASE_WRITE); 79852192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 799*52230Sheideman error = VOP_LINK(vp, ndp->ni_dvp, &ndp->ni_cnd); 80042465Smckusick } else { 801*52230Sheideman VOP_ABORTOP(ndp->ni_dvp, &ndp->ni_cnd); 80243344Smckusick if (ndp->ni_dvp == ndp->ni_vp) 80343344Smckusick vrele(ndp->ni_dvp); 80443344Smckusick else 80543344Smckusick vput(ndp->ni_dvp); 80642465Smckusick if (ndp->ni_vp) 80742465Smckusick vrele(ndp->ni_vp); 80842465Smckusick } 80937741Smckusick out1: 81037741Smckusick vrele(vp); 811*52230Sheideman CHECKCHECK("link"); 81247540Skarels return (error); 8136254Sroot } 8146254Sroot 8156254Sroot /* 81649365Smckusick * Make a symbolic link. 8176254Sroot */ 81842441Smckusick /* ARGSUSED */ 81942441Smckusick symlink(p, uap, retval) 82045914Smckusick struct proc *p; 82142441Smckusick register struct args { 8226254Sroot char *target; 8236254Sroot char *linkname; 82442441Smckusick } *uap; 82542441Smckusick int *retval; 82642441Smckusick { 82747540Skarels register struct nameidata *ndp; 82837741Smckusick struct vattr vattr; 82937741Smckusick char *target; 83037741Smckusick int error; 83147540Skarels struct nameidata nd; 8326254Sroot 833*52230Sheideman CHECKPOINT; 83447540Skarels ndp = &nd; 83516694Smckusick ndp->ni_segflg = UIO_USERSPACE; 83616694Smckusick ndp->ni_dirp = uap->linkname; 83737741Smckusick MALLOC(target, char *, MAXPATHLEN, M_NAMEI, M_WAITOK); 83837741Smckusick if (error = copyinstr(uap->target, target, MAXPATHLEN, (u_int *)0)) 83942465Smckusick goto out; 84037741Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 84147540Skarels if (error = namei(ndp, p)) 84242465Smckusick goto out; 84342465Smckusick if (ndp->ni_vp) { 844*52230Sheideman VOP_ABORTOP(ndp->ni_dvp, &ndp->ni_cnd); 84543344Smckusick if (ndp->ni_dvp == ndp->ni_vp) 84643344Smckusick vrele(ndp->ni_dvp); 84743344Smckusick else 84843344Smckusick vput(ndp->ni_dvp); 84942465Smckusick vrele(ndp->ni_vp); 85037741Smckusick error = EEXIST; 85137741Smckusick goto out; 8526254Sroot } 85341362Smckusick VATTR_NULL(&vattr); 85445914Smckusick vattr.va_mode = 0777 &~ p->p_fd->fd_cmask; 85552192Smckusick LEASE_CHECK(ndp->ni_dvp, p, p->p_ucred, LEASE_WRITE); 856*52230Sheideman error = VOP_SYMLINK(ndp->ni_dvp, &ndp->ni_vp, &ndp->ni_cnd, &vattr, target); 85737741Smckusick out: 85837741Smckusick FREE(target, M_NAMEI); 859*52230Sheideman CHECKCHECK("symlink"); 86047540Skarels return (error); 8616254Sroot } 8626254Sroot 8636254Sroot /* 86449365Smckusick * Delete a name from the filesystem. 8656254Sroot */ 86642441Smckusick /* ARGSUSED */ 86742441Smckusick unlink(p, uap, retval) 86845914Smckusick struct proc *p; 86942441Smckusick struct args { 87042441Smckusick char *fname; 87142441Smckusick } *uap; 87242441Smckusick int *retval; 8736254Sroot { 87447540Skarels register struct nameidata *ndp; 87537741Smckusick register struct vnode *vp; 87637741Smckusick int error; 87747540Skarels struct nameidata nd; 8786254Sroot 879*52230Sheideman CHECKPOINT; 88047540Skarels ndp = &nd; 88137741Smckusick ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF; 88216694Smckusick ndp->ni_segflg = UIO_USERSPACE; 88316694Smckusick ndp->ni_dirp = uap->fname; 88447540Skarels if (error = namei(ndp, p)) 88547540Skarels return (error); 88637741Smckusick vp = ndp->ni_vp; 88737741Smckusick if (vp->v_type == VDIR && 88847540Skarels (error = suser(p->p_ucred, &p->p_acflag))) 8896254Sroot goto out; 8906254Sroot /* 89149365Smckusick * The root of a mounted filesystem cannot be deleted. 8926254Sroot */ 89337741Smckusick if (vp->v_flag & VROOT) { 89437741Smckusick error = EBUSY; 8956254Sroot goto out; 8966254Sroot } 89745738Smckusick (void) vnode_pager_uncache(vp); 8986254Sroot out: 89942465Smckusick if (!error) { 90052192Smckusick LEASE_CHECK(ndp->ni_dvp, p, p->p_ucred, LEASE_WRITE); 90152192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 902*52230Sheideman error = VOP_REMOVE(ndp->ni_dvp, ndp->ni_vp, &ndp->ni_cnd); 90342465Smckusick } else { 904*52230Sheideman VOP_ABORTOP(ndp->ni_dvp, &ndp->ni_cnd); 90543344Smckusick if (ndp->ni_dvp == vp) 90643344Smckusick vrele(ndp->ni_dvp); 90743344Smckusick else 90843344Smckusick vput(ndp->ni_dvp); 90942465Smckusick vput(vp); 91042465Smckusick } 911*52230Sheideman CHECKCHECK("unlink"); 91247540Skarels return (error); 9136254Sroot } 9146254Sroot 9156254Sroot /* 91649365Smckusick * Seek system call. 9176254Sroot */ 91842441Smckusick lseek(p, uap, retval) 91945914Smckusick struct proc *p; 92042441Smckusick register struct args { 92137741Smckusick int fdes; 9226254Sroot off_t off; 9236254Sroot int sbase; 92442441Smckusick } *uap; 92542441Smckusick off_t *retval; 92642441Smckusick { 92747540Skarels struct ucred *cred = p->p_ucred; 92845914Smckusick register struct filedesc *fdp = p->p_fd; 92942441Smckusick register struct file *fp; 93037741Smckusick struct vattr vattr; 93137741Smckusick int error; 9326254Sroot 93347540Skarels if ((unsigned)uap->fdes >= fdp->fd_nfiles || 93447688Skarels (fp = fdp->fd_ofiles[uap->fdes]) == NULL) 93547540Skarels return (EBADF); 93637741Smckusick if (fp->f_type != DTYPE_VNODE) 93747540Skarels return (ESPIPE); 93813878Ssam switch (uap->sbase) { 93913878Ssam 94013878Ssam case L_INCR: 94113878Ssam fp->f_offset += uap->off; 94213878Ssam break; 94313878Ssam 94413878Ssam case L_XTND: 94537741Smckusick if (error = VOP_GETATTR((struct vnode *)fp->f_data, 94648026Smckusick &vattr, cred, p)) 94747540Skarels return (error); 94837741Smckusick fp->f_offset = uap->off + vattr.va_size; 94913878Ssam break; 95013878Ssam 95113878Ssam case L_SET: 95213878Ssam fp->f_offset = uap->off; 95313878Ssam break; 95413878Ssam 95513878Ssam default: 95647540Skarels return (EINVAL); 95713878Ssam } 95842441Smckusick *retval = fp->f_offset; 95947540Skarels return (0); 9606254Sroot } 9616254Sroot 9626254Sroot /* 96349365Smckusick * Check access permissions. 9646254Sroot */ 96542441Smckusick /* ARGSUSED */ 96642441Smckusick saccess(p, uap, retval) 96745914Smckusick struct proc *p; 96842441Smckusick register struct args { 9696254Sroot char *fname; 9706254Sroot int fmode; 97142441Smckusick } *uap; 97242441Smckusick int *retval; 97342441Smckusick { 97447540Skarels register struct nameidata *ndp; 97547540Skarels register struct ucred *cred = p->p_ucred; 97637741Smckusick register struct vnode *vp; 97737741Smckusick int error, mode, svuid, svgid; 97847540Skarels struct nameidata nd; 9796254Sroot 98047540Skarels ndp = &nd; 98142441Smckusick svuid = cred->cr_uid; 98242441Smckusick svgid = cred->cr_groups[0]; 98347540Skarels cred->cr_uid = p->p_cred->p_ruid; 98447540Skarels cred->cr_groups[0] = p->p_cred->p_rgid; 98537741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 98616694Smckusick ndp->ni_segflg = UIO_USERSPACE; 98716694Smckusick ndp->ni_dirp = uap->fname; 98847540Skarels if (error = namei(ndp, p)) 98937741Smckusick goto out1; 99037741Smckusick vp = ndp->ni_vp; 99137741Smckusick /* 99237741Smckusick * fmode == 0 means only check for exist 99337741Smckusick */ 99437741Smckusick if (uap->fmode) { 99537741Smckusick mode = 0; 99637741Smckusick if (uap->fmode & R_OK) 99737741Smckusick mode |= VREAD; 99837741Smckusick if (uap->fmode & W_OK) 99937741Smckusick mode |= VWRITE; 100037741Smckusick if (uap->fmode & X_OK) 100137741Smckusick mode |= VEXEC; 100239543Smckusick if ((mode & VWRITE) == 0 || (error = vn_writechk(vp)) == 0) 100348026Smckusick error = VOP_ACCESS(vp, mode, cred, p); 10046254Sroot } 100537741Smckusick vput(vp); 100637741Smckusick out1: 100742441Smckusick cred->cr_uid = svuid; 100842441Smckusick cred->cr_groups[0] = svgid; 100947540Skarels return (error); 10106254Sroot } 10116254Sroot 10126254Sroot /* 101349365Smckusick * Stat system call. 101449365Smckusick * This version follows links. 101537Sbill */ 101642441Smckusick /* ARGSUSED */ 101742441Smckusick stat(p, uap, retval) 101845914Smckusick struct proc *p; 101942441Smckusick register struct args { 102042441Smckusick char *fname; 102142441Smckusick struct stat *ub; 102242441Smckusick } *uap; 102342441Smckusick int *retval; 102437Sbill { 102547540Skarels register struct nameidata *ndp; 102642441Smckusick struct stat sb; 102742441Smckusick int error; 102847540Skarels struct nameidata nd; 102937Sbill 103047540Skarels ndp = &nd; 103142441Smckusick ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW; 103242441Smckusick ndp->ni_segflg = UIO_USERSPACE; 103342441Smckusick ndp->ni_dirp = uap->fname; 103447540Skarels if (error = namei(ndp, p)) 103547540Skarels return (error); 103648026Smckusick error = vn_stat(ndp->ni_vp, &sb, p); 103742441Smckusick vput(ndp->ni_vp); 103842441Smckusick if (error) 103947540Skarels return (error); 104042441Smckusick error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb)); 104147540Skarels return (error); 104237Sbill } 104337Sbill 104437Sbill /* 104549365Smckusick * Lstat system call. 104649365Smckusick * This version does not follow links. 10475992Swnj */ 104842441Smckusick /* ARGSUSED */ 104942441Smckusick lstat(p, uap, retval) 105045914Smckusick struct proc *p; 105142441Smckusick register struct args { 10525992Swnj char *fname; 105312756Ssam struct stat *ub; 105442441Smckusick } *uap; 105542441Smckusick int *retval; 105642441Smckusick { 105747540Skarels register struct nameidata *ndp; 105812756Ssam struct stat sb; 105937741Smckusick int error; 106047540Skarels struct nameidata nd; 10615992Swnj 106247540Skarels ndp = &nd; 106342441Smckusick ndp->ni_nameiop = LOOKUP | LOCKLEAF | NOFOLLOW; 106416694Smckusick ndp->ni_segflg = UIO_USERSPACE; 106516694Smckusick ndp->ni_dirp = uap->fname; 106647540Skarels if (error = namei(ndp, p)) 106747540Skarels return (error); 106848026Smckusick error = vn_stat(ndp->ni_vp, &sb, p); 106937741Smckusick vput(ndp->ni_vp); 107037741Smckusick if (error) 107147540Skarels return (error); 107237741Smckusick error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb)); 107347540Skarels return (error); 10745992Swnj } 10755992Swnj 10765992Swnj /* 107749365Smckusick * Return target name of a symbolic link. 107837Sbill */ 107942441Smckusick /* ARGSUSED */ 108042441Smckusick readlink(p, uap, retval) 108145914Smckusick struct proc *p; 108242441Smckusick register struct args { 10835992Swnj char *name; 10845992Swnj char *buf; 10855992Swnj int count; 108642441Smckusick } *uap; 108742441Smckusick int *retval; 108842441Smckusick { 108947540Skarels register struct nameidata *ndp; 109037741Smckusick register struct vnode *vp; 109137741Smckusick struct iovec aiov; 109237741Smckusick struct uio auio; 109337741Smckusick int error; 109447540Skarels struct nameidata nd; 10955992Swnj 1096*52230Sheideman CHECKPOINT; 109747540Skarels ndp = &nd; 109837741Smckusick ndp->ni_nameiop = LOOKUP | LOCKLEAF; 109916694Smckusick ndp->ni_segflg = UIO_USERSPACE; 110016694Smckusick ndp->ni_dirp = uap->name; 110147540Skarels if (error = namei(ndp, p)) 110247540Skarels return (error); 110337741Smckusick vp = ndp->ni_vp; 110437741Smckusick if (vp->v_type != VLNK) { 110537741Smckusick error = EINVAL; 11065992Swnj goto out; 11075992Swnj } 110837741Smckusick aiov.iov_base = uap->buf; 110937741Smckusick aiov.iov_len = uap->count; 111037741Smckusick auio.uio_iov = &aiov; 111137741Smckusick auio.uio_iovcnt = 1; 111237741Smckusick auio.uio_offset = 0; 111337741Smckusick auio.uio_rw = UIO_READ; 111437741Smckusick auio.uio_segflg = UIO_USERSPACE; 111548026Smckusick auio.uio_procp = p; 111637741Smckusick auio.uio_resid = uap->count; 111747540Skarels error = VOP_READLINK(vp, &auio, p->p_ucred); 11185992Swnj out: 111937741Smckusick vput(vp); 112042441Smckusick *retval = uap->count - auio.uio_resid; 1121*52230Sheideman CHECKCHECK("readlink"); 112247540Skarels return (error); 11235992Swnj } 11245992Swnj 11259167Ssam /* 112638259Smckusick * Change flags of a file given path name. 112738259Smckusick */ 112842441Smckusick /* ARGSUSED */ 112942441Smckusick chflags(p, uap, retval) 113045914Smckusick struct proc *p; 113142441Smckusick register struct args { 113238259Smckusick char *fname; 113338259Smckusick int flags; 113442441Smckusick } *uap; 113542441Smckusick int *retval; 113642441Smckusick { 113747540Skarels register struct nameidata *ndp; 113838259Smckusick register struct vnode *vp; 113938259Smckusick struct vattr vattr; 114038259Smckusick int error; 114147540Skarels struct nameidata nd; 114238259Smckusick 114347540Skarels ndp = &nd; 114438259Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 114538259Smckusick ndp->ni_segflg = UIO_USERSPACE; 114638259Smckusick ndp->ni_dirp = uap->fname; 114747540Skarels if (error = namei(ndp, p)) 114847540Skarels return (error); 114938259Smckusick vp = ndp->ni_vp; 115041400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 115138259Smckusick error = EROFS; 115238259Smckusick goto out; 115338259Smckusick } 115445785Sbostic VATTR_NULL(&vattr); 115545785Sbostic vattr.va_flags = uap->flags; 115652192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 115748026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 115838259Smckusick out: 115938259Smckusick vput(vp); 116047540Skarels return (error); 116138259Smckusick } 116238259Smckusick 116338259Smckusick /* 116438259Smckusick * Change flags of a file given a file descriptor. 116538259Smckusick */ 116642441Smckusick /* ARGSUSED */ 116742441Smckusick fchflags(p, uap, retval) 116845914Smckusick struct proc *p; 116942441Smckusick register struct args { 117038259Smckusick int fd; 117138259Smckusick int flags; 117242441Smckusick } *uap; 117342441Smckusick int *retval; 117442441Smckusick { 117538259Smckusick struct vattr vattr; 117638259Smckusick struct vnode *vp; 117738259Smckusick struct file *fp; 117838259Smckusick int error; 117938259Smckusick 118045914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 118147540Skarels return (error); 118238259Smckusick vp = (struct vnode *)fp->f_data; 118338259Smckusick VOP_LOCK(vp); 118441400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 118538259Smckusick error = EROFS; 118638259Smckusick goto out; 118738259Smckusick } 118845785Sbostic VATTR_NULL(&vattr); 118945785Sbostic vattr.va_flags = uap->flags; 119052192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 119148026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 119238259Smckusick out: 119338259Smckusick VOP_UNLOCK(vp); 119447540Skarels return (error); 119538259Smckusick } 119638259Smckusick 119738259Smckusick /* 11989167Ssam * Change mode of a file given path name. 11999167Ssam */ 120042441Smckusick /* ARGSUSED */ 120142441Smckusick chmod(p, uap, retval) 120245914Smckusick struct proc *p; 120342441Smckusick register struct args { 12046254Sroot char *fname; 12056254Sroot int fmode; 120642441Smckusick } *uap; 120742441Smckusick int *retval; 120842441Smckusick { 120947540Skarels register struct nameidata *ndp; 121037741Smckusick register struct vnode *vp; 121137741Smckusick struct vattr vattr; 121237741Smckusick int error; 121347540Skarels struct nameidata nd; 12145992Swnj 121547540Skarels ndp = &nd; 121637741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 121737741Smckusick ndp->ni_segflg = UIO_USERSPACE; 121837741Smckusick ndp->ni_dirp = uap->fname; 121947540Skarels if (error = namei(ndp, p)) 122047540Skarels return (error); 122137741Smckusick vp = ndp->ni_vp; 122241400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 122337741Smckusick error = EROFS; 122437741Smckusick goto out; 122537741Smckusick } 122645785Sbostic VATTR_NULL(&vattr); 122745785Sbostic vattr.va_mode = uap->fmode & 07777; 122852192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 122948026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 123037741Smckusick out: 123137741Smckusick vput(vp); 123247540Skarels return (error); 12337701Ssam } 12347439Sroot 12359167Ssam /* 12369167Ssam * Change mode of a file given a file descriptor. 12379167Ssam */ 123842441Smckusick /* ARGSUSED */ 123942441Smckusick fchmod(p, uap, retval) 124045914Smckusick struct proc *p; 124142441Smckusick register struct args { 12427701Ssam int fd; 12437701Ssam int fmode; 124442441Smckusick } *uap; 124542441Smckusick int *retval; 124642441Smckusick { 124737741Smckusick struct vattr vattr; 124837741Smckusick struct vnode *vp; 124937741Smckusick struct file *fp; 125037741Smckusick int error; 12517701Ssam 125245914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 125347540Skarels return (error); 125437741Smckusick vp = (struct vnode *)fp->f_data; 125537741Smckusick VOP_LOCK(vp); 125641400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 125737741Smckusick error = EROFS; 125837741Smckusick goto out; 12597439Sroot } 126045785Sbostic VATTR_NULL(&vattr); 126145785Sbostic vattr.va_mode = uap->fmode & 07777; 126252192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 126348026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 126437741Smckusick out: 126537741Smckusick VOP_UNLOCK(vp); 126647540Skarels return (error); 12675992Swnj } 12685992Swnj 12699167Ssam /* 12709167Ssam * Set ownership given a path name. 12719167Ssam */ 127242441Smckusick /* ARGSUSED */ 127342441Smckusick chown(p, uap, retval) 127445914Smckusick struct proc *p; 127542441Smckusick register struct args { 12766254Sroot char *fname; 12776254Sroot int uid; 12786254Sroot int gid; 127942441Smckusick } *uap; 128042441Smckusick int *retval; 128142441Smckusick { 128247540Skarels register struct nameidata *ndp; 128337741Smckusick register struct vnode *vp; 128437741Smckusick struct vattr vattr; 128537741Smckusick int error; 128647540Skarels struct nameidata nd; 128737Sbill 128847540Skarels ndp = &nd; 128937741Smckusick ndp->ni_nameiop = LOOKUP | NOFOLLOW | LOCKLEAF; 129036614Sbostic ndp->ni_segflg = UIO_USERSPACE; 129136614Sbostic ndp->ni_dirp = uap->fname; 129247540Skarels if (error = namei(ndp, p)) 129347540Skarels return (error); 129437741Smckusick vp = ndp->ni_vp; 129541400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 129637741Smckusick error = EROFS; 129737741Smckusick goto out; 129837741Smckusick } 129945785Sbostic VATTR_NULL(&vattr); 130045785Sbostic vattr.va_uid = uap->uid; 130145785Sbostic vattr.va_gid = uap->gid; 130252192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 130348026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 130437741Smckusick out: 130537741Smckusick vput(vp); 130647540Skarels return (error); 13077701Ssam } 13087439Sroot 13099167Ssam /* 13109167Ssam * Set ownership given a file descriptor. 13119167Ssam */ 131242441Smckusick /* ARGSUSED */ 131342441Smckusick fchown(p, uap, retval) 131445914Smckusick struct proc *p; 131542441Smckusick register struct args { 13167701Ssam int fd; 13177701Ssam int uid; 13187701Ssam int gid; 131942441Smckusick } *uap; 132042441Smckusick int *retval; 132142441Smckusick { 132237741Smckusick struct vattr vattr; 132337741Smckusick struct vnode *vp; 132437741Smckusick struct file *fp; 132537741Smckusick int error; 13267701Ssam 132745914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 132847540Skarels return (error); 132937741Smckusick vp = (struct vnode *)fp->f_data; 133037741Smckusick VOP_LOCK(vp); 133141400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 133237741Smckusick error = EROFS; 133337741Smckusick goto out; 133437741Smckusick } 133545785Sbostic VATTR_NULL(&vattr); 133645785Sbostic vattr.va_uid = uap->uid; 133745785Sbostic vattr.va_gid = uap->gid; 133852192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 133948026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 134037741Smckusick out: 134137741Smckusick VOP_UNLOCK(vp); 134247540Skarels return (error); 13437701Ssam } 13447701Ssam 134542441Smckusick /* 134642441Smckusick * Set the access and modification times of a file. 134742441Smckusick */ 134842441Smckusick /* ARGSUSED */ 134942441Smckusick utimes(p, uap, retval) 135045914Smckusick struct proc *p; 135142441Smckusick register struct args { 135211811Ssam char *fname; 135311811Ssam struct timeval *tptr; 135442441Smckusick } *uap; 135542441Smckusick int *retval; 135642441Smckusick { 135747540Skarels register struct nameidata *ndp; 135837741Smckusick register struct vnode *vp; 135911811Ssam struct timeval tv[2]; 136037741Smckusick struct vattr vattr; 136137741Smckusick int error; 136247540Skarels struct nameidata nd; 136311811Ssam 136437741Smckusick if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv))) 136547540Skarels return (error); 136647540Skarels ndp = &nd; 136737741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 136837741Smckusick ndp->ni_segflg = UIO_USERSPACE; 136937741Smckusick ndp->ni_dirp = uap->fname; 137047540Skarels if (error = namei(ndp, p)) 137147540Skarels return (error); 137237741Smckusick vp = ndp->ni_vp; 137341400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 137437741Smckusick error = EROFS; 137537741Smckusick goto out; 137621015Smckusick } 137745785Sbostic VATTR_NULL(&vattr); 137845785Sbostic vattr.va_atime = tv[0]; 137945785Sbostic vattr.va_mtime = tv[1]; 138052192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 138148026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 138237741Smckusick out: 138337741Smckusick vput(vp); 138447540Skarels return (error); 138511811Ssam } 138611811Ssam 13879167Ssam /* 13889167Ssam * Truncate a file given its path name. 13899167Ssam */ 139042441Smckusick /* ARGSUSED */ 139142441Smckusick truncate(p, uap, retval) 139245914Smckusick struct proc *p; 139342441Smckusick register struct args { 13947701Ssam char *fname; 139526473Skarels off_t length; 139642441Smckusick } *uap; 139742441Smckusick int *retval; 139842441Smckusick { 139947540Skarels register struct nameidata *ndp; 140037741Smckusick register struct vnode *vp; 140137741Smckusick struct vattr vattr; 140237741Smckusick int error; 140347540Skarels struct nameidata nd; 14047701Ssam 140547540Skarels ndp = &nd; 140637741Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 140716694Smckusick ndp->ni_segflg = UIO_USERSPACE; 140816694Smckusick ndp->ni_dirp = uap->fname; 140947540Skarels if (error = namei(ndp, p)) 141047540Skarels return (error); 141137741Smckusick vp = ndp->ni_vp; 141237741Smckusick if (vp->v_type == VDIR) { 141337741Smckusick error = EISDIR; 141437741Smckusick goto out; 14157701Ssam } 141638399Smckusick if ((error = vn_writechk(vp)) || 141748026Smckusick (error = VOP_ACCESS(vp, VWRITE, p->p_ucred, p))) 141837741Smckusick goto out; 141945785Sbostic VATTR_NULL(&vattr); 142045785Sbostic vattr.va_size = uap->length; 142152192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 142248026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 142337741Smckusick out: 142437741Smckusick vput(vp); 142547540Skarels return (error); 14267701Ssam } 14277701Ssam 14289167Ssam /* 14299167Ssam * Truncate a file given a file descriptor. 14309167Ssam */ 143142441Smckusick /* ARGSUSED */ 143242441Smckusick ftruncate(p, uap, retval) 143345914Smckusick struct proc *p; 143442441Smckusick register struct args { 14357701Ssam int fd; 143626473Skarels off_t length; 143742441Smckusick } *uap; 143842441Smckusick int *retval; 143942441Smckusick { 144037741Smckusick struct vattr vattr; 144137741Smckusick struct vnode *vp; 14427701Ssam struct file *fp; 144337741Smckusick int error; 14447701Ssam 144545914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 144647540Skarels return (error); 144737741Smckusick if ((fp->f_flag & FWRITE) == 0) 144847540Skarels return (EINVAL); 144937741Smckusick vp = (struct vnode *)fp->f_data; 145037741Smckusick VOP_LOCK(vp); 145137741Smckusick if (vp->v_type == VDIR) { 145237741Smckusick error = EISDIR; 145337741Smckusick goto out; 14547701Ssam } 145538399Smckusick if (error = vn_writechk(vp)) 145637741Smckusick goto out; 145745785Sbostic VATTR_NULL(&vattr); 145845785Sbostic vattr.va_size = uap->length; 145952192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 146048026Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred, p); 146137741Smckusick out: 146237741Smckusick VOP_UNLOCK(vp); 146347540Skarels return (error); 14647701Ssam } 14657701Ssam 14669167Ssam /* 14679167Ssam * Synch an open file. 14689167Ssam */ 146942441Smckusick /* ARGSUSED */ 147042441Smckusick fsync(p, uap, retval) 147145914Smckusick struct proc *p; 147242441Smckusick struct args { 147342441Smckusick int fd; 147442441Smckusick } *uap; 147542441Smckusick int *retval; 14769167Ssam { 147739592Smckusick register struct vnode *vp; 14789167Ssam struct file *fp; 147937741Smckusick int error; 14809167Ssam 148145914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 148247540Skarels return (error); 148339592Smckusick vp = (struct vnode *)fp->f_data; 148439592Smckusick VOP_LOCK(vp); 148548026Smckusick error = VOP_FSYNC(vp, fp->f_flag, fp->f_cred, MNT_WAIT, p); 148639592Smckusick VOP_UNLOCK(vp); 148747540Skarels return (error); 14889167Ssam } 14899167Ssam 14909167Ssam /* 14919167Ssam * Rename system call. 14929167Ssam * 14939167Ssam * Source and destination must either both be directories, or both 14949167Ssam * not be directories. If target is a directory, it must be empty. 14959167Ssam */ 149642441Smckusick /* ARGSUSED */ 149742441Smckusick rename(p, uap, retval) 149845914Smckusick struct proc *p; 149942441Smckusick register struct args { 15007701Ssam char *from; 15017701Ssam char *to; 150242441Smckusick } *uap; 150342441Smckusick int *retval; 150442441Smckusick { 150537741Smckusick register struct vnode *tvp, *fvp, *tdvp; 150649735Smckusick struct nameidata fromnd, tond; 150737741Smckusick int error; 15087701Ssam 1509*52230Sheideman CHECKPOINT; 151049735Smckusick fromnd.ni_nameiop = DELETE | WANTPARENT | SAVESTART; 151149735Smckusick fromnd.ni_segflg = UIO_USERSPACE; 151249735Smckusick fromnd.ni_dirp = uap->from; 151349735Smckusick if (error = namei(&fromnd, p)) 151447540Skarels return (error); 151549735Smckusick fvp = fromnd.ni_vp; 151649735Smckusick tond.ni_nameiop = RENAME | LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART; 151737741Smckusick tond.ni_segflg = UIO_USERSPACE; 151837741Smckusick tond.ni_dirp = uap->to; 151947540Skarels if (error = namei(&tond, p)) { 1520*52230Sheideman VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 152149735Smckusick vrele(fromnd.ni_dvp); 152242465Smckusick vrele(fvp); 152342465Smckusick goto out1; 152442465Smckusick } 152537741Smckusick tdvp = tond.ni_dvp; 152637741Smckusick tvp = tond.ni_vp; 152737741Smckusick if (tvp != NULL) { 152837741Smckusick if (fvp->v_type == VDIR && tvp->v_type != VDIR) { 152939242Sbostic error = ENOTDIR; 153037741Smckusick goto out; 153137741Smckusick } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) { 153239242Sbostic error = EISDIR; 153337741Smckusick goto out; 15349167Ssam } 153545240Smckusick if (fvp->v_mount != tvp->v_mount) { 153645240Smckusick error = EXDEV; 153745240Smckusick goto out; 153845240Smckusick } 15399167Ssam } 154037741Smckusick if (fvp->v_mount != tdvp->v_mount) { 154137741Smckusick error = EXDEV; 15429167Ssam goto out; 154310051Ssam } 154439286Smckusick if (fvp == tdvp) 154537741Smckusick error = EINVAL; 154639286Smckusick /* 154749735Smckusick * If source is the same as the destination (that is the 154849735Smckusick * same inode number with the same name in the same directory), 154939286Smckusick * then there is nothing to do. 155039286Smckusick */ 155149735Smckusick if (fvp == tvp && fromnd.ni_dvp == tdvp && 155249735Smckusick fromnd.ni_namelen == tond.ni_namelen && 155349735Smckusick !bcmp(fromnd.ni_ptr, tond.ni_ptr, fromnd.ni_namelen)) 155439286Smckusick error = -1; 155537741Smckusick out: 155642465Smckusick if (!error) { 155752192Smckusick LEASE_CHECK(tdvp, p, p->p_ucred, LEASE_WRITE); 155852192Smckusick if (fromnd.ni_dvp != tdvp) 155952192Smckusick LEASE_CHECK(fromnd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 156052192Smckusick if (tvp) 156152192Smckusick LEASE_CHECK(tvp, p, p->p_ucred, LEASE_WRITE); 1562*52230Sheideman if (fromnd.ni_startdir != fromnd.ni_dvp || 1563*52230Sheideman tond.ni_startdir != tond.ni_dvp) /* NEEDSWORK: debug */ 1564*52230Sheideman printf ("rename: f.startdir=%x, dvp=%x; t.startdir=%x, dvp=%x\n", fromnd.ni_startdir, fromnd.ni_dvp, tond.ni_startdir, tond.ni_dvp); 1565*52230Sheideman error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd, 1566*52230Sheideman tond.ni_dvp, tond.ni_vp, &tond.ni_cnd); 1567*52230Sheideman if (fromnd.ni_startdir != fromnd.ni_dvp || 1568*52230Sheideman tond.ni_startdir != tond.ni_dvp) /* NEEDSWORK: debug */ 1569*52230Sheideman printf ("rename: f.startdir=%x, dvp=%x; t.startdir=%x, dvp=%x\n", fromnd.ni_startdir, fromnd.ni_dvp, tond.ni_startdir, tond.ni_dvp); 157042465Smckusick } else { 1571*52230Sheideman VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd); 157243344Smckusick if (tdvp == tvp) 157343344Smckusick vrele(tdvp); 157443344Smckusick else 157543344Smckusick vput(tdvp); 157642465Smckusick if (tvp) 157742465Smckusick vput(tvp); 1578*52230Sheideman VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 157949735Smckusick vrele(fromnd.ni_dvp); 158042465Smckusick vrele(fvp); 15819167Ssam } 158249735Smckusick vrele(tond.ni_startdir); 158349735Smckusick FREE(tond.ni_pnbuf, M_NAMEI); 158437741Smckusick out1: 158549735Smckusick vrele(fromnd.ni_startdir); 158649735Smckusick FREE(fromnd.ni_pnbuf, M_NAMEI); 1587*52230Sheideman CHECKCHECK("rename"); 158839286Smckusick if (error == -1) 158947540Skarels return (0); 159047540Skarels return (error); 15917701Ssam } 15927701Ssam 15937535Sroot /* 159449365Smckusick * Mkdir system call. 159512756Ssam */ 159642441Smckusick /* ARGSUSED */ 159742441Smckusick mkdir(p, uap, retval) 159845914Smckusick struct proc *p; 159942441Smckusick register struct args { 160012756Ssam char *name; 160112756Ssam int dmode; 160242441Smckusick } *uap; 160342441Smckusick int *retval; 160442441Smckusick { 160547540Skarels register struct nameidata *ndp; 160637741Smckusick register struct vnode *vp; 160737741Smckusick struct vattr vattr; 160837741Smckusick int error; 160947540Skarels struct nameidata nd; 161012756Ssam 1611*52230Sheideman CHECKPOINT; 161247540Skarels ndp = &nd; 161337741Smckusick ndp->ni_nameiop = CREATE | LOCKPARENT; 161416694Smckusick ndp->ni_segflg = UIO_USERSPACE; 161516694Smckusick ndp->ni_dirp = uap->name; 161647540Skarels if (error = namei(ndp, p)) 161747540Skarels return (error); 161837741Smckusick vp = ndp->ni_vp; 161937741Smckusick if (vp != NULL) { 1620*52230Sheideman VOP_ABORTOP(ndp->ni_dvp, &ndp->ni_cnd); 162143344Smckusick if (ndp->ni_dvp == vp) 162243344Smckusick vrele(ndp->ni_dvp); 162343344Smckusick else 162443344Smckusick vput(ndp->ni_dvp); 162542465Smckusick vrele(vp); 1626*52230Sheideman CHECKCHECK("mkdir1"); 162747540Skarels return (EEXIST); 162812756Ssam } 162941362Smckusick VATTR_NULL(&vattr); 163037741Smckusick vattr.va_type = VDIR; 163145914Smckusick vattr.va_mode = (uap->dmode & 0777) &~ p->p_fd->fd_cmask; 163252192Smckusick LEASE_CHECK(ndp->ni_dvp, p, p->p_ucred, LEASE_WRITE); 1633*52230Sheideman error = VOP_MKDIR(ndp->ni_dvp, &ndp->ni_vp, &ndp->ni_cnd, &vattr); 163438145Smckusick if (!error) 163538145Smckusick vput(ndp->ni_vp); 1636*52230Sheideman CHECKCHECK("mkdir2"); 163747540Skarels return (error); 163812756Ssam } 163912756Ssam 164012756Ssam /* 164112756Ssam * Rmdir system call. 164212756Ssam */ 164342441Smckusick /* ARGSUSED */ 164442441Smckusick rmdir(p, uap, retval) 164545914Smckusick struct proc *p; 164642441Smckusick struct args { 164742441Smckusick char *name; 164842441Smckusick } *uap; 164942441Smckusick int *retval; 165012756Ssam { 165147540Skarels register struct nameidata *ndp; 165237741Smckusick register struct vnode *vp; 165337741Smckusick int error; 165447540Skarels struct nameidata nd; 165512756Ssam 1656*52230Sheideman CHECKPOINT; 165747540Skarels ndp = &nd; 165837741Smckusick ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF; 165916694Smckusick ndp->ni_segflg = UIO_USERSPACE; 166016694Smckusick ndp->ni_dirp = uap->name; 166147540Skarels if (error = namei(ndp, p)) 166247540Skarels return (error); 166337741Smckusick vp = ndp->ni_vp; 166437741Smckusick if (vp->v_type != VDIR) { 166537741Smckusick error = ENOTDIR; 166612756Ssam goto out; 166712756Ssam } 166812756Ssam /* 166937741Smckusick * No rmdir "." please. 167012756Ssam */ 167137741Smckusick if (ndp->ni_dvp == vp) { 167237741Smckusick error = EINVAL; 167312756Ssam goto out; 167412756Ssam } 167512756Ssam /* 167649365Smckusick * The root of a mounted filesystem cannot be deleted. 167712756Ssam */ 167837741Smckusick if (vp->v_flag & VROOT) 167937741Smckusick error = EBUSY; 168012756Ssam out: 168142465Smckusick if (!error) { 168252192Smckusick LEASE_CHECK(ndp->ni_dvp, p, p->p_ucred, LEASE_WRITE); 168352192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 1684*52230Sheideman error = VOP_RMDIR(ndp->ni_dvp, ndp->ni_vp, &ndp->ni_cnd); 168542465Smckusick } else { 1686*52230Sheideman VOP_ABORTOP(ndp->ni_dvp, &ndp->ni_cnd); 168743344Smckusick if (ndp->ni_dvp == vp) 168843344Smckusick vrele(ndp->ni_dvp); 168943344Smckusick else 169043344Smckusick vput(ndp->ni_dvp); 169142465Smckusick vput(vp); 169242465Smckusick } 1693*52230Sheideman CHECKCHECK("rmdir"); 169447540Skarels return (error); 169512756Ssam } 169612756Ssam 169737741Smckusick /* 169849365Smckusick * Read a block of directory entries in a file system independent format. 169937741Smckusick */ 170042441Smckusick getdirentries(p, uap, retval) 170145914Smckusick struct proc *p; 170242441Smckusick register struct args { 170337741Smckusick int fd; 170437741Smckusick char *buf; 170537741Smckusick unsigned count; 170637741Smckusick long *basep; 170742441Smckusick } *uap; 170842441Smckusick int *retval; 170942441Smckusick { 171039592Smckusick register struct vnode *vp; 171116540Ssam struct file *fp; 171237741Smckusick struct uio auio; 171337741Smckusick struct iovec aiov; 171438129Smckusick off_t off; 171540321Smckusick int error, eofflag; 171612756Ssam 171745914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 171847540Skarels return (error); 171937741Smckusick if ((fp->f_flag & FREAD) == 0) 172047540Skarels return (EBADF); 172139592Smckusick vp = (struct vnode *)fp->f_data; 172239592Smckusick if (vp->v_type != VDIR) 172347540Skarels return (EINVAL); 172437741Smckusick aiov.iov_base = uap->buf; 172537741Smckusick aiov.iov_len = uap->count; 172637741Smckusick auio.uio_iov = &aiov; 172737741Smckusick auio.uio_iovcnt = 1; 172837741Smckusick auio.uio_rw = UIO_READ; 172937741Smckusick auio.uio_segflg = UIO_USERSPACE; 173048026Smckusick auio.uio_procp = p; 173137741Smckusick auio.uio_resid = uap->count; 173239592Smckusick VOP_LOCK(vp); 173339592Smckusick auio.uio_offset = off = fp->f_offset; 173440321Smckusick error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag); 173539592Smckusick fp->f_offset = auio.uio_offset; 173639592Smckusick VOP_UNLOCK(vp); 173739592Smckusick if (error) 173847540Skarels return (error); 173939592Smckusick error = copyout((caddr_t)&off, (caddr_t)uap->basep, sizeof(long)); 174042441Smckusick *retval = uap->count - auio.uio_resid; 174147540Skarels return (error); 174212756Ssam } 174312756Ssam 174412756Ssam /* 174549365Smckusick * Set the mode mask for creation of filesystem nodes. 174612756Ssam */ 174742441Smckusick mode_t 174842441Smckusick umask(p, uap, retval) 174945914Smckusick struct proc *p; 175042441Smckusick struct args { 175142441Smckusick int mask; 175242441Smckusick } *uap; 175342441Smckusick int *retval; 175412756Ssam { 175545914Smckusick register struct filedesc *fdp = p->p_fd; 175612756Ssam 175745914Smckusick *retval = fdp->fd_cmask; 175845914Smckusick fdp->fd_cmask = uap->mask & 07777; 175947540Skarels return (0); 176012756Ssam } 176137741Smckusick 176239566Smarc /* 176339566Smarc * Void all references to file by ripping underlying filesystem 176439566Smarc * away from vnode. 176539566Smarc */ 176642441Smckusick /* ARGSUSED */ 176742441Smckusick revoke(p, uap, retval) 176845914Smckusick struct proc *p; 176942441Smckusick register struct args { 177039566Smarc char *fname; 177142441Smckusick } *uap; 177242441Smckusick int *retval; 177342441Smckusick { 177447540Skarels register struct nameidata *ndp; 177539566Smarc register struct vnode *vp; 177639566Smarc struct vattr vattr; 177739566Smarc int error; 177847540Skarels struct nameidata nd; 177939566Smarc 178047540Skarels ndp = &nd; 178139566Smarc ndp->ni_nameiop = LOOKUP | FOLLOW; 178239566Smarc ndp->ni_segflg = UIO_USERSPACE; 178339566Smarc ndp->ni_dirp = uap->fname; 178447540Skarels if (error = namei(ndp, p)) 178547540Skarels return (error); 178639566Smarc vp = ndp->ni_vp; 178739566Smarc if (vp->v_type != VCHR && vp->v_type != VBLK) { 178839566Smarc error = EINVAL; 178939566Smarc goto out; 179039566Smarc } 179148026Smckusick if (error = VOP_GETATTR(vp, &vattr, p->p_ucred, p)) 179239566Smarc goto out; 179347540Skarels if (p->p_ucred->cr_uid != vattr.va_uid && 179447540Skarels (error = suser(p->p_ucred, &p->p_acflag))) 179539566Smarc goto out; 179639805Smckusick if (vp->v_usecount > 1 || (vp->v_flag & VALIASED)) 179739632Smckusick vgoneall(vp); 179839566Smarc out: 179939566Smarc vrele(vp); 180047540Skarels return (error); 180139566Smarc } 180239566Smarc 180349365Smckusick /* 180449365Smckusick * Convert a user file descriptor to a kernel file entry. 180549365Smckusick */ 180645914Smckusick getvnode(fdp, fdes, fpp) 180745914Smckusick struct filedesc *fdp; 180837741Smckusick struct file **fpp; 180937741Smckusick int fdes; 181037741Smckusick { 181137741Smckusick struct file *fp; 181237741Smckusick 181347540Skarels if ((unsigned)fdes >= fdp->fd_nfiles || 181447688Skarels (fp = fdp->fd_ofiles[fdes]) == NULL) 181537741Smckusick return (EBADF); 181637741Smckusick if (fp->f_type != DTYPE_VNODE) 181737741Smckusick return (EINVAL); 181837741Smckusick *fpp = fp; 181937741Smckusick return (0); 182037741Smckusick } 1821