123405Smckusick /* 237741Smckusick * Copyright (c) 1989 The Regents of the University of California. 337741Smckusick * All rights reserved. 423405Smckusick * 544459Sbostic * %sccs.include.redist.c% 637741Smckusick * 7*59382Smckusick * @(#)vfs_syscalls.c 7.107 (Berkeley) 04/27/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 846*59382Smckusick NDINIT(&nd, DELETE, LOCKPARENT, UIO_USERSPACE, uap->name, p); 84752322Smckusick if (error = namei(&nd)) 84847540Skarels return (error); 84952322Smckusick vp = nd.ni_vp; 850*59382Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 851*59382Smckusick VOP_LOCK(vp); 85237741Smckusick if (vp->v_type == VDIR && 85347540Skarels (error = suser(p->p_ucred, &p->p_acflag))) 8546254Sroot goto out; 8556254Sroot /* 85649365Smckusick * The root of a mounted filesystem cannot be deleted. 8576254Sroot */ 85837741Smckusick if (vp->v_flag & VROOT) { 85937741Smckusick error = EBUSY; 8606254Sroot goto out; 8616254Sroot } 86245738Smckusick (void) vnode_pager_uncache(vp); 8636254Sroot out: 86442465Smckusick if (!error) { 86552322Smckusick LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 86652322Smckusick error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); 86742465Smckusick } else { 86852322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 86952322Smckusick if (nd.ni_dvp == vp) 87052322Smckusick vrele(nd.ni_dvp); 87143344Smckusick else 87252322Smckusick vput(nd.ni_dvp); 87342465Smckusick vput(vp); 87442465Smckusick } 87547540Skarels return (error); 8766254Sroot } 8776254Sroot 87854916Storek struct __lseek_args { 87954863Storek int fdes; 88054863Storek int pad; 88154863Storek off_t off; 88254863Storek int sbase; 88354863Storek }; 88454863Storek 88554348Smckusick #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 8866254Sroot /* 88749365Smckusick * Seek system call. 8886254Sroot */ 88954916Storek struct lseek_args { 89054916Storek int fdes; 89154916Storek long off; 89254916Storek int sbase; 89354916Storek }; 89442441Smckusick lseek(p, uap, retval) 89545914Smckusick struct proc *p; 89654916Storek register struct lseek_args *uap; 89754916Storek int *retval; 89853468Smckusick { 89954916Storek struct __lseek_args nuap; 90054863Storek off_t qret; 90153468Smckusick int error; 90253468Smckusick 90353468Smckusick nuap.fdes = uap->fdes; 90453468Smckusick nuap.off = uap->off; 90553468Smckusick nuap.sbase = uap->sbase; 90653759Smckusick error = __lseek(p, &nuap, &qret); 90754916Storek *(long *)retval = qret; 90853468Smckusick return (error); 90953468Smckusick } 91054348Smckusick #endif /* COMPAT_43 || COMPAT_SUNOS */ 91153468Smckusick 91253468Smckusick /* 91353468Smckusick * Seek system call. 91453468Smckusick */ 91553759Smckusick __lseek(p, uap, retval) 91653468Smckusick struct proc *p; 91754916Storek register struct __lseek_args *uap; 91854916Storek int *retval; 91942441Smckusick { 92047540Skarels struct ucred *cred = p->p_ucred; 92145914Smckusick register struct filedesc *fdp = p->p_fd; 92242441Smckusick register struct file *fp; 92337741Smckusick struct vattr vattr; 92437741Smckusick int error; 9256254Sroot 92647540Skarels if ((unsigned)uap->fdes >= fdp->fd_nfiles || 92747688Skarels (fp = fdp->fd_ofiles[uap->fdes]) == NULL) 92847540Skarels return (EBADF); 92937741Smckusick if (fp->f_type != DTYPE_VNODE) 93047540Skarels return (ESPIPE); 93113878Ssam switch (uap->sbase) { 93213878Ssam 93313878Ssam case L_INCR: 93413878Ssam fp->f_offset += uap->off; 93513878Ssam break; 93613878Ssam 93713878Ssam case L_XTND: 93837741Smckusick if (error = VOP_GETATTR((struct vnode *)fp->f_data, 93948026Smckusick &vattr, cred, p)) 94047540Skarels return (error); 94137741Smckusick fp->f_offset = uap->off + vattr.va_size; 94213878Ssam break; 94313878Ssam 94413878Ssam case L_SET: 94513878Ssam fp->f_offset = uap->off; 94613878Ssam break; 94713878Ssam 94813878Ssam default: 94947540Skarels return (EINVAL); 95013878Ssam } 95154916Storek *(off_t *)retval = fp->f_offset; 95247540Skarels return (0); 9536254Sroot } 9546254Sroot 9556254Sroot /* 95649365Smckusick * Check access permissions. 9576254Sroot */ 95854916Storek struct saccess_args { 95954916Storek char *fname; 96054916Storek int fmode; 96154916Storek }; 96242441Smckusick /* ARGSUSED */ 96342441Smckusick saccess(p, uap, retval) 96445914Smckusick struct proc *p; 96554916Storek register struct saccess_args *uap; 96642441Smckusick int *retval; 96742441Smckusick { 96847540Skarels register struct ucred *cred = p->p_ucred; 96937741Smckusick register struct vnode *vp; 97037741Smckusick int error, mode, svuid, svgid; 97147540Skarels struct nameidata nd; 9726254Sroot 97342441Smckusick svuid = cred->cr_uid; 97442441Smckusick svgid = cred->cr_groups[0]; 97547540Skarels cred->cr_uid = p->p_cred->p_ruid; 97647540Skarels cred->cr_groups[0] = p->p_cred->p_rgid; 97752322Smckusick NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 97852322Smckusick if (error = namei(&nd)) 97937741Smckusick goto out1; 98052322Smckusick vp = nd.ni_vp; 98137741Smckusick /* 98237741Smckusick * fmode == 0 means only check for exist 98337741Smckusick */ 98437741Smckusick if (uap->fmode) { 98537741Smckusick mode = 0; 98637741Smckusick if (uap->fmode & R_OK) 98737741Smckusick mode |= VREAD; 98837741Smckusick if (uap->fmode & W_OK) 98937741Smckusick mode |= VWRITE; 99037741Smckusick if (uap->fmode & X_OK) 99137741Smckusick mode |= VEXEC; 99239543Smckusick if ((mode & VWRITE) == 0 || (error = vn_writechk(vp)) == 0) 99348026Smckusick error = VOP_ACCESS(vp, mode, cred, p); 9946254Sroot } 99537741Smckusick vput(vp); 99637741Smckusick out1: 99742441Smckusick cred->cr_uid = svuid; 99842441Smckusick cred->cr_groups[0] = svgid; 99947540Skarels return (error); 10006254Sroot } 10016254Sroot 100254348Smckusick #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 10036254Sroot /* 100449365Smckusick * Stat system call. 100549365Smckusick * This version follows links. 100637Sbill */ 100754916Storek struct ostat_args { 100854916Storek char *fname; 100954916Storek struct ostat *ub; 101054916Storek }; 101142441Smckusick /* ARGSUSED */ 101253759Smckusick ostat(p, uap, retval) 101345914Smckusick struct proc *p; 101454916Storek register struct ostat_args *uap; 101553468Smckusick int *retval; 101653468Smckusick { 101753468Smckusick struct stat sb; 101853468Smckusick struct ostat osb; 101953468Smckusick int error; 102053468Smckusick struct nameidata nd; 102153468Smckusick 102253468Smckusick NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 102353468Smckusick if (error = namei(&nd)) 102453468Smckusick return (error); 102553468Smckusick error = vn_stat(nd.ni_vp, &sb, p); 102653468Smckusick vput(nd.ni_vp); 102753468Smckusick if (error) 102853468Smckusick return (error); 102953468Smckusick cvtstat(&sb, &osb); 103053468Smckusick error = copyout((caddr_t)&osb, (caddr_t)uap->ub, sizeof (osb)); 103153468Smckusick return (error); 103253468Smckusick } 103353468Smckusick 103453468Smckusick /* 103553468Smckusick * Lstat system call. 103653468Smckusick * This version does not follow links. 103753468Smckusick */ 103854916Storek struct olstat_args { 103954916Storek char *fname; 104054916Storek struct ostat *ub; 104154916Storek }; 104253468Smckusick /* ARGSUSED */ 104353759Smckusick olstat(p, uap, retval) 104453468Smckusick struct proc *p; 104554916Storek register struct olstat_args *uap; 104653468Smckusick int *retval; 104753468Smckusick { 104853468Smckusick struct stat sb; 104953468Smckusick struct ostat osb; 105053468Smckusick int error; 105153468Smckusick struct nameidata nd; 105253468Smckusick 105353468Smckusick NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 105453468Smckusick if (error = namei(&nd)) 105553468Smckusick return (error); 105653468Smckusick error = vn_stat(nd.ni_vp, &sb, p); 105753468Smckusick vput(nd.ni_vp); 105853468Smckusick if (error) 105953468Smckusick return (error); 106053468Smckusick cvtstat(&sb, &osb); 106153468Smckusick error = copyout((caddr_t)&osb, (caddr_t)uap->ub, sizeof (osb)); 106253468Smckusick return (error); 106353468Smckusick } 106453468Smckusick 106553468Smckusick /* 106653468Smckusick * convert from an old to a new stat structure. 106753468Smckusick */ 106853468Smckusick cvtstat(st, ost) 106953468Smckusick struct stat *st; 107053468Smckusick struct ostat *ost; 107153468Smckusick { 107253468Smckusick 107353468Smckusick ost->st_dev = st->st_dev; 107453468Smckusick ost->st_ino = st->st_ino; 107553468Smckusick ost->st_mode = st->st_mode; 107653468Smckusick ost->st_nlink = st->st_nlink; 107753468Smckusick ost->st_uid = st->st_uid; 107853468Smckusick ost->st_gid = st->st_gid; 107953468Smckusick ost->st_rdev = st->st_rdev; 108053468Smckusick if (st->st_size < (quad_t)1 << 32) 108153468Smckusick ost->st_size = st->st_size; 108253468Smckusick else 108353468Smckusick ost->st_size = -2; 108453468Smckusick ost->st_atime = st->st_atime; 108553468Smckusick ost->st_mtime = st->st_mtime; 108653468Smckusick ost->st_ctime = st->st_ctime; 108753468Smckusick ost->st_blksize = st->st_blksize; 108853468Smckusick ost->st_blocks = st->st_blocks; 108953468Smckusick ost->st_flags = st->st_flags; 109053468Smckusick ost->st_gen = st->st_gen; 109153468Smckusick } 109254348Smckusick #endif /* COMPAT_43 || COMPAT_SUNOS */ 109353468Smckusick 109453468Smckusick /* 109553468Smckusick * Stat system call. 109653468Smckusick * This version follows links. 109753468Smckusick */ 109854916Storek struct stat_args { 109954916Storek char *fname; 110054916Storek struct stat *ub; 110154916Storek }; 110253468Smckusick /* ARGSUSED */ 110353759Smckusick stat(p, uap, retval) 110453468Smckusick struct proc *p; 110554916Storek register struct stat_args *uap; 110642441Smckusick int *retval; 110737Sbill { 110842441Smckusick struct stat sb; 110942441Smckusick int error; 111047540Skarels struct nameidata nd; 111137Sbill 111252322Smckusick NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 111352322Smckusick if (error = namei(&nd)) 111447540Skarels return (error); 111552322Smckusick error = vn_stat(nd.ni_vp, &sb, p); 111652322Smckusick vput(nd.ni_vp); 111742441Smckusick if (error) 111847540Skarels return (error); 111942441Smckusick error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb)); 112047540Skarels return (error); 112137Sbill } 112237Sbill 112337Sbill /* 112449365Smckusick * Lstat system call. 112549365Smckusick * This version does not follow links. 11265992Swnj */ 112754916Storek struct lstat_args { 112854916Storek char *fname; 112954916Storek struct stat *ub; 113054916Storek }; 113142441Smckusick /* ARGSUSED */ 113253759Smckusick lstat(p, uap, retval) 113345914Smckusick struct proc *p; 113454916Storek register struct lstat_args *uap; 113542441Smckusick int *retval; 113642441Smckusick { 113737741Smckusick int error; 113859373Smckusick struct vnode *vp, *dvp; 113959373Smckusick struct stat sb, sb1; 114047540Skarels struct nameidata nd; 11415992Swnj 114259373Smckusick NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | LOCKPARENT, UIO_USERSPACE, 114359373Smckusick uap->fname, p); 114452322Smckusick if (error = namei(&nd)) 114547540Skarels return (error); 114659373Smckusick /* 114759373Smckusick * For symbolic links, always return the attributes of its 114859373Smckusick * containing directory, except for mode, size, and links. 114959373Smckusick */ 115059373Smckusick vp = nd.ni_vp; 115159373Smckusick dvp = nd.ni_dvp; 115259373Smckusick if (vp->v_type != VLNK) { 115359373Smckusick if (dvp == vp) 115459373Smckusick vrele(dvp); 115559373Smckusick else 115659373Smckusick vput(dvp); 115759373Smckusick error = vn_stat(vp, &sb, p); 115859373Smckusick vput(vp); 115959373Smckusick if (error) 116059373Smckusick return (error); 116159373Smckusick } else { 116259373Smckusick error = vn_stat(dvp, &sb, p); 116359373Smckusick vput(dvp); 116459373Smckusick if (error) { 116559373Smckusick vput(vp); 116659373Smckusick return (error); 116759373Smckusick } 116859373Smckusick error = vn_stat(vp, &sb1, p); 116959373Smckusick vput(vp); 117059373Smckusick if (error) 117159373Smckusick return (error); 117259373Smckusick sb.st_mode &= ~S_IFDIR; 117359373Smckusick sb.st_mode |= S_IFLNK; 117459373Smckusick sb.st_nlink = sb1.st_nlink; 117559373Smckusick sb.st_size = sb1.st_size; 117659373Smckusick sb.st_blocks = sb1.st_blocks; 117759373Smckusick } 117837741Smckusick error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb)); 117947540Skarels return (error); 11805992Swnj } 11815992Swnj 11825992Swnj /* 118349365Smckusick * Return target name of a symbolic link. 118437Sbill */ 118554916Storek struct readlink_args { 118654916Storek char *name; 118754916Storek char *buf; 118854916Storek int count; 118954916Storek }; 119042441Smckusick /* ARGSUSED */ 119142441Smckusick readlink(p, uap, retval) 119245914Smckusick struct proc *p; 119354916Storek register struct readlink_args *uap; 119442441Smckusick int *retval; 119542441Smckusick { 119637741Smckusick register struct vnode *vp; 119737741Smckusick struct iovec aiov; 119837741Smckusick struct uio auio; 119937741Smckusick int error; 120047540Skarels struct nameidata nd; 12015992Swnj 120252322Smckusick NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, uap->name, p); 120352322Smckusick if (error = namei(&nd)) 120447540Skarels return (error); 120552322Smckusick vp = nd.ni_vp; 120637741Smckusick if (vp->v_type != VLNK) { 120737741Smckusick error = EINVAL; 12085992Swnj goto out; 12095992Swnj } 121037741Smckusick aiov.iov_base = uap->buf; 121137741Smckusick aiov.iov_len = uap->count; 121237741Smckusick auio.uio_iov = &aiov; 121337741Smckusick auio.uio_iovcnt = 1; 121437741Smckusick auio.uio_offset = 0; 121537741Smckusick auio.uio_rw = UIO_READ; 121637741Smckusick auio.uio_segflg = UIO_USERSPACE; 121748026Smckusick auio.uio_procp = p; 121837741Smckusick auio.uio_resid = uap->count; 121947540Skarels error = VOP_READLINK(vp, &auio, p->p_ucred); 12205992Swnj out: 122137741Smckusick vput(vp); 122242441Smckusick *retval = uap->count - auio.uio_resid; 122347540Skarels return (error); 12245992Swnj } 12255992Swnj 12269167Ssam /* 122738259Smckusick * Change flags of a file given path name. 122838259Smckusick */ 122954916Storek struct chflags_args { 123054916Storek char *fname; 123154916Storek int flags; 123254916Storek }; 123342441Smckusick /* ARGSUSED */ 123442441Smckusick chflags(p, uap, retval) 123545914Smckusick struct proc *p; 123654916Storek register struct chflags_args *uap; 123742441Smckusick int *retval; 123842441Smckusick { 123938259Smckusick register struct vnode *vp; 124038259Smckusick struct vattr vattr; 124138259Smckusick int error; 124247540Skarels struct nameidata nd; 124338259Smckusick 1244*59382Smckusick NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->fname, p); 124552322Smckusick if (error = namei(&nd)) 124647540Skarels return (error); 124752322Smckusick vp = nd.ni_vp; 1248*59382Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 1249*59382Smckusick VOP_LOCK(vp); 125041400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 125138259Smckusick error = EROFS; 125238259Smckusick goto out; 125338259Smckusick } 125445785Sbostic VATTR_NULL(&vattr); 125545785Sbostic vattr.va_flags = uap->flags; 125648026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 125738259Smckusick out: 125838259Smckusick vput(vp); 125947540Skarels return (error); 126038259Smckusick } 126138259Smckusick 126238259Smckusick /* 126338259Smckusick * Change flags of a file given a file descriptor. 126438259Smckusick */ 126554916Storek struct fchflags_args { 126654916Storek int fd; 126754916Storek int flags; 126854916Storek }; 126942441Smckusick /* ARGSUSED */ 127042441Smckusick fchflags(p, uap, retval) 127145914Smckusick struct proc *p; 127254916Storek register struct fchflags_args *uap; 127342441Smckusick int *retval; 127442441Smckusick { 127538259Smckusick struct vattr vattr; 127638259Smckusick struct vnode *vp; 127738259Smckusick struct file *fp; 127838259Smckusick int error; 127938259Smckusick 128045914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 128147540Skarels return (error); 128238259Smckusick vp = (struct vnode *)fp->f_data; 1283*59382Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 128438259Smckusick VOP_LOCK(vp); 128541400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 128638259Smckusick error = EROFS; 128738259Smckusick goto out; 128838259Smckusick } 128945785Sbostic VATTR_NULL(&vattr); 129045785Sbostic vattr.va_flags = uap->flags; 129148026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 129238259Smckusick out: 129338259Smckusick VOP_UNLOCK(vp); 129447540Skarels return (error); 129538259Smckusick } 129638259Smckusick 129738259Smckusick /* 12989167Ssam * Change mode of a file given path name. 12999167Ssam */ 130054916Storek struct chmod_args { 130154916Storek char *fname; 130254916Storek int fmode; 130354916Storek }; 130442441Smckusick /* ARGSUSED */ 130542441Smckusick chmod(p, uap, retval) 130645914Smckusick struct proc *p; 130754916Storek register struct chmod_args *uap; 130842441Smckusick int *retval; 130942441Smckusick { 131037741Smckusick register struct vnode *vp; 131137741Smckusick struct vattr vattr; 131237741Smckusick int error; 131347540Skarels struct nameidata nd; 13145992Swnj 1315*59382Smckusick NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->fname, p); 131652322Smckusick if (error = namei(&nd)) 131747540Skarels return (error); 131852322Smckusick vp = nd.ni_vp; 1319*59382Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 1320*59382Smckusick VOP_LOCK(vp); 132141400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 132237741Smckusick error = EROFS; 132337741Smckusick goto out; 132437741Smckusick } 132545785Sbostic VATTR_NULL(&vattr); 132645785Sbostic vattr.va_mode = uap->fmode & 07777; 132748026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 132837741Smckusick out: 132937741Smckusick vput(vp); 133047540Skarels return (error); 13317701Ssam } 13327439Sroot 13339167Ssam /* 13349167Ssam * Change mode of a file given a file descriptor. 13359167Ssam */ 133654916Storek struct fchmod_args { 133754916Storek int fd; 133854916Storek int fmode; 133954916Storek }; 134042441Smckusick /* ARGSUSED */ 134142441Smckusick fchmod(p, uap, retval) 134245914Smckusick struct proc *p; 134354916Storek register struct fchmod_args *uap; 134442441Smckusick int *retval; 134542441Smckusick { 134637741Smckusick struct vattr vattr; 134737741Smckusick struct vnode *vp; 134837741Smckusick struct file *fp; 134937741Smckusick int error; 13507701Ssam 135145914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 135247540Skarels return (error); 135337741Smckusick vp = (struct vnode *)fp->f_data; 1354*59382Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 135537741Smckusick VOP_LOCK(vp); 135641400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 135737741Smckusick error = EROFS; 135837741Smckusick goto out; 13597439Sroot } 136045785Sbostic VATTR_NULL(&vattr); 136145785Sbostic vattr.va_mode = uap->fmode & 07777; 136248026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 136337741Smckusick out: 136437741Smckusick VOP_UNLOCK(vp); 136547540Skarels return (error); 13665992Swnj } 13675992Swnj 13689167Ssam /* 13699167Ssam * Set ownership given a path name. 13709167Ssam */ 137154916Storek struct chown_args { 137254916Storek char *fname; 137354916Storek int uid; 137454916Storek int gid; 137554916Storek }; 137642441Smckusick /* ARGSUSED */ 137742441Smckusick chown(p, uap, retval) 137845914Smckusick struct proc *p; 137954916Storek register struct chown_args *uap; 138042441Smckusick int *retval; 138142441Smckusick { 138237741Smckusick register struct vnode *vp; 138337741Smckusick struct vattr vattr; 138437741Smckusick int error; 138547540Skarels struct nameidata nd; 138637Sbill 1387*59382Smckusick NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, uap->fname, p); 138852322Smckusick if (error = namei(&nd)) 138947540Skarels return (error); 139052322Smckusick vp = nd.ni_vp; 1391*59382Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 1392*59382Smckusick VOP_LOCK(vp); 139341400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 139437741Smckusick error = EROFS; 139537741Smckusick goto out; 139637741Smckusick } 139745785Sbostic VATTR_NULL(&vattr); 139845785Sbostic vattr.va_uid = uap->uid; 139945785Sbostic vattr.va_gid = uap->gid; 140048026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 140137741Smckusick out: 140237741Smckusick vput(vp); 140347540Skarels return (error); 14047701Ssam } 14057439Sroot 14069167Ssam /* 14079167Ssam * Set ownership given a file descriptor. 14089167Ssam */ 140954916Storek struct fchown_args { 141054916Storek int fd; 141154916Storek int uid; 141254916Storek int gid; 141354916Storek }; 141442441Smckusick /* ARGSUSED */ 141542441Smckusick fchown(p, uap, retval) 141645914Smckusick struct proc *p; 141754916Storek register struct fchown_args *uap; 141842441Smckusick int *retval; 141942441Smckusick { 142037741Smckusick struct vattr vattr; 142137741Smckusick struct vnode *vp; 142237741Smckusick struct file *fp; 142337741Smckusick int error; 14247701Ssam 142545914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 142647540Skarels return (error); 142737741Smckusick vp = (struct vnode *)fp->f_data; 1428*59382Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 142937741Smckusick VOP_LOCK(vp); 143041400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 143137741Smckusick error = EROFS; 143237741Smckusick goto out; 143337741Smckusick } 143445785Sbostic VATTR_NULL(&vattr); 143545785Sbostic vattr.va_uid = uap->uid; 143645785Sbostic vattr.va_gid = uap->gid; 143748026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 143837741Smckusick out: 143937741Smckusick VOP_UNLOCK(vp); 144047540Skarels return (error); 14417701Ssam } 14427701Ssam 144342441Smckusick /* 144442441Smckusick * Set the access and modification times of a file. 144542441Smckusick */ 144654916Storek struct utimes_args { 144754916Storek char *fname; 144854916Storek struct timeval *tptr; 144954916Storek }; 145042441Smckusick /* ARGSUSED */ 145142441Smckusick utimes(p, uap, retval) 145245914Smckusick struct proc *p; 145354916Storek register struct utimes_args *uap; 145442441Smckusick int *retval; 145542441Smckusick { 145637741Smckusick register struct vnode *vp; 145711811Ssam struct timeval tv[2]; 145837741Smckusick struct vattr vattr; 145958840Storek int error; 146047540Skarels struct nameidata nd; 146111811Ssam 146258505Sbostic VATTR_NULL(&vattr); 146358505Sbostic if (uap->tptr == NULL) { 146458505Sbostic microtime(&tv[0]); 146558505Sbostic tv[1] = tv[0]; 146658548Sbostic vattr.va_vaflags |= VA_UTIMES_NULL; 146758505Sbostic } else if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv))) 146858505Sbostic return (error); 1469*59382Smckusick NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->fname, p); 147052322Smckusick if (error = namei(&nd)) 147147540Skarels return (error); 147252322Smckusick vp = nd.ni_vp; 1473*59382Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 1474*59382Smckusick VOP_LOCK(vp); 147541400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 147637741Smckusick error = EROFS; 147737741Smckusick goto out; 147821015Smckusick } 147954100Smckusick vattr.va_atime.ts_sec = tv[0].tv_sec; 148054100Smckusick vattr.va_atime.ts_nsec = tv[0].tv_usec * 1000; 148154100Smckusick vattr.va_mtime.ts_sec = tv[1].tv_sec; 148254100Smckusick vattr.va_mtime.ts_nsec = tv[1].tv_usec * 1000; 148348026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 148437741Smckusick out: 148537741Smckusick vput(vp); 148647540Skarels return (error); 148711811Ssam } 148811811Ssam 148954916Storek struct __truncate_args { 149054863Storek char *fname; 149154863Storek int pad; 149254863Storek off_t length; 149354863Storek }; 149453468Smckusick 149553468Smckusick /* 149653468Smckusick * Truncate a file given its path name. 149753468Smckusick */ 149853468Smckusick /* ARGSUSED */ 149953759Smckusick __truncate(p, uap, retval) 150053468Smckusick struct proc *p; 150154916Storek register struct __truncate_args *uap; 150253468Smckusick int *retval; 150353468Smckusick { 150437741Smckusick register struct vnode *vp; 150537741Smckusick struct vattr vattr; 150637741Smckusick int error; 150747540Skarels struct nameidata nd; 15087701Ssam 1509*59382Smckusick NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->fname, p); 151052322Smckusick if (error = namei(&nd)) 151147540Skarels return (error); 151252322Smckusick vp = nd.ni_vp; 1513*59382Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 1514*59382Smckusick VOP_LOCK(vp); 151537741Smckusick if (vp->v_type == VDIR) { 151637741Smckusick error = EISDIR; 151737741Smckusick goto out; 15187701Ssam } 151938399Smckusick if ((error = vn_writechk(vp)) || 152048026Smckusick (error = VOP_ACCESS(vp, VWRITE, p->p_ucred, p))) 152137741Smckusick goto out; 152245785Sbostic VATTR_NULL(&vattr); 152345785Sbostic vattr.va_size = uap->length; 152448026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 152537741Smckusick out: 152637741Smckusick vput(vp); 152747540Skarels return (error); 15287701Ssam } 15297701Ssam 153054916Storek struct __ftruncate_args { 153154863Storek int fd; 153254863Storek int pad; 153354863Storek off_t length; 153454863Storek }; 153554863Storek 15369167Ssam /* 15379167Ssam * Truncate a file given a file descriptor. 15389167Ssam */ 153942441Smckusick /* ARGSUSED */ 154053759Smckusick __ftruncate(p, uap, retval) 154145914Smckusick struct proc *p; 154254916Storek register struct __ftruncate_args *uap; 154342441Smckusick int *retval; 154442441Smckusick { 154537741Smckusick struct vattr vattr; 154637741Smckusick struct vnode *vp; 15477701Ssam struct file *fp; 154837741Smckusick int error; 15497701Ssam 155045914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 155147540Skarels return (error); 155237741Smckusick if ((fp->f_flag & FWRITE) == 0) 155347540Skarels return (EINVAL); 155437741Smckusick vp = (struct vnode *)fp->f_data; 1555*59382Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 155637741Smckusick VOP_LOCK(vp); 155737741Smckusick if (vp->v_type == VDIR) { 155837741Smckusick error = EISDIR; 155937741Smckusick goto out; 15607701Ssam } 156138399Smckusick if (error = vn_writechk(vp)) 156237741Smckusick goto out; 156345785Sbostic VATTR_NULL(&vattr); 156445785Sbostic vattr.va_size = uap->length; 156548026Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred, p); 156637741Smckusick out: 156737741Smckusick VOP_UNLOCK(vp); 156847540Skarels return (error); 15697701Ssam } 15707701Ssam 157154863Storek #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 15729167Ssam /* 157354863Storek * Truncate a file given its path name. 157454863Storek */ 157554916Storek struct truncate_args { 157654916Storek char *fname; 157754916Storek long length; 157854916Storek }; 157954863Storek /* ARGSUSED */ 158054863Storek truncate(p, uap, retval) 158154863Storek struct proc *p; 158254916Storek register struct truncate_args *uap; 158354863Storek int *retval; 158454863Storek { 158554916Storek struct __truncate_args nuap; 158654863Storek 158754863Storek nuap.fname = uap->fname; 158854863Storek nuap.length = uap->length; 158954863Storek return (__truncate(p, &nuap, retval)); 159054863Storek } 159154863Storek 159254863Storek /* 159354863Storek * Truncate a file given a file descriptor. 159454863Storek */ 159554916Storek struct ftruncate_args { 159654916Storek int fd; 159754916Storek long length; 159854916Storek }; 159954863Storek /* ARGSUSED */ 160054863Storek ftruncate(p, uap, retval) 160154863Storek struct proc *p; 160254916Storek register struct ftruncate_args *uap; 160354863Storek int *retval; 160454863Storek { 160554969Smckusick struct __ftruncate_args nuap; 160654863Storek 160754863Storek nuap.fd = uap->fd; 160854863Storek nuap.length = uap->length; 160954863Storek return (__ftruncate(p, &nuap, retval)); 161054863Storek } 161154863Storek #endif /* COMPAT_43 || COMPAT_SUNOS */ 161254863Storek 161354863Storek /* 16149167Ssam * Synch an open file. 16159167Ssam */ 161654916Storek struct fsync_args { 161754916Storek int fd; 161854916Storek }; 161942441Smckusick /* ARGSUSED */ 162042441Smckusick fsync(p, uap, retval) 162145914Smckusick struct proc *p; 162254916Storek struct fsync_args *uap; 162342441Smckusick int *retval; 16249167Ssam { 162539592Smckusick register struct vnode *vp; 16269167Ssam struct file *fp; 162737741Smckusick int error; 16289167Ssam 162945914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 163047540Skarels return (error); 163139592Smckusick vp = (struct vnode *)fp->f_data; 163239592Smckusick VOP_LOCK(vp); 163354441Smckusick error = VOP_FSYNC(vp, fp->f_cred, MNT_WAIT, p); 163439592Smckusick VOP_UNLOCK(vp); 163547540Skarels return (error); 16369167Ssam } 16379167Ssam 16389167Ssam /* 16399167Ssam * Rename system call. 16409167Ssam * 16419167Ssam * Source and destination must either both be directories, or both 16429167Ssam * not be directories. If target is a directory, it must be empty. 16439167Ssam */ 164454916Storek struct rename_args { 164554916Storek char *from; 164654916Storek char *to; 164754916Storek }; 164842441Smckusick /* ARGSUSED */ 164942441Smckusick rename(p, uap, retval) 165045914Smckusick struct proc *p; 165154916Storek register struct rename_args *uap; 165242441Smckusick int *retval; 165342441Smckusick { 165437741Smckusick register struct vnode *tvp, *fvp, *tdvp; 165549735Smckusick struct nameidata fromnd, tond; 165637741Smckusick int error; 16577701Ssam 165852322Smckusick NDINIT(&fromnd, DELETE, WANTPARENT | SAVESTART, UIO_USERSPACE, 165952322Smckusick uap->from, p); 166052322Smckusick if (error = namei(&fromnd)) 166147540Skarels return (error); 166249735Smckusick fvp = fromnd.ni_vp; 166352322Smckusick NDINIT(&tond, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART, 166452322Smckusick UIO_USERSPACE, uap->to, p); 166552322Smckusick if (error = namei(&tond)) { 166652230Sheideman VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 166749735Smckusick vrele(fromnd.ni_dvp); 166842465Smckusick vrele(fvp); 166942465Smckusick goto out1; 167042465Smckusick } 167137741Smckusick tdvp = tond.ni_dvp; 167237741Smckusick tvp = tond.ni_vp; 167337741Smckusick if (tvp != NULL) { 167437741Smckusick if (fvp->v_type == VDIR && tvp->v_type != VDIR) { 167539242Sbostic error = ENOTDIR; 167637741Smckusick goto out; 167737741Smckusick } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) { 167839242Sbostic error = EISDIR; 167937741Smckusick goto out; 16809167Ssam } 16819167Ssam } 168239286Smckusick if (fvp == tdvp) 168337741Smckusick error = EINVAL; 168439286Smckusick /* 168549735Smckusick * If source is the same as the destination (that is the 168649735Smckusick * same inode number with the same name in the same directory), 168739286Smckusick * then there is nothing to do. 168839286Smckusick */ 168949735Smckusick if (fvp == tvp && fromnd.ni_dvp == tdvp && 169052322Smckusick fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen && 169152322Smckusick !bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr, 169252322Smckusick fromnd.ni_cnd.cn_namelen)) 169339286Smckusick error = -1; 169437741Smckusick out: 169542465Smckusick if (!error) { 169652192Smckusick LEASE_CHECK(tdvp, p, p->p_ucred, LEASE_WRITE); 169752192Smckusick if (fromnd.ni_dvp != tdvp) 169852192Smckusick LEASE_CHECK(fromnd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 169952192Smckusick if (tvp) 170052192Smckusick LEASE_CHECK(tvp, p, p->p_ucred, LEASE_WRITE); 170152230Sheideman error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd, 170252230Sheideman tond.ni_dvp, tond.ni_vp, &tond.ni_cnd); 170342465Smckusick } else { 170452230Sheideman VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd); 170543344Smckusick if (tdvp == tvp) 170643344Smckusick vrele(tdvp); 170743344Smckusick else 170843344Smckusick vput(tdvp); 170942465Smckusick if (tvp) 171042465Smckusick vput(tvp); 171152230Sheideman VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 171249735Smckusick vrele(fromnd.ni_dvp); 171342465Smckusick vrele(fvp); 17149167Ssam } 171549735Smckusick vrele(tond.ni_startdir); 171652322Smckusick FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI); 171737741Smckusick out1: 171849735Smckusick vrele(fromnd.ni_startdir); 171952322Smckusick FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI); 172039286Smckusick if (error == -1) 172147540Skarels return (0); 172247540Skarels return (error); 17237701Ssam } 17247701Ssam 17257535Sroot /* 172649365Smckusick * Mkdir system call. 172712756Ssam */ 172854916Storek struct mkdir_args { 172954916Storek char *name; 173054916Storek int dmode; 173154916Storek }; 173242441Smckusick /* ARGSUSED */ 173342441Smckusick mkdir(p, uap, retval) 173445914Smckusick struct proc *p; 173554916Storek register struct mkdir_args *uap; 173642441Smckusick int *retval; 173742441Smckusick { 173837741Smckusick register struct vnode *vp; 173937741Smckusick struct vattr vattr; 174037741Smckusick int error; 174147540Skarels struct nameidata nd; 174212756Ssam 174352322Smckusick NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->name, p); 174452322Smckusick if (error = namei(&nd)) 174547540Skarels return (error); 174652322Smckusick vp = nd.ni_vp; 174737741Smckusick if (vp != NULL) { 174852322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 174952322Smckusick if (nd.ni_dvp == vp) 175052322Smckusick vrele(nd.ni_dvp); 175143344Smckusick else 175252322Smckusick vput(nd.ni_dvp); 175342465Smckusick vrele(vp); 175447540Skarels return (EEXIST); 175512756Ssam } 175641362Smckusick VATTR_NULL(&vattr); 175737741Smckusick vattr.va_type = VDIR; 175845914Smckusick vattr.va_mode = (uap->dmode & 0777) &~ p->p_fd->fd_cmask; 175952322Smckusick LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 176052322Smckusick error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr); 176138145Smckusick if (!error) 176252322Smckusick vput(nd.ni_vp); 176347540Skarels return (error); 176412756Ssam } 176512756Ssam 176612756Ssam /* 176712756Ssam * Rmdir system call. 176812756Ssam */ 176954916Storek struct rmdir_args { 177054916Storek char *name; 177154916Storek }; 177242441Smckusick /* ARGSUSED */ 177342441Smckusick rmdir(p, uap, retval) 177445914Smckusick struct proc *p; 177554916Storek struct rmdir_args *uap; 177642441Smckusick int *retval; 177712756Ssam { 177837741Smckusick register struct vnode *vp; 177937741Smckusick int error; 178047540Skarels struct nameidata nd; 178112756Ssam 178252322Smckusick NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE, uap->name, p); 178352322Smckusick if (error = namei(&nd)) 178447540Skarels return (error); 178552322Smckusick vp = nd.ni_vp; 178637741Smckusick if (vp->v_type != VDIR) { 178737741Smckusick error = ENOTDIR; 178812756Ssam goto out; 178912756Ssam } 179012756Ssam /* 179137741Smckusick * No rmdir "." please. 179212756Ssam */ 179352322Smckusick if (nd.ni_dvp == vp) { 179437741Smckusick error = EINVAL; 179512756Ssam goto out; 179612756Ssam } 179712756Ssam /* 179849365Smckusick * The root of a mounted filesystem cannot be deleted. 179912756Ssam */ 180037741Smckusick if (vp->v_flag & VROOT) 180137741Smckusick error = EBUSY; 180212756Ssam out: 180342465Smckusick if (!error) { 180452322Smckusick LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 180552192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 180652322Smckusick error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); 180742465Smckusick } else { 180852322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 180952322Smckusick if (nd.ni_dvp == vp) 181052322Smckusick vrele(nd.ni_dvp); 181143344Smckusick else 181252322Smckusick vput(nd.ni_dvp); 181342465Smckusick vput(vp); 181442465Smckusick } 181547540Skarels return (error); 181612756Ssam } 181712756Ssam 181854620Smckusick #ifdef COMPAT_43 181937741Smckusick /* 182049365Smckusick * Read a block of directory entries in a file system independent format. 182137741Smckusick */ 182254916Storek struct ogetdirentries_args { 182354916Storek int fd; 182454916Storek char *buf; 182554916Storek unsigned count; 182654916Storek long *basep; 182754916Storek }; 182854620Smckusick ogetdirentries(p, uap, retval) 182954620Smckusick struct proc *p; 183054916Storek register struct ogetdirentries_args *uap; 183154620Smckusick int *retval; 183254620Smckusick { 183354620Smckusick register struct vnode *vp; 183454620Smckusick struct file *fp; 183554620Smckusick struct uio auio, kuio; 183654620Smckusick struct iovec aiov, kiov; 183754620Smckusick struct dirent *dp, *edp; 183854620Smckusick caddr_t dirbuf; 183954620Smckusick int error, readcnt; 184054969Smckusick long loff; 184154620Smckusick 184254620Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 184354620Smckusick return (error); 184454620Smckusick if ((fp->f_flag & FREAD) == 0) 184554620Smckusick return (EBADF); 184654620Smckusick vp = (struct vnode *)fp->f_data; 184754620Smckusick if (vp->v_type != VDIR) 184854620Smckusick return (EINVAL); 184954620Smckusick aiov.iov_base = uap->buf; 185054620Smckusick aiov.iov_len = uap->count; 185154620Smckusick auio.uio_iov = &aiov; 185254620Smckusick auio.uio_iovcnt = 1; 185354620Smckusick auio.uio_rw = UIO_READ; 185454620Smckusick auio.uio_segflg = UIO_USERSPACE; 185554620Smckusick auio.uio_procp = p; 185654620Smckusick auio.uio_resid = uap->count; 185754620Smckusick VOP_LOCK(vp); 185854969Smckusick loff = auio.uio_offset = fp->f_offset; 185954620Smckusick # if (BYTE_ORDER != LITTLE_ENDIAN) 186056339Smckusick if (vp->v_mount->mnt_maxsymlinklen <= 0) { 186154620Smckusick error = VOP_READDIR(vp, &auio, fp->f_cred); 186256339Smckusick fp->f_offset = auio.uio_offset; 186356339Smckusick } else 186454620Smckusick # endif 186554620Smckusick { 186654620Smckusick kuio = auio; 186754620Smckusick kuio.uio_iov = &kiov; 186854620Smckusick kuio.uio_segflg = UIO_SYSSPACE; 186954620Smckusick kiov.iov_len = uap->count; 187054620Smckusick MALLOC(dirbuf, caddr_t, uap->count, M_TEMP, M_WAITOK); 187154620Smckusick kiov.iov_base = dirbuf; 187254620Smckusick error = VOP_READDIR(vp, &kuio, fp->f_cred); 187356339Smckusick fp->f_offset = kuio.uio_offset; 187454620Smckusick if (error == 0) { 187554620Smckusick readcnt = uap->count - kuio.uio_resid; 187654620Smckusick edp = (struct dirent *)&dirbuf[readcnt]; 187754620Smckusick for (dp = (struct dirent *)dirbuf; dp < edp; ) { 187854620Smckusick # if (BYTE_ORDER == LITTLE_ENDIAN) 187954969Smckusick /* 188055009Smckusick * The expected low byte of 188155009Smckusick * dp->d_namlen is our dp->d_type. 188255009Smckusick * The high MBZ byte of dp->d_namlen 188355009Smckusick * is our dp->d_namlen. 188454969Smckusick */ 188555009Smckusick dp->d_type = dp->d_namlen; 188655009Smckusick dp->d_namlen = 0; 188755009Smckusick # else 188855009Smckusick /* 188955009Smckusick * The dp->d_type is the high byte 189055009Smckusick * of the expected dp->d_namlen, 189155009Smckusick * so must be zero'ed. 189255009Smckusick */ 189355009Smckusick dp->d_type = 0; 189454620Smckusick # endif 189554620Smckusick if (dp->d_reclen > 0) { 189654620Smckusick dp = (struct dirent *) 189754620Smckusick ((char *)dp + dp->d_reclen); 189854620Smckusick } else { 189954620Smckusick error = EIO; 190054620Smckusick break; 190154620Smckusick } 190254620Smckusick } 190354620Smckusick if (dp >= edp) 190454620Smckusick error = uiomove(dirbuf, readcnt, &auio); 190554620Smckusick } 190654620Smckusick FREE(dirbuf, M_TEMP); 190754620Smckusick } 190854620Smckusick VOP_UNLOCK(vp); 190954620Smckusick if (error) 191054620Smckusick return (error); 191154969Smckusick error = copyout((caddr_t)&loff, (caddr_t)uap->basep, sizeof(long)); 191254620Smckusick *retval = uap->count - auio.uio_resid; 191354620Smckusick return (error); 191454620Smckusick } 191554620Smckusick #endif 191654620Smckusick 191754620Smckusick /* 191854620Smckusick * Read a block of directory entries in a file system independent format. 191954620Smckusick */ 192054916Storek struct getdirentries_args { 192154916Storek int fd; 192254916Storek char *buf; 192354916Storek unsigned count; 192454916Storek long *basep; 192554916Storek }; 192642441Smckusick getdirentries(p, uap, retval) 192745914Smckusick struct proc *p; 192854916Storek register struct getdirentries_args *uap; 192942441Smckusick int *retval; 193042441Smckusick { 193139592Smckusick register struct vnode *vp; 193216540Ssam struct file *fp; 193337741Smckusick struct uio auio; 193437741Smckusick struct iovec aiov; 193554969Smckusick long loff; 193654441Smckusick int error; 193712756Ssam 193845914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 193947540Skarels return (error); 194037741Smckusick if ((fp->f_flag & FREAD) == 0) 194147540Skarels return (EBADF); 194239592Smckusick vp = (struct vnode *)fp->f_data; 194355451Spendry unionread: 194439592Smckusick if (vp->v_type != VDIR) 194547540Skarels return (EINVAL); 194637741Smckusick aiov.iov_base = uap->buf; 194737741Smckusick aiov.iov_len = uap->count; 194837741Smckusick auio.uio_iov = &aiov; 194937741Smckusick auio.uio_iovcnt = 1; 195037741Smckusick auio.uio_rw = UIO_READ; 195137741Smckusick auio.uio_segflg = UIO_USERSPACE; 195248026Smckusick auio.uio_procp = p; 195337741Smckusick auio.uio_resid = uap->count; 195439592Smckusick VOP_LOCK(vp); 195554969Smckusick loff = auio.uio_offset = fp->f_offset; 195654441Smckusick error = VOP_READDIR(vp, &auio, fp->f_cred); 195739592Smckusick fp->f_offset = auio.uio_offset; 195839592Smckusick VOP_UNLOCK(vp); 195939592Smckusick if (error) 196047540Skarels return (error); 196155451Spendry if ((uap->count == auio.uio_resid) && 196255451Spendry (vp->v_flag & VROOT) && 196355451Spendry (vp->v_mount->mnt_flag & MNT_UNION)) { 196455451Spendry struct vnode *tvp = vp; 196555451Spendry vp = vp->v_mount->mnt_vnodecovered; 196655451Spendry VREF(vp); 196755451Spendry fp->f_data = (caddr_t) vp; 196855451Spendry fp->f_offset = 0; 196955451Spendry vrele(tvp); 197055451Spendry goto unionread; 197155451Spendry } 197254969Smckusick error = copyout((caddr_t)&loff, (caddr_t)uap->basep, sizeof(long)); 197342441Smckusick *retval = uap->count - auio.uio_resid; 197447540Skarels return (error); 197512756Ssam } 197612756Ssam 197712756Ssam /* 197849365Smckusick * Set the mode mask for creation of filesystem nodes. 197912756Ssam */ 198054916Storek struct umask_args { 198154916Storek int mask; 198254916Storek }; 198354916Storek mode_t /* XXX */ 198442441Smckusick umask(p, uap, retval) 198545914Smckusick struct proc *p; 198654916Storek struct umask_args *uap; 198742441Smckusick int *retval; 198812756Ssam { 198945914Smckusick register struct filedesc *fdp = p->p_fd; 199012756Ssam 199145914Smckusick *retval = fdp->fd_cmask; 199245914Smckusick fdp->fd_cmask = uap->mask & 07777; 199347540Skarels return (0); 199412756Ssam } 199537741Smckusick 199639566Smarc /* 199739566Smarc * Void all references to file by ripping underlying filesystem 199839566Smarc * away from vnode. 199939566Smarc */ 200054916Storek struct revoke_args { 200154916Storek char *fname; 200254916Storek }; 200342441Smckusick /* ARGSUSED */ 200442441Smckusick revoke(p, uap, retval) 200545914Smckusick struct proc *p; 200654916Storek register struct revoke_args *uap; 200742441Smckusick int *retval; 200842441Smckusick { 200939566Smarc register struct vnode *vp; 201039566Smarc struct vattr vattr; 201139566Smarc int error; 201247540Skarels struct nameidata nd; 201339566Smarc 201452322Smckusick NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->fname, p); 201552322Smckusick if (error = namei(&nd)) 201647540Skarels return (error); 201752322Smckusick vp = nd.ni_vp; 201839566Smarc if (vp->v_type != VCHR && vp->v_type != VBLK) { 201939566Smarc error = EINVAL; 202039566Smarc goto out; 202139566Smarc } 202248026Smckusick if (error = VOP_GETATTR(vp, &vattr, p->p_ucred, p)) 202339566Smarc goto out; 202447540Skarels if (p->p_ucred->cr_uid != vattr.va_uid && 202547540Skarels (error = suser(p->p_ucred, &p->p_acflag))) 202639566Smarc goto out; 202739805Smckusick if (vp->v_usecount > 1 || (vp->v_flag & VALIASED)) 202839632Smckusick vgoneall(vp); 202939566Smarc out: 203039566Smarc vrele(vp); 203147540Skarels return (error); 203239566Smarc } 203339566Smarc 203449365Smckusick /* 203549365Smckusick * Convert a user file descriptor to a kernel file entry. 203649365Smckusick */ 203745914Smckusick getvnode(fdp, fdes, fpp) 203845914Smckusick struct filedesc *fdp; 203937741Smckusick struct file **fpp; 204037741Smckusick int fdes; 204137741Smckusick { 204237741Smckusick struct file *fp; 204337741Smckusick 204447540Skarels if ((unsigned)fdes >= fdp->fd_nfiles || 204547688Skarels (fp = fdp->fd_ofiles[fdes]) == NULL) 204637741Smckusick return (EBADF); 204737741Smckusick if (fp->f_type != DTYPE_VNODE) 204837741Smckusick return (EINVAL); 204937741Smckusick *fpp = fp; 205037741Smckusick return (0); 205137741Smckusick } 2052