123405Smckusick /* 237741Smckusick * Copyright (c) 1989 The Regents of the University of California. 337741Smckusick * All rights reserved. 423405Smckusick * 544459Sbostic * %sccs.include.redist.c% 637741Smckusick * 7*58840Storek * @(#)vfs_syscalls.c 7.105 (Berkeley) 03/28/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> 2537Sbill 2637741Smckusick /* 2737741Smckusick * Virtual File System System Calls 2837741Smckusick */ 2912756Ssam 309167Ssam /* 3149365Smckusick * Mount system call. 329167Ssam */ 3354916Storek struct mount_args { 3454916Storek int type; 3554916Storek char *dir; 3654916Storek int flags; 3754916Storek caddr_t data; 3854916Storek }; 3942441Smckusick /* ARGSUSED */ 4042441Smckusick mount(p, uap, retval) 4145914Smckusick struct proc *p; 4254916Storek register struct mount_args *uap; 4342441Smckusick int *retval; 4442441Smckusick { 4539335Smckusick register struct vnode *vp; 4639335Smckusick register struct mount *mp; 4740111Smckusick int error, flag; 4847540Skarels struct nameidata nd; 496254Sroot 5037741Smckusick /* 5137741Smckusick * Must be super user 5237741Smckusick */ 5347540Skarels if (error = suser(p->p_ucred, &p->p_acflag)) 5447540Skarels return (error); 5537741Smckusick /* 5637741Smckusick * Get vnode to be covered 5737741Smckusick */ 5852322Smckusick NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->dir, p); 5952322Smckusick if (error = namei(&nd)) 6047540Skarels return (error); 6152322Smckusick vp = nd.ni_vp; 6241400Smckusick if (uap->flags & MNT_UPDATE) { 6339335Smckusick if ((vp->v_flag & VROOT) == 0) { 6439335Smckusick vput(vp); 6547540Skarels return (EINVAL); 6639335Smckusick } 6739335Smckusick mp = vp->v_mount; 6857047Smckusick flag = mp->mnt_flag; 6939335Smckusick /* 7057047Smckusick * We only allow the filesystem to be reloaded if it 7157047Smckusick * is currently mounted read-only. 7239335Smckusick */ 7357047Smckusick if ((uap->flags & MNT_RELOAD) && 7457047Smckusick ((mp->mnt_flag & MNT_RDONLY) == 0)) { 7539335Smckusick vput(vp); 7647540Skarels return (EOPNOTSUPP); /* Needs translation */ 7739335Smckusick } 7857047Smckusick mp->mnt_flag |= 7957047Smckusick uap->flags & (MNT_RELOAD | MNT_FORCE | MNT_UPDATE); 8039335Smckusick VOP_UNLOCK(vp); 8139335Smckusick goto update; 8239335Smckusick } 8355451Spendry if (vp->v_usecount != 1 && (uap->flags & MNT_UNION) == 0) { 8437741Smckusick vput(vp); 8547540Skarels return (EBUSY); 8637741Smckusick } 8757793Smckusick if (error = vinvalbuf(vp, V_SAVE, p->p_ucred, p, 0, 0)) 8854441Smckusick return (error); 8937741Smckusick if (vp->v_type != VDIR) { 9037741Smckusick vput(vp); 9147540Skarels return (ENOTDIR); 9237741Smckusick } 9339741Smckusick if ((unsigned long)uap->type > MOUNT_MAXTYPE || 9437741Smckusick vfssw[uap->type] == (struct vfsops *)0) { 9537741Smckusick vput(vp); 9647540Skarels return (ENODEV); 9737741Smckusick } 9837741Smckusick 9937741Smckusick /* 10039335Smckusick * Allocate and initialize the file system. 10137741Smckusick */ 10237741Smckusick mp = (struct mount *)malloc((u_long)sizeof(struct mount), 10337741Smckusick M_MOUNT, M_WAITOK); 10454172Smckusick bzero((char *)mp, (u_long)sizeof(struct mount)); 10541400Smckusick mp->mnt_op = vfssw[uap->type]; 10639335Smckusick if (error = vfs_lock(mp)) { 10739335Smckusick free((caddr_t)mp, M_MOUNT); 10839335Smckusick vput(vp); 10947540Skarels return (error); 11039335Smckusick } 11139335Smckusick if (vp->v_mountedhere != (struct mount *)0) { 11239335Smckusick vfs_unlock(mp); 11339335Smckusick free((caddr_t)mp, M_MOUNT); 11439335Smckusick vput(vp); 11547540Skarels return (EBUSY); 11639335Smckusick } 11739335Smckusick vp->v_mountedhere = mp; 11841400Smckusick mp->mnt_vnodecovered = vp; 11939335Smckusick update: 12039335Smckusick /* 12139335Smckusick * Set the mount level flags. 12239335Smckusick */ 12341400Smckusick if (uap->flags & MNT_RDONLY) 12441400Smckusick mp->mnt_flag |= MNT_RDONLY; 12557047Smckusick else if (mp->mnt_flag & MNT_RDONLY) 12657047Smckusick mp->mnt_flag |= MNT_WANTRDWR; 12757047Smckusick mp->mnt_flag &=~ 12857047Smckusick (MNT_NOSUID | MNT_NOEXEC | MNT_NODEV | MNT_SYNCHRONOUS | MNT_UNION); 12957047Smckusick mp->mnt_flag |= uap->flags & 13057047Smckusick (MNT_NOSUID | MNT_NOEXEC | MNT_NODEV | MNT_SYNCHRONOUS | MNT_UNION); 13139335Smckusick /* 13239335Smckusick * Mount the filesystem. 13339335Smckusick */ 13452322Smckusick error = VFS_MOUNT(mp, uap->dir, uap->data, &nd, p); 13541400Smckusick if (mp->mnt_flag & MNT_UPDATE) { 13639335Smckusick vrele(vp); 13757047Smckusick if (mp->mnt_flag & MNT_WANTRDWR) 13857047Smckusick mp->mnt_flag &= ~MNT_RDONLY; 13957047Smckusick mp->mnt_flag &=~ 14057047Smckusick (MNT_UPDATE | MNT_RELOAD | MNT_FORCE | MNT_WANTRDWR); 14140111Smckusick if (error) 14241400Smckusick mp->mnt_flag = flag; 14347540Skarels return (error); 14439335Smckusick } 14540110Smckusick /* 14640110Smckusick * Put the new filesystem on the mount list after root. 14740110Smckusick */ 14841400Smckusick mp->mnt_next = rootfs->mnt_next; 14941400Smckusick mp->mnt_prev = rootfs; 15041400Smckusick rootfs->mnt_next = mp; 15141400Smckusick mp->mnt_next->mnt_prev = mp; 15237741Smckusick cache_purge(vp); 15337741Smckusick if (!error) { 15439335Smckusick VOP_UNLOCK(vp); 15537741Smckusick vfs_unlock(mp); 15648026Smckusick error = VFS_START(mp, 0, p); 15737741Smckusick } else { 15837741Smckusick vfs_remove(mp); 15937741Smckusick free((caddr_t)mp, M_MOUNT); 16039335Smckusick vput(vp); 16137741Smckusick } 16247540Skarels return (error); 1636254Sroot } 1646254Sroot 1659167Ssam /* 16637741Smckusick * Unmount system call. 16737741Smckusick * 16837741Smckusick * Note: unmount takes a path to the vnode mounted on as argument, 16937741Smckusick * not special file (as before). 1709167Ssam */ 17154916Storek struct unmount_args { 17254916Storek char *pathp; 17354916Storek int flags; 17454916Storek }; 17542441Smckusick /* ARGSUSED */ 17642441Smckusick unmount(p, uap, retval) 17745914Smckusick struct proc *p; 17854916Storek register struct unmount_args *uap; 17942441Smckusick int *retval; 18042441Smckusick { 18137741Smckusick register struct vnode *vp; 18239356Smckusick struct mount *mp; 18337741Smckusick int error; 18447540Skarels struct nameidata nd; 1856254Sroot 18637741Smckusick /* 18737741Smckusick * Must be super user 18837741Smckusick */ 18947540Skarels if (error = suser(p->p_ucred, &p->p_acflag)) 19047540Skarels return (error); 19137741Smckusick 19252322Smckusick NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->pathp, p); 19352322Smckusick if (error = namei(&nd)) 19447540Skarels return (error); 19552322Smckusick vp = nd.ni_vp; 19637741Smckusick /* 19737741Smckusick * Must be the root of the filesystem 19837741Smckusick */ 19937741Smckusick if ((vp->v_flag & VROOT) == 0) { 20037741Smckusick vput(vp); 20147540Skarels return (EINVAL); 20237741Smckusick } 20337741Smckusick mp = vp->v_mount; 20437741Smckusick vput(vp); 20548026Smckusick return (dounmount(mp, uap->flags, p)); 20639356Smckusick } 20739356Smckusick 20839356Smckusick /* 20939356Smckusick * Do an unmount. 21039356Smckusick */ 21148026Smckusick dounmount(mp, flags, p) 21239356Smckusick register struct mount *mp; 21339356Smckusick int flags; 21448026Smckusick struct proc *p; 21539356Smckusick { 21639356Smckusick struct vnode *coveredvp; 21739356Smckusick int error; 21839356Smckusick 21941400Smckusick coveredvp = mp->mnt_vnodecovered; 22041298Smckusick if (vfs_busy(mp)) 22141298Smckusick return (EBUSY); 22241400Smckusick mp->mnt_flag |= MNT_UNMOUNT; 22337741Smckusick if (error = vfs_lock(mp)) 22439356Smckusick return (error); 22537741Smckusick 22645738Smckusick vnode_pager_umount(mp); /* release cached vnodes */ 22737741Smckusick cache_purgevfs(mp); /* remove cache entries for this file sys */ 22854441Smckusick if ((error = VFS_SYNC(mp, MNT_WAIT, p->p_ucred, p)) == 0 || 22954441Smckusick (flags & MNT_FORCE)) 23048026Smckusick error = VFS_UNMOUNT(mp, flags, p); 23141400Smckusick mp->mnt_flag &= ~MNT_UNMOUNT; 23241298Smckusick vfs_unbusy(mp); 23337741Smckusick if (error) { 23437741Smckusick vfs_unlock(mp); 23537741Smckusick } else { 23637741Smckusick vrele(coveredvp); 23737741Smckusick vfs_remove(mp); 23852287Smckusick if (mp->mnt_mounth != NULL) 23952287Smckusick panic("unmount: dangling vnode"); 24037741Smckusick free((caddr_t)mp, M_MOUNT); 24137741Smckusick } 24239356Smckusick return (error); 2436254Sroot } 2446254Sroot 2459167Ssam /* 24637741Smckusick * Sync system call. 24737741Smckusick * Sync each mounted filesystem. 2489167Ssam */ 24956352Smckusick #ifdef DIAGNOSTIC 25056352Smckusick int syncprt = 0; 25156352Smckusick #endif 25256352Smckusick 25354916Storek struct sync_args { 25454916Storek int dummy; 25554916Storek }; 25639491Smckusick /* ARGSUSED */ 25742441Smckusick sync(p, uap, retval) 25845914Smckusick struct proc *p; 25954916Storek struct sync_args *uap; 26042441Smckusick int *retval; 2616254Sroot { 26237741Smckusick register struct mount *mp; 26341298Smckusick struct mount *omp; 26437741Smckusick 26537741Smckusick mp = rootfs; 26637741Smckusick do { 26740343Smckusick /* 26840343Smckusick * The lock check below is to avoid races with mount 26940343Smckusick * and unmount. 27040343Smckusick */ 27141400Smckusick if ((mp->mnt_flag & (MNT_MLOCK|MNT_RDONLY|MNT_MPBUSY)) == 0 && 27241298Smckusick !vfs_busy(mp)) { 27354441Smckusick VFS_SYNC(mp, MNT_NOWAIT, p->p_ucred, p); 27441298Smckusick omp = mp; 27541400Smckusick mp = mp->mnt_next; 27641298Smckusick vfs_unbusy(omp); 27741298Smckusick } else 27841400Smckusick mp = mp->mnt_next; 27937741Smckusick } while (mp != rootfs); 28056352Smckusick #ifdef DIAGNOSTIC 28156352Smckusick if (syncprt) 28256352Smckusick vfs_bufstats(); 28356352Smckusick #endif /* DIAGNOSTIC */ 28447688Skarels return (0); 28537741Smckusick } 28637741Smckusick 28737741Smckusick /* 28849365Smckusick * Operate on filesystem quotas. 28941298Smckusick */ 29054916Storek struct quotactl_args { 29154916Storek char *path; 29254916Storek int cmd; 29354916Storek int uid; 29454916Storek caddr_t arg; 29554916Storek }; 29642441Smckusick /* ARGSUSED */ 29742441Smckusick quotactl(p, uap, retval) 29845914Smckusick struct proc *p; 29954916Storek register struct quotactl_args *uap; 30042441Smckusick int *retval; 30142441Smckusick { 30241298Smckusick register struct mount *mp; 30341298Smckusick int error; 30447540Skarels struct nameidata nd; 30541298Smckusick 30652322Smckusick NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); 30752322Smckusick if (error = namei(&nd)) 30847540Skarels return (error); 30952322Smckusick mp = nd.ni_vp->v_mount; 31052322Smckusick vrele(nd.ni_vp); 31148026Smckusick return (VFS_QUOTACTL(mp, uap->cmd, uap->uid, uap->arg, p)); 31241298Smckusick } 31341298Smckusick 31441298Smckusick /* 31549365Smckusick * Get filesystem statistics. 31637741Smckusick */ 31754916Storek struct statfs_args { 31854916Storek char *path; 31954916Storek struct statfs *buf; 32054916Storek }; 32142441Smckusick /* ARGSUSED */ 32242441Smckusick statfs(p, uap, retval) 32345914Smckusick struct proc *p; 32454916Storek register struct statfs_args *uap; 32542441Smckusick int *retval; 32642441Smckusick { 32739464Smckusick register struct mount *mp; 32840343Smckusick register struct statfs *sp; 32937741Smckusick int error; 33047540Skarels struct nameidata nd; 33137741Smckusick 33252322Smckusick NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); 33352322Smckusick if (error = namei(&nd)) 33447540Skarels return (error); 33552322Smckusick mp = nd.ni_vp->v_mount; 33641400Smckusick sp = &mp->mnt_stat; 33752322Smckusick vrele(nd.ni_vp); 33848026Smckusick if (error = VFS_STATFS(mp, sp, p)) 33947540Skarels return (error); 34041400Smckusick sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 34147540Skarels return (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp))); 34237741Smckusick } 34337741Smckusick 34442441Smckusick /* 34549365Smckusick * Get filesystem statistics. 34642441Smckusick */ 34754916Storek struct fstatfs_args { 34854916Storek int fd; 34954916Storek struct statfs *buf; 35054916Storek }; 35142441Smckusick /* ARGSUSED */ 35242441Smckusick fstatfs(p, uap, retval) 35345914Smckusick struct proc *p; 35454916Storek register struct fstatfs_args *uap; 35542441Smckusick int *retval; 35642441Smckusick { 35737741Smckusick struct file *fp; 35839464Smckusick struct mount *mp; 35940343Smckusick register struct statfs *sp; 36037741Smckusick int error; 36137741Smckusick 36245914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 36347540Skarels return (error); 36439464Smckusick mp = ((struct vnode *)fp->f_data)->v_mount; 36541400Smckusick sp = &mp->mnt_stat; 36648026Smckusick if (error = VFS_STATFS(mp, sp, p)) 36747540Skarels return (error); 36841400Smckusick sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 36947540Skarels return (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp))); 37037741Smckusick } 37137741Smckusick 37237741Smckusick /* 37349365Smckusick * Get statistics on all filesystems. 37438270Smckusick */ 37554916Storek struct getfsstat_args { 37654916Storek struct statfs *buf; 37754916Storek long bufsize; 37854916Storek int flags; 37954916Storek }; 38042441Smckusick getfsstat(p, uap, retval) 38145914Smckusick struct proc *p; 38254916Storek register struct getfsstat_args *uap; 38342441Smckusick int *retval; 38442441Smckusick { 38538270Smckusick register struct mount *mp; 38640343Smckusick register struct statfs *sp; 38739606Smckusick caddr_t sfsp; 38838270Smckusick long count, maxcount, error; 38938270Smckusick 39038270Smckusick maxcount = uap->bufsize / sizeof(struct statfs); 39139606Smckusick sfsp = (caddr_t)uap->buf; 39238270Smckusick mp = rootfs; 39338270Smckusick count = 0; 39438270Smckusick do { 39541400Smckusick if (sfsp && count < maxcount && 39641400Smckusick ((mp->mnt_flag & MNT_MLOCK) == 0)) { 39741400Smckusick sp = &mp->mnt_stat; 39840343Smckusick /* 39940343Smckusick * If MNT_NOWAIT is specified, do not refresh the 40040343Smckusick * fsstat cache. MNT_WAIT overrides MNT_NOWAIT. 40140343Smckusick */ 40240343Smckusick if (((uap->flags & MNT_NOWAIT) == 0 || 40340343Smckusick (uap->flags & MNT_WAIT)) && 40448026Smckusick (error = VFS_STATFS(mp, sp, p))) { 40541400Smckusick mp = mp->mnt_prev; 40639607Smckusick continue; 40739607Smckusick } 40841400Smckusick sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 40940343Smckusick if (error = copyout((caddr_t)sp, sfsp, sizeof(*sp))) 41047540Skarels return (error); 41140343Smckusick sfsp += sizeof(*sp); 41238270Smckusick } 41339606Smckusick count++; 41441400Smckusick mp = mp->mnt_prev; 41538270Smckusick } while (mp != rootfs); 41638270Smckusick if (sfsp && count > maxcount) 41742441Smckusick *retval = maxcount; 41838270Smckusick else 41942441Smckusick *retval = count; 42047540Skarels return (0); 42138270Smckusick } 42238270Smckusick 42338270Smckusick /* 42438259Smckusick * Change current working directory to a given file descriptor. 42538259Smckusick */ 42654916Storek struct fchdir_args { 42754916Storek int fd; 42854916Storek }; 42942441Smckusick /* ARGSUSED */ 43042441Smckusick fchdir(p, uap, retval) 43145914Smckusick struct proc *p; 43254916Storek struct fchdir_args *uap; 43342441Smckusick int *retval; 43438259Smckusick { 43545914Smckusick register struct filedesc *fdp = p->p_fd; 43638259Smckusick register struct vnode *vp; 43738259Smckusick struct file *fp; 43838259Smckusick int error; 43938259Smckusick 44045914Smckusick if (error = getvnode(fdp, uap->fd, &fp)) 44147540Skarels return (error); 44238259Smckusick vp = (struct vnode *)fp->f_data; 44338259Smckusick VOP_LOCK(vp); 44438259Smckusick if (vp->v_type != VDIR) 44538259Smckusick error = ENOTDIR; 44638259Smckusick else 44748026Smckusick error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p); 44838259Smckusick VOP_UNLOCK(vp); 44939860Smckusick if (error) 45047540Skarels return (error); 45139860Smckusick VREF(vp); 45245914Smckusick vrele(fdp->fd_cdir); 45345914Smckusick fdp->fd_cdir = vp; 45447540Skarels return (0); 45538259Smckusick } 45638259Smckusick 45738259Smckusick /* 45837741Smckusick * Change current working directory (``.''). 45937741Smckusick */ 46054916Storek struct chdir_args { 46154916Storek char *fname; 46254916Storek }; 46342441Smckusick /* ARGSUSED */ 46442441Smckusick chdir(p, uap, retval) 46545914Smckusick struct proc *p; 46654916Storek struct chdir_args *uap; 46742441Smckusick int *retval; 46837741Smckusick { 46945914Smckusick register struct filedesc *fdp = p->p_fd; 47037741Smckusick int error; 47147540Skarels struct nameidata nd; 4726254Sroot 47352322Smckusick NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 47452781Sralph if (error = chdirec(&nd, p)) 47547540Skarels return (error); 47645914Smckusick vrele(fdp->fd_cdir); 47752322Smckusick fdp->fd_cdir = nd.ni_vp; 47847540Skarels return (0); 47937741Smckusick } 4806254Sroot 48137741Smckusick /* 48237741Smckusick * Change notion of root (``/'') directory. 48337741Smckusick */ 48454916Storek struct chroot_args { 48554916Storek char *fname; 48654916Storek }; 48742441Smckusick /* ARGSUSED */ 48842441Smckusick chroot(p, uap, retval) 48945914Smckusick struct proc *p; 49054916Storek struct chroot_args *uap; 49142441Smckusick int *retval; 49237741Smckusick { 49345914Smckusick register struct filedesc *fdp = p->p_fd; 49437741Smckusick int error; 49547540Skarels struct nameidata nd; 49637741Smckusick 49747540Skarels if (error = suser(p->p_ucred, &p->p_acflag)) 49847540Skarels return (error); 49952322Smckusick NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 50052781Sralph if (error = chdirec(&nd, p)) 50147540Skarels return (error); 50245914Smckusick if (fdp->fd_rdir != NULL) 50345914Smckusick vrele(fdp->fd_rdir); 50452322Smckusick fdp->fd_rdir = nd.ni_vp; 50547540Skarels return (0); 5066254Sroot } 5076254Sroot 50837Sbill /* 50937741Smckusick * Common routine for chroot and chdir. 51037741Smckusick */ 51147540Skarels chdirec(ndp, p) 51252322Smckusick register struct nameidata *ndp; 51347540Skarels struct proc *p; 51437741Smckusick { 51537741Smckusick struct vnode *vp; 51637741Smckusick int error; 51737741Smckusick 51852322Smckusick if (error = namei(ndp)) 51937741Smckusick return (error); 52037741Smckusick vp = ndp->ni_vp; 52137741Smckusick if (vp->v_type != VDIR) 52237741Smckusick error = ENOTDIR; 52337741Smckusick else 52448026Smckusick error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p); 52537741Smckusick VOP_UNLOCK(vp); 52637741Smckusick if (error) 52737741Smckusick vrele(vp); 52837741Smckusick return (error); 52937741Smckusick } 53037741Smckusick 53137741Smckusick /* 5326254Sroot * Open system call. 53342441Smckusick * Check permissions, allocate an open file structure, 53442441Smckusick * and call the device open routine if any. 5356254Sroot */ 53654916Storek struct open_args { 53754916Storek char *fname; 53854916Storek int mode; 53954916Storek int crtmode; 54054916Storek }; 54142441Smckusick open(p, uap, retval) 54245914Smckusick struct proc *p; 54354916Storek register struct open_args *uap; 54442441Smckusick int *retval; 5456254Sroot { 54645914Smckusick register struct filedesc *fdp = p->p_fd; 54742441Smckusick register struct file *fp; 54850111Smckusick register struct vnode *vp; 54937741Smckusick int fmode, cmode; 55037741Smckusick struct file *nfp; 55149945Smckusick int type, indx, error; 55249945Smckusick struct flock lf; 55347540Skarels struct nameidata nd; 55437741Smckusick extern struct fileops vnops; 5556254Sroot 55645914Smckusick if (error = falloc(p, &nfp, &indx)) 55747540Skarels return (error); 55837741Smckusick fp = nfp; 55946553Skarels fmode = FFLAGS(uap->mode); 56045914Smckusick cmode = ((uap->crtmode &~ fdp->fd_cmask) & 07777) &~ S_ISVTX; 56152322Smckusick NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->fname, p); 56245202Smckusick p->p_dupfd = -indx - 1; /* XXX check for fdopen */ 56352322Smckusick if (error = vn_open(&nd, fmode, cmode)) { 56449980Smckusick ffree(fp); 56554723Smckusick if ((error == ENODEV || error == ENXIO) && 56654723Smckusick p->p_dupfd >= 0 && /* XXX from fdopen */ 56753828Spendry (error = dupfdopen(fdp, indx, p->p_dupfd, 56853828Spendry fmode, error)) == 0) { 56942441Smckusick *retval = indx; 57047540Skarels return (0); 57142441Smckusick } 57240884Smckusick if (error == ERESTART) 57340884Smckusick error = EINTR; 57447688Skarels fdp->fd_ofiles[indx] = NULL; 57547540Skarels return (error); 57612756Ssam } 57753828Spendry p->p_dupfd = 0; 57852322Smckusick vp = nd.ni_vp; 57949949Smckusick fp->f_flag = fmode & FMASK; 58054348Smckusick fp->f_type = DTYPE_VNODE; 58154348Smckusick fp->f_ops = &vnops; 58254348Smckusick fp->f_data = (caddr_t)vp; 58349945Smckusick if (fmode & (O_EXLOCK | O_SHLOCK)) { 58449945Smckusick lf.l_whence = SEEK_SET; 58549945Smckusick lf.l_start = 0; 58649945Smckusick lf.l_len = 0; 58749945Smckusick if (fmode & O_EXLOCK) 58849945Smckusick lf.l_type = F_WRLCK; 58949945Smckusick else 59049945Smckusick lf.l_type = F_RDLCK; 59149945Smckusick type = F_FLOCK; 59249945Smckusick if ((fmode & FNONBLOCK) == 0) 59349945Smckusick type |= F_WAIT; 59450111Smckusick if (error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, type)) { 59550111Smckusick VOP_UNLOCK(vp); 59650111Smckusick (void) vn_close(vp, fp->f_flag, fp->f_cred, p); 59749980Smckusick ffree(fp); 59849945Smckusick fdp->fd_ofiles[indx] = NULL; 59949945Smckusick return (error); 60049945Smckusick } 60149949Smckusick fp->f_flag |= FHASLOCK; 60249945Smckusick } 60350111Smckusick VOP_UNLOCK(vp); 60442441Smckusick *retval = indx; 60547540Skarels return (0); 6066254Sroot } 6076254Sroot 60842955Smckusick #ifdef COMPAT_43 6096254Sroot /* 61042441Smckusick * Creat system call. 6116254Sroot */ 61254916Storek struct ocreat_args { 61354916Storek char *fname; 61454916Storek int fmode; 61554916Storek }; 61642955Smckusick ocreat(p, uap, retval) 61742441Smckusick struct proc *p; 61854916Storek register struct ocreat_args *uap; 61942441Smckusick int *retval; 6206254Sroot { 62154916Storek struct open_args openuap; 62242441Smckusick 62342441Smckusick openuap.fname = uap->fname; 62442441Smckusick openuap.crtmode = uap->fmode; 62542441Smckusick openuap.mode = O_WRONLY | O_CREAT | O_TRUNC; 62647540Skarels return (open(p, &openuap, retval)); 62742441Smckusick } 62842955Smckusick #endif /* COMPAT_43 */ 62942441Smckusick 63042441Smckusick /* 63149365Smckusick * Mknod system call. 63242441Smckusick */ 63354916Storek struct mknod_args { 63454916Storek char *fname; 63554916Storek int fmode; 63654916Storek int dev; 63754916Storek }; 63842441Smckusick /* ARGSUSED */ 63942441Smckusick mknod(p, uap, retval) 64045914Smckusick struct proc *p; 64154916Storek register struct mknod_args *uap; 64242441Smckusick int *retval; 64342441Smckusick { 64437741Smckusick register struct vnode *vp; 64537741Smckusick struct vattr vattr; 64637741Smckusick int error; 64747540Skarels struct nameidata nd; 6486254Sroot 64947540Skarels if (error = suser(p->p_ucred, &p->p_acflag)) 65047540Skarels return (error); 65152322Smckusick NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->fname, p); 65252322Smckusick if (error = namei(&nd)) 65347540Skarels return (error); 65452322Smckusick vp = nd.ni_vp; 65537741Smckusick if (vp != NULL) { 65637741Smckusick error = EEXIST; 65712756Ssam goto out; 6586254Sroot } 65941362Smckusick VATTR_NULL(&vattr); 66040635Smckusick switch (uap->fmode & S_IFMT) { 66112756Ssam 66240635Smckusick case S_IFMT: /* used by badsect to flag bad sectors */ 66337741Smckusick vattr.va_type = VBAD; 66437741Smckusick break; 66540635Smckusick case S_IFCHR: 66637741Smckusick vattr.va_type = VCHR; 66737741Smckusick break; 66840635Smckusick case S_IFBLK: 66937741Smckusick vattr.va_type = VBLK; 67037741Smckusick break; 67137741Smckusick default: 67237741Smckusick error = EINVAL; 67337741Smckusick goto out; 6746254Sroot } 67545914Smckusick vattr.va_mode = (uap->fmode & 07777) &~ p->p_fd->fd_cmask; 67637741Smckusick vattr.va_rdev = uap->dev; 6776254Sroot out: 67842465Smckusick if (!error) { 67952322Smckusick LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 68052322Smckusick error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr); 68142465Smckusick } else { 68252322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 68352322Smckusick if (nd.ni_dvp == vp) 68452322Smckusick vrele(nd.ni_dvp); 68543344Smckusick else 68652322Smckusick vput(nd.ni_dvp); 68742465Smckusick if (vp) 68842465Smckusick vrele(vp); 68942465Smckusick } 69047540Skarels return (error); 6916254Sroot } 6926254Sroot 6936254Sroot /* 69449365Smckusick * Mkfifo system call. 69540285Smckusick */ 69654916Storek struct mkfifo_args { 69754916Storek char *fname; 69854916Storek int fmode; 69954916Storek }; 70042441Smckusick /* ARGSUSED */ 70142441Smckusick mkfifo(p, uap, retval) 70245914Smckusick struct proc *p; 70354916Storek register struct mkfifo_args *uap; 70442441Smckusick int *retval; 70542441Smckusick { 70640285Smckusick struct vattr vattr; 70740285Smckusick int error; 70847540Skarels struct nameidata nd; 70940285Smckusick 71040285Smckusick #ifndef FIFO 71147540Skarels return (EOPNOTSUPP); 71240285Smckusick #else 71352322Smckusick NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->fname, p); 71452322Smckusick if (error = namei(&nd)) 71547540Skarels return (error); 71652322Smckusick if (nd.ni_vp != NULL) { 71752322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 71852322Smckusick if (nd.ni_dvp == nd.ni_vp) 71952322Smckusick vrele(nd.ni_dvp); 72043344Smckusick else 72152322Smckusick vput(nd.ni_dvp); 72252322Smckusick vrele(nd.ni_vp); 72347540Skarels return (EEXIST); 72440285Smckusick } 72545785Sbostic VATTR_NULL(&vattr); 72645785Sbostic vattr.va_type = VFIFO; 72745914Smckusick vattr.va_mode = (uap->fmode & 07777) &~ p->p_fd->fd_cmask; 72852322Smckusick LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 72952322Smckusick return (VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr)); 73040285Smckusick #endif /* FIFO */ 73140285Smckusick } 73240285Smckusick 73340285Smckusick /* 73449365Smckusick * Link system call. 7356254Sroot */ 73654916Storek struct link_args { 73754916Storek char *target; 73854916Storek char *linkname; 73954916Storek }; 74042441Smckusick /* ARGSUSED */ 74142441Smckusick link(p, uap, retval) 74245914Smckusick struct proc *p; 74354916Storek register struct link_args *uap; 74442441Smckusick int *retval; 74542441Smckusick { 74637741Smckusick register struct vnode *vp, *xp; 74737741Smckusick int error; 74847540Skarels struct nameidata nd; 7496254Sroot 75052322Smckusick NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->target, p); 75152322Smckusick if (error = namei(&nd)) 75247540Skarels return (error); 75352322Smckusick vp = nd.ni_vp; 75437741Smckusick if (vp->v_type == VDIR && 75547540Skarels (error = suser(p->p_ucred, &p->p_acflag))) 75637741Smckusick goto out1; 75752322Smckusick nd.ni_cnd.cn_nameiop = CREATE; 75852322Smckusick nd.ni_cnd.cn_flags = LOCKPARENT; 75952322Smckusick nd.ni_dirp = (caddr_t)uap->linkname; 76052322Smckusick if (error = namei(&nd)) 76137741Smckusick goto out1; 76252322Smckusick xp = nd.ni_vp; 7636254Sroot if (xp != NULL) { 76437741Smckusick error = EEXIST; 7656254Sroot goto out; 7666254Sroot } 76752322Smckusick xp = nd.ni_dvp; 7686254Sroot out: 76942465Smckusick if (!error) { 77052192Smckusick LEASE_CHECK(xp, p, p->p_ucred, LEASE_WRITE); 77152192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 77252821Smckusick error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd); 77342465Smckusick } else { 77452322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 77552322Smckusick if (nd.ni_dvp == nd.ni_vp) 77652322Smckusick vrele(nd.ni_dvp); 77743344Smckusick else 77852322Smckusick vput(nd.ni_dvp); 77952322Smckusick if (nd.ni_vp) 78052322Smckusick vrele(nd.ni_vp); 78142465Smckusick } 78237741Smckusick out1: 78337741Smckusick vrele(vp); 78447540Skarels return (error); 7856254Sroot } 7866254Sroot 7876254Sroot /* 78849365Smckusick * Make a symbolic link. 7896254Sroot */ 79054916Storek struct symlink_args { 79154916Storek char *target; 79254916Storek char *linkname; 79354916Storek }; 79442441Smckusick /* ARGSUSED */ 79542441Smckusick symlink(p, uap, retval) 79645914Smckusick struct proc *p; 79754916Storek register struct symlink_args *uap; 79842441Smckusick int *retval; 79942441Smckusick { 80037741Smckusick struct vattr vattr; 80137741Smckusick char *target; 80237741Smckusick int error; 80347540Skarels struct nameidata nd; 8046254Sroot 80537741Smckusick MALLOC(target, char *, MAXPATHLEN, M_NAMEI, M_WAITOK); 80637741Smckusick if (error = copyinstr(uap->target, target, MAXPATHLEN, (u_int *)0)) 80742465Smckusick goto out; 80852322Smckusick NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->linkname, p); 80952322Smckusick if (error = namei(&nd)) 81042465Smckusick goto out; 81152322Smckusick if (nd.ni_vp) { 81252322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 81352322Smckusick if (nd.ni_dvp == nd.ni_vp) 81452322Smckusick vrele(nd.ni_dvp); 81543344Smckusick else 81652322Smckusick vput(nd.ni_dvp); 81752322Smckusick vrele(nd.ni_vp); 81837741Smckusick error = EEXIST; 81937741Smckusick goto out; 8206254Sroot } 82141362Smckusick VATTR_NULL(&vattr); 82245914Smckusick vattr.va_mode = 0777 &~ p->p_fd->fd_cmask; 82352322Smckusick LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 82452322Smckusick error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr, target); 82537741Smckusick out: 82637741Smckusick FREE(target, M_NAMEI); 82747540Skarels return (error); 8286254Sroot } 8296254Sroot 8306254Sroot /* 83149365Smckusick * Delete a name from the filesystem. 8326254Sroot */ 83354916Storek struct unlink_args { 83454916Storek char *name; 83554916Storek }; 83642441Smckusick /* ARGSUSED */ 83742441Smckusick unlink(p, uap, retval) 83845914Smckusick struct proc *p; 83954916Storek struct unlink_args *uap; 84042441Smckusick int *retval; 8416254Sroot { 84237741Smckusick register struct vnode *vp; 84337741Smckusick int error; 84447540Skarels struct nameidata nd; 8456254Sroot 84652322Smckusick NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE, uap->name, p); 84752322Smckusick if (error = namei(&nd)) 84847540Skarels return (error); 84952322Smckusick vp = nd.ni_vp; 85037741Smckusick if (vp->v_type == VDIR && 85147540Skarels (error = suser(p->p_ucred, &p->p_acflag))) 8526254Sroot goto out; 8536254Sroot /* 85449365Smckusick * The root of a mounted filesystem cannot be deleted. 8556254Sroot */ 85637741Smckusick if (vp->v_flag & VROOT) { 85737741Smckusick error = EBUSY; 8586254Sroot goto out; 8596254Sroot } 86045738Smckusick (void) vnode_pager_uncache(vp); 8616254Sroot out: 86242465Smckusick if (!error) { 86352322Smckusick LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 86452192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 86552322Smckusick error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); 86642465Smckusick } else { 86752322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 86852322Smckusick if (nd.ni_dvp == vp) 86952322Smckusick vrele(nd.ni_dvp); 87043344Smckusick else 87152322Smckusick vput(nd.ni_dvp); 87242465Smckusick vput(vp); 87342465Smckusick } 87447540Skarels return (error); 8756254Sroot } 8766254Sroot 87754916Storek struct __lseek_args { 87854863Storek int fdes; 87954863Storek int pad; 88054863Storek off_t off; 88154863Storek int sbase; 88254863Storek }; 88354863Storek 88454348Smckusick #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 8856254Sroot /* 88649365Smckusick * Seek system call. 8876254Sroot */ 88854916Storek struct lseek_args { 88954916Storek int fdes; 89054916Storek long off; 89154916Storek int sbase; 89254916Storek }; 89342441Smckusick lseek(p, uap, retval) 89445914Smckusick struct proc *p; 89554916Storek register struct lseek_args *uap; 89654916Storek int *retval; 89753468Smckusick { 89854916Storek struct __lseek_args nuap; 89954863Storek off_t qret; 90053468Smckusick int error; 90153468Smckusick 90253468Smckusick nuap.fdes = uap->fdes; 90353468Smckusick nuap.off = uap->off; 90453468Smckusick nuap.sbase = uap->sbase; 90553759Smckusick error = __lseek(p, &nuap, &qret); 90654916Storek *(long *)retval = qret; 90753468Smckusick return (error); 90853468Smckusick } 90954348Smckusick #endif /* COMPAT_43 || COMPAT_SUNOS */ 91053468Smckusick 91153468Smckusick /* 91253468Smckusick * Seek system call. 91353468Smckusick */ 91453759Smckusick __lseek(p, uap, retval) 91553468Smckusick struct proc *p; 91654916Storek register struct __lseek_args *uap; 91754916Storek int *retval; 91842441Smckusick { 91947540Skarels struct ucred *cred = p->p_ucred; 92045914Smckusick register struct filedesc *fdp = p->p_fd; 92142441Smckusick register struct file *fp; 92237741Smckusick struct vattr vattr; 92337741Smckusick int error; 9246254Sroot 92547540Skarels if ((unsigned)uap->fdes >= fdp->fd_nfiles || 92647688Skarels (fp = fdp->fd_ofiles[uap->fdes]) == NULL) 92747540Skarels return (EBADF); 92837741Smckusick if (fp->f_type != DTYPE_VNODE) 92947540Skarels return (ESPIPE); 93013878Ssam switch (uap->sbase) { 93113878Ssam 93213878Ssam case L_INCR: 93313878Ssam fp->f_offset += uap->off; 93413878Ssam break; 93513878Ssam 93613878Ssam case L_XTND: 93737741Smckusick if (error = VOP_GETATTR((struct vnode *)fp->f_data, 93848026Smckusick &vattr, cred, p)) 93947540Skarels return (error); 94037741Smckusick fp->f_offset = uap->off + vattr.va_size; 94113878Ssam break; 94213878Ssam 94313878Ssam case L_SET: 94413878Ssam fp->f_offset = uap->off; 94513878Ssam break; 94613878Ssam 94713878Ssam default: 94847540Skarels return (EINVAL); 94913878Ssam } 95054916Storek *(off_t *)retval = fp->f_offset; 95147540Skarels return (0); 9526254Sroot } 9536254Sroot 9546254Sroot /* 95549365Smckusick * Check access permissions. 9566254Sroot */ 95754916Storek struct saccess_args { 95854916Storek char *fname; 95954916Storek int fmode; 96054916Storek }; 96142441Smckusick /* ARGSUSED */ 96242441Smckusick saccess(p, uap, retval) 96345914Smckusick struct proc *p; 96454916Storek register struct saccess_args *uap; 96542441Smckusick int *retval; 96642441Smckusick { 96747540Skarels register struct ucred *cred = p->p_ucred; 96837741Smckusick register struct vnode *vp; 96937741Smckusick int error, mode, svuid, svgid; 97047540Skarels struct nameidata nd; 9716254Sroot 97242441Smckusick svuid = cred->cr_uid; 97342441Smckusick svgid = cred->cr_groups[0]; 97447540Skarels cred->cr_uid = p->p_cred->p_ruid; 97547540Skarels cred->cr_groups[0] = p->p_cred->p_rgid; 97652322Smckusick NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 97752322Smckusick if (error = namei(&nd)) 97837741Smckusick goto out1; 97952322Smckusick vp = nd.ni_vp; 98037741Smckusick /* 98137741Smckusick * fmode == 0 means only check for exist 98237741Smckusick */ 98337741Smckusick if (uap->fmode) { 98437741Smckusick mode = 0; 98537741Smckusick if (uap->fmode & R_OK) 98637741Smckusick mode |= VREAD; 98737741Smckusick if (uap->fmode & W_OK) 98837741Smckusick mode |= VWRITE; 98937741Smckusick if (uap->fmode & X_OK) 99037741Smckusick mode |= VEXEC; 99139543Smckusick if ((mode & VWRITE) == 0 || (error = vn_writechk(vp)) == 0) 99248026Smckusick error = VOP_ACCESS(vp, mode, cred, p); 9936254Sroot } 99437741Smckusick vput(vp); 99537741Smckusick out1: 99642441Smckusick cred->cr_uid = svuid; 99742441Smckusick cred->cr_groups[0] = svgid; 99847540Skarels return (error); 9996254Sroot } 10006254Sroot 100154348Smckusick #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 10026254Sroot /* 100349365Smckusick * Stat system call. 100449365Smckusick * This version follows links. 100537Sbill */ 100654916Storek struct ostat_args { 100754916Storek char *fname; 100854916Storek struct ostat *ub; 100954916Storek }; 101042441Smckusick /* ARGSUSED */ 101153759Smckusick ostat(p, uap, retval) 101245914Smckusick struct proc *p; 101354916Storek register struct ostat_args *uap; 101453468Smckusick int *retval; 101553468Smckusick { 101653468Smckusick struct stat sb; 101753468Smckusick struct ostat osb; 101853468Smckusick int error; 101953468Smckusick struct nameidata nd; 102053468Smckusick 102153468Smckusick NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 102253468Smckusick if (error = namei(&nd)) 102353468Smckusick return (error); 102453468Smckusick error = vn_stat(nd.ni_vp, &sb, p); 102553468Smckusick vput(nd.ni_vp); 102653468Smckusick if (error) 102753468Smckusick return (error); 102853468Smckusick cvtstat(&sb, &osb); 102953468Smckusick error = copyout((caddr_t)&osb, (caddr_t)uap->ub, sizeof (osb)); 103053468Smckusick return (error); 103153468Smckusick } 103253468Smckusick 103353468Smckusick /* 103453468Smckusick * Lstat system call. 103553468Smckusick * This version does not follow links. 103653468Smckusick */ 103754916Storek struct olstat_args { 103854916Storek char *fname; 103954916Storek struct ostat *ub; 104054916Storek }; 104153468Smckusick /* ARGSUSED */ 104253759Smckusick olstat(p, uap, retval) 104353468Smckusick struct proc *p; 104454916Storek register struct olstat_args *uap; 104553468Smckusick int *retval; 104653468Smckusick { 104753468Smckusick struct stat sb; 104853468Smckusick struct ostat osb; 104953468Smckusick int error; 105053468Smckusick struct nameidata nd; 105153468Smckusick 105253468Smckusick NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 105353468Smckusick if (error = namei(&nd)) 105453468Smckusick return (error); 105553468Smckusick error = vn_stat(nd.ni_vp, &sb, p); 105653468Smckusick vput(nd.ni_vp); 105753468Smckusick if (error) 105853468Smckusick return (error); 105953468Smckusick cvtstat(&sb, &osb); 106053468Smckusick error = copyout((caddr_t)&osb, (caddr_t)uap->ub, sizeof (osb)); 106153468Smckusick return (error); 106253468Smckusick } 106353468Smckusick 106453468Smckusick /* 106553468Smckusick * convert from an old to a new stat structure. 106653468Smckusick */ 106753468Smckusick cvtstat(st, ost) 106853468Smckusick struct stat *st; 106953468Smckusick struct ostat *ost; 107053468Smckusick { 107153468Smckusick 107253468Smckusick ost->st_dev = st->st_dev; 107353468Smckusick ost->st_ino = st->st_ino; 107453468Smckusick ost->st_mode = st->st_mode; 107553468Smckusick ost->st_nlink = st->st_nlink; 107653468Smckusick ost->st_uid = st->st_uid; 107753468Smckusick ost->st_gid = st->st_gid; 107853468Smckusick ost->st_rdev = st->st_rdev; 107953468Smckusick if (st->st_size < (quad_t)1 << 32) 108053468Smckusick ost->st_size = st->st_size; 108153468Smckusick else 108253468Smckusick ost->st_size = -2; 108353468Smckusick ost->st_atime = st->st_atime; 108453468Smckusick ost->st_mtime = st->st_mtime; 108553468Smckusick ost->st_ctime = st->st_ctime; 108653468Smckusick ost->st_blksize = st->st_blksize; 108753468Smckusick ost->st_blocks = st->st_blocks; 108853468Smckusick ost->st_flags = st->st_flags; 108953468Smckusick ost->st_gen = st->st_gen; 109053468Smckusick } 109154348Smckusick #endif /* COMPAT_43 || COMPAT_SUNOS */ 109253468Smckusick 109353468Smckusick /* 109453468Smckusick * Stat system call. 109553468Smckusick * This version follows links. 109653468Smckusick */ 109754916Storek struct stat_args { 109854916Storek char *fname; 109954916Storek struct stat *ub; 110054916Storek }; 110153468Smckusick /* ARGSUSED */ 110253759Smckusick stat(p, uap, retval) 110353468Smckusick struct proc *p; 110454916Storek register struct stat_args *uap; 110542441Smckusick int *retval; 110637Sbill { 110742441Smckusick struct stat sb; 110842441Smckusick int error; 110947540Skarels struct nameidata nd; 111037Sbill 111152322Smckusick NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 111252322Smckusick if (error = namei(&nd)) 111347540Skarels return (error); 111452322Smckusick error = vn_stat(nd.ni_vp, &sb, p); 111552322Smckusick vput(nd.ni_vp); 111642441Smckusick if (error) 111747540Skarels return (error); 111842441Smckusick error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb)); 111947540Skarels return (error); 112037Sbill } 112137Sbill 112237Sbill /* 112349365Smckusick * Lstat system call. 112449365Smckusick * This version does not follow links. 11255992Swnj */ 112654916Storek struct lstat_args { 112754916Storek char *fname; 112854916Storek struct stat *ub; 112954916Storek }; 113042441Smckusick /* ARGSUSED */ 113153759Smckusick lstat(p, uap, retval) 113245914Smckusick struct proc *p; 113354916Storek register struct lstat_args *uap; 113442441Smckusick int *retval; 113542441Smckusick { 113612756Ssam struct stat sb; 113737741Smckusick int error; 113847540Skarels struct nameidata nd; 11395992Swnj 114052322Smckusick NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 114152322Smckusick if (error = namei(&nd)) 114247540Skarels return (error); 114352322Smckusick error = vn_stat(nd.ni_vp, &sb, p); 114452322Smckusick vput(nd.ni_vp); 114537741Smckusick if (error) 114647540Skarels return (error); 114737741Smckusick error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb)); 114847540Skarels return (error); 11495992Swnj } 11505992Swnj 11515992Swnj /* 115249365Smckusick * Return target name of a symbolic link. 115337Sbill */ 115454916Storek struct readlink_args { 115554916Storek char *name; 115654916Storek char *buf; 115754916Storek int count; 115854916Storek }; 115942441Smckusick /* ARGSUSED */ 116042441Smckusick readlink(p, uap, retval) 116145914Smckusick struct proc *p; 116254916Storek register struct readlink_args *uap; 116342441Smckusick int *retval; 116442441Smckusick { 116537741Smckusick register struct vnode *vp; 116637741Smckusick struct iovec aiov; 116737741Smckusick struct uio auio; 116837741Smckusick int error; 116947540Skarels struct nameidata nd; 11705992Swnj 117152322Smckusick NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, uap->name, p); 117252322Smckusick if (error = namei(&nd)) 117347540Skarels return (error); 117452322Smckusick vp = nd.ni_vp; 117537741Smckusick if (vp->v_type != VLNK) { 117637741Smckusick error = EINVAL; 11775992Swnj goto out; 11785992Swnj } 117937741Smckusick aiov.iov_base = uap->buf; 118037741Smckusick aiov.iov_len = uap->count; 118137741Smckusick auio.uio_iov = &aiov; 118237741Smckusick auio.uio_iovcnt = 1; 118337741Smckusick auio.uio_offset = 0; 118437741Smckusick auio.uio_rw = UIO_READ; 118537741Smckusick auio.uio_segflg = UIO_USERSPACE; 118648026Smckusick auio.uio_procp = p; 118737741Smckusick auio.uio_resid = uap->count; 118847540Skarels error = VOP_READLINK(vp, &auio, p->p_ucred); 11895992Swnj out: 119037741Smckusick vput(vp); 119142441Smckusick *retval = uap->count - auio.uio_resid; 119247540Skarels return (error); 11935992Swnj } 11945992Swnj 11959167Ssam /* 119638259Smckusick * Change flags of a file given path name. 119738259Smckusick */ 119854916Storek struct chflags_args { 119954916Storek char *fname; 120054916Storek int flags; 120154916Storek }; 120242441Smckusick /* ARGSUSED */ 120342441Smckusick chflags(p, uap, retval) 120445914Smckusick struct proc *p; 120554916Storek register struct chflags_args *uap; 120642441Smckusick int *retval; 120742441Smckusick { 120838259Smckusick register struct vnode *vp; 120938259Smckusick struct vattr vattr; 121038259Smckusick int error; 121147540Skarels struct nameidata nd; 121238259Smckusick 121352322Smckusick NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 121452322Smckusick if (error = namei(&nd)) 121547540Skarels return (error); 121652322Smckusick vp = nd.ni_vp; 121741400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 121838259Smckusick error = EROFS; 121938259Smckusick goto out; 122038259Smckusick } 122145785Sbostic VATTR_NULL(&vattr); 122245785Sbostic vattr.va_flags = uap->flags; 122352192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 122448026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 122538259Smckusick out: 122638259Smckusick vput(vp); 122747540Skarels return (error); 122838259Smckusick } 122938259Smckusick 123038259Smckusick /* 123138259Smckusick * Change flags of a file given a file descriptor. 123238259Smckusick */ 123354916Storek struct fchflags_args { 123454916Storek int fd; 123554916Storek int flags; 123654916Storek }; 123742441Smckusick /* ARGSUSED */ 123842441Smckusick fchflags(p, uap, retval) 123945914Smckusick struct proc *p; 124054916Storek register struct fchflags_args *uap; 124142441Smckusick int *retval; 124242441Smckusick { 124338259Smckusick struct vattr vattr; 124438259Smckusick struct vnode *vp; 124538259Smckusick struct file *fp; 124638259Smckusick int error; 124738259Smckusick 124845914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 124947540Skarels return (error); 125038259Smckusick vp = (struct vnode *)fp->f_data; 125138259Smckusick VOP_LOCK(vp); 125241400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 125338259Smckusick error = EROFS; 125438259Smckusick goto out; 125538259Smckusick } 125645785Sbostic VATTR_NULL(&vattr); 125745785Sbostic vattr.va_flags = uap->flags; 125852192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 125948026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 126038259Smckusick out: 126138259Smckusick VOP_UNLOCK(vp); 126247540Skarels return (error); 126338259Smckusick } 126438259Smckusick 126538259Smckusick /* 12669167Ssam * Change mode of a file given path name. 12679167Ssam */ 126854916Storek struct chmod_args { 126954916Storek char *fname; 127054916Storek int fmode; 127154916Storek }; 127242441Smckusick /* ARGSUSED */ 127342441Smckusick chmod(p, uap, retval) 127445914Smckusick struct proc *p; 127554916Storek register struct chmod_args *uap; 127642441Smckusick int *retval; 127742441Smckusick { 127837741Smckusick register struct vnode *vp; 127937741Smckusick struct vattr vattr; 128037741Smckusick int error; 128147540Skarels struct nameidata nd; 12825992Swnj 128352322Smckusick NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 128452322Smckusick if (error = namei(&nd)) 128547540Skarels return (error); 128652322Smckusick vp = nd.ni_vp; 128741400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 128837741Smckusick error = EROFS; 128937741Smckusick goto out; 129037741Smckusick } 129145785Sbostic VATTR_NULL(&vattr); 129245785Sbostic vattr.va_mode = uap->fmode & 07777; 129352192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 129448026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 129537741Smckusick out: 129637741Smckusick vput(vp); 129747540Skarels return (error); 12987701Ssam } 12997439Sroot 13009167Ssam /* 13019167Ssam * Change mode of a file given a file descriptor. 13029167Ssam */ 130354916Storek struct fchmod_args { 130454916Storek int fd; 130554916Storek int fmode; 130654916Storek }; 130742441Smckusick /* ARGSUSED */ 130842441Smckusick fchmod(p, uap, retval) 130945914Smckusick struct proc *p; 131054916Storek register struct fchmod_args *uap; 131142441Smckusick int *retval; 131242441Smckusick { 131337741Smckusick struct vattr vattr; 131437741Smckusick struct vnode *vp; 131537741Smckusick struct file *fp; 131637741Smckusick int error; 13177701Ssam 131845914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 131947540Skarels return (error); 132037741Smckusick vp = (struct vnode *)fp->f_data; 132137741Smckusick VOP_LOCK(vp); 132241400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 132337741Smckusick error = EROFS; 132437741Smckusick goto out; 13257439Sroot } 132645785Sbostic VATTR_NULL(&vattr); 132745785Sbostic vattr.va_mode = uap->fmode & 07777; 132852192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 132948026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 133037741Smckusick out: 133137741Smckusick VOP_UNLOCK(vp); 133247540Skarels return (error); 13335992Swnj } 13345992Swnj 13359167Ssam /* 13369167Ssam * Set ownership given a path name. 13379167Ssam */ 133854916Storek struct chown_args { 133954916Storek char *fname; 134054916Storek int uid; 134154916Storek int gid; 134254916Storek }; 134342441Smckusick /* ARGSUSED */ 134442441Smckusick chown(p, uap, retval) 134545914Smckusick struct proc *p; 134654916Storek register struct chown_args *uap; 134742441Smckusick int *retval; 134842441Smckusick { 134937741Smckusick register struct vnode *vp; 135037741Smckusick struct vattr vattr; 135137741Smckusick int error; 135247540Skarels struct nameidata nd; 135337Sbill 135452322Smckusick NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 135552322Smckusick if (error = namei(&nd)) 135647540Skarels return (error); 135752322Smckusick vp = nd.ni_vp; 135841400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 135937741Smckusick error = EROFS; 136037741Smckusick goto out; 136137741Smckusick } 136245785Sbostic VATTR_NULL(&vattr); 136345785Sbostic vattr.va_uid = uap->uid; 136445785Sbostic vattr.va_gid = uap->gid; 136552192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 136648026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 136737741Smckusick out: 136837741Smckusick vput(vp); 136947540Skarels return (error); 13707701Ssam } 13717439Sroot 13729167Ssam /* 13739167Ssam * Set ownership given a file descriptor. 13749167Ssam */ 137554916Storek struct fchown_args { 137654916Storek int fd; 137754916Storek int uid; 137854916Storek int gid; 137954916Storek }; 138042441Smckusick /* ARGSUSED */ 138142441Smckusick fchown(p, uap, retval) 138245914Smckusick struct proc *p; 138354916Storek register struct fchown_args *uap; 138442441Smckusick int *retval; 138542441Smckusick { 138637741Smckusick struct vattr vattr; 138737741Smckusick struct vnode *vp; 138837741Smckusick struct file *fp; 138937741Smckusick int error; 13907701Ssam 139145914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 139247540Skarels return (error); 139337741Smckusick vp = (struct vnode *)fp->f_data; 139437741Smckusick 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; 140252192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 140348026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 140437741Smckusick out: 140537741Smckusick VOP_UNLOCK(vp); 140647540Skarels return (error); 14077701Ssam } 14087701Ssam 140942441Smckusick /* 141042441Smckusick * Set the access and modification times of a file. 141142441Smckusick */ 141254916Storek struct utimes_args { 141354916Storek char *fname; 141454916Storek struct timeval *tptr; 141554916Storek }; 141642441Smckusick /* ARGSUSED */ 141742441Smckusick utimes(p, uap, retval) 141845914Smckusick struct proc *p; 141954916Storek register struct utimes_args *uap; 142042441Smckusick int *retval; 142142441Smckusick { 142237741Smckusick register struct vnode *vp; 142311811Ssam struct timeval tv[2]; 142437741Smckusick struct vattr vattr; 1425*58840Storek int error; 142647540Skarels struct nameidata nd; 142711811Ssam 142858505Sbostic VATTR_NULL(&vattr); 142958505Sbostic if (uap->tptr == NULL) { 143058505Sbostic microtime(&tv[0]); 143158505Sbostic tv[1] = tv[0]; 143258548Sbostic vattr.va_vaflags |= VA_UTIMES_NULL; 143358505Sbostic } else if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv))) 143458505Sbostic return (error); 143552322Smckusick NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 143652322Smckusick if (error = namei(&nd)) 143747540Skarels return (error); 143852322Smckusick vp = nd.ni_vp; 143941400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 144037741Smckusick error = EROFS; 144137741Smckusick goto out; 144221015Smckusick } 144354100Smckusick vattr.va_atime.ts_sec = tv[0].tv_sec; 144454100Smckusick vattr.va_atime.ts_nsec = tv[0].tv_usec * 1000; 144554100Smckusick vattr.va_mtime.ts_sec = tv[1].tv_sec; 144654100Smckusick vattr.va_mtime.ts_nsec = tv[1].tv_usec * 1000; 144752192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 144848026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 144937741Smckusick out: 145037741Smckusick vput(vp); 145147540Skarels return (error); 145211811Ssam } 145311811Ssam 145454916Storek struct __truncate_args { 145554863Storek char *fname; 145654863Storek int pad; 145754863Storek off_t length; 145854863Storek }; 145953468Smckusick 146053468Smckusick /* 146153468Smckusick * Truncate a file given its path name. 146253468Smckusick */ 146353468Smckusick /* ARGSUSED */ 146453759Smckusick __truncate(p, uap, retval) 146553468Smckusick struct proc *p; 146654916Storek register struct __truncate_args *uap; 146753468Smckusick int *retval; 146853468Smckusick { 146937741Smckusick register struct vnode *vp; 147037741Smckusick struct vattr vattr; 147137741Smckusick int error; 147247540Skarels struct nameidata nd; 14737701Ssam 147452322Smckusick NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 147552322Smckusick if (error = namei(&nd)) 147647540Skarels return (error); 147752322Smckusick vp = nd.ni_vp; 147837741Smckusick if (vp->v_type == VDIR) { 147937741Smckusick error = EISDIR; 148037741Smckusick goto out; 14817701Ssam } 148238399Smckusick if ((error = vn_writechk(vp)) || 148348026Smckusick (error = VOP_ACCESS(vp, VWRITE, p->p_ucred, p))) 148437741Smckusick goto out; 148545785Sbostic VATTR_NULL(&vattr); 148645785Sbostic vattr.va_size = uap->length; 148752192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 148848026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 148937741Smckusick out: 149037741Smckusick vput(vp); 149147540Skarels return (error); 14927701Ssam } 14937701Ssam 149454916Storek struct __ftruncate_args { 149554863Storek int fd; 149654863Storek int pad; 149754863Storek off_t length; 149854863Storek }; 149954863Storek 15009167Ssam /* 15019167Ssam * Truncate a file given a file descriptor. 15029167Ssam */ 150342441Smckusick /* ARGSUSED */ 150453759Smckusick __ftruncate(p, uap, retval) 150545914Smckusick struct proc *p; 150654916Storek register struct __ftruncate_args *uap; 150742441Smckusick int *retval; 150842441Smckusick { 150937741Smckusick struct vattr vattr; 151037741Smckusick struct vnode *vp; 15117701Ssam struct file *fp; 151237741Smckusick int error; 15137701Ssam 151445914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 151547540Skarels return (error); 151637741Smckusick if ((fp->f_flag & FWRITE) == 0) 151747540Skarels return (EINVAL); 151837741Smckusick vp = (struct vnode *)fp->f_data; 151937741Smckusick VOP_LOCK(vp); 152037741Smckusick if (vp->v_type == VDIR) { 152137741Smckusick error = EISDIR; 152237741Smckusick goto out; 15237701Ssam } 152438399Smckusick if (error = vn_writechk(vp)) 152537741Smckusick goto out; 152645785Sbostic VATTR_NULL(&vattr); 152745785Sbostic vattr.va_size = uap->length; 152852192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 152948026Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred, p); 153037741Smckusick out: 153137741Smckusick VOP_UNLOCK(vp); 153247540Skarels return (error); 15337701Ssam } 15347701Ssam 153554863Storek #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 15369167Ssam /* 153754863Storek * Truncate a file given its path name. 153854863Storek */ 153954916Storek struct truncate_args { 154054916Storek char *fname; 154154916Storek long length; 154254916Storek }; 154354863Storek /* ARGSUSED */ 154454863Storek truncate(p, uap, retval) 154554863Storek struct proc *p; 154654916Storek register struct truncate_args *uap; 154754863Storek int *retval; 154854863Storek { 154954916Storek struct __truncate_args nuap; 155054863Storek 155154863Storek nuap.fname = uap->fname; 155254863Storek nuap.length = uap->length; 155354863Storek return (__truncate(p, &nuap, retval)); 155454863Storek } 155554863Storek 155654863Storek /* 155754863Storek * Truncate a file given a file descriptor. 155854863Storek */ 155954916Storek struct ftruncate_args { 156054916Storek int fd; 156154916Storek long length; 156254916Storek }; 156354863Storek /* ARGSUSED */ 156454863Storek ftruncate(p, uap, retval) 156554863Storek struct proc *p; 156654916Storek register struct ftruncate_args *uap; 156754863Storek int *retval; 156854863Storek { 156954969Smckusick struct __ftruncate_args nuap; 157054863Storek 157154863Storek nuap.fd = uap->fd; 157254863Storek nuap.length = uap->length; 157354863Storek return (__ftruncate(p, &nuap, retval)); 157454863Storek } 157554863Storek #endif /* COMPAT_43 || COMPAT_SUNOS */ 157654863Storek 157754863Storek /* 15789167Ssam * Synch an open file. 15799167Ssam */ 158054916Storek struct fsync_args { 158154916Storek int fd; 158254916Storek }; 158342441Smckusick /* ARGSUSED */ 158442441Smckusick fsync(p, uap, retval) 158545914Smckusick struct proc *p; 158654916Storek struct fsync_args *uap; 158742441Smckusick int *retval; 15889167Ssam { 158939592Smckusick register struct vnode *vp; 15909167Ssam struct file *fp; 159137741Smckusick int error; 15929167Ssam 159345914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 159447540Skarels return (error); 159539592Smckusick vp = (struct vnode *)fp->f_data; 159639592Smckusick VOP_LOCK(vp); 159754441Smckusick error = VOP_FSYNC(vp, fp->f_cred, MNT_WAIT, p); 159839592Smckusick VOP_UNLOCK(vp); 159947540Skarels return (error); 16009167Ssam } 16019167Ssam 16029167Ssam /* 16039167Ssam * Rename system call. 16049167Ssam * 16059167Ssam * Source and destination must either both be directories, or both 16069167Ssam * not be directories. If target is a directory, it must be empty. 16079167Ssam */ 160854916Storek struct rename_args { 160954916Storek char *from; 161054916Storek char *to; 161154916Storek }; 161242441Smckusick /* ARGSUSED */ 161342441Smckusick rename(p, uap, retval) 161445914Smckusick struct proc *p; 161554916Storek register struct rename_args *uap; 161642441Smckusick int *retval; 161742441Smckusick { 161837741Smckusick register struct vnode *tvp, *fvp, *tdvp; 161949735Smckusick struct nameidata fromnd, tond; 162037741Smckusick int error; 16217701Ssam 162252322Smckusick NDINIT(&fromnd, DELETE, WANTPARENT | SAVESTART, UIO_USERSPACE, 162352322Smckusick uap->from, p); 162452322Smckusick if (error = namei(&fromnd)) 162547540Skarels return (error); 162649735Smckusick fvp = fromnd.ni_vp; 162752322Smckusick NDINIT(&tond, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART, 162852322Smckusick UIO_USERSPACE, uap->to, p); 162952322Smckusick if (error = namei(&tond)) { 163052230Sheideman VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 163149735Smckusick vrele(fromnd.ni_dvp); 163242465Smckusick vrele(fvp); 163342465Smckusick goto out1; 163442465Smckusick } 163537741Smckusick tdvp = tond.ni_dvp; 163637741Smckusick tvp = tond.ni_vp; 163737741Smckusick if (tvp != NULL) { 163837741Smckusick if (fvp->v_type == VDIR && tvp->v_type != VDIR) { 163939242Sbostic error = ENOTDIR; 164037741Smckusick goto out; 164137741Smckusick } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) { 164239242Sbostic error = EISDIR; 164337741Smckusick goto out; 16449167Ssam } 16459167Ssam } 164639286Smckusick if (fvp == tdvp) 164737741Smckusick error = EINVAL; 164839286Smckusick /* 164949735Smckusick * If source is the same as the destination (that is the 165049735Smckusick * same inode number with the same name in the same directory), 165139286Smckusick * then there is nothing to do. 165239286Smckusick */ 165349735Smckusick if (fvp == tvp && fromnd.ni_dvp == tdvp && 165452322Smckusick fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen && 165552322Smckusick !bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr, 165652322Smckusick fromnd.ni_cnd.cn_namelen)) 165739286Smckusick error = -1; 165837741Smckusick out: 165942465Smckusick if (!error) { 166052192Smckusick LEASE_CHECK(tdvp, p, p->p_ucred, LEASE_WRITE); 166152192Smckusick if (fromnd.ni_dvp != tdvp) 166252192Smckusick LEASE_CHECK(fromnd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 166352192Smckusick if (tvp) 166452192Smckusick LEASE_CHECK(tvp, p, p->p_ucred, LEASE_WRITE); 166552230Sheideman error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd, 166652230Sheideman tond.ni_dvp, tond.ni_vp, &tond.ni_cnd); 166742465Smckusick } else { 166852230Sheideman VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd); 166943344Smckusick if (tdvp == tvp) 167043344Smckusick vrele(tdvp); 167143344Smckusick else 167243344Smckusick vput(tdvp); 167342465Smckusick if (tvp) 167442465Smckusick vput(tvp); 167552230Sheideman VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 167649735Smckusick vrele(fromnd.ni_dvp); 167742465Smckusick vrele(fvp); 16789167Ssam } 167949735Smckusick vrele(tond.ni_startdir); 168052322Smckusick FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI); 168137741Smckusick out1: 168249735Smckusick vrele(fromnd.ni_startdir); 168352322Smckusick FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI); 168439286Smckusick if (error == -1) 168547540Skarels return (0); 168647540Skarels return (error); 16877701Ssam } 16887701Ssam 16897535Sroot /* 169049365Smckusick * Mkdir system call. 169112756Ssam */ 169254916Storek struct mkdir_args { 169354916Storek char *name; 169454916Storek int dmode; 169554916Storek }; 169642441Smckusick /* ARGSUSED */ 169742441Smckusick mkdir(p, uap, retval) 169845914Smckusick struct proc *p; 169954916Storek register struct mkdir_args *uap; 170042441Smckusick int *retval; 170142441Smckusick { 170237741Smckusick register struct vnode *vp; 170337741Smckusick struct vattr vattr; 170437741Smckusick int error; 170547540Skarels struct nameidata nd; 170612756Ssam 170752322Smckusick NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->name, p); 170852322Smckusick if (error = namei(&nd)) 170947540Skarels return (error); 171052322Smckusick vp = nd.ni_vp; 171137741Smckusick if (vp != NULL) { 171252322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 171352322Smckusick if (nd.ni_dvp == vp) 171452322Smckusick vrele(nd.ni_dvp); 171543344Smckusick else 171652322Smckusick vput(nd.ni_dvp); 171742465Smckusick vrele(vp); 171847540Skarels return (EEXIST); 171912756Ssam } 172041362Smckusick VATTR_NULL(&vattr); 172137741Smckusick vattr.va_type = VDIR; 172245914Smckusick vattr.va_mode = (uap->dmode & 0777) &~ p->p_fd->fd_cmask; 172352322Smckusick LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 172452322Smckusick error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr); 172538145Smckusick if (!error) 172652322Smckusick vput(nd.ni_vp); 172747540Skarels return (error); 172812756Ssam } 172912756Ssam 173012756Ssam /* 173112756Ssam * Rmdir system call. 173212756Ssam */ 173354916Storek struct rmdir_args { 173454916Storek char *name; 173554916Storek }; 173642441Smckusick /* ARGSUSED */ 173742441Smckusick rmdir(p, uap, retval) 173845914Smckusick struct proc *p; 173954916Storek struct rmdir_args *uap; 174042441Smckusick int *retval; 174112756Ssam { 174237741Smckusick register struct vnode *vp; 174337741Smckusick int error; 174447540Skarels struct nameidata nd; 174512756Ssam 174652322Smckusick NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE, uap->name, p); 174752322Smckusick if (error = namei(&nd)) 174847540Skarels return (error); 174952322Smckusick vp = nd.ni_vp; 175037741Smckusick if (vp->v_type != VDIR) { 175137741Smckusick error = ENOTDIR; 175212756Ssam goto out; 175312756Ssam } 175412756Ssam /* 175537741Smckusick * No rmdir "." please. 175612756Ssam */ 175752322Smckusick if (nd.ni_dvp == vp) { 175837741Smckusick error = EINVAL; 175912756Ssam goto out; 176012756Ssam } 176112756Ssam /* 176249365Smckusick * The root of a mounted filesystem cannot be deleted. 176312756Ssam */ 176437741Smckusick if (vp->v_flag & VROOT) 176537741Smckusick error = EBUSY; 176612756Ssam out: 176742465Smckusick if (!error) { 176852322Smckusick LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 176952192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 177052322Smckusick error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); 177142465Smckusick } else { 177252322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 177352322Smckusick if (nd.ni_dvp == vp) 177452322Smckusick vrele(nd.ni_dvp); 177543344Smckusick else 177652322Smckusick vput(nd.ni_dvp); 177742465Smckusick vput(vp); 177842465Smckusick } 177947540Skarels return (error); 178012756Ssam } 178112756Ssam 178254620Smckusick #ifdef COMPAT_43 178337741Smckusick /* 178449365Smckusick * Read a block of directory entries in a file system independent format. 178537741Smckusick */ 178654916Storek struct ogetdirentries_args { 178754916Storek int fd; 178854916Storek char *buf; 178954916Storek unsigned count; 179054916Storek long *basep; 179154916Storek }; 179254620Smckusick ogetdirentries(p, uap, retval) 179354620Smckusick struct proc *p; 179454916Storek register struct ogetdirentries_args *uap; 179554620Smckusick int *retval; 179654620Smckusick { 179754620Smckusick register struct vnode *vp; 179854620Smckusick struct file *fp; 179954620Smckusick struct uio auio, kuio; 180054620Smckusick struct iovec aiov, kiov; 180154620Smckusick struct dirent *dp, *edp; 180254620Smckusick caddr_t dirbuf; 180354620Smckusick int error, readcnt; 180454969Smckusick long loff; 180554620Smckusick 180654620Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 180754620Smckusick return (error); 180854620Smckusick if ((fp->f_flag & FREAD) == 0) 180954620Smckusick return (EBADF); 181054620Smckusick vp = (struct vnode *)fp->f_data; 181154620Smckusick if (vp->v_type != VDIR) 181254620Smckusick return (EINVAL); 181354620Smckusick aiov.iov_base = uap->buf; 181454620Smckusick aiov.iov_len = uap->count; 181554620Smckusick auio.uio_iov = &aiov; 181654620Smckusick auio.uio_iovcnt = 1; 181754620Smckusick auio.uio_rw = UIO_READ; 181854620Smckusick auio.uio_segflg = UIO_USERSPACE; 181954620Smckusick auio.uio_procp = p; 182054620Smckusick auio.uio_resid = uap->count; 182154620Smckusick VOP_LOCK(vp); 182254969Smckusick loff = auio.uio_offset = fp->f_offset; 182354620Smckusick # if (BYTE_ORDER != LITTLE_ENDIAN) 182456339Smckusick if (vp->v_mount->mnt_maxsymlinklen <= 0) { 182554620Smckusick error = VOP_READDIR(vp, &auio, fp->f_cred); 182656339Smckusick fp->f_offset = auio.uio_offset; 182756339Smckusick } else 182854620Smckusick # endif 182954620Smckusick { 183054620Smckusick kuio = auio; 183154620Smckusick kuio.uio_iov = &kiov; 183254620Smckusick kuio.uio_segflg = UIO_SYSSPACE; 183354620Smckusick kiov.iov_len = uap->count; 183454620Smckusick MALLOC(dirbuf, caddr_t, uap->count, M_TEMP, M_WAITOK); 183554620Smckusick kiov.iov_base = dirbuf; 183654620Smckusick error = VOP_READDIR(vp, &kuio, fp->f_cred); 183756339Smckusick fp->f_offset = kuio.uio_offset; 183854620Smckusick if (error == 0) { 183954620Smckusick readcnt = uap->count - kuio.uio_resid; 184054620Smckusick edp = (struct dirent *)&dirbuf[readcnt]; 184154620Smckusick for (dp = (struct dirent *)dirbuf; dp < edp; ) { 184254620Smckusick # if (BYTE_ORDER == LITTLE_ENDIAN) 184354969Smckusick /* 184455009Smckusick * The expected low byte of 184555009Smckusick * dp->d_namlen is our dp->d_type. 184655009Smckusick * The high MBZ byte of dp->d_namlen 184755009Smckusick * is our dp->d_namlen. 184854969Smckusick */ 184955009Smckusick dp->d_type = dp->d_namlen; 185055009Smckusick dp->d_namlen = 0; 185155009Smckusick # else 185255009Smckusick /* 185355009Smckusick * The dp->d_type is the high byte 185455009Smckusick * of the expected dp->d_namlen, 185555009Smckusick * so must be zero'ed. 185655009Smckusick */ 185755009Smckusick dp->d_type = 0; 185854620Smckusick # endif 185954620Smckusick if (dp->d_reclen > 0) { 186054620Smckusick dp = (struct dirent *) 186154620Smckusick ((char *)dp + dp->d_reclen); 186254620Smckusick } else { 186354620Smckusick error = EIO; 186454620Smckusick break; 186554620Smckusick } 186654620Smckusick } 186754620Smckusick if (dp >= edp) 186854620Smckusick error = uiomove(dirbuf, readcnt, &auio); 186954620Smckusick } 187054620Smckusick FREE(dirbuf, M_TEMP); 187154620Smckusick } 187254620Smckusick VOP_UNLOCK(vp); 187354620Smckusick if (error) 187454620Smckusick return (error); 187554969Smckusick error = copyout((caddr_t)&loff, (caddr_t)uap->basep, sizeof(long)); 187654620Smckusick *retval = uap->count - auio.uio_resid; 187754620Smckusick return (error); 187854620Smckusick } 187954620Smckusick #endif 188054620Smckusick 188154620Smckusick /* 188254620Smckusick * Read a block of directory entries in a file system independent format. 188354620Smckusick */ 188454916Storek struct getdirentries_args { 188554916Storek int fd; 188654916Storek char *buf; 188754916Storek unsigned count; 188854916Storek long *basep; 188954916Storek }; 189042441Smckusick getdirentries(p, uap, retval) 189145914Smckusick struct proc *p; 189254916Storek register struct getdirentries_args *uap; 189342441Smckusick int *retval; 189442441Smckusick { 189539592Smckusick register struct vnode *vp; 189616540Ssam struct file *fp; 189737741Smckusick struct uio auio; 189837741Smckusick struct iovec aiov; 189954969Smckusick long loff; 190054441Smckusick int error; 190112756Ssam 190245914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 190347540Skarels return (error); 190437741Smckusick if ((fp->f_flag & FREAD) == 0) 190547540Skarels return (EBADF); 190639592Smckusick vp = (struct vnode *)fp->f_data; 190755451Spendry unionread: 190839592Smckusick if (vp->v_type != VDIR) 190947540Skarels return (EINVAL); 191037741Smckusick aiov.iov_base = uap->buf; 191137741Smckusick aiov.iov_len = uap->count; 191237741Smckusick auio.uio_iov = &aiov; 191337741Smckusick auio.uio_iovcnt = 1; 191437741Smckusick auio.uio_rw = UIO_READ; 191537741Smckusick auio.uio_segflg = UIO_USERSPACE; 191648026Smckusick auio.uio_procp = p; 191737741Smckusick auio.uio_resid = uap->count; 191839592Smckusick VOP_LOCK(vp); 191954969Smckusick loff = auio.uio_offset = fp->f_offset; 192054441Smckusick error = VOP_READDIR(vp, &auio, fp->f_cred); 192139592Smckusick fp->f_offset = auio.uio_offset; 192239592Smckusick VOP_UNLOCK(vp); 192339592Smckusick if (error) 192447540Skarels return (error); 192555451Spendry if ((uap->count == auio.uio_resid) && 192655451Spendry (vp->v_flag & VROOT) && 192755451Spendry (vp->v_mount->mnt_flag & MNT_UNION)) { 192855451Spendry struct vnode *tvp = vp; 192955451Spendry vp = vp->v_mount->mnt_vnodecovered; 193055451Spendry VREF(vp); 193155451Spendry fp->f_data = (caddr_t) vp; 193255451Spendry fp->f_offset = 0; 193355451Spendry vrele(tvp); 193455451Spendry goto unionread; 193555451Spendry } 193654969Smckusick error = copyout((caddr_t)&loff, (caddr_t)uap->basep, sizeof(long)); 193742441Smckusick *retval = uap->count - auio.uio_resid; 193847540Skarels return (error); 193912756Ssam } 194012756Ssam 194112756Ssam /* 194249365Smckusick * Set the mode mask for creation of filesystem nodes. 194312756Ssam */ 194454916Storek struct umask_args { 194554916Storek int mask; 194654916Storek }; 194754916Storek mode_t /* XXX */ 194842441Smckusick umask(p, uap, retval) 194945914Smckusick struct proc *p; 195054916Storek struct umask_args *uap; 195142441Smckusick int *retval; 195212756Ssam { 195345914Smckusick register struct filedesc *fdp = p->p_fd; 195412756Ssam 195545914Smckusick *retval = fdp->fd_cmask; 195645914Smckusick fdp->fd_cmask = uap->mask & 07777; 195747540Skarels return (0); 195812756Ssam } 195937741Smckusick 196039566Smarc /* 196139566Smarc * Void all references to file by ripping underlying filesystem 196239566Smarc * away from vnode. 196339566Smarc */ 196454916Storek struct revoke_args { 196554916Storek char *fname; 196654916Storek }; 196742441Smckusick /* ARGSUSED */ 196842441Smckusick revoke(p, uap, retval) 196945914Smckusick struct proc *p; 197054916Storek register struct revoke_args *uap; 197142441Smckusick int *retval; 197242441Smckusick { 197339566Smarc register struct vnode *vp; 197439566Smarc struct vattr vattr; 197539566Smarc int error; 197647540Skarels struct nameidata nd; 197739566Smarc 197852322Smckusick NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->fname, p); 197952322Smckusick if (error = namei(&nd)) 198047540Skarels return (error); 198152322Smckusick vp = nd.ni_vp; 198239566Smarc if (vp->v_type != VCHR && vp->v_type != VBLK) { 198339566Smarc error = EINVAL; 198439566Smarc goto out; 198539566Smarc } 198648026Smckusick if (error = VOP_GETATTR(vp, &vattr, p->p_ucred, p)) 198739566Smarc goto out; 198847540Skarels if (p->p_ucred->cr_uid != vattr.va_uid && 198947540Skarels (error = suser(p->p_ucred, &p->p_acflag))) 199039566Smarc goto out; 199139805Smckusick if (vp->v_usecount > 1 || (vp->v_flag & VALIASED)) 199239632Smckusick vgoneall(vp); 199339566Smarc out: 199439566Smarc vrele(vp); 199547540Skarels return (error); 199639566Smarc } 199739566Smarc 199849365Smckusick /* 199949365Smckusick * Convert a user file descriptor to a kernel file entry. 200049365Smckusick */ 200145914Smckusick getvnode(fdp, fdes, fpp) 200245914Smckusick struct filedesc *fdp; 200337741Smckusick struct file **fpp; 200437741Smckusick int fdes; 200537741Smckusick { 200637741Smckusick struct file *fp; 200737741Smckusick 200847540Skarels if ((unsigned)fdes >= fdp->fd_nfiles || 200947688Skarels (fp = fdp->fd_ofiles[fdes]) == NULL) 201037741Smckusick return (EBADF); 201137741Smckusick if (fp->f_type != DTYPE_VNODE) 201237741Smckusick return (EINVAL); 201337741Smckusick *fpp = fp; 201437741Smckusick return (0); 201537741Smckusick } 2016