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*67518Spendry * @(#)vfs_syscalls.c 8.17 (Berkeley) 07/12/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 */ 25767403Smckusick #ifdef DEBUG 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 /* 833*67518Spendry * Delete a whiteout from the filesystem. 834*67518Spendry */ 835*67518Spendry struct unwhiteout_args { 836*67518Spendry char *path; 837*67518Spendry }; 838*67518Spendry /* ARGSUSED */ 839*67518Spendry unwhiteout(p, uap, retval) 840*67518Spendry struct proc *p; 841*67518Spendry struct unwhiteout_args *uap; 842*67518Spendry int *retval; 843*67518Spendry { 844*67518Spendry int error; 845*67518Spendry struct nameidata nd; 846*67518Spendry 847*67518Spendry NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->path, p); 848*67518Spendry if (error = namei(&nd)) 849*67518Spendry return (error); 850*67518Spendry if (nd.ni_vp || !(nd.ni_cnd.cn_flags & WHITEOUT)) { 851*67518Spendry VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 852*67518Spendry if (nd.ni_dvp == nd.ni_vp) 853*67518Spendry vrele(nd.ni_dvp); 854*67518Spendry else 855*67518Spendry vput(nd.ni_dvp); 856*67518Spendry if (nd.ni_vp) 857*67518Spendry vrele(nd.ni_vp); 858*67518Spendry return (EEXIST); 859*67518Spendry } 860*67518Spendry LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 861*67518Spendry error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, DELETE); 862*67518Spendry vput(nd.ni_dvp); 863*67518Spendry return (error); 864*67518Spendry } 865*67518Spendry 866*67518Spendry /* 86749365Smckusick * Delete a name from the filesystem. 8686254Sroot */ 86954916Storek struct unlink_args { 87064410Sbostic char *path; 87154916Storek }; 87242441Smckusick /* ARGSUSED */ 87342441Smckusick unlink(p, uap, retval) 87445914Smckusick struct proc *p; 87554916Storek struct unlink_args *uap; 87642441Smckusick int *retval; 8776254Sroot { 87837741Smckusick register struct vnode *vp; 87937741Smckusick int error; 88047540Skarels struct nameidata nd; 8816254Sroot 88264410Sbostic NDINIT(&nd, DELETE, LOCKPARENT, UIO_USERSPACE, uap->path, p); 88352322Smckusick if (error = namei(&nd)) 88447540Skarels return (error); 88552322Smckusick vp = nd.ni_vp; 88659382Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 88759382Smckusick VOP_LOCK(vp); 88864410Sbostic 88964585Sbostic if (vp->v_type != VDIR || 89064585Sbostic (error = suser(p->p_ucred, &p->p_acflag)) == 0) { 89164585Sbostic /* 89264585Sbostic * The root of a mounted filesystem cannot be deleted. 89364585Sbostic */ 89464585Sbostic if (vp->v_flag & VROOT) 89564585Sbostic error = EBUSY; 89664585Sbostic else 89764585Sbostic (void)vnode_pager_uncache(vp); 89864585Sbostic } 89964585Sbostic 90064585Sbostic if (!error) { 90152322Smckusick LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 90252322Smckusick error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); 90342465Smckusick } else { 90452322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 90552322Smckusick if (nd.ni_dvp == vp) 90652322Smckusick vrele(nd.ni_dvp); 90743344Smckusick else 90852322Smckusick vput(nd.ni_dvp); 90942465Smckusick vput(vp); 91042465Smckusick } 91147540Skarels return (error); 9126254Sroot } 9136254Sroot 91464410Sbostic /* 91564410Sbostic * Reposition read/write file offset. 91664410Sbostic */ 91760428Smckusick struct lseek_args { 91864410Sbostic int fd; 91954863Storek int pad; 92064410Sbostic off_t offset; 92164410Sbostic int whence; 92254863Storek }; 92360414Smckusick lseek(p, uap, retval) 92453468Smckusick struct proc *p; 92560428Smckusick register struct lseek_args *uap; 92654916Storek int *retval; 92742441Smckusick { 92847540Skarels struct ucred *cred = p->p_ucred; 92945914Smckusick register struct filedesc *fdp = p->p_fd; 93042441Smckusick register struct file *fp; 93137741Smckusick struct vattr vattr; 93237741Smckusick int error; 9336254Sroot 93464410Sbostic if ((u_int)uap->fd >= fdp->fd_nfiles || 93564410Sbostic (fp = fdp->fd_ofiles[uap->fd]) == NULL) 93647540Skarels return (EBADF); 93737741Smckusick if (fp->f_type != DTYPE_VNODE) 93847540Skarels return (ESPIPE); 93964410Sbostic switch (uap->whence) { 94013878Ssam case L_INCR: 94164410Sbostic fp->f_offset += uap->offset; 94213878Ssam break; 94313878Ssam case L_XTND: 94464410Sbostic if (error = 94564410Sbostic VOP_GETATTR((struct vnode *)fp->f_data, &vattr, cred, p)) 94647540Skarels return (error); 94764410Sbostic fp->f_offset = uap->offset + vattr.va_size; 94813878Ssam break; 94913878Ssam case L_SET: 95064410Sbostic fp->f_offset = uap->offset; 95113878Ssam break; 95213878Ssam default: 95347540Skarels return (EINVAL); 95413878Ssam } 95554916Storek *(off_t *)retval = fp->f_offset; 95647540Skarels return (0); 9576254Sroot } 9586254Sroot 95960414Smckusick #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 9606254Sroot /* 96164410Sbostic * Reposition read/write file offset. 96260036Smckusick */ 96360428Smckusick struct olseek_args { 96464410Sbostic int fd; 96564410Sbostic long offset; 96664410Sbostic int whence; 96760036Smckusick }; 96860414Smckusick olseek(p, uap, retval) 96960036Smckusick struct proc *p; 97060428Smckusick register struct olseek_args *uap; 97160036Smckusick int *retval; 97260036Smckusick { 97360428Smckusick struct lseek_args nuap; 97460036Smckusick off_t qret; 97560036Smckusick int error; 97660036Smckusick 97764410Sbostic nuap.fd = uap->fd; 97864410Sbostic nuap.offset = uap->offset; 97964410Sbostic nuap.whence = uap->whence; 98060428Smckusick error = lseek(p, &nuap, &qret); 98160036Smckusick *(long *)retval = qret; 98260036Smckusick return (error); 98360036Smckusick } 98460414Smckusick #endif /* COMPAT_43 */ 98560036Smckusick 98660036Smckusick /* 98749365Smckusick * Check access permissions. 9886254Sroot */ 98963427Sbostic struct access_args { 99064410Sbostic char *path; 99164410Sbostic int flags; 99254916Storek }; 99363427Sbostic access(p, uap, retval) 99445914Smckusick struct proc *p; 99563427Sbostic register struct access_args *uap; 99642441Smckusick int *retval; 99742441Smckusick { 99847540Skarels register struct ucred *cred = p->p_ucred; 99937741Smckusick register struct vnode *vp; 100064585Sbostic int error, flags, t_gid, t_uid; 100147540Skarels struct nameidata nd; 10026254Sroot 100364585Sbostic t_uid = cred->cr_uid; 100464585Sbostic t_gid = cred->cr_groups[0]; 100547540Skarels cred->cr_uid = p->p_cred->p_ruid; 100647540Skarels cred->cr_groups[0] = p->p_cred->p_rgid; 100764410Sbostic NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); 100852322Smckusick if (error = namei(&nd)) 100937741Smckusick goto out1; 101052322Smckusick vp = nd.ni_vp; 101164410Sbostic 101264410Sbostic /* Flags == 0 means only check for existence. */ 101364410Sbostic if (uap->flags) { 101464410Sbostic flags = 0; 101564410Sbostic if (uap->flags & R_OK) 101664410Sbostic flags |= VREAD; 101764410Sbostic if (uap->flags & W_OK) 101864410Sbostic flags |= VWRITE; 101964410Sbostic if (uap->flags & X_OK) 102064410Sbostic flags |= VEXEC; 102164410Sbostic if ((flags & VWRITE) == 0 || (error = vn_writechk(vp)) == 0) 102264410Sbostic error = VOP_ACCESS(vp, flags, cred, p); 10236254Sroot } 102437741Smckusick vput(vp); 102537741Smckusick out1: 102664585Sbostic cred->cr_uid = t_uid; 102764585Sbostic cred->cr_groups[0] = t_gid; 102847540Skarels return (error); 10296254Sroot } 10306254Sroot 103154348Smckusick #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 10326254Sroot /* 103364410Sbostic * Get file status; this version follows links. 103437Sbill */ 103554916Storek struct ostat_args { 103664410Sbostic char *path; 103754916Storek struct ostat *ub; 103854916Storek }; 103942441Smckusick /* ARGSUSED */ 104053759Smckusick ostat(p, uap, retval) 104145914Smckusick struct proc *p; 104254916Storek register struct ostat_args *uap; 104353468Smckusick int *retval; 104453468Smckusick { 104553468Smckusick struct stat sb; 104653468Smckusick struct ostat osb; 104753468Smckusick int error; 104853468Smckusick struct nameidata nd; 104953468Smckusick 105064410Sbostic NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); 105153468Smckusick if (error = namei(&nd)) 105253468Smckusick return (error); 105353468Smckusick error = vn_stat(nd.ni_vp, &sb, p); 105453468Smckusick vput(nd.ni_vp); 105553468Smckusick if (error) 105653468Smckusick return (error); 105753468Smckusick cvtstat(&sb, &osb); 105853468Smckusick error = copyout((caddr_t)&osb, (caddr_t)uap->ub, sizeof (osb)); 105953468Smckusick return (error); 106053468Smckusick } 106153468Smckusick 106253468Smckusick /* 106364410Sbostic * Get file status; this version does not follow links. 106453468Smckusick */ 106554916Storek struct olstat_args { 106664410Sbostic char *path; 106754916Storek struct ostat *ub; 106854916Storek }; 106953468Smckusick /* ARGSUSED */ 107053759Smckusick olstat(p, uap, retval) 107153468Smckusick struct proc *p; 107254916Storek register struct olstat_args *uap; 107353468Smckusick int *retval; 107453468Smckusick { 107553468Smckusick struct stat sb; 107653468Smckusick struct ostat osb; 107753468Smckusick int error; 107853468Smckusick struct nameidata nd; 107953468Smckusick 108064410Sbostic NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); 108153468Smckusick if (error = namei(&nd)) 108253468Smckusick return (error); 108353468Smckusick error = vn_stat(nd.ni_vp, &sb, p); 108453468Smckusick vput(nd.ni_vp); 108553468Smckusick if (error) 108653468Smckusick return (error); 108753468Smckusick cvtstat(&sb, &osb); 108853468Smckusick error = copyout((caddr_t)&osb, (caddr_t)uap->ub, sizeof (osb)); 108953468Smckusick return (error); 109053468Smckusick } 109153468Smckusick 109253468Smckusick /* 109364410Sbostic * Convert from an old to a new stat structure. 109453468Smckusick */ 109553468Smckusick cvtstat(st, ost) 109653468Smckusick struct stat *st; 109753468Smckusick struct ostat *ost; 109853468Smckusick { 109953468Smckusick 110053468Smckusick ost->st_dev = st->st_dev; 110153468Smckusick ost->st_ino = st->st_ino; 110253468Smckusick ost->st_mode = st->st_mode; 110353468Smckusick ost->st_nlink = st->st_nlink; 110453468Smckusick ost->st_uid = st->st_uid; 110553468Smckusick ost->st_gid = st->st_gid; 110653468Smckusick ost->st_rdev = st->st_rdev; 110753468Smckusick if (st->st_size < (quad_t)1 << 32) 110853468Smckusick ost->st_size = st->st_size; 110953468Smckusick else 111053468Smckusick ost->st_size = -2; 111153468Smckusick ost->st_atime = st->st_atime; 111253468Smckusick ost->st_mtime = st->st_mtime; 111353468Smckusick ost->st_ctime = st->st_ctime; 111453468Smckusick ost->st_blksize = st->st_blksize; 111553468Smckusick ost->st_blocks = st->st_blocks; 111653468Smckusick ost->st_flags = st->st_flags; 111753468Smckusick ost->st_gen = st->st_gen; 111853468Smckusick } 111954348Smckusick #endif /* COMPAT_43 || COMPAT_SUNOS */ 112053468Smckusick 112153468Smckusick /* 112264410Sbostic * Get file status; this version follows links. 112353468Smckusick */ 112454916Storek struct stat_args { 112564410Sbostic char *path; 112654916Storek struct stat *ub; 112754916Storek }; 112853468Smckusick /* ARGSUSED */ 112953759Smckusick stat(p, uap, retval) 113053468Smckusick struct proc *p; 113154916Storek register struct stat_args *uap; 113242441Smckusick int *retval; 113337Sbill { 113442441Smckusick struct stat sb; 113542441Smckusick int error; 113647540Skarels struct nameidata nd; 113737Sbill 113864410Sbostic NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); 113952322Smckusick if (error = namei(&nd)) 114047540Skarels return (error); 114152322Smckusick error = vn_stat(nd.ni_vp, &sb, p); 114252322Smckusick vput(nd.ni_vp); 114342441Smckusick if (error) 114447540Skarels return (error); 114542441Smckusick error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb)); 114647540Skarels return (error); 114737Sbill } 114837Sbill 114937Sbill /* 115064410Sbostic * Get file status; this version does not follow links. 11515992Swnj */ 115254916Storek struct lstat_args { 115364410Sbostic char *path; 115454916Storek struct stat *ub; 115554916Storek }; 115642441Smckusick /* ARGSUSED */ 115753759Smckusick lstat(p, uap, retval) 115845914Smckusick struct proc *p; 115954916Storek register struct lstat_args *uap; 116042441Smckusick int *retval; 116142441Smckusick { 116237741Smckusick int error; 116359373Smckusick struct vnode *vp, *dvp; 116459373Smckusick struct stat sb, sb1; 116547540Skarels struct nameidata nd; 11665992Swnj 116759373Smckusick NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | LOCKPARENT, UIO_USERSPACE, 116864410Sbostic uap->path, p); 116952322Smckusick if (error = namei(&nd)) 117047540Skarels return (error); 117159373Smckusick /* 117259373Smckusick * For symbolic links, always return the attributes of its 117359373Smckusick * containing directory, except for mode, size, and links. 117459373Smckusick */ 117559373Smckusick vp = nd.ni_vp; 117659373Smckusick dvp = nd.ni_dvp; 117759373Smckusick if (vp->v_type != VLNK) { 117859373Smckusick if (dvp == vp) 117959373Smckusick vrele(dvp); 118059373Smckusick else 118159373Smckusick vput(dvp); 118259373Smckusick error = vn_stat(vp, &sb, p); 118359373Smckusick vput(vp); 118459373Smckusick if (error) 118559373Smckusick return (error); 118659373Smckusick } else { 118759373Smckusick error = vn_stat(dvp, &sb, p); 118859373Smckusick vput(dvp); 118959373Smckusick if (error) { 119059373Smckusick vput(vp); 119159373Smckusick return (error); 119259373Smckusick } 119359373Smckusick error = vn_stat(vp, &sb1, p); 119459373Smckusick vput(vp); 119559373Smckusick if (error) 119659373Smckusick return (error); 119759373Smckusick sb.st_mode &= ~S_IFDIR; 119859373Smckusick sb.st_mode |= S_IFLNK; 119959373Smckusick sb.st_nlink = sb1.st_nlink; 120059373Smckusick sb.st_size = sb1.st_size; 120159373Smckusick sb.st_blocks = sb1.st_blocks; 120259373Smckusick } 120337741Smckusick error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb)); 120447540Skarels return (error); 12055992Swnj } 12065992Swnj 12075992Swnj /* 120864410Sbostic * Get configurable pathname variables. 120960414Smckusick */ 121060414Smckusick struct pathconf_args { 121164410Sbostic char *path; 121260414Smckusick int name; 121360414Smckusick }; 121460414Smckusick /* ARGSUSED */ 121560414Smckusick pathconf(p, uap, retval) 121660414Smckusick struct proc *p; 121760414Smckusick register struct pathconf_args *uap; 121860414Smckusick int *retval; 121960414Smckusick { 122060414Smckusick int error; 122160414Smckusick struct nameidata nd; 122260414Smckusick 122364410Sbostic NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); 122460414Smckusick if (error = namei(&nd)) 122560414Smckusick return (error); 122660414Smckusick error = VOP_PATHCONF(nd.ni_vp, uap->name, retval); 122760414Smckusick vput(nd.ni_vp); 122860414Smckusick return (error); 122960414Smckusick } 123060414Smckusick 123160414Smckusick /* 123249365Smckusick * Return target name of a symbolic link. 123337Sbill */ 123454916Storek struct readlink_args { 123564410Sbostic char *path; 123654916Storek char *buf; 123754916Storek int count; 123854916Storek }; 123942441Smckusick /* ARGSUSED */ 124042441Smckusick readlink(p, uap, retval) 124145914Smckusick struct proc *p; 124254916Storek register struct readlink_args *uap; 124342441Smckusick int *retval; 124442441Smckusick { 124537741Smckusick register struct vnode *vp; 124637741Smckusick struct iovec aiov; 124737741Smckusick struct uio auio; 124837741Smckusick int error; 124947540Skarels struct nameidata nd; 12505992Swnj 125164410Sbostic NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); 125252322Smckusick if (error = namei(&nd)) 125347540Skarels return (error); 125452322Smckusick vp = nd.ni_vp; 125564410Sbostic if (vp->v_type != VLNK) 125637741Smckusick error = EINVAL; 125764410Sbostic else { 125864410Sbostic aiov.iov_base = uap->buf; 125964410Sbostic aiov.iov_len = uap->count; 126064410Sbostic auio.uio_iov = &aiov; 126164410Sbostic auio.uio_iovcnt = 1; 126264410Sbostic auio.uio_offset = 0; 126364410Sbostic auio.uio_rw = UIO_READ; 126464410Sbostic auio.uio_segflg = UIO_USERSPACE; 126564410Sbostic auio.uio_procp = p; 126664410Sbostic auio.uio_resid = uap->count; 126764410Sbostic error = VOP_READLINK(vp, &auio, p->p_ucred); 12685992Swnj } 126937741Smckusick vput(vp); 127042441Smckusick *retval = uap->count - auio.uio_resid; 127147540Skarels return (error); 12725992Swnj } 12735992Swnj 12749167Ssam /* 127564410Sbostic * Change flags of a file given a path name. 127638259Smckusick */ 127754916Storek struct chflags_args { 127864410Sbostic char *path; 127954916Storek int flags; 128054916Storek }; 128142441Smckusick /* ARGSUSED */ 128242441Smckusick chflags(p, uap, retval) 128345914Smckusick struct proc *p; 128454916Storek register struct chflags_args *uap; 128542441Smckusick int *retval; 128642441Smckusick { 128738259Smckusick register struct vnode *vp; 128838259Smckusick struct vattr vattr; 128938259Smckusick int error; 129047540Skarels struct nameidata nd; 129138259Smckusick 129264410Sbostic NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); 129352322Smckusick if (error = namei(&nd)) 129447540Skarels return (error); 129552322Smckusick vp = nd.ni_vp; 129659382Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 129759382Smckusick 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 vput(vp); 130647540Skarels return (error); 130738259Smckusick } 130838259Smckusick 130938259Smckusick /* 131038259Smckusick * Change flags of a file given a file descriptor. 131138259Smckusick */ 131254916Storek struct fchflags_args { 131354916Storek int fd; 131454916Storek int flags; 131554916Storek }; 131642441Smckusick /* ARGSUSED */ 131742441Smckusick fchflags(p, uap, retval) 131845914Smckusick struct proc *p; 131954916Storek register struct fchflags_args *uap; 132042441Smckusick int *retval; 132142441Smckusick { 132238259Smckusick struct vattr vattr; 132338259Smckusick struct vnode *vp; 132438259Smckusick struct file *fp; 132538259Smckusick int error; 132638259Smckusick 132745914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 132847540Skarels return (error); 132938259Smckusick vp = (struct vnode *)fp->f_data; 133059382Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 133138259Smckusick VOP_LOCK(vp); 133264410Sbostic if (vp->v_mount->mnt_flag & MNT_RDONLY) 133338259Smckusick error = EROFS; 133464410Sbostic else { 133564410Sbostic VATTR_NULL(&vattr); 133664410Sbostic vattr.va_flags = uap->flags; 133764410Sbostic error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 133838259Smckusick } 133938259Smckusick VOP_UNLOCK(vp); 134047540Skarels return (error); 134138259Smckusick } 134238259Smckusick 134338259Smckusick /* 13449167Ssam * Change mode of a file given path name. 13459167Ssam */ 134654916Storek struct chmod_args { 134764410Sbostic char *path; 134864410Sbostic int mode; 134954916Storek }; 135042441Smckusick /* ARGSUSED */ 135142441Smckusick chmod(p, uap, retval) 135245914Smckusick struct proc *p; 135354916Storek register struct chmod_args *uap; 135442441Smckusick int *retval; 135542441Smckusick { 135637741Smckusick register struct vnode *vp; 135737741Smckusick struct vattr vattr; 135837741Smckusick int error; 135947540Skarels struct nameidata nd; 13605992Swnj 136164410Sbostic NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); 136252322Smckusick if (error = namei(&nd)) 136347540Skarels return (error); 136452322Smckusick vp = nd.ni_vp; 136559382Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 136659382Smckusick 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); 137337741Smckusick } 137437741Smckusick vput(vp); 137547540Skarels return (error); 13767701Ssam } 13777439Sroot 13789167Ssam /* 13799167Ssam * Change mode of a file given a file descriptor. 13809167Ssam */ 138154916Storek struct fchmod_args { 138254916Storek int fd; 138364410Sbostic int mode; 138454916Storek }; 138542441Smckusick /* ARGSUSED */ 138642441Smckusick fchmod(p, uap, retval) 138745914Smckusick struct proc *p; 138854916Storek register struct fchmod_args *uap; 138942441Smckusick int *retval; 139042441Smckusick { 139137741Smckusick struct vattr vattr; 139237741Smckusick struct vnode *vp; 139337741Smckusick struct file *fp; 139437741Smckusick int error; 13957701Ssam 139645914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 139747540Skarels return (error); 139837741Smckusick vp = (struct vnode *)fp->f_data; 139959382Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 140037741Smckusick VOP_LOCK(vp); 140164410Sbostic if (vp->v_mount->mnt_flag & MNT_RDONLY) 140237741Smckusick error = EROFS; 140364410Sbostic else { 140464410Sbostic VATTR_NULL(&vattr); 140564410Sbostic vattr.va_mode = uap->mode & ALLPERMS; 140664410Sbostic error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 14077439Sroot } 140837741Smckusick VOP_UNLOCK(vp); 140947540Skarels return (error); 14105992Swnj } 14115992Swnj 14129167Ssam /* 14139167Ssam * Set ownership given a path name. 14149167Ssam */ 141554916Storek struct chown_args { 141664410Sbostic char *path; 141754916Storek int uid; 141854916Storek int gid; 141954916Storek }; 142042441Smckusick /* ARGSUSED */ 142142441Smckusick chown(p, uap, retval) 142245914Smckusick struct proc *p; 142354916Storek register struct chown_args *uap; 142442441Smckusick int *retval; 142542441Smckusick { 142637741Smckusick register struct vnode *vp; 142737741Smckusick struct vattr vattr; 142837741Smckusick int error; 142947540Skarels struct nameidata nd; 143037Sbill 143166510Sbostic NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); 143252322Smckusick if (error = namei(&nd)) 143347540Skarels return (error); 143452322Smckusick vp = nd.ni_vp; 143559382Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 143659382Smckusick VOP_LOCK(vp); 143764410Sbostic if (vp->v_mount->mnt_flag & MNT_RDONLY) 143837741Smckusick error = EROFS; 143964410Sbostic else { 144064410Sbostic VATTR_NULL(&vattr); 144164410Sbostic vattr.va_uid = uap->uid; 144264410Sbostic vattr.va_gid = uap->gid; 144364410Sbostic error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 144437741Smckusick } 144537741Smckusick vput(vp); 144647540Skarels return (error); 14477701Ssam } 14487439Sroot 14499167Ssam /* 14509167Ssam * Set ownership given a file descriptor. 14519167Ssam */ 145254916Storek struct fchown_args { 145354916Storek int fd; 145454916Storek int uid; 145554916Storek int gid; 145654916Storek }; 145742441Smckusick /* ARGSUSED */ 145842441Smckusick fchown(p, uap, retval) 145945914Smckusick struct proc *p; 146054916Storek register struct fchown_args *uap; 146142441Smckusick int *retval; 146242441Smckusick { 146337741Smckusick struct vattr vattr; 146437741Smckusick struct vnode *vp; 146537741Smckusick struct file *fp; 146637741Smckusick int error; 14677701Ssam 146845914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 146947540Skarels return (error); 147037741Smckusick vp = (struct vnode *)fp->f_data; 147159382Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 147237741Smckusick VOP_LOCK(vp); 147364410Sbostic if (vp->v_mount->mnt_flag & MNT_RDONLY) 147437741Smckusick error = EROFS; 147564410Sbostic else { 147664410Sbostic VATTR_NULL(&vattr); 147764410Sbostic vattr.va_uid = uap->uid; 147864410Sbostic vattr.va_gid = uap->gid; 147964410Sbostic error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 148037741Smckusick } 148137741Smckusick VOP_UNLOCK(vp); 148247540Skarels return (error); 14837701Ssam } 14847701Ssam 148542441Smckusick /* 148642441Smckusick * Set the access and modification times of a file. 148742441Smckusick */ 148854916Storek struct utimes_args { 148964410Sbostic char *path; 149054916Storek struct timeval *tptr; 149154916Storek }; 149242441Smckusick /* ARGSUSED */ 149342441Smckusick utimes(p, uap, retval) 149445914Smckusick struct proc *p; 149554916Storek register struct utimes_args *uap; 149642441Smckusick int *retval; 149742441Smckusick { 149837741Smckusick register struct vnode *vp; 149911811Ssam struct timeval tv[2]; 150037741Smckusick struct vattr vattr; 150158840Storek int error; 150247540Skarels struct nameidata nd; 150311811Ssam 150458505Sbostic VATTR_NULL(&vattr); 150558505Sbostic if (uap->tptr == NULL) { 150658505Sbostic microtime(&tv[0]); 150758505Sbostic tv[1] = tv[0]; 150858548Sbostic vattr.va_vaflags |= VA_UTIMES_NULL; 150958505Sbostic } else if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv))) 151058505Sbostic return (error); 151164410Sbostic NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); 151252322Smckusick if (error = namei(&nd)) 151347540Skarels return (error); 151452322Smckusick vp = nd.ni_vp; 151559382Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 151659382Smckusick VOP_LOCK(vp); 151764410Sbostic if (vp->v_mount->mnt_flag & MNT_RDONLY) 151837741Smckusick error = EROFS; 151964410Sbostic else { 152064410Sbostic vattr.va_atime.ts_sec = tv[0].tv_sec; 152164410Sbostic vattr.va_atime.ts_nsec = tv[0].tv_usec * 1000; 152264410Sbostic vattr.va_mtime.ts_sec = tv[1].tv_sec; 152364410Sbostic vattr.va_mtime.ts_nsec = tv[1].tv_usec * 1000; 152464410Sbostic error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 152521015Smckusick } 152637741Smckusick vput(vp); 152747540Skarels return (error); 152811811Ssam } 152911811Ssam 153064410Sbostic /* 153164410Sbostic * Truncate a file given its path name. 153264410Sbostic */ 153360428Smckusick struct truncate_args { 153464410Sbostic char *path; 153554863Storek int pad; 153654863Storek off_t length; 153754863Storek }; 153853468Smckusick /* ARGSUSED */ 153960414Smckusick truncate(p, uap, retval) 154053468Smckusick struct proc *p; 154160428Smckusick register struct truncate_args *uap; 154253468Smckusick int *retval; 154353468Smckusick { 154437741Smckusick register struct vnode *vp; 154537741Smckusick struct vattr vattr; 154637741Smckusick int error; 154747540Skarels struct nameidata nd; 15487701Ssam 154964410Sbostic NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); 155052322Smckusick if (error = namei(&nd)) 155147540Skarels return (error); 155252322Smckusick vp = nd.ni_vp; 155359382Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 155459382Smckusick VOP_LOCK(vp); 155564410Sbostic if (vp->v_type == VDIR) 155637741Smckusick error = EISDIR; 155764410Sbostic else if ((error = vn_writechk(vp)) == 0 && 155864410Sbostic (error = VOP_ACCESS(vp, VWRITE, p->p_ucred, p)) == 0) { 155964410Sbostic VATTR_NULL(&vattr); 156064410Sbostic vattr.va_size = uap->length; 156164410Sbostic error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 15627701Ssam } 156337741Smckusick vput(vp); 156447540Skarels return (error); 15657701Ssam } 15667701Ssam 156764410Sbostic /* 156864410Sbostic * Truncate a file given a file descriptor. 156964410Sbostic */ 157060428Smckusick struct ftruncate_args { 157154863Storek int fd; 157254863Storek int pad; 157354863Storek off_t length; 157454863Storek }; 157542441Smckusick /* ARGSUSED */ 157660414Smckusick ftruncate(p, uap, retval) 157745914Smckusick struct proc *p; 157860428Smckusick register struct ftruncate_args *uap; 157942441Smckusick int *retval; 158042441Smckusick { 158137741Smckusick struct vattr vattr; 158237741Smckusick struct vnode *vp; 15837701Ssam struct file *fp; 158437741Smckusick int error; 15857701Ssam 158645914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 158747540Skarels return (error); 158837741Smckusick if ((fp->f_flag & FWRITE) == 0) 158947540Skarels return (EINVAL); 159037741Smckusick vp = (struct vnode *)fp->f_data; 159159382Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 159237741Smckusick VOP_LOCK(vp); 159364410Sbostic if (vp->v_type == VDIR) 159437741Smckusick error = EISDIR; 159564410Sbostic else if ((error = vn_writechk(vp)) == 0) { 159664410Sbostic VATTR_NULL(&vattr); 159764410Sbostic vattr.va_size = uap->length; 159864410Sbostic error = VOP_SETATTR(vp, &vattr, fp->f_cred, p); 15997701Ssam } 160037741Smckusick VOP_UNLOCK(vp); 160147540Skarels return (error); 16027701Ssam } 16037701Ssam 160454863Storek #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 16059167Ssam /* 160654863Storek * Truncate a file given its path name. 160754863Storek */ 160860428Smckusick struct otruncate_args { 160964410Sbostic char *path; 161054916Storek long length; 161154916Storek }; 161254863Storek /* ARGSUSED */ 161360105Smckusick otruncate(p, uap, retval) 161454863Storek struct proc *p; 161560428Smckusick register struct otruncate_args *uap; 161654863Storek int *retval; 161754863Storek { 161860428Smckusick struct truncate_args nuap; 161954863Storek 162064410Sbostic nuap.path = uap->path; 162154863Storek nuap.length = uap->length; 162260428Smckusick return (truncate(p, &nuap, retval)); 162354863Storek } 162454863Storek 162554863Storek /* 162654863Storek * Truncate a file given a file descriptor. 162754863Storek */ 162860428Smckusick struct oftruncate_args { 162954916Storek int fd; 163054916Storek long length; 163154916Storek }; 163254863Storek /* ARGSUSED */ 163360105Smckusick oftruncate(p, uap, retval) 163454863Storek struct proc *p; 163560428Smckusick register struct oftruncate_args *uap; 163654863Storek int *retval; 163754863Storek { 163860428Smckusick struct ftruncate_args nuap; 163954863Storek 164054863Storek nuap.fd = uap->fd; 164154863Storek nuap.length = uap->length; 164260428Smckusick return (ftruncate(p, &nuap, retval)); 164354863Storek } 164454863Storek #endif /* COMPAT_43 || COMPAT_SUNOS */ 164554863Storek 164654863Storek /* 164764410Sbostic * Sync an open file. 16489167Ssam */ 164954916Storek struct fsync_args { 165054916Storek int fd; 165154916Storek }; 165242441Smckusick /* ARGSUSED */ 165342441Smckusick fsync(p, uap, retval) 165445914Smckusick struct proc *p; 165554916Storek struct fsync_args *uap; 165642441Smckusick int *retval; 16579167Ssam { 165839592Smckusick register struct vnode *vp; 16599167Ssam struct file *fp; 166037741Smckusick int error; 16619167Ssam 166245914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 166347540Skarels return (error); 166439592Smckusick vp = (struct vnode *)fp->f_data; 166539592Smckusick VOP_LOCK(vp); 166654441Smckusick error = VOP_FSYNC(vp, fp->f_cred, MNT_WAIT, p); 166739592Smckusick VOP_UNLOCK(vp); 166847540Skarels return (error); 16699167Ssam } 16709167Ssam 16719167Ssam /* 167264410Sbostic * Rename files. Source and destination must either both be directories, 167364410Sbostic * or both not be directories. If target is a directory, it must be empty. 16749167Ssam */ 167554916Storek struct rename_args { 167654916Storek char *from; 167754916Storek char *to; 167854916Storek }; 167942441Smckusick /* ARGSUSED */ 168042441Smckusick rename(p, uap, retval) 168145914Smckusick struct proc *p; 168254916Storek register struct rename_args *uap; 168342441Smckusick int *retval; 168442441Smckusick { 168537741Smckusick register struct vnode *tvp, *fvp, *tdvp; 168649735Smckusick struct nameidata fromnd, tond; 168737741Smckusick int error; 16887701Ssam 168952322Smckusick NDINIT(&fromnd, DELETE, WANTPARENT | SAVESTART, UIO_USERSPACE, 169052322Smckusick uap->from, p); 169152322Smckusick if (error = namei(&fromnd)) 169247540Skarels return (error); 169349735Smckusick fvp = fromnd.ni_vp; 169452322Smckusick NDINIT(&tond, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART, 169552322Smckusick UIO_USERSPACE, uap->to, p); 169652322Smckusick if (error = namei(&tond)) { 169752230Sheideman VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 169849735Smckusick vrele(fromnd.ni_dvp); 169942465Smckusick vrele(fvp); 170042465Smckusick goto out1; 170142465Smckusick } 170237741Smckusick tdvp = tond.ni_dvp; 170337741Smckusick tvp = tond.ni_vp; 170437741Smckusick if (tvp != NULL) { 170537741Smckusick if (fvp->v_type == VDIR && tvp->v_type != VDIR) { 170639242Sbostic error = ENOTDIR; 170737741Smckusick goto out; 170837741Smckusick } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) { 170939242Sbostic error = EISDIR; 171037741Smckusick goto out; 17119167Ssam } 17129167Ssam } 171339286Smckusick if (fvp == tdvp) 171437741Smckusick error = EINVAL; 171539286Smckusick /* 171649735Smckusick * If source is the same as the destination (that is the 171749735Smckusick * same inode number with the same name in the same directory), 171839286Smckusick * then there is nothing to do. 171939286Smckusick */ 172049735Smckusick if (fvp == tvp && fromnd.ni_dvp == tdvp && 172152322Smckusick fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen && 172252322Smckusick !bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr, 172352322Smckusick fromnd.ni_cnd.cn_namelen)) 172439286Smckusick error = -1; 172537741Smckusick out: 172642465Smckusick if (!error) { 172752192Smckusick LEASE_CHECK(tdvp, p, p->p_ucred, LEASE_WRITE); 172852192Smckusick if (fromnd.ni_dvp != tdvp) 172952192Smckusick LEASE_CHECK(fromnd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 173052192Smckusick if (tvp) 173152192Smckusick LEASE_CHECK(tvp, p, p->p_ucred, LEASE_WRITE); 173252230Sheideman error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd, 173352230Sheideman tond.ni_dvp, tond.ni_vp, &tond.ni_cnd); 173442465Smckusick } else { 173552230Sheideman VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd); 173643344Smckusick if (tdvp == tvp) 173743344Smckusick vrele(tdvp); 173843344Smckusick else 173943344Smckusick vput(tdvp); 174042465Smckusick if (tvp) 174142465Smckusick vput(tvp); 174252230Sheideman VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 174349735Smckusick vrele(fromnd.ni_dvp); 174442465Smckusick vrele(fvp); 17459167Ssam } 174649735Smckusick vrele(tond.ni_startdir); 174752322Smckusick FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI); 174837741Smckusick out1: 174966801Smckusick if (fromnd.ni_startdir) 175066801Smckusick vrele(fromnd.ni_startdir); 175152322Smckusick FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI); 175239286Smckusick if (error == -1) 175347540Skarels return (0); 175447540Skarels return (error); 17557701Ssam } 17567701Ssam 17577535Sroot /* 175864410Sbostic * Make a directory file. 175912756Ssam */ 176054916Storek struct mkdir_args { 176164410Sbostic char *path; 176264410Sbostic int mode; 176354916Storek }; 176442441Smckusick /* ARGSUSED */ 176542441Smckusick mkdir(p, uap, retval) 176645914Smckusick struct proc *p; 176754916Storek register struct mkdir_args *uap; 176842441Smckusick int *retval; 176942441Smckusick { 177037741Smckusick register struct vnode *vp; 177137741Smckusick struct vattr vattr; 177237741Smckusick int error; 177347540Skarels struct nameidata nd; 177412756Ssam 177564410Sbostic NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->path, p); 177652322Smckusick if (error = namei(&nd)) 177747540Skarels return (error); 177852322Smckusick vp = nd.ni_vp; 177937741Smckusick if (vp != NULL) { 178052322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 178152322Smckusick if (nd.ni_dvp == vp) 178252322Smckusick vrele(nd.ni_dvp); 178343344Smckusick else 178452322Smckusick vput(nd.ni_dvp); 178542465Smckusick vrele(vp); 178647540Skarels return (EEXIST); 178712756Ssam } 178841362Smckusick VATTR_NULL(&vattr); 178937741Smckusick vattr.va_type = VDIR; 179064410Sbostic vattr.va_mode = (uap->mode & ACCESSPERMS) &~ p->p_fd->fd_cmask; 179152322Smckusick LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 179252322Smckusick error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr); 179338145Smckusick if (!error) 179452322Smckusick vput(nd.ni_vp); 179547540Skarels return (error); 179612756Ssam } 179712756Ssam 179812756Ssam /* 179964410Sbostic * Remove a directory file. 180012756Ssam */ 180154916Storek struct rmdir_args { 180264410Sbostic char *path; 180354916Storek }; 180442441Smckusick /* ARGSUSED */ 180542441Smckusick rmdir(p, uap, retval) 180645914Smckusick struct proc *p; 180754916Storek struct rmdir_args *uap; 180842441Smckusick int *retval; 180912756Ssam { 181037741Smckusick register struct vnode *vp; 181137741Smckusick int error; 181247540Skarels struct nameidata nd; 181312756Ssam 181464410Sbostic NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE, uap->path, p); 181552322Smckusick if (error = namei(&nd)) 181647540Skarels return (error); 181752322Smckusick vp = nd.ni_vp; 181837741Smckusick if (vp->v_type != VDIR) { 181937741Smckusick error = ENOTDIR; 182012756Ssam goto out; 182112756Ssam } 182212756Ssam /* 182337741Smckusick * No rmdir "." please. 182412756Ssam */ 182552322Smckusick if (nd.ni_dvp == vp) { 182637741Smckusick error = EINVAL; 182712756Ssam goto out; 182812756Ssam } 182912756Ssam /* 183049365Smckusick * The root of a mounted filesystem cannot be deleted. 183112756Ssam */ 183237741Smckusick if (vp->v_flag & VROOT) 183337741Smckusick error = EBUSY; 183412756Ssam out: 183542465Smckusick if (!error) { 183652322Smckusick LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 183752192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 183852322Smckusick error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); 183942465Smckusick } else { 184052322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 184152322Smckusick if (nd.ni_dvp == vp) 184252322Smckusick vrele(nd.ni_dvp); 184343344Smckusick else 184452322Smckusick vput(nd.ni_dvp); 184542465Smckusick vput(vp); 184642465Smckusick } 184747540Skarels return (error); 184812756Ssam } 184912756Ssam 185054620Smckusick #ifdef COMPAT_43 185137741Smckusick /* 185249365Smckusick * Read a block of directory entries in a file system independent format. 185337741Smckusick */ 185454916Storek struct ogetdirentries_args { 185554916Storek int fd; 185654916Storek char *buf; 185764410Sbostic u_int count; 185854916Storek long *basep; 185954916Storek }; 186054620Smckusick ogetdirentries(p, uap, retval) 186154620Smckusick struct proc *p; 186254916Storek register struct ogetdirentries_args *uap; 186354620Smckusick int *retval; 186454620Smckusick { 186554620Smckusick register struct vnode *vp; 186654620Smckusick struct file *fp; 186754620Smckusick struct uio auio, kuio; 186854620Smckusick struct iovec aiov, kiov; 186954620Smckusick struct dirent *dp, *edp; 187054620Smckusick caddr_t dirbuf; 187167362Smckusick int error, eofflag, readcnt; 187254969Smckusick long loff; 187354620Smckusick 187454620Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 187554620Smckusick return (error); 187654620Smckusick if ((fp->f_flag & FREAD) == 0) 187754620Smckusick return (EBADF); 187854620Smckusick vp = (struct vnode *)fp->f_data; 187967362Smckusick unionread: 188054620Smckusick if (vp->v_type != VDIR) 188154620Smckusick return (EINVAL); 188254620Smckusick aiov.iov_base = uap->buf; 188354620Smckusick aiov.iov_len = uap->count; 188454620Smckusick auio.uio_iov = &aiov; 188554620Smckusick auio.uio_iovcnt = 1; 188654620Smckusick auio.uio_rw = UIO_READ; 188754620Smckusick auio.uio_segflg = UIO_USERSPACE; 188854620Smckusick auio.uio_procp = p; 188954620Smckusick auio.uio_resid = uap->count; 189054620Smckusick VOP_LOCK(vp); 189154969Smckusick loff = auio.uio_offset = fp->f_offset; 189254620Smckusick # if (BYTE_ORDER != LITTLE_ENDIAN) 189356339Smckusick if (vp->v_mount->mnt_maxsymlinklen <= 0) { 189467362Smckusick error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, 189567362Smckusick (u_long *)0, 0); 189656339Smckusick fp->f_offset = auio.uio_offset; 189756339Smckusick } else 189854620Smckusick # endif 189954620Smckusick { 190054620Smckusick kuio = auio; 190154620Smckusick kuio.uio_iov = &kiov; 190254620Smckusick kuio.uio_segflg = UIO_SYSSPACE; 190354620Smckusick kiov.iov_len = uap->count; 190454620Smckusick MALLOC(dirbuf, caddr_t, uap->count, M_TEMP, M_WAITOK); 190554620Smckusick kiov.iov_base = dirbuf; 190667362Smckusick error = VOP_READDIR(vp, &kuio, fp->f_cred, &eofflag, 190767362Smckusick (u_long *)0, 0); 190856339Smckusick fp->f_offset = kuio.uio_offset; 190954620Smckusick if (error == 0) { 191054620Smckusick readcnt = uap->count - kuio.uio_resid; 191154620Smckusick edp = (struct dirent *)&dirbuf[readcnt]; 191254620Smckusick for (dp = (struct dirent *)dirbuf; dp < edp; ) { 191354620Smckusick # if (BYTE_ORDER == LITTLE_ENDIAN) 191454969Smckusick /* 191555009Smckusick * The expected low byte of 191655009Smckusick * dp->d_namlen is our dp->d_type. 191755009Smckusick * The high MBZ byte of dp->d_namlen 191855009Smckusick * is our dp->d_namlen. 191954969Smckusick */ 192055009Smckusick dp->d_type = dp->d_namlen; 192155009Smckusick dp->d_namlen = 0; 192255009Smckusick # else 192355009Smckusick /* 192455009Smckusick * The dp->d_type is the high byte 192555009Smckusick * of the expected dp->d_namlen, 192655009Smckusick * so must be zero'ed. 192755009Smckusick */ 192855009Smckusick dp->d_type = 0; 192954620Smckusick # endif 193054620Smckusick if (dp->d_reclen > 0) { 193154620Smckusick dp = (struct dirent *) 193254620Smckusick ((char *)dp + dp->d_reclen); 193354620Smckusick } else { 193454620Smckusick error = EIO; 193554620Smckusick break; 193654620Smckusick } 193754620Smckusick } 193854620Smckusick if (dp >= edp) 193954620Smckusick error = uiomove(dirbuf, readcnt, &auio); 194054620Smckusick } 194154620Smckusick FREE(dirbuf, M_TEMP); 194254620Smckusick } 194354620Smckusick VOP_UNLOCK(vp); 194454620Smckusick if (error) 194554620Smckusick return (error); 194667362Smckusick 194767362Smckusick #ifdef UNION 194867362Smckusick { 194967362Smckusick extern int (**union_vnodeop_p)(); 195067362Smckusick extern struct vnode *union_lowervp __P((struct vnode *)); 195167362Smckusick 195267362Smckusick if ((uap->count == auio.uio_resid) && 195367362Smckusick (vp->v_op == union_vnodeop_p)) { 195467362Smckusick struct vnode *lvp; 195567362Smckusick 195667362Smckusick lvp = union_lowervp(vp); 195767362Smckusick if (lvp != NULLVP) { 195867362Smckusick VOP_LOCK(lvp); 195967362Smckusick error = VOP_OPEN(lvp, FREAD, fp->f_cred, p); 196067362Smckusick VOP_UNLOCK(lvp); 196167362Smckusick 196267362Smckusick if (error) { 196367362Smckusick vrele(lvp); 196467362Smckusick return (error); 196567362Smckusick } 196667362Smckusick fp->f_data = (caddr_t) lvp; 196767362Smckusick fp->f_offset = 0; 196867362Smckusick error = vn_close(vp, FREAD, fp->f_cred, p); 196967362Smckusick if (error) 197067362Smckusick return (error); 197167362Smckusick vp = lvp; 197267362Smckusick goto unionread; 197367362Smckusick } 197467362Smckusick } 197567362Smckusick } 197667362Smckusick #endif /* UNION */ 197767362Smckusick 197867362Smckusick if ((uap->count == auio.uio_resid) && 197967362Smckusick (vp->v_flag & VROOT) && 198067362Smckusick (vp->v_mount->mnt_flag & MNT_UNION)) { 198167362Smckusick struct vnode *tvp = vp; 198267362Smckusick vp = vp->v_mount->mnt_vnodecovered; 198367362Smckusick VREF(vp); 198467362Smckusick fp->f_data = (caddr_t) vp; 198567362Smckusick fp->f_offset = 0; 198667362Smckusick vrele(tvp); 198767362Smckusick goto unionread; 198867362Smckusick } 198954969Smckusick error = copyout((caddr_t)&loff, (caddr_t)uap->basep, sizeof(long)); 199054620Smckusick *retval = uap->count - auio.uio_resid; 199154620Smckusick return (error); 199254620Smckusick } 199367362Smckusick #endif /* COMPAT_43 */ 199454620Smckusick 199554620Smckusick /* 199654620Smckusick * Read a block of directory entries in a file system independent format. 199754620Smckusick */ 199854916Storek struct getdirentries_args { 199954916Storek int fd; 200054916Storek char *buf; 200164410Sbostic u_int count; 200254916Storek long *basep; 200354916Storek }; 200442441Smckusick getdirentries(p, uap, retval) 200545914Smckusick struct proc *p; 200654916Storek register struct getdirentries_args *uap; 200742441Smckusick int *retval; 200842441Smckusick { 200939592Smckusick register struct vnode *vp; 201016540Ssam struct file *fp; 201137741Smckusick struct uio auio; 201237741Smckusick struct iovec aiov; 201354969Smckusick long loff; 201467362Smckusick int error, eofflag; 201512756Ssam 201645914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 201747540Skarels return (error); 201837741Smckusick if ((fp->f_flag & FREAD) == 0) 201947540Skarels return (EBADF); 202039592Smckusick vp = (struct vnode *)fp->f_data; 202155451Spendry unionread: 202239592Smckusick if (vp->v_type != VDIR) 202347540Skarels return (EINVAL); 202437741Smckusick aiov.iov_base = uap->buf; 202537741Smckusick aiov.iov_len = uap->count; 202637741Smckusick auio.uio_iov = &aiov; 202737741Smckusick auio.uio_iovcnt = 1; 202837741Smckusick auio.uio_rw = UIO_READ; 202937741Smckusick auio.uio_segflg = UIO_USERSPACE; 203048026Smckusick auio.uio_procp = p; 203137741Smckusick auio.uio_resid = uap->count; 203239592Smckusick VOP_LOCK(vp); 203354969Smckusick loff = auio.uio_offset = fp->f_offset; 203467362Smckusick error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, (u_long *)0, 0); 203539592Smckusick fp->f_offset = auio.uio_offset; 203639592Smckusick VOP_UNLOCK(vp); 203739592Smckusick if (error) 203847540Skarels return (error); 203966095Spendry 204066095Spendry #ifdef UNION 204166095Spendry { 204266095Spendry extern int (**union_vnodeop_p)(); 204366095Spendry extern struct vnode *union_lowervp __P((struct vnode *)); 204466095Spendry 204555451Spendry if ((uap->count == auio.uio_resid) && 204666095Spendry (vp->v_op == union_vnodeop_p)) { 204767122Spendry struct vnode *lvp; 204866095Spendry 204967122Spendry lvp = union_lowervp(vp); 205067122Spendry if (lvp != NULLVP) { 205167122Spendry VOP_LOCK(lvp); 205267362Smckusick error = VOP_OPEN(lvp, FREAD, fp->f_cred, p); 205367122Spendry VOP_UNLOCK(lvp); 205466095Spendry 205566095Spendry if (error) { 205667122Spendry vrele(lvp); 205766095Spendry return (error); 205866095Spendry } 205967122Spendry fp->f_data = (caddr_t) lvp; 206066095Spendry fp->f_offset = 0; 206167122Spendry error = vn_close(vp, FREAD, fp->f_cred, p); 206266095Spendry if (error) 206366095Spendry return (error); 206467122Spendry vp = lvp; 206566095Spendry goto unionread; 206666095Spendry } 206766095Spendry } 206866095Spendry } 206966095Spendry #endif 207066095Spendry 207166095Spendry if ((uap->count == auio.uio_resid) && 207255451Spendry (vp->v_flag & VROOT) && 207355451Spendry (vp->v_mount->mnt_flag & MNT_UNION)) { 207455451Spendry struct vnode *tvp = vp; 207555451Spendry vp = vp->v_mount->mnt_vnodecovered; 207655451Spendry VREF(vp); 207755451Spendry fp->f_data = (caddr_t) vp; 207855451Spendry fp->f_offset = 0; 207955451Spendry vrele(tvp); 208055451Spendry goto unionread; 208155451Spendry } 208254969Smckusick error = copyout((caddr_t)&loff, (caddr_t)uap->basep, sizeof(long)); 208342441Smckusick *retval = uap->count - auio.uio_resid; 208447540Skarels return (error); 208512756Ssam } 208612756Ssam 208712756Ssam /* 208849365Smckusick * Set the mode mask for creation of filesystem nodes. 208912756Ssam */ 209054916Storek struct umask_args { 209164410Sbostic int newmask; 209254916Storek }; 209354916Storek mode_t /* XXX */ 209442441Smckusick umask(p, uap, retval) 209545914Smckusick struct proc *p; 209654916Storek struct umask_args *uap; 209742441Smckusick int *retval; 209812756Ssam { 209964410Sbostic register struct filedesc *fdp; 210012756Ssam 210164410Sbostic fdp = p->p_fd; 210245914Smckusick *retval = fdp->fd_cmask; 210364410Sbostic fdp->fd_cmask = uap->newmask & ALLPERMS; 210447540Skarels return (0); 210512756Ssam } 210637741Smckusick 210739566Smarc /* 210839566Smarc * Void all references to file by ripping underlying filesystem 210939566Smarc * away from vnode. 211039566Smarc */ 211154916Storek struct revoke_args { 211264410Sbostic char *path; 211354916Storek }; 211442441Smckusick /* ARGSUSED */ 211542441Smckusick revoke(p, uap, retval) 211645914Smckusick struct proc *p; 211754916Storek register struct revoke_args *uap; 211842441Smckusick int *retval; 211942441Smckusick { 212039566Smarc register struct vnode *vp; 212139566Smarc struct vattr vattr; 212239566Smarc int error; 212347540Skarels struct nameidata nd; 212439566Smarc 212564410Sbostic NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); 212652322Smckusick if (error = namei(&nd)) 212747540Skarels return (error); 212852322Smckusick vp = nd.ni_vp; 212939566Smarc if (vp->v_type != VCHR && vp->v_type != VBLK) { 213039566Smarc error = EINVAL; 213139566Smarc goto out; 213239566Smarc } 213348026Smckusick if (error = VOP_GETATTR(vp, &vattr, p->p_ucred, p)) 213439566Smarc goto out; 213547540Skarels if (p->p_ucred->cr_uid != vattr.va_uid && 213647540Skarels (error = suser(p->p_ucred, &p->p_acflag))) 213739566Smarc goto out; 213839805Smckusick if (vp->v_usecount > 1 || (vp->v_flag & VALIASED)) 213939632Smckusick vgoneall(vp); 214039566Smarc out: 214139566Smarc vrele(vp); 214247540Skarels return (error); 214339566Smarc } 214439566Smarc 214549365Smckusick /* 214649365Smckusick * Convert a user file descriptor to a kernel file entry. 214749365Smckusick */ 214864410Sbostic getvnode(fdp, fd, fpp) 214945914Smckusick struct filedesc *fdp; 215037741Smckusick struct file **fpp; 215164410Sbostic int fd; 215237741Smckusick { 215337741Smckusick struct file *fp; 215437741Smckusick 215564410Sbostic if ((u_int)fd >= fdp->fd_nfiles || 215664410Sbostic (fp = fdp->fd_ofiles[fd]) == NULL) 215737741Smckusick return (EBADF); 215837741Smckusick if (fp->f_type != DTYPE_VNODE) 215937741Smckusick return (EINVAL); 216037741Smckusick *fpp = fp; 216137741Smckusick return (0); 216237741Smckusick } 2163