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*64410Sbostic * @(#)vfs_syscalls.c 8.2 (Berkeley) 09/05/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 27*64410Sbostic static int change_dir __P((struct nameidata *ndp, struct proc *p)); 28*64410Sbostic 2937741Smckusick /* 3037741Smckusick * Virtual File System System Calls 3137741Smckusick */ 3212756Ssam 339167Ssam /* 34*64410Sbostic * Mount a file system. 359167Ssam */ 3654916Storek struct mount_args { 3754916Storek int type; 38*64410Sbostic 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 */ 61*64410Sbostic 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 } 96*64410Sbostic 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 } 113*64410Sbostic 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 */ 136*64410Sbostic 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 */ 15041400Smckusick mp->mnt_next = rootfs->mnt_next; 15141400Smckusick mp->mnt_prev = rootfs; 15241400Smckusick rootfs->mnt_next = mp; 15341400Smckusick mp->mnt_next->mnt_prev = mp; 15437741Smckusick cache_purge(vp); 15537741Smckusick if (!error) { 15639335Smckusick VOP_UNLOCK(vp); 15737741Smckusick vfs_unlock(mp); 15848026Smckusick error = VFS_START(mp, 0, p); 15937741Smckusick } else { 16037741Smckusick vfs_remove(mp); 16137741Smckusick free((caddr_t)mp, M_MOUNT); 16239335Smckusick vput(vp); 16337741Smckusick } 16447540Skarels return (error); 1656254Sroot } 1666254Sroot 1679167Ssam /* 168*64410Sbostic * Unmount a file system. 16937741Smckusick * 17037741Smckusick * Note: unmount takes a path to the vnode mounted on as argument, 17137741Smckusick * not special file (as before). 1729167Ssam */ 17354916Storek struct unmount_args { 174*64410Sbostic char *path; 17554916Storek int flags; 17654916Storek }; 17742441Smckusick /* ARGSUSED */ 17842441Smckusick unmount(p, uap, retval) 17945914Smckusick struct proc *p; 18054916Storek register struct unmount_args *uap; 18142441Smckusick int *retval; 18242441Smckusick { 18337741Smckusick register struct vnode *vp; 18439356Smckusick struct mount *mp; 18537741Smckusick int error; 18647540Skarels struct nameidata nd; 1876254Sroot 18837741Smckusick /* 18937741Smckusick * Must be super user 19037741Smckusick */ 19147540Skarels if (error = suser(p->p_ucred, &p->p_acflag)) 19247540Skarels return (error); 19337741Smckusick 194*64410Sbostic NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); 19552322Smckusick if (error = namei(&nd)) 19647540Skarels return (error); 19752322Smckusick vp = nd.ni_vp; 19837741Smckusick /* 19937741Smckusick * Must be the root of the filesystem 20037741Smckusick */ 20137741Smckusick if ((vp->v_flag & VROOT) == 0) { 20237741Smckusick vput(vp); 20347540Skarels return (EINVAL); 20437741Smckusick } 20537741Smckusick mp = vp->v_mount; 20637741Smckusick vput(vp); 20748026Smckusick return (dounmount(mp, uap->flags, p)); 20839356Smckusick } 20939356Smckusick 21039356Smckusick /* 211*64410Sbostic * Do the actual file system unmount. 21239356Smckusick */ 21348026Smckusick dounmount(mp, flags, p) 21439356Smckusick register struct mount *mp; 21539356Smckusick int flags; 21648026Smckusick struct proc *p; 21739356Smckusick { 21839356Smckusick struct vnode *coveredvp; 21939356Smckusick int error; 22039356Smckusick 22141400Smckusick coveredvp = mp->mnt_vnodecovered; 22241298Smckusick if (vfs_busy(mp)) 22341298Smckusick return (EBUSY); 22441400Smckusick mp->mnt_flag |= MNT_UNMOUNT; 22537741Smckusick if (error = vfs_lock(mp)) 22639356Smckusick return (error); 22737741Smckusick 22845738Smckusick vnode_pager_umount(mp); /* release cached vnodes */ 22937741Smckusick cache_purgevfs(mp); /* remove cache entries for this file sys */ 23054441Smckusick if ((error = VFS_SYNC(mp, MNT_WAIT, p->p_ucred, p)) == 0 || 23154441Smckusick (flags & MNT_FORCE)) 23248026Smckusick error = VFS_UNMOUNT(mp, flags, p); 23341400Smckusick mp->mnt_flag &= ~MNT_UNMOUNT; 23441298Smckusick vfs_unbusy(mp); 23537741Smckusick if (error) { 23637741Smckusick vfs_unlock(mp); 23737741Smckusick } else { 23837741Smckusick vrele(coveredvp); 23937741Smckusick vfs_remove(mp); 24052287Smckusick if (mp->mnt_mounth != 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 { 26437741Smckusick register struct mount *mp; 26541298Smckusick struct mount *omp; 26637741Smckusick 26737741Smckusick mp = rootfs; 26837741Smckusick do { 26940343Smckusick /* 27040343Smckusick * The lock check below is to avoid races with mount 27140343Smckusick * and unmount. 27240343Smckusick */ 27341400Smckusick if ((mp->mnt_flag & (MNT_MLOCK|MNT_RDONLY|MNT_MPBUSY)) == 0 && 27441298Smckusick !vfs_busy(mp)) { 27554441Smckusick VFS_SYNC(mp, MNT_NOWAIT, p->p_ucred, p); 27641298Smckusick omp = mp; 27741400Smckusick mp = mp->mnt_next; 27841298Smckusick vfs_unbusy(omp); 27941298Smckusick } else 28041400Smckusick mp = mp->mnt_next; 28137741Smckusick } while (mp != rootfs); 28256352Smckusick #ifdef DIAGNOSTIC 28356352Smckusick if (syncprt) 28456352Smckusick vfs_bufstats(); 28556352Smckusick #endif /* DIAGNOSTIC */ 28647688Skarels return (0); 28737741Smckusick } 28837741Smckusick 28937741Smckusick /* 290*64410Sbostic * Change filesystem quotas. 29141298Smckusick */ 29254916Storek struct quotactl_args { 29354916Storek char *path; 29454916Storek int cmd; 29554916Storek int uid; 29654916Storek caddr_t arg; 29754916Storek }; 29842441Smckusick /* ARGSUSED */ 29942441Smckusick quotactl(p, uap, retval) 30045914Smckusick struct proc *p; 30154916Storek register struct quotactl_args *uap; 30242441Smckusick int *retval; 30342441Smckusick { 30441298Smckusick register struct mount *mp; 30541298Smckusick int error; 30647540Skarels struct nameidata nd; 30741298Smckusick 30852322Smckusick NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); 30952322Smckusick if (error = namei(&nd)) 31047540Skarels return (error); 31152322Smckusick mp = nd.ni_vp->v_mount; 31252322Smckusick vrele(nd.ni_vp); 31348026Smckusick return (VFS_QUOTACTL(mp, uap->cmd, uap->uid, uap->arg, p)); 31441298Smckusick } 31541298Smckusick 31641298Smckusick /* 31749365Smckusick * Get filesystem statistics. 31837741Smckusick */ 31954916Storek struct statfs_args { 32054916Storek char *path; 32154916Storek struct statfs *buf; 32254916Storek }; 32342441Smckusick /* ARGSUSED */ 32442441Smckusick statfs(p, uap, retval) 32545914Smckusick struct proc *p; 32654916Storek register struct statfs_args *uap; 32742441Smckusick int *retval; 32842441Smckusick { 32939464Smckusick register struct mount *mp; 33040343Smckusick register struct statfs *sp; 33137741Smckusick int error; 33247540Skarels struct nameidata nd; 33337741Smckusick 33452322Smckusick NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); 33552322Smckusick if (error = namei(&nd)) 33647540Skarels return (error); 33752322Smckusick mp = nd.ni_vp->v_mount; 33841400Smckusick sp = &mp->mnt_stat; 33952322Smckusick vrele(nd.ni_vp); 34048026Smckusick if (error = VFS_STATFS(mp, sp, p)) 34147540Skarels return (error); 34241400Smckusick sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 34347540Skarels return (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp))); 34437741Smckusick } 34537741Smckusick 34642441Smckusick /* 34749365Smckusick * Get filesystem statistics. 34842441Smckusick */ 34954916Storek struct fstatfs_args { 35054916Storek int fd; 35154916Storek struct statfs *buf; 35254916Storek }; 35342441Smckusick /* ARGSUSED */ 35442441Smckusick fstatfs(p, uap, retval) 35545914Smckusick struct proc *p; 35654916Storek register struct fstatfs_args *uap; 35742441Smckusick int *retval; 35842441Smckusick { 35937741Smckusick struct file *fp; 36039464Smckusick struct mount *mp; 36140343Smckusick register struct statfs *sp; 36237741Smckusick int error; 36337741Smckusick 36445914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 36547540Skarels return (error); 36639464Smckusick mp = ((struct vnode *)fp->f_data)->v_mount; 36741400Smckusick sp = &mp->mnt_stat; 36848026Smckusick if (error = VFS_STATFS(mp, sp, p)) 36947540Skarels return (error); 37041400Smckusick sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 37147540Skarels return (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp))); 37237741Smckusick } 37337741Smckusick 37437741Smckusick /* 37549365Smckusick * Get statistics on all filesystems. 37638270Smckusick */ 37754916Storek struct getfsstat_args { 37854916Storek struct statfs *buf; 37954916Storek long bufsize; 38054916Storek int flags; 38154916Storek }; 38242441Smckusick getfsstat(p, uap, retval) 38345914Smckusick struct proc *p; 38454916Storek register struct getfsstat_args *uap; 38542441Smckusick int *retval; 38642441Smckusick { 38738270Smckusick register struct mount *mp; 38840343Smckusick register struct statfs *sp; 38939606Smckusick caddr_t sfsp; 39038270Smckusick long count, maxcount, error; 39138270Smckusick 39238270Smckusick maxcount = uap->bufsize / sizeof(struct statfs); 39339606Smckusick sfsp = (caddr_t)uap->buf; 39438270Smckusick mp = rootfs; 39538270Smckusick count = 0; 39638270Smckusick do { 39741400Smckusick if (sfsp && count < maxcount && 39841400Smckusick ((mp->mnt_flag & MNT_MLOCK) == 0)) { 39941400Smckusick sp = &mp->mnt_stat; 40040343Smckusick /* 40140343Smckusick * If MNT_NOWAIT is specified, do not refresh the 40240343Smckusick * fsstat cache. MNT_WAIT overrides MNT_NOWAIT. 40340343Smckusick */ 40440343Smckusick if (((uap->flags & MNT_NOWAIT) == 0 || 40540343Smckusick (uap->flags & MNT_WAIT)) && 40648026Smckusick (error = VFS_STATFS(mp, sp, p))) { 40741400Smckusick mp = mp->mnt_prev; 40839607Smckusick continue; 40939607Smckusick } 41041400Smckusick sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 41140343Smckusick if (error = copyout((caddr_t)sp, sfsp, sizeof(*sp))) 41247540Skarels return (error); 41340343Smckusick sfsp += sizeof(*sp); 41438270Smckusick } 41539606Smckusick count++; 41641400Smckusick mp = mp->mnt_prev; 41738270Smckusick } while (mp != rootfs); 41838270Smckusick if (sfsp && count > maxcount) 41942441Smckusick *retval = maxcount; 42038270Smckusick else 42142441Smckusick *retval = count; 42247540Skarels return (0); 42338270Smckusick } 42438270Smckusick 42538270Smckusick /* 42638259Smckusick * Change current working directory to a given file descriptor. 42738259Smckusick */ 42854916Storek struct fchdir_args { 42954916Storek int fd; 43054916Storek }; 43142441Smckusick /* ARGSUSED */ 43242441Smckusick fchdir(p, uap, retval) 43345914Smckusick struct proc *p; 43454916Storek struct fchdir_args *uap; 43542441Smckusick int *retval; 43638259Smckusick { 43745914Smckusick register struct filedesc *fdp = p->p_fd; 43838259Smckusick register struct vnode *vp; 43938259Smckusick struct file *fp; 44038259Smckusick int error; 44138259Smckusick 44245914Smckusick if (error = getvnode(fdp, uap->fd, &fp)) 44347540Skarels return (error); 44438259Smckusick vp = (struct vnode *)fp->f_data; 44538259Smckusick VOP_LOCK(vp); 44638259Smckusick if (vp->v_type != VDIR) 44738259Smckusick error = ENOTDIR; 44838259Smckusick else 44948026Smckusick error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p); 45038259Smckusick VOP_UNLOCK(vp); 45139860Smckusick if (error) 45247540Skarels return (error); 45339860Smckusick VREF(vp); 45445914Smckusick vrele(fdp->fd_cdir); 45545914Smckusick fdp->fd_cdir = vp; 45647540Skarels return (0); 45738259Smckusick } 45838259Smckusick 45938259Smckusick /* 46037741Smckusick * Change current working directory (``.''). 46137741Smckusick */ 46254916Storek struct chdir_args { 463*64410Sbostic char *path; 46454916Storek }; 46542441Smckusick /* ARGSUSED */ 46642441Smckusick chdir(p, uap, retval) 46745914Smckusick struct proc *p; 46854916Storek struct chdir_args *uap; 46942441Smckusick int *retval; 47037741Smckusick { 47145914Smckusick register struct filedesc *fdp = p->p_fd; 47237741Smckusick int error; 47347540Skarels struct nameidata nd; 4746254Sroot 475*64410Sbostic NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); 476*64410Sbostic if (error = change_dir(&nd, p)) 47747540Skarels return (error); 47845914Smckusick vrele(fdp->fd_cdir); 47952322Smckusick fdp->fd_cdir = nd.ni_vp; 48047540Skarels return (0); 48137741Smckusick } 4826254Sroot 48337741Smckusick /* 48437741Smckusick * Change notion of root (``/'') directory. 48537741Smckusick */ 48654916Storek struct chroot_args { 487*64410Sbostic char *path; 48854916Storek }; 48942441Smckusick /* ARGSUSED */ 49042441Smckusick chroot(p, uap, retval) 49145914Smckusick struct proc *p; 49254916Storek struct chroot_args *uap; 49342441Smckusick int *retval; 49437741Smckusick { 49545914Smckusick register struct filedesc *fdp = p->p_fd; 49637741Smckusick int error; 49747540Skarels struct nameidata nd; 49837741Smckusick 49947540Skarels if (error = suser(p->p_ucred, &p->p_acflag)) 50047540Skarels return (error); 501*64410Sbostic NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); 502*64410Sbostic if (error = change_dir(&nd, p)) 50347540Skarels return (error); 50445914Smckusick if (fdp->fd_rdir != NULL) 50545914Smckusick vrele(fdp->fd_rdir); 50652322Smckusick fdp->fd_rdir = nd.ni_vp; 50747540Skarels return (0); 5086254Sroot } 5096254Sroot 51037Sbill /* 51137741Smckusick * Common routine for chroot and chdir. 51237741Smckusick */ 513*64410Sbostic static int 514*64410Sbostic change_dir(ndp, p) 51552322Smckusick register struct nameidata *ndp; 51647540Skarels struct proc *p; 51737741Smckusick { 51837741Smckusick struct vnode *vp; 51937741Smckusick int error; 52037741Smckusick 52152322Smckusick if (error = namei(ndp)) 52237741Smckusick return (error); 52337741Smckusick vp = ndp->ni_vp; 52437741Smckusick if (vp->v_type != VDIR) 52537741Smckusick error = ENOTDIR; 52637741Smckusick else 52748026Smckusick error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p); 52837741Smckusick VOP_UNLOCK(vp); 52937741Smckusick if (error) 53037741Smckusick vrele(vp); 53137741Smckusick return (error); 53237741Smckusick } 53337741Smckusick 53437741Smckusick /* 53542441Smckusick * Check permissions, allocate an open file structure, 53642441Smckusick * and call the device open routine if any. 5376254Sroot */ 53854916Storek struct open_args { 539*64410Sbostic char *path; 540*64410Sbostic int flags; 54154916Storek int mode; 54254916Storek }; 54342441Smckusick open(p, uap, retval) 54445914Smckusick struct proc *p; 54554916Storek register struct open_args *uap; 54642441Smckusick int *retval; 5476254Sroot { 54845914Smckusick register struct filedesc *fdp = p->p_fd; 54942441Smckusick register struct file *fp; 55050111Smckusick register struct vnode *vp; 551*64410Sbostic int flags, cmode; 55237741Smckusick struct file *nfp; 55349945Smckusick int type, indx, error; 55449945Smckusick struct flock lf; 55547540Skarels struct nameidata nd; 55637741Smckusick extern struct fileops vnops; 5576254Sroot 55845914Smckusick if (error = falloc(p, &nfp, &indx)) 55947540Skarels return (error); 56037741Smckusick fp = nfp; 561*64410Sbostic flags = FFLAGS(uap->flags); 562*64410Sbostic cmode = ((uap->mode &~ fdp->fd_cmask) & ALLPERMS) &~ S_ISTXT; 563*64410Sbostic NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); 56445202Smckusick p->p_dupfd = -indx - 1; /* XXX check for fdopen */ 565*64410Sbostic if (error = vn_open(&nd, flags, cmode)) { 56649980Smckusick ffree(fp); 56754723Smckusick if ((error == ENODEV || error == ENXIO) && 56854723Smckusick p->p_dupfd >= 0 && /* XXX from fdopen */ 569*64410Sbostic (error = 570*64410Sbostic dupfdopen(fdp, indx, p->p_dupfd, flags, error)) == 0) { 57142441Smckusick *retval = indx; 57247540Skarels return (0); 57342441Smckusick } 57440884Smckusick if (error == ERESTART) 57540884Smckusick error = EINTR; 57647688Skarels fdp->fd_ofiles[indx] = NULL; 57747540Skarels return (error); 57812756Ssam } 57953828Spendry p->p_dupfd = 0; 58052322Smckusick vp = nd.ni_vp; 581*64410Sbostic fp->f_flag = flags & FMASK; 58254348Smckusick fp->f_type = DTYPE_VNODE; 58354348Smckusick fp->f_ops = &vnops; 58454348Smckusick fp->f_data = (caddr_t)vp; 585*64410Sbostic if (flags & (O_EXLOCK | O_SHLOCK)) { 58649945Smckusick lf.l_whence = SEEK_SET; 58749945Smckusick lf.l_start = 0; 58849945Smckusick lf.l_len = 0; 589*64410Sbostic if (flags & O_EXLOCK) 59049945Smckusick lf.l_type = F_WRLCK; 59149945Smckusick else 59249945Smckusick lf.l_type = F_RDLCK; 59349945Smckusick type = F_FLOCK; 594*64410Sbostic if ((flags & FNONBLOCK) == 0) 59549945Smckusick type |= F_WAIT; 59650111Smckusick if (error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, type)) { 59750111Smckusick VOP_UNLOCK(vp); 59850111Smckusick (void) vn_close(vp, fp->f_flag, fp->f_cred, p); 59949980Smckusick ffree(fp); 60049945Smckusick fdp->fd_ofiles[indx] = NULL; 60149945Smckusick return (error); 60249945Smckusick } 60349949Smckusick fp->f_flag |= FHASLOCK; 60449945Smckusick } 60550111Smckusick VOP_UNLOCK(vp); 60642441Smckusick *retval = indx; 60747540Skarels return (0); 6086254Sroot } 6096254Sroot 61042955Smckusick #ifdef COMPAT_43 6116254Sroot /* 612*64410Sbostic * Create a file. 6136254Sroot */ 61454916Storek struct ocreat_args { 615*64410Sbostic char *path; 616*64410Sbostic int mode; 61754916Storek }; 61842955Smckusick ocreat(p, uap, retval) 61942441Smckusick struct proc *p; 62054916Storek register struct ocreat_args *uap; 62142441Smckusick int *retval; 6226254Sroot { 62354916Storek struct open_args openuap; 62442441Smckusick 625*64410Sbostic openuap.path = uap->path; 626*64410Sbostic openuap.mode = uap->mode; 627*64410Sbostic openuap.flags = O_WRONLY | O_CREAT | O_TRUNC; 62847540Skarels return (open(p, &openuap, retval)); 62942441Smckusick } 63042955Smckusick #endif /* COMPAT_43 */ 63142441Smckusick 63242441Smckusick /* 633*64410Sbostic * Create a special file. 63442441Smckusick */ 63554916Storek struct mknod_args { 636*64410Sbostic char *path; 637*64410Sbostic int mode; 63854916Storek int dev; 63954916Storek }; 64042441Smckusick /* ARGSUSED */ 64142441Smckusick mknod(p, uap, retval) 64245914Smckusick struct proc *p; 64354916Storek register struct mknod_args *uap; 64442441Smckusick int *retval; 64542441Smckusick { 64637741Smckusick register struct vnode *vp; 64737741Smckusick struct vattr vattr; 64837741Smckusick int error; 64947540Skarels struct nameidata nd; 6506254Sroot 65147540Skarels if (error = suser(p->p_ucred, &p->p_acflag)) 65247540Skarels return (error); 653*64410Sbostic NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->path, p); 65452322Smckusick if (error = namei(&nd)) 65547540Skarels return (error); 65652322Smckusick vp = nd.ni_vp; 65737741Smckusick if (vp != NULL) { 65837741Smckusick error = EEXIST; 65912756Ssam goto out; 6606254Sroot } 66141362Smckusick VATTR_NULL(&vattr); 662*64410Sbostic switch (uap->mode & S_IFMT) { 66340635Smckusick case S_IFMT: /* used by badsect to flag bad sectors */ 66437741Smckusick vattr.va_type = VBAD; 66537741Smckusick break; 66640635Smckusick case S_IFCHR: 66737741Smckusick vattr.va_type = VCHR; 66837741Smckusick break; 66940635Smckusick case S_IFBLK: 67037741Smckusick vattr.va_type = VBLK; 67137741Smckusick break; 67237741Smckusick default: 67337741Smckusick error = EINVAL; 67437741Smckusick goto out; 6756254Sroot } 676*64410Sbostic vattr.va_mode = (uap->mode & ALLPERMS) &~ p->p_fd->fd_cmask; 67737741Smckusick vattr.va_rdev = uap->dev; 6786254Sroot out: 67942465Smckusick if (!error) { 68052322Smckusick LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 68152322Smckusick error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr); 68242465Smckusick } else { 68352322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 68452322Smckusick if (nd.ni_dvp == vp) 68552322Smckusick vrele(nd.ni_dvp); 68643344Smckusick else 68752322Smckusick vput(nd.ni_dvp); 68842465Smckusick if (vp) 68942465Smckusick vrele(vp); 69042465Smckusick } 69147540Skarels return (error); 6926254Sroot } 6936254Sroot 6946254Sroot /* 695*64410Sbostic * Create named pipe. 69640285Smckusick */ 69754916Storek struct mkfifo_args { 698*64410Sbostic char *path; 699*64410Sbostic int mode; 70054916Storek }; 70142441Smckusick /* ARGSUSED */ 70242441Smckusick mkfifo(p, uap, retval) 70345914Smckusick struct proc *p; 70454916Storek register struct mkfifo_args *uap; 70542441Smckusick int *retval; 70642441Smckusick { 70740285Smckusick struct vattr vattr; 70840285Smckusick int error; 70947540Skarels struct nameidata nd; 71040285Smckusick 71140285Smckusick #ifndef FIFO 71247540Skarels return (EOPNOTSUPP); 71340285Smckusick #else 714*64410Sbostic NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->path, p); 71552322Smckusick if (error = namei(&nd)) 71647540Skarels return (error); 71752322Smckusick if (nd.ni_vp != NULL) { 71852322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 71952322Smckusick if (nd.ni_dvp == nd.ni_vp) 72052322Smckusick vrele(nd.ni_dvp); 72143344Smckusick else 72252322Smckusick vput(nd.ni_dvp); 72352322Smckusick vrele(nd.ni_vp); 72447540Skarels return (EEXIST); 72540285Smckusick } 72645785Sbostic VATTR_NULL(&vattr); 72745785Sbostic vattr.va_type = VFIFO; 728*64410Sbostic vattr.va_mode = (uap->mode & ALLPERMS) &~ p->p_fd->fd_cmask; 72952322Smckusick LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 73052322Smckusick return (VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr)); 73140285Smckusick #endif /* FIFO */ 73240285Smckusick } 73340285Smckusick 73440285Smckusick /* 735*64410Sbostic * Make a hard file link. 7366254Sroot */ 73754916Storek struct link_args { 738*64410Sbostic char *path; 739*64410Sbostic char *link; 74054916Storek }; 74142441Smckusick /* ARGSUSED */ 74242441Smckusick link(p, uap, retval) 74345914Smckusick struct proc *p; 74454916Storek register struct link_args *uap; 74542441Smckusick int *retval; 74642441Smckusick { 747*64410Sbostic register struct vnode *vp; 748*64410Sbostic struct nameidata nd; 74937741Smckusick int error; 7506254Sroot 751*64410Sbostic NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); 75252322Smckusick if (error = namei(&nd)) 75347540Skarels return (error); 75452322Smckusick vp = nd.ni_vp; 75537741Smckusick if (vp->v_type == VDIR && 75647540Skarels (error = suser(p->p_ucred, &p->p_acflag))) 757*64410Sbostic goto out; 75852322Smckusick nd.ni_cnd.cn_nameiop = CREATE; 75952322Smckusick nd.ni_cnd.cn_flags = LOCKPARENT; 760*64410Sbostic nd.ni_dirp = uap->link; 76152322Smckusick if (error = namei(&nd)) 762*64410Sbostic goto out; 763*64410Sbostic if (nd.ni_vp != NULL) 76437741Smckusick error = EEXIST; 76542465Smckusick if (!error) { 766*64410Sbostic LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 76752192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 76852821Smckusick error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd); 76942465Smckusick } else { 77052322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 77152322Smckusick if (nd.ni_dvp == nd.ni_vp) 77252322Smckusick vrele(nd.ni_dvp); 77343344Smckusick else 77452322Smckusick vput(nd.ni_dvp); 77552322Smckusick if (nd.ni_vp) 77652322Smckusick vrele(nd.ni_vp); 77742465Smckusick } 778*64410Sbostic out: vrele(vp); 77947540Skarels return (error); 7806254Sroot } 7816254Sroot 7826254Sroot /* 78349365Smckusick * Make a symbolic link. 7846254Sroot */ 78554916Storek struct symlink_args { 786*64410Sbostic char *path; 787*64410Sbostic char *link; 78854916Storek }; 78942441Smckusick /* ARGSUSED */ 79042441Smckusick symlink(p, uap, retval) 79145914Smckusick struct proc *p; 79254916Storek register struct symlink_args *uap; 79342441Smckusick int *retval; 79442441Smckusick { 79537741Smckusick struct vattr vattr; 796*64410Sbostic char *path; 79737741Smckusick int error; 79847540Skarels struct nameidata nd; 7996254Sroot 800*64410Sbostic MALLOC(path, char *, MAXPATHLEN, M_NAMEI, M_WAITOK); 801*64410Sbostic if (error = copyinstr(uap->path, path, MAXPATHLEN, NULL)) 80242465Smckusick goto out; 803*64410Sbostic NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->link, p); 80452322Smckusick if (error = namei(&nd)) 80542465Smckusick goto out; 80652322Smckusick if (nd.ni_vp) { 80752322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 80852322Smckusick if (nd.ni_dvp == nd.ni_vp) 80952322Smckusick vrele(nd.ni_dvp); 81043344Smckusick else 81152322Smckusick vput(nd.ni_dvp); 81252322Smckusick vrele(nd.ni_vp); 81337741Smckusick error = EEXIST; 81437741Smckusick goto out; 8156254Sroot } 81641362Smckusick VATTR_NULL(&vattr); 817*64410Sbostic vattr.va_mode = ACCESSPERMS &~ p->p_fd->fd_cmask; 81852322Smckusick LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 819*64410Sbostic error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr, path); 82037741Smckusick out: 821*64410Sbostic FREE(path, M_NAMEI); 82247540Skarels return (error); 8236254Sroot } 8246254Sroot 8256254Sroot /* 82649365Smckusick * Delete a name from the filesystem. 8276254Sroot */ 82854916Storek struct unlink_args { 829*64410Sbostic char *path; 83054916Storek }; 83142441Smckusick /* ARGSUSED */ 83242441Smckusick unlink(p, uap, retval) 83345914Smckusick struct proc *p; 83454916Storek struct unlink_args *uap; 83542441Smckusick int *retval; 8366254Sroot { 83737741Smckusick register struct vnode *vp; 83837741Smckusick int error; 83947540Skarels struct nameidata nd; 8406254Sroot 841*64410Sbostic NDINIT(&nd, DELETE, LOCKPARENT, UIO_USERSPACE, uap->path, p); 84252322Smckusick if (error = namei(&nd)) 84347540Skarels return (error); 84452322Smckusick vp = nd.ni_vp; 84559382Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 84659382Smckusick VOP_LOCK(vp); 84737741Smckusick if (vp->v_type == VDIR && 84847540Skarels (error = suser(p->p_ucred, &p->p_acflag))) 8496254Sroot goto out; 8506254Sroot /* 85149365Smckusick * The root of a mounted filesystem cannot be deleted. 8526254Sroot */ 853*64410Sbostic if (vp->v_flag & VROOT) 85437741Smckusick error = EBUSY; 855*64410Sbostic else 856*64410Sbostic (void)vnode_pager_uncache(vp); 857*64410Sbostic 858*64410Sbostic out: if (!error) { 85952322Smckusick LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 86052322Smckusick error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); 86142465Smckusick } else { 86252322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 86352322Smckusick if (nd.ni_dvp == vp) 86452322Smckusick vrele(nd.ni_dvp); 86543344Smckusick else 86652322Smckusick vput(nd.ni_dvp); 86742465Smckusick vput(vp); 86842465Smckusick } 86947540Skarels return (error); 8706254Sroot } 8716254Sroot 872*64410Sbostic /* 873*64410Sbostic * Reposition read/write file offset. 874*64410Sbostic */ 87560428Smckusick struct lseek_args { 876*64410Sbostic int fd; 87754863Storek int pad; 878*64410Sbostic off_t offset; 879*64410Sbostic int whence; 88054863Storek }; 88160414Smckusick lseek(p, uap, retval) 88253468Smckusick struct proc *p; 88360428Smckusick register struct lseek_args *uap; 88454916Storek int *retval; 88542441Smckusick { 88647540Skarels struct ucred *cred = p->p_ucred; 88745914Smckusick register struct filedesc *fdp = p->p_fd; 88842441Smckusick register struct file *fp; 88937741Smckusick struct vattr vattr; 89037741Smckusick int error; 8916254Sroot 892*64410Sbostic if ((u_int)uap->fd >= fdp->fd_nfiles || 893*64410Sbostic (fp = fdp->fd_ofiles[uap->fd]) == NULL) 89447540Skarels return (EBADF); 89537741Smckusick if (fp->f_type != DTYPE_VNODE) 89647540Skarels return (ESPIPE); 897*64410Sbostic switch (uap->whence) { 89813878Ssam case L_INCR: 899*64410Sbostic fp->f_offset += uap->offset; 90013878Ssam break; 90113878Ssam case L_XTND: 902*64410Sbostic if (error = 903*64410Sbostic VOP_GETATTR((struct vnode *)fp->f_data, &vattr, cred, p)) 90447540Skarels return (error); 905*64410Sbostic fp->f_offset = uap->offset + vattr.va_size; 90613878Ssam break; 90713878Ssam case L_SET: 908*64410Sbostic fp->f_offset = uap->offset; 90913878Ssam break; 91013878Ssam default: 91147540Skarels return (EINVAL); 91213878Ssam } 91354916Storek *(off_t *)retval = fp->f_offset; 91447540Skarels return (0); 9156254Sroot } 9166254Sroot 91760414Smckusick #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 9186254Sroot /* 919*64410Sbostic * Reposition read/write file offset. 92060036Smckusick */ 92160428Smckusick struct olseek_args { 922*64410Sbostic int fd; 923*64410Sbostic long offset; 924*64410Sbostic int whence; 92560036Smckusick }; 92660414Smckusick olseek(p, uap, retval) 92760036Smckusick struct proc *p; 92860428Smckusick register struct olseek_args *uap; 92960036Smckusick int *retval; 93060036Smckusick { 93160428Smckusick struct lseek_args nuap; 93260036Smckusick off_t qret; 93360036Smckusick int error; 93460036Smckusick 935*64410Sbostic nuap.fd = uap->fd; 936*64410Sbostic nuap.offset = uap->offset; 937*64410Sbostic nuap.whence = uap->whence; 93860428Smckusick error = lseek(p, &nuap, &qret); 93960036Smckusick *(long *)retval = qret; 94060036Smckusick return (error); 94160036Smckusick } 94260414Smckusick #endif /* COMPAT_43 */ 94360036Smckusick 94460036Smckusick /* 94549365Smckusick * Check access permissions. 9466254Sroot */ 94763427Sbostic struct access_args { 948*64410Sbostic char *path; 949*64410Sbostic int flags; 95054916Storek }; 95163427Sbostic access(p, uap, retval) 95245914Smckusick struct proc *p; 95363427Sbostic register struct access_args *uap; 95442441Smckusick int *retval; 95542441Smckusick { 95647540Skarels register struct ucred *cred = p->p_ucred; 95737741Smckusick register struct vnode *vp; 958*64410Sbostic int error, flags, saved_uid, saved_gid; 95947540Skarels struct nameidata nd; 9606254Sroot 961*64410Sbostic saved_uid = cred->cr_uid; 962*64410Sbostic saved_gid = cred->cr_groups[0]; 96347540Skarels cred->cr_uid = p->p_cred->p_ruid; 96447540Skarels cred->cr_groups[0] = p->p_cred->p_rgid; 965*64410Sbostic NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); 96652322Smckusick if (error = namei(&nd)) 96737741Smckusick goto out1; 96852322Smckusick vp = nd.ni_vp; 969*64410Sbostic 970*64410Sbostic /* Flags == 0 means only check for existence. */ 971*64410Sbostic if (uap->flags) { 972*64410Sbostic flags = 0; 973*64410Sbostic if (uap->flags & R_OK) 974*64410Sbostic flags |= VREAD; 975*64410Sbostic if (uap->flags & W_OK) 976*64410Sbostic flags |= VWRITE; 977*64410Sbostic if (uap->flags & X_OK) 978*64410Sbostic flags |= VEXEC; 979*64410Sbostic if ((flags & VWRITE) == 0 || (error = vn_writechk(vp)) == 0) 980*64410Sbostic error = VOP_ACCESS(vp, flags, cred, p); 9816254Sroot } 98237741Smckusick vput(vp); 98337741Smckusick out1: 984*64410Sbostic cred->cr_uid = saved_uid; 985*64410Sbostic cred->cr_groups[0] = saved_gid; 98647540Skarels return (error); 9876254Sroot } 9886254Sroot 98954348Smckusick #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 9906254Sroot /* 991*64410Sbostic * Get file status; this version follows links. 99237Sbill */ 99354916Storek struct ostat_args { 994*64410Sbostic char *path; 99554916Storek struct ostat *ub; 99654916Storek }; 99742441Smckusick /* ARGSUSED */ 99853759Smckusick ostat(p, uap, retval) 99945914Smckusick struct proc *p; 100054916Storek register struct ostat_args *uap; 100153468Smckusick int *retval; 100253468Smckusick { 100353468Smckusick struct stat sb; 100453468Smckusick struct ostat osb; 100553468Smckusick int error; 100653468Smckusick struct nameidata nd; 100753468Smckusick 1008*64410Sbostic NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); 100953468Smckusick if (error = namei(&nd)) 101053468Smckusick return (error); 101153468Smckusick error = vn_stat(nd.ni_vp, &sb, p); 101253468Smckusick vput(nd.ni_vp); 101353468Smckusick if (error) 101453468Smckusick return (error); 101553468Smckusick cvtstat(&sb, &osb); 101653468Smckusick error = copyout((caddr_t)&osb, (caddr_t)uap->ub, sizeof (osb)); 101753468Smckusick return (error); 101853468Smckusick } 101953468Smckusick 102053468Smckusick /* 1021*64410Sbostic * Get file status; this version does not follow links. 102253468Smckusick */ 102354916Storek struct olstat_args { 1024*64410Sbostic char *path; 102554916Storek struct ostat *ub; 102654916Storek }; 102753468Smckusick /* ARGSUSED */ 102853759Smckusick olstat(p, uap, retval) 102953468Smckusick struct proc *p; 103054916Storek register struct olstat_args *uap; 103153468Smckusick int *retval; 103253468Smckusick { 103353468Smckusick struct stat sb; 103453468Smckusick struct ostat osb; 103553468Smckusick int error; 103653468Smckusick struct nameidata nd; 103753468Smckusick 1038*64410Sbostic NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); 103953468Smckusick if (error = namei(&nd)) 104053468Smckusick return (error); 104153468Smckusick error = vn_stat(nd.ni_vp, &sb, p); 104253468Smckusick vput(nd.ni_vp); 104353468Smckusick if (error) 104453468Smckusick return (error); 104553468Smckusick cvtstat(&sb, &osb); 104653468Smckusick error = copyout((caddr_t)&osb, (caddr_t)uap->ub, sizeof (osb)); 104753468Smckusick return (error); 104853468Smckusick } 104953468Smckusick 105053468Smckusick /* 1051*64410Sbostic * Convert from an old to a new stat structure. 105253468Smckusick */ 105353468Smckusick cvtstat(st, ost) 105453468Smckusick struct stat *st; 105553468Smckusick struct ostat *ost; 105653468Smckusick { 105753468Smckusick 105853468Smckusick ost->st_dev = st->st_dev; 105953468Smckusick ost->st_ino = st->st_ino; 106053468Smckusick ost->st_mode = st->st_mode; 106153468Smckusick ost->st_nlink = st->st_nlink; 106253468Smckusick ost->st_uid = st->st_uid; 106353468Smckusick ost->st_gid = st->st_gid; 106453468Smckusick ost->st_rdev = st->st_rdev; 106553468Smckusick if (st->st_size < (quad_t)1 << 32) 106653468Smckusick ost->st_size = st->st_size; 106753468Smckusick else 106853468Smckusick ost->st_size = -2; 106953468Smckusick ost->st_atime = st->st_atime; 107053468Smckusick ost->st_mtime = st->st_mtime; 107153468Smckusick ost->st_ctime = st->st_ctime; 107253468Smckusick ost->st_blksize = st->st_blksize; 107353468Smckusick ost->st_blocks = st->st_blocks; 107453468Smckusick ost->st_flags = st->st_flags; 107553468Smckusick ost->st_gen = st->st_gen; 107653468Smckusick } 107754348Smckusick #endif /* COMPAT_43 || COMPAT_SUNOS */ 107853468Smckusick 107953468Smckusick /* 1080*64410Sbostic * Get file status; this version follows links. 108153468Smckusick */ 108254916Storek struct stat_args { 1083*64410Sbostic char *path; 108454916Storek struct stat *ub; 108554916Storek }; 108653468Smckusick /* ARGSUSED */ 108753759Smckusick stat(p, uap, retval) 108853468Smckusick struct proc *p; 108954916Storek register struct stat_args *uap; 109042441Smckusick int *retval; 109137Sbill { 109242441Smckusick struct stat sb; 109342441Smckusick int error; 109447540Skarels struct nameidata nd; 109537Sbill 1096*64410Sbostic NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); 109752322Smckusick if (error = namei(&nd)) 109847540Skarels return (error); 109952322Smckusick error = vn_stat(nd.ni_vp, &sb, p); 110052322Smckusick vput(nd.ni_vp); 110142441Smckusick if (error) 110247540Skarels return (error); 110342441Smckusick error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb)); 110447540Skarels return (error); 110537Sbill } 110637Sbill 110737Sbill /* 1108*64410Sbostic * Get file status; this version does not follow links. 11095992Swnj */ 111054916Storek struct lstat_args { 1111*64410Sbostic char *path; 111254916Storek struct stat *ub; 111354916Storek }; 111442441Smckusick /* ARGSUSED */ 111553759Smckusick lstat(p, uap, retval) 111645914Smckusick struct proc *p; 111754916Storek register struct lstat_args *uap; 111842441Smckusick int *retval; 111942441Smckusick { 112037741Smckusick int error; 112159373Smckusick struct vnode *vp, *dvp; 112259373Smckusick struct stat sb, sb1; 112347540Skarels struct nameidata nd; 11245992Swnj 112559373Smckusick NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | LOCKPARENT, UIO_USERSPACE, 1126*64410Sbostic uap->path, p); 112752322Smckusick if (error = namei(&nd)) 112847540Skarels return (error); 112959373Smckusick /* 113059373Smckusick * For symbolic links, always return the attributes of its 113159373Smckusick * containing directory, except for mode, size, and links. 113259373Smckusick */ 113359373Smckusick vp = nd.ni_vp; 113459373Smckusick dvp = nd.ni_dvp; 113559373Smckusick if (vp->v_type != VLNK) { 113659373Smckusick if (dvp == vp) 113759373Smckusick vrele(dvp); 113859373Smckusick else 113959373Smckusick vput(dvp); 114059373Smckusick error = vn_stat(vp, &sb, p); 114159373Smckusick vput(vp); 114259373Smckusick if (error) 114359373Smckusick return (error); 114459373Smckusick } else { 114559373Smckusick error = vn_stat(dvp, &sb, p); 114659373Smckusick vput(dvp); 114759373Smckusick if (error) { 114859373Smckusick vput(vp); 114959373Smckusick return (error); 115059373Smckusick } 115159373Smckusick error = vn_stat(vp, &sb1, p); 115259373Smckusick vput(vp); 115359373Smckusick if (error) 115459373Smckusick return (error); 115559373Smckusick sb.st_mode &= ~S_IFDIR; 115659373Smckusick sb.st_mode |= S_IFLNK; 115759373Smckusick sb.st_nlink = sb1.st_nlink; 115859373Smckusick sb.st_size = sb1.st_size; 115959373Smckusick sb.st_blocks = sb1.st_blocks; 116059373Smckusick } 116137741Smckusick error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb)); 116247540Skarels return (error); 11635992Swnj } 11645992Swnj 11655992Swnj /* 1166*64410Sbostic * Get configurable pathname variables. 116760414Smckusick */ 116860414Smckusick struct pathconf_args { 1169*64410Sbostic char *path; 117060414Smckusick int name; 117160414Smckusick }; 117260414Smckusick /* ARGSUSED */ 117360414Smckusick pathconf(p, uap, retval) 117460414Smckusick struct proc *p; 117560414Smckusick register struct pathconf_args *uap; 117660414Smckusick int *retval; 117760414Smckusick { 117860414Smckusick int error; 117960414Smckusick struct nameidata nd; 118060414Smckusick 1181*64410Sbostic NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); 118260414Smckusick if (error = namei(&nd)) 118360414Smckusick return (error); 118460414Smckusick error = VOP_PATHCONF(nd.ni_vp, uap->name, retval); 118560414Smckusick vput(nd.ni_vp); 118660414Smckusick return (error); 118760414Smckusick } 118860414Smckusick 118960414Smckusick /* 119049365Smckusick * Return target name of a symbolic link. 119137Sbill */ 119254916Storek struct readlink_args { 1193*64410Sbostic char *path; 119454916Storek char *buf; 119554916Storek int count; 119654916Storek }; 119742441Smckusick /* ARGSUSED */ 119842441Smckusick readlink(p, uap, retval) 119945914Smckusick struct proc *p; 120054916Storek register struct readlink_args *uap; 120142441Smckusick int *retval; 120242441Smckusick { 120337741Smckusick register struct vnode *vp; 120437741Smckusick struct iovec aiov; 120537741Smckusick struct uio auio; 120637741Smckusick int error; 120747540Skarels struct nameidata nd; 12085992Swnj 1209*64410Sbostic NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); 121052322Smckusick if (error = namei(&nd)) 121147540Skarels return (error); 121252322Smckusick vp = nd.ni_vp; 1213*64410Sbostic if (vp->v_type != VLNK) 121437741Smckusick error = EINVAL; 1215*64410Sbostic else { 1216*64410Sbostic aiov.iov_base = uap->buf; 1217*64410Sbostic aiov.iov_len = uap->count; 1218*64410Sbostic auio.uio_iov = &aiov; 1219*64410Sbostic auio.uio_iovcnt = 1; 1220*64410Sbostic auio.uio_offset = 0; 1221*64410Sbostic auio.uio_rw = UIO_READ; 1222*64410Sbostic auio.uio_segflg = UIO_USERSPACE; 1223*64410Sbostic auio.uio_procp = p; 1224*64410Sbostic auio.uio_resid = uap->count; 1225*64410Sbostic error = VOP_READLINK(vp, &auio, p->p_ucred); 12265992Swnj } 122737741Smckusick vput(vp); 122842441Smckusick *retval = uap->count - auio.uio_resid; 122947540Skarels return (error); 12305992Swnj } 12315992Swnj 12329167Ssam /* 1233*64410Sbostic * Change flags of a file given a path name. 123438259Smckusick */ 123554916Storek struct chflags_args { 1236*64410Sbostic char *path; 123754916Storek int flags; 123854916Storek }; 123942441Smckusick /* ARGSUSED */ 124042441Smckusick chflags(p, uap, retval) 124145914Smckusick struct proc *p; 124254916Storek register struct chflags_args *uap; 124342441Smckusick int *retval; 124442441Smckusick { 124538259Smckusick register struct vnode *vp; 124638259Smckusick struct vattr vattr; 124738259Smckusick int error; 124847540Skarels struct nameidata nd; 124938259Smckusick 1250*64410Sbostic NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); 125152322Smckusick if (error = namei(&nd)) 125247540Skarels return (error); 125352322Smckusick vp = nd.ni_vp; 125459382Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 125559382Smckusick VOP_LOCK(vp); 1256*64410Sbostic if (vp->v_mount->mnt_flag & MNT_RDONLY) 125738259Smckusick error = EROFS; 1258*64410Sbostic else { 1259*64410Sbostic VATTR_NULL(&vattr); 1260*64410Sbostic vattr.va_flags = uap->flags; 1261*64410Sbostic error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 126238259Smckusick } 126338259Smckusick vput(vp); 126447540Skarels return (error); 126538259Smckusick } 126638259Smckusick 126738259Smckusick /* 126838259Smckusick * Change flags of a file given a file descriptor. 126938259Smckusick */ 127054916Storek struct fchflags_args { 127154916Storek int fd; 127254916Storek int flags; 127354916Storek }; 127442441Smckusick /* ARGSUSED */ 127542441Smckusick fchflags(p, uap, retval) 127645914Smckusick struct proc *p; 127754916Storek register struct fchflags_args *uap; 127842441Smckusick int *retval; 127942441Smckusick { 128038259Smckusick struct vattr vattr; 128138259Smckusick struct vnode *vp; 128238259Smckusick struct file *fp; 128338259Smckusick int error; 128438259Smckusick 128545914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 128647540Skarels return (error); 128738259Smckusick vp = (struct vnode *)fp->f_data; 128859382Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 128938259Smckusick VOP_LOCK(vp); 1290*64410Sbostic if (vp->v_mount->mnt_flag & MNT_RDONLY) 129138259Smckusick error = EROFS; 1292*64410Sbostic else { 1293*64410Sbostic VATTR_NULL(&vattr); 1294*64410Sbostic vattr.va_flags = uap->flags; 1295*64410Sbostic error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 129638259Smckusick } 129738259Smckusick VOP_UNLOCK(vp); 129847540Skarels return (error); 129938259Smckusick } 130038259Smckusick 130138259Smckusick /* 13029167Ssam * Change mode of a file given path name. 13039167Ssam */ 130454916Storek struct chmod_args { 1305*64410Sbostic char *path; 1306*64410Sbostic int mode; 130754916Storek }; 130842441Smckusick /* ARGSUSED */ 130942441Smckusick chmod(p, uap, retval) 131045914Smckusick struct proc *p; 131154916Storek register struct chmod_args *uap; 131242441Smckusick int *retval; 131342441Smckusick { 131437741Smckusick register struct vnode *vp; 131537741Smckusick struct vattr vattr; 131637741Smckusick int error; 131747540Skarels struct nameidata nd; 13185992Swnj 1319*64410Sbostic NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); 132052322Smckusick if (error = namei(&nd)) 132147540Skarels return (error); 132252322Smckusick vp = nd.ni_vp; 132359382Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 132459382Smckusick VOP_LOCK(vp); 1325*64410Sbostic if (vp->v_mount->mnt_flag & MNT_RDONLY) 132637741Smckusick error = EROFS; 1327*64410Sbostic else { 1328*64410Sbostic VATTR_NULL(&vattr); 1329*64410Sbostic vattr.va_mode = uap->mode & ALLPERMS; 1330*64410Sbostic error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 133137741Smckusick } 133237741Smckusick vput(vp); 133347540Skarels return (error); 13347701Ssam } 13357439Sroot 13369167Ssam /* 13379167Ssam * Change mode of a file given a file descriptor. 13389167Ssam */ 133954916Storek struct fchmod_args { 134054916Storek int fd; 1341*64410Sbostic int mode; 134254916Storek }; 134342441Smckusick /* ARGSUSED */ 134442441Smckusick fchmod(p, uap, retval) 134545914Smckusick struct proc *p; 134654916Storek register struct fchmod_args *uap; 134742441Smckusick int *retval; 134842441Smckusick { 134937741Smckusick struct vattr vattr; 135037741Smckusick struct vnode *vp; 135137741Smckusick struct file *fp; 135237741Smckusick int error; 13537701Ssam 135445914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 135547540Skarels return (error); 135637741Smckusick vp = (struct vnode *)fp->f_data; 135759382Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 135837741Smckusick VOP_LOCK(vp); 1359*64410Sbostic if (vp->v_mount->mnt_flag & MNT_RDONLY) 136037741Smckusick error = EROFS; 1361*64410Sbostic else { 1362*64410Sbostic VATTR_NULL(&vattr); 1363*64410Sbostic vattr.va_mode = uap->mode & ALLPERMS; 1364*64410Sbostic error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 13657439Sroot } 136637741Smckusick VOP_UNLOCK(vp); 136747540Skarels return (error); 13685992Swnj } 13695992Swnj 13709167Ssam /* 13719167Ssam * Set ownership given a path name. 13729167Ssam */ 137354916Storek struct chown_args { 1374*64410Sbostic char *path; 137554916Storek int uid; 137654916Storek int gid; 137754916Storek }; 137842441Smckusick /* ARGSUSED */ 137942441Smckusick chown(p, uap, retval) 138045914Smckusick struct proc *p; 138154916Storek register struct chown_args *uap; 138242441Smckusick int *retval; 138342441Smckusick { 138437741Smckusick register struct vnode *vp; 138537741Smckusick struct vattr vattr; 138637741Smckusick int error; 138747540Skarels struct nameidata nd; 138837Sbill 1389*64410Sbostic NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, uap->path, p); 139052322Smckusick if (error = namei(&nd)) 139147540Skarels return (error); 139252322Smckusick vp = nd.ni_vp; 139359382Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 139459382Smckusick VOP_LOCK(vp); 1395*64410Sbostic if (vp->v_mount->mnt_flag & MNT_RDONLY) 139637741Smckusick error = EROFS; 1397*64410Sbostic else { 1398*64410Sbostic VATTR_NULL(&vattr); 1399*64410Sbostic vattr.va_uid = uap->uid; 1400*64410Sbostic vattr.va_gid = uap->gid; 1401*64410Sbostic error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 140237741Smckusick } 140337741Smckusick vput(vp); 140447540Skarels return (error); 14057701Ssam } 14067439Sroot 14079167Ssam /* 14089167Ssam * Set ownership given a file descriptor. 14099167Ssam */ 141054916Storek struct fchown_args { 141154916Storek int fd; 141254916Storek int uid; 141354916Storek int gid; 141454916Storek }; 141542441Smckusick /* ARGSUSED */ 141642441Smckusick fchown(p, uap, retval) 141745914Smckusick struct proc *p; 141854916Storek register struct fchown_args *uap; 141942441Smckusick int *retval; 142042441Smckusick { 142137741Smckusick struct vattr vattr; 142237741Smckusick struct vnode *vp; 142337741Smckusick struct file *fp; 142437741Smckusick int error; 14257701Ssam 142645914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 142747540Skarels return (error); 142837741Smckusick vp = (struct vnode *)fp->f_data; 142959382Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 143037741Smckusick VOP_LOCK(vp); 1431*64410Sbostic if (vp->v_mount->mnt_flag & MNT_RDONLY) 143237741Smckusick error = EROFS; 1433*64410Sbostic else { 1434*64410Sbostic VATTR_NULL(&vattr); 1435*64410Sbostic vattr.va_uid = uap->uid; 1436*64410Sbostic vattr.va_gid = uap->gid; 1437*64410Sbostic error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 143837741Smckusick } 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 { 1447*64410Sbostic char *path; 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*64410Sbostic NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); 147052322Smckusick if (error = namei(&nd)) 147147540Skarels return (error); 147252322Smckusick vp = nd.ni_vp; 147359382Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 147459382Smckusick VOP_LOCK(vp); 1475*64410Sbostic if (vp->v_mount->mnt_flag & MNT_RDONLY) 147637741Smckusick error = EROFS; 1477*64410Sbostic else { 1478*64410Sbostic vattr.va_atime.ts_sec = tv[0].tv_sec; 1479*64410Sbostic vattr.va_atime.ts_nsec = tv[0].tv_usec * 1000; 1480*64410Sbostic vattr.va_mtime.ts_sec = tv[1].tv_sec; 1481*64410Sbostic vattr.va_mtime.ts_nsec = tv[1].tv_usec * 1000; 1482*64410Sbostic error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 148321015Smckusick } 148437741Smckusick vput(vp); 148547540Skarels return (error); 148611811Ssam } 148711811Ssam 1488*64410Sbostic /* 1489*64410Sbostic * Truncate a file given its path name. 1490*64410Sbostic */ 149160428Smckusick struct truncate_args { 1492*64410Sbostic char *path; 149354863Storek int pad; 149454863Storek off_t length; 149554863Storek }; 149653468Smckusick /* ARGSUSED */ 149760414Smckusick truncate(p, uap, retval) 149853468Smckusick struct proc *p; 149960428Smckusick register struct truncate_args *uap; 150053468Smckusick int *retval; 150153468Smckusick { 150237741Smckusick register struct vnode *vp; 150337741Smckusick struct vattr vattr; 150437741Smckusick int error; 150547540Skarels struct nameidata nd; 15067701Ssam 1507*64410Sbostic NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); 150852322Smckusick if (error = namei(&nd)) 150947540Skarels return (error); 151052322Smckusick vp = nd.ni_vp; 151159382Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 151259382Smckusick VOP_LOCK(vp); 1513*64410Sbostic if (vp->v_type == VDIR) 151437741Smckusick error = EISDIR; 1515*64410Sbostic else if ((error = vn_writechk(vp)) == 0 && 1516*64410Sbostic (error = VOP_ACCESS(vp, VWRITE, p->p_ucred, p)) == 0) { 1517*64410Sbostic VATTR_NULL(&vattr); 1518*64410Sbostic vattr.va_size = uap->length; 1519*64410Sbostic error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 15207701Ssam } 152137741Smckusick vput(vp); 152247540Skarels return (error); 15237701Ssam } 15247701Ssam 1525*64410Sbostic /* 1526*64410Sbostic * Truncate a file given a file descriptor. 1527*64410Sbostic */ 152860428Smckusick struct ftruncate_args { 152954863Storek int fd; 153054863Storek int pad; 153154863Storek off_t length; 153254863Storek }; 153342441Smckusick /* ARGSUSED */ 153460414Smckusick ftruncate(p, uap, retval) 153545914Smckusick struct proc *p; 153660428Smckusick register struct ftruncate_args *uap; 153742441Smckusick int *retval; 153842441Smckusick { 153937741Smckusick struct vattr vattr; 154037741Smckusick struct vnode *vp; 15417701Ssam struct file *fp; 154237741Smckusick int error; 15437701Ssam 154445914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 154547540Skarels return (error); 154637741Smckusick if ((fp->f_flag & FWRITE) == 0) 154747540Skarels return (EINVAL); 154837741Smckusick vp = (struct vnode *)fp->f_data; 154959382Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 155037741Smckusick VOP_LOCK(vp); 1551*64410Sbostic if (vp->v_type == VDIR) 155237741Smckusick error = EISDIR; 1553*64410Sbostic else if ((error = vn_writechk(vp)) == 0) { 1554*64410Sbostic VATTR_NULL(&vattr); 1555*64410Sbostic vattr.va_size = uap->length; 1556*64410Sbostic error = VOP_SETATTR(vp, &vattr, fp->f_cred, p); 15577701Ssam } 155837741Smckusick VOP_UNLOCK(vp); 155947540Skarels return (error); 15607701Ssam } 15617701Ssam 156254863Storek #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 15639167Ssam /* 156454863Storek * Truncate a file given its path name. 156554863Storek */ 156660428Smckusick struct otruncate_args { 1567*64410Sbostic char *path; 156854916Storek long length; 156954916Storek }; 157054863Storek /* ARGSUSED */ 157160105Smckusick otruncate(p, uap, retval) 157254863Storek struct proc *p; 157360428Smckusick register struct otruncate_args *uap; 157454863Storek int *retval; 157554863Storek { 157660428Smckusick struct truncate_args nuap; 157754863Storek 1578*64410Sbostic nuap.path = uap->path; 157954863Storek nuap.length = uap->length; 158060428Smckusick return (truncate(p, &nuap, retval)); 158154863Storek } 158254863Storek 158354863Storek /* 158454863Storek * Truncate a file given a file descriptor. 158554863Storek */ 158660428Smckusick struct oftruncate_args { 158754916Storek int fd; 158854916Storek long length; 158954916Storek }; 159054863Storek /* ARGSUSED */ 159160105Smckusick oftruncate(p, uap, retval) 159254863Storek struct proc *p; 159360428Smckusick register struct oftruncate_args *uap; 159454863Storek int *retval; 159554863Storek { 159660428Smckusick struct ftruncate_args nuap; 159754863Storek 159854863Storek nuap.fd = uap->fd; 159954863Storek nuap.length = uap->length; 160060428Smckusick return (ftruncate(p, &nuap, retval)); 160154863Storek } 160254863Storek #endif /* COMPAT_43 || COMPAT_SUNOS */ 160354863Storek 160454863Storek /* 1605*64410Sbostic * Sync an open file. 16069167Ssam */ 160754916Storek struct fsync_args { 160854916Storek int fd; 160954916Storek }; 161042441Smckusick /* ARGSUSED */ 161142441Smckusick fsync(p, uap, retval) 161245914Smckusick struct proc *p; 161354916Storek struct fsync_args *uap; 161442441Smckusick int *retval; 16159167Ssam { 161639592Smckusick register struct vnode *vp; 16179167Ssam struct file *fp; 161837741Smckusick int error; 16199167Ssam 162045914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 162147540Skarels return (error); 162239592Smckusick vp = (struct vnode *)fp->f_data; 162339592Smckusick VOP_LOCK(vp); 162454441Smckusick error = VOP_FSYNC(vp, fp->f_cred, MNT_WAIT, p); 162539592Smckusick VOP_UNLOCK(vp); 162647540Skarels return (error); 16279167Ssam } 16289167Ssam 16299167Ssam /* 1630*64410Sbostic * Rename files. Source and destination must either both be directories, 1631*64410Sbostic * or both not be directories. If target is a directory, it must be empty. 16329167Ssam */ 163354916Storek struct rename_args { 163454916Storek char *from; 163554916Storek char *to; 163654916Storek }; 163742441Smckusick /* ARGSUSED */ 163842441Smckusick rename(p, uap, retval) 163945914Smckusick struct proc *p; 164054916Storek register struct rename_args *uap; 164142441Smckusick int *retval; 164242441Smckusick { 164337741Smckusick register struct vnode *tvp, *fvp, *tdvp; 164449735Smckusick struct nameidata fromnd, tond; 164537741Smckusick int error; 16467701Ssam 164752322Smckusick NDINIT(&fromnd, DELETE, WANTPARENT | SAVESTART, UIO_USERSPACE, 164852322Smckusick uap->from, p); 164952322Smckusick if (error = namei(&fromnd)) 165047540Skarels return (error); 165149735Smckusick fvp = fromnd.ni_vp; 165252322Smckusick NDINIT(&tond, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART, 165352322Smckusick UIO_USERSPACE, uap->to, p); 165452322Smckusick if (error = namei(&tond)) { 165552230Sheideman VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 165649735Smckusick vrele(fromnd.ni_dvp); 165742465Smckusick vrele(fvp); 165842465Smckusick goto out1; 165942465Smckusick } 166037741Smckusick tdvp = tond.ni_dvp; 166137741Smckusick tvp = tond.ni_vp; 166237741Smckusick if (tvp != NULL) { 166337741Smckusick if (fvp->v_type == VDIR && tvp->v_type != VDIR) { 166439242Sbostic error = ENOTDIR; 166537741Smckusick goto out; 166637741Smckusick } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) { 166739242Sbostic error = EISDIR; 166837741Smckusick goto out; 16699167Ssam } 16709167Ssam } 167139286Smckusick if (fvp == tdvp) 167237741Smckusick error = EINVAL; 167339286Smckusick /* 167449735Smckusick * If source is the same as the destination (that is the 167549735Smckusick * same inode number with the same name in the same directory), 167639286Smckusick * then there is nothing to do. 167739286Smckusick */ 167849735Smckusick if (fvp == tvp && fromnd.ni_dvp == tdvp && 167952322Smckusick fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen && 168052322Smckusick !bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr, 168152322Smckusick fromnd.ni_cnd.cn_namelen)) 168239286Smckusick error = -1; 168337741Smckusick out: 168442465Smckusick if (!error) { 168552192Smckusick LEASE_CHECK(tdvp, p, p->p_ucred, LEASE_WRITE); 168652192Smckusick if (fromnd.ni_dvp != tdvp) 168752192Smckusick LEASE_CHECK(fromnd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 168852192Smckusick if (tvp) 168952192Smckusick LEASE_CHECK(tvp, p, p->p_ucred, LEASE_WRITE); 169052230Sheideman error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd, 169152230Sheideman tond.ni_dvp, tond.ni_vp, &tond.ni_cnd); 169242465Smckusick } else { 169352230Sheideman VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd); 169443344Smckusick if (tdvp == tvp) 169543344Smckusick vrele(tdvp); 169643344Smckusick else 169743344Smckusick vput(tdvp); 169842465Smckusick if (tvp) 169942465Smckusick vput(tvp); 170052230Sheideman VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 170149735Smckusick vrele(fromnd.ni_dvp); 170242465Smckusick vrele(fvp); 17039167Ssam } 170449735Smckusick vrele(tond.ni_startdir); 170552322Smckusick FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI); 170637741Smckusick out1: 170749735Smckusick vrele(fromnd.ni_startdir); 170852322Smckusick FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI); 170939286Smckusick if (error == -1) 171047540Skarels return (0); 171147540Skarels return (error); 17127701Ssam } 17137701Ssam 17147535Sroot /* 1715*64410Sbostic * Make a directory file. 171612756Ssam */ 171754916Storek struct mkdir_args { 1718*64410Sbostic char *path; 1719*64410Sbostic int mode; 172054916Storek }; 172142441Smckusick /* ARGSUSED */ 172242441Smckusick mkdir(p, uap, retval) 172345914Smckusick struct proc *p; 172454916Storek register struct mkdir_args *uap; 172542441Smckusick int *retval; 172642441Smckusick { 172737741Smckusick register struct vnode *vp; 172837741Smckusick struct vattr vattr; 172937741Smckusick int error; 173047540Skarels struct nameidata nd; 173112756Ssam 1732*64410Sbostic NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->path, p); 173352322Smckusick if (error = namei(&nd)) 173447540Skarels return (error); 173552322Smckusick vp = nd.ni_vp; 173637741Smckusick if (vp != NULL) { 173752322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 173852322Smckusick if (nd.ni_dvp == vp) 173952322Smckusick vrele(nd.ni_dvp); 174043344Smckusick else 174152322Smckusick vput(nd.ni_dvp); 174242465Smckusick vrele(vp); 174347540Skarels return (EEXIST); 174412756Ssam } 174541362Smckusick VATTR_NULL(&vattr); 174637741Smckusick vattr.va_type = VDIR; 1747*64410Sbostic vattr.va_mode = (uap->mode & ACCESSPERMS) &~ p->p_fd->fd_cmask; 174852322Smckusick LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 174952322Smckusick error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr); 175038145Smckusick if (!error) 175152322Smckusick vput(nd.ni_vp); 175247540Skarels return (error); 175312756Ssam } 175412756Ssam 175512756Ssam /* 1756*64410Sbostic * Remove a directory file. 175712756Ssam */ 175854916Storek struct rmdir_args { 1759*64410Sbostic char *path; 176054916Storek }; 176142441Smckusick /* ARGSUSED */ 176242441Smckusick rmdir(p, uap, retval) 176345914Smckusick struct proc *p; 176454916Storek struct rmdir_args *uap; 176542441Smckusick int *retval; 176612756Ssam { 176737741Smckusick register struct vnode *vp; 176837741Smckusick int error; 176947540Skarels struct nameidata nd; 177012756Ssam 1771*64410Sbostic NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE, uap->path, p); 177252322Smckusick if (error = namei(&nd)) 177347540Skarels return (error); 177452322Smckusick vp = nd.ni_vp; 177537741Smckusick if (vp->v_type != VDIR) { 177637741Smckusick error = ENOTDIR; 177712756Ssam goto out; 177812756Ssam } 177912756Ssam /* 178037741Smckusick * No rmdir "." please. 178112756Ssam */ 178252322Smckusick if (nd.ni_dvp == vp) { 178337741Smckusick error = EINVAL; 178412756Ssam goto out; 178512756Ssam } 178612756Ssam /* 178749365Smckusick * The root of a mounted filesystem cannot be deleted. 178812756Ssam */ 178937741Smckusick if (vp->v_flag & VROOT) 179037741Smckusick error = EBUSY; 179112756Ssam out: 179242465Smckusick if (!error) { 179352322Smckusick LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 179452192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 179552322Smckusick error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); 179642465Smckusick } else { 179752322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 179852322Smckusick if (nd.ni_dvp == vp) 179952322Smckusick vrele(nd.ni_dvp); 180043344Smckusick else 180152322Smckusick vput(nd.ni_dvp); 180242465Smckusick vput(vp); 180342465Smckusick } 180447540Skarels return (error); 180512756Ssam } 180612756Ssam 180754620Smckusick #ifdef COMPAT_43 180837741Smckusick /* 180949365Smckusick * Read a block of directory entries in a file system independent format. 181037741Smckusick */ 181154916Storek struct ogetdirentries_args { 181254916Storek int fd; 181354916Storek char *buf; 1814*64410Sbostic u_int count; 181554916Storek long *basep; 181654916Storek }; 181754620Smckusick ogetdirentries(p, uap, retval) 181854620Smckusick struct proc *p; 181954916Storek register struct ogetdirentries_args *uap; 182054620Smckusick int *retval; 182154620Smckusick { 182254620Smckusick register struct vnode *vp; 182354620Smckusick struct file *fp; 182454620Smckusick struct uio auio, kuio; 182554620Smckusick struct iovec aiov, kiov; 182654620Smckusick struct dirent *dp, *edp; 182754620Smckusick caddr_t dirbuf; 182854620Smckusick int error, readcnt; 182954969Smckusick long loff; 183054620Smckusick 183154620Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 183254620Smckusick return (error); 183354620Smckusick if ((fp->f_flag & FREAD) == 0) 183454620Smckusick return (EBADF); 183554620Smckusick vp = (struct vnode *)fp->f_data; 183654620Smckusick if (vp->v_type != VDIR) 183754620Smckusick return (EINVAL); 183854620Smckusick aiov.iov_base = uap->buf; 183954620Smckusick aiov.iov_len = uap->count; 184054620Smckusick auio.uio_iov = &aiov; 184154620Smckusick auio.uio_iovcnt = 1; 184254620Smckusick auio.uio_rw = UIO_READ; 184354620Smckusick auio.uio_segflg = UIO_USERSPACE; 184454620Smckusick auio.uio_procp = p; 184554620Smckusick auio.uio_resid = uap->count; 184654620Smckusick VOP_LOCK(vp); 184754969Smckusick loff = auio.uio_offset = fp->f_offset; 184854620Smckusick # if (BYTE_ORDER != LITTLE_ENDIAN) 184956339Smckusick if (vp->v_mount->mnt_maxsymlinklen <= 0) { 185054620Smckusick error = VOP_READDIR(vp, &auio, fp->f_cred); 185156339Smckusick fp->f_offset = auio.uio_offset; 185256339Smckusick } else 185354620Smckusick # endif 185454620Smckusick { 185554620Smckusick kuio = auio; 185654620Smckusick kuio.uio_iov = &kiov; 185754620Smckusick kuio.uio_segflg = UIO_SYSSPACE; 185854620Smckusick kiov.iov_len = uap->count; 185954620Smckusick MALLOC(dirbuf, caddr_t, uap->count, M_TEMP, M_WAITOK); 186054620Smckusick kiov.iov_base = dirbuf; 186154620Smckusick error = VOP_READDIR(vp, &kuio, fp->f_cred); 186256339Smckusick fp->f_offset = kuio.uio_offset; 186354620Smckusick if (error == 0) { 186454620Smckusick readcnt = uap->count - kuio.uio_resid; 186554620Smckusick edp = (struct dirent *)&dirbuf[readcnt]; 186654620Smckusick for (dp = (struct dirent *)dirbuf; dp < edp; ) { 186754620Smckusick # if (BYTE_ORDER == LITTLE_ENDIAN) 186854969Smckusick /* 186955009Smckusick * The expected low byte of 187055009Smckusick * dp->d_namlen is our dp->d_type. 187155009Smckusick * The high MBZ byte of dp->d_namlen 187255009Smckusick * is our dp->d_namlen. 187354969Smckusick */ 187455009Smckusick dp->d_type = dp->d_namlen; 187555009Smckusick dp->d_namlen = 0; 187655009Smckusick # else 187755009Smckusick /* 187855009Smckusick * The dp->d_type is the high byte 187955009Smckusick * of the expected dp->d_namlen, 188055009Smckusick * so must be zero'ed. 188155009Smckusick */ 188255009Smckusick dp->d_type = 0; 188354620Smckusick # endif 188454620Smckusick if (dp->d_reclen > 0) { 188554620Smckusick dp = (struct dirent *) 188654620Smckusick ((char *)dp + dp->d_reclen); 188754620Smckusick } else { 188854620Smckusick error = EIO; 188954620Smckusick break; 189054620Smckusick } 189154620Smckusick } 189254620Smckusick if (dp >= edp) 189354620Smckusick error = uiomove(dirbuf, readcnt, &auio); 189454620Smckusick } 189554620Smckusick FREE(dirbuf, M_TEMP); 189654620Smckusick } 189754620Smckusick VOP_UNLOCK(vp); 189854620Smckusick if (error) 189954620Smckusick return (error); 190054969Smckusick error = copyout((caddr_t)&loff, (caddr_t)uap->basep, sizeof(long)); 190154620Smckusick *retval = uap->count - auio.uio_resid; 190254620Smckusick return (error); 190354620Smckusick } 190454620Smckusick #endif 190554620Smckusick 190654620Smckusick /* 190754620Smckusick * Read a block of directory entries in a file system independent format. 190854620Smckusick */ 190954916Storek struct getdirentries_args { 191054916Storek int fd; 191154916Storek char *buf; 1912*64410Sbostic u_int count; 191354916Storek long *basep; 191454916Storek }; 191542441Smckusick getdirentries(p, uap, retval) 191645914Smckusick struct proc *p; 191754916Storek register struct getdirentries_args *uap; 191842441Smckusick int *retval; 191942441Smckusick { 192039592Smckusick register struct vnode *vp; 192116540Ssam struct file *fp; 192237741Smckusick struct uio auio; 192337741Smckusick struct iovec aiov; 192454969Smckusick long loff; 192554441Smckusick int error; 192612756Ssam 192745914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 192847540Skarels return (error); 192937741Smckusick if ((fp->f_flag & FREAD) == 0) 193047540Skarels return (EBADF); 193139592Smckusick vp = (struct vnode *)fp->f_data; 193255451Spendry unionread: 193339592Smckusick if (vp->v_type != VDIR) 193447540Skarels return (EINVAL); 193537741Smckusick aiov.iov_base = uap->buf; 193637741Smckusick aiov.iov_len = uap->count; 193737741Smckusick auio.uio_iov = &aiov; 193837741Smckusick auio.uio_iovcnt = 1; 193937741Smckusick auio.uio_rw = UIO_READ; 194037741Smckusick auio.uio_segflg = UIO_USERSPACE; 194148026Smckusick auio.uio_procp = p; 194237741Smckusick auio.uio_resid = uap->count; 194339592Smckusick VOP_LOCK(vp); 194454969Smckusick loff = auio.uio_offset = fp->f_offset; 194554441Smckusick error = VOP_READDIR(vp, &auio, fp->f_cred); 194639592Smckusick fp->f_offset = auio.uio_offset; 194739592Smckusick VOP_UNLOCK(vp); 194839592Smckusick if (error) 194947540Skarels return (error); 195055451Spendry if ((uap->count == auio.uio_resid) && 195155451Spendry (vp->v_flag & VROOT) && 195255451Spendry (vp->v_mount->mnt_flag & MNT_UNION)) { 195355451Spendry struct vnode *tvp = vp; 195455451Spendry vp = vp->v_mount->mnt_vnodecovered; 195555451Spendry VREF(vp); 195655451Spendry fp->f_data = (caddr_t) vp; 195755451Spendry fp->f_offset = 0; 195855451Spendry vrele(tvp); 195955451Spendry goto unionread; 196055451Spendry } 196154969Smckusick error = copyout((caddr_t)&loff, (caddr_t)uap->basep, sizeof(long)); 196242441Smckusick *retval = uap->count - auio.uio_resid; 196347540Skarels return (error); 196412756Ssam } 196512756Ssam 196612756Ssam /* 196749365Smckusick * Set the mode mask for creation of filesystem nodes. 196812756Ssam */ 196954916Storek struct umask_args { 1970*64410Sbostic int newmask; 197154916Storek }; 197254916Storek mode_t /* XXX */ 197342441Smckusick umask(p, uap, retval) 197445914Smckusick struct proc *p; 197554916Storek struct umask_args *uap; 197642441Smckusick int *retval; 197712756Ssam { 1978*64410Sbostic register struct filedesc *fdp; 197912756Ssam 1980*64410Sbostic fdp = p->p_fd; 198145914Smckusick *retval = fdp->fd_cmask; 1982*64410Sbostic fdp->fd_cmask = uap->newmask & ALLPERMS; 198347540Skarels return (0); 198412756Ssam } 198537741Smckusick 198639566Smarc /* 198739566Smarc * Void all references to file by ripping underlying filesystem 198839566Smarc * away from vnode. 198939566Smarc */ 199054916Storek struct revoke_args { 1991*64410Sbostic char *path; 199254916Storek }; 199342441Smckusick /* ARGSUSED */ 199442441Smckusick revoke(p, uap, retval) 199545914Smckusick struct proc *p; 199654916Storek register struct revoke_args *uap; 199742441Smckusick int *retval; 199842441Smckusick { 199939566Smarc register struct vnode *vp; 200039566Smarc struct vattr vattr; 200139566Smarc int error; 200247540Skarels struct nameidata nd; 200339566Smarc 2004*64410Sbostic NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); 200552322Smckusick if (error = namei(&nd)) 200647540Skarels return (error); 200752322Smckusick vp = nd.ni_vp; 200839566Smarc if (vp->v_type != VCHR && vp->v_type != VBLK) { 200939566Smarc error = EINVAL; 201039566Smarc goto out; 201139566Smarc } 201248026Smckusick if (error = VOP_GETATTR(vp, &vattr, p->p_ucred, p)) 201339566Smarc goto out; 201447540Skarels if (p->p_ucred->cr_uid != vattr.va_uid && 201547540Skarels (error = suser(p->p_ucred, &p->p_acflag))) 201639566Smarc goto out; 201739805Smckusick if (vp->v_usecount > 1 || (vp->v_flag & VALIASED)) 201839632Smckusick vgoneall(vp); 201939566Smarc out: 202039566Smarc vrele(vp); 202147540Skarels return (error); 202239566Smarc } 202339566Smarc 202449365Smckusick /* 202549365Smckusick * Convert a user file descriptor to a kernel file entry. 202649365Smckusick */ 2027*64410Sbostic getvnode(fdp, fd, fpp) 202845914Smckusick struct filedesc *fdp; 202937741Smckusick struct file **fpp; 2030*64410Sbostic int fd; 203137741Smckusick { 203237741Smckusick struct file *fp; 203337741Smckusick 2034*64410Sbostic if ((u_int)fd >= fdp->fd_nfiles || 2035*64410Sbostic (fp = fdp->fd_ofiles[fd]) == NULL) 203637741Smckusick return (EBADF); 203737741Smckusick if (fp->f_type != DTYPE_VNODE) 203837741Smckusick return (EINVAL); 203937741Smckusick *fpp = fp; 204037741Smckusick return (0); 204137741Smckusick } 2042