123405Smckusick /* 237741Smckusick * Copyright (c) 1989 The Regents of the University of California. 337741Smckusick * All rights reserved. 423405Smckusick * 544459Sbostic * %sccs.include.redist.c% 637741Smckusick * 7*60414Smckusick * @(#)vfs_syscalls.c 7.111 (Berkeley) 05/25/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 2737741Smckusick /* 2837741Smckusick * Virtual File System System Calls 2937741Smckusick */ 3012756Ssam 319167Ssam /* 3249365Smckusick * Mount system call. 339167Ssam */ 3454916Storek struct mount_args { 3554916Storek int type; 3654916Storek char *dir; 3754916Storek int flags; 3854916Storek caddr_t data; 3954916Storek }; 4042441Smckusick /* ARGSUSED */ 4142441Smckusick mount(p, uap, retval) 4245914Smckusick struct proc *p; 4354916Storek register struct mount_args *uap; 4442441Smckusick int *retval; 4542441Smckusick { 4639335Smckusick register struct vnode *vp; 4739335Smckusick register struct mount *mp; 4840111Smckusick int error, flag; 4947540Skarels struct nameidata nd; 506254Sroot 5137741Smckusick /* 5237741Smckusick * Must be super user 5337741Smckusick */ 5447540Skarels if (error = suser(p->p_ucred, &p->p_acflag)) 5547540Skarels return (error); 5637741Smckusick /* 5737741Smckusick * Get vnode to be covered 5837741Smckusick */ 5952322Smckusick NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->dir, p); 6052322Smckusick if (error = namei(&nd)) 6147540Skarels return (error); 6252322Smckusick vp = nd.ni_vp; 6341400Smckusick if (uap->flags & MNT_UPDATE) { 6439335Smckusick if ((vp->v_flag & VROOT) == 0) { 6539335Smckusick vput(vp); 6647540Skarels return (EINVAL); 6739335Smckusick } 6839335Smckusick mp = vp->v_mount; 6957047Smckusick flag = mp->mnt_flag; 7039335Smckusick /* 7157047Smckusick * We only allow the filesystem to be reloaded if it 7257047Smckusick * is currently mounted read-only. 7339335Smckusick */ 7457047Smckusick if ((uap->flags & MNT_RELOAD) && 7557047Smckusick ((mp->mnt_flag & MNT_RDONLY) == 0)) { 7639335Smckusick vput(vp); 7747540Skarels return (EOPNOTSUPP); /* Needs translation */ 7839335Smckusick } 7957047Smckusick mp->mnt_flag |= 8057047Smckusick uap->flags & (MNT_RELOAD | MNT_FORCE | MNT_UPDATE); 8139335Smckusick VOP_UNLOCK(vp); 8239335Smckusick goto update; 8339335Smckusick } 8455451Spendry if (vp->v_usecount != 1 && (uap->flags & MNT_UNION) == 0) { 8537741Smckusick vput(vp); 8647540Skarels return (EBUSY); 8737741Smckusick } 8857793Smckusick if (error = vinvalbuf(vp, V_SAVE, p->p_ucred, p, 0, 0)) 8954441Smckusick return (error); 9037741Smckusick if (vp->v_type != VDIR) { 9137741Smckusick vput(vp); 9247540Skarels return (ENOTDIR); 9337741Smckusick } 9439741Smckusick if ((unsigned long)uap->type > MOUNT_MAXTYPE || 9537741Smckusick vfssw[uap->type] == (struct vfsops *)0) { 9637741Smckusick vput(vp); 9747540Skarels return (ENODEV); 9837741Smckusick } 9937741Smckusick 10037741Smckusick /* 10139335Smckusick * Allocate and initialize the file system. 10237741Smckusick */ 10337741Smckusick mp = (struct mount *)malloc((u_long)sizeof(struct mount), 10437741Smckusick M_MOUNT, M_WAITOK); 10554172Smckusick bzero((char *)mp, (u_long)sizeof(struct mount)); 10641400Smckusick mp->mnt_op = vfssw[uap->type]; 10739335Smckusick if (error = vfs_lock(mp)) { 10839335Smckusick free((caddr_t)mp, M_MOUNT); 10939335Smckusick vput(vp); 11047540Skarels return (error); 11139335Smckusick } 11239335Smckusick if (vp->v_mountedhere != (struct mount *)0) { 11339335Smckusick vfs_unlock(mp); 11439335Smckusick free((caddr_t)mp, M_MOUNT); 11539335Smckusick vput(vp); 11647540Skarels return (EBUSY); 11739335Smckusick } 11839335Smckusick vp->v_mountedhere = mp; 11941400Smckusick mp->mnt_vnodecovered = vp; 12039335Smckusick update: 12139335Smckusick /* 12239335Smckusick * Set the mount level flags. 12339335Smckusick */ 12441400Smckusick if (uap->flags & MNT_RDONLY) 12541400Smckusick mp->mnt_flag |= MNT_RDONLY; 12657047Smckusick else if (mp->mnt_flag & MNT_RDONLY) 12757047Smckusick mp->mnt_flag |= MNT_WANTRDWR; 12857047Smckusick mp->mnt_flag &=~ 12957047Smckusick (MNT_NOSUID | MNT_NOEXEC | MNT_NODEV | MNT_SYNCHRONOUS | MNT_UNION); 13057047Smckusick mp->mnt_flag |= uap->flags & 13157047Smckusick (MNT_NOSUID | MNT_NOEXEC | MNT_NODEV | MNT_SYNCHRONOUS | MNT_UNION); 13239335Smckusick /* 13339335Smckusick * Mount the filesystem. 13439335Smckusick */ 13552322Smckusick error = VFS_MOUNT(mp, uap->dir, uap->data, &nd, p); 13641400Smckusick if (mp->mnt_flag & MNT_UPDATE) { 13739335Smckusick vrele(vp); 13857047Smckusick if (mp->mnt_flag & MNT_WANTRDWR) 13957047Smckusick mp->mnt_flag &= ~MNT_RDONLY; 14057047Smckusick mp->mnt_flag &=~ 14157047Smckusick (MNT_UPDATE | MNT_RELOAD | MNT_FORCE | MNT_WANTRDWR); 14240111Smckusick if (error) 14341400Smckusick mp->mnt_flag = flag; 14447540Skarels return (error); 14539335Smckusick } 14640110Smckusick /* 14740110Smckusick * Put the new filesystem on the mount list after root. 14840110Smckusick */ 14941400Smckusick mp->mnt_next = rootfs->mnt_next; 15041400Smckusick mp->mnt_prev = rootfs; 15141400Smckusick rootfs->mnt_next = mp; 15241400Smckusick mp->mnt_next->mnt_prev = mp; 15337741Smckusick cache_purge(vp); 15437741Smckusick if (!error) { 15539335Smckusick VOP_UNLOCK(vp); 15637741Smckusick vfs_unlock(mp); 15748026Smckusick error = VFS_START(mp, 0, p); 15837741Smckusick } else { 15937741Smckusick vfs_remove(mp); 16037741Smckusick free((caddr_t)mp, M_MOUNT); 16139335Smckusick vput(vp); 16237741Smckusick } 16347540Skarels return (error); 1646254Sroot } 1656254Sroot 1669167Ssam /* 16737741Smckusick * Unmount system call. 16837741Smckusick * 16937741Smckusick * Note: unmount takes a path to the vnode mounted on as argument, 17037741Smckusick * not special file (as before). 1719167Ssam */ 17254916Storek struct unmount_args { 17354916Storek char *pathp; 17454916Storek int flags; 17554916Storek }; 17642441Smckusick /* ARGSUSED */ 17742441Smckusick unmount(p, uap, retval) 17845914Smckusick struct proc *p; 17954916Storek register struct unmount_args *uap; 18042441Smckusick int *retval; 18142441Smckusick { 18237741Smckusick register struct vnode *vp; 18339356Smckusick struct mount *mp; 18437741Smckusick int error; 18547540Skarels struct nameidata nd; 1866254Sroot 18737741Smckusick /* 18837741Smckusick * Must be super user 18937741Smckusick */ 19047540Skarels if (error = suser(p->p_ucred, &p->p_acflag)) 19147540Skarels return (error); 19237741Smckusick 19352322Smckusick NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->pathp, p); 19452322Smckusick if (error = namei(&nd)) 19547540Skarels return (error); 19652322Smckusick vp = nd.ni_vp; 19737741Smckusick /* 19837741Smckusick * Must be the root of the filesystem 19937741Smckusick */ 20037741Smckusick if ((vp->v_flag & VROOT) == 0) { 20137741Smckusick vput(vp); 20247540Skarels return (EINVAL); 20337741Smckusick } 20437741Smckusick mp = vp->v_mount; 20537741Smckusick vput(vp); 20648026Smckusick return (dounmount(mp, uap->flags, p)); 20739356Smckusick } 20839356Smckusick 20939356Smckusick /* 21039356Smckusick * Do an unmount. 21139356Smckusick */ 21248026Smckusick dounmount(mp, flags, p) 21339356Smckusick register struct mount *mp; 21439356Smckusick int flags; 21548026Smckusick struct proc *p; 21639356Smckusick { 21739356Smckusick struct vnode *coveredvp; 21839356Smckusick int error; 21939356Smckusick 22041400Smckusick coveredvp = mp->mnt_vnodecovered; 22141298Smckusick if (vfs_busy(mp)) 22241298Smckusick return (EBUSY); 22341400Smckusick mp->mnt_flag |= MNT_UNMOUNT; 22437741Smckusick if (error = vfs_lock(mp)) 22539356Smckusick return (error); 22637741Smckusick 22745738Smckusick vnode_pager_umount(mp); /* release cached vnodes */ 22837741Smckusick cache_purgevfs(mp); /* remove cache entries for this file sys */ 22954441Smckusick if ((error = VFS_SYNC(mp, MNT_WAIT, p->p_ucred, p)) == 0 || 23054441Smckusick (flags & MNT_FORCE)) 23148026Smckusick error = VFS_UNMOUNT(mp, flags, p); 23241400Smckusick mp->mnt_flag &= ~MNT_UNMOUNT; 23341298Smckusick vfs_unbusy(mp); 23437741Smckusick if (error) { 23537741Smckusick vfs_unlock(mp); 23637741Smckusick } else { 23737741Smckusick vrele(coveredvp); 23837741Smckusick vfs_remove(mp); 23952287Smckusick if (mp->mnt_mounth != NULL) 24052287Smckusick panic("unmount: dangling vnode"); 24137741Smckusick free((caddr_t)mp, M_MOUNT); 24237741Smckusick } 24339356Smckusick return (error); 2446254Sroot } 2456254Sroot 2469167Ssam /* 24737741Smckusick * Sync system call. 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 /* 29049365Smckusick * Operate on 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 { 46354916Storek char *fname; 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 47552322Smckusick NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 47652781Sralph if (error = chdirec(&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 { 48754916Storek char *fname; 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); 50152322Smckusick NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 50252781Sralph if (error = chdirec(&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 */ 51347540Skarels chdirec(ndp, p) 51452322Smckusick register struct nameidata *ndp; 51547540Skarels struct proc *p; 51637741Smckusick { 51737741Smckusick struct vnode *vp; 51837741Smckusick int error; 51937741Smckusick 52052322Smckusick if (error = namei(ndp)) 52137741Smckusick return (error); 52237741Smckusick vp = ndp->ni_vp; 52337741Smckusick if (vp->v_type != VDIR) 52437741Smckusick error = ENOTDIR; 52537741Smckusick else 52648026Smckusick error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p); 52737741Smckusick VOP_UNLOCK(vp); 52837741Smckusick if (error) 52937741Smckusick vrele(vp); 53037741Smckusick return (error); 53137741Smckusick } 53237741Smckusick 53337741Smckusick /* 5346254Sroot * Open system call. 53542441Smckusick * Check permissions, allocate an open file structure, 53642441Smckusick * and call the device open routine if any. 5376254Sroot */ 53854916Storek struct open_args { 53954916Storek char *fname; 54054916Storek int mode; 54154916Storek int crtmode; 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; 55137741Smckusick int fmode, 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; 56146553Skarels fmode = FFLAGS(uap->mode); 56245914Smckusick cmode = ((uap->crtmode &~ fdp->fd_cmask) & 07777) &~ S_ISVTX; 56352322Smckusick NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->fname, p); 56445202Smckusick p->p_dupfd = -indx - 1; /* XXX check for fdopen */ 56552322Smckusick if (error = vn_open(&nd, fmode, cmode)) { 56649980Smckusick ffree(fp); 56754723Smckusick if ((error == ENODEV || error == ENXIO) && 56854723Smckusick p->p_dupfd >= 0 && /* XXX from fdopen */ 56953828Spendry (error = dupfdopen(fdp, indx, p->p_dupfd, 57053828Spendry fmode, 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; 58149949Smckusick fp->f_flag = fmode & FMASK; 58254348Smckusick fp->f_type = DTYPE_VNODE; 58354348Smckusick fp->f_ops = &vnops; 58454348Smckusick fp->f_data = (caddr_t)vp; 58549945Smckusick if (fmode & (O_EXLOCK | O_SHLOCK)) { 58649945Smckusick lf.l_whence = SEEK_SET; 58749945Smckusick lf.l_start = 0; 58849945Smckusick lf.l_len = 0; 58949945Smckusick if (fmode & O_EXLOCK) 59049945Smckusick lf.l_type = F_WRLCK; 59149945Smckusick else 59249945Smckusick lf.l_type = F_RDLCK; 59349945Smckusick type = F_FLOCK; 59449945Smckusick if ((fmode & 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 /* 61242441Smckusick * Creat system call. 6136254Sroot */ 61454916Storek struct ocreat_args { 61554916Storek char *fname; 61654916Storek int fmode; 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 62542441Smckusick openuap.fname = uap->fname; 62642441Smckusick openuap.crtmode = uap->fmode; 62742441Smckusick openuap.mode = O_WRONLY | O_CREAT | O_TRUNC; 62847540Skarels return (open(p, &openuap, retval)); 62942441Smckusick } 63042955Smckusick #endif /* COMPAT_43 */ 63142441Smckusick 63242441Smckusick /* 63349365Smckusick * Mknod system call. 63442441Smckusick */ 63554916Storek struct mknod_args { 63654916Storek char *fname; 63754916Storek int fmode; 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); 65352322Smckusick NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->fname, 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); 66240635Smckusick switch (uap->fmode & S_IFMT) { 66312756Ssam 66440635Smckusick case S_IFMT: /* used by badsect to flag bad sectors */ 66537741Smckusick vattr.va_type = VBAD; 66637741Smckusick break; 66740635Smckusick case S_IFCHR: 66837741Smckusick vattr.va_type = VCHR; 66937741Smckusick break; 67040635Smckusick case S_IFBLK: 67137741Smckusick vattr.va_type = VBLK; 67237741Smckusick break; 67337741Smckusick default: 67437741Smckusick error = EINVAL; 67537741Smckusick goto out; 6766254Sroot } 67745914Smckusick vattr.va_mode = (uap->fmode & 07777) &~ p->p_fd->fd_cmask; 67837741Smckusick vattr.va_rdev = uap->dev; 6796254Sroot out: 68042465Smckusick if (!error) { 68152322Smckusick LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 68252322Smckusick error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr); 68342465Smckusick } else { 68452322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 68552322Smckusick if (nd.ni_dvp == vp) 68652322Smckusick vrele(nd.ni_dvp); 68743344Smckusick else 68852322Smckusick vput(nd.ni_dvp); 68942465Smckusick if (vp) 69042465Smckusick vrele(vp); 69142465Smckusick } 69247540Skarels return (error); 6936254Sroot } 6946254Sroot 6956254Sroot /* 69649365Smckusick * Mkfifo system call. 69740285Smckusick */ 69854916Storek struct mkfifo_args { 69954916Storek char *fname; 70054916Storek int fmode; 70154916Storek }; 70242441Smckusick /* ARGSUSED */ 70342441Smckusick mkfifo(p, uap, retval) 70445914Smckusick struct proc *p; 70554916Storek register struct mkfifo_args *uap; 70642441Smckusick int *retval; 70742441Smckusick { 70840285Smckusick struct vattr vattr; 70940285Smckusick int error; 71047540Skarels struct nameidata nd; 71140285Smckusick 71240285Smckusick #ifndef FIFO 71347540Skarels return (EOPNOTSUPP); 71440285Smckusick #else 71552322Smckusick NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->fname, p); 71652322Smckusick if (error = namei(&nd)) 71747540Skarels return (error); 71852322Smckusick if (nd.ni_vp != NULL) { 71952322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 72052322Smckusick if (nd.ni_dvp == nd.ni_vp) 72152322Smckusick vrele(nd.ni_dvp); 72243344Smckusick else 72352322Smckusick vput(nd.ni_dvp); 72452322Smckusick vrele(nd.ni_vp); 72547540Skarels return (EEXIST); 72640285Smckusick } 72745785Sbostic VATTR_NULL(&vattr); 72845785Sbostic vattr.va_type = VFIFO; 72945914Smckusick vattr.va_mode = (uap->fmode & 07777) &~ p->p_fd->fd_cmask; 73052322Smckusick LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 73152322Smckusick return (VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr)); 73240285Smckusick #endif /* FIFO */ 73340285Smckusick } 73440285Smckusick 73540285Smckusick /* 73649365Smckusick * Link system call. 7376254Sroot */ 73854916Storek struct link_args { 73954916Storek char *target; 74054916Storek char *linkname; 74154916Storek }; 74242441Smckusick /* ARGSUSED */ 74342441Smckusick link(p, uap, retval) 74445914Smckusick struct proc *p; 74554916Storek register struct link_args *uap; 74642441Smckusick int *retval; 74742441Smckusick { 74837741Smckusick register struct vnode *vp, *xp; 74937741Smckusick int error; 75047540Skarels struct nameidata nd; 7516254Sroot 75252322Smckusick NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->target, p); 75352322Smckusick if (error = namei(&nd)) 75447540Skarels return (error); 75552322Smckusick vp = nd.ni_vp; 75637741Smckusick if (vp->v_type == VDIR && 75747540Skarels (error = suser(p->p_ucred, &p->p_acflag))) 75837741Smckusick goto out1; 75952322Smckusick nd.ni_cnd.cn_nameiop = CREATE; 76052322Smckusick nd.ni_cnd.cn_flags = LOCKPARENT; 76152322Smckusick nd.ni_dirp = (caddr_t)uap->linkname; 76252322Smckusick if (error = namei(&nd)) 76337741Smckusick goto out1; 76452322Smckusick xp = nd.ni_vp; 7656254Sroot if (xp != NULL) { 76637741Smckusick error = EEXIST; 7676254Sroot goto out; 7686254Sroot } 76952322Smckusick xp = nd.ni_dvp; 7706254Sroot out: 77142465Smckusick if (!error) { 77252192Smckusick LEASE_CHECK(xp, p, p->p_ucred, LEASE_WRITE); 77352192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 77452821Smckusick error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd); 77542465Smckusick } else { 77652322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 77752322Smckusick if (nd.ni_dvp == nd.ni_vp) 77852322Smckusick vrele(nd.ni_dvp); 77943344Smckusick else 78052322Smckusick vput(nd.ni_dvp); 78152322Smckusick if (nd.ni_vp) 78252322Smckusick vrele(nd.ni_vp); 78342465Smckusick } 78437741Smckusick out1: 78537741Smckusick vrele(vp); 78647540Skarels return (error); 7876254Sroot } 7886254Sroot 7896254Sroot /* 79049365Smckusick * Make a symbolic link. 7916254Sroot */ 79254916Storek struct symlink_args { 79354916Storek char *target; 79454916Storek char *linkname; 79554916Storek }; 79642441Smckusick /* ARGSUSED */ 79742441Smckusick symlink(p, uap, retval) 79845914Smckusick struct proc *p; 79954916Storek register struct symlink_args *uap; 80042441Smckusick int *retval; 80142441Smckusick { 80237741Smckusick struct vattr vattr; 80337741Smckusick char *target; 80437741Smckusick int error; 80547540Skarels struct nameidata nd; 8066254Sroot 80737741Smckusick MALLOC(target, char *, MAXPATHLEN, M_NAMEI, M_WAITOK); 80837741Smckusick if (error = copyinstr(uap->target, target, MAXPATHLEN, (u_int *)0)) 80942465Smckusick goto out; 81052322Smckusick NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->linkname, p); 81152322Smckusick if (error = namei(&nd)) 81242465Smckusick goto out; 81352322Smckusick if (nd.ni_vp) { 81452322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 81552322Smckusick if (nd.ni_dvp == nd.ni_vp) 81652322Smckusick vrele(nd.ni_dvp); 81743344Smckusick else 81852322Smckusick vput(nd.ni_dvp); 81952322Smckusick vrele(nd.ni_vp); 82037741Smckusick error = EEXIST; 82137741Smckusick goto out; 8226254Sroot } 82341362Smckusick VATTR_NULL(&vattr); 82445914Smckusick vattr.va_mode = 0777 &~ p->p_fd->fd_cmask; 82552322Smckusick LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 82652322Smckusick error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr, target); 82737741Smckusick out: 82837741Smckusick FREE(target, M_NAMEI); 82947540Skarels return (error); 8306254Sroot } 8316254Sroot 8326254Sroot /* 83349365Smckusick * Delete a name from the filesystem. 8346254Sroot */ 83554916Storek struct unlink_args { 83654916Storek char *name; 83754916Storek }; 83842441Smckusick /* ARGSUSED */ 83942441Smckusick unlink(p, uap, retval) 84045914Smckusick struct proc *p; 84154916Storek struct unlink_args *uap; 84242441Smckusick int *retval; 8436254Sroot { 84437741Smckusick register struct vnode *vp; 84537741Smckusick int error; 84647540Skarels struct nameidata nd; 8476254Sroot 84859382Smckusick NDINIT(&nd, DELETE, LOCKPARENT, UIO_USERSPACE, uap->name, p); 84952322Smckusick if (error = namei(&nd)) 85047540Skarels return (error); 85152322Smckusick vp = nd.ni_vp; 85259382Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 85359382Smckusick VOP_LOCK(vp); 85437741Smckusick if (vp->v_type == VDIR && 85547540Skarels (error = suser(p->p_ucred, &p->p_acflag))) 8566254Sroot goto out; 8576254Sroot /* 85849365Smckusick * The root of a mounted filesystem cannot be deleted. 8596254Sroot */ 86037741Smckusick if (vp->v_flag & VROOT) { 86137741Smckusick error = EBUSY; 8626254Sroot goto out; 8636254Sroot } 86445738Smckusick (void) vnode_pager_uncache(vp); 8656254Sroot out: 86642465Smckusick if (!error) { 86752322Smckusick LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 86852322Smckusick error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); 86942465Smckusick } else { 87052322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 87152322Smckusick if (nd.ni_dvp == vp) 87252322Smckusick vrele(nd.ni_dvp); 87343344Smckusick else 87452322Smckusick vput(nd.ni_dvp); 87542465Smckusick vput(vp); 87642465Smckusick } 87747540Skarels return (error); 8786254Sroot } 8796254Sroot 88054916Storek struct __lseek_args { 88154863Storek int fdes; 88254863Storek int pad; 88354863Storek off_t off; 88454863Storek int sbase; 88554863Storek }; 88654863Storek 8876254Sroot /* 88849365Smckusick * Seek system call. 8896254Sroot */ 890*60414Smckusick lseek(p, uap, retval) 89153468Smckusick struct proc *p; 89254916Storek register struct __lseek_args *uap; 89354916Storek int *retval; 89442441Smckusick { 89547540Skarels struct ucred *cred = p->p_ucred; 89645914Smckusick register struct filedesc *fdp = p->p_fd; 89742441Smckusick register struct file *fp; 89837741Smckusick struct vattr vattr; 89937741Smckusick int error; 9006254Sroot 90147540Skarels if ((unsigned)uap->fdes >= fdp->fd_nfiles || 90247688Skarels (fp = fdp->fd_ofiles[uap->fdes]) == NULL) 90347540Skarels return (EBADF); 90437741Smckusick if (fp->f_type != DTYPE_VNODE) 90547540Skarels return (ESPIPE); 90613878Ssam switch (uap->sbase) { 90713878Ssam 90813878Ssam case L_INCR: 90913878Ssam fp->f_offset += uap->off; 91013878Ssam break; 91113878Ssam 91213878Ssam case L_XTND: 91337741Smckusick if (error = VOP_GETATTR((struct vnode *)fp->f_data, 91448026Smckusick &vattr, cred, p)) 91547540Skarels return (error); 91637741Smckusick fp->f_offset = uap->off + vattr.va_size; 91713878Ssam break; 91813878Ssam 91913878Ssam case L_SET: 92013878Ssam fp->f_offset = uap->off; 92113878Ssam break; 92213878Ssam 92313878Ssam default: 92447540Skarels return (EINVAL); 92513878Ssam } 92654916Storek *(off_t *)retval = fp->f_offset; 92747540Skarels return (0); 9286254Sroot } 9296254Sroot 930*60414Smckusick #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 9316254Sroot /* 93260036Smckusick * Old lseek system call. 93360036Smckusick */ 93460036Smckusick struct lseek_args { 93560036Smckusick int fdes; 93660036Smckusick long off; 93760036Smckusick int sbase; 93860036Smckusick }; 939*60414Smckusick olseek(p, uap, retval) 94060036Smckusick struct proc *p; 94160036Smckusick register struct lseek_args *uap; 94260036Smckusick int *retval; 94360036Smckusick { 94460036Smckusick struct __lseek_args nuap; 94560036Smckusick off_t qret; 94660036Smckusick int error; 94760036Smckusick 94860036Smckusick nuap.fdes = uap->fdes; 94960036Smckusick nuap.off = uap->off; 95060036Smckusick nuap.sbase = uap->sbase; 95160036Smckusick error = __lseek(p, &nuap, &qret); 95260036Smckusick *(long *)retval = qret; 95360036Smckusick return (error); 95460036Smckusick } 955*60414Smckusick #endif /* COMPAT_43 */ 95660036Smckusick 95760036Smckusick /* 95849365Smckusick * Check access permissions. 9596254Sroot */ 96054916Storek struct saccess_args { 96154916Storek char *fname; 96254916Storek int fmode; 96354916Storek }; 96442441Smckusick /* ARGSUSED */ 96542441Smckusick saccess(p, uap, retval) 96645914Smckusick struct proc *p; 96754916Storek register struct saccess_args *uap; 96842441Smckusick int *retval; 96942441Smckusick { 97047540Skarels register struct ucred *cred = p->p_ucred; 97137741Smckusick register struct vnode *vp; 97237741Smckusick int error, mode, svuid, svgid; 97347540Skarels struct nameidata nd; 9746254Sroot 97542441Smckusick svuid = cred->cr_uid; 97642441Smckusick svgid = cred->cr_groups[0]; 97747540Skarels cred->cr_uid = p->p_cred->p_ruid; 97847540Skarels cred->cr_groups[0] = p->p_cred->p_rgid; 97952322Smckusick NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 98052322Smckusick if (error = namei(&nd)) 98137741Smckusick goto out1; 98252322Smckusick vp = nd.ni_vp; 98337741Smckusick /* 98437741Smckusick * fmode == 0 means only check for exist 98537741Smckusick */ 98637741Smckusick if (uap->fmode) { 98737741Smckusick mode = 0; 98837741Smckusick if (uap->fmode & R_OK) 98937741Smckusick mode |= VREAD; 99037741Smckusick if (uap->fmode & W_OK) 99137741Smckusick mode |= VWRITE; 99237741Smckusick if (uap->fmode & X_OK) 99337741Smckusick mode |= VEXEC; 99439543Smckusick if ((mode & VWRITE) == 0 || (error = vn_writechk(vp)) == 0) 99548026Smckusick error = VOP_ACCESS(vp, mode, cred, p); 9966254Sroot } 99737741Smckusick vput(vp); 99837741Smckusick out1: 99942441Smckusick cred->cr_uid = svuid; 100042441Smckusick cred->cr_groups[0] = svgid; 100147540Skarels return (error); 10026254Sroot } 10036254Sroot 100454348Smckusick #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 10056254Sroot /* 100649365Smckusick * Stat system call. 100749365Smckusick * This version follows links. 100837Sbill */ 100954916Storek struct ostat_args { 101054916Storek char *fname; 101154916Storek struct ostat *ub; 101254916Storek }; 101342441Smckusick /* ARGSUSED */ 101453759Smckusick ostat(p, uap, retval) 101545914Smckusick struct proc *p; 101654916Storek register struct ostat_args *uap; 101753468Smckusick int *retval; 101853468Smckusick { 101953468Smckusick struct stat sb; 102053468Smckusick struct ostat osb; 102153468Smckusick int error; 102253468Smckusick struct nameidata nd; 102353468Smckusick 102453468Smckusick NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 102553468Smckusick if (error = namei(&nd)) 102653468Smckusick return (error); 102753468Smckusick error = vn_stat(nd.ni_vp, &sb, p); 102853468Smckusick vput(nd.ni_vp); 102953468Smckusick if (error) 103053468Smckusick return (error); 103153468Smckusick cvtstat(&sb, &osb); 103253468Smckusick error = copyout((caddr_t)&osb, (caddr_t)uap->ub, sizeof (osb)); 103353468Smckusick return (error); 103453468Smckusick } 103553468Smckusick 103653468Smckusick /* 103753468Smckusick * Lstat system call. 103853468Smckusick * This version does not follow links. 103953468Smckusick */ 104054916Storek struct olstat_args { 104154916Storek char *fname; 104254916Storek struct ostat *ub; 104354916Storek }; 104453468Smckusick /* ARGSUSED */ 104553759Smckusick olstat(p, uap, retval) 104653468Smckusick struct proc *p; 104754916Storek register struct olstat_args *uap; 104853468Smckusick int *retval; 104953468Smckusick { 105053468Smckusick struct stat sb; 105153468Smckusick struct ostat osb; 105253468Smckusick int error; 105353468Smckusick struct nameidata nd; 105453468Smckusick 105553468Smckusick NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 105653468Smckusick if (error = namei(&nd)) 105753468Smckusick return (error); 105853468Smckusick error = vn_stat(nd.ni_vp, &sb, p); 105953468Smckusick vput(nd.ni_vp); 106053468Smckusick if (error) 106153468Smckusick return (error); 106253468Smckusick cvtstat(&sb, &osb); 106353468Smckusick error = copyout((caddr_t)&osb, (caddr_t)uap->ub, sizeof (osb)); 106453468Smckusick return (error); 106553468Smckusick } 106653468Smckusick 106753468Smckusick /* 106853468Smckusick * convert from an old to a new stat structure. 106953468Smckusick */ 107053468Smckusick cvtstat(st, ost) 107153468Smckusick struct stat *st; 107253468Smckusick struct ostat *ost; 107353468Smckusick { 107453468Smckusick 107553468Smckusick ost->st_dev = st->st_dev; 107653468Smckusick ost->st_ino = st->st_ino; 107753468Smckusick ost->st_mode = st->st_mode; 107853468Smckusick ost->st_nlink = st->st_nlink; 107953468Smckusick ost->st_uid = st->st_uid; 108053468Smckusick ost->st_gid = st->st_gid; 108153468Smckusick ost->st_rdev = st->st_rdev; 108253468Smckusick if (st->st_size < (quad_t)1 << 32) 108353468Smckusick ost->st_size = st->st_size; 108453468Smckusick else 108553468Smckusick ost->st_size = -2; 108653468Smckusick ost->st_atime = st->st_atime; 108753468Smckusick ost->st_mtime = st->st_mtime; 108853468Smckusick ost->st_ctime = st->st_ctime; 108953468Smckusick ost->st_blksize = st->st_blksize; 109053468Smckusick ost->st_blocks = st->st_blocks; 109153468Smckusick ost->st_flags = st->st_flags; 109253468Smckusick ost->st_gen = st->st_gen; 109353468Smckusick } 109454348Smckusick #endif /* COMPAT_43 || COMPAT_SUNOS */ 109553468Smckusick 109653468Smckusick /* 109753468Smckusick * Stat system call. 109853468Smckusick * This version follows links. 109953468Smckusick */ 110054916Storek struct stat_args { 110154916Storek char *fname; 110254916Storek struct stat *ub; 110354916Storek }; 110453468Smckusick /* ARGSUSED */ 110553759Smckusick stat(p, uap, retval) 110653468Smckusick struct proc *p; 110754916Storek register struct stat_args *uap; 110842441Smckusick int *retval; 110937Sbill { 111042441Smckusick struct stat sb; 111142441Smckusick int error; 111247540Skarels struct nameidata nd; 111337Sbill 111452322Smckusick NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 111552322Smckusick if (error = namei(&nd)) 111647540Skarels return (error); 111752322Smckusick error = vn_stat(nd.ni_vp, &sb, p); 111852322Smckusick vput(nd.ni_vp); 111942441Smckusick if (error) 112047540Skarels return (error); 112142441Smckusick error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb)); 112247540Skarels return (error); 112337Sbill } 112437Sbill 112537Sbill /* 112649365Smckusick * Lstat system call. 112749365Smckusick * This version does not follow links. 11285992Swnj */ 112954916Storek struct lstat_args { 113054916Storek char *fname; 113154916Storek struct stat *ub; 113254916Storek }; 113342441Smckusick /* ARGSUSED */ 113453759Smckusick lstat(p, uap, retval) 113545914Smckusick struct proc *p; 113654916Storek register struct lstat_args *uap; 113742441Smckusick int *retval; 113842441Smckusick { 113937741Smckusick int error; 114059373Smckusick struct vnode *vp, *dvp; 114159373Smckusick struct stat sb, sb1; 114247540Skarels struct nameidata nd; 11435992Swnj 114459373Smckusick NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | LOCKPARENT, UIO_USERSPACE, 114559373Smckusick uap->fname, p); 114652322Smckusick if (error = namei(&nd)) 114747540Skarels return (error); 114859373Smckusick /* 114959373Smckusick * For symbolic links, always return the attributes of its 115059373Smckusick * containing directory, except for mode, size, and links. 115159373Smckusick */ 115259373Smckusick vp = nd.ni_vp; 115359373Smckusick dvp = nd.ni_dvp; 115459373Smckusick if (vp->v_type != VLNK) { 115559373Smckusick if (dvp == vp) 115659373Smckusick vrele(dvp); 115759373Smckusick else 115859373Smckusick vput(dvp); 115959373Smckusick error = vn_stat(vp, &sb, p); 116059373Smckusick vput(vp); 116159373Smckusick if (error) 116259373Smckusick return (error); 116359373Smckusick } else { 116459373Smckusick error = vn_stat(dvp, &sb, p); 116559373Smckusick vput(dvp); 116659373Smckusick if (error) { 116759373Smckusick vput(vp); 116859373Smckusick return (error); 116959373Smckusick } 117059373Smckusick error = vn_stat(vp, &sb1, p); 117159373Smckusick vput(vp); 117259373Smckusick if (error) 117359373Smckusick return (error); 117459373Smckusick sb.st_mode &= ~S_IFDIR; 117559373Smckusick sb.st_mode |= S_IFLNK; 117659373Smckusick sb.st_nlink = sb1.st_nlink; 117759373Smckusick sb.st_size = sb1.st_size; 117859373Smckusick sb.st_blocks = sb1.st_blocks; 117959373Smckusick } 118037741Smckusick error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb)); 118147540Skarels return (error); 11825992Swnj } 11835992Swnj 11845992Swnj /* 1185*60414Smckusick * Pathconf system call. 1186*60414Smckusick */ 1187*60414Smckusick struct pathconf_args { 1188*60414Smckusick char *fname; 1189*60414Smckusick int name; 1190*60414Smckusick }; 1191*60414Smckusick /* ARGSUSED */ 1192*60414Smckusick pathconf(p, uap, retval) 1193*60414Smckusick struct proc *p; 1194*60414Smckusick register struct pathconf_args *uap; 1195*60414Smckusick int *retval; 1196*60414Smckusick { 1197*60414Smckusick int error; 1198*60414Smckusick struct nameidata nd; 1199*60414Smckusick 1200*60414Smckusick NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); 1201*60414Smckusick if (error = namei(&nd)) 1202*60414Smckusick return (error); 1203*60414Smckusick error = VOP_PATHCONF(nd.ni_vp, uap->name, retval); 1204*60414Smckusick vput(nd.ni_vp); 1205*60414Smckusick return (error); 1206*60414Smckusick } 1207*60414Smckusick 1208*60414Smckusick /* 120949365Smckusick * Return target name of a symbolic link. 121037Sbill */ 121154916Storek struct readlink_args { 121254916Storek char *name; 121354916Storek char *buf; 121454916Storek int count; 121554916Storek }; 121642441Smckusick /* ARGSUSED */ 121742441Smckusick readlink(p, uap, retval) 121845914Smckusick struct proc *p; 121954916Storek register struct readlink_args *uap; 122042441Smckusick int *retval; 122142441Smckusick { 122237741Smckusick register struct vnode *vp; 122337741Smckusick struct iovec aiov; 122437741Smckusick struct uio auio; 122537741Smckusick int error; 122647540Skarels struct nameidata nd; 12275992Swnj 122852322Smckusick NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, uap->name, p); 122952322Smckusick if (error = namei(&nd)) 123047540Skarels return (error); 123152322Smckusick vp = nd.ni_vp; 123237741Smckusick if (vp->v_type != VLNK) { 123337741Smckusick error = EINVAL; 12345992Swnj goto out; 12355992Swnj } 123637741Smckusick aiov.iov_base = uap->buf; 123737741Smckusick aiov.iov_len = uap->count; 123837741Smckusick auio.uio_iov = &aiov; 123937741Smckusick auio.uio_iovcnt = 1; 124037741Smckusick auio.uio_offset = 0; 124137741Smckusick auio.uio_rw = UIO_READ; 124237741Smckusick auio.uio_segflg = UIO_USERSPACE; 124348026Smckusick auio.uio_procp = p; 124437741Smckusick auio.uio_resid = uap->count; 124547540Skarels error = VOP_READLINK(vp, &auio, p->p_ucred); 12465992Swnj out: 124737741Smckusick vput(vp); 124842441Smckusick *retval = uap->count - auio.uio_resid; 124947540Skarels return (error); 12505992Swnj } 12515992Swnj 12529167Ssam /* 125338259Smckusick * Change flags of a file given path name. 125438259Smckusick */ 125554916Storek struct chflags_args { 125654916Storek char *fname; 125754916Storek int flags; 125854916Storek }; 125942441Smckusick /* ARGSUSED */ 126042441Smckusick chflags(p, uap, retval) 126145914Smckusick struct proc *p; 126254916Storek register struct chflags_args *uap; 126342441Smckusick int *retval; 126442441Smckusick { 126538259Smckusick register struct vnode *vp; 126638259Smckusick struct vattr vattr; 126738259Smckusick int error; 126847540Skarels struct nameidata nd; 126938259Smckusick 127059382Smckusick NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->fname, p); 127152322Smckusick if (error = namei(&nd)) 127247540Skarels return (error); 127352322Smckusick vp = nd.ni_vp; 127459382Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 127559382Smckusick VOP_LOCK(vp); 127641400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 127738259Smckusick error = EROFS; 127838259Smckusick goto out; 127938259Smckusick } 128045785Sbostic VATTR_NULL(&vattr); 128145785Sbostic vattr.va_flags = uap->flags; 128248026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 128338259Smckusick out: 128438259Smckusick vput(vp); 128547540Skarels return (error); 128638259Smckusick } 128738259Smckusick 128838259Smckusick /* 128938259Smckusick * Change flags of a file given a file descriptor. 129038259Smckusick */ 129154916Storek struct fchflags_args { 129254916Storek int fd; 129354916Storek int flags; 129454916Storek }; 129542441Smckusick /* ARGSUSED */ 129642441Smckusick fchflags(p, uap, retval) 129745914Smckusick struct proc *p; 129854916Storek register struct fchflags_args *uap; 129942441Smckusick int *retval; 130042441Smckusick { 130138259Smckusick struct vattr vattr; 130238259Smckusick struct vnode *vp; 130338259Smckusick struct file *fp; 130438259Smckusick int error; 130538259Smckusick 130645914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 130747540Skarels return (error); 130838259Smckusick vp = (struct vnode *)fp->f_data; 130959382Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 131038259Smckusick VOP_LOCK(vp); 131141400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 131238259Smckusick error = EROFS; 131338259Smckusick goto out; 131438259Smckusick } 131545785Sbostic VATTR_NULL(&vattr); 131645785Sbostic vattr.va_flags = uap->flags; 131748026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 131838259Smckusick out: 131938259Smckusick VOP_UNLOCK(vp); 132047540Skarels return (error); 132138259Smckusick } 132238259Smckusick 132338259Smckusick /* 13249167Ssam * Change mode of a file given path name. 13259167Ssam */ 132654916Storek struct chmod_args { 132754916Storek char *fname; 132854916Storek int fmode; 132954916Storek }; 133042441Smckusick /* ARGSUSED */ 133142441Smckusick chmod(p, uap, retval) 133245914Smckusick struct proc *p; 133354916Storek register struct chmod_args *uap; 133442441Smckusick int *retval; 133542441Smckusick { 133637741Smckusick register struct vnode *vp; 133737741Smckusick struct vattr vattr; 133837741Smckusick int error; 133947540Skarels struct nameidata nd; 13405992Swnj 134159382Smckusick NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->fname, p); 134252322Smckusick if (error = namei(&nd)) 134347540Skarels return (error); 134452322Smckusick vp = nd.ni_vp; 134559382Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 134659382Smckusick VOP_LOCK(vp); 134741400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 134837741Smckusick error = EROFS; 134937741Smckusick goto out; 135037741Smckusick } 135145785Sbostic VATTR_NULL(&vattr); 135245785Sbostic vattr.va_mode = uap->fmode & 07777; 135348026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 135437741Smckusick out: 135537741Smckusick vput(vp); 135647540Skarels return (error); 13577701Ssam } 13587439Sroot 13599167Ssam /* 13609167Ssam * Change mode of a file given a file descriptor. 13619167Ssam */ 136254916Storek struct fchmod_args { 136354916Storek int fd; 136454916Storek int fmode; 136554916Storek }; 136642441Smckusick /* ARGSUSED */ 136742441Smckusick fchmod(p, uap, retval) 136845914Smckusick struct proc *p; 136954916Storek register struct fchmod_args *uap; 137042441Smckusick int *retval; 137142441Smckusick { 137237741Smckusick struct vattr vattr; 137337741Smckusick struct vnode *vp; 137437741Smckusick struct file *fp; 137537741Smckusick int error; 13767701Ssam 137745914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 137847540Skarels return (error); 137937741Smckusick vp = (struct vnode *)fp->f_data; 138059382Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 138137741Smckusick VOP_LOCK(vp); 138241400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 138337741Smckusick error = EROFS; 138437741Smckusick goto out; 13857439Sroot } 138645785Sbostic VATTR_NULL(&vattr); 138745785Sbostic vattr.va_mode = uap->fmode & 07777; 138848026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 138937741Smckusick out: 139037741Smckusick VOP_UNLOCK(vp); 139147540Skarels return (error); 13925992Swnj } 13935992Swnj 13949167Ssam /* 13959167Ssam * Set ownership given a path name. 13969167Ssam */ 139754916Storek struct chown_args { 139854916Storek char *fname; 139954916Storek int uid; 140054916Storek int gid; 140154916Storek }; 140242441Smckusick /* ARGSUSED */ 140342441Smckusick chown(p, uap, retval) 140445914Smckusick struct proc *p; 140554916Storek register struct chown_args *uap; 140642441Smckusick int *retval; 140742441Smckusick { 140837741Smckusick register struct vnode *vp; 140937741Smckusick struct vattr vattr; 141037741Smckusick int error; 141147540Skarels struct nameidata nd; 141237Sbill 141359382Smckusick NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, uap->fname, p); 141452322Smckusick if (error = namei(&nd)) 141547540Skarels return (error); 141652322Smckusick vp = nd.ni_vp; 141759382Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 141859382Smckusick VOP_LOCK(vp); 141941400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 142037741Smckusick error = EROFS; 142137741Smckusick goto out; 142237741Smckusick } 142345785Sbostic VATTR_NULL(&vattr); 142445785Sbostic vattr.va_uid = uap->uid; 142545785Sbostic vattr.va_gid = uap->gid; 142648026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 142737741Smckusick out: 142837741Smckusick vput(vp); 142947540Skarels return (error); 14307701Ssam } 14317439Sroot 14329167Ssam /* 14339167Ssam * Set ownership given a file descriptor. 14349167Ssam */ 143554916Storek struct fchown_args { 143654916Storek int fd; 143754916Storek int uid; 143854916Storek int gid; 143954916Storek }; 144042441Smckusick /* ARGSUSED */ 144142441Smckusick fchown(p, uap, retval) 144245914Smckusick struct proc *p; 144354916Storek register struct fchown_args *uap; 144442441Smckusick int *retval; 144542441Smckusick { 144637741Smckusick struct vattr vattr; 144737741Smckusick struct vnode *vp; 144837741Smckusick struct file *fp; 144937741Smckusick int error; 14507701Ssam 145145914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 145247540Skarels return (error); 145337741Smckusick vp = (struct vnode *)fp->f_data; 145459382Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 145537741Smckusick VOP_LOCK(vp); 145641400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 145737741Smckusick error = EROFS; 145837741Smckusick goto out; 145937741Smckusick } 146045785Sbostic VATTR_NULL(&vattr); 146145785Sbostic vattr.va_uid = uap->uid; 146245785Sbostic vattr.va_gid = uap->gid; 146348026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 146437741Smckusick out: 146537741Smckusick VOP_UNLOCK(vp); 146647540Skarels return (error); 14677701Ssam } 14687701Ssam 146942441Smckusick /* 147042441Smckusick * Set the access and modification times of a file. 147142441Smckusick */ 147254916Storek struct utimes_args { 147354916Storek char *fname; 147454916Storek struct timeval *tptr; 147554916Storek }; 147642441Smckusick /* ARGSUSED */ 147742441Smckusick utimes(p, uap, retval) 147845914Smckusick struct proc *p; 147954916Storek register struct utimes_args *uap; 148042441Smckusick int *retval; 148142441Smckusick { 148237741Smckusick register struct vnode *vp; 148311811Ssam struct timeval tv[2]; 148437741Smckusick struct vattr vattr; 148558840Storek int error; 148647540Skarels struct nameidata nd; 148711811Ssam 148858505Sbostic VATTR_NULL(&vattr); 148958505Sbostic if (uap->tptr == NULL) { 149058505Sbostic microtime(&tv[0]); 149158505Sbostic tv[1] = tv[0]; 149258548Sbostic vattr.va_vaflags |= VA_UTIMES_NULL; 149358505Sbostic } else if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv))) 149458505Sbostic return (error); 149559382Smckusick NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->fname, p); 149652322Smckusick if (error = namei(&nd)) 149747540Skarels return (error); 149852322Smckusick vp = nd.ni_vp; 149959382Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 150059382Smckusick VOP_LOCK(vp); 150141400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 150237741Smckusick error = EROFS; 150337741Smckusick goto out; 150421015Smckusick } 150554100Smckusick vattr.va_atime.ts_sec = tv[0].tv_sec; 150654100Smckusick vattr.va_atime.ts_nsec = tv[0].tv_usec * 1000; 150754100Smckusick vattr.va_mtime.ts_sec = tv[1].tv_sec; 150854100Smckusick vattr.va_mtime.ts_nsec = tv[1].tv_usec * 1000; 150948026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 151037741Smckusick out: 151137741Smckusick vput(vp); 151247540Skarels return (error); 151311811Ssam } 151411811Ssam 151554916Storek struct __truncate_args { 151654863Storek char *fname; 151754863Storek int pad; 151854863Storek off_t length; 151954863Storek }; 152053468Smckusick 152153468Smckusick /* 152253468Smckusick * Truncate a file given its path name. 152353468Smckusick */ 152453468Smckusick /* ARGSUSED */ 1525*60414Smckusick truncate(p, uap, retval) 152653468Smckusick struct proc *p; 152754916Storek register struct __truncate_args *uap; 152853468Smckusick int *retval; 152953468Smckusick { 153037741Smckusick register struct vnode *vp; 153137741Smckusick struct vattr vattr; 153237741Smckusick int error; 153347540Skarels struct nameidata nd; 15347701Ssam 153559382Smckusick NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->fname, p); 153652322Smckusick if (error = namei(&nd)) 153747540Skarels return (error); 153852322Smckusick vp = nd.ni_vp; 153959382Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 154059382Smckusick VOP_LOCK(vp); 154137741Smckusick if (vp->v_type == VDIR) { 154237741Smckusick error = EISDIR; 154337741Smckusick goto out; 15447701Ssam } 154538399Smckusick if ((error = vn_writechk(vp)) || 154648026Smckusick (error = VOP_ACCESS(vp, VWRITE, p->p_ucred, p))) 154737741Smckusick goto out; 154845785Sbostic VATTR_NULL(&vattr); 154945785Sbostic vattr.va_size = uap->length; 155048026Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 155137741Smckusick out: 155237741Smckusick vput(vp); 155347540Skarels return (error); 15547701Ssam } 15557701Ssam 155654916Storek struct __ftruncate_args { 155754863Storek int fd; 155854863Storek int pad; 155954863Storek off_t length; 156054863Storek }; 156154863Storek 15629167Ssam /* 15639167Ssam * Truncate a file given a file descriptor. 15649167Ssam */ 156542441Smckusick /* ARGSUSED */ 1566*60414Smckusick ftruncate(p, uap, retval) 156745914Smckusick struct proc *p; 156854916Storek register struct __ftruncate_args *uap; 156942441Smckusick int *retval; 157042441Smckusick { 157137741Smckusick struct vattr vattr; 157237741Smckusick struct vnode *vp; 15737701Ssam struct file *fp; 157437741Smckusick int error; 15757701Ssam 157645914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 157747540Skarels return (error); 157837741Smckusick if ((fp->f_flag & FWRITE) == 0) 157947540Skarels return (EINVAL); 158037741Smckusick vp = (struct vnode *)fp->f_data; 158159382Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 158237741Smckusick VOP_LOCK(vp); 158337741Smckusick if (vp->v_type == VDIR) { 158437741Smckusick error = EISDIR; 158537741Smckusick goto out; 15867701Ssam } 158738399Smckusick if (error = vn_writechk(vp)) 158837741Smckusick goto out; 158945785Sbostic VATTR_NULL(&vattr); 159045785Sbostic vattr.va_size = uap->length; 159148026Smckusick error = VOP_SETATTR(vp, &vattr, fp->f_cred, p); 159237741Smckusick out: 159337741Smckusick VOP_UNLOCK(vp); 159447540Skarels return (error); 15957701Ssam } 15967701Ssam 159754863Storek #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 15989167Ssam /* 159954863Storek * Truncate a file given its path name. 160054863Storek */ 160154916Storek struct truncate_args { 160254916Storek char *fname; 160354916Storek long length; 160454916Storek }; 160554863Storek /* ARGSUSED */ 160660105Smckusick otruncate(p, uap, retval) 160754863Storek struct proc *p; 160854916Storek register struct truncate_args *uap; 160954863Storek int *retval; 161054863Storek { 161154916Storek struct __truncate_args nuap; 161254863Storek 161354863Storek nuap.fname = uap->fname; 161454863Storek nuap.length = uap->length; 161554863Storek return (__truncate(p, &nuap, retval)); 161654863Storek } 161754863Storek 161854863Storek /* 161954863Storek * Truncate a file given a file descriptor. 162054863Storek */ 162154916Storek struct ftruncate_args { 162254916Storek int fd; 162354916Storek long length; 162454916Storek }; 162554863Storek /* ARGSUSED */ 162660105Smckusick oftruncate(p, uap, retval) 162754863Storek struct proc *p; 162854916Storek register struct ftruncate_args *uap; 162954863Storek int *retval; 163054863Storek { 163154969Smckusick struct __ftruncate_args nuap; 163254863Storek 163354863Storek nuap.fd = uap->fd; 163454863Storek nuap.length = uap->length; 163554863Storek return (__ftruncate(p, &nuap, retval)); 163654863Storek } 163754863Storek #endif /* COMPAT_43 || COMPAT_SUNOS */ 163854863Storek 163954863Storek /* 16409167Ssam * Synch an open file. 16419167Ssam */ 164254916Storek struct fsync_args { 164354916Storek int fd; 164454916Storek }; 164542441Smckusick /* ARGSUSED */ 164642441Smckusick fsync(p, uap, retval) 164745914Smckusick struct proc *p; 164854916Storek struct fsync_args *uap; 164942441Smckusick int *retval; 16509167Ssam { 165139592Smckusick register struct vnode *vp; 16529167Ssam struct file *fp; 165337741Smckusick int error; 16549167Ssam 165545914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 165647540Skarels return (error); 165739592Smckusick vp = (struct vnode *)fp->f_data; 165839592Smckusick VOP_LOCK(vp); 165954441Smckusick error = VOP_FSYNC(vp, fp->f_cred, MNT_WAIT, p); 166039592Smckusick VOP_UNLOCK(vp); 166147540Skarels return (error); 16629167Ssam } 16639167Ssam 16649167Ssam /* 16659167Ssam * Rename system call. 16669167Ssam * 16679167Ssam * Source and destination must either both be directories, or both 16689167Ssam * not be directories. If target is a directory, it must be empty. 16699167Ssam */ 167054916Storek struct rename_args { 167154916Storek char *from; 167254916Storek char *to; 167354916Storek }; 167442441Smckusick /* ARGSUSED */ 167542441Smckusick rename(p, uap, retval) 167645914Smckusick struct proc *p; 167754916Storek register struct rename_args *uap; 167842441Smckusick int *retval; 167942441Smckusick { 168037741Smckusick register struct vnode *tvp, *fvp, *tdvp; 168149735Smckusick struct nameidata fromnd, tond; 168237741Smckusick int error; 16837701Ssam 168452322Smckusick NDINIT(&fromnd, DELETE, WANTPARENT | SAVESTART, UIO_USERSPACE, 168552322Smckusick uap->from, p); 168652322Smckusick if (error = namei(&fromnd)) 168747540Skarels return (error); 168849735Smckusick fvp = fromnd.ni_vp; 168952322Smckusick NDINIT(&tond, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART, 169052322Smckusick UIO_USERSPACE, uap->to, p); 169152322Smckusick if (error = namei(&tond)) { 169252230Sheideman VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 169349735Smckusick vrele(fromnd.ni_dvp); 169442465Smckusick vrele(fvp); 169542465Smckusick goto out1; 169642465Smckusick } 169737741Smckusick tdvp = tond.ni_dvp; 169837741Smckusick tvp = tond.ni_vp; 169937741Smckusick if (tvp != NULL) { 170037741Smckusick if (fvp->v_type == VDIR && tvp->v_type != VDIR) { 170139242Sbostic error = ENOTDIR; 170237741Smckusick goto out; 170337741Smckusick } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) { 170439242Sbostic error = EISDIR; 170537741Smckusick goto out; 17069167Ssam } 17079167Ssam } 170839286Smckusick if (fvp == tdvp) 170937741Smckusick error = EINVAL; 171039286Smckusick /* 171149735Smckusick * If source is the same as the destination (that is the 171249735Smckusick * same inode number with the same name in the same directory), 171339286Smckusick * then there is nothing to do. 171439286Smckusick */ 171549735Smckusick if (fvp == tvp && fromnd.ni_dvp == tdvp && 171652322Smckusick fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen && 171752322Smckusick !bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr, 171852322Smckusick fromnd.ni_cnd.cn_namelen)) 171939286Smckusick error = -1; 172037741Smckusick out: 172142465Smckusick if (!error) { 172252192Smckusick LEASE_CHECK(tdvp, p, p->p_ucred, LEASE_WRITE); 172352192Smckusick if (fromnd.ni_dvp != tdvp) 172452192Smckusick LEASE_CHECK(fromnd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 172552192Smckusick if (tvp) 172652192Smckusick LEASE_CHECK(tvp, p, p->p_ucred, LEASE_WRITE); 172752230Sheideman error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd, 172852230Sheideman tond.ni_dvp, tond.ni_vp, &tond.ni_cnd); 172942465Smckusick } else { 173052230Sheideman VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd); 173143344Smckusick if (tdvp == tvp) 173243344Smckusick vrele(tdvp); 173343344Smckusick else 173443344Smckusick vput(tdvp); 173542465Smckusick if (tvp) 173642465Smckusick vput(tvp); 173752230Sheideman VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 173849735Smckusick vrele(fromnd.ni_dvp); 173942465Smckusick vrele(fvp); 17409167Ssam } 174149735Smckusick vrele(tond.ni_startdir); 174252322Smckusick FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI); 174337741Smckusick out1: 174449735Smckusick vrele(fromnd.ni_startdir); 174552322Smckusick FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI); 174639286Smckusick if (error == -1) 174747540Skarels return (0); 174847540Skarels return (error); 17497701Ssam } 17507701Ssam 17517535Sroot /* 175249365Smckusick * Mkdir system call. 175312756Ssam */ 175454916Storek struct mkdir_args { 175554916Storek char *name; 175654916Storek int dmode; 175754916Storek }; 175842441Smckusick /* ARGSUSED */ 175942441Smckusick mkdir(p, uap, retval) 176045914Smckusick struct proc *p; 176154916Storek register struct mkdir_args *uap; 176242441Smckusick int *retval; 176342441Smckusick { 176437741Smckusick register struct vnode *vp; 176537741Smckusick struct vattr vattr; 176637741Smckusick int error; 176747540Skarels struct nameidata nd; 176812756Ssam 176952322Smckusick NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->name, p); 177052322Smckusick if (error = namei(&nd)) 177147540Skarels return (error); 177252322Smckusick vp = nd.ni_vp; 177337741Smckusick if (vp != NULL) { 177452322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 177552322Smckusick if (nd.ni_dvp == vp) 177652322Smckusick vrele(nd.ni_dvp); 177743344Smckusick else 177852322Smckusick vput(nd.ni_dvp); 177942465Smckusick vrele(vp); 178047540Skarels return (EEXIST); 178112756Ssam } 178241362Smckusick VATTR_NULL(&vattr); 178337741Smckusick vattr.va_type = VDIR; 178445914Smckusick vattr.va_mode = (uap->dmode & 0777) &~ p->p_fd->fd_cmask; 178552322Smckusick LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 178652322Smckusick error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr); 178738145Smckusick if (!error) 178852322Smckusick vput(nd.ni_vp); 178947540Skarels return (error); 179012756Ssam } 179112756Ssam 179212756Ssam /* 179312756Ssam * Rmdir system call. 179412756Ssam */ 179554916Storek struct rmdir_args { 179654916Storek char *name; 179754916Storek }; 179842441Smckusick /* ARGSUSED */ 179942441Smckusick rmdir(p, uap, retval) 180045914Smckusick struct proc *p; 180154916Storek struct rmdir_args *uap; 180242441Smckusick int *retval; 180312756Ssam { 180437741Smckusick register struct vnode *vp; 180537741Smckusick int error; 180647540Skarels struct nameidata nd; 180712756Ssam 180852322Smckusick NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE, uap->name, p); 180952322Smckusick if (error = namei(&nd)) 181047540Skarels return (error); 181152322Smckusick vp = nd.ni_vp; 181237741Smckusick if (vp->v_type != VDIR) { 181337741Smckusick error = ENOTDIR; 181412756Ssam goto out; 181512756Ssam } 181612756Ssam /* 181737741Smckusick * No rmdir "." please. 181812756Ssam */ 181952322Smckusick if (nd.ni_dvp == vp) { 182037741Smckusick error = EINVAL; 182112756Ssam goto out; 182212756Ssam } 182312756Ssam /* 182449365Smckusick * The root of a mounted filesystem cannot be deleted. 182512756Ssam */ 182637741Smckusick if (vp->v_flag & VROOT) 182737741Smckusick error = EBUSY; 182812756Ssam out: 182942465Smckusick if (!error) { 183052322Smckusick LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 183152192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 183252322Smckusick error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); 183342465Smckusick } else { 183452322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 183552322Smckusick if (nd.ni_dvp == vp) 183652322Smckusick vrele(nd.ni_dvp); 183743344Smckusick else 183852322Smckusick vput(nd.ni_dvp); 183942465Smckusick vput(vp); 184042465Smckusick } 184147540Skarels return (error); 184212756Ssam } 184312756Ssam 184454620Smckusick #ifdef COMPAT_43 184537741Smckusick /* 184649365Smckusick * Read a block of directory entries in a file system independent format. 184737741Smckusick */ 184854916Storek struct ogetdirentries_args { 184954916Storek int fd; 185054916Storek char *buf; 185154916Storek unsigned count; 185254916Storek long *basep; 185354916Storek }; 185454620Smckusick ogetdirentries(p, uap, retval) 185554620Smckusick struct proc *p; 185654916Storek register struct ogetdirentries_args *uap; 185754620Smckusick int *retval; 185854620Smckusick { 185954620Smckusick register struct vnode *vp; 186054620Smckusick struct file *fp; 186154620Smckusick struct uio auio, kuio; 186254620Smckusick struct iovec aiov, kiov; 186354620Smckusick struct dirent *dp, *edp; 186454620Smckusick caddr_t dirbuf; 186554620Smckusick int error, readcnt; 186654969Smckusick long loff; 186754620Smckusick 186854620Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 186954620Smckusick return (error); 187054620Smckusick if ((fp->f_flag & FREAD) == 0) 187154620Smckusick return (EBADF); 187254620Smckusick vp = (struct vnode *)fp->f_data; 187354620Smckusick if (vp->v_type != VDIR) 187454620Smckusick return (EINVAL); 187554620Smckusick aiov.iov_base = uap->buf; 187654620Smckusick aiov.iov_len = uap->count; 187754620Smckusick auio.uio_iov = &aiov; 187854620Smckusick auio.uio_iovcnt = 1; 187954620Smckusick auio.uio_rw = UIO_READ; 188054620Smckusick auio.uio_segflg = UIO_USERSPACE; 188154620Smckusick auio.uio_procp = p; 188254620Smckusick auio.uio_resid = uap->count; 188354620Smckusick VOP_LOCK(vp); 188454969Smckusick loff = auio.uio_offset = fp->f_offset; 188554620Smckusick # if (BYTE_ORDER != LITTLE_ENDIAN) 188656339Smckusick if (vp->v_mount->mnt_maxsymlinklen <= 0) { 188754620Smckusick error = VOP_READDIR(vp, &auio, fp->f_cred); 188856339Smckusick fp->f_offset = auio.uio_offset; 188956339Smckusick } else 189054620Smckusick # endif 189154620Smckusick { 189254620Smckusick kuio = auio; 189354620Smckusick kuio.uio_iov = &kiov; 189454620Smckusick kuio.uio_segflg = UIO_SYSSPACE; 189554620Smckusick kiov.iov_len = uap->count; 189654620Smckusick MALLOC(dirbuf, caddr_t, uap->count, M_TEMP, M_WAITOK); 189754620Smckusick kiov.iov_base = dirbuf; 189854620Smckusick error = VOP_READDIR(vp, &kuio, fp->f_cred); 189956339Smckusick fp->f_offset = kuio.uio_offset; 190054620Smckusick if (error == 0) { 190154620Smckusick readcnt = uap->count - kuio.uio_resid; 190254620Smckusick edp = (struct dirent *)&dirbuf[readcnt]; 190354620Smckusick for (dp = (struct dirent *)dirbuf; dp < edp; ) { 190454620Smckusick # if (BYTE_ORDER == LITTLE_ENDIAN) 190554969Smckusick /* 190655009Smckusick * The expected low byte of 190755009Smckusick * dp->d_namlen is our dp->d_type. 190855009Smckusick * The high MBZ byte of dp->d_namlen 190955009Smckusick * is our dp->d_namlen. 191054969Smckusick */ 191155009Smckusick dp->d_type = dp->d_namlen; 191255009Smckusick dp->d_namlen = 0; 191355009Smckusick # else 191455009Smckusick /* 191555009Smckusick * The dp->d_type is the high byte 191655009Smckusick * of the expected dp->d_namlen, 191755009Smckusick * so must be zero'ed. 191855009Smckusick */ 191955009Smckusick dp->d_type = 0; 192054620Smckusick # endif 192154620Smckusick if (dp->d_reclen > 0) { 192254620Smckusick dp = (struct dirent *) 192354620Smckusick ((char *)dp + dp->d_reclen); 192454620Smckusick } else { 192554620Smckusick error = EIO; 192654620Smckusick break; 192754620Smckusick } 192854620Smckusick } 192954620Smckusick if (dp >= edp) 193054620Smckusick error = uiomove(dirbuf, readcnt, &auio); 193154620Smckusick } 193254620Smckusick FREE(dirbuf, M_TEMP); 193354620Smckusick } 193454620Smckusick VOP_UNLOCK(vp); 193554620Smckusick if (error) 193654620Smckusick return (error); 193754969Smckusick error = copyout((caddr_t)&loff, (caddr_t)uap->basep, sizeof(long)); 193854620Smckusick *retval = uap->count - auio.uio_resid; 193954620Smckusick return (error); 194054620Smckusick } 194154620Smckusick #endif 194254620Smckusick 194354620Smckusick /* 194454620Smckusick * Read a block of directory entries in a file system independent format. 194554620Smckusick */ 194654916Storek struct getdirentries_args { 194754916Storek int fd; 194854916Storek char *buf; 194954916Storek unsigned count; 195054916Storek long *basep; 195154916Storek }; 195242441Smckusick getdirentries(p, uap, retval) 195345914Smckusick struct proc *p; 195454916Storek register struct getdirentries_args *uap; 195542441Smckusick int *retval; 195642441Smckusick { 195739592Smckusick register struct vnode *vp; 195816540Ssam struct file *fp; 195937741Smckusick struct uio auio; 196037741Smckusick struct iovec aiov; 196154969Smckusick long loff; 196254441Smckusick int error; 196312756Ssam 196445914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 196547540Skarels return (error); 196637741Smckusick if ((fp->f_flag & FREAD) == 0) 196747540Skarels return (EBADF); 196839592Smckusick vp = (struct vnode *)fp->f_data; 196955451Spendry unionread: 197039592Smckusick if (vp->v_type != VDIR) 197147540Skarels return (EINVAL); 197237741Smckusick aiov.iov_base = uap->buf; 197337741Smckusick aiov.iov_len = uap->count; 197437741Smckusick auio.uio_iov = &aiov; 197537741Smckusick auio.uio_iovcnt = 1; 197637741Smckusick auio.uio_rw = UIO_READ; 197737741Smckusick auio.uio_segflg = UIO_USERSPACE; 197848026Smckusick auio.uio_procp = p; 197937741Smckusick auio.uio_resid = uap->count; 198039592Smckusick VOP_LOCK(vp); 198154969Smckusick loff = auio.uio_offset = fp->f_offset; 198254441Smckusick error = VOP_READDIR(vp, &auio, fp->f_cred); 198339592Smckusick fp->f_offset = auio.uio_offset; 198439592Smckusick VOP_UNLOCK(vp); 198539592Smckusick if (error) 198647540Skarels return (error); 198755451Spendry if ((uap->count == auio.uio_resid) && 198855451Spendry (vp->v_flag & VROOT) && 198955451Spendry (vp->v_mount->mnt_flag & MNT_UNION)) { 199055451Spendry struct vnode *tvp = vp; 199155451Spendry vp = vp->v_mount->mnt_vnodecovered; 199255451Spendry VREF(vp); 199355451Spendry fp->f_data = (caddr_t) vp; 199455451Spendry fp->f_offset = 0; 199555451Spendry vrele(tvp); 199655451Spendry goto unionread; 199755451Spendry } 199854969Smckusick error = copyout((caddr_t)&loff, (caddr_t)uap->basep, sizeof(long)); 199942441Smckusick *retval = uap->count - auio.uio_resid; 200047540Skarels return (error); 200112756Ssam } 200212756Ssam 200312756Ssam /* 200449365Smckusick * Set the mode mask for creation of filesystem nodes. 200512756Ssam */ 200654916Storek struct umask_args { 200754916Storek int mask; 200854916Storek }; 200954916Storek mode_t /* XXX */ 201042441Smckusick umask(p, uap, retval) 201145914Smckusick struct proc *p; 201254916Storek struct umask_args *uap; 201342441Smckusick int *retval; 201412756Ssam { 201545914Smckusick register struct filedesc *fdp = p->p_fd; 201612756Ssam 201745914Smckusick *retval = fdp->fd_cmask; 201845914Smckusick fdp->fd_cmask = uap->mask & 07777; 201947540Skarels return (0); 202012756Ssam } 202137741Smckusick 202239566Smarc /* 202339566Smarc * Void all references to file by ripping underlying filesystem 202439566Smarc * away from vnode. 202539566Smarc */ 202654916Storek struct revoke_args { 202754916Storek char *fname; 202854916Storek }; 202942441Smckusick /* ARGSUSED */ 203042441Smckusick revoke(p, uap, retval) 203145914Smckusick struct proc *p; 203254916Storek register struct revoke_args *uap; 203342441Smckusick int *retval; 203442441Smckusick { 203539566Smarc register struct vnode *vp; 203639566Smarc struct vattr vattr; 203739566Smarc int error; 203847540Skarels struct nameidata nd; 203939566Smarc 204052322Smckusick NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->fname, p); 204152322Smckusick if (error = namei(&nd)) 204247540Skarels return (error); 204352322Smckusick vp = nd.ni_vp; 204439566Smarc if (vp->v_type != VCHR && vp->v_type != VBLK) { 204539566Smarc error = EINVAL; 204639566Smarc goto out; 204739566Smarc } 204848026Smckusick if (error = VOP_GETATTR(vp, &vattr, p->p_ucred, p)) 204939566Smarc goto out; 205047540Skarels if (p->p_ucred->cr_uid != vattr.va_uid && 205147540Skarels (error = suser(p->p_ucred, &p->p_acflag))) 205239566Smarc goto out; 205339805Smckusick if (vp->v_usecount > 1 || (vp->v_flag & VALIASED)) 205439632Smckusick vgoneall(vp); 205539566Smarc out: 205639566Smarc vrele(vp); 205747540Skarels return (error); 205839566Smarc } 205939566Smarc 206049365Smckusick /* 206149365Smckusick * Convert a user file descriptor to a kernel file entry. 206249365Smckusick */ 206345914Smckusick getvnode(fdp, fdes, fpp) 206445914Smckusick struct filedesc *fdp; 206537741Smckusick struct file **fpp; 206637741Smckusick int fdes; 206737741Smckusick { 206837741Smckusick struct file *fp; 206937741Smckusick 207047540Skarels if ((unsigned)fdes >= fdp->fd_nfiles || 207147688Skarels (fp = fdp->fd_ofiles[fdes]) == NULL) 207237741Smckusick return (EBADF); 207337741Smckusick if (fp->f_type != DTYPE_VNODE) 207437741Smckusick return (EINVAL); 207537741Smckusick *fpp = fp; 207637741Smckusick return (0); 207737741Smckusick } 2078