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*67532Smckusick * @(#)vfs_syscalls.c 8.18 (Berkeley) 07/14/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; 56*67532Smckusick struct vattr va; 5747540Skarels struct nameidata nd; 586254Sroot 5937741Smckusick /* 6037741Smckusick * Get vnode to be covered 6137741Smckusick */ 6264410Sbostic NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); 6352322Smckusick if (error = namei(&nd)) 6447540Skarels return (error); 6552322Smckusick vp = nd.ni_vp; 6641400Smckusick if (uap->flags & MNT_UPDATE) { 6739335Smckusick if ((vp->v_flag & VROOT) == 0) { 6839335Smckusick vput(vp); 6947540Skarels return (EINVAL); 7039335Smckusick } 7139335Smckusick mp = vp->v_mount; 7257047Smckusick flag = mp->mnt_flag; 7339335Smckusick /* 7457047Smckusick * We only allow the filesystem to be reloaded if it 7557047Smckusick * is currently mounted read-only. 7639335Smckusick */ 7757047Smckusick if ((uap->flags & MNT_RELOAD) && 7857047Smckusick ((mp->mnt_flag & MNT_RDONLY) == 0)) { 7939335Smckusick vput(vp); 8047540Skarels return (EOPNOTSUPP); /* Needs translation */ 8139335Smckusick } 8257047Smckusick mp->mnt_flag |= 8357047Smckusick uap->flags & (MNT_RELOAD | MNT_FORCE | MNT_UPDATE); 84*67532Smckusick /* 85*67532Smckusick * Only root, or the user that did the original mount is 86*67532Smckusick * permitted to update it. 87*67532Smckusick */ 88*67532Smckusick if (mp->mnt_stat.f_owner != p->p_ucred->cr_uid && 89*67532Smckusick (error = suser(p->p_ucred, &p->p_acflag))) { 90*67532Smckusick vput(vp); 91*67532Smckusick return (error); 92*67532Smckusick } 93*67532Smckusick /* 94*67532Smckusick * Do not allow NFS export by non-root users. Silently 95*67532Smckusick * enforce MNT_NOSUID and MNT_NODEV for non-root users. 96*67532Smckusick */ 97*67532Smckusick if (p->p_ucred->cr_uid != 0) { 98*67532Smckusick if (uap->flags & MNT_EXPORTED) { 99*67532Smckusick vput(vp); 100*67532Smckusick return (EPERM); 101*67532Smckusick } 102*67532Smckusick uap->flags |= MNT_NOSUID | MNT_NODEV; 103*67532Smckusick } 10439335Smckusick VOP_UNLOCK(vp); 10539335Smckusick goto update; 10639335Smckusick } 107*67532Smckusick /* 108*67532Smckusick * If the user is not root, ensure that they own the directory 109*67532Smckusick * onto which we are attempting to mount. 110*67532Smckusick */ 111*67532Smckusick if ((error = VOP_GETATTR(vp, &va, p->p_ucred, p)) || 112*67532Smckusick (va.va_uid != p->p_ucred->cr_uid && 113*67532Smckusick (error = suser(p->p_ucred, &p->p_acflag)))) { 114*67532Smckusick vput(vp); 115*67532Smckusick return (error); 116*67532Smckusick } 117*67532Smckusick /* 118*67532Smckusick * Do not allow NFS export by non-root users. Silently 119*67532Smckusick * enforce MNT_NOSUID and MNT_NODEV for non-root users. 120*67532Smckusick */ 121*67532Smckusick if (p->p_ucred->cr_uid != 0) { 122*67532Smckusick if (uap->flags & MNT_EXPORTED) { 123*67532Smckusick vput(vp); 124*67532Smckusick return (EPERM); 125*67532Smckusick } 126*67532Smckusick uap->flags |= MNT_NOSUID | MNT_NODEV; 127*67532Smckusick } 12857793Smckusick if (error = vinvalbuf(vp, V_SAVE, p->p_ucred, p, 0, 0)) 12954441Smckusick return (error); 13037741Smckusick if (vp->v_type != VDIR) { 13137741Smckusick vput(vp); 13247540Skarels return (ENOTDIR); 13337741Smckusick } 13464410Sbostic if ((u_long)uap->type > MOUNT_MAXTYPE || vfssw[uap->type] == NULL) { 13537741Smckusick vput(vp); 13647540Skarels return (ENODEV); 13737741Smckusick } 13837741Smckusick 13937741Smckusick /* 14039335Smckusick * Allocate and initialize the file system. 14137741Smckusick */ 14237741Smckusick mp = (struct mount *)malloc((u_long)sizeof(struct mount), 14337741Smckusick M_MOUNT, M_WAITOK); 14454172Smckusick bzero((char *)mp, (u_long)sizeof(struct mount)); 14541400Smckusick mp->mnt_op = vfssw[uap->type]; 14639335Smckusick if (error = vfs_lock(mp)) { 14739335Smckusick free((caddr_t)mp, M_MOUNT); 14839335Smckusick vput(vp); 14947540Skarels return (error); 15039335Smckusick } 15164410Sbostic if (vp->v_mountedhere != NULL) { 15239335Smckusick vfs_unlock(mp); 15339335Smckusick free((caddr_t)mp, M_MOUNT); 15439335Smckusick vput(vp); 15547540Skarels return (EBUSY); 15639335Smckusick } 15739335Smckusick vp->v_mountedhere = mp; 15841400Smckusick mp->mnt_vnodecovered = vp; 159*67532Smckusick mp->mnt_stat.f_owner = p->p_ucred->cr_uid; 16039335Smckusick update: 16139335Smckusick /* 16239335Smckusick * Set the mount level flags. 16339335Smckusick */ 16441400Smckusick if (uap->flags & MNT_RDONLY) 16541400Smckusick mp->mnt_flag |= MNT_RDONLY; 16657047Smckusick else if (mp->mnt_flag & MNT_RDONLY) 16757047Smckusick mp->mnt_flag |= MNT_WANTRDWR; 16865613Smckusick mp->mnt_flag &=~ (MNT_NOSUID | MNT_NOEXEC | MNT_NODEV | 16965613Smckusick MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC); 17065613Smckusick mp->mnt_flag |= uap->flags & (MNT_NOSUID | MNT_NOEXEC | MNT_NODEV | 17165613Smckusick MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC); 17239335Smckusick /* 17339335Smckusick * Mount the filesystem. 17439335Smckusick */ 17564410Sbostic error = VFS_MOUNT(mp, uap->path, uap->data, &nd, p); 17641400Smckusick if (mp->mnt_flag & MNT_UPDATE) { 17739335Smckusick vrele(vp); 17857047Smckusick if (mp->mnt_flag & MNT_WANTRDWR) 17957047Smckusick mp->mnt_flag &= ~MNT_RDONLY; 18057047Smckusick mp->mnt_flag &=~ 18157047Smckusick (MNT_UPDATE | MNT_RELOAD | MNT_FORCE | MNT_WANTRDWR); 18240111Smckusick if (error) 18341400Smckusick mp->mnt_flag = flag; 18447540Skarels return (error); 18539335Smckusick } 18640110Smckusick /* 18740110Smckusick * Put the new filesystem on the mount list after root. 18840110Smckusick */ 18937741Smckusick cache_purge(vp); 19037741Smckusick if (!error) { 19165259Smckusick TAILQ_INSERT_TAIL(&mountlist, mp, mnt_list); 19239335Smckusick VOP_UNLOCK(vp); 19337741Smckusick vfs_unlock(mp); 19448026Smckusick error = VFS_START(mp, 0, p); 19537741Smckusick } else { 19665259Smckusick mp->mnt_vnodecovered->v_mountedhere = (struct mount *)0; 19765259Smckusick vfs_unlock(mp); 19837741Smckusick free((caddr_t)mp, M_MOUNT); 19939335Smckusick vput(vp); 20037741Smckusick } 20147540Skarels return (error); 2026254Sroot } 2036254Sroot 2049167Ssam /* 20564410Sbostic * Unmount a file system. 20637741Smckusick * 20737741Smckusick * Note: unmount takes a path to the vnode mounted on as argument, 20837741Smckusick * not special file (as before). 2099167Ssam */ 21054916Storek struct unmount_args { 21164410Sbostic char *path; 21254916Storek int flags; 21354916Storek }; 21442441Smckusick /* ARGSUSED */ 21542441Smckusick unmount(p, uap, retval) 21645914Smckusick struct proc *p; 21754916Storek register struct unmount_args *uap; 21842441Smckusick int *retval; 21942441Smckusick { 22037741Smckusick register struct vnode *vp; 22139356Smckusick struct mount *mp; 22237741Smckusick int error; 22347540Skarels struct nameidata nd; 2246254Sroot 22564410Sbostic NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); 22652322Smckusick if (error = namei(&nd)) 22747540Skarels return (error); 22852322Smckusick vp = nd.ni_vp; 229*67532Smckusick mp = vp->v_mount; 23066172Spendry 23137741Smckusick /* 232*67532Smckusick * Only root, or the user that did the original mount is 233*67532Smckusick * permitted to unmount this filesystem. 23466172Spendry */ 235*67532Smckusick if ((mp->mnt_stat.f_owner != p->p_ucred->cr_uid) && 23666172Spendry (error = suser(p->p_ucred, &p->p_acflag))) { 23766172Spendry vput(vp); 23866172Spendry return (error); 23966172Spendry } 24066172Spendry 24166172Spendry /* 24237741Smckusick * Must be the root of the filesystem 24337741Smckusick */ 24437741Smckusick if ((vp->v_flag & VROOT) == 0) { 24537741Smckusick vput(vp); 24647540Skarels return (EINVAL); 24737741Smckusick } 24837741Smckusick vput(vp); 24948026Smckusick return (dounmount(mp, uap->flags, p)); 25039356Smckusick } 25139356Smckusick 25239356Smckusick /* 25364410Sbostic * Do the actual file system unmount. 25439356Smckusick */ 25548026Smckusick dounmount(mp, flags, p) 25639356Smckusick register struct mount *mp; 25739356Smckusick int flags; 25848026Smckusick struct proc *p; 25939356Smckusick { 26039356Smckusick struct vnode *coveredvp; 26139356Smckusick int error; 26239356Smckusick 26341400Smckusick coveredvp = mp->mnt_vnodecovered; 26441298Smckusick if (vfs_busy(mp)) 26541298Smckusick return (EBUSY); 26641400Smckusick mp->mnt_flag |= MNT_UNMOUNT; 26737741Smckusick if (error = vfs_lock(mp)) 26839356Smckusick return (error); 26937741Smckusick 27065859Smckusick mp->mnt_flag &=~ MNT_ASYNC; 27145738Smckusick vnode_pager_umount(mp); /* release cached vnodes */ 27237741Smckusick cache_purgevfs(mp); /* remove cache entries for this file sys */ 27354441Smckusick if ((error = VFS_SYNC(mp, MNT_WAIT, p->p_ucred, p)) == 0 || 27454441Smckusick (flags & MNT_FORCE)) 27548026Smckusick error = VFS_UNMOUNT(mp, flags, p); 27641400Smckusick mp->mnt_flag &= ~MNT_UNMOUNT; 27741298Smckusick vfs_unbusy(mp); 27837741Smckusick if (error) { 27937741Smckusick vfs_unlock(mp); 28037741Smckusick } else { 28137741Smckusick vrele(coveredvp); 28265259Smckusick TAILQ_REMOVE(&mountlist, mp, mnt_list); 28365259Smckusick mp->mnt_vnodecovered->v_mountedhere = (struct mount *)0; 28465259Smckusick vfs_unlock(mp); 28565259Smckusick if (mp->mnt_vnodelist.lh_first != NULL) 28652287Smckusick panic("unmount: dangling vnode"); 28737741Smckusick free((caddr_t)mp, M_MOUNT); 28837741Smckusick } 28939356Smckusick return (error); 2906254Sroot } 2916254Sroot 2929167Ssam /* 29337741Smckusick * Sync each mounted filesystem. 2949167Ssam */ 29567403Smckusick #ifdef DEBUG 29656352Smckusick int syncprt = 0; 29759875Smckusick struct ctldebug debug0 = { "syncprt", &syncprt }; 29856352Smckusick #endif 29956352Smckusick 30054916Storek struct sync_args { 30154916Storek int dummy; 30254916Storek }; 30339491Smckusick /* ARGSUSED */ 30442441Smckusick sync(p, uap, retval) 30545914Smckusick struct proc *p; 30654916Storek struct sync_args *uap; 30742441Smckusick int *retval; 3086254Sroot { 30965259Smckusick register struct mount *mp, *nmp; 31065859Smckusick int asyncflag; 31137741Smckusick 31265259Smckusick for (mp = mountlist.tqh_first; mp != NULL; mp = nmp) { 31365259Smckusick nmp = mp->mnt_list.tqe_next; 31440343Smckusick /* 31540343Smckusick * The lock check below is to avoid races with mount 31640343Smckusick * and unmount. 31740343Smckusick */ 31841400Smckusick if ((mp->mnt_flag & (MNT_MLOCK|MNT_RDONLY|MNT_MPBUSY)) == 0 && 31941298Smckusick !vfs_busy(mp)) { 32065859Smckusick asyncflag = mp->mnt_flag & MNT_ASYNC; 32165859Smckusick mp->mnt_flag &= ~MNT_ASYNC; 32254441Smckusick VFS_SYNC(mp, MNT_NOWAIT, p->p_ucred, p); 32365859Smckusick if (asyncflag) 32465859Smckusick mp->mnt_flag |= MNT_ASYNC; 32565259Smckusick vfs_unbusy(mp); 32665259Smckusick } 32765259Smckusick } 32856352Smckusick #ifdef DIAGNOSTIC 32956352Smckusick if (syncprt) 33056352Smckusick vfs_bufstats(); 33156352Smckusick #endif /* DIAGNOSTIC */ 33247688Skarels return (0); 33337741Smckusick } 33437741Smckusick 33537741Smckusick /* 33664410Sbostic * Change filesystem quotas. 33741298Smckusick */ 33854916Storek struct quotactl_args { 33954916Storek char *path; 34054916Storek int cmd; 34154916Storek int uid; 34254916Storek caddr_t arg; 34354916Storek }; 34442441Smckusick /* ARGSUSED */ 34542441Smckusick quotactl(p, uap, retval) 34645914Smckusick struct proc *p; 34754916Storek register struct quotactl_args *uap; 34842441Smckusick int *retval; 34942441Smckusick { 35041298Smckusick register struct mount *mp; 35141298Smckusick int error; 35247540Skarels struct nameidata nd; 35341298Smckusick 35452322Smckusick NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); 35552322Smckusick if (error = namei(&nd)) 35647540Skarels return (error); 35752322Smckusick mp = nd.ni_vp->v_mount; 35852322Smckusick vrele(nd.ni_vp); 35948026Smckusick return (VFS_QUOTACTL(mp, uap->cmd, uap->uid, uap->arg, p)); 36041298Smckusick } 36141298Smckusick 36241298Smckusick /* 36349365Smckusick * Get filesystem statistics. 36437741Smckusick */ 36554916Storek struct statfs_args { 36654916Storek char *path; 36754916Storek struct statfs *buf; 36854916Storek }; 36942441Smckusick /* ARGSUSED */ 37042441Smckusick statfs(p, uap, retval) 37145914Smckusick struct proc *p; 37254916Storek register struct statfs_args *uap; 37342441Smckusick int *retval; 37442441Smckusick { 37539464Smckusick register struct mount *mp; 37640343Smckusick register struct statfs *sp; 37737741Smckusick int error; 37847540Skarels struct nameidata nd; 37937741Smckusick 38052322Smckusick NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); 38152322Smckusick if (error = namei(&nd)) 38247540Skarels return (error); 38352322Smckusick mp = nd.ni_vp->v_mount; 38441400Smckusick sp = &mp->mnt_stat; 38552322Smckusick vrele(nd.ni_vp); 38648026Smckusick if (error = VFS_STATFS(mp, sp, p)) 38747540Skarels return (error); 38841400Smckusick sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 38947540Skarels return (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp))); 39037741Smckusick } 39137741Smckusick 39242441Smckusick /* 39349365Smckusick * Get filesystem statistics. 39442441Smckusick */ 39554916Storek struct fstatfs_args { 39654916Storek int fd; 39754916Storek struct statfs *buf; 39854916Storek }; 39942441Smckusick /* ARGSUSED */ 40042441Smckusick fstatfs(p, uap, retval) 40145914Smckusick struct proc *p; 40254916Storek register struct fstatfs_args *uap; 40342441Smckusick int *retval; 40442441Smckusick { 40537741Smckusick struct file *fp; 40639464Smckusick struct mount *mp; 40740343Smckusick register struct statfs *sp; 40837741Smckusick int error; 40937741Smckusick 41045914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 41147540Skarels return (error); 41239464Smckusick mp = ((struct vnode *)fp->f_data)->v_mount; 41341400Smckusick sp = &mp->mnt_stat; 41448026Smckusick if (error = VFS_STATFS(mp, sp, p)) 41547540Skarels return (error); 41641400Smckusick sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 41747540Skarels return (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp))); 41837741Smckusick } 41937741Smckusick 42037741Smckusick /* 42149365Smckusick * Get statistics on all filesystems. 42238270Smckusick */ 42354916Storek struct getfsstat_args { 42454916Storek struct statfs *buf; 42554916Storek long bufsize; 42654916Storek int flags; 42754916Storek }; 42842441Smckusick getfsstat(p, uap, retval) 42945914Smckusick struct proc *p; 43054916Storek register struct getfsstat_args *uap; 43142441Smckusick int *retval; 43242441Smckusick { 43365259Smckusick register struct mount *mp, *nmp; 43440343Smckusick register struct statfs *sp; 43539606Smckusick caddr_t sfsp; 43638270Smckusick long count, maxcount, error; 43738270Smckusick 43838270Smckusick maxcount = uap->bufsize / sizeof(struct statfs); 43939606Smckusick sfsp = (caddr_t)uap->buf; 44065259Smckusick for (count = 0, mp = mountlist.tqh_first; mp != NULL; mp = nmp) { 44165259Smckusick nmp = mp->mnt_list.tqe_next; 44241400Smckusick if (sfsp && count < maxcount && 44341400Smckusick ((mp->mnt_flag & MNT_MLOCK) == 0)) { 44441400Smckusick sp = &mp->mnt_stat; 44540343Smckusick /* 44640343Smckusick * If MNT_NOWAIT is specified, do not refresh the 44740343Smckusick * fsstat cache. MNT_WAIT overrides MNT_NOWAIT. 44840343Smckusick */ 44940343Smckusick if (((uap->flags & MNT_NOWAIT) == 0 || 45040343Smckusick (uap->flags & MNT_WAIT)) && 45165259Smckusick (error = VFS_STATFS(mp, sp, p))) 45239607Smckusick continue; 45341400Smckusick sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 45440343Smckusick if (error = copyout((caddr_t)sp, sfsp, sizeof(*sp))) 45547540Skarels return (error); 45640343Smckusick sfsp += sizeof(*sp); 45738270Smckusick } 45839606Smckusick count++; 45965259Smckusick } 46038270Smckusick if (sfsp && count > maxcount) 46142441Smckusick *retval = maxcount; 46238270Smckusick else 46342441Smckusick *retval = count; 46447540Skarels return (0); 46538270Smckusick } 46638270Smckusick 46738270Smckusick /* 46838259Smckusick * Change current working directory to a given file descriptor. 46938259Smckusick */ 47054916Storek struct fchdir_args { 47154916Storek int fd; 47254916Storek }; 47342441Smckusick /* ARGSUSED */ 47442441Smckusick fchdir(p, uap, retval) 47545914Smckusick struct proc *p; 47654916Storek struct fchdir_args *uap; 47742441Smckusick int *retval; 47838259Smckusick { 47945914Smckusick register struct filedesc *fdp = p->p_fd; 48038259Smckusick register struct vnode *vp; 48138259Smckusick struct file *fp; 48238259Smckusick int error; 48338259Smckusick 48445914Smckusick if (error = getvnode(fdp, uap->fd, &fp)) 48547540Skarels return (error); 48638259Smckusick vp = (struct vnode *)fp->f_data; 48738259Smckusick VOP_LOCK(vp); 48838259Smckusick if (vp->v_type != VDIR) 48938259Smckusick error = ENOTDIR; 49038259Smckusick else 49148026Smckusick error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p); 49238259Smckusick VOP_UNLOCK(vp); 49339860Smckusick if (error) 49447540Skarels return (error); 49539860Smckusick VREF(vp); 49645914Smckusick vrele(fdp->fd_cdir); 49745914Smckusick fdp->fd_cdir = vp; 49847540Skarels return (0); 49938259Smckusick } 50038259Smckusick 50138259Smckusick /* 50237741Smckusick * Change current working directory (``.''). 50337741Smckusick */ 50454916Storek struct chdir_args { 50564410Sbostic char *path; 50654916Storek }; 50742441Smckusick /* ARGSUSED */ 50842441Smckusick chdir(p, uap, retval) 50945914Smckusick struct proc *p; 51054916Storek struct chdir_args *uap; 51142441Smckusick int *retval; 51237741Smckusick { 51345914Smckusick register struct filedesc *fdp = p->p_fd; 51437741Smckusick int error; 51547540Skarels struct nameidata nd; 5166254Sroot 51764410Sbostic NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); 51864410Sbostic if (error = change_dir(&nd, p)) 51947540Skarels return (error); 52045914Smckusick vrele(fdp->fd_cdir); 52152322Smckusick fdp->fd_cdir = nd.ni_vp; 52247540Skarels return (0); 52337741Smckusick } 5246254Sroot 52537741Smckusick /* 52637741Smckusick * Change notion of root (``/'') directory. 52737741Smckusick */ 52854916Storek struct chroot_args { 52964410Sbostic char *path; 53054916Storek }; 53142441Smckusick /* ARGSUSED */ 53242441Smckusick chroot(p, uap, retval) 53345914Smckusick struct proc *p; 53454916Storek struct chroot_args *uap; 53542441Smckusick int *retval; 53637741Smckusick { 53745914Smckusick register struct filedesc *fdp = p->p_fd; 53837741Smckusick int error; 53947540Skarels struct nameidata nd; 54037741Smckusick 54147540Skarels if (error = suser(p->p_ucred, &p->p_acflag)) 54247540Skarels return (error); 54364410Sbostic NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); 54464410Sbostic if (error = change_dir(&nd, p)) 54547540Skarels return (error); 54645914Smckusick if (fdp->fd_rdir != NULL) 54745914Smckusick vrele(fdp->fd_rdir); 54852322Smckusick fdp->fd_rdir = nd.ni_vp; 54947540Skarels return (0); 5506254Sroot } 5516254Sroot 55237Sbill /* 55337741Smckusick * Common routine for chroot and chdir. 55437741Smckusick */ 55564410Sbostic static int 55664410Sbostic change_dir(ndp, p) 55752322Smckusick register struct nameidata *ndp; 55847540Skarels struct proc *p; 55937741Smckusick { 56037741Smckusick struct vnode *vp; 56137741Smckusick int error; 56237741Smckusick 56352322Smckusick if (error = namei(ndp)) 56437741Smckusick return (error); 56537741Smckusick vp = ndp->ni_vp; 56637741Smckusick if (vp->v_type != VDIR) 56737741Smckusick error = ENOTDIR; 56837741Smckusick else 56948026Smckusick error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p); 57037741Smckusick VOP_UNLOCK(vp); 57137741Smckusick if (error) 57237741Smckusick vrele(vp); 57337741Smckusick return (error); 57437741Smckusick } 57537741Smckusick 57637741Smckusick /* 57742441Smckusick * Check permissions, allocate an open file structure, 57842441Smckusick * and call the device open routine if any. 5796254Sroot */ 58054916Storek struct open_args { 58164410Sbostic char *path; 58264410Sbostic int flags; 58354916Storek int mode; 58454916Storek }; 58542441Smckusick open(p, uap, retval) 58645914Smckusick struct proc *p; 58754916Storek register struct open_args *uap; 58842441Smckusick int *retval; 5896254Sroot { 59045914Smckusick register struct filedesc *fdp = p->p_fd; 59142441Smckusick register struct file *fp; 59250111Smckusick register struct vnode *vp; 59364410Sbostic int flags, cmode; 59437741Smckusick struct file *nfp; 59549945Smckusick int type, indx, error; 59649945Smckusick struct flock lf; 59747540Skarels struct nameidata nd; 59837741Smckusick extern struct fileops vnops; 5996254Sroot 60045914Smckusick if (error = falloc(p, &nfp, &indx)) 60147540Skarels return (error); 60237741Smckusick fp = nfp; 60364410Sbostic flags = FFLAGS(uap->flags); 60464410Sbostic cmode = ((uap->mode &~ fdp->fd_cmask) & ALLPERMS) &~ S_ISTXT; 60564410Sbostic NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); 60645202Smckusick p->p_dupfd = -indx - 1; /* XXX check for fdopen */ 60764410Sbostic if (error = vn_open(&nd, flags, cmode)) { 60849980Smckusick ffree(fp); 60954723Smckusick if ((error == ENODEV || error == ENXIO) && 61054723Smckusick p->p_dupfd >= 0 && /* XXX from fdopen */ 61164410Sbostic (error = 61264410Sbostic dupfdopen(fdp, indx, p->p_dupfd, flags, error)) == 0) { 61342441Smckusick *retval = indx; 61447540Skarels return (0); 61542441Smckusick } 61640884Smckusick if (error == ERESTART) 61740884Smckusick error = EINTR; 61847688Skarels fdp->fd_ofiles[indx] = NULL; 61947540Skarels return (error); 62012756Ssam } 62153828Spendry p->p_dupfd = 0; 62252322Smckusick vp = nd.ni_vp; 62364410Sbostic fp->f_flag = flags & FMASK; 62454348Smckusick fp->f_type = DTYPE_VNODE; 62554348Smckusick fp->f_ops = &vnops; 62654348Smckusick fp->f_data = (caddr_t)vp; 62764410Sbostic if (flags & (O_EXLOCK | O_SHLOCK)) { 62849945Smckusick lf.l_whence = SEEK_SET; 62949945Smckusick lf.l_start = 0; 63049945Smckusick lf.l_len = 0; 63164410Sbostic if (flags & O_EXLOCK) 63249945Smckusick lf.l_type = F_WRLCK; 63349945Smckusick else 63449945Smckusick lf.l_type = F_RDLCK; 63549945Smckusick type = F_FLOCK; 63664410Sbostic if ((flags & FNONBLOCK) == 0) 63749945Smckusick type |= F_WAIT; 63865757Smckusick VOP_UNLOCK(vp); 63950111Smckusick if (error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, type)) { 64050111Smckusick (void) vn_close(vp, fp->f_flag, fp->f_cred, p); 64149980Smckusick ffree(fp); 64249945Smckusick fdp->fd_ofiles[indx] = NULL; 64349945Smckusick return (error); 64449945Smckusick } 64565757Smckusick VOP_LOCK(vp); 64649949Smckusick fp->f_flag |= FHASLOCK; 64749945Smckusick } 64850111Smckusick VOP_UNLOCK(vp); 64942441Smckusick *retval = indx; 65047540Skarels return (0); 6516254Sroot } 6526254Sroot 65342955Smckusick #ifdef COMPAT_43 6546254Sroot /* 65564410Sbostic * Create a file. 6566254Sroot */ 65754916Storek struct ocreat_args { 65864410Sbostic char *path; 65964410Sbostic int mode; 66054916Storek }; 66142955Smckusick ocreat(p, uap, retval) 66242441Smckusick struct proc *p; 66354916Storek register struct ocreat_args *uap; 66442441Smckusick int *retval; 6656254Sroot { 66654916Storek struct open_args openuap; 66742441Smckusick 66864410Sbostic openuap.path = uap->path; 66964410Sbostic openuap.mode = uap->mode; 67064410Sbostic openuap.flags = O_WRONLY | O_CREAT | O_TRUNC; 67147540Skarels return (open(p, &openuap, retval)); 67242441Smckusick } 67342955Smckusick #endif /* COMPAT_43 */ 67442441Smckusick 67542441Smckusick /* 67664410Sbostic * Create a special file. 67742441Smckusick */ 67854916Storek struct mknod_args { 67964410Sbostic char *path; 68064410Sbostic int mode; 68154916Storek int dev; 68254916Storek }; 68342441Smckusick /* ARGSUSED */ 68442441Smckusick mknod(p, uap, retval) 68545914Smckusick struct proc *p; 68654916Storek register struct mknod_args *uap; 68742441Smckusick int *retval; 68842441Smckusick { 68937741Smckusick register struct vnode *vp; 69037741Smckusick struct vattr vattr; 69137741Smckusick int error; 69247540Skarels struct nameidata nd; 6936254Sroot 69447540Skarels if (error = suser(p->p_ucred, &p->p_acflag)) 69547540Skarels return (error); 69664410Sbostic NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->path, p); 69752322Smckusick if (error = namei(&nd)) 69847540Skarels return (error); 69952322Smckusick vp = nd.ni_vp; 70064585Sbostic if (vp != NULL) 70137741Smckusick error = EEXIST; 70264585Sbostic else { 70364585Sbostic VATTR_NULL(&vattr); 70464585Sbostic vattr.va_mode = (uap->mode & ALLPERMS) &~ p->p_fd->fd_cmask; 70564585Sbostic vattr.va_rdev = uap->dev; 70664585Sbostic 70764585Sbostic switch (uap->mode & S_IFMT) { 70864585Sbostic case S_IFMT: /* used by badsect to flag bad sectors */ 70964585Sbostic vattr.va_type = VBAD; 71064585Sbostic break; 71164585Sbostic case S_IFCHR: 71264585Sbostic vattr.va_type = VCHR; 71364585Sbostic break; 71464585Sbostic case S_IFBLK: 71564585Sbostic vattr.va_type = VBLK; 71664585Sbostic break; 71764585Sbostic default: 71864585Sbostic error = EINVAL; 71964585Sbostic break; 72064585Sbostic } 7216254Sroot } 72242465Smckusick if (!error) { 72352322Smckusick LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 72452322Smckusick error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr); 72542465Smckusick } else { 72652322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 72752322Smckusick if (nd.ni_dvp == vp) 72852322Smckusick vrele(nd.ni_dvp); 72943344Smckusick else 73052322Smckusick vput(nd.ni_dvp); 73142465Smckusick if (vp) 73242465Smckusick vrele(vp); 73342465Smckusick } 73447540Skarels return (error); 7356254Sroot } 7366254Sroot 7376254Sroot /* 73864410Sbostic * Create named pipe. 73940285Smckusick */ 74054916Storek struct mkfifo_args { 74164410Sbostic char *path; 74264410Sbostic int mode; 74354916Storek }; 74442441Smckusick /* ARGSUSED */ 74542441Smckusick mkfifo(p, uap, retval) 74645914Smckusick struct proc *p; 74754916Storek register struct mkfifo_args *uap; 74842441Smckusick int *retval; 74942441Smckusick { 75040285Smckusick struct vattr vattr; 75140285Smckusick int error; 75247540Skarels struct nameidata nd; 75340285Smckusick 75440285Smckusick #ifndef FIFO 75547540Skarels return (EOPNOTSUPP); 75640285Smckusick #else 75764410Sbostic NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->path, p); 75852322Smckusick if (error = namei(&nd)) 75947540Skarels return (error); 76052322Smckusick if (nd.ni_vp != NULL) { 76152322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 76252322Smckusick if (nd.ni_dvp == nd.ni_vp) 76352322Smckusick vrele(nd.ni_dvp); 76443344Smckusick else 76552322Smckusick vput(nd.ni_dvp); 76652322Smckusick vrele(nd.ni_vp); 76747540Skarels return (EEXIST); 76840285Smckusick } 76945785Sbostic VATTR_NULL(&vattr); 77045785Sbostic vattr.va_type = VFIFO; 77164410Sbostic vattr.va_mode = (uap->mode & ALLPERMS) &~ p->p_fd->fd_cmask; 77252322Smckusick LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 77352322Smckusick return (VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr)); 77440285Smckusick #endif /* FIFO */ 77540285Smckusick } 77640285Smckusick 77740285Smckusick /* 77864410Sbostic * Make a hard file link. 7796254Sroot */ 78054916Storek struct link_args { 78164410Sbostic char *path; 78264410Sbostic char *link; 78354916Storek }; 78442441Smckusick /* ARGSUSED */ 78542441Smckusick link(p, uap, retval) 78645914Smckusick struct proc *p; 78754916Storek register struct link_args *uap; 78842441Smckusick int *retval; 78942441Smckusick { 79064410Sbostic register struct vnode *vp; 79164410Sbostic struct nameidata nd; 79237741Smckusick int error; 7936254Sroot 79464410Sbostic NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); 79552322Smckusick if (error = namei(&nd)) 79647540Skarels return (error); 79752322Smckusick vp = nd.ni_vp; 79864585Sbostic if (vp->v_type != VDIR || 79964585Sbostic (error = suser(p->p_ucred, &p->p_acflag)) == 0) { 80064585Sbostic nd.ni_cnd.cn_nameiop = CREATE; 80164585Sbostic nd.ni_cnd.cn_flags = LOCKPARENT; 80264585Sbostic nd.ni_dirp = uap->link; 80364585Sbostic if ((error = namei(&nd)) == 0) { 80464585Sbostic if (nd.ni_vp != NULL) 80564585Sbostic error = EEXIST; 80664585Sbostic if (!error) { 80764585Sbostic LEASE_CHECK(nd.ni_dvp, 80864585Sbostic p, p->p_ucred, LEASE_WRITE); 80964585Sbostic LEASE_CHECK(vp, 81064585Sbostic p, p->p_ucred, LEASE_WRITE); 81164585Sbostic error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd); 81264585Sbostic } else { 81364585Sbostic VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 81464585Sbostic if (nd.ni_dvp == nd.ni_vp) 81564585Sbostic vrele(nd.ni_dvp); 81664585Sbostic else 81764585Sbostic vput(nd.ni_dvp); 81864585Sbostic if (nd.ni_vp) 81964585Sbostic vrele(nd.ni_vp); 82064585Sbostic } 82164585Sbostic } 82242465Smckusick } 82364585Sbostic vrele(vp); 82447540Skarels return (error); 8256254Sroot } 8266254Sroot 8276254Sroot /* 82849365Smckusick * Make a symbolic link. 8296254Sroot */ 83054916Storek struct symlink_args { 83164410Sbostic char *path; 83264410Sbostic char *link; 83354916Storek }; 83442441Smckusick /* ARGSUSED */ 83542441Smckusick symlink(p, uap, retval) 83645914Smckusick struct proc *p; 83754916Storek register struct symlink_args *uap; 83842441Smckusick int *retval; 83942441Smckusick { 84037741Smckusick struct vattr vattr; 84164410Sbostic char *path; 84237741Smckusick int error; 84347540Skarels struct nameidata nd; 8446254Sroot 84564410Sbostic MALLOC(path, char *, MAXPATHLEN, M_NAMEI, M_WAITOK); 84664410Sbostic if (error = copyinstr(uap->path, path, MAXPATHLEN, NULL)) 84742465Smckusick goto out; 84864410Sbostic NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->link, p); 84952322Smckusick if (error = namei(&nd)) 85042465Smckusick goto out; 85152322Smckusick if (nd.ni_vp) { 85252322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 85352322Smckusick if (nd.ni_dvp == nd.ni_vp) 85452322Smckusick vrele(nd.ni_dvp); 85543344Smckusick else 85652322Smckusick vput(nd.ni_dvp); 85752322Smckusick vrele(nd.ni_vp); 85837741Smckusick error = EEXIST; 85937741Smckusick goto out; 8606254Sroot } 86141362Smckusick VATTR_NULL(&vattr); 86264410Sbostic vattr.va_mode = ACCESSPERMS &~ p->p_fd->fd_cmask; 86352322Smckusick LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 86464410Sbostic error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr, path); 86537741Smckusick out: 86664410Sbostic FREE(path, M_NAMEI); 86747540Skarels return (error); 8686254Sroot } 8696254Sroot 8706254Sroot /* 87167518Spendry * Delete a whiteout from the filesystem. 87267518Spendry */ 87367518Spendry struct unwhiteout_args { 87467518Spendry char *path; 87567518Spendry }; 87667518Spendry /* ARGSUSED */ 87767518Spendry unwhiteout(p, uap, retval) 87867518Spendry struct proc *p; 87967518Spendry struct unwhiteout_args *uap; 88067518Spendry int *retval; 88167518Spendry { 88267518Spendry int error; 88367518Spendry struct nameidata nd; 88467518Spendry 88567518Spendry NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->path, p); 88667518Spendry if (error = namei(&nd)) 88767518Spendry return (error); 88867518Spendry if (nd.ni_vp || !(nd.ni_cnd.cn_flags & WHITEOUT)) { 88967518Spendry VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 89067518Spendry if (nd.ni_dvp == nd.ni_vp) 89167518Spendry vrele(nd.ni_dvp); 89267518Spendry else 89367518Spendry vput(nd.ni_dvp); 89467518Spendry if (nd.ni_vp) 89567518Spendry vrele(nd.ni_vp); 89667518Spendry return (EEXIST); 89767518Spendry } 89867518Spendry LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 89967518Spendry error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, DELETE); 90067518Spendry vput(nd.ni_dvp); 90167518Spendry return (error); 90267518Spendry } 90367518Spendry 90467518Spendry /* 90549365Smckusick * Delete a name from the filesystem. 9066254Sroot */ 90754916Storek struct unlink_args { 90864410Sbostic char *path; 90954916Storek }; 91042441Smckusick /* ARGSUSED */ 91142441Smckusick unlink(p, uap, retval) 91245914Smckusick struct proc *p; 91354916Storek struct unlink_args *uap; 91442441Smckusick int *retval; 9156254Sroot { 91637741Smckusick register struct vnode *vp; 91737741Smckusick int error; 91847540Skarels struct nameidata nd; 9196254Sroot 92064410Sbostic NDINIT(&nd, DELETE, LOCKPARENT, UIO_USERSPACE, uap->path, p); 92152322Smckusick if (error = namei(&nd)) 92247540Skarels return (error); 92352322Smckusick vp = nd.ni_vp; 92459382Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 92559382Smckusick VOP_LOCK(vp); 92664410Sbostic 92764585Sbostic if (vp->v_type != VDIR || 92864585Sbostic (error = suser(p->p_ucred, &p->p_acflag)) == 0) { 92964585Sbostic /* 93064585Sbostic * The root of a mounted filesystem cannot be deleted. 93164585Sbostic */ 93264585Sbostic if (vp->v_flag & VROOT) 93364585Sbostic error = EBUSY; 93464585Sbostic else 93564585Sbostic (void)vnode_pager_uncache(vp); 93664585Sbostic } 93764585Sbostic 93864585Sbostic if (!error) { 93952322Smckusick LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 94052322Smckusick error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); 94142465Smckusick } else { 94252322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 94352322Smckusick if (nd.ni_dvp == vp) 94452322Smckusick vrele(nd.ni_dvp); 94543344Smckusick else 94652322Smckusick vput(nd.ni_dvp); 94742465Smckusick vput(vp); 94842465Smckusick } 94947540Skarels return (error); 9506254Sroot } 9516254Sroot 95264410Sbostic /* 95364410Sbostic * Reposition read/write file offset. 95464410Sbostic */ 95560428Smckusick struct lseek_args { 95664410Sbostic int fd; 95754863Storek int pad; 95864410Sbostic off_t offset; 95964410Sbostic int whence; 96054863Storek }; 96160414Smckusick lseek(p, uap, retval) 96253468Smckusick struct proc *p; 96360428Smckusick register struct lseek_args *uap; 96454916Storek int *retval; 96542441Smckusick { 96647540Skarels struct ucred *cred = p->p_ucred; 96745914Smckusick register struct filedesc *fdp = p->p_fd; 96842441Smckusick register struct file *fp; 96937741Smckusick struct vattr vattr; 97037741Smckusick int error; 9716254Sroot 97264410Sbostic if ((u_int)uap->fd >= fdp->fd_nfiles || 97364410Sbostic (fp = fdp->fd_ofiles[uap->fd]) == NULL) 97447540Skarels return (EBADF); 97537741Smckusick if (fp->f_type != DTYPE_VNODE) 97647540Skarels return (ESPIPE); 97764410Sbostic switch (uap->whence) { 97813878Ssam case L_INCR: 97964410Sbostic fp->f_offset += uap->offset; 98013878Ssam break; 98113878Ssam case L_XTND: 98264410Sbostic if (error = 98364410Sbostic VOP_GETATTR((struct vnode *)fp->f_data, &vattr, cred, p)) 98447540Skarels return (error); 98564410Sbostic fp->f_offset = uap->offset + vattr.va_size; 98613878Ssam break; 98713878Ssam case L_SET: 98864410Sbostic fp->f_offset = uap->offset; 98913878Ssam break; 99013878Ssam default: 99147540Skarels return (EINVAL); 99213878Ssam } 99354916Storek *(off_t *)retval = fp->f_offset; 99447540Skarels return (0); 9956254Sroot } 9966254Sroot 99760414Smckusick #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 9986254Sroot /* 99964410Sbostic * Reposition read/write file offset. 100060036Smckusick */ 100160428Smckusick struct olseek_args { 100264410Sbostic int fd; 100364410Sbostic long offset; 100464410Sbostic int whence; 100560036Smckusick }; 100660414Smckusick olseek(p, uap, retval) 100760036Smckusick struct proc *p; 100860428Smckusick register struct olseek_args *uap; 100960036Smckusick int *retval; 101060036Smckusick { 101160428Smckusick struct lseek_args nuap; 101260036Smckusick off_t qret; 101360036Smckusick int error; 101460036Smckusick 101564410Sbostic nuap.fd = uap->fd; 101664410Sbostic nuap.offset = uap->offset; 101764410Sbostic nuap.whence = uap->whence; 101860428Smckusick error = lseek(p, &nuap, &qret); 101960036Smckusick *(long *)retval = qret; 102060036Smckusick return (error); 102160036Smckusick } 102260414Smckusick #endif /* COMPAT_43 */ 102360036Smckusick 102460036Smckusick /* 102549365Smckusick * Check access permissions. 10266254Sroot */ 102763427Sbostic struct access_args { 102864410Sbostic char *path; 102964410Sbostic int flags; 103054916Storek }; 103163427Sbostic access(p, uap, retval) 103245914Smckusick struct proc *p; 103363427Sbostic register struct access_args *uap; 103442441Smckusick int *retval; 103542441Smckusick { 103647540Skarels register struct ucred *cred = p->p_ucred; 103737741Smckusick register struct vnode *vp; 103864585Sbostic int error, flags, t_gid, t_uid; 103947540Skarels struct nameidata nd; 10406254Sroot 104164585Sbostic t_uid = cred->cr_uid; 104264585Sbostic t_gid = cred->cr_groups[0]; 104347540Skarels cred->cr_uid = p->p_cred->p_ruid; 104447540Skarels cred->cr_groups[0] = p->p_cred->p_rgid; 104564410Sbostic NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); 104652322Smckusick if (error = namei(&nd)) 104737741Smckusick goto out1; 104852322Smckusick vp = nd.ni_vp; 104964410Sbostic 105064410Sbostic /* Flags == 0 means only check for existence. */ 105164410Sbostic if (uap->flags) { 105264410Sbostic flags = 0; 105364410Sbostic if (uap->flags & R_OK) 105464410Sbostic flags |= VREAD; 105564410Sbostic if (uap->flags & W_OK) 105664410Sbostic flags |= VWRITE; 105764410Sbostic if (uap->flags & X_OK) 105864410Sbostic flags |= VEXEC; 105964410Sbostic if ((flags & VWRITE) == 0 || (error = vn_writechk(vp)) == 0) 106064410Sbostic error = VOP_ACCESS(vp, flags, cred, p); 10616254Sroot } 106237741Smckusick vput(vp); 106337741Smckusick out1: 106464585Sbostic cred->cr_uid = t_uid; 106564585Sbostic cred->cr_groups[0] = t_gid; 106647540Skarels return (error); 10676254Sroot } 10686254Sroot 106954348Smckusick #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 10706254Sroot /* 107164410Sbostic * Get file status; this version follows links. 107237Sbill */ 107354916Storek struct ostat_args { 107464410Sbostic char *path; 107554916Storek struct ostat *ub; 107654916Storek }; 107742441Smckusick /* ARGSUSED */ 107853759Smckusick ostat(p, uap, retval) 107945914Smckusick struct proc *p; 108054916Storek register struct ostat_args *uap; 108153468Smckusick int *retval; 108253468Smckusick { 108353468Smckusick struct stat sb; 108453468Smckusick struct ostat osb; 108553468Smckusick int error; 108653468Smckusick struct nameidata nd; 108753468Smckusick 108864410Sbostic NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); 108953468Smckusick if (error = namei(&nd)) 109053468Smckusick return (error); 109153468Smckusick error = vn_stat(nd.ni_vp, &sb, p); 109253468Smckusick vput(nd.ni_vp); 109353468Smckusick if (error) 109453468Smckusick return (error); 109553468Smckusick cvtstat(&sb, &osb); 109653468Smckusick error = copyout((caddr_t)&osb, (caddr_t)uap->ub, sizeof (osb)); 109753468Smckusick return (error); 109853468Smckusick } 109953468Smckusick 110053468Smckusick /* 110164410Sbostic * Get file status; this version does not follow links. 110253468Smckusick */ 110354916Storek struct olstat_args { 110464410Sbostic char *path; 110554916Storek struct ostat *ub; 110654916Storek }; 110753468Smckusick /* ARGSUSED */ 110853759Smckusick olstat(p, uap, retval) 110953468Smckusick struct proc *p; 111054916Storek register struct olstat_args *uap; 111153468Smckusick int *retval; 111253468Smckusick { 111353468Smckusick struct stat sb; 111453468Smckusick struct ostat osb; 111553468Smckusick int error; 111653468Smckusick struct nameidata nd; 111753468Smckusick 111864410Sbostic NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); 111953468Smckusick if (error = namei(&nd)) 112053468Smckusick return (error); 112153468Smckusick error = vn_stat(nd.ni_vp, &sb, p); 112253468Smckusick vput(nd.ni_vp); 112353468Smckusick if (error) 112453468Smckusick return (error); 112553468Smckusick cvtstat(&sb, &osb); 112653468Smckusick error = copyout((caddr_t)&osb, (caddr_t)uap->ub, sizeof (osb)); 112753468Smckusick return (error); 112853468Smckusick } 112953468Smckusick 113053468Smckusick /* 113164410Sbostic * Convert from an old to a new stat structure. 113253468Smckusick */ 113353468Smckusick cvtstat(st, ost) 113453468Smckusick struct stat *st; 113553468Smckusick struct ostat *ost; 113653468Smckusick { 113753468Smckusick 113853468Smckusick ost->st_dev = st->st_dev; 113953468Smckusick ost->st_ino = st->st_ino; 114053468Smckusick ost->st_mode = st->st_mode; 114153468Smckusick ost->st_nlink = st->st_nlink; 114253468Smckusick ost->st_uid = st->st_uid; 114353468Smckusick ost->st_gid = st->st_gid; 114453468Smckusick ost->st_rdev = st->st_rdev; 114553468Smckusick if (st->st_size < (quad_t)1 << 32) 114653468Smckusick ost->st_size = st->st_size; 114753468Smckusick else 114853468Smckusick ost->st_size = -2; 114953468Smckusick ost->st_atime = st->st_atime; 115053468Smckusick ost->st_mtime = st->st_mtime; 115153468Smckusick ost->st_ctime = st->st_ctime; 115253468Smckusick ost->st_blksize = st->st_blksize; 115353468Smckusick ost->st_blocks = st->st_blocks; 115453468Smckusick ost->st_flags = st->st_flags; 115553468Smckusick ost->st_gen = st->st_gen; 115653468Smckusick } 115754348Smckusick #endif /* COMPAT_43 || COMPAT_SUNOS */ 115853468Smckusick 115953468Smckusick /* 116064410Sbostic * Get file status; this version follows links. 116153468Smckusick */ 116254916Storek struct stat_args { 116364410Sbostic char *path; 116454916Storek struct stat *ub; 116554916Storek }; 116653468Smckusick /* ARGSUSED */ 116753759Smckusick stat(p, uap, retval) 116853468Smckusick struct proc *p; 116954916Storek register struct stat_args *uap; 117042441Smckusick int *retval; 117137Sbill { 117242441Smckusick struct stat sb; 117342441Smckusick int error; 117447540Skarels struct nameidata nd; 117537Sbill 117664410Sbostic NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); 117752322Smckusick if (error = namei(&nd)) 117847540Skarels return (error); 117952322Smckusick error = vn_stat(nd.ni_vp, &sb, p); 118052322Smckusick vput(nd.ni_vp); 118142441Smckusick if (error) 118247540Skarels return (error); 118342441Smckusick error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb)); 118447540Skarels return (error); 118537Sbill } 118637Sbill 118737Sbill /* 118864410Sbostic * Get file status; this version does not follow links. 11895992Swnj */ 119054916Storek struct lstat_args { 119164410Sbostic char *path; 119254916Storek struct stat *ub; 119354916Storek }; 119442441Smckusick /* ARGSUSED */ 119553759Smckusick lstat(p, uap, retval) 119645914Smckusick struct proc *p; 119754916Storek register struct lstat_args *uap; 119842441Smckusick int *retval; 119942441Smckusick { 120037741Smckusick int error; 120159373Smckusick struct vnode *vp, *dvp; 120259373Smckusick struct stat sb, sb1; 120347540Skarels struct nameidata nd; 12045992Swnj 120559373Smckusick NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | LOCKPARENT, UIO_USERSPACE, 120664410Sbostic uap->path, p); 120752322Smckusick if (error = namei(&nd)) 120847540Skarels return (error); 120959373Smckusick /* 121059373Smckusick * For symbolic links, always return the attributes of its 121159373Smckusick * containing directory, except for mode, size, and links. 121259373Smckusick */ 121359373Smckusick vp = nd.ni_vp; 121459373Smckusick dvp = nd.ni_dvp; 121559373Smckusick if (vp->v_type != VLNK) { 121659373Smckusick if (dvp == vp) 121759373Smckusick vrele(dvp); 121859373Smckusick else 121959373Smckusick vput(dvp); 122059373Smckusick error = vn_stat(vp, &sb, p); 122159373Smckusick vput(vp); 122259373Smckusick if (error) 122359373Smckusick return (error); 122459373Smckusick } else { 122559373Smckusick error = vn_stat(dvp, &sb, p); 122659373Smckusick vput(dvp); 122759373Smckusick if (error) { 122859373Smckusick vput(vp); 122959373Smckusick return (error); 123059373Smckusick } 123159373Smckusick error = vn_stat(vp, &sb1, p); 123259373Smckusick vput(vp); 123359373Smckusick if (error) 123459373Smckusick return (error); 123559373Smckusick sb.st_mode &= ~S_IFDIR; 123659373Smckusick sb.st_mode |= S_IFLNK; 123759373Smckusick sb.st_nlink = sb1.st_nlink; 123859373Smckusick sb.st_size = sb1.st_size; 123959373Smckusick sb.st_blocks = sb1.st_blocks; 124059373Smckusick } 124137741Smckusick error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb)); 124247540Skarels return (error); 12435992Swnj } 12445992Swnj 12455992Swnj /* 124664410Sbostic * Get configurable pathname variables. 124760414Smckusick */ 124860414Smckusick struct pathconf_args { 124964410Sbostic char *path; 125060414Smckusick int name; 125160414Smckusick }; 125260414Smckusick /* ARGSUSED */ 125360414Smckusick pathconf(p, uap, retval) 125460414Smckusick struct proc *p; 125560414Smckusick register struct pathconf_args *uap; 125660414Smckusick int *retval; 125760414Smckusick { 125860414Smckusick int error; 125960414Smckusick struct nameidata nd; 126060414Smckusick 126164410Sbostic NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); 126260414Smckusick if (error = namei(&nd)) 126360414Smckusick return (error); 126460414Smckusick error = VOP_PATHCONF(nd.ni_vp, uap->name, retval); 126560414Smckusick vput(nd.ni_vp); 126660414Smckusick return (error); 126760414Smckusick } 126860414Smckusick 126960414Smckusick /* 127049365Smckusick * Return target name of a symbolic link. 127137Sbill */ 127254916Storek struct readlink_args { 127364410Sbostic char *path; 127454916Storek char *buf; 127554916Storek int count; 127654916Storek }; 127742441Smckusick /* ARGSUSED */ 127842441Smckusick readlink(p, uap, retval) 127945914Smckusick struct proc *p; 128054916Storek register struct readlink_args *uap; 128142441Smckusick int *retval; 128242441Smckusick { 128337741Smckusick register struct vnode *vp; 128437741Smckusick struct iovec aiov; 128537741Smckusick struct uio auio; 128637741Smckusick int error; 128747540Skarels struct nameidata nd; 12885992Swnj 128964410Sbostic NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); 129052322Smckusick if (error = namei(&nd)) 129147540Skarels return (error); 129252322Smckusick vp = nd.ni_vp; 129364410Sbostic if (vp->v_type != VLNK) 129437741Smckusick error = EINVAL; 129564410Sbostic else { 129664410Sbostic aiov.iov_base = uap->buf; 129764410Sbostic aiov.iov_len = uap->count; 129864410Sbostic auio.uio_iov = &aiov; 129964410Sbostic auio.uio_iovcnt = 1; 130064410Sbostic auio.uio_offset = 0; 130164410Sbostic auio.uio_rw = UIO_READ; 130264410Sbostic auio.uio_segflg = UIO_USERSPACE; 130364410Sbostic auio.uio_procp = p; 130464410Sbostic auio.uio_resid = uap->count; 130564410Sbostic error = VOP_READLINK(vp, &auio, p->p_ucred); 13065992Swnj } 130737741Smckusick vput(vp); 130842441Smckusick *retval = uap->count - auio.uio_resid; 130947540Skarels return (error); 13105992Swnj } 13115992Swnj 13129167Ssam /* 131364410Sbostic * Change flags of a file given a path name. 131438259Smckusick */ 131554916Storek struct chflags_args { 131664410Sbostic char *path; 131754916Storek int flags; 131854916Storek }; 131942441Smckusick /* ARGSUSED */ 132042441Smckusick chflags(p, uap, retval) 132145914Smckusick struct proc *p; 132254916Storek register struct chflags_args *uap; 132342441Smckusick int *retval; 132442441Smckusick { 132538259Smckusick register struct vnode *vp; 132638259Smckusick struct vattr vattr; 132738259Smckusick int error; 132847540Skarels struct nameidata nd; 132938259Smckusick 133064410Sbostic NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); 133152322Smckusick if (error = namei(&nd)) 133247540Skarels return (error); 133352322Smckusick vp = nd.ni_vp; 133459382Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 133559382Smckusick VOP_LOCK(vp); 133664410Sbostic if (vp->v_mount->mnt_flag & MNT_RDONLY) 133738259Smckusick error = EROFS; 133864410Sbostic else { 133964410Sbostic VATTR_NULL(&vattr); 134064410Sbostic vattr.va_flags = uap->flags; 134164410Sbostic error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 134238259Smckusick } 134338259Smckusick vput(vp); 134447540Skarels return (error); 134538259Smckusick } 134638259Smckusick 134738259Smckusick /* 134838259Smckusick * Change flags of a file given a file descriptor. 134938259Smckusick */ 135054916Storek struct fchflags_args { 135154916Storek int fd; 135254916Storek int flags; 135354916Storek }; 135442441Smckusick /* ARGSUSED */ 135542441Smckusick fchflags(p, uap, retval) 135645914Smckusick struct proc *p; 135754916Storek register struct fchflags_args *uap; 135842441Smckusick int *retval; 135942441Smckusick { 136038259Smckusick struct vattr vattr; 136138259Smckusick struct vnode *vp; 136238259Smckusick struct file *fp; 136338259Smckusick int error; 136438259Smckusick 136545914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 136647540Skarels return (error); 136738259Smckusick vp = (struct vnode *)fp->f_data; 136859382Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 136938259Smckusick VOP_LOCK(vp); 137064410Sbostic if (vp->v_mount->mnt_flag & MNT_RDONLY) 137138259Smckusick error = EROFS; 137264410Sbostic else { 137364410Sbostic VATTR_NULL(&vattr); 137464410Sbostic vattr.va_flags = uap->flags; 137564410Sbostic error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 137638259Smckusick } 137738259Smckusick VOP_UNLOCK(vp); 137847540Skarels return (error); 137938259Smckusick } 138038259Smckusick 138138259Smckusick /* 13829167Ssam * Change mode of a file given path name. 13839167Ssam */ 138454916Storek struct chmod_args { 138564410Sbostic char *path; 138664410Sbostic int mode; 138754916Storek }; 138842441Smckusick /* ARGSUSED */ 138942441Smckusick chmod(p, uap, retval) 139045914Smckusick struct proc *p; 139154916Storek register struct chmod_args *uap; 139242441Smckusick int *retval; 139342441Smckusick { 139437741Smckusick register struct vnode *vp; 139537741Smckusick struct vattr vattr; 139637741Smckusick int error; 139747540Skarels struct nameidata nd; 13985992Swnj 139964410Sbostic NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); 140052322Smckusick if (error = namei(&nd)) 140147540Skarels return (error); 140252322Smckusick vp = nd.ni_vp; 140359382Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 140459382Smckusick VOP_LOCK(vp); 140564410Sbostic if (vp->v_mount->mnt_flag & MNT_RDONLY) 140637741Smckusick error = EROFS; 140764410Sbostic else { 140864410Sbostic VATTR_NULL(&vattr); 140964410Sbostic vattr.va_mode = uap->mode & ALLPERMS; 141064410Sbostic error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 141137741Smckusick } 141237741Smckusick vput(vp); 141347540Skarels return (error); 14147701Ssam } 14157439Sroot 14169167Ssam /* 14179167Ssam * Change mode of a file given a file descriptor. 14189167Ssam */ 141954916Storek struct fchmod_args { 142054916Storek int fd; 142164410Sbostic int mode; 142254916Storek }; 142342441Smckusick /* ARGSUSED */ 142442441Smckusick fchmod(p, uap, retval) 142545914Smckusick struct proc *p; 142654916Storek register struct fchmod_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_mode = uap->mode & ALLPERMS; 144464410Sbostic error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 14457439Sroot } 144637741Smckusick VOP_UNLOCK(vp); 144747540Skarels return (error); 14485992Swnj } 14495992Swnj 14509167Ssam /* 14519167Ssam * Set ownership given a path name. 14529167Ssam */ 145354916Storek struct chown_args { 145464410Sbostic char *path; 145554916Storek int uid; 145654916Storek int gid; 145754916Storek }; 145842441Smckusick /* ARGSUSED */ 145942441Smckusick chown(p, uap, retval) 146045914Smckusick struct proc *p; 146154916Storek register struct chown_args *uap; 146242441Smckusick int *retval; 146342441Smckusick { 146437741Smckusick register struct vnode *vp; 146537741Smckusick struct vattr vattr; 146637741Smckusick int error; 146747540Skarels struct nameidata nd; 146837Sbill 146966510Sbostic NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); 147052322Smckusick if (error = namei(&nd)) 147147540Skarels return (error); 147252322Smckusick vp = nd.ni_vp; 147359382Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 147459382Smckusick VOP_LOCK(vp); 147564410Sbostic if (vp->v_mount->mnt_flag & MNT_RDONLY) 147637741Smckusick error = EROFS; 147764410Sbostic else { 147864410Sbostic VATTR_NULL(&vattr); 147964410Sbostic vattr.va_uid = uap->uid; 148064410Sbostic vattr.va_gid = uap->gid; 148164410Sbostic error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 148237741Smckusick } 148337741Smckusick vput(vp); 148447540Skarels return (error); 14857701Ssam } 14867439Sroot 14879167Ssam /* 14889167Ssam * Set ownership given a file descriptor. 14899167Ssam */ 149054916Storek struct fchown_args { 149154916Storek int fd; 149254916Storek int uid; 149354916Storek int gid; 149454916Storek }; 149542441Smckusick /* ARGSUSED */ 149642441Smckusick fchown(p, uap, retval) 149745914Smckusick struct proc *p; 149854916Storek register struct fchown_args *uap; 149942441Smckusick int *retval; 150042441Smckusick { 150137741Smckusick struct vattr vattr; 150237741Smckusick struct vnode *vp; 150337741Smckusick struct file *fp; 150437741Smckusick int error; 15057701Ssam 150645914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 150747540Skarels return (error); 150837741Smckusick vp = (struct vnode *)fp->f_data; 150959382Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 151037741Smckusick VOP_LOCK(vp); 151164410Sbostic if (vp->v_mount->mnt_flag & MNT_RDONLY) 151237741Smckusick error = EROFS; 151364410Sbostic else { 151464410Sbostic VATTR_NULL(&vattr); 151564410Sbostic vattr.va_uid = uap->uid; 151664410Sbostic vattr.va_gid = uap->gid; 151764410Sbostic error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 151837741Smckusick } 151937741Smckusick VOP_UNLOCK(vp); 152047540Skarels return (error); 15217701Ssam } 15227701Ssam 152342441Smckusick /* 152442441Smckusick * Set the access and modification times of a file. 152542441Smckusick */ 152654916Storek struct utimes_args { 152764410Sbostic char *path; 152854916Storek struct timeval *tptr; 152954916Storek }; 153042441Smckusick /* ARGSUSED */ 153142441Smckusick utimes(p, uap, retval) 153245914Smckusick struct proc *p; 153354916Storek register struct utimes_args *uap; 153442441Smckusick int *retval; 153542441Smckusick { 153637741Smckusick register struct vnode *vp; 153711811Ssam struct timeval tv[2]; 153837741Smckusick struct vattr vattr; 153958840Storek int error; 154047540Skarels struct nameidata nd; 154111811Ssam 154258505Sbostic VATTR_NULL(&vattr); 154358505Sbostic if (uap->tptr == NULL) { 154458505Sbostic microtime(&tv[0]); 154558505Sbostic tv[1] = tv[0]; 154658548Sbostic vattr.va_vaflags |= VA_UTIMES_NULL; 154758505Sbostic } else if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv))) 154858505Sbostic return (error); 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_mount->mnt_flag & MNT_RDONLY) 155637741Smckusick error = EROFS; 155764410Sbostic else { 155864410Sbostic vattr.va_atime.ts_sec = tv[0].tv_sec; 155964410Sbostic vattr.va_atime.ts_nsec = tv[0].tv_usec * 1000; 156064410Sbostic vattr.va_mtime.ts_sec = tv[1].tv_sec; 156164410Sbostic vattr.va_mtime.ts_nsec = tv[1].tv_usec * 1000; 156264410Sbostic error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 156321015Smckusick } 156437741Smckusick vput(vp); 156547540Skarels return (error); 156611811Ssam } 156711811Ssam 156864410Sbostic /* 156964410Sbostic * Truncate a file given its path name. 157064410Sbostic */ 157160428Smckusick struct truncate_args { 157264410Sbostic char *path; 157354863Storek int pad; 157454863Storek off_t length; 157554863Storek }; 157653468Smckusick /* ARGSUSED */ 157760414Smckusick truncate(p, uap, retval) 157853468Smckusick struct proc *p; 157960428Smckusick register struct truncate_args *uap; 158053468Smckusick int *retval; 158153468Smckusick { 158237741Smckusick register struct vnode *vp; 158337741Smckusick struct vattr vattr; 158437741Smckusick int error; 158547540Skarels struct nameidata nd; 15867701Ssam 158764410Sbostic NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); 158852322Smckusick if (error = namei(&nd)) 158947540Skarels return (error); 159052322Smckusick vp = nd.ni_vp; 159159382Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 159259382Smckusick VOP_LOCK(vp); 159364410Sbostic if (vp->v_type == VDIR) 159437741Smckusick error = EISDIR; 159564410Sbostic else if ((error = vn_writechk(vp)) == 0 && 159664410Sbostic (error = VOP_ACCESS(vp, VWRITE, p->p_ucred, p)) == 0) { 159764410Sbostic VATTR_NULL(&vattr); 159864410Sbostic vattr.va_size = uap->length; 159964410Sbostic error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 16007701Ssam } 160137741Smckusick vput(vp); 160247540Skarels return (error); 16037701Ssam } 16047701Ssam 160564410Sbostic /* 160664410Sbostic * Truncate a file given a file descriptor. 160764410Sbostic */ 160860428Smckusick struct ftruncate_args { 160954863Storek int fd; 161054863Storek int pad; 161154863Storek off_t length; 161254863Storek }; 161342441Smckusick /* ARGSUSED */ 161460414Smckusick ftruncate(p, uap, retval) 161545914Smckusick struct proc *p; 161660428Smckusick register struct ftruncate_args *uap; 161742441Smckusick int *retval; 161842441Smckusick { 161937741Smckusick struct vattr vattr; 162037741Smckusick struct vnode *vp; 16217701Ssam struct file *fp; 162237741Smckusick int error; 16237701Ssam 162445914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 162547540Skarels return (error); 162637741Smckusick if ((fp->f_flag & FWRITE) == 0) 162747540Skarels return (EINVAL); 162837741Smckusick vp = (struct vnode *)fp->f_data; 162959382Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 163037741Smckusick VOP_LOCK(vp); 163164410Sbostic if (vp->v_type == VDIR) 163237741Smckusick error = EISDIR; 163364410Sbostic else if ((error = vn_writechk(vp)) == 0) { 163464410Sbostic VATTR_NULL(&vattr); 163564410Sbostic vattr.va_size = uap->length; 163664410Sbostic error = VOP_SETATTR(vp, &vattr, fp->f_cred, p); 16377701Ssam } 163837741Smckusick VOP_UNLOCK(vp); 163947540Skarels return (error); 16407701Ssam } 16417701Ssam 164254863Storek #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 16439167Ssam /* 164454863Storek * Truncate a file given its path name. 164554863Storek */ 164660428Smckusick struct otruncate_args { 164764410Sbostic char *path; 164854916Storek long length; 164954916Storek }; 165054863Storek /* ARGSUSED */ 165160105Smckusick otruncate(p, uap, retval) 165254863Storek struct proc *p; 165360428Smckusick register struct otruncate_args *uap; 165454863Storek int *retval; 165554863Storek { 165660428Smckusick struct truncate_args nuap; 165754863Storek 165864410Sbostic nuap.path = uap->path; 165954863Storek nuap.length = uap->length; 166060428Smckusick return (truncate(p, &nuap, retval)); 166154863Storek } 166254863Storek 166354863Storek /* 166454863Storek * Truncate a file given a file descriptor. 166554863Storek */ 166660428Smckusick struct oftruncate_args { 166754916Storek int fd; 166854916Storek long length; 166954916Storek }; 167054863Storek /* ARGSUSED */ 167160105Smckusick oftruncate(p, uap, retval) 167254863Storek struct proc *p; 167360428Smckusick register struct oftruncate_args *uap; 167454863Storek int *retval; 167554863Storek { 167660428Smckusick struct ftruncate_args nuap; 167754863Storek 167854863Storek nuap.fd = uap->fd; 167954863Storek nuap.length = uap->length; 168060428Smckusick return (ftruncate(p, &nuap, retval)); 168154863Storek } 168254863Storek #endif /* COMPAT_43 || COMPAT_SUNOS */ 168354863Storek 168454863Storek /* 168564410Sbostic * Sync an open file. 16869167Ssam */ 168754916Storek struct fsync_args { 168854916Storek int fd; 168954916Storek }; 169042441Smckusick /* ARGSUSED */ 169142441Smckusick fsync(p, uap, retval) 169245914Smckusick struct proc *p; 169354916Storek struct fsync_args *uap; 169442441Smckusick int *retval; 16959167Ssam { 169639592Smckusick register struct vnode *vp; 16979167Ssam struct file *fp; 169837741Smckusick int error; 16999167Ssam 170045914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 170147540Skarels return (error); 170239592Smckusick vp = (struct vnode *)fp->f_data; 170339592Smckusick VOP_LOCK(vp); 170454441Smckusick error = VOP_FSYNC(vp, fp->f_cred, MNT_WAIT, p); 170539592Smckusick VOP_UNLOCK(vp); 170647540Skarels return (error); 17079167Ssam } 17089167Ssam 17099167Ssam /* 171064410Sbostic * Rename files. Source and destination must either both be directories, 171164410Sbostic * or both not be directories. If target is a directory, it must be empty. 17129167Ssam */ 171354916Storek struct rename_args { 171454916Storek char *from; 171554916Storek char *to; 171654916Storek }; 171742441Smckusick /* ARGSUSED */ 171842441Smckusick rename(p, uap, retval) 171945914Smckusick struct proc *p; 172054916Storek register struct rename_args *uap; 172142441Smckusick int *retval; 172242441Smckusick { 172337741Smckusick register struct vnode *tvp, *fvp, *tdvp; 172449735Smckusick struct nameidata fromnd, tond; 172537741Smckusick int error; 17267701Ssam 172752322Smckusick NDINIT(&fromnd, DELETE, WANTPARENT | SAVESTART, UIO_USERSPACE, 172852322Smckusick uap->from, p); 172952322Smckusick if (error = namei(&fromnd)) 173047540Skarels return (error); 173149735Smckusick fvp = fromnd.ni_vp; 173252322Smckusick NDINIT(&tond, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART, 173352322Smckusick UIO_USERSPACE, uap->to, p); 173452322Smckusick if (error = namei(&tond)) { 173552230Sheideman VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 173649735Smckusick vrele(fromnd.ni_dvp); 173742465Smckusick vrele(fvp); 173842465Smckusick goto out1; 173942465Smckusick } 174037741Smckusick tdvp = tond.ni_dvp; 174137741Smckusick tvp = tond.ni_vp; 174237741Smckusick if (tvp != NULL) { 174337741Smckusick if (fvp->v_type == VDIR && tvp->v_type != VDIR) { 174439242Sbostic error = ENOTDIR; 174537741Smckusick goto out; 174637741Smckusick } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) { 174739242Sbostic error = EISDIR; 174837741Smckusick goto out; 17499167Ssam } 17509167Ssam } 175139286Smckusick if (fvp == tdvp) 175237741Smckusick error = EINVAL; 175339286Smckusick /* 175449735Smckusick * If source is the same as the destination (that is the 175549735Smckusick * same inode number with the same name in the same directory), 175639286Smckusick * then there is nothing to do. 175739286Smckusick */ 175849735Smckusick if (fvp == tvp && fromnd.ni_dvp == tdvp && 175952322Smckusick fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen && 176052322Smckusick !bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr, 176152322Smckusick fromnd.ni_cnd.cn_namelen)) 176239286Smckusick error = -1; 176337741Smckusick out: 176442465Smckusick if (!error) { 176552192Smckusick LEASE_CHECK(tdvp, p, p->p_ucred, LEASE_WRITE); 176652192Smckusick if (fromnd.ni_dvp != tdvp) 176752192Smckusick LEASE_CHECK(fromnd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 176852192Smckusick if (tvp) 176952192Smckusick LEASE_CHECK(tvp, p, p->p_ucred, LEASE_WRITE); 177052230Sheideman error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd, 177152230Sheideman tond.ni_dvp, tond.ni_vp, &tond.ni_cnd); 177242465Smckusick } else { 177352230Sheideman VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd); 177443344Smckusick if (tdvp == tvp) 177543344Smckusick vrele(tdvp); 177643344Smckusick else 177743344Smckusick vput(tdvp); 177842465Smckusick if (tvp) 177942465Smckusick vput(tvp); 178052230Sheideman VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 178149735Smckusick vrele(fromnd.ni_dvp); 178242465Smckusick vrele(fvp); 17839167Ssam } 178449735Smckusick vrele(tond.ni_startdir); 178552322Smckusick FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI); 178637741Smckusick out1: 178766801Smckusick if (fromnd.ni_startdir) 178866801Smckusick vrele(fromnd.ni_startdir); 178952322Smckusick FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI); 179039286Smckusick if (error == -1) 179147540Skarels return (0); 179247540Skarels return (error); 17937701Ssam } 17947701Ssam 17957535Sroot /* 179664410Sbostic * Make a directory file. 179712756Ssam */ 179854916Storek struct mkdir_args { 179964410Sbostic char *path; 180064410Sbostic int mode; 180154916Storek }; 180242441Smckusick /* ARGSUSED */ 180342441Smckusick mkdir(p, uap, retval) 180445914Smckusick struct proc *p; 180554916Storek register struct mkdir_args *uap; 180642441Smckusick int *retval; 180742441Smckusick { 180837741Smckusick register struct vnode *vp; 180937741Smckusick struct vattr vattr; 181037741Smckusick int error; 181147540Skarels struct nameidata nd; 181212756Ssam 181364410Sbostic NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->path, p); 181452322Smckusick if (error = namei(&nd)) 181547540Skarels return (error); 181652322Smckusick vp = nd.ni_vp; 181737741Smckusick if (vp != NULL) { 181852322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 181952322Smckusick if (nd.ni_dvp == vp) 182052322Smckusick vrele(nd.ni_dvp); 182143344Smckusick else 182252322Smckusick vput(nd.ni_dvp); 182342465Smckusick vrele(vp); 182447540Skarels return (EEXIST); 182512756Ssam } 182641362Smckusick VATTR_NULL(&vattr); 182737741Smckusick vattr.va_type = VDIR; 182864410Sbostic vattr.va_mode = (uap->mode & ACCESSPERMS) &~ p->p_fd->fd_cmask; 182952322Smckusick LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 183052322Smckusick error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr); 183138145Smckusick if (!error) 183252322Smckusick vput(nd.ni_vp); 183347540Skarels return (error); 183412756Ssam } 183512756Ssam 183612756Ssam /* 183764410Sbostic * Remove a directory file. 183812756Ssam */ 183954916Storek struct rmdir_args { 184064410Sbostic char *path; 184154916Storek }; 184242441Smckusick /* ARGSUSED */ 184342441Smckusick rmdir(p, uap, retval) 184445914Smckusick struct proc *p; 184554916Storek struct rmdir_args *uap; 184642441Smckusick int *retval; 184712756Ssam { 184837741Smckusick register struct vnode *vp; 184937741Smckusick int error; 185047540Skarels struct nameidata nd; 185112756Ssam 185264410Sbostic NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE, uap->path, p); 185352322Smckusick if (error = namei(&nd)) 185447540Skarels return (error); 185552322Smckusick vp = nd.ni_vp; 185637741Smckusick if (vp->v_type != VDIR) { 185737741Smckusick error = ENOTDIR; 185812756Ssam goto out; 185912756Ssam } 186012756Ssam /* 186137741Smckusick * No rmdir "." please. 186212756Ssam */ 186352322Smckusick if (nd.ni_dvp == vp) { 186437741Smckusick error = EINVAL; 186512756Ssam goto out; 186612756Ssam } 186712756Ssam /* 186849365Smckusick * The root of a mounted filesystem cannot be deleted. 186912756Ssam */ 187037741Smckusick if (vp->v_flag & VROOT) 187137741Smckusick error = EBUSY; 187212756Ssam out: 187342465Smckusick if (!error) { 187452322Smckusick LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 187552192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 187652322Smckusick error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); 187742465Smckusick } else { 187852322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 187952322Smckusick if (nd.ni_dvp == vp) 188052322Smckusick vrele(nd.ni_dvp); 188143344Smckusick else 188252322Smckusick vput(nd.ni_dvp); 188342465Smckusick vput(vp); 188442465Smckusick } 188547540Skarels return (error); 188612756Ssam } 188712756Ssam 188854620Smckusick #ifdef COMPAT_43 188937741Smckusick /* 189049365Smckusick * Read a block of directory entries in a file system independent format. 189137741Smckusick */ 189254916Storek struct ogetdirentries_args { 189354916Storek int fd; 189454916Storek char *buf; 189564410Sbostic u_int count; 189654916Storek long *basep; 189754916Storek }; 189854620Smckusick ogetdirentries(p, uap, retval) 189954620Smckusick struct proc *p; 190054916Storek register struct ogetdirentries_args *uap; 190154620Smckusick int *retval; 190254620Smckusick { 190354620Smckusick register struct vnode *vp; 190454620Smckusick struct file *fp; 190554620Smckusick struct uio auio, kuio; 190654620Smckusick struct iovec aiov, kiov; 190754620Smckusick struct dirent *dp, *edp; 190854620Smckusick caddr_t dirbuf; 190967362Smckusick int error, eofflag, readcnt; 191054969Smckusick long loff; 191154620Smckusick 191254620Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 191354620Smckusick return (error); 191454620Smckusick if ((fp->f_flag & FREAD) == 0) 191554620Smckusick return (EBADF); 191654620Smckusick vp = (struct vnode *)fp->f_data; 191767362Smckusick unionread: 191854620Smckusick if (vp->v_type != VDIR) 191954620Smckusick return (EINVAL); 192054620Smckusick aiov.iov_base = uap->buf; 192154620Smckusick aiov.iov_len = uap->count; 192254620Smckusick auio.uio_iov = &aiov; 192354620Smckusick auio.uio_iovcnt = 1; 192454620Smckusick auio.uio_rw = UIO_READ; 192554620Smckusick auio.uio_segflg = UIO_USERSPACE; 192654620Smckusick auio.uio_procp = p; 192754620Smckusick auio.uio_resid = uap->count; 192854620Smckusick VOP_LOCK(vp); 192954969Smckusick loff = auio.uio_offset = fp->f_offset; 193054620Smckusick # if (BYTE_ORDER != LITTLE_ENDIAN) 193156339Smckusick if (vp->v_mount->mnt_maxsymlinklen <= 0) { 193267362Smckusick error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, 193367362Smckusick (u_long *)0, 0); 193456339Smckusick fp->f_offset = auio.uio_offset; 193556339Smckusick } else 193654620Smckusick # endif 193754620Smckusick { 193854620Smckusick kuio = auio; 193954620Smckusick kuio.uio_iov = &kiov; 194054620Smckusick kuio.uio_segflg = UIO_SYSSPACE; 194154620Smckusick kiov.iov_len = uap->count; 194254620Smckusick MALLOC(dirbuf, caddr_t, uap->count, M_TEMP, M_WAITOK); 194354620Smckusick kiov.iov_base = dirbuf; 194467362Smckusick error = VOP_READDIR(vp, &kuio, fp->f_cred, &eofflag, 194567362Smckusick (u_long *)0, 0); 194656339Smckusick fp->f_offset = kuio.uio_offset; 194754620Smckusick if (error == 0) { 194854620Smckusick readcnt = uap->count - kuio.uio_resid; 194954620Smckusick edp = (struct dirent *)&dirbuf[readcnt]; 195054620Smckusick for (dp = (struct dirent *)dirbuf; dp < edp; ) { 195154620Smckusick # if (BYTE_ORDER == LITTLE_ENDIAN) 195254969Smckusick /* 195355009Smckusick * The expected low byte of 195455009Smckusick * dp->d_namlen is our dp->d_type. 195555009Smckusick * The high MBZ byte of dp->d_namlen 195655009Smckusick * is our dp->d_namlen. 195754969Smckusick */ 195855009Smckusick dp->d_type = dp->d_namlen; 195955009Smckusick dp->d_namlen = 0; 196055009Smckusick # else 196155009Smckusick /* 196255009Smckusick * The dp->d_type is the high byte 196355009Smckusick * of the expected dp->d_namlen, 196455009Smckusick * so must be zero'ed. 196555009Smckusick */ 196655009Smckusick dp->d_type = 0; 196754620Smckusick # endif 196854620Smckusick if (dp->d_reclen > 0) { 196954620Smckusick dp = (struct dirent *) 197054620Smckusick ((char *)dp + dp->d_reclen); 197154620Smckusick } else { 197254620Smckusick error = EIO; 197354620Smckusick break; 197454620Smckusick } 197554620Smckusick } 197654620Smckusick if (dp >= edp) 197754620Smckusick error = uiomove(dirbuf, readcnt, &auio); 197854620Smckusick } 197954620Smckusick FREE(dirbuf, M_TEMP); 198054620Smckusick } 198154620Smckusick VOP_UNLOCK(vp); 198254620Smckusick if (error) 198354620Smckusick return (error); 198467362Smckusick 198567362Smckusick #ifdef UNION 198667362Smckusick { 198767362Smckusick extern int (**union_vnodeop_p)(); 198867362Smckusick extern struct vnode *union_lowervp __P((struct vnode *)); 198967362Smckusick 199067362Smckusick if ((uap->count == auio.uio_resid) && 199167362Smckusick (vp->v_op == union_vnodeop_p)) { 199267362Smckusick struct vnode *lvp; 199367362Smckusick 199467362Smckusick lvp = union_lowervp(vp); 199567362Smckusick if (lvp != NULLVP) { 199667362Smckusick VOP_LOCK(lvp); 199767362Smckusick error = VOP_OPEN(lvp, FREAD, fp->f_cred, p); 199867362Smckusick VOP_UNLOCK(lvp); 199967362Smckusick 200067362Smckusick if (error) { 200167362Smckusick vrele(lvp); 200267362Smckusick return (error); 200367362Smckusick } 200467362Smckusick fp->f_data = (caddr_t) lvp; 200567362Smckusick fp->f_offset = 0; 200667362Smckusick error = vn_close(vp, FREAD, fp->f_cred, p); 200767362Smckusick if (error) 200867362Smckusick return (error); 200967362Smckusick vp = lvp; 201067362Smckusick goto unionread; 201167362Smckusick } 201267362Smckusick } 201367362Smckusick } 201467362Smckusick #endif /* UNION */ 201567362Smckusick 201667362Smckusick if ((uap->count == auio.uio_resid) && 201767362Smckusick (vp->v_flag & VROOT) && 201867362Smckusick (vp->v_mount->mnt_flag & MNT_UNION)) { 201967362Smckusick struct vnode *tvp = vp; 202067362Smckusick vp = vp->v_mount->mnt_vnodecovered; 202167362Smckusick VREF(vp); 202267362Smckusick fp->f_data = (caddr_t) vp; 202367362Smckusick fp->f_offset = 0; 202467362Smckusick vrele(tvp); 202567362Smckusick goto unionread; 202667362Smckusick } 202754969Smckusick error = copyout((caddr_t)&loff, (caddr_t)uap->basep, sizeof(long)); 202854620Smckusick *retval = uap->count - auio.uio_resid; 202954620Smckusick return (error); 203054620Smckusick } 203167362Smckusick #endif /* COMPAT_43 */ 203254620Smckusick 203354620Smckusick /* 203454620Smckusick * Read a block of directory entries in a file system independent format. 203554620Smckusick */ 203654916Storek struct getdirentries_args { 203754916Storek int fd; 203854916Storek char *buf; 203964410Sbostic u_int count; 204054916Storek long *basep; 204154916Storek }; 204242441Smckusick getdirentries(p, uap, retval) 204345914Smckusick struct proc *p; 204454916Storek register struct getdirentries_args *uap; 204542441Smckusick int *retval; 204642441Smckusick { 204739592Smckusick register struct vnode *vp; 204816540Ssam struct file *fp; 204937741Smckusick struct uio auio; 205037741Smckusick struct iovec aiov; 205154969Smckusick long loff; 205267362Smckusick int error, eofflag; 205312756Ssam 205445914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 205547540Skarels return (error); 205637741Smckusick if ((fp->f_flag & FREAD) == 0) 205747540Skarels return (EBADF); 205839592Smckusick vp = (struct vnode *)fp->f_data; 205955451Spendry unionread: 206039592Smckusick if (vp->v_type != VDIR) 206147540Skarels return (EINVAL); 206237741Smckusick aiov.iov_base = uap->buf; 206337741Smckusick aiov.iov_len = uap->count; 206437741Smckusick auio.uio_iov = &aiov; 206537741Smckusick auio.uio_iovcnt = 1; 206637741Smckusick auio.uio_rw = UIO_READ; 206737741Smckusick auio.uio_segflg = UIO_USERSPACE; 206848026Smckusick auio.uio_procp = p; 206937741Smckusick auio.uio_resid = uap->count; 207039592Smckusick VOP_LOCK(vp); 207154969Smckusick loff = auio.uio_offset = fp->f_offset; 207267362Smckusick error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, (u_long *)0, 0); 207339592Smckusick fp->f_offset = auio.uio_offset; 207439592Smckusick VOP_UNLOCK(vp); 207539592Smckusick if (error) 207647540Skarels return (error); 207766095Spendry 207866095Spendry #ifdef UNION 207966095Spendry { 208066095Spendry extern int (**union_vnodeop_p)(); 208166095Spendry extern struct vnode *union_lowervp __P((struct vnode *)); 208266095Spendry 208355451Spendry if ((uap->count == auio.uio_resid) && 208466095Spendry (vp->v_op == union_vnodeop_p)) { 208567122Spendry struct vnode *lvp; 208666095Spendry 208767122Spendry lvp = union_lowervp(vp); 208867122Spendry if (lvp != NULLVP) { 208967122Spendry VOP_LOCK(lvp); 209067362Smckusick error = VOP_OPEN(lvp, FREAD, fp->f_cred, p); 209167122Spendry VOP_UNLOCK(lvp); 209266095Spendry 209366095Spendry if (error) { 209467122Spendry vrele(lvp); 209566095Spendry return (error); 209666095Spendry } 209767122Spendry fp->f_data = (caddr_t) lvp; 209866095Spendry fp->f_offset = 0; 209967122Spendry error = vn_close(vp, FREAD, fp->f_cred, p); 210066095Spendry if (error) 210166095Spendry return (error); 210267122Spendry vp = lvp; 210366095Spendry goto unionread; 210466095Spendry } 210566095Spendry } 210666095Spendry } 210766095Spendry #endif 210866095Spendry 210966095Spendry if ((uap->count == auio.uio_resid) && 211055451Spendry (vp->v_flag & VROOT) && 211155451Spendry (vp->v_mount->mnt_flag & MNT_UNION)) { 211255451Spendry struct vnode *tvp = vp; 211355451Spendry vp = vp->v_mount->mnt_vnodecovered; 211455451Spendry VREF(vp); 211555451Spendry fp->f_data = (caddr_t) vp; 211655451Spendry fp->f_offset = 0; 211755451Spendry vrele(tvp); 211855451Spendry goto unionread; 211955451Spendry } 212054969Smckusick error = copyout((caddr_t)&loff, (caddr_t)uap->basep, sizeof(long)); 212142441Smckusick *retval = uap->count - auio.uio_resid; 212247540Skarels return (error); 212312756Ssam } 212412756Ssam 212512756Ssam /* 212649365Smckusick * Set the mode mask for creation of filesystem nodes. 212712756Ssam */ 212854916Storek struct umask_args { 212964410Sbostic int newmask; 213054916Storek }; 213154916Storek mode_t /* XXX */ 213242441Smckusick umask(p, uap, retval) 213345914Smckusick struct proc *p; 213454916Storek struct umask_args *uap; 213542441Smckusick int *retval; 213612756Ssam { 213764410Sbostic register struct filedesc *fdp; 213812756Ssam 213964410Sbostic fdp = p->p_fd; 214045914Smckusick *retval = fdp->fd_cmask; 214164410Sbostic fdp->fd_cmask = uap->newmask & ALLPERMS; 214247540Skarels return (0); 214312756Ssam } 214437741Smckusick 214539566Smarc /* 214639566Smarc * Void all references to file by ripping underlying filesystem 214739566Smarc * away from vnode. 214839566Smarc */ 214954916Storek struct revoke_args { 215064410Sbostic char *path; 215154916Storek }; 215242441Smckusick /* ARGSUSED */ 215342441Smckusick revoke(p, uap, retval) 215445914Smckusick struct proc *p; 215554916Storek register struct revoke_args *uap; 215642441Smckusick int *retval; 215742441Smckusick { 215839566Smarc register struct vnode *vp; 215939566Smarc struct vattr vattr; 216039566Smarc int error; 216147540Skarels struct nameidata nd; 216239566Smarc 216364410Sbostic NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); 216452322Smckusick if (error = namei(&nd)) 216547540Skarels return (error); 216652322Smckusick vp = nd.ni_vp; 216739566Smarc if (vp->v_type != VCHR && vp->v_type != VBLK) { 216839566Smarc error = EINVAL; 216939566Smarc goto out; 217039566Smarc } 217148026Smckusick if (error = VOP_GETATTR(vp, &vattr, p->p_ucred, p)) 217239566Smarc goto out; 217347540Skarels if (p->p_ucred->cr_uid != vattr.va_uid && 217447540Skarels (error = suser(p->p_ucred, &p->p_acflag))) 217539566Smarc goto out; 217639805Smckusick if (vp->v_usecount > 1 || (vp->v_flag & VALIASED)) 217739632Smckusick vgoneall(vp); 217839566Smarc out: 217939566Smarc vrele(vp); 218047540Skarels return (error); 218139566Smarc } 218239566Smarc 218349365Smckusick /* 218449365Smckusick * Convert a user file descriptor to a kernel file entry. 218549365Smckusick */ 218664410Sbostic getvnode(fdp, fd, fpp) 218745914Smckusick struct filedesc *fdp; 218837741Smckusick struct file **fpp; 218964410Sbostic int fd; 219037741Smckusick { 219137741Smckusick struct file *fp; 219237741Smckusick 219364410Sbostic if ((u_int)fd >= fdp->fd_nfiles || 219464410Sbostic (fp = fdp->fd_ofiles[fd]) == NULL) 219537741Smckusick return (EBADF); 219637741Smckusick if (fp->f_type != DTYPE_VNODE) 219737741Smckusick return (EINVAL); 219837741Smckusick *fpp = fp; 219937741Smckusick return (0); 220037741Smckusick } 2201