123405Smckusick /* 263428Sbostic * Copyright (c) 1989, 1993 363428Sbostic * The Regents of the University of California. All rights reserved. 423405Smckusick * 544459Sbostic * %sccs.include.redist.c% 637741Smckusick * 7*65259Smckusick * @(#)vfs_syscalls.c 8.4 (Berkeley) 12/30/93 823405Smckusick */ 937Sbill 1056517Sbostic #include <sys/param.h> 1156517Sbostic #include <sys/systm.h> 1256517Sbostic #include <sys/namei.h> 1356517Sbostic #include <sys/filedesc.h> 1456517Sbostic #include <sys/kernel.h> 1556517Sbostic #include <sys/file.h> 1656517Sbostic #include <sys/stat.h> 1756517Sbostic #include <sys/vnode.h> 1856517Sbostic #include <sys/mount.h> 1956517Sbostic #include <sys/proc.h> 2056517Sbostic #include <sys/uio.h> 2156517Sbostic #include <sys/malloc.h> 2256517Sbostic #include <sys/dirent.h> 2356517Sbostic 2453468Smckusick #include <vm/vm.h> 2559875Smckusick #include <sys/sysctl.h> 2637Sbill 2764410Sbostic static int change_dir __P((struct nameidata *ndp, struct proc *p)); 2864410Sbostic 2937741Smckusick /* 3037741Smckusick * Virtual File System System Calls 3137741Smckusick */ 3212756Ssam 339167Ssam /* 3464410Sbostic * Mount a file system. 359167Ssam */ 3654916Storek struct mount_args { 3754916Storek int type; 3864410Sbostic char *path; 3954916Storek int flags; 4054916Storek caddr_t data; 4154916Storek }; 4242441Smckusick /* ARGSUSED */ 4342441Smckusick mount(p, uap, retval) 4445914Smckusick struct proc *p; 4554916Storek register struct mount_args *uap; 4642441Smckusick int *retval; 4742441Smckusick { 4839335Smckusick register struct vnode *vp; 4939335Smckusick register struct mount *mp; 5040111Smckusick int error, flag; 5147540Skarels struct nameidata nd; 526254Sroot 5337741Smckusick /* 5437741Smckusick * Must be super user 5537741Smckusick */ 5647540Skarels if (error = suser(p->p_ucred, &p->p_acflag)) 5747540Skarels return (error); 5837741Smckusick /* 5937741Smckusick * Get vnode to be covered 6037741Smckusick */ 6164410Sbostic NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); 6252322Smckusick if (error = namei(&nd)) 6347540Skarels return (error); 6452322Smckusick vp = nd.ni_vp; 6541400Smckusick if (uap->flags & MNT_UPDATE) { 6639335Smckusick if ((vp->v_flag & VROOT) == 0) { 6739335Smckusick vput(vp); 6847540Skarels return (EINVAL); 6939335Smckusick } 7039335Smckusick mp = vp->v_mount; 7157047Smckusick flag = mp->mnt_flag; 7239335Smckusick /* 7357047Smckusick * We only allow the filesystem to be reloaded if it 7457047Smckusick * is currently mounted read-only. 7539335Smckusick */ 7657047Smckusick if ((uap->flags & MNT_RELOAD) && 7757047Smckusick ((mp->mnt_flag & MNT_RDONLY) == 0)) { 7839335Smckusick vput(vp); 7947540Skarels return (EOPNOTSUPP); /* Needs translation */ 8039335Smckusick } 8157047Smckusick mp->mnt_flag |= 8257047Smckusick uap->flags & (MNT_RELOAD | MNT_FORCE | MNT_UPDATE); 8339335Smckusick VOP_UNLOCK(vp); 8439335Smckusick goto update; 8539335Smckusick } 8655451Spendry if (vp->v_usecount != 1 && (uap->flags & MNT_UNION) == 0) { 8737741Smckusick vput(vp); 8847540Skarels return (EBUSY); 8937741Smckusick } 9057793Smckusick if (error = vinvalbuf(vp, V_SAVE, p->p_ucred, p, 0, 0)) 9154441Smckusick return (error); 9237741Smckusick if (vp->v_type != VDIR) { 9337741Smckusick vput(vp); 9447540Skarels return (ENOTDIR); 9537741Smckusick } 9664410Sbostic if ((u_long)uap->type > MOUNT_MAXTYPE || vfssw[uap->type] == NULL) { 9737741Smckusick vput(vp); 9847540Skarels return (ENODEV); 9937741Smckusick } 10037741Smckusick 10137741Smckusick /* 10239335Smckusick * Allocate and initialize the file system. 10337741Smckusick */ 10437741Smckusick mp = (struct mount *)malloc((u_long)sizeof(struct mount), 10537741Smckusick M_MOUNT, M_WAITOK); 10654172Smckusick bzero((char *)mp, (u_long)sizeof(struct mount)); 10741400Smckusick mp->mnt_op = vfssw[uap->type]; 10839335Smckusick if (error = vfs_lock(mp)) { 10939335Smckusick free((caddr_t)mp, M_MOUNT); 11039335Smckusick vput(vp); 11147540Skarels return (error); 11239335Smckusick } 11364410Sbostic if (vp->v_mountedhere != NULL) { 11439335Smckusick vfs_unlock(mp); 11539335Smckusick free((caddr_t)mp, M_MOUNT); 11639335Smckusick vput(vp); 11747540Skarels return (EBUSY); 11839335Smckusick } 11939335Smckusick vp->v_mountedhere = mp; 12041400Smckusick mp->mnt_vnodecovered = vp; 12139335Smckusick update: 12239335Smckusick /* 12339335Smckusick * Set the mount level flags. 12439335Smckusick */ 12541400Smckusick if (uap->flags & MNT_RDONLY) 12641400Smckusick mp->mnt_flag |= MNT_RDONLY; 12757047Smckusick else if (mp->mnt_flag & MNT_RDONLY) 12857047Smckusick mp->mnt_flag |= MNT_WANTRDWR; 12957047Smckusick mp->mnt_flag &=~ 13057047Smckusick (MNT_NOSUID | MNT_NOEXEC | MNT_NODEV | MNT_SYNCHRONOUS | MNT_UNION); 13157047Smckusick mp->mnt_flag |= uap->flags & 13257047Smckusick (MNT_NOSUID | MNT_NOEXEC | MNT_NODEV | MNT_SYNCHRONOUS | MNT_UNION); 13339335Smckusick /* 13439335Smckusick * Mount the filesystem. 13539335Smckusick */ 13664410Sbostic error = VFS_MOUNT(mp, uap->path, uap->data, &nd, p); 13741400Smckusick if (mp->mnt_flag & MNT_UPDATE) { 13839335Smckusick vrele(vp); 13957047Smckusick if (mp->mnt_flag & MNT_WANTRDWR) 14057047Smckusick mp->mnt_flag &= ~MNT_RDONLY; 14157047Smckusick mp->mnt_flag &=~ 14257047Smckusick (MNT_UPDATE | MNT_RELOAD | MNT_FORCE | MNT_WANTRDWR); 14340111Smckusick if (error) 14441400Smckusick mp->mnt_flag = flag; 14547540Skarels return (error); 14639335Smckusick } 14740110Smckusick /* 14840110Smckusick * Put the new filesystem on the mount list after root. 14940110Smckusick */ 15037741Smckusick cache_purge(vp); 15137741Smckusick if (!error) { 152*65259Smckusick TAILQ_INSERT_TAIL(&mountlist, mp, mnt_list); 15339335Smckusick VOP_UNLOCK(vp); 15437741Smckusick vfs_unlock(mp); 15548026Smckusick error = VFS_START(mp, 0, p); 15637741Smckusick } else { 157*65259Smckusick mp->mnt_vnodecovered->v_mountedhere = (struct mount *)0; 158*65259Smckusick vfs_unlock(mp); 15937741Smckusick free((caddr_t)mp, M_MOUNT); 16039335Smckusick vput(vp); 16137741Smckusick } 16247540Skarels return (error); 1636254Sroot } 1646254Sroot 1659167Ssam /* 16664410Sbostic * Unmount a file system. 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 { 17264410Sbostic char *path; 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 19264410Sbostic NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, 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 /* 20964410Sbostic * Do the actual file system 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); 237*65259Smckusick TAILQ_REMOVE(&mountlist, mp, mnt_list); 238*65259Smckusick mp->mnt_vnodecovered->v_mountedhere = (struct mount *)0; 239*65259Smckusick vfs_unlock(mp); 240*65259Smckusick if (mp->mnt_vnodelist.lh_first != NULL) 24152287Smckusick panic("unmount: dangling vnode"); 24237741Smckusick free((caddr_t)mp, M_MOUNT); 24337741Smckusick } 24439356Smckusick return (error); 2456254Sroot } 2466254Sroot 2479167Ssam /* 24837741Smckusick * Sync each mounted filesystem. 2499167Ssam */ 25056352Smckusick #ifdef DIAGNOSTIC 25156352Smckusick int syncprt = 0; 25259875Smckusick struct ctldebug debug0 = { "syncprt", &syncprt }; 25356352Smckusick #endif 25456352Smckusick 25554916Storek struct sync_args { 25654916Storek int dummy; 25754916Storek }; 25839491Smckusick /* ARGSUSED */ 25942441Smckusick sync(p, uap, retval) 26045914Smckusick struct proc *p; 26154916Storek struct sync_args *uap; 26242441Smckusick int *retval; 2636254Sroot { 264*65259Smckusick register struct mount *mp, *nmp; 26537741Smckusick 266*65259Smckusick for (mp = mountlist.tqh_first; mp != NULL; mp = nmp) { 267*65259Smckusick nmp = mp->mnt_list.tqe_next; 26840343Smckusick /* 26940343Smckusick * The lock check below is to avoid races with mount 27040343Smckusick * and unmount. 27140343Smckusick */ 27241400Smckusick if ((mp->mnt_flag & (MNT_MLOCK|MNT_RDONLY|MNT_MPBUSY)) == 0 && 27341298Smckusick !vfs_busy(mp)) { 27454441Smckusick VFS_SYNC(mp, MNT_NOWAIT, p->p_ucred, p); 275*65259Smckusick vfs_unbusy(mp); 276*65259Smckusick } 277*65259Smckusick } 27856352Smckusick #ifdef DIAGNOSTIC 27956352Smckusick if (syncprt) 28056352Smckusick vfs_bufstats(); 28156352Smckusick #endif /* DIAGNOSTIC */ 28247688Skarels return (0); 28337741Smckusick } 28437741Smckusick 28537741Smckusick /* 28664410Sbostic * Change filesystem quotas. 28741298Smckusick */ 28854916Storek struct quotactl_args { 28954916Storek char *path; 29054916Storek int cmd; 29154916Storek int uid; 29254916Storek caddr_t arg; 29354916Storek }; 29442441Smckusick /* ARGSUSED */ 29542441Smckusick quotactl(p, uap, retval) 29645914Smckusick struct proc *p; 29754916Storek register struct quotactl_args *uap; 29842441Smckusick int *retval; 29942441Smckusick { 30041298Smckusick register struct mount *mp; 30141298Smckusick int error; 30247540Skarels struct nameidata nd; 30341298Smckusick 30452322Smckusick NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); 30552322Smckusick if (error = namei(&nd)) 30647540Skarels return (error); 30752322Smckusick mp = nd.ni_vp->v_mount; 30852322Smckusick vrele(nd.ni_vp); 30948026Smckusick return (VFS_QUOTACTL(mp, uap->cmd, uap->uid, uap->arg, p)); 31041298Smckusick } 31141298Smckusick 31241298Smckusick /* 31349365Smckusick * Get filesystem statistics. 31437741Smckusick */ 31554916Storek struct statfs_args { 31654916Storek char *path; 31754916Storek struct statfs *buf; 31854916Storek }; 31942441Smckusick /* ARGSUSED */ 32042441Smckusick statfs(p, uap, retval) 32145914Smckusick struct proc *p; 32254916Storek register struct statfs_args *uap; 32342441Smckusick int *retval; 32442441Smckusick { 32539464Smckusick register struct mount *mp; 32640343Smckusick register struct statfs *sp; 32737741Smckusick int error; 32847540Skarels struct nameidata nd; 32937741Smckusick 33052322Smckusick NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); 33152322Smckusick if (error = namei(&nd)) 33247540Skarels return (error); 33352322Smckusick mp = nd.ni_vp->v_mount; 33441400Smckusick sp = &mp->mnt_stat; 33552322Smckusick vrele(nd.ni_vp); 33648026Smckusick if (error = VFS_STATFS(mp, sp, p)) 33747540Skarels return (error); 33841400Smckusick sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 33947540Skarels return (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp))); 34037741Smckusick } 34137741Smckusick 34242441Smckusick /* 34349365Smckusick * Get filesystem statistics. 34442441Smckusick */ 34554916Storek struct fstatfs_args { 34654916Storek int fd; 34754916Storek struct statfs *buf; 34854916Storek }; 34942441Smckusick /* ARGSUSED */ 35042441Smckusick fstatfs(p, uap, retval) 35145914Smckusick struct proc *p; 35254916Storek register struct fstatfs_args *uap; 35342441Smckusick int *retval; 35442441Smckusick { 35537741Smckusick struct file *fp; 35639464Smckusick struct mount *mp; 35740343Smckusick register struct statfs *sp; 35837741Smckusick int error; 35937741Smckusick 36045914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 36147540Skarels return (error); 36239464Smckusick mp = ((struct vnode *)fp->f_data)->v_mount; 36341400Smckusick sp = &mp->mnt_stat; 36448026Smckusick if (error = VFS_STATFS(mp, sp, p)) 36547540Skarels return (error); 36641400Smckusick sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 36747540Skarels return (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp))); 36837741Smckusick } 36937741Smckusick 37037741Smckusick /* 37149365Smckusick * Get statistics on all filesystems. 37238270Smckusick */ 37354916Storek struct getfsstat_args { 37454916Storek struct statfs *buf; 37554916Storek long bufsize; 37654916Storek int flags; 37754916Storek }; 37842441Smckusick getfsstat(p, uap, retval) 37945914Smckusick struct proc *p; 38054916Storek register struct getfsstat_args *uap; 38142441Smckusick int *retval; 38242441Smckusick { 383*65259Smckusick register struct mount *mp, *nmp; 38440343Smckusick register struct statfs *sp; 38539606Smckusick caddr_t sfsp; 38638270Smckusick long count, maxcount, error; 38738270Smckusick 38838270Smckusick maxcount = uap->bufsize / sizeof(struct statfs); 38939606Smckusick sfsp = (caddr_t)uap->buf; 390*65259Smckusick for (count = 0, mp = mountlist.tqh_first; mp != NULL; mp = nmp) { 391*65259Smckusick nmp = mp->mnt_list.tqe_next; 39241400Smckusick if (sfsp && count < maxcount && 39341400Smckusick ((mp->mnt_flag & MNT_MLOCK) == 0)) { 39441400Smckusick sp = &mp->mnt_stat; 39540343Smckusick /* 39640343Smckusick * If MNT_NOWAIT is specified, do not refresh the 39740343Smckusick * fsstat cache. MNT_WAIT overrides MNT_NOWAIT. 39840343Smckusick */ 39940343Smckusick if (((uap->flags & MNT_NOWAIT) == 0 || 40040343Smckusick (uap->flags & MNT_WAIT)) && 401*65259Smckusick (error = VFS_STATFS(mp, sp, p))) 40239607Smckusick continue; 40341400Smckusick sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 40440343Smckusick if (error = copyout((caddr_t)sp, sfsp, sizeof(*sp))) 40547540Skarels return (error); 40640343Smckusick sfsp += sizeof(*sp); 40738270Smckusick } 40839606Smckusick count++; 409*65259Smckusick } 41038270Smckusick if (sfsp && count > maxcount) 41142441Smckusick *retval = maxcount; 41238270Smckusick else 41342441Smckusick *retval = count; 41447540Skarels return (0); 41538270Smckusick } 41638270Smckusick 41738270Smckusick /* 41838259Smckusick * Change current working directory to a given file descriptor. 41938259Smckusick */ 42054916Storek struct fchdir_args { 42154916Storek int fd; 42254916Storek }; 42342441Smckusick /* ARGSUSED */ 42442441Smckusick fchdir(p, uap, retval) 42545914Smckusick struct proc *p; 42654916Storek struct fchdir_args *uap; 42742441Smckusick int *retval; 42838259Smckusick { 42945914Smckusick register struct filedesc *fdp = p->p_fd; 43038259Smckusick register struct vnode *vp; 43138259Smckusick struct file *fp; 43238259Smckusick int error; 43338259Smckusick 43445914Smckusick if (error = getvnode(fdp, uap->fd, &fp)) 43547540Skarels return (error); 43638259Smckusick vp = (struct vnode *)fp->f_data; 43738259Smckusick VOP_LOCK(vp); 43838259Smckusick if (vp->v_type != VDIR) 43938259Smckusick error = ENOTDIR; 44038259Smckusick else 44148026Smckusick error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p); 44238259Smckusick VOP_UNLOCK(vp); 44339860Smckusick if (error) 44447540Skarels return (error); 44539860Smckusick VREF(vp); 44645914Smckusick vrele(fdp->fd_cdir); 44745914Smckusick fdp->fd_cdir = vp; 44847540Skarels return (0); 44938259Smckusick } 45038259Smckusick 45138259Smckusick /* 45237741Smckusick * Change current working directory (``.''). 45337741Smckusick */ 45454916Storek struct chdir_args { 45564410Sbostic char *path; 45654916Storek }; 45742441Smckusick /* ARGSUSED */ 45842441Smckusick chdir(p, uap, retval) 45945914Smckusick struct proc *p; 46054916Storek struct chdir_args *uap; 46142441Smckusick int *retval; 46237741Smckusick { 46345914Smckusick register struct filedesc *fdp = p->p_fd; 46437741Smckusick int error; 46547540Skarels struct nameidata nd; 4666254Sroot 46764410Sbostic NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); 46864410Sbostic if (error = change_dir(&nd, p)) 46947540Skarels return (error); 47045914Smckusick vrele(fdp->fd_cdir); 47152322Smckusick fdp->fd_cdir = nd.ni_vp; 47247540Skarels return (0); 47337741Smckusick } 4746254Sroot 47537741Smckusick /* 47637741Smckusick * Change notion of root (``/'') directory. 47737741Smckusick */ 47854916Storek struct chroot_args { 47964410Sbostic char *path; 48054916Storek }; 48142441Smckusick /* ARGSUSED */ 48242441Smckusick chroot(p, uap, retval) 48345914Smckusick struct proc *p; 48454916Storek struct chroot_args *uap; 48542441Smckusick int *retval; 48637741Smckusick { 48745914Smckusick register struct filedesc *fdp = p->p_fd; 48837741Smckusick int error; 48947540Skarels struct nameidata nd; 49037741Smckusick 49147540Skarels if (error = suser(p->p_ucred, &p->p_acflag)) 49247540Skarels return (error); 49364410Sbostic NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); 49464410Sbostic if (error = change_dir(&nd, p)) 49547540Skarels return (error); 49645914Smckusick if (fdp->fd_rdir != NULL) 49745914Smckusick vrele(fdp->fd_rdir); 49852322Smckusick fdp->fd_rdir = nd.ni_vp; 49947540Skarels return (0); 5006254Sroot } 5016254Sroot 50237Sbill /* 50337741Smckusick * Common routine for chroot and chdir. 50437741Smckusick */ 50564410Sbostic static int 50664410Sbostic change_dir(ndp, p) 50752322Smckusick register struct nameidata *ndp; 50847540Skarels struct proc *p; 50937741Smckusick { 51037741Smckusick struct vnode *vp; 51137741Smckusick int error; 51237741Smckusick 51352322Smckusick if (error = namei(ndp)) 51437741Smckusick return (error); 51537741Smckusick vp = ndp->ni_vp; 51637741Smckusick if (vp->v_type != VDIR) 51737741Smckusick error = ENOTDIR; 51837741Smckusick else 51948026Smckusick error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p); 52037741Smckusick VOP_UNLOCK(vp); 52137741Smckusick if (error) 52237741Smckusick vrele(vp); 52337741Smckusick return (error); 52437741Smckusick } 52537741Smckusick 52637741Smckusick /* 52742441Smckusick * Check permissions, allocate an open file structure, 52842441Smckusick * and call the device open routine if any. 5296254Sroot */ 53054916Storek struct open_args { 53164410Sbostic char *path; 53264410Sbostic int flags; 53354916Storek int mode; 53454916Storek }; 53542441Smckusick open(p, uap, retval) 53645914Smckusick struct proc *p; 53754916Storek register struct open_args *uap; 53842441Smckusick int *retval; 5396254Sroot { 54045914Smckusick register struct filedesc *fdp = p->p_fd; 54142441Smckusick register struct file *fp; 54250111Smckusick register struct vnode *vp; 54364410Sbostic int flags, cmode; 54437741Smckusick struct file *nfp; 54549945Smckusick int type, indx, error; 54649945Smckusick struct flock lf; 54747540Skarels struct nameidata nd; 54837741Smckusick extern struct fileops vnops; 5496254Sroot 55045914Smckusick if (error = falloc(p, &nfp, &indx)) 55147540Skarels return (error); 55237741Smckusick fp = nfp; 55364410Sbostic flags = FFLAGS(uap->flags); 55464410Sbostic cmode = ((uap->mode &~ fdp->fd_cmask) & ALLPERMS) &~ S_ISTXT; 55564410Sbostic NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); 55645202Smckusick p->p_dupfd = -indx - 1; /* XXX check for fdopen */ 55764410Sbostic if (error = vn_open(&nd, flags, cmode)) { 55849980Smckusick ffree(fp); 55954723Smckusick if ((error == ENODEV || error == ENXIO) && 56054723Smckusick p->p_dupfd >= 0 && /* XXX from fdopen */ 56164410Sbostic (error = 56264410Sbostic dupfdopen(fdp, indx, p->p_dupfd, flags, error)) == 0) { 56342441Smckusick *retval = indx; 56447540Skarels return (0); 56542441Smckusick } 56640884Smckusick if (error == ERESTART) 56740884Smckusick error = EINTR; 56847688Skarels fdp->fd_ofiles[indx] = NULL; 56947540Skarels return (error); 57012756Ssam } 57153828Spendry p->p_dupfd = 0; 57252322Smckusick vp = nd.ni_vp; 57364410Sbostic fp->f_flag = flags & FMASK; 57454348Smckusick fp->f_type = DTYPE_VNODE; 57554348Smckusick fp->f_ops = &vnops; 57654348Smckusick fp->f_data = (caddr_t)vp; 57764410Sbostic if (flags & (O_EXLOCK | O_SHLOCK)) { 57849945Smckusick lf.l_whence = SEEK_SET; 57949945Smckusick lf.l_start = 0; 58049945Smckusick lf.l_len = 0; 58164410Sbostic if (flags & O_EXLOCK) 58249945Smckusick lf.l_type = F_WRLCK; 58349945Smckusick else 58449945Smckusick lf.l_type = F_RDLCK; 58549945Smckusick type = F_FLOCK; 58664410Sbostic if ((flags & FNONBLOCK) == 0) 58749945Smckusick type |= F_WAIT; 58850111Smckusick if (error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, type)) { 58950111Smckusick VOP_UNLOCK(vp); 59050111Smckusick (void) vn_close(vp, fp->f_flag, fp->f_cred, p); 59149980Smckusick ffree(fp); 59249945Smckusick fdp->fd_ofiles[indx] = NULL; 59349945Smckusick return (error); 59449945Smckusick } 59549949Smckusick fp->f_flag |= FHASLOCK; 59649945Smckusick } 59750111Smckusick VOP_UNLOCK(vp); 59842441Smckusick *retval = indx; 59947540Skarels return (0); 6006254Sroot } 6016254Sroot 60242955Smckusick #ifdef COMPAT_43 6036254Sroot /* 60464410Sbostic * Create a file. 6056254Sroot */ 60654916Storek struct ocreat_args { 60764410Sbostic char *path; 60864410Sbostic int mode; 60954916Storek }; 61042955Smckusick ocreat(p, uap, retval) 61142441Smckusick struct proc *p; 61254916Storek register struct ocreat_args *uap; 61342441Smckusick int *retval; 6146254Sroot { 61554916Storek struct open_args openuap; 61642441Smckusick 61764410Sbostic openuap.path = uap->path; 61864410Sbostic openuap.mode = uap->mode; 61964410Sbostic openuap.flags = O_WRONLY | O_CREAT | O_TRUNC; 62047540Skarels return (open(p, &openuap, retval)); 62142441Smckusick } 62242955Smckusick #endif /* COMPAT_43 */ 62342441Smckusick 62442441Smckusick /* 62564410Sbostic * Create a special file. 62642441Smckusick */ 62754916Storek struct mknod_args { 62864410Sbostic char *path; 62964410Sbostic int mode; 63054916Storek int dev; 63154916Storek }; 63242441Smckusick /* ARGSUSED */ 63342441Smckusick mknod(p, uap, retval) 63445914Smckusick struct proc *p; 63554916Storek register struct mknod_args *uap; 63642441Smckusick int *retval; 63742441Smckusick { 63837741Smckusick register struct vnode *vp; 63937741Smckusick struct vattr vattr; 64037741Smckusick int error; 64147540Skarels struct nameidata nd; 6426254Sroot 64347540Skarels if (error = suser(p->p_ucred, &p->p_acflag)) 64447540Skarels return (error); 64564410Sbostic NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->path, p); 64652322Smckusick if (error = namei(&nd)) 64747540Skarels return (error); 64852322Smckusick vp = nd.ni_vp; 64964585Sbostic if (vp != NULL) 65037741Smckusick error = EEXIST; 65164585Sbostic else { 65264585Sbostic VATTR_NULL(&vattr); 65364585Sbostic vattr.va_mode = (uap->mode & ALLPERMS) &~ p->p_fd->fd_cmask; 65464585Sbostic vattr.va_rdev = uap->dev; 65564585Sbostic 65664585Sbostic switch (uap->mode & S_IFMT) { 65764585Sbostic case S_IFMT: /* used by badsect to flag bad sectors */ 65864585Sbostic vattr.va_type = VBAD; 65964585Sbostic break; 66064585Sbostic case S_IFCHR: 66164585Sbostic vattr.va_type = VCHR; 66264585Sbostic break; 66364585Sbostic case S_IFBLK: 66464585Sbostic vattr.va_type = VBLK; 66564585Sbostic break; 66664585Sbostic default: 66764585Sbostic error = EINVAL; 66864585Sbostic break; 66964585Sbostic } 6706254Sroot } 67142465Smckusick if (!error) { 67252322Smckusick LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 67352322Smckusick error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr); 67442465Smckusick } else { 67552322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 67652322Smckusick if (nd.ni_dvp == vp) 67752322Smckusick vrele(nd.ni_dvp); 67843344Smckusick else 67952322Smckusick vput(nd.ni_dvp); 68042465Smckusick if (vp) 68142465Smckusick vrele(vp); 68242465Smckusick } 68347540Skarels return (error); 6846254Sroot } 6856254Sroot 6866254Sroot /* 68764410Sbostic * Create named pipe. 68840285Smckusick */ 68954916Storek struct mkfifo_args { 69064410Sbostic char *path; 69164410Sbostic int mode; 69254916Storek }; 69342441Smckusick /* ARGSUSED */ 69442441Smckusick mkfifo(p, uap, retval) 69545914Smckusick struct proc *p; 69654916Storek register struct mkfifo_args *uap; 69742441Smckusick int *retval; 69842441Smckusick { 69940285Smckusick struct vattr vattr; 70040285Smckusick int error; 70147540Skarels struct nameidata nd; 70240285Smckusick 70340285Smckusick #ifndef FIFO 70447540Skarels return (EOPNOTSUPP); 70540285Smckusick #else 70664410Sbostic NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->path, p); 70752322Smckusick if (error = namei(&nd)) 70847540Skarels return (error); 70952322Smckusick if (nd.ni_vp != NULL) { 71052322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 71152322Smckusick if (nd.ni_dvp == nd.ni_vp) 71252322Smckusick vrele(nd.ni_dvp); 71343344Smckusick else 71452322Smckusick vput(nd.ni_dvp); 71552322Smckusick vrele(nd.ni_vp); 71647540Skarels return (EEXIST); 71740285Smckusick } 71845785Sbostic VATTR_NULL(&vattr); 71945785Sbostic vattr.va_type = VFIFO; 72064410Sbostic vattr.va_mode = (uap->mode & ALLPERMS) &~ p->p_fd->fd_cmask; 72152322Smckusick LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 72252322Smckusick return (VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr)); 72340285Smckusick #endif /* FIFO */ 72440285Smckusick } 72540285Smckusick 72640285Smckusick /* 72764410Sbostic * Make a hard file link. 7286254Sroot */ 72954916Storek struct link_args { 73064410Sbostic char *path; 73164410Sbostic char *link; 73254916Storek }; 73342441Smckusick /* ARGSUSED */ 73442441Smckusick link(p, uap, retval) 73545914Smckusick struct proc *p; 73654916Storek register struct link_args *uap; 73742441Smckusick int *retval; 73842441Smckusick { 73964410Sbostic register struct vnode *vp; 74064410Sbostic struct nameidata nd; 74137741Smckusick int error; 7426254Sroot 74364410Sbostic NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); 74452322Smckusick if (error = namei(&nd)) 74547540Skarels return (error); 74652322Smckusick vp = nd.ni_vp; 74764585Sbostic if (vp->v_type != VDIR || 74864585Sbostic (error = suser(p->p_ucred, &p->p_acflag)) == 0) { 74964585Sbostic nd.ni_cnd.cn_nameiop = CREATE; 75064585Sbostic nd.ni_cnd.cn_flags = LOCKPARENT; 75164585Sbostic nd.ni_dirp = uap->link; 75264585Sbostic if ((error = namei(&nd)) == 0) { 75364585Sbostic if (nd.ni_vp != NULL) 75464585Sbostic error = EEXIST; 75564585Sbostic if (!error) { 75664585Sbostic LEASE_CHECK(nd.ni_dvp, 75764585Sbostic p, p->p_ucred, LEASE_WRITE); 75864585Sbostic LEASE_CHECK(vp, 75964585Sbostic p, p->p_ucred, LEASE_WRITE); 76064585Sbostic error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd); 76164585Sbostic } else { 76264585Sbostic VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 76364585Sbostic if (nd.ni_dvp == nd.ni_vp) 76464585Sbostic vrele(nd.ni_dvp); 76564585Sbostic else 76664585Sbostic vput(nd.ni_dvp); 76764585Sbostic if (nd.ni_vp) 76864585Sbostic vrele(nd.ni_vp); 76964585Sbostic } 77064585Sbostic } 77142465Smckusick } 77264585Sbostic vrele(vp); 77347540Skarels return (error); 7746254Sroot } 7756254Sroot 7766254Sroot /* 77749365Smckusick * Make a symbolic link. 7786254Sroot */ 77954916Storek struct symlink_args { 78064410Sbostic char *path; 78164410Sbostic char *link; 78254916Storek }; 78342441Smckusick /* ARGSUSED */ 78442441Smckusick symlink(p, uap, retval) 78545914Smckusick struct proc *p; 78654916Storek register struct symlink_args *uap; 78742441Smckusick int *retval; 78842441Smckusick { 78937741Smckusick struct vattr vattr; 79064410Sbostic char *path; 79137741Smckusick int error; 79247540Skarels struct nameidata nd; 7936254Sroot 79464410Sbostic MALLOC(path, char *, MAXPATHLEN, M_NAMEI, M_WAITOK); 79564410Sbostic if (error = copyinstr(uap->path, path, MAXPATHLEN, NULL)) 79642465Smckusick goto out; 79764410Sbostic NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->link, p); 79852322Smckusick if (error = namei(&nd)) 79942465Smckusick goto out; 80052322Smckusick if (nd.ni_vp) { 80152322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 80252322Smckusick if (nd.ni_dvp == nd.ni_vp) 80352322Smckusick vrele(nd.ni_dvp); 80443344Smckusick else 80552322Smckusick vput(nd.ni_dvp); 80652322Smckusick vrele(nd.ni_vp); 80737741Smckusick error = EEXIST; 80837741Smckusick goto out; 8096254Sroot } 81041362Smckusick VATTR_NULL(&vattr); 81164410Sbostic vattr.va_mode = ACCESSPERMS &~ p->p_fd->fd_cmask; 81252322Smckusick LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 81364410Sbostic error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr, path); 81437741Smckusick out: 81564410Sbostic FREE(path, M_NAMEI); 81647540Skarels return (error); 8176254Sroot } 8186254Sroot 8196254Sroot /* 82049365Smckusick * Delete a name from the filesystem. 8216254Sroot */ 82254916Storek struct unlink_args { 82364410Sbostic char *path; 82454916Storek }; 82542441Smckusick /* ARGSUSED */ 82642441Smckusick unlink(p, uap, retval) 82745914Smckusick struct proc *p; 82854916Storek struct unlink_args *uap; 82942441Smckusick int *retval; 8306254Sroot { 83137741Smckusick register struct vnode *vp; 83237741Smckusick int error; 83347540Skarels struct nameidata nd; 8346254Sroot 83564410Sbostic NDINIT(&nd, DELETE, LOCKPARENT, UIO_USERSPACE, uap->path, p); 83652322Smckusick if (error = namei(&nd)) 83747540Skarels return (error); 83852322Smckusick vp = nd.ni_vp; 83959382Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 84059382Smckusick VOP_LOCK(vp); 84164410Sbostic 84264585Sbostic if (vp->v_type != VDIR || 84364585Sbostic (error = suser(p->p_ucred, &p->p_acflag)) == 0) { 84464585Sbostic /* 84564585Sbostic * The root of a mounted filesystem cannot be deleted. 84664585Sbostic */ 84764585Sbostic if (vp->v_flag & VROOT) 84864585Sbostic error = EBUSY; 84964585Sbostic else 85064585Sbostic (void)vnode_pager_uncache(vp); 85164585Sbostic } 85264585Sbostic 85364585Sbostic if (!error) { 85452322Smckusick LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 85552322Smckusick error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); 85642465Smckusick } else { 85752322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 85852322Smckusick if (nd.ni_dvp == vp) 85952322Smckusick vrele(nd.ni_dvp); 86043344Smckusick else 86152322Smckusick vput(nd.ni_dvp); 86242465Smckusick vput(vp); 86342465Smckusick } 86447540Skarels return (error); 8656254Sroot } 8666254Sroot 86764410Sbostic /* 86864410Sbostic * Reposition read/write file offset. 86964410Sbostic */ 87060428Smckusick struct lseek_args { 87164410Sbostic int fd; 87254863Storek int pad; 87364410Sbostic off_t offset; 87464410Sbostic int whence; 87554863Storek }; 87660414Smckusick lseek(p, uap, retval) 87753468Smckusick struct proc *p; 87860428Smckusick register struct lseek_args *uap; 87954916Storek int *retval; 88042441Smckusick { 88147540Skarels struct ucred *cred = p->p_ucred; 88245914Smckusick register struct filedesc *fdp = p->p_fd; 88342441Smckusick register struct file *fp; 88437741Smckusick struct vattr vattr; 88537741Smckusick int error; 8866254Sroot 88764410Sbostic if ((u_int)uap->fd >= fdp->fd_nfiles || 88864410Sbostic (fp = fdp->fd_ofiles[uap->fd]) == NULL) 88947540Skarels return (EBADF); 89037741Smckusick if (fp->f_type != DTYPE_VNODE) 89147540Skarels return (ESPIPE); 89264410Sbostic switch (uap->whence) { 89313878Ssam case L_INCR: 89464410Sbostic fp->f_offset += uap->offset; 89513878Ssam break; 89613878Ssam case L_XTND: 89764410Sbostic if (error = 89864410Sbostic VOP_GETATTR((struct vnode *)fp->f_data, &vattr, cred, p)) 89947540Skarels return (error); 90064410Sbostic fp->f_offset = uap->offset + vattr.va_size; 90113878Ssam break; 90213878Ssam case L_SET: 90364410Sbostic fp->f_offset = uap->offset; 90413878Ssam break; 90513878Ssam default: 90647540Skarels return (EINVAL); 90713878Ssam } 90854916Storek *(off_t *)retval = fp->f_offset; 90947540Skarels return (0); 9106254Sroot } 9116254Sroot 91260414Smckusick #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 9136254Sroot /* 91464410Sbostic * Reposition read/write file offset. 91560036Smckusick */ 91660428Smckusick struct olseek_args { 91764410Sbostic int fd; 91864410Sbostic long offset; 91964410Sbostic int whence; 92060036Smckusick }; 92160414Smckusick olseek(p, uap, retval) 92260036Smckusick struct proc *p; 92360428Smckusick register struct olseek_args *uap; 92460036Smckusick int *retval; 92560036Smckusick { 92660428Smckusick struct lseek_args nuap; 92760036Smckusick off_t qret; 92860036Smckusick int error; 92960036Smckusick 93064410Sbostic nuap.fd = uap->fd; 93164410Sbostic nuap.offset = uap->offset; 93264410Sbostic nuap.whence = uap->whence; 93360428Smckusick error = lseek(p, &nuap, &qret); 93460036Smckusick *(long *)retval = qret; 93560036Smckusick return (error); 93660036Smckusick } 93760414Smckusick #endif /* COMPAT_43 */ 93860036Smckusick 93960036Smckusick /* 94049365Smckusick * Check access permissions. 9416254Sroot */ 94263427Sbostic struct access_args { 94364410Sbostic char *path; 94464410Sbostic int flags; 94554916Storek }; 94663427Sbostic access(p, uap, retval) 94745914Smckusick struct proc *p; 94863427Sbostic register struct access_args *uap; 94942441Smckusick int *retval; 95042441Smckusick { 95147540Skarels register struct ucred *cred = p->p_ucred; 95237741Smckusick register struct vnode *vp; 95364585Sbostic int error, flags, t_gid, t_uid; 95447540Skarels struct nameidata nd; 9556254Sroot 95664585Sbostic t_uid = cred->cr_uid; 95764585Sbostic t_gid = cred->cr_groups[0]; 95847540Skarels cred->cr_uid = p->p_cred->p_ruid; 95947540Skarels cred->cr_groups[0] = p->p_cred->p_rgid; 96064410Sbostic NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); 96152322Smckusick if (error = namei(&nd)) 96237741Smckusick goto out1; 96352322Smckusick vp = nd.ni_vp; 96464410Sbostic 96564410Sbostic /* Flags == 0 means only check for existence. */ 96664410Sbostic if (uap->flags) { 96764410Sbostic flags = 0; 96864410Sbostic if (uap->flags & R_OK) 96964410Sbostic flags |= VREAD; 97064410Sbostic if (uap->flags & W_OK) 97164410Sbostic flags |= VWRITE; 97264410Sbostic if (uap->flags & X_OK) 97364410Sbostic flags |= VEXEC; 97464410Sbostic if ((flags & VWRITE) == 0 || (error = vn_writechk(vp)) == 0) 97564410Sbostic error = VOP_ACCESS(vp, flags, cred, p); 9766254Sroot } 97737741Smckusick vput(vp); 97837741Smckusick out1: 97964585Sbostic cred->cr_uid = t_uid; 98064585Sbostic cred->cr_groups[0] = t_gid; 98147540Skarels return (error); 9826254Sroot } 9836254Sroot 98454348Smckusick #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 9856254Sroot /* 98664410Sbostic * Get file status; this version follows links. 98737Sbill */ 98854916Storek struct ostat_args { 98964410Sbostic char *path; 99054916Storek struct ostat *ub; 99154916Storek }; 99242441Smckusick /* ARGSUSED */ 99353759Smckusick ostat(p, uap, retval) 99445914Smckusick struct proc *p; 99554916Storek register struct ostat_args *uap; 99653468Smckusick int *retval; 99753468Smckusick { 99853468Smckusick struct stat sb; 99953468Smckusick struct ostat osb; 100053468Smckusick int error; 100153468Smckusick struct nameidata nd; 100253468Smckusick 100364410Sbostic NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); 100453468Smckusick if (error = namei(&nd)) 100553468Smckusick return (error); 100653468Smckusick error = vn_stat(nd.ni_vp, &sb, p); 100753468Smckusick vput(nd.ni_vp); 100853468Smckusick if (error) 100953468Smckusick return (error); 101053468Smckusick cvtstat(&sb, &osb); 101153468Smckusick error = copyout((caddr_t)&osb, (caddr_t)uap->ub, sizeof (osb)); 101253468Smckusick return (error); 101353468Smckusick } 101453468Smckusick 101553468Smckusick /* 101664410Sbostic * Get file status; this version does not follow links. 101753468Smckusick */ 101854916Storek struct olstat_args { 101964410Sbostic char *path; 102054916Storek struct ostat *ub; 102154916Storek }; 102253468Smckusick /* ARGSUSED */ 102353759Smckusick olstat(p, uap, retval) 102453468Smckusick struct proc *p; 102554916Storek register struct olstat_args *uap; 102653468Smckusick int *retval; 102753468Smckusick { 102853468Smckusick struct stat sb; 102953468Smckusick struct ostat osb; 103053468Smckusick int error; 103153468Smckusick struct nameidata nd; 103253468Smckusick 103364410Sbostic NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); 103453468Smckusick if (error = namei(&nd)) 103553468Smckusick return (error); 103653468Smckusick error = vn_stat(nd.ni_vp, &sb, p); 103753468Smckusick vput(nd.ni_vp); 103853468Smckusick if (error) 103953468Smckusick return (error); 104053468Smckusick cvtstat(&sb, &osb); 104153468Smckusick error = copyout((caddr_t)&osb, (caddr_t)uap->ub, sizeof (osb)); 104253468Smckusick return (error); 104353468Smckusick } 104453468Smckusick 104553468Smckusick /* 104664410Sbostic * Convert from an old to a new stat structure. 104753468Smckusick */ 104853468Smckusick cvtstat(st, ost) 104953468Smckusick struct stat *st; 105053468Smckusick struct ostat *ost; 105153468Smckusick { 105253468Smckusick 105353468Smckusick ost->st_dev = st->st_dev; 105453468Smckusick ost->st_ino = st->st_ino; 105553468Smckusick ost->st_mode = st->st_mode; 105653468Smckusick ost->st_nlink = st->st_nlink; 105753468Smckusick ost->st_uid = st->st_uid; 105853468Smckusick ost->st_gid = st->st_gid; 105953468Smckusick ost->st_rdev = st->st_rdev; 106053468Smckusick if (st->st_size < (quad_t)1 << 32) 106153468Smckusick ost->st_size = st->st_size; 106253468Smckusick else 106353468Smckusick ost->st_size = -2; 106453468Smckusick ost->st_atime = st->st_atime; 106553468Smckusick ost->st_mtime = st->st_mtime; 106653468Smckusick ost->st_ctime = st->st_ctime; 106753468Smckusick ost->st_blksize = st->st_blksize; 106853468Smckusick ost->st_blocks = st->st_blocks; 106953468Smckusick ost->st_flags = st->st_flags; 107053468Smckusick ost->st_gen = st->st_gen; 107153468Smckusick } 107254348Smckusick #endif /* COMPAT_43 || COMPAT_SUNOS */ 107353468Smckusick 107453468Smckusick /* 107564410Sbostic * Get file status; this version follows links. 107653468Smckusick */ 107754916Storek struct stat_args { 107864410Sbostic char *path; 107954916Storek struct stat *ub; 108054916Storek }; 108153468Smckusick /* ARGSUSED */ 108253759Smckusick stat(p, uap, retval) 108353468Smckusick struct proc *p; 108454916Storek register struct stat_args *uap; 108542441Smckusick int *retval; 108637Sbill { 108742441Smckusick struct stat sb; 108842441Smckusick int error; 108947540Skarels struct nameidata nd; 109037Sbill 109164410Sbostic NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); 109252322Smckusick if (error = namei(&nd)) 109347540Skarels return (error); 109452322Smckusick error = vn_stat(nd.ni_vp, &sb, p); 109552322Smckusick vput(nd.ni_vp); 109642441Smckusick if (error) 109747540Skarels return (error); 109842441Smckusick error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb)); 109947540Skarels return (error); 110037Sbill } 110137Sbill 110237Sbill /* 110364410Sbostic * Get file status; this version does not follow links. 11045992Swnj */ 110554916Storek struct lstat_args { 110664410Sbostic char *path; 110754916Storek struct stat *ub; 110854916Storek }; 110942441Smckusick /* ARGSUSED */ 111053759Smckusick lstat(p, uap, retval) 111145914Smckusick struct proc *p; 111254916Storek register struct lstat_args *uap; 111342441Smckusick int *retval; 111442441Smckusick { 111537741Smckusick int error; 111659373Smckusick struct vnode *vp, *dvp; 111759373Smckusick struct stat sb, sb1; 111847540Skarels struct nameidata nd; 11195992Swnj 112059373Smckusick NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | LOCKPARENT, UIO_USERSPACE, 112164410Sbostic uap->path, p); 112252322Smckusick if (error = namei(&nd)) 112347540Skarels return (error); 112459373Smckusick /* 112559373Smckusick * For symbolic links, always return the attributes of its 112659373Smckusick * containing directory, except for mode, size, and links. 112759373Smckusick */ 112859373Smckusick vp = nd.ni_vp; 112959373Smckusick dvp = nd.ni_dvp; 113059373Smckusick if (vp->v_type != VLNK) { 113159373Smckusick if (dvp == vp) 113259373Smckusick vrele(dvp); 113359373Smckusick else 113459373Smckusick vput(dvp); 113559373Smckusick error = vn_stat(vp, &sb, p); 113659373Smckusick vput(vp); 113759373Smckusick if (error) 113859373Smckusick return (error); 113959373Smckusick } else { 114059373Smckusick error = vn_stat(dvp, &sb, p); 114159373Smckusick vput(dvp); 114259373Smckusick if (error) { 114359373Smckusick vput(vp); 114459373Smckusick return (error); 114559373Smckusick } 114659373Smckusick error = vn_stat(vp, &sb1, p); 114759373Smckusick vput(vp); 114859373Smckusick if (error) 114959373Smckusick return (error); 115059373Smckusick sb.st_mode &= ~S_IFDIR; 115159373Smckusick sb.st_mode |= S_IFLNK; 115259373Smckusick sb.st_nlink = sb1.st_nlink; 115359373Smckusick sb.st_size = sb1.st_size; 115459373Smckusick sb.st_blocks = sb1.st_blocks; 115559373Smckusick } 115637741Smckusick error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb)); 115747540Skarels return (error); 11585992Swnj } 11595992Swnj 11605992Swnj /* 116164410Sbostic * Get configurable pathname variables. 116260414Smckusick */ 116360414Smckusick struct pathconf_args { 116464410Sbostic char *path; 116560414Smckusick int name; 116660414Smckusick }; 116760414Smckusick /* ARGSUSED */ 116860414Smckusick pathconf(p, uap, retval) 116960414Smckusick struct proc *p; 117060414Smckusick register struct pathconf_args *uap; 117160414Smckusick int *retval; 117260414Smckusick { 117360414Smckusick int error; 117460414Smckusick struct nameidata nd; 117560414Smckusick 117664410Sbostic NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); 117760414Smckusick if (error = namei(&nd)) 117860414Smckusick return (error); 117960414Smckusick error = VOP_PATHCONF(nd.ni_vp, uap->name, retval); 118060414Smckusick vput(nd.ni_vp); 118160414Smckusick return (error); 118260414Smckusick } 118360414Smckusick 118460414Smckusick /* 118549365Smckusick * Return target name of a symbolic link. 118637Sbill */ 118754916Storek struct readlink_args { 118864410Sbostic char *path; 118954916Storek char *buf; 119054916Storek int count; 119154916Storek }; 119242441Smckusick /* ARGSUSED */ 119342441Smckusick readlink(p, uap, retval) 119445914Smckusick struct proc *p; 119554916Storek register struct readlink_args *uap; 119642441Smckusick int *retval; 119742441Smckusick { 119837741Smckusick register struct vnode *vp; 119937741Smckusick struct iovec aiov; 120037741Smckusick struct uio auio; 120137741Smckusick int error; 120247540Skarels struct nameidata nd; 12035992Swnj 120464410Sbostic NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); 120552322Smckusick if (error = namei(&nd)) 120647540Skarels return (error); 120752322Smckusick vp = nd.ni_vp; 120864410Sbostic if (vp->v_type != VLNK) 120937741Smckusick error = EINVAL; 121064410Sbostic else { 121164410Sbostic aiov.iov_base = uap->buf; 121264410Sbostic aiov.iov_len = uap->count; 121364410Sbostic auio.uio_iov = &aiov; 121464410Sbostic auio.uio_iovcnt = 1; 121564410Sbostic auio.uio_offset = 0; 121664410Sbostic auio.uio_rw = UIO_READ; 121764410Sbostic auio.uio_segflg = UIO_USERSPACE; 121864410Sbostic auio.uio_procp = p; 121964410Sbostic auio.uio_resid = uap->count; 122064410Sbostic error = VOP_READLINK(vp, &auio, p->p_ucred); 12215992Swnj } 122237741Smckusick vput(vp); 122342441Smckusick *retval = uap->count - auio.uio_resid; 122447540Skarels return (error); 12255992Swnj } 12265992Swnj 12279167Ssam /* 122864410Sbostic * Change flags of a file given a path name. 122938259Smckusick */ 123054916Storek struct chflags_args { 123164410Sbostic char *path; 123254916Storek int flags; 123354916Storek }; 123442441Smckusick /* ARGSUSED */ 123542441Smckusick chflags(p, uap, retval) 123645914Smckusick struct proc *p; 123754916Storek register struct chflags_args *uap; 123842441Smckusick int *retval; 123942441Smckusick { 124038259Smckusick register struct vnode *vp; 124138259Smckusick struct vattr vattr; 124238259Smckusick int error; 124347540Skarels struct nameidata nd; 124438259Smckusick 124564410Sbostic NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); 124652322Smckusick if (error = namei(&nd)) 124747540Skarels return (error); 124852322Smckusick vp = nd.ni_vp; 124959382Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 125059382Smckusick VOP_LOCK(vp); 125164410Sbostic if (vp->v_mount->mnt_flag & MNT_RDONLY) 125238259Smckusick error = EROFS; 125364410Sbostic else { 125464410Sbostic VATTR_NULL(&vattr); 125564410Sbostic vattr.va_flags = uap->flags; 125664410Sbostic error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 125738259Smckusick } 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; 128359382Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 128438259Smckusick VOP_LOCK(vp); 128564410Sbostic if (vp->v_mount->mnt_flag & MNT_RDONLY) 128638259Smckusick error = EROFS; 128764410Sbostic else { 128864410Sbostic VATTR_NULL(&vattr); 128964410Sbostic vattr.va_flags = uap->flags; 129064410Sbostic error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 129138259Smckusick } 129238259Smckusick VOP_UNLOCK(vp); 129347540Skarels return (error); 129438259Smckusick } 129538259Smckusick 129638259Smckusick /* 12979167Ssam * Change mode of a file given path name. 12989167Ssam */ 129954916Storek struct chmod_args { 130064410Sbostic char *path; 130164410Sbostic int mode; 130254916Storek }; 130342441Smckusick /* ARGSUSED */ 130442441Smckusick chmod(p, uap, retval) 130545914Smckusick struct proc *p; 130654916Storek register struct chmod_args *uap; 130742441Smckusick int *retval; 130842441Smckusick { 130937741Smckusick register struct vnode *vp; 131037741Smckusick struct vattr vattr; 131137741Smckusick int error; 131247540Skarels struct nameidata nd; 13135992Swnj 131464410Sbostic NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); 131552322Smckusick if (error = namei(&nd)) 131647540Skarels return (error); 131752322Smckusick vp = nd.ni_vp; 131859382Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 131959382Smckusick VOP_LOCK(vp); 132064410Sbostic if (vp->v_mount->mnt_flag & MNT_RDONLY) 132137741Smckusick error = EROFS; 132264410Sbostic else { 132364410Sbostic VATTR_NULL(&vattr); 132464410Sbostic vattr.va_mode = uap->mode & ALLPERMS; 132564410Sbostic error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 132637741Smckusick } 132737741Smckusick vput(vp); 132847540Skarels return (error); 13297701Ssam } 13307439Sroot 13319167Ssam /* 13329167Ssam * Change mode of a file given a file descriptor. 13339167Ssam */ 133454916Storek struct fchmod_args { 133554916Storek int fd; 133664410Sbostic int mode; 133754916Storek }; 133842441Smckusick /* ARGSUSED */ 133942441Smckusick fchmod(p, uap, retval) 134045914Smckusick struct proc *p; 134154916Storek register struct fchmod_args *uap; 134242441Smckusick int *retval; 134342441Smckusick { 134437741Smckusick struct vattr vattr; 134537741Smckusick struct vnode *vp; 134637741Smckusick struct file *fp; 134737741Smckusick int error; 13487701Ssam 134945914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 135047540Skarels return (error); 135137741Smckusick vp = (struct vnode *)fp->f_data; 135259382Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 135337741Smckusick VOP_LOCK(vp); 135464410Sbostic if (vp->v_mount->mnt_flag & MNT_RDONLY) 135537741Smckusick error = EROFS; 135664410Sbostic else { 135764410Sbostic VATTR_NULL(&vattr); 135864410Sbostic vattr.va_mode = uap->mode & ALLPERMS; 135964410Sbostic error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 13607439Sroot } 136137741Smckusick VOP_UNLOCK(vp); 136247540Skarels return (error); 13635992Swnj } 13645992Swnj 13659167Ssam /* 13669167Ssam * Set ownership given a path name. 13679167Ssam */ 136854916Storek struct chown_args { 136964410Sbostic char *path; 137054916Storek int uid; 137154916Storek int gid; 137254916Storek }; 137342441Smckusick /* ARGSUSED */ 137442441Smckusick chown(p, uap, retval) 137545914Smckusick struct proc *p; 137654916Storek register struct chown_args *uap; 137742441Smckusick int *retval; 137842441Smckusick { 137937741Smckusick register struct vnode *vp; 138037741Smckusick struct vattr vattr; 138137741Smckusick int error; 138247540Skarels struct nameidata nd; 138337Sbill 138464410Sbostic NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, uap->path, p); 138552322Smckusick if (error = namei(&nd)) 138647540Skarels return (error); 138752322Smckusick vp = nd.ni_vp; 138859382Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 138959382Smckusick VOP_LOCK(vp); 139064410Sbostic if (vp->v_mount->mnt_flag & MNT_RDONLY) 139137741Smckusick error = EROFS; 139264410Sbostic else { 139364410Sbostic VATTR_NULL(&vattr); 139464410Sbostic vattr.va_uid = uap->uid; 139564410Sbostic vattr.va_gid = uap->gid; 139664410Sbostic error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 139737741Smckusick } 139837741Smckusick vput(vp); 139947540Skarels return (error); 14007701Ssam } 14017439Sroot 14029167Ssam /* 14039167Ssam * Set ownership given a file descriptor. 14049167Ssam */ 140554916Storek struct fchown_args { 140654916Storek int fd; 140754916Storek int uid; 140854916Storek int gid; 140954916Storek }; 141042441Smckusick /* ARGSUSED */ 141142441Smckusick fchown(p, uap, retval) 141245914Smckusick struct proc *p; 141354916Storek register struct fchown_args *uap; 141442441Smckusick int *retval; 141542441Smckusick { 141637741Smckusick struct vattr vattr; 141737741Smckusick struct vnode *vp; 141837741Smckusick struct file *fp; 141937741Smckusick int error; 14207701Ssam 142145914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 142247540Skarels return (error); 142337741Smckusick vp = (struct vnode *)fp->f_data; 142459382Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 142537741Smckusick VOP_LOCK(vp); 142664410Sbostic if (vp->v_mount->mnt_flag & MNT_RDONLY) 142737741Smckusick error = EROFS; 142864410Sbostic else { 142964410Sbostic VATTR_NULL(&vattr); 143064410Sbostic vattr.va_uid = uap->uid; 143164410Sbostic vattr.va_gid = uap->gid; 143264410Sbostic error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 143337741Smckusick } 143437741Smckusick VOP_UNLOCK(vp); 143547540Skarels return (error); 14367701Ssam } 14377701Ssam 143842441Smckusick /* 143942441Smckusick * Set the access and modification times of a file. 144042441Smckusick */ 144154916Storek struct utimes_args { 144264410Sbostic char *path; 144354916Storek struct timeval *tptr; 144454916Storek }; 144542441Smckusick /* ARGSUSED */ 144642441Smckusick utimes(p, uap, retval) 144745914Smckusick struct proc *p; 144854916Storek register struct utimes_args *uap; 144942441Smckusick int *retval; 145042441Smckusick { 145137741Smckusick register struct vnode *vp; 145211811Ssam struct timeval tv[2]; 145337741Smckusick struct vattr vattr; 145458840Storek int error; 145547540Skarels struct nameidata nd; 145611811Ssam 145758505Sbostic VATTR_NULL(&vattr); 145858505Sbostic if (uap->tptr == NULL) { 145958505Sbostic microtime(&tv[0]); 146058505Sbostic tv[1] = tv[0]; 146158548Sbostic vattr.va_vaflags |= VA_UTIMES_NULL; 146258505Sbostic } else if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv))) 146358505Sbostic return (error); 146464410Sbostic NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); 146552322Smckusick if (error = namei(&nd)) 146647540Skarels return (error); 146752322Smckusick vp = nd.ni_vp; 146859382Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 146959382Smckusick VOP_LOCK(vp); 147064410Sbostic if (vp->v_mount->mnt_flag & MNT_RDONLY) 147137741Smckusick error = EROFS; 147264410Sbostic else { 147364410Sbostic vattr.va_atime.ts_sec = tv[0].tv_sec; 147464410Sbostic vattr.va_atime.ts_nsec = tv[0].tv_usec * 1000; 147564410Sbostic vattr.va_mtime.ts_sec = tv[1].tv_sec; 147664410Sbostic vattr.va_mtime.ts_nsec = tv[1].tv_usec * 1000; 147764410Sbostic error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 147821015Smckusick } 147937741Smckusick vput(vp); 148047540Skarels return (error); 148111811Ssam } 148211811Ssam 148364410Sbostic /* 148464410Sbostic * Truncate a file given its path name. 148564410Sbostic */ 148660428Smckusick struct truncate_args { 148764410Sbostic char *path; 148854863Storek int pad; 148954863Storek off_t length; 149054863Storek }; 149153468Smckusick /* ARGSUSED */ 149260414Smckusick truncate(p, uap, retval) 149353468Smckusick struct proc *p; 149460428Smckusick register struct truncate_args *uap; 149553468Smckusick int *retval; 149653468Smckusick { 149737741Smckusick register struct vnode *vp; 149837741Smckusick struct vattr vattr; 149937741Smckusick int error; 150047540Skarels struct nameidata nd; 15017701Ssam 150264410Sbostic NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); 150352322Smckusick if (error = namei(&nd)) 150447540Skarels return (error); 150552322Smckusick vp = nd.ni_vp; 150659382Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 150759382Smckusick VOP_LOCK(vp); 150864410Sbostic if (vp->v_type == VDIR) 150937741Smckusick error = EISDIR; 151064410Sbostic else if ((error = vn_writechk(vp)) == 0 && 151164410Sbostic (error = VOP_ACCESS(vp, VWRITE, p->p_ucred, p)) == 0) { 151264410Sbostic VATTR_NULL(&vattr); 151364410Sbostic vattr.va_size = uap->length; 151464410Sbostic error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 15157701Ssam } 151637741Smckusick vput(vp); 151747540Skarels return (error); 15187701Ssam } 15197701Ssam 152064410Sbostic /* 152164410Sbostic * Truncate a file given a file descriptor. 152264410Sbostic */ 152360428Smckusick struct ftruncate_args { 152454863Storek int fd; 152554863Storek int pad; 152654863Storek off_t length; 152754863Storek }; 152842441Smckusick /* ARGSUSED */ 152960414Smckusick ftruncate(p, uap, retval) 153045914Smckusick struct proc *p; 153160428Smckusick register struct ftruncate_args *uap; 153242441Smckusick int *retval; 153342441Smckusick { 153437741Smckusick struct vattr vattr; 153537741Smckusick struct vnode *vp; 15367701Ssam struct file *fp; 153737741Smckusick int error; 15387701Ssam 153945914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 154047540Skarels return (error); 154137741Smckusick if ((fp->f_flag & FWRITE) == 0) 154247540Skarels return (EINVAL); 154337741Smckusick vp = (struct vnode *)fp->f_data; 154459382Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 154537741Smckusick VOP_LOCK(vp); 154664410Sbostic if (vp->v_type == VDIR) 154737741Smckusick error = EISDIR; 154864410Sbostic else if ((error = vn_writechk(vp)) == 0) { 154964410Sbostic VATTR_NULL(&vattr); 155064410Sbostic vattr.va_size = uap->length; 155164410Sbostic error = VOP_SETATTR(vp, &vattr, fp->f_cred, p); 15527701Ssam } 155337741Smckusick VOP_UNLOCK(vp); 155447540Skarels return (error); 15557701Ssam } 15567701Ssam 155754863Storek #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 15589167Ssam /* 155954863Storek * Truncate a file given its path name. 156054863Storek */ 156160428Smckusick struct otruncate_args { 156264410Sbostic char *path; 156354916Storek long length; 156454916Storek }; 156554863Storek /* ARGSUSED */ 156660105Smckusick otruncate(p, uap, retval) 156754863Storek struct proc *p; 156860428Smckusick register struct otruncate_args *uap; 156954863Storek int *retval; 157054863Storek { 157160428Smckusick struct truncate_args nuap; 157254863Storek 157364410Sbostic nuap.path = uap->path; 157454863Storek nuap.length = uap->length; 157560428Smckusick return (truncate(p, &nuap, retval)); 157654863Storek } 157754863Storek 157854863Storek /* 157954863Storek * Truncate a file given a file descriptor. 158054863Storek */ 158160428Smckusick struct oftruncate_args { 158254916Storek int fd; 158354916Storek long length; 158454916Storek }; 158554863Storek /* ARGSUSED */ 158660105Smckusick oftruncate(p, uap, retval) 158754863Storek struct proc *p; 158860428Smckusick register struct oftruncate_args *uap; 158954863Storek int *retval; 159054863Storek { 159160428Smckusick struct ftruncate_args nuap; 159254863Storek 159354863Storek nuap.fd = uap->fd; 159454863Storek nuap.length = uap->length; 159560428Smckusick return (ftruncate(p, &nuap, retval)); 159654863Storek } 159754863Storek #endif /* COMPAT_43 || COMPAT_SUNOS */ 159854863Storek 159954863Storek /* 160064410Sbostic * Sync an open file. 16019167Ssam */ 160254916Storek struct fsync_args { 160354916Storek int fd; 160454916Storek }; 160542441Smckusick /* ARGSUSED */ 160642441Smckusick fsync(p, uap, retval) 160745914Smckusick struct proc *p; 160854916Storek struct fsync_args *uap; 160942441Smckusick int *retval; 16109167Ssam { 161139592Smckusick register struct vnode *vp; 16129167Ssam struct file *fp; 161337741Smckusick int error; 16149167Ssam 161545914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 161647540Skarels return (error); 161739592Smckusick vp = (struct vnode *)fp->f_data; 161839592Smckusick VOP_LOCK(vp); 161954441Smckusick error = VOP_FSYNC(vp, fp->f_cred, MNT_WAIT, p); 162039592Smckusick VOP_UNLOCK(vp); 162147540Skarels return (error); 16229167Ssam } 16239167Ssam 16249167Ssam /* 162564410Sbostic * Rename files. Source and destination must either both be directories, 162664410Sbostic * or both not be directories. If target is a directory, it must be empty. 16279167Ssam */ 162854916Storek struct rename_args { 162954916Storek char *from; 163054916Storek char *to; 163154916Storek }; 163242441Smckusick /* ARGSUSED */ 163342441Smckusick rename(p, uap, retval) 163445914Smckusick struct proc *p; 163554916Storek register struct rename_args *uap; 163642441Smckusick int *retval; 163742441Smckusick { 163837741Smckusick register struct vnode *tvp, *fvp, *tdvp; 163949735Smckusick struct nameidata fromnd, tond; 164037741Smckusick int error; 16417701Ssam 164252322Smckusick NDINIT(&fromnd, DELETE, WANTPARENT | SAVESTART, UIO_USERSPACE, 164352322Smckusick uap->from, p); 164452322Smckusick if (error = namei(&fromnd)) 164547540Skarels return (error); 164649735Smckusick fvp = fromnd.ni_vp; 164752322Smckusick NDINIT(&tond, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART, 164852322Smckusick UIO_USERSPACE, uap->to, p); 164952322Smckusick if (error = namei(&tond)) { 165052230Sheideman VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 165149735Smckusick vrele(fromnd.ni_dvp); 165242465Smckusick vrele(fvp); 165342465Smckusick goto out1; 165442465Smckusick } 165537741Smckusick tdvp = tond.ni_dvp; 165637741Smckusick tvp = tond.ni_vp; 165737741Smckusick if (tvp != NULL) { 165837741Smckusick if (fvp->v_type == VDIR && tvp->v_type != VDIR) { 165939242Sbostic error = ENOTDIR; 166037741Smckusick goto out; 166137741Smckusick } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) { 166239242Sbostic error = EISDIR; 166337741Smckusick goto out; 16649167Ssam } 16659167Ssam } 166639286Smckusick if (fvp == tdvp) 166737741Smckusick error = EINVAL; 166839286Smckusick /* 166949735Smckusick * If source is the same as the destination (that is the 167049735Smckusick * same inode number with the same name in the same directory), 167139286Smckusick * then there is nothing to do. 167239286Smckusick */ 167349735Smckusick if (fvp == tvp && fromnd.ni_dvp == tdvp && 167452322Smckusick fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen && 167552322Smckusick !bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr, 167652322Smckusick fromnd.ni_cnd.cn_namelen)) 167739286Smckusick error = -1; 167837741Smckusick out: 167942465Smckusick if (!error) { 168052192Smckusick LEASE_CHECK(tdvp, p, p->p_ucred, LEASE_WRITE); 168152192Smckusick if (fromnd.ni_dvp != tdvp) 168252192Smckusick LEASE_CHECK(fromnd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 168352192Smckusick if (tvp) 168452192Smckusick LEASE_CHECK(tvp, p, p->p_ucred, LEASE_WRITE); 168552230Sheideman error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd, 168652230Sheideman tond.ni_dvp, tond.ni_vp, &tond.ni_cnd); 168742465Smckusick } else { 168852230Sheideman VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd); 168943344Smckusick if (tdvp == tvp) 169043344Smckusick vrele(tdvp); 169143344Smckusick else 169243344Smckusick vput(tdvp); 169342465Smckusick if (tvp) 169442465Smckusick vput(tvp); 169552230Sheideman VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 169649735Smckusick vrele(fromnd.ni_dvp); 169742465Smckusick vrele(fvp); 16989167Ssam } 169949735Smckusick vrele(tond.ni_startdir); 170052322Smckusick FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI); 170137741Smckusick out1: 170249735Smckusick vrele(fromnd.ni_startdir); 170352322Smckusick FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI); 170439286Smckusick if (error == -1) 170547540Skarels return (0); 170647540Skarels return (error); 17077701Ssam } 17087701Ssam 17097535Sroot /* 171064410Sbostic * Make a directory file. 171112756Ssam */ 171254916Storek struct mkdir_args { 171364410Sbostic char *path; 171464410Sbostic int mode; 171554916Storek }; 171642441Smckusick /* ARGSUSED */ 171742441Smckusick mkdir(p, uap, retval) 171845914Smckusick struct proc *p; 171954916Storek register struct mkdir_args *uap; 172042441Smckusick int *retval; 172142441Smckusick { 172237741Smckusick register struct vnode *vp; 172337741Smckusick struct vattr vattr; 172437741Smckusick int error; 172547540Skarels struct nameidata nd; 172612756Ssam 172764410Sbostic NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->path, p); 172852322Smckusick if (error = namei(&nd)) 172947540Skarels return (error); 173052322Smckusick vp = nd.ni_vp; 173137741Smckusick if (vp != NULL) { 173252322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 173352322Smckusick if (nd.ni_dvp == vp) 173452322Smckusick vrele(nd.ni_dvp); 173543344Smckusick else 173652322Smckusick vput(nd.ni_dvp); 173742465Smckusick vrele(vp); 173847540Skarels return (EEXIST); 173912756Ssam } 174041362Smckusick VATTR_NULL(&vattr); 174137741Smckusick vattr.va_type = VDIR; 174264410Sbostic vattr.va_mode = (uap->mode & ACCESSPERMS) &~ p->p_fd->fd_cmask; 174352322Smckusick LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 174452322Smckusick error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr); 174538145Smckusick if (!error) 174652322Smckusick vput(nd.ni_vp); 174747540Skarels return (error); 174812756Ssam } 174912756Ssam 175012756Ssam /* 175164410Sbostic * Remove a directory file. 175212756Ssam */ 175354916Storek struct rmdir_args { 175464410Sbostic char *path; 175554916Storek }; 175642441Smckusick /* ARGSUSED */ 175742441Smckusick rmdir(p, uap, retval) 175845914Smckusick struct proc *p; 175954916Storek struct rmdir_args *uap; 176042441Smckusick int *retval; 176112756Ssam { 176237741Smckusick register struct vnode *vp; 176337741Smckusick int error; 176447540Skarels struct nameidata nd; 176512756Ssam 176664410Sbostic NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE, uap->path, p); 176752322Smckusick if (error = namei(&nd)) 176847540Skarels return (error); 176952322Smckusick vp = nd.ni_vp; 177037741Smckusick if (vp->v_type != VDIR) { 177137741Smckusick error = ENOTDIR; 177212756Ssam goto out; 177312756Ssam } 177412756Ssam /* 177537741Smckusick * No rmdir "." please. 177612756Ssam */ 177752322Smckusick if (nd.ni_dvp == vp) { 177837741Smckusick error = EINVAL; 177912756Ssam goto out; 178012756Ssam } 178112756Ssam /* 178249365Smckusick * The root of a mounted filesystem cannot be deleted. 178312756Ssam */ 178437741Smckusick if (vp->v_flag & VROOT) 178537741Smckusick error = EBUSY; 178612756Ssam out: 178742465Smckusick if (!error) { 178852322Smckusick LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 178952192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 179052322Smckusick error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); 179142465Smckusick } else { 179252322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 179352322Smckusick if (nd.ni_dvp == vp) 179452322Smckusick vrele(nd.ni_dvp); 179543344Smckusick else 179652322Smckusick vput(nd.ni_dvp); 179742465Smckusick vput(vp); 179842465Smckusick } 179947540Skarels return (error); 180012756Ssam } 180112756Ssam 180254620Smckusick #ifdef COMPAT_43 180337741Smckusick /* 180449365Smckusick * Read a block of directory entries in a file system independent format. 180537741Smckusick */ 180654916Storek struct ogetdirentries_args { 180754916Storek int fd; 180854916Storek char *buf; 180964410Sbostic u_int count; 181054916Storek long *basep; 181154916Storek }; 181254620Smckusick ogetdirentries(p, uap, retval) 181354620Smckusick struct proc *p; 181454916Storek register struct ogetdirentries_args *uap; 181554620Smckusick int *retval; 181654620Smckusick { 181754620Smckusick register struct vnode *vp; 181854620Smckusick struct file *fp; 181954620Smckusick struct uio auio, kuio; 182054620Smckusick struct iovec aiov, kiov; 182154620Smckusick struct dirent *dp, *edp; 182254620Smckusick caddr_t dirbuf; 182354620Smckusick int error, readcnt; 182454969Smckusick long loff; 182554620Smckusick 182654620Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 182754620Smckusick return (error); 182854620Smckusick if ((fp->f_flag & FREAD) == 0) 182954620Smckusick return (EBADF); 183054620Smckusick vp = (struct vnode *)fp->f_data; 183154620Smckusick if (vp->v_type != VDIR) 183254620Smckusick return (EINVAL); 183354620Smckusick aiov.iov_base = uap->buf; 183454620Smckusick aiov.iov_len = uap->count; 183554620Smckusick auio.uio_iov = &aiov; 183654620Smckusick auio.uio_iovcnt = 1; 183754620Smckusick auio.uio_rw = UIO_READ; 183854620Smckusick auio.uio_segflg = UIO_USERSPACE; 183954620Smckusick auio.uio_procp = p; 184054620Smckusick auio.uio_resid = uap->count; 184154620Smckusick VOP_LOCK(vp); 184254969Smckusick loff = auio.uio_offset = fp->f_offset; 184354620Smckusick # if (BYTE_ORDER != LITTLE_ENDIAN) 184456339Smckusick if (vp->v_mount->mnt_maxsymlinklen <= 0) { 184554620Smckusick error = VOP_READDIR(vp, &auio, fp->f_cred); 184656339Smckusick fp->f_offset = auio.uio_offset; 184756339Smckusick } else 184854620Smckusick # endif 184954620Smckusick { 185054620Smckusick kuio = auio; 185154620Smckusick kuio.uio_iov = &kiov; 185254620Smckusick kuio.uio_segflg = UIO_SYSSPACE; 185354620Smckusick kiov.iov_len = uap->count; 185454620Smckusick MALLOC(dirbuf, caddr_t, uap->count, M_TEMP, M_WAITOK); 185554620Smckusick kiov.iov_base = dirbuf; 185654620Smckusick error = VOP_READDIR(vp, &kuio, fp->f_cred); 185756339Smckusick fp->f_offset = kuio.uio_offset; 185854620Smckusick if (error == 0) { 185954620Smckusick readcnt = uap->count - kuio.uio_resid; 186054620Smckusick edp = (struct dirent *)&dirbuf[readcnt]; 186154620Smckusick for (dp = (struct dirent *)dirbuf; dp < edp; ) { 186254620Smckusick # if (BYTE_ORDER == LITTLE_ENDIAN) 186354969Smckusick /* 186455009Smckusick * The expected low byte of 186555009Smckusick * dp->d_namlen is our dp->d_type. 186655009Smckusick * The high MBZ byte of dp->d_namlen 186755009Smckusick * is our dp->d_namlen. 186854969Smckusick */ 186955009Smckusick dp->d_type = dp->d_namlen; 187055009Smckusick dp->d_namlen = 0; 187155009Smckusick # else 187255009Smckusick /* 187355009Smckusick * The dp->d_type is the high byte 187455009Smckusick * of the expected dp->d_namlen, 187555009Smckusick * so must be zero'ed. 187655009Smckusick */ 187755009Smckusick dp->d_type = 0; 187854620Smckusick # endif 187954620Smckusick if (dp->d_reclen > 0) { 188054620Smckusick dp = (struct dirent *) 188154620Smckusick ((char *)dp + dp->d_reclen); 188254620Smckusick } else { 188354620Smckusick error = EIO; 188454620Smckusick break; 188554620Smckusick } 188654620Smckusick } 188754620Smckusick if (dp >= edp) 188854620Smckusick error = uiomove(dirbuf, readcnt, &auio); 188954620Smckusick } 189054620Smckusick FREE(dirbuf, M_TEMP); 189154620Smckusick } 189254620Smckusick VOP_UNLOCK(vp); 189354620Smckusick if (error) 189454620Smckusick return (error); 189554969Smckusick error = copyout((caddr_t)&loff, (caddr_t)uap->basep, sizeof(long)); 189654620Smckusick *retval = uap->count - auio.uio_resid; 189754620Smckusick return (error); 189854620Smckusick } 189954620Smckusick #endif 190054620Smckusick 190154620Smckusick /* 190254620Smckusick * Read a block of directory entries in a file system independent format. 190354620Smckusick */ 190454916Storek struct getdirentries_args { 190554916Storek int fd; 190654916Storek char *buf; 190764410Sbostic u_int count; 190854916Storek long *basep; 190954916Storek }; 191042441Smckusick getdirentries(p, uap, retval) 191145914Smckusick struct proc *p; 191254916Storek register struct getdirentries_args *uap; 191342441Smckusick int *retval; 191442441Smckusick { 191539592Smckusick register struct vnode *vp; 191616540Ssam struct file *fp; 191737741Smckusick struct uio auio; 191837741Smckusick struct iovec aiov; 191954969Smckusick long loff; 192054441Smckusick int error; 192112756Ssam 192245914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 192347540Skarels return (error); 192437741Smckusick if ((fp->f_flag & FREAD) == 0) 192547540Skarels return (EBADF); 192639592Smckusick vp = (struct vnode *)fp->f_data; 192755451Spendry unionread: 192839592Smckusick if (vp->v_type != VDIR) 192947540Skarels return (EINVAL); 193037741Smckusick aiov.iov_base = uap->buf; 193137741Smckusick aiov.iov_len = uap->count; 193237741Smckusick auio.uio_iov = &aiov; 193337741Smckusick auio.uio_iovcnt = 1; 193437741Smckusick auio.uio_rw = UIO_READ; 193537741Smckusick auio.uio_segflg = UIO_USERSPACE; 193648026Smckusick auio.uio_procp = p; 193737741Smckusick auio.uio_resid = uap->count; 193839592Smckusick VOP_LOCK(vp); 193954969Smckusick loff = auio.uio_offset = fp->f_offset; 194054441Smckusick error = VOP_READDIR(vp, &auio, fp->f_cred); 194139592Smckusick fp->f_offset = auio.uio_offset; 194239592Smckusick VOP_UNLOCK(vp); 194339592Smckusick if (error) 194447540Skarels return (error); 194555451Spendry if ((uap->count == auio.uio_resid) && 194655451Spendry (vp->v_flag & VROOT) && 194755451Spendry (vp->v_mount->mnt_flag & MNT_UNION)) { 194855451Spendry struct vnode *tvp = vp; 194955451Spendry vp = vp->v_mount->mnt_vnodecovered; 195055451Spendry VREF(vp); 195155451Spendry fp->f_data = (caddr_t) vp; 195255451Spendry fp->f_offset = 0; 195355451Spendry vrele(tvp); 195455451Spendry goto unionread; 195555451Spendry } 195654969Smckusick error = copyout((caddr_t)&loff, (caddr_t)uap->basep, sizeof(long)); 195742441Smckusick *retval = uap->count - auio.uio_resid; 195847540Skarels return (error); 195912756Ssam } 196012756Ssam 196112756Ssam /* 196249365Smckusick * Set the mode mask for creation of filesystem nodes. 196312756Ssam */ 196454916Storek struct umask_args { 196564410Sbostic int newmask; 196654916Storek }; 196754916Storek mode_t /* XXX */ 196842441Smckusick umask(p, uap, retval) 196945914Smckusick struct proc *p; 197054916Storek struct umask_args *uap; 197142441Smckusick int *retval; 197212756Ssam { 197364410Sbostic register struct filedesc *fdp; 197412756Ssam 197564410Sbostic fdp = p->p_fd; 197645914Smckusick *retval = fdp->fd_cmask; 197764410Sbostic fdp->fd_cmask = uap->newmask & ALLPERMS; 197847540Skarels return (0); 197912756Ssam } 198037741Smckusick 198139566Smarc /* 198239566Smarc * Void all references to file by ripping underlying filesystem 198339566Smarc * away from vnode. 198439566Smarc */ 198554916Storek struct revoke_args { 198664410Sbostic char *path; 198754916Storek }; 198842441Smckusick /* ARGSUSED */ 198942441Smckusick revoke(p, uap, retval) 199045914Smckusick struct proc *p; 199154916Storek register struct revoke_args *uap; 199242441Smckusick int *retval; 199342441Smckusick { 199439566Smarc register struct vnode *vp; 199539566Smarc struct vattr vattr; 199639566Smarc int error; 199747540Skarels struct nameidata nd; 199839566Smarc 199964410Sbostic NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); 200052322Smckusick if (error = namei(&nd)) 200147540Skarels return (error); 200252322Smckusick vp = nd.ni_vp; 200339566Smarc if (vp->v_type != VCHR && vp->v_type != VBLK) { 200439566Smarc error = EINVAL; 200539566Smarc goto out; 200639566Smarc } 200748026Smckusick if (error = VOP_GETATTR(vp, &vattr, p->p_ucred, p)) 200839566Smarc goto out; 200947540Skarels if (p->p_ucred->cr_uid != vattr.va_uid && 201047540Skarels (error = suser(p->p_ucred, &p->p_acflag))) 201139566Smarc goto out; 201239805Smckusick if (vp->v_usecount > 1 || (vp->v_flag & VALIASED)) 201339632Smckusick vgoneall(vp); 201439566Smarc out: 201539566Smarc vrele(vp); 201647540Skarels return (error); 201739566Smarc } 201839566Smarc 201949365Smckusick /* 202049365Smckusick * Convert a user file descriptor to a kernel file entry. 202149365Smckusick */ 202264410Sbostic getvnode(fdp, fd, fpp) 202345914Smckusick struct filedesc *fdp; 202437741Smckusick struct file **fpp; 202564410Sbostic int fd; 202637741Smckusick { 202737741Smckusick struct file *fp; 202837741Smckusick 202964410Sbostic if ((u_int)fd >= fdp->fd_nfiles || 203064410Sbostic (fp = fdp->fd_ofiles[fd]) == NULL) 203137741Smckusick return (EBADF); 203237741Smckusick if (fp->f_type != DTYPE_VNODE) 203337741Smckusick return (EINVAL); 203437741Smckusick *fpp = fp; 203537741Smckusick return (0); 203637741Smckusick } 2037