123405Smckusick /* 263428Sbostic * Copyright (c) 1989, 1993 363428Sbostic * The Regents of the University of California. All rights reserved. 465771Sbostic * (c) UNIX System Laboratories, Inc. 565771Sbostic * All or some portions of this file are derived from material licensed 665771Sbostic * to the University of California by American Telephone and Telegraph 765771Sbostic * Co. or Unix System Laboratories, Inc. and are reproduced herein with 865771Sbostic * the permission of UNIX System Laboratories, Inc. 923405Smckusick * 1044459Sbostic * %sccs.include.redist.c% 1137741Smckusick * 12*66801Smckusick * @(#)vfs_syscalls.c 8.13 (Berkeley) 04/15/94 1323405Smckusick */ 1437Sbill 1556517Sbostic #include <sys/param.h> 1656517Sbostic #include <sys/systm.h> 1756517Sbostic #include <sys/namei.h> 1856517Sbostic #include <sys/filedesc.h> 1956517Sbostic #include <sys/kernel.h> 2056517Sbostic #include <sys/file.h> 2156517Sbostic #include <sys/stat.h> 2256517Sbostic #include <sys/vnode.h> 2356517Sbostic #include <sys/mount.h> 2456517Sbostic #include <sys/proc.h> 2556517Sbostic #include <sys/uio.h> 2656517Sbostic #include <sys/malloc.h> 2756517Sbostic #include <sys/dirent.h> 2856517Sbostic 2953468Smckusick #include <vm/vm.h> 3059875Smckusick #include <sys/sysctl.h> 3137Sbill 3264410Sbostic static int change_dir __P((struct nameidata *ndp, struct proc *p)); 3364410Sbostic 3437741Smckusick /* 3537741Smckusick * Virtual File System System Calls 3637741Smckusick */ 3712756Ssam 389167Ssam /* 3964410Sbostic * Mount a file system. 409167Ssam */ 4154916Storek struct mount_args { 4254916Storek int type; 4364410Sbostic char *path; 4454916Storek int flags; 4554916Storek caddr_t data; 4654916Storek }; 4742441Smckusick /* ARGSUSED */ 4842441Smckusick mount(p, uap, retval) 4945914Smckusick struct proc *p; 5054916Storek register struct mount_args *uap; 5142441Smckusick int *retval; 5242441Smckusick { 5339335Smckusick register struct vnode *vp; 5439335Smckusick register struct mount *mp; 5540111Smckusick int error, flag; 5647540Skarels struct nameidata nd; 576254Sroot 5837741Smckusick /* 5937741Smckusick * Must be super user 6037741Smckusick */ 6147540Skarels if (error = suser(p->p_ucred, &p->p_acflag)) 6247540Skarels return (error); 6337741Smckusick /* 6437741Smckusick * Get vnode to be covered 6537741Smckusick */ 6664410Sbostic NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); 6752322Smckusick if (error = namei(&nd)) 6847540Skarels return (error); 6952322Smckusick vp = nd.ni_vp; 7041400Smckusick if (uap->flags & MNT_UPDATE) { 7139335Smckusick if ((vp->v_flag & VROOT) == 0) { 7239335Smckusick vput(vp); 7347540Skarels return (EINVAL); 7439335Smckusick } 7539335Smckusick mp = vp->v_mount; 7657047Smckusick flag = mp->mnt_flag; 7739335Smckusick /* 7857047Smckusick * We only allow the filesystem to be reloaded if it 7957047Smckusick * is currently mounted read-only. 8039335Smckusick */ 8157047Smckusick if ((uap->flags & MNT_RELOAD) && 8257047Smckusick ((mp->mnt_flag & MNT_RDONLY) == 0)) { 8339335Smckusick vput(vp); 8447540Skarels return (EOPNOTSUPP); /* Needs translation */ 8539335Smckusick } 8657047Smckusick mp->mnt_flag |= 8757047Smckusick uap->flags & (MNT_RELOAD | MNT_FORCE | MNT_UPDATE); 8839335Smckusick VOP_UNLOCK(vp); 8939335Smckusick goto update; 9039335Smckusick } 9157793Smckusick if (error = vinvalbuf(vp, V_SAVE, p->p_ucred, p, 0, 0)) 9254441Smckusick return (error); 9337741Smckusick if (vp->v_type != VDIR) { 9437741Smckusick vput(vp); 9547540Skarels return (ENOTDIR); 9637741Smckusick } 9764410Sbostic if ((u_long)uap->type > MOUNT_MAXTYPE || vfssw[uap->type] == NULL) { 9837741Smckusick vput(vp); 9947540Skarels return (ENODEV); 10037741Smckusick } 10137741Smckusick 10237741Smckusick /* 10339335Smckusick * Allocate and initialize the file system. 10437741Smckusick */ 10537741Smckusick mp = (struct mount *)malloc((u_long)sizeof(struct mount), 10637741Smckusick M_MOUNT, M_WAITOK); 10754172Smckusick bzero((char *)mp, (u_long)sizeof(struct mount)); 10841400Smckusick mp->mnt_op = vfssw[uap->type]; 10939335Smckusick if (error = vfs_lock(mp)) { 11039335Smckusick free((caddr_t)mp, M_MOUNT); 11139335Smckusick vput(vp); 11247540Skarels return (error); 11339335Smckusick } 11464410Sbostic if (vp->v_mountedhere != NULL) { 11539335Smckusick vfs_unlock(mp); 11639335Smckusick free((caddr_t)mp, M_MOUNT); 11739335Smckusick vput(vp); 11847540Skarels return (EBUSY); 11939335Smckusick } 12039335Smckusick vp->v_mountedhere = mp; 12141400Smckusick mp->mnt_vnodecovered = vp; 12239335Smckusick update: 12339335Smckusick /* 12439335Smckusick * Set the mount level flags. 12539335Smckusick */ 12641400Smckusick if (uap->flags & MNT_RDONLY) 12741400Smckusick mp->mnt_flag |= MNT_RDONLY; 12857047Smckusick else if (mp->mnt_flag & MNT_RDONLY) 12957047Smckusick mp->mnt_flag |= MNT_WANTRDWR; 13065613Smckusick mp->mnt_flag &=~ (MNT_NOSUID | MNT_NOEXEC | MNT_NODEV | 13165613Smckusick MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC); 13265613Smckusick mp->mnt_flag |= uap->flags & (MNT_NOSUID | MNT_NOEXEC | MNT_NODEV | 13365613Smckusick MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC); 13439335Smckusick /* 13539335Smckusick * Mount the filesystem. 13639335Smckusick */ 13764410Sbostic error = VFS_MOUNT(mp, uap->path, uap->data, &nd, p); 13841400Smckusick if (mp->mnt_flag & MNT_UPDATE) { 13939335Smckusick vrele(vp); 14057047Smckusick if (mp->mnt_flag & MNT_WANTRDWR) 14157047Smckusick mp->mnt_flag &= ~MNT_RDONLY; 14257047Smckusick mp->mnt_flag &=~ 14357047Smckusick (MNT_UPDATE | MNT_RELOAD | MNT_FORCE | MNT_WANTRDWR); 14440111Smckusick if (error) 14541400Smckusick mp->mnt_flag = flag; 14647540Skarels return (error); 14739335Smckusick } 14840110Smckusick /* 14940110Smckusick * Put the new filesystem on the mount list after root. 15040110Smckusick */ 15137741Smckusick cache_purge(vp); 15237741Smckusick if (!error) { 15365259Smckusick TAILQ_INSERT_TAIL(&mountlist, mp, mnt_list); 15439335Smckusick VOP_UNLOCK(vp); 15537741Smckusick vfs_unlock(mp); 15648026Smckusick error = VFS_START(mp, 0, p); 15737741Smckusick } else { 15865259Smckusick mp->mnt_vnodecovered->v_mountedhere = (struct mount *)0; 15965259Smckusick vfs_unlock(mp); 16037741Smckusick free((caddr_t)mp, M_MOUNT); 16139335Smckusick vput(vp); 16237741Smckusick } 16347540Skarels return (error); 1646254Sroot } 1656254Sroot 1669167Ssam /* 16764410Sbostic * Unmount a file system. 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 { 17364410Sbostic char *path; 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 18764410Sbostic NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); 18852322Smckusick if (error = namei(&nd)) 18947540Skarels return (error); 19052322Smckusick vp = nd.ni_vp; 19166172Spendry 19237741Smckusick /* 19366172Spendry * Unless this is a user mount, then must 19466172Spendry * have suser privilege. 19566172Spendry */ 19666172Spendry if (((vp->v_mount->mnt_flag & MNT_USER) == 0) && 19766172Spendry (error = suser(p->p_ucred, &p->p_acflag))) { 19866172Spendry vput(vp); 19966172Spendry return (error); 20066172Spendry } 20166172Spendry 20266172Spendry /* 20337741Smckusick * Must be the root of the filesystem 20437741Smckusick */ 20537741Smckusick if ((vp->v_flag & VROOT) == 0) { 20637741Smckusick vput(vp); 20747540Skarels return (EINVAL); 20837741Smckusick } 20937741Smckusick mp = vp->v_mount; 21037741Smckusick vput(vp); 21148026Smckusick return (dounmount(mp, uap->flags, p)); 21239356Smckusick } 21339356Smckusick 21439356Smckusick /* 21564410Sbostic * Do the actual file system unmount. 21639356Smckusick */ 21748026Smckusick dounmount(mp, flags, p) 21839356Smckusick register struct mount *mp; 21939356Smckusick int flags; 22048026Smckusick struct proc *p; 22139356Smckusick { 22239356Smckusick struct vnode *coveredvp; 22339356Smckusick int error; 22439356Smckusick 22541400Smckusick coveredvp = mp->mnt_vnodecovered; 22641298Smckusick if (vfs_busy(mp)) 22741298Smckusick return (EBUSY); 22841400Smckusick mp->mnt_flag |= MNT_UNMOUNT; 22937741Smckusick if (error = vfs_lock(mp)) 23039356Smckusick return (error); 23137741Smckusick 23265859Smckusick mp->mnt_flag &=~ MNT_ASYNC; 23345738Smckusick vnode_pager_umount(mp); /* release cached vnodes */ 23437741Smckusick cache_purgevfs(mp); /* remove cache entries for this file sys */ 23554441Smckusick if ((error = VFS_SYNC(mp, MNT_WAIT, p->p_ucred, p)) == 0 || 23654441Smckusick (flags & MNT_FORCE)) 23748026Smckusick error = VFS_UNMOUNT(mp, flags, p); 23841400Smckusick mp->mnt_flag &= ~MNT_UNMOUNT; 23941298Smckusick vfs_unbusy(mp); 24037741Smckusick if (error) { 24137741Smckusick vfs_unlock(mp); 24237741Smckusick } else { 24337741Smckusick vrele(coveredvp); 24465259Smckusick TAILQ_REMOVE(&mountlist, mp, mnt_list); 24565259Smckusick mp->mnt_vnodecovered->v_mountedhere = (struct mount *)0; 24665259Smckusick vfs_unlock(mp); 24765259Smckusick if (mp->mnt_vnodelist.lh_first != NULL) 24852287Smckusick panic("unmount: dangling vnode"); 24937741Smckusick free((caddr_t)mp, M_MOUNT); 25037741Smckusick } 25139356Smckusick return (error); 2526254Sroot } 2536254Sroot 2549167Ssam /* 25537741Smckusick * Sync each mounted filesystem. 2569167Ssam */ 25756352Smckusick #ifdef DIAGNOSTIC 25856352Smckusick int syncprt = 0; 25959875Smckusick struct ctldebug debug0 = { "syncprt", &syncprt }; 26056352Smckusick #endif 26156352Smckusick 26254916Storek struct sync_args { 26354916Storek int dummy; 26454916Storek }; 26539491Smckusick /* ARGSUSED */ 26642441Smckusick sync(p, uap, retval) 26745914Smckusick struct proc *p; 26854916Storek struct sync_args *uap; 26942441Smckusick int *retval; 2706254Sroot { 27165259Smckusick register struct mount *mp, *nmp; 27265859Smckusick int asyncflag; 27337741Smckusick 27465259Smckusick for (mp = mountlist.tqh_first; mp != NULL; mp = nmp) { 27565259Smckusick nmp = mp->mnt_list.tqe_next; 27640343Smckusick /* 27740343Smckusick * The lock check below is to avoid races with mount 27840343Smckusick * and unmount. 27940343Smckusick */ 28041400Smckusick if ((mp->mnt_flag & (MNT_MLOCK|MNT_RDONLY|MNT_MPBUSY)) == 0 && 28141298Smckusick !vfs_busy(mp)) { 28265859Smckusick asyncflag = mp->mnt_flag & MNT_ASYNC; 28365859Smckusick mp->mnt_flag &= ~MNT_ASYNC; 28454441Smckusick VFS_SYNC(mp, MNT_NOWAIT, p->p_ucred, p); 28565859Smckusick if (asyncflag) 28665859Smckusick mp->mnt_flag |= MNT_ASYNC; 28765259Smckusick vfs_unbusy(mp); 28865259Smckusick } 28965259Smckusick } 29056352Smckusick #ifdef DIAGNOSTIC 29156352Smckusick if (syncprt) 29256352Smckusick vfs_bufstats(); 29356352Smckusick #endif /* DIAGNOSTIC */ 29447688Skarels return (0); 29537741Smckusick } 29637741Smckusick 29737741Smckusick /* 29864410Sbostic * Change filesystem quotas. 29941298Smckusick */ 30054916Storek struct quotactl_args { 30154916Storek char *path; 30254916Storek int cmd; 30354916Storek int uid; 30454916Storek caddr_t arg; 30554916Storek }; 30642441Smckusick /* ARGSUSED */ 30742441Smckusick quotactl(p, uap, retval) 30845914Smckusick struct proc *p; 30954916Storek register struct quotactl_args *uap; 31042441Smckusick int *retval; 31142441Smckusick { 31241298Smckusick register struct mount *mp; 31341298Smckusick int error; 31447540Skarels struct nameidata nd; 31541298Smckusick 31652322Smckusick NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); 31752322Smckusick if (error = namei(&nd)) 31847540Skarels return (error); 31952322Smckusick mp = nd.ni_vp->v_mount; 32052322Smckusick vrele(nd.ni_vp); 32148026Smckusick return (VFS_QUOTACTL(mp, uap->cmd, uap->uid, uap->arg, p)); 32241298Smckusick } 32341298Smckusick 32441298Smckusick /* 32549365Smckusick * Get filesystem statistics. 32637741Smckusick */ 32754916Storek struct statfs_args { 32854916Storek char *path; 32954916Storek struct statfs *buf; 33054916Storek }; 33142441Smckusick /* ARGSUSED */ 33242441Smckusick statfs(p, uap, retval) 33345914Smckusick struct proc *p; 33454916Storek register struct statfs_args *uap; 33542441Smckusick int *retval; 33642441Smckusick { 33739464Smckusick register struct mount *mp; 33840343Smckusick register struct statfs *sp; 33937741Smckusick int error; 34047540Skarels struct nameidata nd; 34137741Smckusick 34252322Smckusick NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); 34352322Smckusick if (error = namei(&nd)) 34447540Skarels return (error); 34552322Smckusick mp = nd.ni_vp->v_mount; 34641400Smckusick sp = &mp->mnt_stat; 34752322Smckusick vrele(nd.ni_vp); 34848026Smckusick if (error = VFS_STATFS(mp, sp, p)) 34947540Skarels return (error); 35041400Smckusick sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 35147540Skarels return (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp))); 35237741Smckusick } 35337741Smckusick 35442441Smckusick /* 35549365Smckusick * Get filesystem statistics. 35642441Smckusick */ 35754916Storek struct fstatfs_args { 35854916Storek int fd; 35954916Storek struct statfs *buf; 36054916Storek }; 36142441Smckusick /* ARGSUSED */ 36242441Smckusick fstatfs(p, uap, retval) 36345914Smckusick struct proc *p; 36454916Storek register struct fstatfs_args *uap; 36542441Smckusick int *retval; 36642441Smckusick { 36737741Smckusick struct file *fp; 36839464Smckusick struct mount *mp; 36940343Smckusick register struct statfs *sp; 37037741Smckusick int error; 37137741Smckusick 37245914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 37347540Skarels return (error); 37439464Smckusick mp = ((struct vnode *)fp->f_data)->v_mount; 37541400Smckusick sp = &mp->mnt_stat; 37648026Smckusick if (error = VFS_STATFS(mp, sp, p)) 37747540Skarels return (error); 37841400Smckusick sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 37947540Skarels return (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp))); 38037741Smckusick } 38137741Smckusick 38237741Smckusick /* 38349365Smckusick * Get statistics on all filesystems. 38438270Smckusick */ 38554916Storek struct getfsstat_args { 38654916Storek struct statfs *buf; 38754916Storek long bufsize; 38854916Storek int flags; 38954916Storek }; 39042441Smckusick getfsstat(p, uap, retval) 39145914Smckusick struct proc *p; 39254916Storek register struct getfsstat_args *uap; 39342441Smckusick int *retval; 39442441Smckusick { 39565259Smckusick register struct mount *mp, *nmp; 39640343Smckusick register struct statfs *sp; 39739606Smckusick caddr_t sfsp; 39838270Smckusick long count, maxcount, error; 39938270Smckusick 40038270Smckusick maxcount = uap->bufsize / sizeof(struct statfs); 40139606Smckusick sfsp = (caddr_t)uap->buf; 40265259Smckusick for (count = 0, mp = mountlist.tqh_first; mp != NULL; mp = nmp) { 40365259Smckusick nmp = mp->mnt_list.tqe_next; 40441400Smckusick if (sfsp && count < maxcount && 40541400Smckusick ((mp->mnt_flag & MNT_MLOCK) == 0)) { 40641400Smckusick sp = &mp->mnt_stat; 40740343Smckusick /* 40840343Smckusick * If MNT_NOWAIT is specified, do not refresh the 40940343Smckusick * fsstat cache. MNT_WAIT overrides MNT_NOWAIT. 41040343Smckusick */ 41140343Smckusick if (((uap->flags & MNT_NOWAIT) == 0 || 41240343Smckusick (uap->flags & MNT_WAIT)) && 41365259Smckusick (error = VFS_STATFS(mp, sp, p))) 41439607Smckusick continue; 41541400Smckusick sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 41640343Smckusick if (error = copyout((caddr_t)sp, sfsp, sizeof(*sp))) 41747540Skarels return (error); 41840343Smckusick sfsp += sizeof(*sp); 41938270Smckusick } 42039606Smckusick count++; 42165259Smckusick } 42238270Smckusick if (sfsp && count > maxcount) 42342441Smckusick *retval = maxcount; 42438270Smckusick else 42542441Smckusick *retval = count; 42647540Skarels return (0); 42738270Smckusick } 42838270Smckusick 42938270Smckusick /* 43038259Smckusick * Change current working directory to a given file descriptor. 43138259Smckusick */ 43254916Storek struct fchdir_args { 43354916Storek int fd; 43454916Storek }; 43542441Smckusick /* ARGSUSED */ 43642441Smckusick fchdir(p, uap, retval) 43745914Smckusick struct proc *p; 43854916Storek struct fchdir_args *uap; 43942441Smckusick int *retval; 44038259Smckusick { 44145914Smckusick register struct filedesc *fdp = p->p_fd; 44238259Smckusick register struct vnode *vp; 44338259Smckusick struct file *fp; 44438259Smckusick int error; 44538259Smckusick 44645914Smckusick if (error = getvnode(fdp, uap->fd, &fp)) 44747540Skarels return (error); 44838259Smckusick vp = (struct vnode *)fp->f_data; 44938259Smckusick VOP_LOCK(vp); 45038259Smckusick if (vp->v_type != VDIR) 45138259Smckusick error = ENOTDIR; 45238259Smckusick else 45348026Smckusick error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p); 45438259Smckusick VOP_UNLOCK(vp); 45539860Smckusick if (error) 45647540Skarels return (error); 45739860Smckusick VREF(vp); 45845914Smckusick vrele(fdp->fd_cdir); 45945914Smckusick fdp->fd_cdir = vp; 46047540Skarels return (0); 46138259Smckusick } 46238259Smckusick 46338259Smckusick /* 46437741Smckusick * Change current working directory (``.''). 46537741Smckusick */ 46654916Storek struct chdir_args { 46764410Sbostic char *path; 46854916Storek }; 46942441Smckusick /* ARGSUSED */ 47042441Smckusick chdir(p, uap, retval) 47145914Smckusick struct proc *p; 47254916Storek struct chdir_args *uap; 47342441Smckusick int *retval; 47437741Smckusick { 47545914Smckusick register struct filedesc *fdp = p->p_fd; 47637741Smckusick int error; 47747540Skarels struct nameidata nd; 4786254Sroot 47964410Sbostic NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); 48064410Sbostic if (error = change_dir(&nd, p)) 48147540Skarels return (error); 48245914Smckusick vrele(fdp->fd_cdir); 48352322Smckusick fdp->fd_cdir = nd.ni_vp; 48447540Skarels return (0); 48537741Smckusick } 4866254Sroot 48737741Smckusick /* 48837741Smckusick * Change notion of root (``/'') directory. 48937741Smckusick */ 49054916Storek struct chroot_args { 49164410Sbostic char *path; 49254916Storek }; 49342441Smckusick /* ARGSUSED */ 49442441Smckusick chroot(p, uap, retval) 49545914Smckusick struct proc *p; 49654916Storek struct chroot_args *uap; 49742441Smckusick int *retval; 49837741Smckusick { 49945914Smckusick register struct filedesc *fdp = p->p_fd; 50037741Smckusick int error; 50147540Skarels struct nameidata nd; 50237741Smckusick 50347540Skarels if (error = suser(p->p_ucred, &p->p_acflag)) 50447540Skarels return (error); 50564410Sbostic NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); 50664410Sbostic if (error = change_dir(&nd, p)) 50747540Skarels return (error); 50845914Smckusick if (fdp->fd_rdir != NULL) 50945914Smckusick vrele(fdp->fd_rdir); 51052322Smckusick fdp->fd_rdir = nd.ni_vp; 51147540Skarels return (0); 5126254Sroot } 5136254Sroot 51437Sbill /* 51537741Smckusick * Common routine for chroot and chdir. 51637741Smckusick */ 51764410Sbostic static int 51864410Sbostic change_dir(ndp, p) 51952322Smckusick register struct nameidata *ndp; 52047540Skarels struct proc *p; 52137741Smckusick { 52237741Smckusick struct vnode *vp; 52337741Smckusick int error; 52437741Smckusick 52552322Smckusick if (error = namei(ndp)) 52637741Smckusick return (error); 52737741Smckusick vp = ndp->ni_vp; 52837741Smckusick if (vp->v_type != VDIR) 52937741Smckusick error = ENOTDIR; 53037741Smckusick else 53148026Smckusick error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p); 53237741Smckusick VOP_UNLOCK(vp); 53337741Smckusick if (error) 53437741Smckusick vrele(vp); 53537741Smckusick return (error); 53637741Smckusick } 53737741Smckusick 53837741Smckusick /* 53942441Smckusick * Check permissions, allocate an open file structure, 54042441Smckusick * and call the device open routine if any. 5416254Sroot */ 54254916Storek struct open_args { 54364410Sbostic char *path; 54464410Sbostic int flags; 54554916Storek int mode; 54654916Storek }; 54742441Smckusick open(p, uap, retval) 54845914Smckusick struct proc *p; 54954916Storek register struct open_args *uap; 55042441Smckusick int *retval; 5516254Sroot { 55245914Smckusick register struct filedesc *fdp = p->p_fd; 55342441Smckusick register struct file *fp; 55450111Smckusick register struct vnode *vp; 55564410Sbostic int flags, cmode; 55637741Smckusick struct file *nfp; 55749945Smckusick int type, indx, error; 55849945Smckusick struct flock lf; 55947540Skarels struct nameidata nd; 56037741Smckusick extern struct fileops vnops; 5616254Sroot 56245914Smckusick if (error = falloc(p, &nfp, &indx)) 56347540Skarels return (error); 56437741Smckusick fp = nfp; 56564410Sbostic flags = FFLAGS(uap->flags); 56664410Sbostic cmode = ((uap->mode &~ fdp->fd_cmask) & ALLPERMS) &~ S_ISTXT; 56764410Sbostic NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); 56845202Smckusick p->p_dupfd = -indx - 1; /* XXX check for fdopen */ 56964410Sbostic if (error = vn_open(&nd, flags, cmode)) { 57049980Smckusick ffree(fp); 57154723Smckusick if ((error == ENODEV || error == ENXIO) && 57254723Smckusick p->p_dupfd >= 0 && /* XXX from fdopen */ 57364410Sbostic (error = 57464410Sbostic dupfdopen(fdp, indx, p->p_dupfd, flags, error)) == 0) { 57542441Smckusick *retval = indx; 57647540Skarels return (0); 57742441Smckusick } 57840884Smckusick if (error == ERESTART) 57940884Smckusick error = EINTR; 58047688Skarels fdp->fd_ofiles[indx] = NULL; 58147540Skarels return (error); 58212756Ssam } 58353828Spendry p->p_dupfd = 0; 58452322Smckusick vp = nd.ni_vp; 58564410Sbostic fp->f_flag = flags & FMASK; 58654348Smckusick fp->f_type = DTYPE_VNODE; 58754348Smckusick fp->f_ops = &vnops; 58854348Smckusick fp->f_data = (caddr_t)vp; 58964410Sbostic if (flags & (O_EXLOCK | O_SHLOCK)) { 59049945Smckusick lf.l_whence = SEEK_SET; 59149945Smckusick lf.l_start = 0; 59249945Smckusick lf.l_len = 0; 59364410Sbostic if (flags & O_EXLOCK) 59449945Smckusick lf.l_type = F_WRLCK; 59549945Smckusick else 59649945Smckusick lf.l_type = F_RDLCK; 59749945Smckusick type = F_FLOCK; 59864410Sbostic if ((flags & FNONBLOCK) == 0) 59949945Smckusick type |= F_WAIT; 60065757Smckusick VOP_UNLOCK(vp); 60150111Smckusick if (error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, type)) { 60250111Smckusick (void) vn_close(vp, fp->f_flag, fp->f_cred, p); 60349980Smckusick ffree(fp); 60449945Smckusick fdp->fd_ofiles[indx] = NULL; 60549945Smckusick return (error); 60649945Smckusick } 60765757Smckusick VOP_LOCK(vp); 60849949Smckusick fp->f_flag |= FHASLOCK; 60949945Smckusick } 61050111Smckusick VOP_UNLOCK(vp); 61142441Smckusick *retval = indx; 61247540Skarels return (0); 6136254Sroot } 6146254Sroot 61542955Smckusick #ifdef COMPAT_43 6166254Sroot /* 61764410Sbostic * Create a file. 6186254Sroot */ 61954916Storek struct ocreat_args { 62064410Sbostic char *path; 62164410Sbostic int mode; 62254916Storek }; 62342955Smckusick ocreat(p, uap, retval) 62442441Smckusick struct proc *p; 62554916Storek register struct ocreat_args *uap; 62642441Smckusick int *retval; 6276254Sroot { 62854916Storek struct open_args openuap; 62942441Smckusick 63064410Sbostic openuap.path = uap->path; 63164410Sbostic openuap.mode = uap->mode; 63264410Sbostic openuap.flags = O_WRONLY | O_CREAT | O_TRUNC; 63347540Skarels return (open(p, &openuap, retval)); 63442441Smckusick } 63542955Smckusick #endif /* COMPAT_43 */ 63642441Smckusick 63742441Smckusick /* 63864410Sbostic * Create a special file. 63942441Smckusick */ 64054916Storek struct mknod_args { 64164410Sbostic char *path; 64264410Sbostic int mode; 64354916Storek int dev; 64454916Storek }; 64542441Smckusick /* ARGSUSED */ 64642441Smckusick mknod(p, uap, retval) 64745914Smckusick struct proc *p; 64854916Storek register struct mknod_args *uap; 64942441Smckusick int *retval; 65042441Smckusick { 65137741Smckusick register struct vnode *vp; 65237741Smckusick struct vattr vattr; 65337741Smckusick int error; 65447540Skarels struct nameidata nd; 6556254Sroot 65647540Skarels if (error = suser(p->p_ucred, &p->p_acflag)) 65747540Skarels return (error); 65864410Sbostic NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->path, p); 65952322Smckusick if (error = namei(&nd)) 66047540Skarels return (error); 66152322Smckusick vp = nd.ni_vp; 66264585Sbostic if (vp != NULL) 66337741Smckusick error = EEXIST; 66464585Sbostic else { 66564585Sbostic VATTR_NULL(&vattr); 66664585Sbostic vattr.va_mode = (uap->mode & ALLPERMS) &~ p->p_fd->fd_cmask; 66764585Sbostic vattr.va_rdev = uap->dev; 66864585Sbostic 66964585Sbostic switch (uap->mode & S_IFMT) { 67064585Sbostic case S_IFMT: /* used by badsect to flag bad sectors */ 67164585Sbostic vattr.va_type = VBAD; 67264585Sbostic break; 67364585Sbostic case S_IFCHR: 67464585Sbostic vattr.va_type = VCHR; 67564585Sbostic break; 67664585Sbostic case S_IFBLK: 67764585Sbostic vattr.va_type = VBLK; 67864585Sbostic break; 67964585Sbostic default: 68064585Sbostic error = EINVAL; 68164585Sbostic break; 68264585Sbostic } 6836254Sroot } 68442465Smckusick if (!error) { 68552322Smckusick LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 68652322Smckusick error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr); 68742465Smckusick } else { 68852322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 68952322Smckusick if (nd.ni_dvp == vp) 69052322Smckusick vrele(nd.ni_dvp); 69143344Smckusick else 69252322Smckusick vput(nd.ni_dvp); 69342465Smckusick if (vp) 69442465Smckusick vrele(vp); 69542465Smckusick } 69647540Skarels return (error); 6976254Sroot } 6986254Sroot 6996254Sroot /* 70064410Sbostic * Create named pipe. 70140285Smckusick */ 70254916Storek struct mkfifo_args { 70364410Sbostic char *path; 70464410Sbostic int mode; 70554916Storek }; 70642441Smckusick /* ARGSUSED */ 70742441Smckusick mkfifo(p, uap, retval) 70845914Smckusick struct proc *p; 70954916Storek register struct mkfifo_args *uap; 71042441Smckusick int *retval; 71142441Smckusick { 71240285Smckusick struct vattr vattr; 71340285Smckusick int error; 71447540Skarels struct nameidata nd; 71540285Smckusick 71640285Smckusick #ifndef FIFO 71747540Skarels return (EOPNOTSUPP); 71840285Smckusick #else 71964410Sbostic NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->path, p); 72052322Smckusick if (error = namei(&nd)) 72147540Skarels return (error); 72252322Smckusick if (nd.ni_vp != NULL) { 72352322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 72452322Smckusick if (nd.ni_dvp == nd.ni_vp) 72552322Smckusick vrele(nd.ni_dvp); 72643344Smckusick else 72752322Smckusick vput(nd.ni_dvp); 72852322Smckusick vrele(nd.ni_vp); 72947540Skarels return (EEXIST); 73040285Smckusick } 73145785Sbostic VATTR_NULL(&vattr); 73245785Sbostic vattr.va_type = VFIFO; 73364410Sbostic vattr.va_mode = (uap->mode & ALLPERMS) &~ p->p_fd->fd_cmask; 73452322Smckusick LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 73552322Smckusick return (VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr)); 73640285Smckusick #endif /* FIFO */ 73740285Smckusick } 73840285Smckusick 73940285Smckusick /* 74064410Sbostic * Make a hard file link. 7416254Sroot */ 74254916Storek struct link_args { 74364410Sbostic char *path; 74464410Sbostic char *link; 74554916Storek }; 74642441Smckusick /* ARGSUSED */ 74742441Smckusick link(p, uap, retval) 74845914Smckusick struct proc *p; 74954916Storek register struct link_args *uap; 75042441Smckusick int *retval; 75142441Smckusick { 75264410Sbostic register struct vnode *vp; 75364410Sbostic struct nameidata nd; 75437741Smckusick int error; 7556254Sroot 75664410Sbostic NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); 75752322Smckusick if (error = namei(&nd)) 75847540Skarels return (error); 75952322Smckusick vp = nd.ni_vp; 76064585Sbostic if (vp->v_type != VDIR || 76164585Sbostic (error = suser(p->p_ucred, &p->p_acflag)) == 0) { 76264585Sbostic nd.ni_cnd.cn_nameiop = CREATE; 76364585Sbostic nd.ni_cnd.cn_flags = LOCKPARENT; 76464585Sbostic nd.ni_dirp = uap->link; 76564585Sbostic if ((error = namei(&nd)) == 0) { 76664585Sbostic if (nd.ni_vp != NULL) 76764585Sbostic error = EEXIST; 76864585Sbostic if (!error) { 76964585Sbostic LEASE_CHECK(nd.ni_dvp, 77064585Sbostic p, p->p_ucred, LEASE_WRITE); 77164585Sbostic LEASE_CHECK(vp, 77264585Sbostic p, p->p_ucred, LEASE_WRITE); 77364585Sbostic error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd); 77464585Sbostic } else { 77564585Sbostic VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 77664585Sbostic if (nd.ni_dvp == nd.ni_vp) 77764585Sbostic vrele(nd.ni_dvp); 77864585Sbostic else 77964585Sbostic vput(nd.ni_dvp); 78064585Sbostic if (nd.ni_vp) 78164585Sbostic vrele(nd.ni_vp); 78264585Sbostic } 78364585Sbostic } 78442465Smckusick } 78564585Sbostic vrele(vp); 78647540Skarels return (error); 7876254Sroot } 7886254Sroot 7896254Sroot /* 79049365Smckusick * Make a symbolic link. 7916254Sroot */ 79254916Storek struct symlink_args { 79364410Sbostic char *path; 79464410Sbostic char *link; 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; 80364410Sbostic char *path; 80437741Smckusick int error; 80547540Skarels struct nameidata nd; 8066254Sroot 80764410Sbostic MALLOC(path, char *, MAXPATHLEN, M_NAMEI, M_WAITOK); 80864410Sbostic if (error = copyinstr(uap->path, path, MAXPATHLEN, NULL)) 80942465Smckusick goto out; 81064410Sbostic NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->link, 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); 82464410Sbostic vattr.va_mode = ACCESSPERMS &~ p->p_fd->fd_cmask; 82552322Smckusick LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 82664410Sbostic error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr, path); 82737741Smckusick out: 82864410Sbostic FREE(path, M_NAMEI); 82947540Skarels return (error); 8306254Sroot } 8316254Sroot 8326254Sroot /* 83349365Smckusick * Delete a name from the filesystem. 8346254Sroot */ 83554916Storek struct unlink_args { 83664410Sbostic char *path; 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 84864410Sbostic NDINIT(&nd, DELETE, LOCKPARENT, UIO_USERSPACE, uap->path, 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); 85464410Sbostic 85564585Sbostic if (vp->v_type != VDIR || 85664585Sbostic (error = suser(p->p_ucred, &p->p_acflag)) == 0) { 85764585Sbostic /* 85864585Sbostic * The root of a mounted filesystem cannot be deleted. 85964585Sbostic */ 86064585Sbostic if (vp->v_flag & VROOT) 86164585Sbostic error = EBUSY; 86264585Sbostic else 86364585Sbostic (void)vnode_pager_uncache(vp); 86464585Sbostic } 86564585Sbostic 86664585Sbostic 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 88064410Sbostic /* 88164410Sbostic * Reposition read/write file offset. 88264410Sbostic */ 88360428Smckusick struct lseek_args { 88464410Sbostic int fd; 88554863Storek int pad; 88664410Sbostic off_t offset; 88764410Sbostic int whence; 88854863Storek }; 88960414Smckusick lseek(p, uap, retval) 89053468Smckusick struct proc *p; 89160428Smckusick register struct lseek_args *uap; 89254916Storek int *retval; 89342441Smckusick { 89447540Skarels struct ucred *cred = p->p_ucred; 89545914Smckusick register struct filedesc *fdp = p->p_fd; 89642441Smckusick register struct file *fp; 89737741Smckusick struct vattr vattr; 89837741Smckusick int error; 8996254Sroot 90064410Sbostic if ((u_int)uap->fd >= fdp->fd_nfiles || 90164410Sbostic (fp = fdp->fd_ofiles[uap->fd]) == NULL) 90247540Skarels return (EBADF); 90337741Smckusick if (fp->f_type != DTYPE_VNODE) 90447540Skarels return (ESPIPE); 90564410Sbostic switch (uap->whence) { 90613878Ssam case L_INCR: 90764410Sbostic fp->f_offset += uap->offset; 90813878Ssam break; 90913878Ssam case L_XTND: 91064410Sbostic if (error = 91164410Sbostic VOP_GETATTR((struct vnode *)fp->f_data, &vattr, cred, p)) 91247540Skarels return (error); 91364410Sbostic fp->f_offset = uap->offset + vattr.va_size; 91413878Ssam break; 91513878Ssam case L_SET: 91664410Sbostic fp->f_offset = uap->offset; 91713878Ssam break; 91813878Ssam default: 91947540Skarels return (EINVAL); 92013878Ssam } 92154916Storek *(off_t *)retval = fp->f_offset; 92247540Skarels return (0); 9236254Sroot } 9246254Sroot 92560414Smckusick #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 9266254Sroot /* 92764410Sbostic * Reposition read/write file offset. 92860036Smckusick */ 92960428Smckusick struct olseek_args { 93064410Sbostic int fd; 93164410Sbostic long offset; 93264410Sbostic int whence; 93360036Smckusick }; 93460414Smckusick olseek(p, uap, retval) 93560036Smckusick struct proc *p; 93660428Smckusick register struct olseek_args *uap; 93760036Smckusick int *retval; 93860036Smckusick { 93960428Smckusick struct lseek_args nuap; 94060036Smckusick off_t qret; 94160036Smckusick int error; 94260036Smckusick 94364410Sbostic nuap.fd = uap->fd; 94464410Sbostic nuap.offset = uap->offset; 94564410Sbostic nuap.whence = uap->whence; 94660428Smckusick error = lseek(p, &nuap, &qret); 94760036Smckusick *(long *)retval = qret; 94860036Smckusick return (error); 94960036Smckusick } 95060414Smckusick #endif /* COMPAT_43 */ 95160036Smckusick 95260036Smckusick /* 95349365Smckusick * Check access permissions. 9546254Sroot */ 95563427Sbostic struct access_args { 95664410Sbostic char *path; 95764410Sbostic int flags; 95854916Storek }; 95963427Sbostic access(p, uap, retval) 96045914Smckusick struct proc *p; 96163427Sbostic register struct access_args *uap; 96242441Smckusick int *retval; 96342441Smckusick { 96447540Skarels register struct ucred *cred = p->p_ucred; 96537741Smckusick register struct vnode *vp; 96664585Sbostic int error, flags, t_gid, t_uid; 96747540Skarels struct nameidata nd; 9686254Sroot 96964585Sbostic t_uid = cred->cr_uid; 97064585Sbostic t_gid = cred->cr_groups[0]; 97147540Skarels cred->cr_uid = p->p_cred->p_ruid; 97247540Skarels cred->cr_groups[0] = p->p_cred->p_rgid; 97364410Sbostic NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); 97452322Smckusick if (error = namei(&nd)) 97537741Smckusick goto out1; 97652322Smckusick vp = nd.ni_vp; 97764410Sbostic 97864410Sbostic /* Flags == 0 means only check for existence. */ 97964410Sbostic if (uap->flags) { 98064410Sbostic flags = 0; 98164410Sbostic if (uap->flags & R_OK) 98264410Sbostic flags |= VREAD; 98364410Sbostic if (uap->flags & W_OK) 98464410Sbostic flags |= VWRITE; 98564410Sbostic if (uap->flags & X_OK) 98664410Sbostic flags |= VEXEC; 98764410Sbostic if ((flags & VWRITE) == 0 || (error = vn_writechk(vp)) == 0) 98864410Sbostic error = VOP_ACCESS(vp, flags, cred, p); 9896254Sroot } 99037741Smckusick vput(vp); 99137741Smckusick out1: 99264585Sbostic cred->cr_uid = t_uid; 99364585Sbostic cred->cr_groups[0] = t_gid; 99447540Skarels return (error); 9956254Sroot } 9966254Sroot 99754348Smckusick #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 9986254Sroot /* 99964410Sbostic * Get file status; this version follows links. 100037Sbill */ 100154916Storek struct ostat_args { 100264410Sbostic char *path; 100354916Storek struct ostat *ub; 100454916Storek }; 100542441Smckusick /* ARGSUSED */ 100653759Smckusick ostat(p, uap, retval) 100745914Smckusick struct proc *p; 100854916Storek register struct ostat_args *uap; 100953468Smckusick int *retval; 101053468Smckusick { 101153468Smckusick struct stat sb; 101253468Smckusick struct ostat osb; 101353468Smckusick int error; 101453468Smckusick struct nameidata nd; 101553468Smckusick 101664410Sbostic NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); 101753468Smckusick if (error = namei(&nd)) 101853468Smckusick return (error); 101953468Smckusick error = vn_stat(nd.ni_vp, &sb, p); 102053468Smckusick vput(nd.ni_vp); 102153468Smckusick if (error) 102253468Smckusick return (error); 102353468Smckusick cvtstat(&sb, &osb); 102453468Smckusick error = copyout((caddr_t)&osb, (caddr_t)uap->ub, sizeof (osb)); 102553468Smckusick return (error); 102653468Smckusick } 102753468Smckusick 102853468Smckusick /* 102964410Sbostic * Get file status; this version does not follow links. 103053468Smckusick */ 103154916Storek struct olstat_args { 103264410Sbostic char *path; 103354916Storek struct ostat *ub; 103454916Storek }; 103553468Smckusick /* ARGSUSED */ 103653759Smckusick olstat(p, uap, retval) 103753468Smckusick struct proc *p; 103854916Storek register struct olstat_args *uap; 103953468Smckusick int *retval; 104053468Smckusick { 104153468Smckusick struct stat sb; 104253468Smckusick struct ostat osb; 104353468Smckusick int error; 104453468Smckusick struct nameidata nd; 104553468Smckusick 104664410Sbostic NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); 104753468Smckusick if (error = namei(&nd)) 104853468Smckusick return (error); 104953468Smckusick error = vn_stat(nd.ni_vp, &sb, p); 105053468Smckusick vput(nd.ni_vp); 105153468Smckusick if (error) 105253468Smckusick return (error); 105353468Smckusick cvtstat(&sb, &osb); 105453468Smckusick error = copyout((caddr_t)&osb, (caddr_t)uap->ub, sizeof (osb)); 105553468Smckusick return (error); 105653468Smckusick } 105753468Smckusick 105853468Smckusick /* 105964410Sbostic * Convert from an old to a new stat structure. 106053468Smckusick */ 106153468Smckusick cvtstat(st, ost) 106253468Smckusick struct stat *st; 106353468Smckusick struct ostat *ost; 106453468Smckusick { 106553468Smckusick 106653468Smckusick ost->st_dev = st->st_dev; 106753468Smckusick ost->st_ino = st->st_ino; 106853468Smckusick ost->st_mode = st->st_mode; 106953468Smckusick ost->st_nlink = st->st_nlink; 107053468Smckusick ost->st_uid = st->st_uid; 107153468Smckusick ost->st_gid = st->st_gid; 107253468Smckusick ost->st_rdev = st->st_rdev; 107353468Smckusick if (st->st_size < (quad_t)1 << 32) 107453468Smckusick ost->st_size = st->st_size; 107553468Smckusick else 107653468Smckusick ost->st_size = -2; 107753468Smckusick ost->st_atime = st->st_atime; 107853468Smckusick ost->st_mtime = st->st_mtime; 107953468Smckusick ost->st_ctime = st->st_ctime; 108053468Smckusick ost->st_blksize = st->st_blksize; 108153468Smckusick ost->st_blocks = st->st_blocks; 108253468Smckusick ost->st_flags = st->st_flags; 108353468Smckusick ost->st_gen = st->st_gen; 108453468Smckusick } 108554348Smckusick #endif /* COMPAT_43 || COMPAT_SUNOS */ 108653468Smckusick 108753468Smckusick /* 108864410Sbostic * Get file status; this version follows links. 108953468Smckusick */ 109054916Storek struct stat_args { 109164410Sbostic char *path; 109254916Storek struct stat *ub; 109354916Storek }; 109453468Smckusick /* ARGSUSED */ 109553759Smckusick stat(p, uap, retval) 109653468Smckusick struct proc *p; 109754916Storek register struct stat_args *uap; 109842441Smckusick int *retval; 109937Sbill { 110042441Smckusick struct stat sb; 110142441Smckusick int error; 110247540Skarels struct nameidata nd; 110337Sbill 110464410Sbostic NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); 110552322Smckusick if (error = namei(&nd)) 110647540Skarels return (error); 110752322Smckusick error = vn_stat(nd.ni_vp, &sb, p); 110852322Smckusick vput(nd.ni_vp); 110942441Smckusick if (error) 111047540Skarels return (error); 111142441Smckusick error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb)); 111247540Skarels return (error); 111337Sbill } 111437Sbill 111537Sbill /* 111664410Sbostic * Get file status; this version does not follow links. 11175992Swnj */ 111854916Storek struct lstat_args { 111964410Sbostic char *path; 112054916Storek struct stat *ub; 112154916Storek }; 112242441Smckusick /* ARGSUSED */ 112353759Smckusick lstat(p, uap, retval) 112445914Smckusick struct proc *p; 112554916Storek register struct lstat_args *uap; 112642441Smckusick int *retval; 112742441Smckusick { 112837741Smckusick int error; 112959373Smckusick struct vnode *vp, *dvp; 113059373Smckusick struct stat sb, sb1; 113147540Skarels struct nameidata nd; 11325992Swnj 113359373Smckusick NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | LOCKPARENT, UIO_USERSPACE, 113464410Sbostic uap->path, p); 113552322Smckusick if (error = namei(&nd)) 113647540Skarels return (error); 113759373Smckusick /* 113859373Smckusick * For symbolic links, always return the attributes of its 113959373Smckusick * containing directory, except for mode, size, and links. 114059373Smckusick */ 114159373Smckusick vp = nd.ni_vp; 114259373Smckusick dvp = nd.ni_dvp; 114359373Smckusick if (vp->v_type != VLNK) { 114459373Smckusick if (dvp == vp) 114559373Smckusick vrele(dvp); 114659373Smckusick else 114759373Smckusick vput(dvp); 114859373Smckusick error = vn_stat(vp, &sb, p); 114959373Smckusick vput(vp); 115059373Smckusick if (error) 115159373Smckusick return (error); 115259373Smckusick } else { 115359373Smckusick error = vn_stat(dvp, &sb, p); 115459373Smckusick vput(dvp); 115559373Smckusick if (error) { 115659373Smckusick vput(vp); 115759373Smckusick return (error); 115859373Smckusick } 115959373Smckusick error = vn_stat(vp, &sb1, p); 116059373Smckusick vput(vp); 116159373Smckusick if (error) 116259373Smckusick return (error); 116359373Smckusick sb.st_mode &= ~S_IFDIR; 116459373Smckusick sb.st_mode |= S_IFLNK; 116559373Smckusick sb.st_nlink = sb1.st_nlink; 116659373Smckusick sb.st_size = sb1.st_size; 116759373Smckusick sb.st_blocks = sb1.st_blocks; 116859373Smckusick } 116937741Smckusick error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb)); 117047540Skarels return (error); 11715992Swnj } 11725992Swnj 11735992Swnj /* 117464410Sbostic * Get configurable pathname variables. 117560414Smckusick */ 117660414Smckusick struct pathconf_args { 117764410Sbostic char *path; 117860414Smckusick int name; 117960414Smckusick }; 118060414Smckusick /* ARGSUSED */ 118160414Smckusick pathconf(p, uap, retval) 118260414Smckusick struct proc *p; 118360414Smckusick register struct pathconf_args *uap; 118460414Smckusick int *retval; 118560414Smckusick { 118660414Smckusick int error; 118760414Smckusick struct nameidata nd; 118860414Smckusick 118964410Sbostic NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); 119060414Smckusick if (error = namei(&nd)) 119160414Smckusick return (error); 119260414Smckusick error = VOP_PATHCONF(nd.ni_vp, uap->name, retval); 119360414Smckusick vput(nd.ni_vp); 119460414Smckusick return (error); 119560414Smckusick } 119660414Smckusick 119760414Smckusick /* 119849365Smckusick * Return target name of a symbolic link. 119937Sbill */ 120054916Storek struct readlink_args { 120164410Sbostic char *path; 120254916Storek char *buf; 120354916Storek int count; 120454916Storek }; 120542441Smckusick /* ARGSUSED */ 120642441Smckusick readlink(p, uap, retval) 120745914Smckusick struct proc *p; 120854916Storek register struct readlink_args *uap; 120942441Smckusick int *retval; 121042441Smckusick { 121137741Smckusick register struct vnode *vp; 121237741Smckusick struct iovec aiov; 121337741Smckusick struct uio auio; 121437741Smckusick int error; 121547540Skarels struct nameidata nd; 12165992Swnj 121764410Sbostic NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); 121852322Smckusick if (error = namei(&nd)) 121947540Skarels return (error); 122052322Smckusick vp = nd.ni_vp; 122164410Sbostic if (vp->v_type != VLNK) 122237741Smckusick error = EINVAL; 122364410Sbostic else { 122464410Sbostic aiov.iov_base = uap->buf; 122564410Sbostic aiov.iov_len = uap->count; 122664410Sbostic auio.uio_iov = &aiov; 122764410Sbostic auio.uio_iovcnt = 1; 122864410Sbostic auio.uio_offset = 0; 122964410Sbostic auio.uio_rw = UIO_READ; 123064410Sbostic auio.uio_segflg = UIO_USERSPACE; 123164410Sbostic auio.uio_procp = p; 123264410Sbostic auio.uio_resid = uap->count; 123364410Sbostic error = VOP_READLINK(vp, &auio, p->p_ucred); 12345992Swnj } 123537741Smckusick vput(vp); 123642441Smckusick *retval = uap->count - auio.uio_resid; 123747540Skarels return (error); 12385992Swnj } 12395992Swnj 12409167Ssam /* 124164410Sbostic * Change flags of a file given a path name. 124238259Smckusick */ 124354916Storek struct chflags_args { 124464410Sbostic char *path; 124554916Storek int flags; 124654916Storek }; 124742441Smckusick /* ARGSUSED */ 124842441Smckusick chflags(p, uap, retval) 124945914Smckusick struct proc *p; 125054916Storek register struct chflags_args *uap; 125142441Smckusick int *retval; 125242441Smckusick { 125338259Smckusick register struct vnode *vp; 125438259Smckusick struct vattr vattr; 125538259Smckusick int error; 125647540Skarels struct nameidata nd; 125738259Smckusick 125864410Sbostic NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); 125952322Smckusick if (error = namei(&nd)) 126047540Skarels return (error); 126152322Smckusick vp = nd.ni_vp; 126259382Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 126359382Smckusick VOP_LOCK(vp); 126464410Sbostic if (vp->v_mount->mnt_flag & MNT_RDONLY) 126538259Smckusick error = EROFS; 126664410Sbostic else { 126764410Sbostic VATTR_NULL(&vattr); 126864410Sbostic vattr.va_flags = uap->flags; 126964410Sbostic error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 127038259Smckusick } 127138259Smckusick vput(vp); 127247540Skarels return (error); 127338259Smckusick } 127438259Smckusick 127538259Smckusick /* 127638259Smckusick * Change flags of a file given a file descriptor. 127738259Smckusick */ 127854916Storek struct fchflags_args { 127954916Storek int fd; 128054916Storek int flags; 128154916Storek }; 128242441Smckusick /* ARGSUSED */ 128342441Smckusick fchflags(p, uap, retval) 128445914Smckusick struct proc *p; 128554916Storek register struct fchflags_args *uap; 128642441Smckusick int *retval; 128742441Smckusick { 128838259Smckusick struct vattr vattr; 128938259Smckusick struct vnode *vp; 129038259Smckusick struct file *fp; 129138259Smckusick int error; 129238259Smckusick 129345914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 129447540Skarels return (error); 129538259Smckusick vp = (struct vnode *)fp->f_data; 129659382Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 129738259Smckusick VOP_LOCK(vp); 129864410Sbostic if (vp->v_mount->mnt_flag & MNT_RDONLY) 129938259Smckusick error = EROFS; 130064410Sbostic else { 130164410Sbostic VATTR_NULL(&vattr); 130264410Sbostic vattr.va_flags = uap->flags; 130364410Sbostic error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 130438259Smckusick } 130538259Smckusick VOP_UNLOCK(vp); 130647540Skarels return (error); 130738259Smckusick } 130838259Smckusick 130938259Smckusick /* 13109167Ssam * Change mode of a file given path name. 13119167Ssam */ 131254916Storek struct chmod_args { 131364410Sbostic char *path; 131464410Sbostic int mode; 131554916Storek }; 131642441Smckusick /* ARGSUSED */ 131742441Smckusick chmod(p, uap, retval) 131845914Smckusick struct proc *p; 131954916Storek register struct chmod_args *uap; 132042441Smckusick int *retval; 132142441Smckusick { 132237741Smckusick register struct vnode *vp; 132337741Smckusick struct vattr vattr; 132437741Smckusick int error; 132547540Skarels struct nameidata nd; 13265992Swnj 132764410Sbostic NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); 132852322Smckusick if (error = namei(&nd)) 132947540Skarels return (error); 133052322Smckusick vp = nd.ni_vp; 133159382Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 133259382Smckusick VOP_LOCK(vp); 133364410Sbostic if (vp->v_mount->mnt_flag & MNT_RDONLY) 133437741Smckusick error = EROFS; 133564410Sbostic else { 133664410Sbostic VATTR_NULL(&vattr); 133764410Sbostic vattr.va_mode = uap->mode & ALLPERMS; 133864410Sbostic error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 133937741Smckusick } 134037741Smckusick vput(vp); 134147540Skarels return (error); 13427701Ssam } 13437439Sroot 13449167Ssam /* 13459167Ssam * Change mode of a file given a file descriptor. 13469167Ssam */ 134754916Storek struct fchmod_args { 134854916Storek int fd; 134964410Sbostic int mode; 135054916Storek }; 135142441Smckusick /* ARGSUSED */ 135242441Smckusick fchmod(p, uap, retval) 135345914Smckusick struct proc *p; 135454916Storek register struct fchmod_args *uap; 135542441Smckusick int *retval; 135642441Smckusick { 135737741Smckusick struct vattr vattr; 135837741Smckusick struct vnode *vp; 135937741Smckusick struct file *fp; 136037741Smckusick int error; 13617701Ssam 136245914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 136347540Skarels return (error); 136437741Smckusick vp = (struct vnode *)fp->f_data; 136559382Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 136637741Smckusick VOP_LOCK(vp); 136764410Sbostic if (vp->v_mount->mnt_flag & MNT_RDONLY) 136837741Smckusick error = EROFS; 136964410Sbostic else { 137064410Sbostic VATTR_NULL(&vattr); 137164410Sbostic vattr.va_mode = uap->mode & ALLPERMS; 137264410Sbostic error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 13737439Sroot } 137437741Smckusick VOP_UNLOCK(vp); 137547540Skarels return (error); 13765992Swnj } 13775992Swnj 13789167Ssam /* 13799167Ssam * Set ownership given a path name. 13809167Ssam */ 138154916Storek struct chown_args { 138264410Sbostic char *path; 138354916Storek int uid; 138454916Storek int gid; 138554916Storek }; 138642441Smckusick /* ARGSUSED */ 138742441Smckusick chown(p, uap, retval) 138845914Smckusick struct proc *p; 138954916Storek register struct chown_args *uap; 139042441Smckusick int *retval; 139142441Smckusick { 139237741Smckusick register struct vnode *vp; 139337741Smckusick struct vattr vattr; 139437741Smckusick int error; 139547540Skarels struct nameidata nd; 139637Sbill 139766510Sbostic NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); 139852322Smckusick if (error = namei(&nd)) 139947540Skarels return (error); 140052322Smckusick vp = nd.ni_vp; 140159382Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 140259382Smckusick VOP_LOCK(vp); 140364410Sbostic if (vp->v_mount->mnt_flag & MNT_RDONLY) 140437741Smckusick error = EROFS; 140564410Sbostic else { 140664410Sbostic VATTR_NULL(&vattr); 140764410Sbostic vattr.va_uid = uap->uid; 140864410Sbostic vattr.va_gid = uap->gid; 140964410Sbostic error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 141037741Smckusick } 141137741Smckusick vput(vp); 141247540Skarels return (error); 14137701Ssam } 14147439Sroot 14159167Ssam /* 14169167Ssam * Set ownership given a file descriptor. 14179167Ssam */ 141854916Storek struct fchown_args { 141954916Storek int fd; 142054916Storek int uid; 142154916Storek int gid; 142254916Storek }; 142342441Smckusick /* ARGSUSED */ 142442441Smckusick fchown(p, uap, retval) 142545914Smckusick struct proc *p; 142654916Storek register struct fchown_args *uap; 142742441Smckusick int *retval; 142842441Smckusick { 142937741Smckusick struct vattr vattr; 143037741Smckusick struct vnode *vp; 143137741Smckusick struct file *fp; 143237741Smckusick int error; 14337701Ssam 143445914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 143547540Skarels return (error); 143637741Smckusick vp = (struct vnode *)fp->f_data; 143759382Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 143837741Smckusick VOP_LOCK(vp); 143964410Sbostic if (vp->v_mount->mnt_flag & MNT_RDONLY) 144037741Smckusick error = EROFS; 144164410Sbostic else { 144264410Sbostic VATTR_NULL(&vattr); 144364410Sbostic vattr.va_uid = uap->uid; 144464410Sbostic vattr.va_gid = uap->gid; 144564410Sbostic error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 144637741Smckusick } 144737741Smckusick VOP_UNLOCK(vp); 144847540Skarels return (error); 14497701Ssam } 14507701Ssam 145142441Smckusick /* 145242441Smckusick * Set the access and modification times of a file. 145342441Smckusick */ 145454916Storek struct utimes_args { 145564410Sbostic char *path; 145654916Storek struct timeval *tptr; 145754916Storek }; 145842441Smckusick /* ARGSUSED */ 145942441Smckusick utimes(p, uap, retval) 146045914Smckusick struct proc *p; 146154916Storek register struct utimes_args *uap; 146242441Smckusick int *retval; 146342441Smckusick { 146437741Smckusick register struct vnode *vp; 146511811Ssam struct timeval tv[2]; 146637741Smckusick struct vattr vattr; 146758840Storek int error; 146847540Skarels struct nameidata nd; 146911811Ssam 147058505Sbostic VATTR_NULL(&vattr); 147158505Sbostic if (uap->tptr == NULL) { 147258505Sbostic microtime(&tv[0]); 147358505Sbostic tv[1] = tv[0]; 147458548Sbostic vattr.va_vaflags |= VA_UTIMES_NULL; 147558505Sbostic } else if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv))) 147658505Sbostic return (error); 147764410Sbostic NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); 147852322Smckusick if (error = namei(&nd)) 147947540Skarels return (error); 148052322Smckusick vp = nd.ni_vp; 148159382Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 148259382Smckusick VOP_LOCK(vp); 148364410Sbostic if (vp->v_mount->mnt_flag & MNT_RDONLY) 148437741Smckusick error = EROFS; 148564410Sbostic else { 148664410Sbostic vattr.va_atime.ts_sec = tv[0].tv_sec; 148764410Sbostic vattr.va_atime.ts_nsec = tv[0].tv_usec * 1000; 148864410Sbostic vattr.va_mtime.ts_sec = tv[1].tv_sec; 148964410Sbostic vattr.va_mtime.ts_nsec = tv[1].tv_usec * 1000; 149064410Sbostic error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 149121015Smckusick } 149237741Smckusick vput(vp); 149347540Skarels return (error); 149411811Ssam } 149511811Ssam 149664410Sbostic /* 149764410Sbostic * Truncate a file given its path name. 149864410Sbostic */ 149960428Smckusick struct truncate_args { 150064410Sbostic char *path; 150154863Storek int pad; 150254863Storek off_t length; 150354863Storek }; 150453468Smckusick /* ARGSUSED */ 150560414Smckusick truncate(p, uap, retval) 150653468Smckusick struct proc *p; 150760428Smckusick register struct truncate_args *uap; 150853468Smckusick int *retval; 150953468Smckusick { 151037741Smckusick register struct vnode *vp; 151137741Smckusick struct vattr vattr; 151237741Smckusick int error; 151347540Skarels struct nameidata nd; 15147701Ssam 151564410Sbostic NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); 151652322Smckusick if (error = namei(&nd)) 151747540Skarels return (error); 151852322Smckusick vp = nd.ni_vp; 151959382Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 152059382Smckusick VOP_LOCK(vp); 152164410Sbostic if (vp->v_type == VDIR) 152237741Smckusick error = EISDIR; 152364410Sbostic else if ((error = vn_writechk(vp)) == 0 && 152464410Sbostic (error = VOP_ACCESS(vp, VWRITE, p->p_ucred, p)) == 0) { 152564410Sbostic VATTR_NULL(&vattr); 152664410Sbostic vattr.va_size = uap->length; 152764410Sbostic error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 15287701Ssam } 152937741Smckusick vput(vp); 153047540Skarels return (error); 15317701Ssam } 15327701Ssam 153364410Sbostic /* 153464410Sbostic * Truncate a file given a file descriptor. 153564410Sbostic */ 153660428Smckusick struct ftruncate_args { 153754863Storek int fd; 153854863Storek int pad; 153954863Storek off_t length; 154054863Storek }; 154142441Smckusick /* ARGSUSED */ 154260414Smckusick ftruncate(p, uap, retval) 154345914Smckusick struct proc *p; 154460428Smckusick register struct ftruncate_args *uap; 154542441Smckusick int *retval; 154642441Smckusick { 154737741Smckusick struct vattr vattr; 154837741Smckusick struct vnode *vp; 15497701Ssam struct file *fp; 155037741Smckusick int error; 15517701Ssam 155245914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 155347540Skarels return (error); 155437741Smckusick if ((fp->f_flag & FWRITE) == 0) 155547540Skarels return (EINVAL); 155637741Smckusick vp = (struct vnode *)fp->f_data; 155759382Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 155837741Smckusick VOP_LOCK(vp); 155964410Sbostic if (vp->v_type == VDIR) 156037741Smckusick error = EISDIR; 156164410Sbostic else if ((error = vn_writechk(vp)) == 0) { 156264410Sbostic VATTR_NULL(&vattr); 156364410Sbostic vattr.va_size = uap->length; 156464410Sbostic error = VOP_SETATTR(vp, &vattr, fp->f_cred, p); 15657701Ssam } 156637741Smckusick VOP_UNLOCK(vp); 156747540Skarels return (error); 15687701Ssam } 15697701Ssam 157054863Storek #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 15719167Ssam /* 157254863Storek * Truncate a file given its path name. 157354863Storek */ 157460428Smckusick struct otruncate_args { 157564410Sbostic char *path; 157654916Storek long length; 157754916Storek }; 157854863Storek /* ARGSUSED */ 157960105Smckusick otruncate(p, uap, retval) 158054863Storek struct proc *p; 158160428Smckusick register struct otruncate_args *uap; 158254863Storek int *retval; 158354863Storek { 158460428Smckusick struct truncate_args nuap; 158554863Storek 158664410Sbostic nuap.path = uap->path; 158754863Storek nuap.length = uap->length; 158860428Smckusick return (truncate(p, &nuap, retval)); 158954863Storek } 159054863Storek 159154863Storek /* 159254863Storek * Truncate a file given a file descriptor. 159354863Storek */ 159460428Smckusick struct oftruncate_args { 159554916Storek int fd; 159654916Storek long length; 159754916Storek }; 159854863Storek /* ARGSUSED */ 159960105Smckusick oftruncate(p, uap, retval) 160054863Storek struct proc *p; 160160428Smckusick register struct oftruncate_args *uap; 160254863Storek int *retval; 160354863Storek { 160460428Smckusick struct ftruncate_args nuap; 160554863Storek 160654863Storek nuap.fd = uap->fd; 160754863Storek nuap.length = uap->length; 160860428Smckusick return (ftruncate(p, &nuap, retval)); 160954863Storek } 161054863Storek #endif /* COMPAT_43 || COMPAT_SUNOS */ 161154863Storek 161254863Storek /* 161364410Sbostic * Sync an open file. 16149167Ssam */ 161554916Storek struct fsync_args { 161654916Storek int fd; 161754916Storek }; 161842441Smckusick /* ARGSUSED */ 161942441Smckusick fsync(p, uap, retval) 162045914Smckusick struct proc *p; 162154916Storek struct fsync_args *uap; 162242441Smckusick int *retval; 16239167Ssam { 162439592Smckusick register struct vnode *vp; 16259167Ssam struct file *fp; 162637741Smckusick int error; 16279167Ssam 162845914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 162947540Skarels return (error); 163039592Smckusick vp = (struct vnode *)fp->f_data; 163139592Smckusick VOP_LOCK(vp); 163254441Smckusick error = VOP_FSYNC(vp, fp->f_cred, MNT_WAIT, p); 163339592Smckusick VOP_UNLOCK(vp); 163447540Skarels return (error); 16359167Ssam } 16369167Ssam 16379167Ssam /* 163864410Sbostic * Rename files. Source and destination must either both be directories, 163964410Sbostic * or both not be directories. If target is a directory, it must be empty. 16409167Ssam */ 164154916Storek struct rename_args { 164254916Storek char *from; 164354916Storek char *to; 164454916Storek }; 164542441Smckusick /* ARGSUSED */ 164642441Smckusick rename(p, uap, retval) 164745914Smckusick struct proc *p; 164854916Storek register struct rename_args *uap; 164942441Smckusick int *retval; 165042441Smckusick { 165137741Smckusick register struct vnode *tvp, *fvp, *tdvp; 165249735Smckusick struct nameidata fromnd, tond; 165337741Smckusick int error; 16547701Ssam 165552322Smckusick NDINIT(&fromnd, DELETE, WANTPARENT | SAVESTART, UIO_USERSPACE, 165652322Smckusick uap->from, p); 165752322Smckusick if (error = namei(&fromnd)) 165847540Skarels return (error); 165949735Smckusick fvp = fromnd.ni_vp; 166052322Smckusick NDINIT(&tond, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART, 166152322Smckusick UIO_USERSPACE, uap->to, p); 166252322Smckusick if (error = namei(&tond)) { 166352230Sheideman VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 166449735Smckusick vrele(fromnd.ni_dvp); 166542465Smckusick vrele(fvp); 166642465Smckusick goto out1; 166742465Smckusick } 166837741Smckusick tdvp = tond.ni_dvp; 166937741Smckusick tvp = tond.ni_vp; 167037741Smckusick if (tvp != NULL) { 167137741Smckusick if (fvp->v_type == VDIR && tvp->v_type != VDIR) { 167239242Sbostic error = ENOTDIR; 167337741Smckusick goto out; 167437741Smckusick } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) { 167539242Sbostic error = EISDIR; 167637741Smckusick goto out; 16779167Ssam } 16789167Ssam } 167939286Smckusick if (fvp == tdvp) 168037741Smckusick error = EINVAL; 168139286Smckusick /* 168249735Smckusick * If source is the same as the destination (that is the 168349735Smckusick * same inode number with the same name in the same directory), 168439286Smckusick * then there is nothing to do. 168539286Smckusick */ 168649735Smckusick if (fvp == tvp && fromnd.ni_dvp == tdvp && 168752322Smckusick fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen && 168852322Smckusick !bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr, 168952322Smckusick fromnd.ni_cnd.cn_namelen)) 169039286Smckusick error = -1; 169137741Smckusick out: 169242465Smckusick if (!error) { 169352192Smckusick LEASE_CHECK(tdvp, p, p->p_ucred, LEASE_WRITE); 169452192Smckusick if (fromnd.ni_dvp != tdvp) 169552192Smckusick LEASE_CHECK(fromnd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 169652192Smckusick if (tvp) 169752192Smckusick LEASE_CHECK(tvp, p, p->p_ucred, LEASE_WRITE); 169852230Sheideman error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd, 169952230Sheideman tond.ni_dvp, tond.ni_vp, &tond.ni_cnd); 170042465Smckusick } else { 170152230Sheideman VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd); 170243344Smckusick if (tdvp == tvp) 170343344Smckusick vrele(tdvp); 170443344Smckusick else 170543344Smckusick vput(tdvp); 170642465Smckusick if (tvp) 170742465Smckusick vput(tvp); 170852230Sheideman VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 170949735Smckusick vrele(fromnd.ni_dvp); 171042465Smckusick vrele(fvp); 17119167Ssam } 171249735Smckusick vrele(tond.ni_startdir); 171352322Smckusick FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI); 171437741Smckusick out1: 1715*66801Smckusick if (fromnd.ni_startdir) 1716*66801Smckusick vrele(fromnd.ni_startdir); 171752322Smckusick FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI); 171839286Smckusick if (error == -1) 171947540Skarels return (0); 172047540Skarels return (error); 17217701Ssam } 17227701Ssam 17237535Sroot /* 172464410Sbostic * Make a directory file. 172512756Ssam */ 172654916Storek struct mkdir_args { 172764410Sbostic char *path; 172864410Sbostic int mode; 172954916Storek }; 173042441Smckusick /* ARGSUSED */ 173142441Smckusick mkdir(p, uap, retval) 173245914Smckusick struct proc *p; 173354916Storek register struct mkdir_args *uap; 173442441Smckusick int *retval; 173542441Smckusick { 173637741Smckusick register struct vnode *vp; 173737741Smckusick struct vattr vattr; 173837741Smckusick int error; 173947540Skarels struct nameidata nd; 174012756Ssam 174164410Sbostic NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->path, p); 174252322Smckusick if (error = namei(&nd)) 174347540Skarels return (error); 174452322Smckusick vp = nd.ni_vp; 174537741Smckusick if (vp != NULL) { 174652322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 174752322Smckusick if (nd.ni_dvp == vp) 174852322Smckusick vrele(nd.ni_dvp); 174943344Smckusick else 175052322Smckusick vput(nd.ni_dvp); 175142465Smckusick vrele(vp); 175247540Skarels return (EEXIST); 175312756Ssam } 175441362Smckusick VATTR_NULL(&vattr); 175537741Smckusick vattr.va_type = VDIR; 175664410Sbostic vattr.va_mode = (uap->mode & ACCESSPERMS) &~ p->p_fd->fd_cmask; 175752322Smckusick LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 175852322Smckusick error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr); 175938145Smckusick if (!error) 176052322Smckusick vput(nd.ni_vp); 176147540Skarels return (error); 176212756Ssam } 176312756Ssam 176412756Ssam /* 176564410Sbostic * Remove a directory file. 176612756Ssam */ 176754916Storek struct rmdir_args { 176864410Sbostic char *path; 176954916Storek }; 177042441Smckusick /* ARGSUSED */ 177142441Smckusick rmdir(p, uap, retval) 177245914Smckusick struct proc *p; 177354916Storek struct rmdir_args *uap; 177442441Smckusick int *retval; 177512756Ssam { 177637741Smckusick register struct vnode *vp; 177737741Smckusick int error; 177847540Skarels struct nameidata nd; 177912756Ssam 178064410Sbostic NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE, uap->path, p); 178152322Smckusick if (error = namei(&nd)) 178247540Skarels return (error); 178352322Smckusick vp = nd.ni_vp; 178437741Smckusick if (vp->v_type != VDIR) { 178537741Smckusick error = ENOTDIR; 178612756Ssam goto out; 178712756Ssam } 178812756Ssam /* 178937741Smckusick * No rmdir "." please. 179012756Ssam */ 179152322Smckusick if (nd.ni_dvp == vp) { 179237741Smckusick error = EINVAL; 179312756Ssam goto out; 179412756Ssam } 179512756Ssam /* 179649365Smckusick * The root of a mounted filesystem cannot be deleted. 179712756Ssam */ 179837741Smckusick if (vp->v_flag & VROOT) 179937741Smckusick error = EBUSY; 180012756Ssam out: 180142465Smckusick if (!error) { 180252322Smckusick LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 180352192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 180452322Smckusick error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); 180542465Smckusick } else { 180652322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 180752322Smckusick if (nd.ni_dvp == vp) 180852322Smckusick vrele(nd.ni_dvp); 180943344Smckusick else 181052322Smckusick vput(nd.ni_dvp); 181142465Smckusick vput(vp); 181242465Smckusick } 181347540Skarels return (error); 181412756Ssam } 181512756Ssam 181654620Smckusick #ifdef COMPAT_43 181737741Smckusick /* 181849365Smckusick * Read a block of directory entries in a file system independent format. 181937741Smckusick */ 182054916Storek struct ogetdirentries_args { 182154916Storek int fd; 182254916Storek char *buf; 182364410Sbostic u_int count; 182454916Storek long *basep; 182554916Storek }; 182654620Smckusick ogetdirentries(p, uap, retval) 182754620Smckusick struct proc *p; 182854916Storek register struct ogetdirentries_args *uap; 182954620Smckusick int *retval; 183054620Smckusick { 183154620Smckusick register struct vnode *vp; 183254620Smckusick struct file *fp; 183354620Smckusick struct uio auio, kuio; 183454620Smckusick struct iovec aiov, kiov; 183554620Smckusick struct dirent *dp, *edp; 183654620Smckusick caddr_t dirbuf; 183754620Smckusick int error, readcnt; 183854969Smckusick long loff; 183954620Smckusick 184054620Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 184154620Smckusick return (error); 184254620Smckusick if ((fp->f_flag & FREAD) == 0) 184354620Smckusick return (EBADF); 184454620Smckusick vp = (struct vnode *)fp->f_data; 184554620Smckusick if (vp->v_type != VDIR) 184654620Smckusick return (EINVAL); 184754620Smckusick aiov.iov_base = uap->buf; 184854620Smckusick aiov.iov_len = uap->count; 184954620Smckusick auio.uio_iov = &aiov; 185054620Smckusick auio.uio_iovcnt = 1; 185154620Smckusick auio.uio_rw = UIO_READ; 185254620Smckusick auio.uio_segflg = UIO_USERSPACE; 185354620Smckusick auio.uio_procp = p; 185454620Smckusick auio.uio_resid = uap->count; 185554620Smckusick VOP_LOCK(vp); 185654969Smckusick loff = auio.uio_offset = fp->f_offset; 185754620Smckusick # if (BYTE_ORDER != LITTLE_ENDIAN) 185856339Smckusick if (vp->v_mount->mnt_maxsymlinklen <= 0) { 185954620Smckusick error = VOP_READDIR(vp, &auio, fp->f_cred); 186056339Smckusick fp->f_offset = auio.uio_offset; 186156339Smckusick } else 186254620Smckusick # endif 186354620Smckusick { 186454620Smckusick kuio = auio; 186554620Smckusick kuio.uio_iov = &kiov; 186654620Smckusick kuio.uio_segflg = UIO_SYSSPACE; 186754620Smckusick kiov.iov_len = uap->count; 186854620Smckusick MALLOC(dirbuf, caddr_t, uap->count, M_TEMP, M_WAITOK); 186954620Smckusick kiov.iov_base = dirbuf; 187054620Smckusick error = VOP_READDIR(vp, &kuio, fp->f_cred); 187156339Smckusick fp->f_offset = kuio.uio_offset; 187254620Smckusick if (error == 0) { 187354620Smckusick readcnt = uap->count - kuio.uio_resid; 187454620Smckusick edp = (struct dirent *)&dirbuf[readcnt]; 187554620Smckusick for (dp = (struct dirent *)dirbuf; dp < edp; ) { 187654620Smckusick # if (BYTE_ORDER == LITTLE_ENDIAN) 187754969Smckusick /* 187855009Smckusick * The expected low byte of 187955009Smckusick * dp->d_namlen is our dp->d_type. 188055009Smckusick * The high MBZ byte of dp->d_namlen 188155009Smckusick * is our dp->d_namlen. 188254969Smckusick */ 188355009Smckusick dp->d_type = dp->d_namlen; 188455009Smckusick dp->d_namlen = 0; 188555009Smckusick # else 188655009Smckusick /* 188755009Smckusick * The dp->d_type is the high byte 188855009Smckusick * of the expected dp->d_namlen, 188955009Smckusick * so must be zero'ed. 189055009Smckusick */ 189155009Smckusick dp->d_type = 0; 189254620Smckusick # endif 189354620Smckusick if (dp->d_reclen > 0) { 189454620Smckusick dp = (struct dirent *) 189554620Smckusick ((char *)dp + dp->d_reclen); 189654620Smckusick } else { 189754620Smckusick error = EIO; 189854620Smckusick break; 189954620Smckusick } 190054620Smckusick } 190154620Smckusick if (dp >= edp) 190254620Smckusick error = uiomove(dirbuf, readcnt, &auio); 190354620Smckusick } 190454620Smckusick FREE(dirbuf, M_TEMP); 190554620Smckusick } 190654620Smckusick VOP_UNLOCK(vp); 190754620Smckusick if (error) 190854620Smckusick return (error); 190954969Smckusick error = copyout((caddr_t)&loff, (caddr_t)uap->basep, sizeof(long)); 191054620Smckusick *retval = uap->count - auio.uio_resid; 191154620Smckusick return (error); 191254620Smckusick } 191354620Smckusick #endif 191454620Smckusick 191554620Smckusick /* 191654620Smckusick * Read a block of directory entries in a file system independent format. 191754620Smckusick */ 191854916Storek struct getdirentries_args { 191954916Storek int fd; 192054916Storek char *buf; 192164410Sbostic u_int count; 192254916Storek long *basep; 192354916Storek }; 192442441Smckusick getdirentries(p, uap, retval) 192545914Smckusick struct proc *p; 192654916Storek register struct getdirentries_args *uap; 192742441Smckusick int *retval; 192842441Smckusick { 192939592Smckusick register struct vnode *vp; 193016540Ssam struct file *fp; 193137741Smckusick struct uio auio; 193237741Smckusick struct iovec aiov; 193354969Smckusick long loff; 193454441Smckusick int error; 193512756Ssam 193645914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 193747540Skarels return (error); 193837741Smckusick if ((fp->f_flag & FREAD) == 0) 193947540Skarels return (EBADF); 194039592Smckusick vp = (struct vnode *)fp->f_data; 194155451Spendry unionread: 194239592Smckusick if (vp->v_type != VDIR) 194347540Skarels return (EINVAL); 194437741Smckusick aiov.iov_base = uap->buf; 194537741Smckusick aiov.iov_len = uap->count; 194637741Smckusick auio.uio_iov = &aiov; 194737741Smckusick auio.uio_iovcnt = 1; 194837741Smckusick auio.uio_rw = UIO_READ; 194937741Smckusick auio.uio_segflg = UIO_USERSPACE; 195048026Smckusick auio.uio_procp = p; 195137741Smckusick auio.uio_resid = uap->count; 195239592Smckusick VOP_LOCK(vp); 195354969Smckusick loff = auio.uio_offset = fp->f_offset; 195454441Smckusick error = VOP_READDIR(vp, &auio, fp->f_cred); 195539592Smckusick fp->f_offset = auio.uio_offset; 195639592Smckusick VOP_UNLOCK(vp); 195739592Smckusick if (error) 195847540Skarels return (error); 195966095Spendry 196066095Spendry #ifdef UNION 196166095Spendry { 196266095Spendry extern int (**union_vnodeop_p)(); 196366095Spendry extern struct vnode *union_lowervp __P((struct vnode *)); 196466095Spendry 196555451Spendry if ((uap->count == auio.uio_resid) && 196666095Spendry (vp->v_op == union_vnodeop_p)) { 196766095Spendry struct vnode *tvp = vp; 196866095Spendry 196966095Spendry vp = union_lowervp(vp); 197066095Spendry if (vp != NULLVP) { 197166095Spendry VOP_LOCK(vp); 197266095Spendry error = VOP_OPEN(vp, FREAD); 197366095Spendry VOP_UNLOCK(vp); 197466095Spendry 197566095Spendry if (error) { 197666095Spendry vrele(vp); 197766095Spendry return (error); 197866095Spendry } 197966095Spendry fp->f_data = (caddr_t) vp; 198066095Spendry fp->f_offset = 0; 198166095Spendry error = vn_close(tvp, FREAD, fp->f_cred, p); 198266095Spendry if (error) 198366095Spendry return (error); 198466095Spendry goto unionread; 198566095Spendry } 198666095Spendry } 198766095Spendry } 198866095Spendry #endif 198966095Spendry 199066095Spendry if ((uap->count == auio.uio_resid) && 199155451Spendry (vp->v_flag & VROOT) && 199255451Spendry (vp->v_mount->mnt_flag & MNT_UNION)) { 199355451Spendry struct vnode *tvp = vp; 199455451Spendry vp = vp->v_mount->mnt_vnodecovered; 199555451Spendry VREF(vp); 199655451Spendry fp->f_data = (caddr_t) vp; 199755451Spendry fp->f_offset = 0; 199855451Spendry vrele(tvp); 199955451Spendry goto unionread; 200055451Spendry } 200154969Smckusick error = copyout((caddr_t)&loff, (caddr_t)uap->basep, sizeof(long)); 200242441Smckusick *retval = uap->count - auio.uio_resid; 200347540Skarels return (error); 200412756Ssam } 200512756Ssam 200612756Ssam /* 200749365Smckusick * Set the mode mask for creation of filesystem nodes. 200812756Ssam */ 200954916Storek struct umask_args { 201064410Sbostic int newmask; 201154916Storek }; 201254916Storek mode_t /* XXX */ 201342441Smckusick umask(p, uap, retval) 201445914Smckusick struct proc *p; 201554916Storek struct umask_args *uap; 201642441Smckusick int *retval; 201712756Ssam { 201864410Sbostic register struct filedesc *fdp; 201912756Ssam 202064410Sbostic fdp = p->p_fd; 202145914Smckusick *retval = fdp->fd_cmask; 202264410Sbostic fdp->fd_cmask = uap->newmask & ALLPERMS; 202347540Skarels return (0); 202412756Ssam } 202537741Smckusick 202639566Smarc /* 202739566Smarc * Void all references to file by ripping underlying filesystem 202839566Smarc * away from vnode. 202939566Smarc */ 203054916Storek struct revoke_args { 203164410Sbostic char *path; 203254916Storek }; 203342441Smckusick /* ARGSUSED */ 203442441Smckusick revoke(p, uap, retval) 203545914Smckusick struct proc *p; 203654916Storek register struct revoke_args *uap; 203742441Smckusick int *retval; 203842441Smckusick { 203939566Smarc register struct vnode *vp; 204039566Smarc struct vattr vattr; 204139566Smarc int error; 204247540Skarels struct nameidata nd; 204339566Smarc 204464410Sbostic NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); 204552322Smckusick if (error = namei(&nd)) 204647540Skarels return (error); 204752322Smckusick vp = nd.ni_vp; 204839566Smarc if (vp->v_type != VCHR && vp->v_type != VBLK) { 204939566Smarc error = EINVAL; 205039566Smarc goto out; 205139566Smarc } 205248026Smckusick if (error = VOP_GETATTR(vp, &vattr, p->p_ucred, p)) 205339566Smarc goto out; 205447540Skarels if (p->p_ucred->cr_uid != vattr.va_uid && 205547540Skarels (error = suser(p->p_ucred, &p->p_acflag))) 205639566Smarc goto out; 205739805Smckusick if (vp->v_usecount > 1 || (vp->v_flag & VALIASED)) 205839632Smckusick vgoneall(vp); 205939566Smarc out: 206039566Smarc vrele(vp); 206147540Skarels return (error); 206239566Smarc } 206339566Smarc 206449365Smckusick /* 206549365Smckusick * Convert a user file descriptor to a kernel file entry. 206649365Smckusick */ 206764410Sbostic getvnode(fdp, fd, fpp) 206845914Smckusick struct filedesc *fdp; 206937741Smckusick struct file **fpp; 207064410Sbostic int fd; 207137741Smckusick { 207237741Smckusick struct file *fp; 207337741Smckusick 207464410Sbostic if ((u_int)fd >= fdp->fd_nfiles || 207564410Sbostic (fp = fdp->fd_ofiles[fd]) == NULL) 207637741Smckusick return (EBADF); 207737741Smckusick if (fp->f_type != DTYPE_VNODE) 207837741Smckusick return (EINVAL); 207937741Smckusick *fpp = fp; 208037741Smckusick return (0); 208137741Smckusick } 2082