123405Smckusick /* 237741Smckusick * Copyright (c) 1989 The Regents of the University of California. 337741Smckusick * All rights reserved. 423405Smckusick * 544459Sbostic * %sccs.include.redist.c% 637741Smckusick * 7*60036Smckusick * @(#)vfs_syscalls.c 7.109 (Berkeley) 05/16/93 823405Smckusick */ 937Sbill 1056517Sbostic #include <sys/param.h> 1156517Sbostic #include <sys/systm.h> 1256517Sbostic #include <sys/namei.h> 1356517Sbostic #include <sys/filedesc.h> 1456517Sbostic #include <sys/kernel.h> 1556517Sbostic #include <sys/file.h> 1656517Sbostic #include <sys/stat.h> 1756517Sbostic #include <sys/vnode.h> 1856517Sbostic #include <sys/mount.h> 1956517Sbostic #include <sys/proc.h> 2056517Sbostic #include <sys/uio.h> 2156517Sbostic #include <sys/malloc.h> 2256517Sbostic #include <sys/dirent.h> 2356517Sbostic 2453468Smckusick #include <vm/vm.h> 2559875Smckusick #include <sys/sysctl.h> 2637Sbill 2737741Smckusick /* 2837741Smckusick * Virtual File System System Calls 2937741Smckusick */ 3012756Ssam 319167Ssam /* 3249365Smckusick * Mount system call. 339167Ssam */ 3454916Storek struct mount_args { 3554916Storek int type; 3654916Storek char *dir; 3754916Storek int flags; 3854916Storek caddr_t data; 3954916Storek }; 4042441Smckusick /* ARGSUSED */ 4142441Smckusick mount(p, uap, retval) 4245914Smckusick struct proc *p; 4354916Storek register struct mount_args *uap; 4442441Smckusick int *retval; 4542441Smckusick { 4639335Smckusick register struct vnode *vp; 4739335Smckusick register struct mount *mp; 4840111Smckusick int error, flag; 4947540Skarels struct nameidata nd; 506254Sroot 5137741Smckusick /* 5237741Smckusick * Must be super user 5337741Smckusick */ 5447540Skarels if (error = suser(p->p_ucred, &p->p_acflag)) 5547540Skarels return (error); 5637741Smckusick /* 5737741Smckusick * Get vnode to be covered 5837741Smckusick */ 5952322Smckusick NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->dir, p); 6052322Smckusick if (error = namei(&nd)) 6147540Skarels return (error); 6252322Smckusick vp = nd.ni_vp; 6341400Smckusick if (uap->flags & MNT_UPDATE) { 6439335Smckusick if ((vp->v_flag & VROOT) == 0) { 6539335Smckusick vput(vp); 6647540Skarels return (EINVAL); 6739335Smckusick } 6839335Smckusick mp = vp->v_mount; 6957047Smckusick flag = mp->mnt_flag; 7039335Smckusick /* 7157047Smckusick * We only allow the filesystem to be reloaded if it 7257047Smckusick * is currently mounted read-only. 7339335Smckusick */ 7457047Smckusick if ((uap->flags & MNT_RELOAD) && 7557047Smckusick ((mp->mnt_flag & MNT_RDONLY) == 0)) { 7639335Smckusick vput(vp); 7747540Skarels return (EOPNOTSUPP); /* Needs translation */ 7839335Smckusick } 7957047Smckusick mp->mnt_flag |= 8057047Smckusick uap->flags & (MNT_RELOAD | MNT_FORCE | MNT_UPDATE); 8139335Smckusick VOP_UNLOCK(vp); 8239335Smckusick goto update; 8339335Smckusick } 8455451Spendry if (vp->v_usecount != 1 && (uap->flags & MNT_UNION) == 0) { 8537741Smckusick vput(vp); 8647540Skarels return (EBUSY); 8737741Smckusick } 8857793Smckusick if (error = vinvalbuf(vp, V_SAVE, p->p_ucred, p, 0, 0)) 8954441Smckusick return (error); 9037741Smckusick if (vp->v_type != VDIR) { 9137741Smckusick vput(vp); 9247540Skarels return (ENOTDIR); 9337741Smckusick } 9439741Smckusick if ((unsigned long)uap->type > MOUNT_MAXTYPE || 9537741Smckusick vfssw[uap->type] == (struct vfsops *)0) { 9637741Smckusick vput(vp); 9747540Skarels return (ENODEV); 9837741Smckusick } 9937741Smckusick 10037741Smckusick /* 10139335Smckusick * Allocate and initialize the file system. 10237741Smckusick */ 10337741Smckusick mp = (struct mount *)malloc((u_long)sizeof(struct mount), 10437741Smckusick M_MOUNT, M_WAITOK); 10554172Smckusick bzero((char *)mp, (u_long)sizeof(struct mount)); 10641400Smckusick mp->mnt_op = vfssw[uap->type]; 10739335Smckusick if (error = vfs_lock(mp)) { 10839335Smckusick free((caddr_t)mp, M_MOUNT); 10939335Smckusick vput(vp); 11047540Skarels return (error); 11139335Smckusick } 11239335Smckusick if (vp->v_mountedhere != (struct mount *)0) { 11339335Smckusick vfs_unlock(mp); 11439335Smckusick free((caddr_t)mp, M_MOUNT); 11539335Smckusick vput(vp); 11647540Skarels return (EBUSY); 11739335Smckusick } 11839335Smckusick vp->v_mountedhere = mp; 11941400Smckusick mp->mnt_vnodecovered = vp; 12039335Smckusick update: 12139335Smckusick /* 12239335Smckusick * Set the mount level flags. 12339335Smckusick */ 12441400Smckusick if (uap->flags & MNT_RDONLY) 12541400Smckusick mp->mnt_flag |= MNT_RDONLY; 12657047Smckusick else if (mp->mnt_flag & MNT_RDONLY) 12757047Smckusick mp->mnt_flag |= MNT_WANTRDWR; 12857047Smckusick mp->mnt_flag &=~ 12957047Smckusick (MNT_NOSUID | MNT_NOEXEC | MNT_NODEV | MNT_SYNCHRONOUS | MNT_UNION); 13057047Smckusick mp->mnt_flag |= uap->flags & 13157047Smckusick (MNT_NOSUID | MNT_NOEXEC | MNT_NODEV | MNT_SYNCHRONOUS | MNT_UNION); 13239335Smckusick /* 13339335Smckusick * Mount the filesystem. 13439335Smckusick */ 13552322Smckusick error = VFS_MOUNT(mp, uap->dir, uap->data, &nd, p); 13641400Smckusick if (mp->mnt_flag & MNT_UPDATE) { 13739335Smckusick vrele(vp); 13857047Smckusick if (mp->mnt_flag & MNT_WANTRDWR) 13957047Smckusick mp->mnt_flag &= ~MNT_RDONLY; 14057047Smckusick mp->mnt_flag &=~ 14157047Smckusick (MNT_UPDATE | MNT_RELOAD | MNT_FORCE | MNT_WANTRDWR); 14240111Smckusick if (error) 14341400Smckusick mp->mnt_flag = flag; 14447540Skarels return (error); 14539335Smckusick } 14640110Smckusick /* 14740110Smckusick * Put the new filesystem on the mount list after root. 14840110Smckusick */ 14941400Smckusick mp->mnt_next = rootfs->mnt_next; 15041400Smckusick mp->mnt_prev = rootfs; 15141400Smckusick rootfs->mnt_next = mp; 15241400Smckusick mp->mnt_next->mnt_prev = mp; 15337741Smckusick cache_purge(vp); 15437741Smckusick if (!error) { 15539335Smckusick VOP_UNLOCK(vp); 15637741Smckusick vfs_unlock(mp); 15748026Smckusick error = VFS_START(mp, 0, p); 15837741Smckusick } else { 15937741Smckusick vfs_remove(mp); 16037741Smckusick free((caddr_t)mp, M_MOUNT); 16139335Smckusick vput(vp); 16237741Smckusick } 16347540Skarels return (error); 1646254Sroot } 1656254Sroot 1669167Ssam /* 16737741Smckusick * Unmount system call. 16837741Smckusick * 16937741Smckusick * Note: unmount takes a path to the vnode mounted on as argument, 17037741Smckusick * not special file (as before). 1719167Ssam */ 17254916Storek struct unmount_args { 17354916Storek char *pathp; 17454916Storek int flags; 17554916Storek }; 17642441Smckusick /* ARGSUSED */ 17742441Smckusick unmount(p, uap, retval) 17845914Smckusick struct proc *p; 17954916Storek register struct unmount_args *uap; 18042441Smckusick int *retval; 18142441Smckusick { 18237741Smckusick register struct vnode *vp; 18339356Smckusick struct mount *mp; 18437741Smckusick int error; 18547540Skarels struct nameidata nd; 1866254Sroot 18737741Smckusick /* 18837741Smckusick * Must be super user 18937741Smckusick */ 19047540Skarels if (error = suser(p->p_ucred, &p->p_acflag)) 19147540Skarels return (error); 19237741Smckusick 19352322Smckusick NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->pathp, p); 19452322Smckusick if (error = namei(&nd)) 19547540Skarels return (error); 19652322Smckusick vp = nd.ni_vp; 19737741Smckusick /* 19837741Smckusick * Must be the root of the filesystem 19937741Smckusick */ 20037741Smckusick if ((vp->v_flag & VROOT) == 0) { 20137741Smckusick vput(vp); 20247540Skarels return (EINVAL); 20337741Smckusick } 20437741Smckusick mp = vp->v_mount; 20537741Smckusick vput(vp); 20648026Smckusick return (dounmount(mp, uap->flags, p)); 20739356Smckusick } 20839356Smckusick 20939356Smckusick /* 21039356Smckusick * Do an unmount. 21139356Smckusick */ 21248026Smckusick dounmount(mp, flags, p) 21339356Smckusick register struct mount *mp; 21439356Smckusick int flags; 21548026Smckusick struct proc *p; 21639356Smckusick { 21739356Smckusick struct vnode *coveredvp; 21839356Smckusick int error; 21939356Smckusick 22041400Smckusick coveredvp = mp->mnt_vnodecovered; 22141298Smckusick if (vfs_busy(mp)) 22241298Smckusick return (EBUSY); 22341400Smckusick mp->mnt_flag |= MNT_UNMOUNT; 22437741Smckusick if (error = vfs_lock(mp)) 22539356Smckusick return (error); 22637741Smckusick 22745738Smckusick vnode_pager_umount(mp); /* release cached vnodes */ 22837741Smckusick cache_purgevfs(mp); /* remove cache entries for this file sys */ 22954441Smckusick if ((error = VFS_SYNC(mp, MNT_WAIT, p->p_ucred, p)) == 0 || 23054441Smckusick (flags & MNT_FORCE)) 23148026Smckusick error = VFS_UNMOUNT(mp, flags, p); 23241400Smckusick mp->mnt_flag &= ~MNT_UNMOUNT; 23341298Smckusick vfs_unbusy(mp); 23437741Smckusick if (error) { 23537741Smckusick vfs_unlock(mp); 23637741Smckusick } else { 23737741Smckusick vrele(coveredvp); 23837741Smckusick vfs_remove(mp); 23952287Smckusick if (mp->mnt_mounth != NULL) 24052287Smckusick panic("unmount: dangling vnode"); 24137741Smckusick free((caddr_t)mp, M_MOUNT); 24237741Smckusick } 24339356Smckusick return (error); 2446254Sroot } 2456254Sroot 2469167Ssam /* 24737741Smckusick * Sync system call. 24837741Smckusick * Sync each mounted filesystem. 2499167Ssam */ 25056352Smckusick #ifdef DIAGNOSTIC 25156352Smckusick int syncprt = 0; 25259875Smckusick struct ctldebug debug0 = { "syncprt", &syncprt }; 25356352Smckusick #endif 25456352Smckusick 25554916Storek struct sync_args { 25654916Storek int dummy; 25754916Storek }; 25839491Smckusick /* ARGSUSED */ 25942441Smckusick sync(p, uap, retval) 26045914Smckusick struct proc *p; 26154916Storek struct sync_args *uap; 26242441Smckusick int *retval; 2636254Sroot { 26437741Smckusick register struct mount *mp; 26541298Smckusick struct mount *omp; 26637741Smckusick 26737741Smckusick mp = rootfs; 26837741Smckusick do { 26940343Smckusick /* 27040343Smckusick * The lock check below is to avoid races with mount 27140343Smckusick * and unmount. 27240343Smckusick */ 27341400Smckusick if ((mp->mnt_flag & (MNT_MLOCK|MNT_RDONLY|MNT_MPBUSY)) == 0 && 27441298Smckusick !vfs_busy(mp)) { 27554441Smckusick VFS_SYNC(mp, MNT_NOWAIT, p->p_ucred, p); 27641298Smckusick omp = mp; 27741400Smckusick mp = mp->mnt_next; 27841298Smckusick vfs_unbusy(omp); 27941298Smckusick } else 28041400Smckusick mp = mp->mnt_next; 28137741Smckusick } while (mp != rootfs); 28256352Smckusick #ifdef DIAGNOSTIC 28356352Smckusick if (syncprt) 28456352Smckusick vfs_bufstats(); 28556352Smckusick #endif /* DIAGNOSTIC */ 28647688Skarels return (0); 28737741Smckusick } 28837741Smckusick 28937741Smckusick /* 29049365Smckusick * Operate on filesystem quotas. 29141298Smckusick */ 29254916Storek struct quotactl_args { 29354916Storek char *path; 29454916Storek int cmd; 29554916Storek int uid; 29654916Storek caddr_t arg; 29754916Storek }; 29842441Smckusick /* ARGSUSED */ 29942441Smckusick quotactl(p, uap, retval) 30045914Smckusick struct proc *p; 30154916Storek register struct quotactl_args *uap; 30242441Smckusick int *retval; 30342441Smckusick { 30441298Smckusick register struct mount *mp; 30541298Smckusick int error; 30647540Skarels struct nameidata nd; 30741298Smckusick 30852322Smckusick NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); 30952322Smckusick if (error = namei(&nd)) 31047540Skarels return (error); 31152322Smckusick mp = nd.ni_vp->v_mount; 31252322Smckusick vrele(nd.ni_vp); 31348026Smckusick return (VFS_QUOTACTL(mp, uap->cmd, uap->uid, uap->arg, p)); 31441298Smckusick } 31541298Smckusick 31641298Smckusick /* 31749365Smckusick * Get filesystem statistics. 31837741Smckusick */ 31954916Storek struct statfs_args { 32054916Storek char *path; 32154916Storek struct statfs *buf; 32254916Storek }; 32342441Smckusick /* ARGSUSED */ 32442441Smckusick statfs(p, uap, retval) 32545914Smckusick struct proc *p; 32654916Storek register struct statfs_args *uap; 32742441Smckusick int *retval; 32842441Smckusick { 32939464Smckusick register struct mount *mp; 33040343Smckusick register struct statfs *sp; 33137741Smckusick int error; 33247540Skarels struct nameidata nd; 33337741Smckusick 33452322Smckusick NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); 33552322Smckusick if (error = namei(&nd)) 33647540Skarels return (error); 33752322Smckusick mp = nd.ni_vp->v_mount; 33841400Smckusick sp = &mp->mnt_stat; 33952322Smckusick vrele(nd.ni_vp); 34048026Smckusick if (error = VFS_STATFS(mp, sp, p)) 34147540Skarels return (error); 34241400Smckusick sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 34347540Skarels return (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp))); 34437741Smckusick } 34537741Smckusick 34642441Smckusick /* 34749365Smckusick * Get filesystem statistics. 34842441Smckusick */ 34954916Storek struct fstatfs_args { 35054916Storek int fd; 35154916Storek struct statfs *buf; 35254916Storek }; 35342441Smckusick /* ARGSUSED */ 35442441Smckusick fstatfs(p, uap, retval) 35545914Smckusick struct proc *p; 35654916Storek register struct fstatfs_args *uap; 35742441Smckusick int *retval; 35842441Smckusick { 35937741Smckusick struct file *fp; 36039464Smckusick struct mount *mp; 36140343Smckusick register struct statfs *sp; 36237741Smckusick int error; 36337741Smckusick 36445914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 36547540Skarels return (error); 36639464Smckusick mp = ((struct vnode *)fp->f_data)->v_mount; 36741400Smckusick sp = &mp->mnt_stat; 36848026Smckusick if (error = VFS_STATFS(mp, sp, p)) 36947540Skarels return (error); 37041400Smckusick sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 37147540Skarels return (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp))); 37237741Smckusick } 37337741Smckusick 37437741Smckusick /* 37549365Smckusick * Get statistics on all filesystems. 37638270Smckusick */ 37754916Storek struct getfsstat_args { 37854916Storek struct statfs *buf; 37954916Storek long bufsize; 38054916Storek int flags; 38154916Storek }; 38242441Smckusick getfsstat(p, uap, retval) 38345914Smckusick struct proc *p; 38454916Storek register struct getfsstat_args *uap; 38542441Smckusick int *retval; 38642441Smckusick { 38738270Smckusick register struct mount *mp; 38840343Smckusick register struct statfs *sp; 38939606Smckusick caddr_t sfsp; 39038270Smckusick long count, maxcount, error; 39138270Smckusick 39238270Smckusick maxcount = uap->bufsize / sizeof(struct statfs); 39339606Smckusick sfsp = (caddr_t)uap->buf; 39438270Smckusick mp = rootfs; 39538270Smckusick count = 0; 39638270Smckusick do { 39741400Smckusick if (sfsp && count < maxcount && 39841400Smckusick ((mp->mnt_flag & MNT_MLOCK) == 0)) { 39941400Smckusick sp = &mp->mnt_stat; 40040343Smckusick /* 40140343Smckusick * If MNT_NOWAIT is specified, do not refresh the 40240343Smckusick * fsstat cache. MNT_WAIT overrides MNT_NOWAIT. 40340343Smckusick */ 40440343Smckusick if (((uap->flags & MNT_NOWAIT) == 0 || 40540343Smckusick (uap->flags & MNT_WAIT)) && 40648026Smckusick (error = VFS_STATFS(mp, sp, p))) { 40741400Smckusick mp = mp->mnt_prev; 40839607Smckusick continue; 40939607Smckusick } 41041400Smckusick sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 41140343Smckusick if (error = copyout((caddr_t)sp, sfsp, sizeof(*sp))) 41247540Skarels return (error); 41340343Smckusick sfsp += sizeof(*sp); 41438270Smckusick } 41539606Smckusick count++; 41641400Smckusick mp = mp->mnt_prev; 41738270Smckusick } while (mp != rootfs); 41838270Smckusick if (sfsp && count > maxcount) 41942441Smckusick *retval = maxcount; 42038270Smckusick else 42142441Smckusick *retval = count; 42247540Skarels return (0); 42338270Smckusick } 42438270Smckusick 42538270Smckusick /* 42638259Smckusick * Change current working directory to a given file descriptor. 42738259Smckusick */ 42854916Storek struct fchdir_args { 42954916Storek int fd; 43054916Storek }; 43142441Smckusick /* ARGSUSED */ 43242441Smckusick fchdir(p, uap, retval) 43345914Smckusick struct proc *p; 43454916Storek struct fchdir_args *uap; 43542441Smckusick int *retval; 43638259Smckusick { 43745914Smckusick register struct filedesc *fdp = p->p_fd; 43838259Smckusick register struct vnode *vp; 43938259Smckusick struct file *fp; 44038259Smckusick int error; 44138259Smckusick 44245914Smckusick if (error = getvnode(fdp, uap->fd, &fp)) 44347540Skarels return (error); 44438259Smckusick vp = (struct vnode *)fp->f_data; 44538259Smckusick VOP_LOCK(vp); 44638259Smckusick if (vp->v_type != VDIR) 44738259Smckusick error = ENOTDIR; 44838259Smckusick else 44948026Smckusick error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p); 45038259Smckusick VOP_UNLOCK(vp); 45139860Smckusick if (error) 45247540Skarels return (error); 45339860Smckusick VREF(vp); 45445914Smckusick vrele(fdp->fd_cdir); 45545914Smckusick fdp->fd_cdir = vp; 45647540Skarels return (0); 45738259Smckusick } 45838259Smckusick 45938259Smckusick /* 46037741Smckusick * Change current working directory (``.''). 46137741Smckusick */ 46254916Storek struct chdir_args { 46354916Storek char *fname; 46454916Storek }; 46542441Smckusick /* ARGSUSED */ 46642441Smckusick chdir(p, uap, retval) 46745914Smckusick struct proc *p; 46854916Storek struct chdir_args *uap; 46942441Smckusick int *retval; 47037741Smckusick { 47145914Smckusick register struct filedesc *fdp = p->p_fd; 47237741Smckusick int error; 47347540Skarels struct nameidata nd; 4746254Sroot 47552322Smckusick NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 47652781Sralph if (error = chdirec(&nd, p)) 47747540Skarels return (error); 47845914Smckusick vrele(fdp->fd_cdir); 47952322Smckusick fdp->fd_cdir = nd.ni_vp; 48047540Skarels return (0); 48137741Smckusick } 4826254Sroot 48337741Smckusick /* 48437741Smckusick * Change notion of root (``/'') directory. 48537741Smckusick */ 48654916Storek struct chroot_args { 48754916Storek char *fname; 48854916Storek }; 48942441Smckusick /* ARGSUSED */ 49042441Smckusick chroot(p, uap, retval) 49145914Smckusick struct proc *p; 49254916Storek struct chroot_args *uap; 49342441Smckusick int *retval; 49437741Smckusick { 49545914Smckusick register struct filedesc *fdp = p->p_fd; 49637741Smckusick int error; 49747540Skarels struct nameidata nd; 49837741Smckusick 49947540Skarels if (error = suser(p->p_ucred, &p->p_acflag)) 50047540Skarels return (error); 50152322Smckusick NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 50252781Sralph if (error = chdirec(&nd, p)) 50347540Skarels return (error); 50445914Smckusick if (fdp->fd_rdir != NULL) 50545914Smckusick vrele(fdp->fd_rdir); 50652322Smckusick fdp->fd_rdir = nd.ni_vp; 50747540Skarels return (0); 5086254Sroot } 5096254Sroot 51037Sbill /* 51137741Smckusick * Common routine for chroot and chdir. 51237741Smckusick */ 51347540Skarels chdirec(ndp, p) 51452322Smckusick register struct nameidata *ndp; 51547540Skarels struct proc *p; 51637741Smckusick { 51737741Smckusick struct vnode *vp; 51837741Smckusick int error; 51937741Smckusick 52052322Smckusick if (error = namei(ndp)) 52137741Smckusick return (error); 52237741Smckusick vp = ndp->ni_vp; 52337741Smckusick if (vp->v_type != VDIR) 52437741Smckusick error = ENOTDIR; 52537741Smckusick else 52648026Smckusick error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p); 52737741Smckusick VOP_UNLOCK(vp); 52837741Smckusick if (error) 52937741Smckusick vrele(vp); 53037741Smckusick return (error); 53137741Smckusick } 53237741Smckusick 53337741Smckusick /* 5346254Sroot * Open system call. 53542441Smckusick * Check permissions, allocate an open file structure, 53642441Smckusick * and call the device open routine if any. 5376254Sroot */ 53854916Storek struct open_args { 53954916Storek char *fname; 54054916Storek int mode; 54154916Storek int crtmode; 54254916Storek }; 54342441Smckusick open(p, uap, retval) 54445914Smckusick struct proc *p; 54554916Storek register struct open_args *uap; 54642441Smckusick int *retval; 5476254Sroot { 54845914Smckusick register struct filedesc *fdp = p->p_fd; 54942441Smckusick register struct file *fp; 55050111Smckusick register struct vnode *vp; 55137741Smckusick int fmode, cmode; 55237741Smckusick struct file *nfp; 55349945Smckusick int type, indx, error; 55449945Smckusick struct flock lf; 55547540Skarels struct nameidata nd; 55637741Smckusick extern struct fileops vnops; 5576254Sroot 55845914Smckusick if (error = falloc(p, &nfp, &indx)) 55947540Skarels return (error); 56037741Smckusick fp = nfp; 56146553Skarels fmode = FFLAGS(uap->mode); 56245914Smckusick cmode = ((uap->crtmode &~ fdp->fd_cmask) & 07777) &~ S_ISVTX; 56352322Smckusick NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->fname, p); 56445202Smckusick p->p_dupfd = -indx - 1; /* XXX check for fdopen */ 56552322Smckusick if (error = vn_open(&nd, fmode, cmode)) { 56649980Smckusick ffree(fp); 56754723Smckusick if ((error == ENODEV || error == ENXIO) && 56854723Smckusick p->p_dupfd >= 0 && /* XXX from fdopen */ 56953828Spendry (error = dupfdopen(fdp, indx, p->p_dupfd, 57053828Spendry fmode, error)) == 0) { 57142441Smckusick *retval = indx; 57247540Skarels return (0); 57342441Smckusick } 57440884Smckusick if (error == ERESTART) 57540884Smckusick error = EINTR; 57647688Skarels fdp->fd_ofiles[indx] = NULL; 57747540Skarels return (error); 57812756Ssam } 57953828Spendry p->p_dupfd = 0; 58052322Smckusick vp = nd.ni_vp; 58149949Smckusick fp->f_flag = fmode & FMASK; 58254348Smckusick fp->f_type = DTYPE_VNODE; 58354348Smckusick fp->f_ops = &vnops; 58454348Smckusick fp->f_data = (caddr_t)vp; 58549945Smckusick if (fmode & (O_EXLOCK | O_SHLOCK)) { 58649945Smckusick lf.l_whence = SEEK_SET; 58749945Smckusick lf.l_start = 0; 58849945Smckusick lf.l_len = 0; 58949945Smckusick if (fmode & O_EXLOCK) 59049945Smckusick lf.l_type = F_WRLCK; 59149945Smckusick else 59249945Smckusick lf.l_type = F_RDLCK; 59349945Smckusick type = F_FLOCK; 59449945Smckusick if ((fmode & FNONBLOCK) == 0) 59549945Smckusick type |= F_WAIT; 59650111Smckusick if (error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, type)) { 59750111Smckusick VOP_UNLOCK(vp); 59850111Smckusick (void) vn_close(vp, fp->f_flag, fp->f_cred, p); 59949980Smckusick ffree(fp); 60049945Smckusick fdp->fd_ofiles[indx] = NULL; 60149945Smckusick return (error); 60249945Smckusick } 60349949Smckusick fp->f_flag |= FHASLOCK; 60449945Smckusick } 60550111Smckusick VOP_UNLOCK(vp); 60642441Smckusick *retval = indx; 60747540Skarels return (0); 6086254Sroot } 6096254Sroot 61042955Smckusick #ifdef COMPAT_43 6116254Sroot /* 61242441Smckusick * Creat system call. 6136254Sroot */ 61454916Storek struct ocreat_args { 61554916Storek char *fname; 61654916Storek int fmode; 61754916Storek }; 61842955Smckusick ocreat(p, uap, retval) 61942441Smckusick struct proc *p; 62054916Storek register struct ocreat_args *uap; 62142441Smckusick int *retval; 6226254Sroot { 62354916Storek struct open_args openuap; 62442441Smckusick 62542441Smckusick openuap.fname = uap->fname; 62642441Smckusick openuap.crtmode = uap->fmode; 62742441Smckusick openuap.mode = O_WRONLY | O_CREAT | O_TRUNC; 62847540Skarels return (open(p, &openuap, retval)); 62942441Smckusick } 63042955Smckusick #endif /* COMPAT_43 */ 63142441Smckusick 63242441Smckusick /* 63349365Smckusick * Mknod system call. 63442441Smckusick */ 63554916Storek struct mknod_args { 63654916Storek char *fname; 63754916Storek int fmode; 63854916Storek int dev; 63954916Storek }; 64042441Smckusick /* ARGSUSED */ 64142441Smckusick mknod(p, uap, retval) 64245914Smckusick struct proc *p; 64354916Storek register struct mknod_args *uap; 64442441Smckusick int *retval; 64542441Smckusick { 64637741Smckusick register struct vnode *vp; 64737741Smckusick struct vattr vattr; 64837741Smckusick int error; 64947540Skarels struct nameidata nd; 6506254Sroot 65147540Skarels if (error = suser(p->p_ucred, &p->p_acflag)) 65247540Skarels return (error); 65352322Smckusick NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->fname, p); 65452322Smckusick if (error = namei(&nd)) 65547540Skarels return (error); 65652322Smckusick vp = nd.ni_vp; 65737741Smckusick if (vp != NULL) { 65837741Smckusick error = EEXIST; 65912756Ssam goto out; 6606254Sroot } 66141362Smckusick VATTR_NULL(&vattr); 66240635Smckusick switch (uap->fmode & S_IFMT) { 66312756Ssam 66440635Smckusick case S_IFMT: /* used by badsect to flag bad sectors */ 66537741Smckusick vattr.va_type = VBAD; 66637741Smckusick break; 66740635Smckusick case S_IFCHR: 66837741Smckusick vattr.va_type = VCHR; 66937741Smckusick break; 67040635Smckusick case S_IFBLK: 67137741Smckusick vattr.va_type = VBLK; 67237741Smckusick break; 67337741Smckusick default: 67437741Smckusick error = EINVAL; 67537741Smckusick goto out; 6766254Sroot } 67745914Smckusick vattr.va_mode = (uap->fmode & 07777) &~ p->p_fd->fd_cmask; 67837741Smckusick vattr.va_rdev = uap->dev; 6796254Sroot out: 68042465Smckusick if (!error) { 68152322Smckusick LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 68252322Smckusick error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr); 68342465Smckusick } else { 68452322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 68552322Smckusick if (nd.ni_dvp == vp) 68652322Smckusick vrele(nd.ni_dvp); 68743344Smckusick else 68852322Smckusick vput(nd.ni_dvp); 68942465Smckusick if (vp) 69042465Smckusick vrele(vp); 69142465Smckusick } 69247540Skarels return (error); 6936254Sroot } 6946254Sroot 6956254Sroot /* 69649365Smckusick * Mkfifo system call. 69740285Smckusick */ 69854916Storek struct mkfifo_args { 69954916Storek char *fname; 70054916Storek int fmode; 70154916Storek }; 70242441Smckusick /* ARGSUSED */ 70342441Smckusick mkfifo(p, uap, retval) 70445914Smckusick struct proc *p; 70554916Storek register struct mkfifo_args *uap; 70642441Smckusick int *retval; 70742441Smckusick { 70840285Smckusick struct vattr vattr; 70940285Smckusick int error; 71047540Skarels struct nameidata nd; 71140285Smckusick 71240285Smckusick #ifndef FIFO 71347540Skarels return (EOPNOTSUPP); 71440285Smckusick #else 71552322Smckusick NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->fname, p); 71652322Smckusick if (error = namei(&nd)) 71747540Skarels return (error); 71852322Smckusick if (nd.ni_vp != NULL) { 71952322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 72052322Smckusick if (nd.ni_dvp == nd.ni_vp) 72152322Smckusick vrele(nd.ni_dvp); 72243344Smckusick else 72352322Smckusick vput(nd.ni_dvp); 72452322Smckusick vrele(nd.ni_vp); 72547540Skarels return (EEXIST); 72640285Smckusick } 72745785Sbostic VATTR_NULL(&vattr); 72845785Sbostic vattr.va_type = VFIFO; 72945914Smckusick vattr.va_mode = (uap->fmode & 07777) &~ p->p_fd->fd_cmask; 73052322Smckusick LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 73152322Smckusick return (VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr)); 73240285Smckusick #endif /* FIFO */ 73340285Smckusick } 73440285Smckusick 73540285Smckusick /* 73649365Smckusick * Link system call. 7376254Sroot */ 73854916Storek struct link_args { 73954916Storek char *target; 74054916Storek char *linkname; 74154916Storek }; 74242441Smckusick /* ARGSUSED */ 74342441Smckusick link(p, uap, retval) 74445914Smckusick struct proc *p; 74554916Storek register struct link_args *uap; 74642441Smckusick int *retval; 74742441Smckusick { 74837741Smckusick register struct vnode *vp, *xp; 74937741Smckusick int error; 75047540Skarels struct nameidata nd; 7516254Sroot 75252322Smckusick NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->target, p); 75352322Smckusick if (error = namei(&nd)) 75447540Skarels return (error); 75552322Smckusick vp = nd.ni_vp; 75637741Smckusick if (vp->v_type == VDIR && 75747540Skarels (error = suser(p->p_ucred, &p->p_acflag))) 75837741Smckusick goto out1; 75952322Smckusick nd.ni_cnd.cn_nameiop = CREATE; 76052322Smckusick nd.ni_cnd.cn_flags = LOCKPARENT; 76152322Smckusick nd.ni_dirp = (caddr_t)uap->linkname; 76252322Smckusick if (error = namei(&nd)) 76337741Smckusick goto out1; 76452322Smckusick xp = nd.ni_vp; 7656254Sroot if (xp != NULL) { 76637741Smckusick error = EEXIST; 7676254Sroot goto out; 7686254Sroot } 76952322Smckusick xp = nd.ni_dvp; 7706254Sroot out: 77142465Smckusick if (!error) { 77252192Smckusick LEASE_CHECK(xp, p, p->p_ucred, LEASE_WRITE); 77352192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 77452821Smckusick error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd); 77542465Smckusick } else { 77652322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 77752322Smckusick if (nd.ni_dvp == nd.ni_vp) 77852322Smckusick vrele(nd.ni_dvp); 77943344Smckusick else 78052322Smckusick vput(nd.ni_dvp); 78152322Smckusick if (nd.ni_vp) 78252322Smckusick vrele(nd.ni_vp); 78342465Smckusick } 78437741Smckusick out1: 78537741Smckusick vrele(vp); 78647540Skarels return (error); 7876254Sroot } 7886254Sroot 7896254Sroot /* 79049365Smckusick * Make a symbolic link. 7916254Sroot */ 79254916Storek struct symlink_args { 79354916Storek char *target; 79454916Storek char *linkname; 79554916Storek }; 79642441Smckusick /* ARGSUSED */ 79742441Smckusick symlink(p, uap, retval) 79845914Smckusick struct proc *p; 79954916Storek register struct symlink_args *uap; 80042441Smckusick int *retval; 80142441Smckusick { 80237741Smckusick struct vattr vattr; 80337741Smckusick char *target; 80437741Smckusick int error; 80547540Skarels struct nameidata nd; 8066254Sroot 80737741Smckusick MALLOC(target, char *, MAXPATHLEN, M_NAMEI, M_WAITOK); 80837741Smckusick if (error = copyinstr(uap->target, target, MAXPATHLEN, (u_int *)0)) 80942465Smckusick goto out; 81052322Smckusick NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->linkname, p); 81152322Smckusick if (error = namei(&nd)) 81242465Smckusick goto out; 81352322Smckusick if (nd.ni_vp) { 81452322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 81552322Smckusick if (nd.ni_dvp == nd.ni_vp) 81652322Smckusick vrele(nd.ni_dvp); 81743344Smckusick else 81852322Smckusick vput(nd.ni_dvp); 81952322Smckusick vrele(nd.ni_vp); 82037741Smckusick error = EEXIST; 82137741Smckusick goto out; 8226254Sroot } 82341362Smckusick VATTR_NULL(&vattr); 82445914Smckusick vattr.va_mode = 0777 &~ p->p_fd->fd_cmask; 82552322Smckusick LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 82652322Smckusick error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr, target); 82737741Smckusick out: 82837741Smckusick FREE(target, M_NAMEI); 82947540Skarels return (error); 8306254Sroot } 8316254Sroot 8326254Sroot /* 83349365Smckusick * Delete a name from the filesystem. 8346254Sroot */ 83554916Storek struct unlink_args { 83654916Storek char *name; 83754916Storek }; 83842441Smckusick /* ARGSUSED */ 83942441Smckusick unlink(p, uap, retval) 84045914Smckusick struct proc *p; 84154916Storek struct unlink_args *uap; 84242441Smckusick int *retval; 8436254Sroot { 84437741Smckusick register struct vnode *vp; 84537741Smckusick int error; 84647540Skarels struct nameidata nd; 8476254Sroot 84859382Smckusick NDINIT(&nd, DELETE, LOCKPARENT, UIO_USERSPACE, uap->name, p); 84952322Smckusick if (error = namei(&nd)) 85047540Skarels return (error); 85152322Smckusick vp = nd.ni_vp; 85259382Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 85359382Smckusick VOP_LOCK(vp); 85437741Smckusick if (vp->v_type == VDIR && 85547540Skarels (error = suser(p->p_ucred, &p->p_acflag))) 8566254Sroot goto out; 8576254Sroot /* 85849365Smckusick * The root of a mounted filesystem cannot be deleted. 8596254Sroot */ 86037741Smckusick if (vp->v_flag & VROOT) { 86137741Smckusick error = EBUSY; 8626254Sroot goto out; 8636254Sroot } 86445738Smckusick (void) vnode_pager_uncache(vp); 8656254Sroot out: 86642465Smckusick if (!error) { 86752322Smckusick LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 86852322Smckusick error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); 86942465Smckusick } else { 87052322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 87152322Smckusick if (nd.ni_dvp == vp) 87252322Smckusick vrele(nd.ni_dvp); 87343344Smckusick else 87452322Smckusick vput(nd.ni_dvp); 87542465Smckusick vput(vp); 87642465Smckusick } 87747540Skarels return (error); 8786254Sroot } 8796254Sroot 88054916Storek struct __lseek_args { 88154863Storek int fdes; 88254863Storek int pad; 88354863Storek off_t off; 88454863Storek int sbase; 88554863Storek }; 88654863Storek 8876254Sroot /* 88849365Smckusick * Seek system call. 8896254Sroot */ 89053759Smckusick __lseek(p, uap, retval) 89153468Smckusick struct proc *p; 89254916Storek register struct __lseek_args *uap; 89354916Storek int *retval; 89442441Smckusick { 89547540Skarels struct ucred *cred = p->p_ucred; 89645914Smckusick register struct filedesc *fdp = p->p_fd; 89742441Smckusick register struct file *fp; 89837741Smckusick struct vattr vattr; 89937741Smckusick int error; 9006254Sroot 90147540Skarels if ((unsigned)uap->fdes >= fdp->fd_nfiles || 90247688Skarels (fp = fdp->fd_ofiles[uap->fdes]) == NULL) 90347540Skarels return (EBADF); 90437741Smckusick if (fp->f_type != DTYPE_VNODE) 90547540Skarels return (ESPIPE); 90613878Ssam switch (uap->sbase) { 90713878Ssam 90813878Ssam case L_INCR: 90913878Ssam fp->f_offset += uap->off; 91013878Ssam break; 91113878Ssam 91213878Ssam case L_XTND: 91337741Smckusick if (error = VOP_GETATTR((struct vnode *)fp->f_data, 91448026Smckusick &vattr, cred, p)) 91547540Skarels return (error); 91637741Smckusick fp->f_offset = uap->off + vattr.va_size; 91713878Ssam break; 91813878Ssam 91913878Ssam case L_SET: 92013878Ssam fp->f_offset = uap->off; 92113878Ssam break; 92213878Ssam 92313878Ssam default: 92447540Skarels return (EINVAL); 92513878Ssam } 92654916Storek *(off_t *)retval = fp->f_offset; 92747540Skarels return (0); 9286254Sroot } 9296254Sroot 9306254Sroot /* 931*60036Smckusick * Old lseek system call. 932*60036Smckusick * 933*60036Smckusick * XXX should be COMPAT_43, but too much breaks. 934*60036Smckusick */ 935*60036Smckusick struct lseek_args { 936*60036Smckusick int fdes; 937*60036Smckusick long off; 938*60036Smckusick int sbase; 939*60036Smckusick }; 940*60036Smckusick lseek(p, uap, retval) 941*60036Smckusick struct proc *p; 942*60036Smckusick register struct lseek_args *uap; 943*60036Smckusick int *retval; 944*60036Smckusick { 945*60036Smckusick struct __lseek_args nuap; 946*60036Smckusick off_t qret; 947*60036Smckusick int error; 948*60036Smckusick 949*60036Smckusick nuap.fdes = uap->fdes; 950*60036Smckusick nuap.off = uap->off; 951*60036Smckusick nuap.sbase = uap->sbase; 952*60036Smckusick error = __lseek(p, &nuap, &qret); 953*60036Smckusick *(long *)retval = qret; 954*60036Smckusick return (error); 955*60036Smckusick } 956*60036Smckusick 957*60036Smckusick /* 95849365Smckusick * Check access permissions. 9596254Sroot */ 96054916Storek struct saccess_args { 96154916Storek char *fname; 96254916Storek int fmode; 96354916Storek }; 96442441Smckusick /* ARGSUSED */ 96542441Smckusick saccess(p, uap, retval) 96645914Smckusick struct proc *p; 96754916Storek register struct saccess_args *uap; 96842441Smckusick int *retval; 96942441Smckusick { 97047540Skarels register struct ucred *cred = p->p_ucred; 97137741Smckusick register struct vnode *vp; 97237741Smckusick int error, mode, svuid, svgid; 97347540Skarels struct nameidata nd; 9746254Sroot 97542441Smckusick svuid = cred->cr_uid; 97642441Smckusick svgid = cred->cr_groups[0]; 97747540Skarels cred->cr_uid = p->p_cred->p_ruid; 97847540Skarels cred->cr_groups[0] = p->p_cred->p_rgid; 97952322Smckusick NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 98052322Smckusick if (error = namei(&nd)) 98137741Smckusick goto out1; 98252322Smckusick vp = nd.ni_vp; 98337741Smckusick /* 98437741Smckusick * fmode == 0 means only check for exist 98537741Smckusick */ 98637741Smckusick if (uap->fmode) { 98737741Smckusick mode = 0; 98837741Smckusick if (uap->fmode & R_OK) 98937741Smckusick mode |= VREAD; 99037741Smckusick if (uap->fmode & W_OK) 99137741Smckusick mode |= VWRITE; 99237741Smckusick if (uap->fmode & X_OK) 99337741Smckusick mode |= VEXEC; 99439543Smckusick if ((mode & VWRITE) == 0 || (error = vn_writechk(vp)) == 0) 99548026Smckusick error = VOP_ACCESS(vp, mode, cred, p); 9966254Sroot } 99737741Smckusick vput(vp); 99837741Smckusick out1: 99942441Smckusick cred->cr_uid = svuid; 100042441Smckusick cred->cr_groups[0] = svgid; 100147540Skarels return (error); 10026254Sroot } 10036254Sroot 100454348Smckusick #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 10056254Sroot /* 100649365Smckusick * Stat system call. 100749365Smckusick * This version follows links. 100837Sbill */ 100954916Storek struct ostat_args { 101054916Storek char *fname; 101154916Storek struct ostat *ub; 101254916Storek }; 101342441Smckusick /* ARGSUSED */ 101453759Smckusick ostat(p, uap, retval) 101545914Smckusick struct proc *p; 101654916Storek register struct ostat_args *uap; 101753468Smckusick int *retval; 101853468Smckusick { 101953468Smckusick struct stat sb; 102053468Smckusick struct ostat osb; 102153468Smckusick int error; 102253468Smckusick struct nameidata nd; 102353468Smckusick 102453468Smckusick NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 102553468Smckusick if (error = namei(&nd)) 102653468Smckusick return (error); 102753468Smckusick error = vn_stat(nd.ni_vp, &sb, p); 102853468Smckusick vput(nd.ni_vp); 102953468Smckusick if (error) 103053468Smckusick return (error); 103153468Smckusick cvtstat(&sb, &osb); 103253468Smckusick error = copyout((caddr_t)&osb, (caddr_t)uap->ub, sizeof (osb)); 103353468Smckusick return (error); 103453468Smckusick } 103553468Smckusick 103653468Smckusick /* 103753468Smckusick * Lstat system call. 103853468Smckusick * This version does not follow links. 103953468Smckusick */ 104054916Storek struct olstat_args { 104154916Storek char *fname; 104254916Storek struct ostat *ub; 104354916Storek }; 104453468Smckusick /* ARGSUSED */ 104553759Smckusick olstat(p, uap, retval) 104653468Smckusick struct proc *p; 104754916Storek register struct olstat_args *uap; 104853468Smckusick int *retval; 104953468Smckusick { 105053468Smckusick struct stat sb; 105153468Smckusick struct ostat osb; 105253468Smckusick int error; 105353468Smckusick struct nameidata nd; 105453468Smckusick 105553468Smckusick NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 105653468Smckusick if (error = namei(&nd)) 105753468Smckusick return (error); 105853468Smckusick error = vn_stat(nd.ni_vp, &sb, p); 105953468Smckusick vput(nd.ni_vp); 106053468Smckusick if (error) 106153468Smckusick return (error); 106253468Smckusick cvtstat(&sb, &osb); 106353468Smckusick error = copyout((caddr_t)&osb, (caddr_t)uap->ub, sizeof (osb)); 106453468Smckusick return (error); 106553468Smckusick } 106653468Smckusick 106753468Smckusick /* 106853468Smckusick * convert from an old to a new stat structure. 106953468Smckusick */ 107053468Smckusick cvtstat(st, ost) 107153468Smckusick struct stat *st; 107253468Smckusick struct ostat *ost; 107353468Smckusick { 107453468Smckusick 107553468Smckusick ost->st_dev = st->st_dev; 107653468Smckusick ost->st_ino = st->st_ino; 107753468Smckusick ost->st_mode = st->st_mode; 107853468Smckusick ost->st_nlink = st->st_nlink; 107953468Smckusick ost->st_uid = st->st_uid; 108053468Smckusick ost->st_gid = st->st_gid; 108153468Smckusick ost->st_rdev = st->st_rdev; 108253468Smckusick if (st->st_size < (quad_t)1 << 32) 108353468Smckusick ost->st_size = st->st_size; 108453468Smckusick else 108553468Smckusick ost->st_size = -2; 108653468Smckusick ost->st_atime = st->st_atime; 108753468Smckusick ost->st_mtime = st->st_mtime; 108853468Smckusick ost->st_ctime = st->st_ctime; 108953468Smckusick ost->st_blksize = st->st_blksize; 109053468Smckusick ost->st_blocks = st->st_blocks; 109153468Smckusick ost->st_flags = st->st_flags; 109253468Smckusick ost->st_gen = st->st_gen; 109353468Smckusick } 109454348Smckusick #endif /* COMPAT_43 || COMPAT_SUNOS */ 109553468Smckusick 109653468Smckusick /* 109753468Smckusick * Stat system call. 109853468Smckusick * This version follows links. 109953468Smckusick */ 110054916Storek struct stat_args { 110154916Storek char *fname; 110254916Storek struct stat *ub; 110354916Storek }; 110453468Smckusick /* ARGSUSED */ 110553759Smckusick stat(p, uap, retval) 110653468Smckusick struct proc *p; 110754916Storek register struct stat_args *uap; 110842441Smckusick int *retval; 110937Sbill { 111042441Smckusick struct stat sb; 111142441Smckusick int error; 111247540Skarels struct nameidata nd; 111337Sbill 111452322Smckusick NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 111552322Smckusick if (error = namei(&nd)) 111647540Skarels return (error); 111752322Smckusick error = vn_stat(nd.ni_vp, &sb, p); 111852322Smckusick vput(nd.ni_vp); 111942441Smckusick if (error) 112047540Skarels return (error); 112142441Smckusick error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb)); 112247540Skarels return (error); 112337Sbill } 112437Sbill 112537Sbill /* 112649365Smckusick * Lstat system call. 112749365Smckusick * This version does not follow links. 11285992Swnj */ 112954916Storek struct lstat_args { 113054916Storek char *fname; 113154916Storek struct stat *ub; 113254916Storek }; 113342441Smckusick /* ARGSUSED */ 113453759Smckusick lstat(p, uap, retval) 113545914Smckusick struct proc *p; 113654916Storek register struct lstat_args *uap; 113742441Smckusick int *retval; 113842441Smckusick { 113937741Smckusick int error; 114059373Smckusick struct vnode *vp, *dvp; 114159373Smckusick struct stat sb, sb1; 114247540Skarels struct nameidata nd; 11435992Swnj 114459373Smckusick NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | LOCKPARENT, UIO_USERSPACE, 114559373Smckusick uap->fname, p); 114652322Smckusick if (error = namei(&nd)) 114747540Skarels return (error); 114859373Smckusick /* 114959373Smckusick * For symbolic links, always return the attributes of its 115059373Smckusick * containing directory, except for mode, size, and links. 115159373Smckusick */ 115259373Smckusick vp = nd.ni_vp; 115359373Smckusick dvp = nd.ni_dvp; 115459373Smckusick if (vp->v_type != VLNK) { 115559373Smckusick if (dvp == vp) 115659373Smckusick vrele(dvp); 115759373Smckusick else 115859373Smckusick vput(dvp); 115959373Smckusick error = vn_stat(vp, &sb, p); 116059373Smckusick vput(vp); 116159373Smckusick if (error) 116259373Smckusick return (error); 116359373Smckusick } else { 116459373Smckusick error = vn_stat(dvp, &sb, p); 116559373Smckusick vput(dvp); 116659373Smckusick if (error) { 116759373Smckusick vput(vp); 116859373Smckusick return (error); 116959373Smckusick } 117059373Smckusick error = vn_stat(vp, &sb1, p); 117159373Smckusick vput(vp); 117259373Smckusick if (error) 117359373Smckusick return (error); 117459373Smckusick sb.st_mode &= ~S_IFDIR; 117559373Smckusick sb.st_mode |= S_IFLNK; 117659373Smckusick sb.st_nlink = sb1.st_nlink; 117759373Smckusick sb.st_size = sb1.st_size; 117859373Smckusick sb.st_blocks = sb1.st_blocks; 117959373Smckusick } 118037741Smckusick error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb)); 118147540Skarels return (error); 11825992Swnj } 11835992Swnj 11845992Swnj /* 118549365Smckusick * Return target name of a symbolic link. 118637Sbill */ 118754916Storek struct readlink_args { 118854916Storek char *name; 118954916Storek char *buf; 119054916Storek int count; 119154916Storek }; 119242441Smckusick /* ARGSUSED */ 119342441Smckusick readlink(p, uap, retval) 119445914Smckusick struct proc *p; 119554916Storek register struct readlink_args *uap; 119642441Smckusick int *retval; 119742441Smckusick { 119837741Smckusick register struct vnode *vp; 119937741Smckusick struct iovec aiov; 120037741Smckusick struct uio auio; 120137741Smckusick int error; 120247540Skarels struct nameidata nd; 12035992Swnj 120452322Smckusick NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, uap->name, p); 120552322Smckusick if (error = namei(&nd)) 120647540Skarels return (error); 120752322Smckusick vp = nd.ni_vp; 120837741Smckusick if (vp->v_type != VLNK) { 120937741Smckusick error = EINVAL; 12105992Swnj goto out; 12115992Swnj } 121237741Smckusick aiov.iov_base = uap->buf; 121337741Smckusick aiov.iov_len = uap->count; 121437741Smckusick auio.uio_iov = &aiov; 121537741Smckusick auio.uio_iovcnt = 1; 121637741Smckusick auio.uio_offset = 0; 121737741Smckusick auio.uio_rw = UIO_READ; 121837741Smckusick auio.uio_segflg = UIO_USERSPACE; 121948026Smckusick auio.uio_procp = p; 122037741Smckusick auio.uio_resid = uap->count; 122147540Skarels error = VOP_READLINK(vp, &auio, p->p_ucred); 12225992Swnj out: 122337741Smckusick vput(vp); 122442441Smckusick *retval = uap->count - auio.uio_resid; 122547540Skarels return (error); 12265992Swnj } 12275992Swnj 12289167Ssam /* 122938259Smckusick * Change flags of a file given path name. 123038259Smckusick */ 123154916Storek struct chflags_args { 123254916Storek char *fname; 123354916Storek int flags; 123454916Storek }; 123542441Smckusick /* ARGSUSED */ 123642441Smckusick chflags(p, uap, retval) 123745914Smckusick struct proc *p; 123854916Storek register struct chflags_args *uap; 123942441Smckusick int *retval; 124042441Smckusick { 124138259Smckusick register struct vnode *vp; 124238259Smckusick struct vattr vattr; 124338259Smckusick int error; 124447540Skarels struct nameidata nd; 124538259Smckusick 124659382Smckusick NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->fname, p); 124752322Smckusick if (error = namei(&nd)) 124847540Skarels return (error); 124952322Smckusick vp = nd.ni_vp; 125059382Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 125159382Smckusick 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; 125848026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 125938259Smckusick out: 126038259Smckusick vput(vp); 126147540Skarels return (error); 126238259Smckusick } 126338259Smckusick 126438259Smckusick /* 126538259Smckusick * Change flags of a file given a file descriptor. 126638259Smckusick */ 126754916Storek struct fchflags_args { 126854916Storek int fd; 126954916Storek int flags; 127054916Storek }; 127142441Smckusick /* ARGSUSED */ 127242441Smckusick fchflags(p, uap, retval) 127345914Smckusick struct proc *p; 127454916Storek register struct fchflags_args *uap; 127542441Smckusick int *retval; 127642441Smckusick { 127738259Smckusick struct vattr vattr; 127838259Smckusick struct vnode *vp; 127938259Smckusick struct file *fp; 128038259Smckusick int error; 128138259Smckusick 128245914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 128347540Skarels return (error); 128438259Smckusick vp = (struct vnode *)fp->f_data; 128559382Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 128638259Smckusick VOP_LOCK(vp); 128741400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 128838259Smckusick error = EROFS; 128938259Smckusick goto out; 129038259Smckusick } 129145785Sbostic VATTR_NULL(&vattr); 129245785Sbostic vattr.va_flags = uap->flags; 129348026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 129438259Smckusick out: 129538259Smckusick VOP_UNLOCK(vp); 129647540Skarels return (error); 129738259Smckusick } 129838259Smckusick 129938259Smckusick /* 13009167Ssam * Change mode of a file given path name. 13019167Ssam */ 130254916Storek struct chmod_args { 130354916Storek char *fname; 130454916Storek int fmode; 130554916Storek }; 130642441Smckusick /* ARGSUSED */ 130742441Smckusick chmod(p, uap, retval) 130845914Smckusick struct proc *p; 130954916Storek register struct chmod_args *uap; 131042441Smckusick int *retval; 131142441Smckusick { 131237741Smckusick register struct vnode *vp; 131337741Smckusick struct vattr vattr; 131437741Smckusick int error; 131547540Skarels struct nameidata nd; 13165992Swnj 131759382Smckusick NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->fname, p); 131852322Smckusick if (error = namei(&nd)) 131947540Skarels return (error); 132052322Smckusick vp = nd.ni_vp; 132159382Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 132259382Smckusick VOP_LOCK(vp); 132341400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 132437741Smckusick error = EROFS; 132537741Smckusick goto out; 132637741Smckusick } 132745785Sbostic VATTR_NULL(&vattr); 132845785Sbostic vattr.va_mode = uap->fmode & 07777; 132948026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 133037741Smckusick out: 133137741Smckusick vput(vp); 133247540Skarels return (error); 13337701Ssam } 13347439Sroot 13359167Ssam /* 13369167Ssam * Change mode of a file given a file descriptor. 13379167Ssam */ 133854916Storek struct fchmod_args { 133954916Storek int fd; 134054916Storek int fmode; 134154916Storek }; 134242441Smckusick /* ARGSUSED */ 134342441Smckusick fchmod(p, uap, retval) 134445914Smckusick struct proc *p; 134554916Storek register struct fchmod_args *uap; 134642441Smckusick int *retval; 134742441Smckusick { 134837741Smckusick struct vattr vattr; 134937741Smckusick struct vnode *vp; 135037741Smckusick struct file *fp; 135137741Smckusick int error; 13527701Ssam 135345914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 135447540Skarels return (error); 135537741Smckusick vp = (struct vnode *)fp->f_data; 135659382Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 135737741Smckusick VOP_LOCK(vp); 135841400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 135937741Smckusick error = EROFS; 136037741Smckusick goto out; 13617439Sroot } 136245785Sbostic VATTR_NULL(&vattr); 136345785Sbostic vattr.va_mode = uap->fmode & 07777; 136448026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 136537741Smckusick out: 136637741Smckusick VOP_UNLOCK(vp); 136747540Skarels return (error); 13685992Swnj } 13695992Swnj 13709167Ssam /* 13719167Ssam * Set ownership given a path name. 13729167Ssam */ 137354916Storek struct chown_args { 137454916Storek char *fname; 137554916Storek int uid; 137654916Storek int gid; 137754916Storek }; 137842441Smckusick /* ARGSUSED */ 137942441Smckusick chown(p, uap, retval) 138045914Smckusick struct proc *p; 138154916Storek register struct chown_args *uap; 138242441Smckusick int *retval; 138342441Smckusick { 138437741Smckusick register struct vnode *vp; 138537741Smckusick struct vattr vattr; 138637741Smckusick int error; 138747540Skarels struct nameidata nd; 138837Sbill 138959382Smckusick NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, uap->fname, p); 139052322Smckusick if (error = namei(&nd)) 139147540Skarels return (error); 139252322Smckusick vp = nd.ni_vp; 139359382Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 139459382Smckusick VOP_LOCK(vp); 139541400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 139637741Smckusick error = EROFS; 139737741Smckusick goto out; 139837741Smckusick } 139945785Sbostic VATTR_NULL(&vattr); 140045785Sbostic vattr.va_uid = uap->uid; 140145785Sbostic vattr.va_gid = uap->gid; 140248026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 140337741Smckusick out: 140437741Smckusick vput(vp); 140547540Skarels return (error); 14067701Ssam } 14077439Sroot 14089167Ssam /* 14099167Ssam * Set ownership given a file descriptor. 14109167Ssam */ 141154916Storek struct fchown_args { 141254916Storek int fd; 141354916Storek int uid; 141454916Storek int gid; 141554916Storek }; 141642441Smckusick /* ARGSUSED */ 141742441Smckusick fchown(p, uap, retval) 141845914Smckusick struct proc *p; 141954916Storek register struct fchown_args *uap; 142042441Smckusick int *retval; 142142441Smckusick { 142237741Smckusick struct vattr vattr; 142337741Smckusick struct vnode *vp; 142437741Smckusick struct file *fp; 142537741Smckusick int error; 14267701Ssam 142745914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 142847540Skarels return (error); 142937741Smckusick vp = (struct vnode *)fp->f_data; 143059382Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 143137741Smckusick VOP_LOCK(vp); 143241400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 143337741Smckusick error = EROFS; 143437741Smckusick goto out; 143537741Smckusick } 143645785Sbostic VATTR_NULL(&vattr); 143745785Sbostic vattr.va_uid = uap->uid; 143845785Sbostic vattr.va_gid = uap->gid; 143948026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 144037741Smckusick out: 144137741Smckusick VOP_UNLOCK(vp); 144247540Skarels return (error); 14437701Ssam } 14447701Ssam 144542441Smckusick /* 144642441Smckusick * Set the access and modification times of a file. 144742441Smckusick */ 144854916Storek struct utimes_args { 144954916Storek char *fname; 145054916Storek struct timeval *tptr; 145154916Storek }; 145242441Smckusick /* ARGSUSED */ 145342441Smckusick utimes(p, uap, retval) 145445914Smckusick struct proc *p; 145554916Storek register struct utimes_args *uap; 145642441Smckusick int *retval; 145742441Smckusick { 145837741Smckusick register struct vnode *vp; 145911811Ssam struct timeval tv[2]; 146037741Smckusick struct vattr vattr; 146158840Storek int error; 146247540Skarels struct nameidata nd; 146311811Ssam 146458505Sbostic VATTR_NULL(&vattr); 146558505Sbostic if (uap->tptr == NULL) { 146658505Sbostic microtime(&tv[0]); 146758505Sbostic tv[1] = tv[0]; 146858548Sbostic vattr.va_vaflags |= VA_UTIMES_NULL; 146958505Sbostic } else if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv))) 147058505Sbostic return (error); 147159382Smckusick NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->fname, p); 147252322Smckusick if (error = namei(&nd)) 147347540Skarels return (error); 147452322Smckusick vp = nd.ni_vp; 147559382Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 147659382Smckusick VOP_LOCK(vp); 147741400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 147837741Smckusick error = EROFS; 147937741Smckusick goto out; 148021015Smckusick } 148154100Smckusick vattr.va_atime.ts_sec = tv[0].tv_sec; 148254100Smckusick vattr.va_atime.ts_nsec = tv[0].tv_usec * 1000; 148354100Smckusick vattr.va_mtime.ts_sec = tv[1].tv_sec; 148454100Smckusick vattr.va_mtime.ts_nsec = tv[1].tv_usec * 1000; 148548026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 148637741Smckusick out: 148737741Smckusick vput(vp); 148847540Skarels return (error); 148911811Ssam } 149011811Ssam 149154916Storek struct __truncate_args { 149254863Storek char *fname; 149354863Storek int pad; 149454863Storek off_t length; 149554863Storek }; 149653468Smckusick 149753468Smckusick /* 149853468Smckusick * Truncate a file given its path name. 149953468Smckusick */ 150053468Smckusick /* ARGSUSED */ 150153759Smckusick __truncate(p, uap, retval) 150253468Smckusick struct proc *p; 150354916Storek register struct __truncate_args *uap; 150453468Smckusick int *retval; 150553468Smckusick { 150637741Smckusick register struct vnode *vp; 150737741Smckusick struct vattr vattr; 150837741Smckusick int error; 150947540Skarels struct nameidata nd; 15107701Ssam 151159382Smckusick NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->fname, p); 151252322Smckusick if (error = namei(&nd)) 151347540Skarels return (error); 151452322Smckusick vp = nd.ni_vp; 151559382Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 151659382Smckusick VOP_LOCK(vp); 151737741Smckusick if (vp->v_type == VDIR) { 151837741Smckusick error = EISDIR; 151937741Smckusick goto out; 15207701Ssam } 152138399Smckusick if ((error = vn_writechk(vp)) || 152248026Smckusick (error = VOP_ACCESS(vp, VWRITE, p->p_ucred, p))) 152337741Smckusick goto out; 152445785Sbostic VATTR_NULL(&vattr); 152545785Sbostic vattr.va_size = uap->length; 152648026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 152737741Smckusick out: 152837741Smckusick vput(vp); 152947540Skarels return (error); 15307701Ssam } 15317701Ssam 153254916Storek struct __ftruncate_args { 153354863Storek int fd; 153454863Storek int pad; 153554863Storek off_t length; 153654863Storek }; 153754863Storek 15389167Ssam /* 15399167Ssam * Truncate a file given a file descriptor. 15409167Ssam */ 154142441Smckusick /* ARGSUSED */ 154253759Smckusick __ftruncate(p, uap, retval) 154345914Smckusick struct proc *p; 154454916Storek register struct __ftruncate_args *uap; 154542441Smckusick int *retval; 154642441Smckusick { 154737741Smckusick struct vattr vattr; 154837741Smckusick struct vnode *vp; 15497701Ssam struct file *fp; 155037741Smckusick int error; 15517701Ssam 155245914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 155347540Skarels return (error); 155437741Smckusick if ((fp->f_flag & FWRITE) == 0) 155547540Skarels return (EINVAL); 155637741Smckusick vp = (struct vnode *)fp->f_data; 155759382Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 155837741Smckusick VOP_LOCK(vp); 155937741Smckusick if (vp->v_type == VDIR) { 156037741Smckusick error = EISDIR; 156137741Smckusick goto out; 15627701Ssam } 156338399Smckusick if (error = vn_writechk(vp)) 156437741Smckusick goto out; 156545785Sbostic VATTR_NULL(&vattr); 156645785Sbostic vattr.va_size = uap->length; 156748026Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred, p); 156837741Smckusick out: 156937741Smckusick VOP_UNLOCK(vp); 157047540Skarels return (error); 15717701Ssam } 15727701Ssam 157354863Storek #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 15749167Ssam /* 157554863Storek * Truncate a file given its path name. 157654863Storek */ 157754916Storek struct truncate_args { 157854916Storek char *fname; 157954916Storek long length; 158054916Storek }; 158154863Storek /* ARGSUSED */ 158254863Storek truncate(p, uap, retval) 158354863Storek struct proc *p; 158454916Storek register struct truncate_args *uap; 158554863Storek int *retval; 158654863Storek { 158754916Storek struct __truncate_args nuap; 158854863Storek 158954863Storek nuap.fname = uap->fname; 159054863Storek nuap.length = uap->length; 159154863Storek return (__truncate(p, &nuap, retval)); 159254863Storek } 159354863Storek 159454863Storek /* 159554863Storek * Truncate a file given a file descriptor. 159654863Storek */ 159754916Storek struct ftruncate_args { 159854916Storek int fd; 159954916Storek long length; 160054916Storek }; 160154863Storek /* ARGSUSED */ 160254863Storek ftruncate(p, uap, retval) 160354863Storek struct proc *p; 160454916Storek register struct ftruncate_args *uap; 160554863Storek int *retval; 160654863Storek { 160754969Smckusick struct __ftruncate_args nuap; 160854863Storek 160954863Storek nuap.fd = uap->fd; 161054863Storek nuap.length = uap->length; 161154863Storek return (__ftruncate(p, &nuap, retval)); 161254863Storek } 161354863Storek #endif /* COMPAT_43 || COMPAT_SUNOS */ 161454863Storek 161554863Storek /* 16169167Ssam * Synch an open file. 16179167Ssam */ 161854916Storek struct fsync_args { 161954916Storek int fd; 162054916Storek }; 162142441Smckusick /* ARGSUSED */ 162242441Smckusick fsync(p, uap, retval) 162345914Smckusick struct proc *p; 162454916Storek struct fsync_args *uap; 162542441Smckusick int *retval; 16269167Ssam { 162739592Smckusick register struct vnode *vp; 16289167Ssam struct file *fp; 162937741Smckusick int error; 16309167Ssam 163145914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 163247540Skarels return (error); 163339592Smckusick vp = (struct vnode *)fp->f_data; 163439592Smckusick VOP_LOCK(vp); 163554441Smckusick error = VOP_FSYNC(vp, fp->f_cred, MNT_WAIT, p); 163639592Smckusick VOP_UNLOCK(vp); 163747540Skarels return (error); 16389167Ssam } 16399167Ssam 16409167Ssam /* 16419167Ssam * Rename system call. 16429167Ssam * 16439167Ssam * Source and destination must either both be directories, or both 16449167Ssam * not be directories. If target is a directory, it must be empty. 16459167Ssam */ 164654916Storek struct rename_args { 164754916Storek char *from; 164854916Storek char *to; 164954916Storek }; 165042441Smckusick /* ARGSUSED */ 165142441Smckusick rename(p, uap, retval) 165245914Smckusick struct proc *p; 165354916Storek register struct rename_args *uap; 165442441Smckusick int *retval; 165542441Smckusick { 165637741Smckusick register struct vnode *tvp, *fvp, *tdvp; 165749735Smckusick struct nameidata fromnd, tond; 165837741Smckusick int error; 16597701Ssam 166052322Smckusick NDINIT(&fromnd, DELETE, WANTPARENT | SAVESTART, UIO_USERSPACE, 166152322Smckusick uap->from, p); 166252322Smckusick if (error = namei(&fromnd)) 166347540Skarels return (error); 166449735Smckusick fvp = fromnd.ni_vp; 166552322Smckusick NDINIT(&tond, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART, 166652322Smckusick UIO_USERSPACE, uap->to, p); 166752322Smckusick if (error = namei(&tond)) { 166852230Sheideman VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 166949735Smckusick vrele(fromnd.ni_dvp); 167042465Smckusick vrele(fvp); 167142465Smckusick goto out1; 167242465Smckusick } 167337741Smckusick tdvp = tond.ni_dvp; 167437741Smckusick tvp = tond.ni_vp; 167537741Smckusick if (tvp != NULL) { 167637741Smckusick if (fvp->v_type == VDIR && tvp->v_type != VDIR) { 167739242Sbostic error = ENOTDIR; 167837741Smckusick goto out; 167937741Smckusick } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) { 168039242Sbostic error = EISDIR; 168137741Smckusick goto out; 16829167Ssam } 16839167Ssam } 168439286Smckusick if (fvp == tdvp) 168537741Smckusick error = EINVAL; 168639286Smckusick /* 168749735Smckusick * If source is the same as the destination (that is the 168849735Smckusick * same inode number with the same name in the same directory), 168939286Smckusick * then there is nothing to do. 169039286Smckusick */ 169149735Smckusick if (fvp == tvp && fromnd.ni_dvp == tdvp && 169252322Smckusick fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen && 169352322Smckusick !bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr, 169452322Smckusick fromnd.ni_cnd.cn_namelen)) 169539286Smckusick error = -1; 169637741Smckusick out: 169742465Smckusick if (!error) { 169852192Smckusick LEASE_CHECK(tdvp, p, p->p_ucred, LEASE_WRITE); 169952192Smckusick if (fromnd.ni_dvp != tdvp) 170052192Smckusick LEASE_CHECK(fromnd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 170152192Smckusick if (tvp) 170252192Smckusick LEASE_CHECK(tvp, p, p->p_ucred, LEASE_WRITE); 170352230Sheideman error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd, 170452230Sheideman tond.ni_dvp, tond.ni_vp, &tond.ni_cnd); 170542465Smckusick } else { 170652230Sheideman VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd); 170743344Smckusick if (tdvp == tvp) 170843344Smckusick vrele(tdvp); 170943344Smckusick else 171043344Smckusick vput(tdvp); 171142465Smckusick if (tvp) 171242465Smckusick vput(tvp); 171352230Sheideman VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 171449735Smckusick vrele(fromnd.ni_dvp); 171542465Smckusick vrele(fvp); 17169167Ssam } 171749735Smckusick vrele(tond.ni_startdir); 171852322Smckusick FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI); 171937741Smckusick out1: 172049735Smckusick vrele(fromnd.ni_startdir); 172152322Smckusick FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI); 172239286Smckusick if (error == -1) 172347540Skarels return (0); 172447540Skarels return (error); 17257701Ssam } 17267701Ssam 17277535Sroot /* 172849365Smckusick * Mkdir system call. 172912756Ssam */ 173054916Storek struct mkdir_args { 173154916Storek char *name; 173254916Storek int dmode; 173354916Storek }; 173442441Smckusick /* ARGSUSED */ 173542441Smckusick mkdir(p, uap, retval) 173645914Smckusick struct proc *p; 173754916Storek register struct mkdir_args *uap; 173842441Smckusick int *retval; 173942441Smckusick { 174037741Smckusick register struct vnode *vp; 174137741Smckusick struct vattr vattr; 174237741Smckusick int error; 174347540Skarels struct nameidata nd; 174412756Ssam 174552322Smckusick NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->name, p); 174652322Smckusick if (error = namei(&nd)) 174747540Skarels return (error); 174852322Smckusick vp = nd.ni_vp; 174937741Smckusick if (vp != NULL) { 175052322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 175152322Smckusick if (nd.ni_dvp == vp) 175252322Smckusick vrele(nd.ni_dvp); 175343344Smckusick else 175452322Smckusick vput(nd.ni_dvp); 175542465Smckusick vrele(vp); 175647540Skarels return (EEXIST); 175712756Ssam } 175841362Smckusick VATTR_NULL(&vattr); 175937741Smckusick vattr.va_type = VDIR; 176045914Smckusick vattr.va_mode = (uap->dmode & 0777) &~ p->p_fd->fd_cmask; 176152322Smckusick LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 176252322Smckusick error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr); 176338145Smckusick if (!error) 176452322Smckusick vput(nd.ni_vp); 176547540Skarels return (error); 176612756Ssam } 176712756Ssam 176812756Ssam /* 176912756Ssam * Rmdir system call. 177012756Ssam */ 177154916Storek struct rmdir_args { 177254916Storek char *name; 177354916Storek }; 177442441Smckusick /* ARGSUSED */ 177542441Smckusick rmdir(p, uap, retval) 177645914Smckusick struct proc *p; 177754916Storek struct rmdir_args *uap; 177842441Smckusick int *retval; 177912756Ssam { 178037741Smckusick register struct vnode *vp; 178137741Smckusick int error; 178247540Skarels struct nameidata nd; 178312756Ssam 178452322Smckusick NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE, uap->name, p); 178552322Smckusick if (error = namei(&nd)) 178647540Skarels return (error); 178752322Smckusick vp = nd.ni_vp; 178837741Smckusick if (vp->v_type != VDIR) { 178937741Smckusick error = ENOTDIR; 179012756Ssam goto out; 179112756Ssam } 179212756Ssam /* 179337741Smckusick * No rmdir "." please. 179412756Ssam */ 179552322Smckusick if (nd.ni_dvp == vp) { 179637741Smckusick error = EINVAL; 179712756Ssam goto out; 179812756Ssam } 179912756Ssam /* 180049365Smckusick * The root of a mounted filesystem cannot be deleted. 180112756Ssam */ 180237741Smckusick if (vp->v_flag & VROOT) 180337741Smckusick error = EBUSY; 180412756Ssam out: 180542465Smckusick if (!error) { 180652322Smckusick LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 180752192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 180852322Smckusick error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); 180942465Smckusick } else { 181052322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 181152322Smckusick if (nd.ni_dvp == vp) 181252322Smckusick vrele(nd.ni_dvp); 181343344Smckusick else 181452322Smckusick vput(nd.ni_dvp); 181542465Smckusick vput(vp); 181642465Smckusick } 181747540Skarels return (error); 181812756Ssam } 181912756Ssam 182054620Smckusick #ifdef COMPAT_43 182137741Smckusick /* 182249365Smckusick * Read a block of directory entries in a file system independent format. 182337741Smckusick */ 182454916Storek struct ogetdirentries_args { 182554916Storek int fd; 182654916Storek char *buf; 182754916Storek unsigned count; 182854916Storek long *basep; 182954916Storek }; 183054620Smckusick ogetdirentries(p, uap, retval) 183154620Smckusick struct proc *p; 183254916Storek register struct ogetdirentries_args *uap; 183354620Smckusick int *retval; 183454620Smckusick { 183554620Smckusick register struct vnode *vp; 183654620Smckusick struct file *fp; 183754620Smckusick struct uio auio, kuio; 183854620Smckusick struct iovec aiov, kiov; 183954620Smckusick struct dirent *dp, *edp; 184054620Smckusick caddr_t dirbuf; 184154620Smckusick int error, readcnt; 184254969Smckusick long loff; 184354620Smckusick 184454620Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 184554620Smckusick return (error); 184654620Smckusick if ((fp->f_flag & FREAD) == 0) 184754620Smckusick return (EBADF); 184854620Smckusick vp = (struct vnode *)fp->f_data; 184954620Smckusick if (vp->v_type != VDIR) 185054620Smckusick return (EINVAL); 185154620Smckusick aiov.iov_base = uap->buf; 185254620Smckusick aiov.iov_len = uap->count; 185354620Smckusick auio.uio_iov = &aiov; 185454620Smckusick auio.uio_iovcnt = 1; 185554620Smckusick auio.uio_rw = UIO_READ; 185654620Smckusick auio.uio_segflg = UIO_USERSPACE; 185754620Smckusick auio.uio_procp = p; 185854620Smckusick auio.uio_resid = uap->count; 185954620Smckusick VOP_LOCK(vp); 186054969Smckusick loff = auio.uio_offset = fp->f_offset; 186154620Smckusick # if (BYTE_ORDER != LITTLE_ENDIAN) 186256339Smckusick if (vp->v_mount->mnt_maxsymlinklen <= 0) { 186354620Smckusick error = VOP_READDIR(vp, &auio, fp->f_cred); 186456339Smckusick fp->f_offset = auio.uio_offset; 186556339Smckusick } else 186654620Smckusick # endif 186754620Smckusick { 186854620Smckusick kuio = auio; 186954620Smckusick kuio.uio_iov = &kiov; 187054620Smckusick kuio.uio_segflg = UIO_SYSSPACE; 187154620Smckusick kiov.iov_len = uap->count; 187254620Smckusick MALLOC(dirbuf, caddr_t, uap->count, M_TEMP, M_WAITOK); 187354620Smckusick kiov.iov_base = dirbuf; 187454620Smckusick error = VOP_READDIR(vp, &kuio, fp->f_cred); 187556339Smckusick fp->f_offset = kuio.uio_offset; 187654620Smckusick if (error == 0) { 187754620Smckusick readcnt = uap->count - kuio.uio_resid; 187854620Smckusick edp = (struct dirent *)&dirbuf[readcnt]; 187954620Smckusick for (dp = (struct dirent *)dirbuf; dp < edp; ) { 188054620Smckusick # if (BYTE_ORDER == LITTLE_ENDIAN) 188154969Smckusick /* 188255009Smckusick * The expected low byte of 188355009Smckusick * dp->d_namlen is our dp->d_type. 188455009Smckusick * The high MBZ byte of dp->d_namlen 188555009Smckusick * is our dp->d_namlen. 188654969Smckusick */ 188755009Smckusick dp->d_type = dp->d_namlen; 188855009Smckusick dp->d_namlen = 0; 188955009Smckusick # else 189055009Smckusick /* 189155009Smckusick * The dp->d_type is the high byte 189255009Smckusick * of the expected dp->d_namlen, 189355009Smckusick * so must be zero'ed. 189455009Smckusick */ 189555009Smckusick dp->d_type = 0; 189654620Smckusick # endif 189754620Smckusick if (dp->d_reclen > 0) { 189854620Smckusick dp = (struct dirent *) 189954620Smckusick ((char *)dp + dp->d_reclen); 190054620Smckusick } else { 190154620Smckusick error = EIO; 190254620Smckusick break; 190354620Smckusick } 190454620Smckusick } 190554620Smckusick if (dp >= edp) 190654620Smckusick error = uiomove(dirbuf, readcnt, &auio); 190754620Smckusick } 190854620Smckusick FREE(dirbuf, M_TEMP); 190954620Smckusick } 191054620Smckusick VOP_UNLOCK(vp); 191154620Smckusick if (error) 191254620Smckusick return (error); 191354969Smckusick error = copyout((caddr_t)&loff, (caddr_t)uap->basep, sizeof(long)); 191454620Smckusick *retval = uap->count - auio.uio_resid; 191554620Smckusick return (error); 191654620Smckusick } 191754620Smckusick #endif 191854620Smckusick 191954620Smckusick /* 192054620Smckusick * Read a block of directory entries in a file system independent format. 192154620Smckusick */ 192254916Storek struct getdirentries_args { 192354916Storek int fd; 192454916Storek char *buf; 192554916Storek unsigned count; 192654916Storek long *basep; 192754916Storek }; 192842441Smckusick getdirentries(p, uap, retval) 192945914Smckusick struct proc *p; 193054916Storek register struct getdirentries_args *uap; 193142441Smckusick int *retval; 193242441Smckusick { 193339592Smckusick register struct vnode *vp; 193416540Ssam struct file *fp; 193537741Smckusick struct uio auio; 193637741Smckusick struct iovec aiov; 193754969Smckusick long loff; 193854441Smckusick int error; 193912756Ssam 194045914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 194147540Skarels return (error); 194237741Smckusick if ((fp->f_flag & FREAD) == 0) 194347540Skarels return (EBADF); 194439592Smckusick vp = (struct vnode *)fp->f_data; 194555451Spendry unionread: 194639592Smckusick if (vp->v_type != VDIR) 194747540Skarels return (EINVAL); 194837741Smckusick aiov.iov_base = uap->buf; 194937741Smckusick aiov.iov_len = uap->count; 195037741Smckusick auio.uio_iov = &aiov; 195137741Smckusick auio.uio_iovcnt = 1; 195237741Smckusick auio.uio_rw = UIO_READ; 195337741Smckusick auio.uio_segflg = UIO_USERSPACE; 195448026Smckusick auio.uio_procp = p; 195537741Smckusick auio.uio_resid = uap->count; 195639592Smckusick VOP_LOCK(vp); 195754969Smckusick loff = auio.uio_offset = fp->f_offset; 195854441Smckusick error = VOP_READDIR(vp, &auio, fp->f_cred); 195939592Smckusick fp->f_offset = auio.uio_offset; 196039592Smckusick VOP_UNLOCK(vp); 196139592Smckusick if (error) 196247540Skarels return (error); 196355451Spendry if ((uap->count == auio.uio_resid) && 196455451Spendry (vp->v_flag & VROOT) && 196555451Spendry (vp->v_mount->mnt_flag & MNT_UNION)) { 196655451Spendry struct vnode *tvp = vp; 196755451Spendry vp = vp->v_mount->mnt_vnodecovered; 196855451Spendry VREF(vp); 196955451Spendry fp->f_data = (caddr_t) vp; 197055451Spendry fp->f_offset = 0; 197155451Spendry vrele(tvp); 197255451Spendry goto unionread; 197355451Spendry } 197454969Smckusick error = copyout((caddr_t)&loff, (caddr_t)uap->basep, sizeof(long)); 197542441Smckusick *retval = uap->count - auio.uio_resid; 197647540Skarels return (error); 197712756Ssam } 197812756Ssam 197912756Ssam /* 198049365Smckusick * Set the mode mask for creation of filesystem nodes. 198112756Ssam */ 198254916Storek struct umask_args { 198354916Storek int mask; 198454916Storek }; 198554916Storek mode_t /* XXX */ 198642441Smckusick umask(p, uap, retval) 198745914Smckusick struct proc *p; 198854916Storek struct umask_args *uap; 198942441Smckusick int *retval; 199012756Ssam { 199145914Smckusick register struct filedesc *fdp = p->p_fd; 199212756Ssam 199345914Smckusick *retval = fdp->fd_cmask; 199445914Smckusick fdp->fd_cmask = uap->mask & 07777; 199547540Skarels return (0); 199612756Ssam } 199737741Smckusick 199839566Smarc /* 199939566Smarc * Void all references to file by ripping underlying filesystem 200039566Smarc * away from vnode. 200139566Smarc */ 200254916Storek struct revoke_args { 200354916Storek char *fname; 200454916Storek }; 200542441Smckusick /* ARGSUSED */ 200642441Smckusick revoke(p, uap, retval) 200745914Smckusick struct proc *p; 200854916Storek register struct revoke_args *uap; 200942441Smckusick int *retval; 201042441Smckusick { 201139566Smarc register struct vnode *vp; 201239566Smarc struct vattr vattr; 201339566Smarc int error; 201447540Skarels struct nameidata nd; 201539566Smarc 201652322Smckusick NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->fname, p); 201752322Smckusick if (error = namei(&nd)) 201847540Skarels return (error); 201952322Smckusick vp = nd.ni_vp; 202039566Smarc if (vp->v_type != VCHR && vp->v_type != VBLK) { 202139566Smarc error = EINVAL; 202239566Smarc goto out; 202339566Smarc } 202448026Smckusick if (error = VOP_GETATTR(vp, &vattr, p->p_ucred, p)) 202539566Smarc goto out; 202647540Skarels if (p->p_ucred->cr_uid != vattr.va_uid && 202747540Skarels (error = suser(p->p_ucred, &p->p_acflag))) 202839566Smarc goto out; 202939805Smckusick if (vp->v_usecount > 1 || (vp->v_flag & VALIASED)) 203039632Smckusick vgoneall(vp); 203139566Smarc out: 203239566Smarc vrele(vp); 203347540Skarels return (error); 203439566Smarc } 203539566Smarc 203649365Smckusick /* 203749365Smckusick * Convert a user file descriptor to a kernel file entry. 203849365Smckusick */ 203945914Smckusick getvnode(fdp, fdes, fpp) 204045914Smckusick struct filedesc *fdp; 204137741Smckusick struct file **fpp; 204237741Smckusick int fdes; 204337741Smckusick { 204437741Smckusick struct file *fp; 204537741Smckusick 204647540Skarels if ((unsigned)fdes >= fdp->fd_nfiles || 204747688Skarels (fp = fdp->fd_ofiles[fdes]) == NULL) 204837741Smckusick return (EBADF); 204937741Smckusick if (fp->f_type != DTYPE_VNODE) 205037741Smckusick return (EINVAL); 205137741Smckusick *fpp = fp; 205237741Smckusick return (0); 205337741Smckusick } 2054