123405Smckusick /* 237741Smckusick * Copyright (c) 1989 The Regents of the University of California. 337741Smckusick * All rights reserved. 423405Smckusick * 544459Sbostic * %sccs.include.redist.c% 637741Smckusick * 7*57793Smckusick * @(#)vfs_syscalls.c 7.102 (Berkeley) 02/02/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 } 87*57793Smckusick 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; 142537741Smckusick int error; 142647540Skarels struct nameidata nd; 142711811Ssam 142837741Smckusick if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv))) 142947540Skarels return (error); 143052322Smckusick NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 143152322Smckusick if (error = namei(&nd)) 143247540Skarels return (error); 143352322Smckusick vp = nd.ni_vp; 143441400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 143537741Smckusick error = EROFS; 143637741Smckusick goto out; 143721015Smckusick } 143845785Sbostic VATTR_NULL(&vattr); 143954100Smckusick vattr.va_atime.ts_sec = tv[0].tv_sec; 144054100Smckusick vattr.va_atime.ts_nsec = tv[0].tv_usec * 1000; 144154100Smckusick vattr.va_mtime.ts_sec = tv[1].tv_sec; 144254100Smckusick vattr.va_mtime.ts_nsec = tv[1].tv_usec * 1000; 144352192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 144448026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 144537741Smckusick out: 144637741Smckusick vput(vp); 144747540Skarels return (error); 144811811Ssam } 144911811Ssam 145054916Storek struct __truncate_args { 145154863Storek char *fname; 145254863Storek int pad; 145354863Storek off_t length; 145454863Storek }; 145553468Smckusick 145653468Smckusick /* 145753468Smckusick * Truncate a file given its path name. 145853468Smckusick */ 145953468Smckusick /* ARGSUSED */ 146053759Smckusick __truncate(p, uap, retval) 146153468Smckusick struct proc *p; 146254916Storek register struct __truncate_args *uap; 146353468Smckusick int *retval; 146453468Smckusick { 146537741Smckusick register struct vnode *vp; 146637741Smckusick struct vattr vattr; 146737741Smckusick int error; 146847540Skarels struct nameidata nd; 14697701Ssam 147052322Smckusick NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 147152322Smckusick if (error = namei(&nd)) 147247540Skarels return (error); 147352322Smckusick vp = nd.ni_vp; 147437741Smckusick if (vp->v_type == VDIR) { 147537741Smckusick error = EISDIR; 147637741Smckusick goto out; 14777701Ssam } 147838399Smckusick if ((error = vn_writechk(vp)) || 147948026Smckusick (error = VOP_ACCESS(vp, VWRITE, p->p_ucred, p))) 148037741Smckusick goto out; 148145785Sbostic VATTR_NULL(&vattr); 148245785Sbostic vattr.va_size = uap->length; 148352192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 148448026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 148537741Smckusick out: 148637741Smckusick vput(vp); 148747540Skarels return (error); 14887701Ssam } 14897701Ssam 149054916Storek struct __ftruncate_args { 149154863Storek int fd; 149254863Storek int pad; 149354863Storek off_t length; 149454863Storek }; 149554863Storek 14969167Ssam /* 14979167Ssam * Truncate a file given a file descriptor. 14989167Ssam */ 149942441Smckusick /* ARGSUSED */ 150053759Smckusick __ftruncate(p, uap, retval) 150145914Smckusick struct proc *p; 150254916Storek register struct __ftruncate_args *uap; 150342441Smckusick int *retval; 150442441Smckusick { 150537741Smckusick struct vattr vattr; 150637741Smckusick struct vnode *vp; 15077701Ssam struct file *fp; 150837741Smckusick int error; 15097701Ssam 151045914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 151147540Skarels return (error); 151237741Smckusick if ((fp->f_flag & FWRITE) == 0) 151347540Skarels return (EINVAL); 151437741Smckusick vp = (struct vnode *)fp->f_data; 151537741Smckusick VOP_LOCK(vp); 151637741Smckusick if (vp->v_type == VDIR) { 151737741Smckusick error = EISDIR; 151837741Smckusick goto out; 15197701Ssam } 152038399Smckusick if (error = vn_writechk(vp)) 152137741Smckusick goto out; 152245785Sbostic VATTR_NULL(&vattr); 152345785Sbostic vattr.va_size = uap->length; 152452192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 152548026Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred, p); 152637741Smckusick out: 152737741Smckusick VOP_UNLOCK(vp); 152847540Skarels return (error); 15297701Ssam } 15307701Ssam 153154863Storek #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 15329167Ssam /* 153354863Storek * Truncate a file given its path name. 153454863Storek */ 153554916Storek struct truncate_args { 153654916Storek char *fname; 153754916Storek long length; 153854916Storek }; 153954863Storek /* ARGSUSED */ 154054863Storek truncate(p, uap, retval) 154154863Storek struct proc *p; 154254916Storek register struct truncate_args *uap; 154354863Storek int *retval; 154454863Storek { 154554916Storek struct __truncate_args nuap; 154654863Storek 154754863Storek nuap.fname = uap->fname; 154854863Storek nuap.length = uap->length; 154954863Storek return (__truncate(p, &nuap, retval)); 155054863Storek } 155154863Storek 155254863Storek /* 155354863Storek * Truncate a file given a file descriptor. 155454863Storek */ 155554916Storek struct ftruncate_args { 155654916Storek int fd; 155754916Storek long length; 155854916Storek }; 155954863Storek /* ARGSUSED */ 156054863Storek ftruncate(p, uap, retval) 156154863Storek struct proc *p; 156254916Storek register struct ftruncate_args *uap; 156354863Storek int *retval; 156454863Storek { 156554969Smckusick struct __ftruncate_args nuap; 156654863Storek 156754863Storek nuap.fd = uap->fd; 156854863Storek nuap.length = uap->length; 156954863Storek return (__ftruncate(p, &nuap, retval)); 157054863Storek } 157154863Storek #endif /* COMPAT_43 || COMPAT_SUNOS */ 157254863Storek 157354863Storek /* 15749167Ssam * Synch an open file. 15759167Ssam */ 157654916Storek struct fsync_args { 157754916Storek int fd; 157854916Storek }; 157942441Smckusick /* ARGSUSED */ 158042441Smckusick fsync(p, uap, retval) 158145914Smckusick struct proc *p; 158254916Storek struct fsync_args *uap; 158342441Smckusick int *retval; 15849167Ssam { 158539592Smckusick register struct vnode *vp; 15869167Ssam struct file *fp; 158737741Smckusick int error; 15889167Ssam 158945914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 159047540Skarels return (error); 159139592Smckusick vp = (struct vnode *)fp->f_data; 159239592Smckusick VOP_LOCK(vp); 159354441Smckusick error = VOP_FSYNC(vp, fp->f_cred, MNT_WAIT, p); 159439592Smckusick VOP_UNLOCK(vp); 159547540Skarels return (error); 15969167Ssam } 15979167Ssam 15989167Ssam /* 15999167Ssam * Rename system call. 16009167Ssam * 16019167Ssam * Source and destination must either both be directories, or both 16029167Ssam * not be directories. If target is a directory, it must be empty. 16039167Ssam */ 160454916Storek struct rename_args { 160554916Storek char *from; 160654916Storek char *to; 160754916Storek }; 160842441Smckusick /* ARGSUSED */ 160942441Smckusick rename(p, uap, retval) 161045914Smckusick struct proc *p; 161154916Storek register struct rename_args *uap; 161242441Smckusick int *retval; 161342441Smckusick { 161437741Smckusick register struct vnode *tvp, *fvp, *tdvp; 161549735Smckusick struct nameidata fromnd, tond; 161637741Smckusick int error; 16177701Ssam 161852322Smckusick NDINIT(&fromnd, DELETE, WANTPARENT | SAVESTART, UIO_USERSPACE, 161952322Smckusick uap->from, p); 162052322Smckusick if (error = namei(&fromnd)) 162147540Skarels return (error); 162249735Smckusick fvp = fromnd.ni_vp; 162352322Smckusick NDINIT(&tond, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART, 162452322Smckusick UIO_USERSPACE, uap->to, p); 162552322Smckusick if (error = namei(&tond)) { 162652230Sheideman VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 162749735Smckusick vrele(fromnd.ni_dvp); 162842465Smckusick vrele(fvp); 162942465Smckusick goto out1; 163042465Smckusick } 163137741Smckusick tdvp = tond.ni_dvp; 163237741Smckusick tvp = tond.ni_vp; 163337741Smckusick if (tvp != NULL) { 163437741Smckusick if (fvp->v_type == VDIR && tvp->v_type != VDIR) { 163539242Sbostic error = ENOTDIR; 163637741Smckusick goto out; 163737741Smckusick } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) { 163839242Sbostic error = EISDIR; 163937741Smckusick goto out; 16409167Ssam } 16419167Ssam } 164239286Smckusick if (fvp == tdvp) 164337741Smckusick error = EINVAL; 164439286Smckusick /* 164549735Smckusick * If source is the same as the destination (that is the 164649735Smckusick * same inode number with the same name in the same directory), 164739286Smckusick * then there is nothing to do. 164839286Smckusick */ 164949735Smckusick if (fvp == tvp && fromnd.ni_dvp == tdvp && 165052322Smckusick fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen && 165152322Smckusick !bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr, 165252322Smckusick fromnd.ni_cnd.cn_namelen)) 165339286Smckusick error = -1; 165437741Smckusick out: 165542465Smckusick if (!error) { 165652192Smckusick LEASE_CHECK(tdvp, p, p->p_ucred, LEASE_WRITE); 165752192Smckusick if (fromnd.ni_dvp != tdvp) 165852192Smckusick LEASE_CHECK(fromnd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 165952192Smckusick if (tvp) 166052192Smckusick LEASE_CHECK(tvp, p, p->p_ucred, LEASE_WRITE); 166152230Sheideman error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd, 166252230Sheideman tond.ni_dvp, tond.ni_vp, &tond.ni_cnd); 166342465Smckusick } else { 166452230Sheideman VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd); 166543344Smckusick if (tdvp == tvp) 166643344Smckusick vrele(tdvp); 166743344Smckusick else 166843344Smckusick vput(tdvp); 166942465Smckusick if (tvp) 167042465Smckusick vput(tvp); 167152230Sheideman VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 167249735Smckusick vrele(fromnd.ni_dvp); 167342465Smckusick vrele(fvp); 16749167Ssam } 167549735Smckusick vrele(tond.ni_startdir); 167652322Smckusick FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI); 167737741Smckusick out1: 167849735Smckusick vrele(fromnd.ni_startdir); 167952322Smckusick FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI); 168039286Smckusick if (error == -1) 168147540Skarels return (0); 168247540Skarels return (error); 16837701Ssam } 16847701Ssam 16857535Sroot /* 168649365Smckusick * Mkdir system call. 168712756Ssam */ 168854916Storek struct mkdir_args { 168954916Storek char *name; 169054916Storek int dmode; 169154916Storek }; 169242441Smckusick /* ARGSUSED */ 169342441Smckusick mkdir(p, uap, retval) 169445914Smckusick struct proc *p; 169554916Storek register struct mkdir_args *uap; 169642441Smckusick int *retval; 169742441Smckusick { 169837741Smckusick register struct vnode *vp; 169937741Smckusick struct vattr vattr; 170037741Smckusick int error; 170147540Skarels struct nameidata nd; 170212756Ssam 170352322Smckusick NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->name, p); 170452322Smckusick if (error = namei(&nd)) 170547540Skarels return (error); 170652322Smckusick vp = nd.ni_vp; 170737741Smckusick if (vp != NULL) { 170852322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 170952322Smckusick if (nd.ni_dvp == vp) 171052322Smckusick vrele(nd.ni_dvp); 171143344Smckusick else 171252322Smckusick vput(nd.ni_dvp); 171342465Smckusick vrele(vp); 171447540Skarels return (EEXIST); 171512756Ssam } 171641362Smckusick VATTR_NULL(&vattr); 171737741Smckusick vattr.va_type = VDIR; 171845914Smckusick vattr.va_mode = (uap->dmode & 0777) &~ p->p_fd->fd_cmask; 171952322Smckusick LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 172052322Smckusick error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr); 172138145Smckusick if (!error) 172252322Smckusick vput(nd.ni_vp); 172347540Skarels return (error); 172412756Ssam } 172512756Ssam 172612756Ssam /* 172712756Ssam * Rmdir system call. 172812756Ssam */ 172954916Storek struct rmdir_args { 173054916Storek char *name; 173154916Storek }; 173242441Smckusick /* ARGSUSED */ 173342441Smckusick rmdir(p, uap, retval) 173445914Smckusick struct proc *p; 173554916Storek struct rmdir_args *uap; 173642441Smckusick int *retval; 173712756Ssam { 173837741Smckusick register struct vnode *vp; 173937741Smckusick int error; 174047540Skarels struct nameidata nd; 174112756Ssam 174252322Smckusick NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE, uap->name, p); 174352322Smckusick if (error = namei(&nd)) 174447540Skarels return (error); 174552322Smckusick vp = nd.ni_vp; 174637741Smckusick if (vp->v_type != VDIR) { 174737741Smckusick error = ENOTDIR; 174812756Ssam goto out; 174912756Ssam } 175012756Ssam /* 175137741Smckusick * No rmdir "." please. 175212756Ssam */ 175352322Smckusick if (nd.ni_dvp == vp) { 175437741Smckusick error = EINVAL; 175512756Ssam goto out; 175612756Ssam } 175712756Ssam /* 175849365Smckusick * The root of a mounted filesystem cannot be deleted. 175912756Ssam */ 176037741Smckusick if (vp->v_flag & VROOT) 176137741Smckusick error = EBUSY; 176212756Ssam out: 176342465Smckusick if (!error) { 176452322Smckusick LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 176552192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 176652322Smckusick error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); 176742465Smckusick } else { 176852322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 176952322Smckusick if (nd.ni_dvp == vp) 177052322Smckusick vrele(nd.ni_dvp); 177143344Smckusick else 177252322Smckusick vput(nd.ni_dvp); 177342465Smckusick vput(vp); 177442465Smckusick } 177547540Skarels return (error); 177612756Ssam } 177712756Ssam 177854620Smckusick #ifdef COMPAT_43 177937741Smckusick /* 178049365Smckusick * Read a block of directory entries in a file system independent format. 178137741Smckusick */ 178254916Storek struct ogetdirentries_args { 178354916Storek int fd; 178454916Storek char *buf; 178554916Storek unsigned count; 178654916Storek long *basep; 178754916Storek }; 178854620Smckusick ogetdirentries(p, uap, retval) 178954620Smckusick struct proc *p; 179054916Storek register struct ogetdirentries_args *uap; 179154620Smckusick int *retval; 179254620Smckusick { 179354620Smckusick register struct vnode *vp; 179454620Smckusick struct file *fp; 179554620Smckusick struct uio auio, kuio; 179654620Smckusick struct iovec aiov, kiov; 179754620Smckusick struct dirent *dp, *edp; 179854620Smckusick caddr_t dirbuf; 179954620Smckusick int error, readcnt; 180054969Smckusick long loff; 180154620Smckusick 180254620Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 180354620Smckusick return (error); 180454620Smckusick if ((fp->f_flag & FREAD) == 0) 180554620Smckusick return (EBADF); 180654620Smckusick vp = (struct vnode *)fp->f_data; 180754620Smckusick if (vp->v_type != VDIR) 180854620Smckusick return (EINVAL); 180954620Smckusick aiov.iov_base = uap->buf; 181054620Smckusick aiov.iov_len = uap->count; 181154620Smckusick auio.uio_iov = &aiov; 181254620Smckusick auio.uio_iovcnt = 1; 181354620Smckusick auio.uio_rw = UIO_READ; 181454620Smckusick auio.uio_segflg = UIO_USERSPACE; 181554620Smckusick auio.uio_procp = p; 181654620Smckusick auio.uio_resid = uap->count; 181754620Smckusick VOP_LOCK(vp); 181854969Smckusick loff = auio.uio_offset = fp->f_offset; 181954620Smckusick # if (BYTE_ORDER != LITTLE_ENDIAN) 182056339Smckusick if (vp->v_mount->mnt_maxsymlinklen <= 0) { 182154620Smckusick error = VOP_READDIR(vp, &auio, fp->f_cred); 182256339Smckusick fp->f_offset = auio.uio_offset; 182356339Smckusick } else 182454620Smckusick # endif 182554620Smckusick { 182654620Smckusick kuio = auio; 182754620Smckusick kuio.uio_iov = &kiov; 182854620Smckusick kuio.uio_segflg = UIO_SYSSPACE; 182954620Smckusick kiov.iov_len = uap->count; 183054620Smckusick MALLOC(dirbuf, caddr_t, uap->count, M_TEMP, M_WAITOK); 183154620Smckusick kiov.iov_base = dirbuf; 183254620Smckusick error = VOP_READDIR(vp, &kuio, fp->f_cred); 183356339Smckusick fp->f_offset = kuio.uio_offset; 183454620Smckusick if (error == 0) { 183554620Smckusick readcnt = uap->count - kuio.uio_resid; 183654620Smckusick edp = (struct dirent *)&dirbuf[readcnt]; 183754620Smckusick for (dp = (struct dirent *)dirbuf; dp < edp; ) { 183854620Smckusick # if (BYTE_ORDER == LITTLE_ENDIAN) 183954969Smckusick /* 184055009Smckusick * The expected low byte of 184155009Smckusick * dp->d_namlen is our dp->d_type. 184255009Smckusick * The high MBZ byte of dp->d_namlen 184355009Smckusick * is our dp->d_namlen. 184454969Smckusick */ 184555009Smckusick dp->d_type = dp->d_namlen; 184655009Smckusick dp->d_namlen = 0; 184755009Smckusick # else 184855009Smckusick /* 184955009Smckusick * The dp->d_type is the high byte 185055009Smckusick * of the expected dp->d_namlen, 185155009Smckusick * so must be zero'ed. 185255009Smckusick */ 185355009Smckusick dp->d_type = 0; 185454620Smckusick # endif 185554620Smckusick if (dp->d_reclen > 0) { 185654620Smckusick dp = (struct dirent *) 185754620Smckusick ((char *)dp + dp->d_reclen); 185854620Smckusick } else { 185954620Smckusick error = EIO; 186054620Smckusick break; 186154620Smckusick } 186254620Smckusick } 186354620Smckusick if (dp >= edp) 186454620Smckusick error = uiomove(dirbuf, readcnt, &auio); 186554620Smckusick } 186654620Smckusick FREE(dirbuf, M_TEMP); 186754620Smckusick } 186854620Smckusick VOP_UNLOCK(vp); 186954620Smckusick if (error) 187054620Smckusick return (error); 187154969Smckusick error = copyout((caddr_t)&loff, (caddr_t)uap->basep, sizeof(long)); 187254620Smckusick *retval = uap->count - auio.uio_resid; 187354620Smckusick return (error); 187454620Smckusick } 187554620Smckusick #endif 187654620Smckusick 187754620Smckusick /* 187854620Smckusick * Read a block of directory entries in a file system independent format. 187954620Smckusick */ 188054916Storek struct getdirentries_args { 188154916Storek int fd; 188254916Storek char *buf; 188354916Storek unsigned count; 188454916Storek long *basep; 188554916Storek }; 188642441Smckusick getdirentries(p, uap, retval) 188745914Smckusick struct proc *p; 188854916Storek register struct getdirentries_args *uap; 188942441Smckusick int *retval; 189042441Smckusick { 189139592Smckusick register struct vnode *vp; 189216540Ssam struct file *fp; 189337741Smckusick struct uio auio; 189437741Smckusick struct iovec aiov; 189554969Smckusick long loff; 189654441Smckusick int error; 189712756Ssam 189845914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 189947540Skarels return (error); 190037741Smckusick if ((fp->f_flag & FREAD) == 0) 190147540Skarels return (EBADF); 190239592Smckusick vp = (struct vnode *)fp->f_data; 190355451Spendry unionread: 190439592Smckusick if (vp->v_type != VDIR) 190547540Skarels return (EINVAL); 190637741Smckusick aiov.iov_base = uap->buf; 190737741Smckusick aiov.iov_len = uap->count; 190837741Smckusick auio.uio_iov = &aiov; 190937741Smckusick auio.uio_iovcnt = 1; 191037741Smckusick auio.uio_rw = UIO_READ; 191137741Smckusick auio.uio_segflg = UIO_USERSPACE; 191248026Smckusick auio.uio_procp = p; 191337741Smckusick auio.uio_resid = uap->count; 191439592Smckusick VOP_LOCK(vp); 191554969Smckusick loff = auio.uio_offset = fp->f_offset; 191654441Smckusick error = VOP_READDIR(vp, &auio, fp->f_cred); 191739592Smckusick fp->f_offset = auio.uio_offset; 191839592Smckusick VOP_UNLOCK(vp); 191939592Smckusick if (error) 192047540Skarels return (error); 192155451Spendry if ((uap->count == auio.uio_resid) && 192255451Spendry (vp->v_flag & VROOT) && 192355451Spendry (vp->v_mount->mnt_flag & MNT_UNION)) { 192455451Spendry struct vnode *tvp = vp; 192555451Spendry vp = vp->v_mount->mnt_vnodecovered; 192655451Spendry VREF(vp); 192755451Spendry fp->f_data = (caddr_t) vp; 192855451Spendry fp->f_offset = 0; 192955451Spendry vrele(tvp); 193055451Spendry goto unionread; 193155451Spendry } 193254969Smckusick error = copyout((caddr_t)&loff, (caddr_t)uap->basep, sizeof(long)); 193342441Smckusick *retval = uap->count - auio.uio_resid; 193447540Skarels return (error); 193512756Ssam } 193612756Ssam 193712756Ssam /* 193849365Smckusick * Set the mode mask for creation of filesystem nodes. 193912756Ssam */ 194054916Storek struct umask_args { 194154916Storek int mask; 194254916Storek }; 194354916Storek mode_t /* XXX */ 194442441Smckusick umask(p, uap, retval) 194545914Smckusick struct proc *p; 194654916Storek struct umask_args *uap; 194742441Smckusick int *retval; 194812756Ssam { 194945914Smckusick register struct filedesc *fdp = p->p_fd; 195012756Ssam 195145914Smckusick *retval = fdp->fd_cmask; 195245914Smckusick fdp->fd_cmask = uap->mask & 07777; 195347540Skarels return (0); 195412756Ssam } 195537741Smckusick 195639566Smarc /* 195739566Smarc * Void all references to file by ripping underlying filesystem 195839566Smarc * away from vnode. 195939566Smarc */ 196054916Storek struct revoke_args { 196154916Storek char *fname; 196254916Storek }; 196342441Smckusick /* ARGSUSED */ 196442441Smckusick revoke(p, uap, retval) 196545914Smckusick struct proc *p; 196654916Storek register struct revoke_args *uap; 196742441Smckusick int *retval; 196842441Smckusick { 196939566Smarc register struct vnode *vp; 197039566Smarc struct vattr vattr; 197139566Smarc int error; 197247540Skarels struct nameidata nd; 197339566Smarc 197452322Smckusick NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->fname, p); 197552322Smckusick if (error = namei(&nd)) 197647540Skarels return (error); 197752322Smckusick vp = nd.ni_vp; 197839566Smarc if (vp->v_type != VCHR && vp->v_type != VBLK) { 197939566Smarc error = EINVAL; 198039566Smarc goto out; 198139566Smarc } 198248026Smckusick if (error = VOP_GETATTR(vp, &vattr, p->p_ucred, p)) 198339566Smarc goto out; 198447540Skarels if (p->p_ucred->cr_uid != vattr.va_uid && 198547540Skarels (error = suser(p->p_ucred, &p->p_acflag))) 198639566Smarc goto out; 198739805Smckusick if (vp->v_usecount > 1 || (vp->v_flag & VALIASED)) 198839632Smckusick vgoneall(vp); 198939566Smarc out: 199039566Smarc vrele(vp); 199147540Skarels return (error); 199239566Smarc } 199339566Smarc 199449365Smckusick /* 199549365Smckusick * Convert a user file descriptor to a kernel file entry. 199649365Smckusick */ 199745914Smckusick getvnode(fdp, fdes, fpp) 199845914Smckusick struct filedesc *fdp; 199937741Smckusick struct file **fpp; 200037741Smckusick int fdes; 200137741Smckusick { 200237741Smckusick struct file *fp; 200337741Smckusick 200447540Skarels if ((unsigned)fdes >= fdp->fd_nfiles || 200547688Skarels (fp = fdp->fd_ofiles[fdes]) == NULL) 200637741Smckusick return (EBADF); 200737741Smckusick if (fp->f_type != DTYPE_VNODE) 200837741Smckusick return (EINVAL); 200937741Smckusick *fpp = fp; 201037741Smckusick return (0); 201137741Smckusick } 2012