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*67575Spendry * @(#)vfs_syscalls.c 8.19 (Berkeley) 07/28/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; 5667532Smckusick 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); 8467532Smckusick /* 8567532Smckusick * Only root, or the user that did the original mount is 8667532Smckusick * permitted to update it. 8767532Smckusick */ 8867532Smckusick if (mp->mnt_stat.f_owner != p->p_ucred->cr_uid && 8967532Smckusick (error = suser(p->p_ucred, &p->p_acflag))) { 9067532Smckusick vput(vp); 9167532Smckusick return (error); 9267532Smckusick } 9367532Smckusick /* 9467532Smckusick * Do not allow NFS export by non-root users. Silently 9567532Smckusick * enforce MNT_NOSUID and MNT_NODEV for non-root users. 9667532Smckusick */ 9767532Smckusick if (p->p_ucred->cr_uid != 0) { 9867532Smckusick if (uap->flags & MNT_EXPORTED) { 9967532Smckusick vput(vp); 10067532Smckusick return (EPERM); 10167532Smckusick } 10267532Smckusick uap->flags |= MNT_NOSUID | MNT_NODEV; 10367532Smckusick } 10439335Smckusick VOP_UNLOCK(vp); 10539335Smckusick goto update; 10639335Smckusick } 10767532Smckusick /* 10867532Smckusick * If the user is not root, ensure that they own the directory 10967532Smckusick * onto which we are attempting to mount. 11067532Smckusick */ 11167532Smckusick if ((error = VOP_GETATTR(vp, &va, p->p_ucred, p)) || 11267532Smckusick (va.va_uid != p->p_ucred->cr_uid && 11367532Smckusick (error = suser(p->p_ucred, &p->p_acflag)))) { 11467532Smckusick vput(vp); 11567532Smckusick return (error); 11667532Smckusick } 11767532Smckusick /* 11867532Smckusick * Do not allow NFS export by non-root users. Silently 11967532Smckusick * enforce MNT_NOSUID and MNT_NODEV for non-root users. 12067532Smckusick */ 12167532Smckusick if (p->p_ucred->cr_uid != 0) { 12267532Smckusick if (uap->flags & MNT_EXPORTED) { 12367532Smckusick vput(vp); 12467532Smckusick return (EPERM); 12567532Smckusick } 12667532Smckusick uap->flags |= MNT_NOSUID | MNT_NODEV; 12767532Smckusick } 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; 15967532Smckusick 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; 22967532Smckusick mp = vp->v_mount; 23066172Spendry 23137741Smckusick /* 23267532Smckusick * Only root, or the user that did the original mount is 23367532Smckusick * permitted to unmount this filesystem. 23466172Spendry */ 23567532Smckusick 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; 692*67575Spendry int whiteout; 69347540Skarels struct nameidata nd; 6946254Sroot 69547540Skarels if (error = suser(p->p_ucred, &p->p_acflag)) 69647540Skarels return (error); 69764410Sbostic NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->path, p); 69852322Smckusick if (error = namei(&nd)) 69947540Skarels return (error); 70052322Smckusick vp = nd.ni_vp; 70164585Sbostic if (vp != NULL) 70237741Smckusick error = EEXIST; 70364585Sbostic else { 70464585Sbostic VATTR_NULL(&vattr); 70564585Sbostic vattr.va_mode = (uap->mode & ALLPERMS) &~ p->p_fd->fd_cmask; 70664585Sbostic vattr.va_rdev = uap->dev; 707*67575Spendry whiteout = 0; 70864585Sbostic 70964585Sbostic switch (uap->mode & S_IFMT) { 71064585Sbostic case S_IFMT: /* used by badsect to flag bad sectors */ 71164585Sbostic vattr.va_type = VBAD; 71264585Sbostic break; 71364585Sbostic case S_IFCHR: 71464585Sbostic vattr.va_type = VCHR; 71564585Sbostic break; 71664585Sbostic case S_IFBLK: 71764585Sbostic vattr.va_type = VBLK; 71864585Sbostic break; 719*67575Spendry case S_IFWHT: 720*67575Spendry whiteout = 1; 721*67575Spendry break; 72264585Sbostic default: 72364585Sbostic error = EINVAL; 72464585Sbostic break; 72564585Sbostic } 7266254Sroot } 727*67575Spendry if (whiteout) { 728*67575Spendry error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, CREATE); 729*67575Spendry vput(nd.ni_dvp); 730*67575Spendry } else if (!error) { 73152322Smckusick LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 73252322Smckusick error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr); 73342465Smckusick } else { 73452322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 73552322Smckusick if (nd.ni_dvp == vp) 73652322Smckusick vrele(nd.ni_dvp); 73743344Smckusick else 73852322Smckusick vput(nd.ni_dvp); 73942465Smckusick if (vp) 74042465Smckusick vrele(vp); 74142465Smckusick } 74247540Skarels return (error); 7436254Sroot } 7446254Sroot 7456254Sroot /* 74664410Sbostic * Create named pipe. 74740285Smckusick */ 74854916Storek struct mkfifo_args { 74964410Sbostic char *path; 75064410Sbostic int mode; 75154916Storek }; 75242441Smckusick /* ARGSUSED */ 75342441Smckusick mkfifo(p, uap, retval) 75445914Smckusick struct proc *p; 75554916Storek register struct mkfifo_args *uap; 75642441Smckusick int *retval; 75742441Smckusick { 75840285Smckusick struct vattr vattr; 75940285Smckusick int error; 76047540Skarels struct nameidata nd; 76140285Smckusick 76240285Smckusick #ifndef FIFO 76347540Skarels return (EOPNOTSUPP); 76440285Smckusick #else 76564410Sbostic NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->path, p); 76652322Smckusick if (error = namei(&nd)) 76747540Skarels return (error); 76852322Smckusick if (nd.ni_vp != NULL) { 76952322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 77052322Smckusick if (nd.ni_dvp == nd.ni_vp) 77152322Smckusick vrele(nd.ni_dvp); 77243344Smckusick else 77352322Smckusick vput(nd.ni_dvp); 77452322Smckusick vrele(nd.ni_vp); 77547540Skarels return (EEXIST); 77640285Smckusick } 77745785Sbostic VATTR_NULL(&vattr); 77845785Sbostic vattr.va_type = VFIFO; 77964410Sbostic vattr.va_mode = (uap->mode & ALLPERMS) &~ p->p_fd->fd_cmask; 78052322Smckusick LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 78152322Smckusick return (VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr)); 78240285Smckusick #endif /* FIFO */ 78340285Smckusick } 78440285Smckusick 78540285Smckusick /* 78664410Sbostic * Make a hard file link. 7876254Sroot */ 78854916Storek struct link_args { 78964410Sbostic char *path; 79064410Sbostic char *link; 79154916Storek }; 79242441Smckusick /* ARGSUSED */ 79342441Smckusick link(p, uap, retval) 79445914Smckusick struct proc *p; 79554916Storek register struct link_args *uap; 79642441Smckusick int *retval; 79742441Smckusick { 79864410Sbostic register struct vnode *vp; 79964410Sbostic struct nameidata nd; 80037741Smckusick int error; 8016254Sroot 80264410Sbostic NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); 80352322Smckusick if (error = namei(&nd)) 80447540Skarels return (error); 80552322Smckusick vp = nd.ni_vp; 80664585Sbostic if (vp->v_type != VDIR || 80764585Sbostic (error = suser(p->p_ucred, &p->p_acflag)) == 0) { 80864585Sbostic nd.ni_cnd.cn_nameiop = CREATE; 80964585Sbostic nd.ni_cnd.cn_flags = LOCKPARENT; 81064585Sbostic nd.ni_dirp = uap->link; 81164585Sbostic if ((error = namei(&nd)) == 0) { 81264585Sbostic if (nd.ni_vp != NULL) 81364585Sbostic error = EEXIST; 81464585Sbostic if (!error) { 81564585Sbostic LEASE_CHECK(nd.ni_dvp, 81664585Sbostic p, p->p_ucred, LEASE_WRITE); 81764585Sbostic LEASE_CHECK(vp, 81864585Sbostic p, p->p_ucred, LEASE_WRITE); 81964585Sbostic error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd); 82064585Sbostic } else { 82164585Sbostic VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 82264585Sbostic if (nd.ni_dvp == nd.ni_vp) 82364585Sbostic vrele(nd.ni_dvp); 82464585Sbostic else 82564585Sbostic vput(nd.ni_dvp); 82664585Sbostic if (nd.ni_vp) 82764585Sbostic vrele(nd.ni_vp); 82864585Sbostic } 82964585Sbostic } 83042465Smckusick } 83164585Sbostic vrele(vp); 83247540Skarels return (error); 8336254Sroot } 8346254Sroot 8356254Sroot /* 83649365Smckusick * Make a symbolic link. 8376254Sroot */ 83854916Storek struct symlink_args { 83964410Sbostic char *path; 84064410Sbostic char *link; 84154916Storek }; 84242441Smckusick /* ARGSUSED */ 84342441Smckusick symlink(p, uap, retval) 84445914Smckusick struct proc *p; 84554916Storek register struct symlink_args *uap; 84642441Smckusick int *retval; 84742441Smckusick { 84837741Smckusick struct vattr vattr; 84964410Sbostic char *path; 85037741Smckusick int error; 85147540Skarels struct nameidata nd; 8526254Sroot 85364410Sbostic MALLOC(path, char *, MAXPATHLEN, M_NAMEI, M_WAITOK); 85464410Sbostic if (error = copyinstr(uap->path, path, MAXPATHLEN, NULL)) 85542465Smckusick goto out; 85664410Sbostic NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->link, p); 85752322Smckusick if (error = namei(&nd)) 85842465Smckusick goto out; 85952322Smckusick if (nd.ni_vp) { 86052322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 86152322Smckusick if (nd.ni_dvp == nd.ni_vp) 86252322Smckusick vrele(nd.ni_dvp); 86343344Smckusick else 86452322Smckusick vput(nd.ni_dvp); 86552322Smckusick vrele(nd.ni_vp); 86637741Smckusick error = EEXIST; 86737741Smckusick goto out; 8686254Sroot } 86941362Smckusick VATTR_NULL(&vattr); 87064410Sbostic vattr.va_mode = ACCESSPERMS &~ p->p_fd->fd_cmask; 87152322Smckusick LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 87264410Sbostic error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr, path); 87337741Smckusick out: 87464410Sbostic FREE(path, M_NAMEI); 87547540Skarels return (error); 8766254Sroot } 8776254Sroot 8786254Sroot /* 87967518Spendry * Delete a whiteout from the filesystem. 88067518Spendry */ 88167518Spendry struct unwhiteout_args { 88267518Spendry char *path; 88367518Spendry }; 88467518Spendry /* ARGSUSED */ 88567518Spendry unwhiteout(p, uap, retval) 88667518Spendry struct proc *p; 88767518Spendry struct unwhiteout_args *uap; 88867518Spendry int *retval; 88967518Spendry { 89067518Spendry int error; 89167518Spendry struct nameidata nd; 89267518Spendry 893*67575Spendry NDINIT(&nd, DELETE, LOCKPARENT|DOWHITEOUT, UIO_USERSPACE, uap->path, p); 894*67575Spendry error = namei(&nd); 895*67575Spendry if (error) 89667518Spendry return (error); 897*67575Spendry 898*67575Spendry if (nd.ni_vp != NULLVP || !(nd.ni_cnd.cn_flags & ISWHITEOUT)) { 89967518Spendry VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 90067518Spendry if (nd.ni_dvp == nd.ni_vp) 90167518Spendry vrele(nd.ni_dvp); 90267518Spendry else 90367518Spendry vput(nd.ni_dvp); 90467518Spendry if (nd.ni_vp) 90567518Spendry vrele(nd.ni_vp); 90667518Spendry return (EEXIST); 90767518Spendry } 908*67575Spendry 90967518Spendry LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 91067518Spendry error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, DELETE); 911*67575Spendry if (error != 0) 912*67575Spendry VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 91367518Spendry vput(nd.ni_dvp); 91467518Spendry return (error); 91567518Spendry } 91667518Spendry 91767518Spendry /* 91849365Smckusick * Delete a name from the filesystem. 9196254Sroot */ 92054916Storek struct unlink_args { 92164410Sbostic char *path; 92254916Storek }; 92342441Smckusick /* ARGSUSED */ 92442441Smckusick unlink(p, uap, retval) 92545914Smckusick struct proc *p; 92654916Storek struct unlink_args *uap; 92742441Smckusick int *retval; 9286254Sroot { 92937741Smckusick register struct vnode *vp; 93037741Smckusick int error; 93147540Skarels struct nameidata nd; 9326254Sroot 93364410Sbostic NDINIT(&nd, DELETE, LOCKPARENT, UIO_USERSPACE, uap->path, p); 93452322Smckusick if (error = namei(&nd)) 93547540Skarels return (error); 93652322Smckusick vp = nd.ni_vp; 93759382Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 93859382Smckusick VOP_LOCK(vp); 93964410Sbostic 94064585Sbostic if (vp->v_type != VDIR || 94164585Sbostic (error = suser(p->p_ucred, &p->p_acflag)) == 0) { 94264585Sbostic /* 94364585Sbostic * The root of a mounted filesystem cannot be deleted. 94464585Sbostic */ 94564585Sbostic if (vp->v_flag & VROOT) 94664585Sbostic error = EBUSY; 94764585Sbostic else 94864585Sbostic (void)vnode_pager_uncache(vp); 94964585Sbostic } 95064585Sbostic 95164585Sbostic if (!error) { 95252322Smckusick LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 95352322Smckusick error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); 95442465Smckusick } else { 95552322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 95652322Smckusick if (nd.ni_dvp == vp) 95752322Smckusick vrele(nd.ni_dvp); 95843344Smckusick else 95952322Smckusick vput(nd.ni_dvp); 960*67575Spendry if (vp != NULLVP) 961*67575Spendry vput(vp); 96242465Smckusick } 96347540Skarels return (error); 9646254Sroot } 9656254Sroot 96664410Sbostic /* 96764410Sbostic * Reposition read/write file offset. 96864410Sbostic */ 96960428Smckusick struct lseek_args { 97064410Sbostic int fd; 97154863Storek int pad; 97264410Sbostic off_t offset; 97364410Sbostic int whence; 97454863Storek }; 97560414Smckusick lseek(p, uap, retval) 97653468Smckusick struct proc *p; 97760428Smckusick register struct lseek_args *uap; 97854916Storek int *retval; 97942441Smckusick { 98047540Skarels struct ucred *cred = p->p_ucred; 98145914Smckusick register struct filedesc *fdp = p->p_fd; 98242441Smckusick register struct file *fp; 98337741Smckusick struct vattr vattr; 98437741Smckusick int error; 9856254Sroot 98664410Sbostic if ((u_int)uap->fd >= fdp->fd_nfiles || 98764410Sbostic (fp = fdp->fd_ofiles[uap->fd]) == NULL) 98847540Skarels return (EBADF); 98937741Smckusick if (fp->f_type != DTYPE_VNODE) 99047540Skarels return (ESPIPE); 99164410Sbostic switch (uap->whence) { 99213878Ssam case L_INCR: 99364410Sbostic fp->f_offset += uap->offset; 99413878Ssam break; 99513878Ssam case L_XTND: 99664410Sbostic if (error = 99764410Sbostic VOP_GETATTR((struct vnode *)fp->f_data, &vattr, cred, p)) 99847540Skarels return (error); 99964410Sbostic fp->f_offset = uap->offset + vattr.va_size; 100013878Ssam break; 100113878Ssam case L_SET: 100264410Sbostic fp->f_offset = uap->offset; 100313878Ssam break; 100413878Ssam default: 100547540Skarels return (EINVAL); 100613878Ssam } 100754916Storek *(off_t *)retval = fp->f_offset; 100847540Skarels return (0); 10096254Sroot } 10106254Sroot 101160414Smckusick #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 10126254Sroot /* 101364410Sbostic * Reposition read/write file offset. 101460036Smckusick */ 101560428Smckusick struct olseek_args { 101664410Sbostic int fd; 101764410Sbostic long offset; 101864410Sbostic int whence; 101960036Smckusick }; 102060414Smckusick olseek(p, uap, retval) 102160036Smckusick struct proc *p; 102260428Smckusick register struct olseek_args *uap; 102360036Smckusick int *retval; 102460036Smckusick { 102560428Smckusick struct lseek_args nuap; 102660036Smckusick off_t qret; 102760036Smckusick int error; 102860036Smckusick 102964410Sbostic nuap.fd = uap->fd; 103064410Sbostic nuap.offset = uap->offset; 103164410Sbostic nuap.whence = uap->whence; 103260428Smckusick error = lseek(p, &nuap, &qret); 103360036Smckusick *(long *)retval = qret; 103460036Smckusick return (error); 103560036Smckusick } 103660414Smckusick #endif /* COMPAT_43 */ 103760036Smckusick 103860036Smckusick /* 103949365Smckusick * Check access permissions. 10406254Sroot */ 104163427Sbostic struct access_args { 104264410Sbostic char *path; 104364410Sbostic int flags; 104454916Storek }; 104563427Sbostic access(p, uap, retval) 104645914Smckusick struct proc *p; 104763427Sbostic register struct access_args *uap; 104842441Smckusick int *retval; 104942441Smckusick { 105047540Skarels register struct ucred *cred = p->p_ucred; 105137741Smckusick register struct vnode *vp; 105264585Sbostic int error, flags, t_gid, t_uid; 105347540Skarels struct nameidata nd; 10546254Sroot 105564585Sbostic t_uid = cred->cr_uid; 105664585Sbostic t_gid = cred->cr_groups[0]; 105747540Skarels cred->cr_uid = p->p_cred->p_ruid; 105847540Skarels cred->cr_groups[0] = p->p_cred->p_rgid; 105964410Sbostic NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); 106052322Smckusick if (error = namei(&nd)) 106137741Smckusick goto out1; 106252322Smckusick vp = nd.ni_vp; 106364410Sbostic 106464410Sbostic /* Flags == 0 means only check for existence. */ 106564410Sbostic if (uap->flags) { 106664410Sbostic flags = 0; 106764410Sbostic if (uap->flags & R_OK) 106864410Sbostic flags |= VREAD; 106964410Sbostic if (uap->flags & W_OK) 107064410Sbostic flags |= VWRITE; 107164410Sbostic if (uap->flags & X_OK) 107264410Sbostic flags |= VEXEC; 107364410Sbostic if ((flags & VWRITE) == 0 || (error = vn_writechk(vp)) == 0) 107464410Sbostic error = VOP_ACCESS(vp, flags, cred, p); 10756254Sroot } 107637741Smckusick vput(vp); 107737741Smckusick out1: 107864585Sbostic cred->cr_uid = t_uid; 107964585Sbostic cred->cr_groups[0] = t_gid; 108047540Skarels return (error); 10816254Sroot } 10826254Sroot 108354348Smckusick #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 10846254Sroot /* 108564410Sbostic * Get file status; this version follows links. 108637Sbill */ 108754916Storek struct ostat_args { 108864410Sbostic char *path; 108954916Storek struct ostat *ub; 109054916Storek }; 109142441Smckusick /* ARGSUSED */ 109253759Smckusick ostat(p, uap, retval) 109345914Smckusick struct proc *p; 109454916Storek register struct ostat_args *uap; 109553468Smckusick int *retval; 109653468Smckusick { 109753468Smckusick struct stat sb; 109853468Smckusick struct ostat osb; 109953468Smckusick int error; 110053468Smckusick struct nameidata nd; 110153468Smckusick 110264410Sbostic NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); 110353468Smckusick if (error = namei(&nd)) 110453468Smckusick return (error); 110553468Smckusick error = vn_stat(nd.ni_vp, &sb, p); 110653468Smckusick vput(nd.ni_vp); 110753468Smckusick if (error) 110853468Smckusick return (error); 110953468Smckusick cvtstat(&sb, &osb); 111053468Smckusick error = copyout((caddr_t)&osb, (caddr_t)uap->ub, sizeof (osb)); 111153468Smckusick return (error); 111253468Smckusick } 111353468Smckusick 111453468Smckusick /* 111564410Sbostic * Get file status; this version does not follow links. 111653468Smckusick */ 111754916Storek struct olstat_args { 111864410Sbostic char *path; 111954916Storek struct ostat *ub; 112054916Storek }; 112153468Smckusick /* ARGSUSED */ 112253759Smckusick olstat(p, uap, retval) 112353468Smckusick struct proc *p; 112454916Storek register struct olstat_args *uap; 112553468Smckusick int *retval; 112653468Smckusick { 112753468Smckusick struct stat sb; 112853468Smckusick struct ostat osb; 112953468Smckusick int error; 113053468Smckusick struct nameidata nd; 113153468Smckusick 113264410Sbostic NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); 113353468Smckusick if (error = namei(&nd)) 113453468Smckusick return (error); 113553468Smckusick error = vn_stat(nd.ni_vp, &sb, p); 113653468Smckusick vput(nd.ni_vp); 113753468Smckusick if (error) 113853468Smckusick return (error); 113953468Smckusick cvtstat(&sb, &osb); 114053468Smckusick error = copyout((caddr_t)&osb, (caddr_t)uap->ub, sizeof (osb)); 114153468Smckusick return (error); 114253468Smckusick } 114353468Smckusick 114453468Smckusick /* 114564410Sbostic * Convert from an old to a new stat structure. 114653468Smckusick */ 114753468Smckusick cvtstat(st, ost) 114853468Smckusick struct stat *st; 114953468Smckusick struct ostat *ost; 115053468Smckusick { 115153468Smckusick 115253468Smckusick ost->st_dev = st->st_dev; 115353468Smckusick ost->st_ino = st->st_ino; 115453468Smckusick ost->st_mode = st->st_mode; 115553468Smckusick ost->st_nlink = st->st_nlink; 115653468Smckusick ost->st_uid = st->st_uid; 115753468Smckusick ost->st_gid = st->st_gid; 115853468Smckusick ost->st_rdev = st->st_rdev; 115953468Smckusick if (st->st_size < (quad_t)1 << 32) 116053468Smckusick ost->st_size = st->st_size; 116153468Smckusick else 116253468Smckusick ost->st_size = -2; 116353468Smckusick ost->st_atime = st->st_atime; 116453468Smckusick ost->st_mtime = st->st_mtime; 116553468Smckusick ost->st_ctime = st->st_ctime; 116653468Smckusick ost->st_blksize = st->st_blksize; 116753468Smckusick ost->st_blocks = st->st_blocks; 116853468Smckusick ost->st_flags = st->st_flags; 116953468Smckusick ost->st_gen = st->st_gen; 117053468Smckusick } 117154348Smckusick #endif /* COMPAT_43 || COMPAT_SUNOS */ 117253468Smckusick 117353468Smckusick /* 117464410Sbostic * Get file status; this version follows links. 117553468Smckusick */ 117654916Storek struct stat_args { 117764410Sbostic char *path; 117854916Storek struct stat *ub; 117954916Storek }; 118053468Smckusick /* ARGSUSED */ 118153759Smckusick stat(p, uap, retval) 118253468Smckusick struct proc *p; 118354916Storek register struct stat_args *uap; 118442441Smckusick int *retval; 118537Sbill { 118642441Smckusick struct stat sb; 118742441Smckusick int error; 118847540Skarels struct nameidata nd; 118937Sbill 119064410Sbostic NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); 119152322Smckusick if (error = namei(&nd)) 119247540Skarels return (error); 119352322Smckusick error = vn_stat(nd.ni_vp, &sb, p); 119452322Smckusick vput(nd.ni_vp); 119542441Smckusick if (error) 119647540Skarels return (error); 119742441Smckusick error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb)); 119847540Skarels return (error); 119937Sbill } 120037Sbill 120137Sbill /* 120264410Sbostic * Get file status; this version does not follow links. 12035992Swnj */ 120454916Storek struct lstat_args { 120564410Sbostic char *path; 120654916Storek struct stat *ub; 120754916Storek }; 120842441Smckusick /* ARGSUSED */ 120953759Smckusick lstat(p, uap, retval) 121045914Smckusick struct proc *p; 121154916Storek register struct lstat_args *uap; 121242441Smckusick int *retval; 121342441Smckusick { 121437741Smckusick int error; 121559373Smckusick struct vnode *vp, *dvp; 121659373Smckusick struct stat sb, sb1; 121747540Skarels struct nameidata nd; 12185992Swnj 121959373Smckusick NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | LOCKPARENT, UIO_USERSPACE, 122064410Sbostic uap->path, p); 122152322Smckusick if (error = namei(&nd)) 122247540Skarels return (error); 122359373Smckusick /* 122459373Smckusick * For symbolic links, always return the attributes of its 122559373Smckusick * containing directory, except for mode, size, and links. 122659373Smckusick */ 122759373Smckusick vp = nd.ni_vp; 122859373Smckusick dvp = nd.ni_dvp; 122959373Smckusick if (vp->v_type != VLNK) { 123059373Smckusick if (dvp == vp) 123159373Smckusick vrele(dvp); 123259373Smckusick else 123359373Smckusick vput(dvp); 123459373Smckusick error = vn_stat(vp, &sb, p); 123559373Smckusick vput(vp); 123659373Smckusick if (error) 123759373Smckusick return (error); 123859373Smckusick } else { 123959373Smckusick error = vn_stat(dvp, &sb, p); 124059373Smckusick vput(dvp); 124159373Smckusick if (error) { 124259373Smckusick vput(vp); 124359373Smckusick return (error); 124459373Smckusick } 124559373Smckusick error = vn_stat(vp, &sb1, p); 124659373Smckusick vput(vp); 124759373Smckusick if (error) 124859373Smckusick return (error); 124959373Smckusick sb.st_mode &= ~S_IFDIR; 125059373Smckusick sb.st_mode |= S_IFLNK; 125159373Smckusick sb.st_nlink = sb1.st_nlink; 125259373Smckusick sb.st_size = sb1.st_size; 125359373Smckusick sb.st_blocks = sb1.st_blocks; 125459373Smckusick } 125537741Smckusick error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb)); 125647540Skarels return (error); 12575992Swnj } 12585992Swnj 12595992Swnj /* 126064410Sbostic * Get configurable pathname variables. 126160414Smckusick */ 126260414Smckusick struct pathconf_args { 126364410Sbostic char *path; 126460414Smckusick int name; 126560414Smckusick }; 126660414Smckusick /* ARGSUSED */ 126760414Smckusick pathconf(p, uap, retval) 126860414Smckusick struct proc *p; 126960414Smckusick register struct pathconf_args *uap; 127060414Smckusick int *retval; 127160414Smckusick { 127260414Smckusick int error; 127360414Smckusick struct nameidata nd; 127460414Smckusick 127564410Sbostic NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); 127660414Smckusick if (error = namei(&nd)) 127760414Smckusick return (error); 127860414Smckusick error = VOP_PATHCONF(nd.ni_vp, uap->name, retval); 127960414Smckusick vput(nd.ni_vp); 128060414Smckusick return (error); 128160414Smckusick } 128260414Smckusick 128360414Smckusick /* 128449365Smckusick * Return target name of a symbolic link. 128537Sbill */ 128654916Storek struct readlink_args { 128764410Sbostic char *path; 128854916Storek char *buf; 128954916Storek int count; 129054916Storek }; 129142441Smckusick /* ARGSUSED */ 129242441Smckusick readlink(p, uap, retval) 129345914Smckusick struct proc *p; 129454916Storek register struct readlink_args *uap; 129542441Smckusick int *retval; 129642441Smckusick { 129737741Smckusick register struct vnode *vp; 129837741Smckusick struct iovec aiov; 129937741Smckusick struct uio auio; 130037741Smckusick int error; 130147540Skarels struct nameidata nd; 13025992Swnj 130364410Sbostic NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); 130452322Smckusick if (error = namei(&nd)) 130547540Skarels return (error); 130652322Smckusick vp = nd.ni_vp; 130764410Sbostic if (vp->v_type != VLNK) 130837741Smckusick error = EINVAL; 130964410Sbostic else { 131064410Sbostic aiov.iov_base = uap->buf; 131164410Sbostic aiov.iov_len = uap->count; 131264410Sbostic auio.uio_iov = &aiov; 131364410Sbostic auio.uio_iovcnt = 1; 131464410Sbostic auio.uio_offset = 0; 131564410Sbostic auio.uio_rw = UIO_READ; 131664410Sbostic auio.uio_segflg = UIO_USERSPACE; 131764410Sbostic auio.uio_procp = p; 131864410Sbostic auio.uio_resid = uap->count; 131964410Sbostic error = VOP_READLINK(vp, &auio, p->p_ucred); 13205992Swnj } 132137741Smckusick vput(vp); 132242441Smckusick *retval = uap->count - auio.uio_resid; 132347540Skarels return (error); 13245992Swnj } 13255992Swnj 13269167Ssam /* 132764410Sbostic * Change flags of a file given a path name. 132838259Smckusick */ 132954916Storek struct chflags_args { 133064410Sbostic char *path; 133154916Storek int flags; 133254916Storek }; 133342441Smckusick /* ARGSUSED */ 133442441Smckusick chflags(p, uap, retval) 133545914Smckusick struct proc *p; 133654916Storek register struct chflags_args *uap; 133742441Smckusick int *retval; 133842441Smckusick { 133938259Smckusick register struct vnode *vp; 134038259Smckusick struct vattr vattr; 134138259Smckusick int error; 134247540Skarels struct nameidata nd; 134338259Smckusick 134464410Sbostic NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); 134552322Smckusick if (error = namei(&nd)) 134647540Skarels return (error); 134752322Smckusick vp = nd.ni_vp; 134859382Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 134959382Smckusick VOP_LOCK(vp); 135064410Sbostic if (vp->v_mount->mnt_flag & MNT_RDONLY) 135138259Smckusick error = EROFS; 135264410Sbostic else { 135364410Sbostic VATTR_NULL(&vattr); 135464410Sbostic vattr.va_flags = uap->flags; 135564410Sbostic error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 135638259Smckusick } 135738259Smckusick vput(vp); 135847540Skarels return (error); 135938259Smckusick } 136038259Smckusick 136138259Smckusick /* 136238259Smckusick * Change flags of a file given a file descriptor. 136338259Smckusick */ 136454916Storek struct fchflags_args { 136554916Storek int fd; 136654916Storek int flags; 136754916Storek }; 136842441Smckusick /* ARGSUSED */ 136942441Smckusick fchflags(p, uap, retval) 137045914Smckusick struct proc *p; 137154916Storek register struct fchflags_args *uap; 137242441Smckusick int *retval; 137342441Smckusick { 137438259Smckusick struct vattr vattr; 137538259Smckusick struct vnode *vp; 137638259Smckusick struct file *fp; 137738259Smckusick int error; 137838259Smckusick 137945914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 138047540Skarels return (error); 138138259Smckusick vp = (struct vnode *)fp->f_data; 138259382Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 138338259Smckusick VOP_LOCK(vp); 138464410Sbostic if (vp->v_mount->mnt_flag & MNT_RDONLY) 138538259Smckusick error = EROFS; 138664410Sbostic else { 138764410Sbostic VATTR_NULL(&vattr); 138864410Sbostic vattr.va_flags = uap->flags; 138964410Sbostic error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 139038259Smckusick } 139138259Smckusick VOP_UNLOCK(vp); 139247540Skarels return (error); 139338259Smckusick } 139438259Smckusick 139538259Smckusick /* 13969167Ssam * Change mode of a file given path name. 13979167Ssam */ 139854916Storek struct chmod_args { 139964410Sbostic char *path; 140064410Sbostic int mode; 140154916Storek }; 140242441Smckusick /* ARGSUSED */ 140342441Smckusick chmod(p, uap, retval) 140445914Smckusick struct proc *p; 140554916Storek register struct chmod_args *uap; 140642441Smckusick int *retval; 140742441Smckusick { 140837741Smckusick register struct vnode *vp; 140937741Smckusick struct vattr vattr; 141037741Smckusick int error; 141147540Skarels struct nameidata nd; 14125992Swnj 141364410Sbostic NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); 141452322Smckusick if (error = namei(&nd)) 141547540Skarels return (error); 141652322Smckusick vp = nd.ni_vp; 141759382Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 141859382Smckusick VOP_LOCK(vp); 141964410Sbostic if (vp->v_mount->mnt_flag & MNT_RDONLY) 142037741Smckusick error = EROFS; 142164410Sbostic else { 142264410Sbostic VATTR_NULL(&vattr); 142364410Sbostic vattr.va_mode = uap->mode & ALLPERMS; 142464410Sbostic error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 142537741Smckusick } 142637741Smckusick vput(vp); 142747540Skarels return (error); 14287701Ssam } 14297439Sroot 14309167Ssam /* 14319167Ssam * Change mode of a file given a file descriptor. 14329167Ssam */ 143354916Storek struct fchmod_args { 143454916Storek int fd; 143564410Sbostic int mode; 143654916Storek }; 143742441Smckusick /* ARGSUSED */ 143842441Smckusick fchmod(p, uap, retval) 143945914Smckusick struct proc *p; 144054916Storek register struct fchmod_args *uap; 144142441Smckusick int *retval; 144242441Smckusick { 144337741Smckusick struct vattr vattr; 144437741Smckusick struct vnode *vp; 144537741Smckusick struct file *fp; 144637741Smckusick int error; 14477701Ssam 144845914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 144947540Skarels return (error); 145037741Smckusick vp = (struct vnode *)fp->f_data; 145159382Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 145237741Smckusick VOP_LOCK(vp); 145364410Sbostic if (vp->v_mount->mnt_flag & MNT_RDONLY) 145437741Smckusick error = EROFS; 145564410Sbostic else { 145664410Sbostic VATTR_NULL(&vattr); 145764410Sbostic vattr.va_mode = uap->mode & ALLPERMS; 145864410Sbostic error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 14597439Sroot } 146037741Smckusick VOP_UNLOCK(vp); 146147540Skarels return (error); 14625992Swnj } 14635992Swnj 14649167Ssam /* 14659167Ssam * Set ownership given a path name. 14669167Ssam */ 146754916Storek struct chown_args { 146864410Sbostic char *path; 146954916Storek int uid; 147054916Storek int gid; 147154916Storek }; 147242441Smckusick /* ARGSUSED */ 147342441Smckusick chown(p, uap, retval) 147445914Smckusick struct proc *p; 147554916Storek register struct chown_args *uap; 147642441Smckusick int *retval; 147742441Smckusick { 147837741Smckusick register struct vnode *vp; 147937741Smckusick struct vattr vattr; 148037741Smckusick int error; 148147540Skarels struct nameidata nd; 148237Sbill 148366510Sbostic NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); 148452322Smckusick if (error = namei(&nd)) 148547540Skarels return (error); 148652322Smckusick vp = nd.ni_vp; 148759382Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 148859382Smckusick VOP_LOCK(vp); 148964410Sbostic if (vp->v_mount->mnt_flag & MNT_RDONLY) 149037741Smckusick error = EROFS; 149164410Sbostic else { 149264410Sbostic VATTR_NULL(&vattr); 149364410Sbostic vattr.va_uid = uap->uid; 149464410Sbostic vattr.va_gid = uap->gid; 149564410Sbostic error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 149637741Smckusick } 149737741Smckusick vput(vp); 149847540Skarels return (error); 14997701Ssam } 15007439Sroot 15019167Ssam /* 15029167Ssam * Set ownership given a file descriptor. 15039167Ssam */ 150454916Storek struct fchown_args { 150554916Storek int fd; 150654916Storek int uid; 150754916Storek int gid; 150854916Storek }; 150942441Smckusick /* ARGSUSED */ 151042441Smckusick fchown(p, uap, retval) 151145914Smckusick struct proc *p; 151254916Storek register struct fchown_args *uap; 151342441Smckusick int *retval; 151442441Smckusick { 151537741Smckusick struct vattr vattr; 151637741Smckusick struct vnode *vp; 151737741Smckusick struct file *fp; 151837741Smckusick int error; 15197701Ssam 152045914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 152147540Skarels return (error); 152237741Smckusick vp = (struct vnode *)fp->f_data; 152359382Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 152437741Smckusick VOP_LOCK(vp); 152564410Sbostic if (vp->v_mount->mnt_flag & MNT_RDONLY) 152637741Smckusick error = EROFS; 152764410Sbostic else { 152864410Sbostic VATTR_NULL(&vattr); 152964410Sbostic vattr.va_uid = uap->uid; 153064410Sbostic vattr.va_gid = uap->gid; 153164410Sbostic error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 153237741Smckusick } 153337741Smckusick VOP_UNLOCK(vp); 153447540Skarels return (error); 15357701Ssam } 15367701Ssam 153742441Smckusick /* 153842441Smckusick * Set the access and modification times of a file. 153942441Smckusick */ 154054916Storek struct utimes_args { 154164410Sbostic char *path; 154254916Storek struct timeval *tptr; 154354916Storek }; 154442441Smckusick /* ARGSUSED */ 154542441Smckusick utimes(p, uap, retval) 154645914Smckusick struct proc *p; 154754916Storek register struct utimes_args *uap; 154842441Smckusick int *retval; 154942441Smckusick { 155037741Smckusick register struct vnode *vp; 155111811Ssam struct timeval tv[2]; 155237741Smckusick struct vattr vattr; 155358840Storek int error; 155447540Skarels struct nameidata nd; 155511811Ssam 155658505Sbostic VATTR_NULL(&vattr); 155758505Sbostic if (uap->tptr == NULL) { 155858505Sbostic microtime(&tv[0]); 155958505Sbostic tv[1] = tv[0]; 156058548Sbostic vattr.va_vaflags |= VA_UTIMES_NULL; 156158505Sbostic } else if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv))) 156258505Sbostic return (error); 156364410Sbostic NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); 156452322Smckusick if (error = namei(&nd)) 156547540Skarels return (error); 156652322Smckusick vp = nd.ni_vp; 156759382Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 156859382Smckusick VOP_LOCK(vp); 156964410Sbostic if (vp->v_mount->mnt_flag & MNT_RDONLY) 157037741Smckusick error = EROFS; 157164410Sbostic else { 157264410Sbostic vattr.va_atime.ts_sec = tv[0].tv_sec; 157364410Sbostic vattr.va_atime.ts_nsec = tv[0].tv_usec * 1000; 157464410Sbostic vattr.va_mtime.ts_sec = tv[1].tv_sec; 157564410Sbostic vattr.va_mtime.ts_nsec = tv[1].tv_usec * 1000; 157664410Sbostic error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 157721015Smckusick } 157837741Smckusick vput(vp); 157947540Skarels return (error); 158011811Ssam } 158111811Ssam 158264410Sbostic /* 158364410Sbostic * Truncate a file given its path name. 158464410Sbostic */ 158560428Smckusick struct truncate_args { 158664410Sbostic char *path; 158754863Storek int pad; 158854863Storek off_t length; 158954863Storek }; 159053468Smckusick /* ARGSUSED */ 159160414Smckusick truncate(p, uap, retval) 159253468Smckusick struct proc *p; 159360428Smckusick register struct truncate_args *uap; 159453468Smckusick int *retval; 159553468Smckusick { 159637741Smckusick register struct vnode *vp; 159737741Smckusick struct vattr vattr; 159837741Smckusick int error; 159947540Skarels struct nameidata nd; 16007701Ssam 160164410Sbostic NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); 160252322Smckusick if (error = namei(&nd)) 160347540Skarels return (error); 160452322Smckusick vp = nd.ni_vp; 160559382Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 160659382Smckusick VOP_LOCK(vp); 160764410Sbostic if (vp->v_type == VDIR) 160837741Smckusick error = EISDIR; 160964410Sbostic else if ((error = vn_writechk(vp)) == 0 && 161064410Sbostic (error = VOP_ACCESS(vp, VWRITE, p->p_ucred, p)) == 0) { 161164410Sbostic VATTR_NULL(&vattr); 161264410Sbostic vattr.va_size = uap->length; 161364410Sbostic error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 16147701Ssam } 161537741Smckusick vput(vp); 161647540Skarels return (error); 16177701Ssam } 16187701Ssam 161964410Sbostic /* 162064410Sbostic * Truncate a file given a file descriptor. 162164410Sbostic */ 162260428Smckusick struct ftruncate_args { 162354863Storek int fd; 162454863Storek int pad; 162554863Storek off_t length; 162654863Storek }; 162742441Smckusick /* ARGSUSED */ 162860414Smckusick ftruncate(p, uap, retval) 162945914Smckusick struct proc *p; 163060428Smckusick register struct ftruncate_args *uap; 163142441Smckusick int *retval; 163242441Smckusick { 163337741Smckusick struct vattr vattr; 163437741Smckusick struct vnode *vp; 16357701Ssam struct file *fp; 163637741Smckusick int error; 16377701Ssam 163845914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 163947540Skarels return (error); 164037741Smckusick if ((fp->f_flag & FWRITE) == 0) 164147540Skarels return (EINVAL); 164237741Smckusick vp = (struct vnode *)fp->f_data; 164359382Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 164437741Smckusick VOP_LOCK(vp); 164564410Sbostic if (vp->v_type == VDIR) 164637741Smckusick error = EISDIR; 164764410Sbostic else if ((error = vn_writechk(vp)) == 0) { 164864410Sbostic VATTR_NULL(&vattr); 164964410Sbostic vattr.va_size = uap->length; 165064410Sbostic error = VOP_SETATTR(vp, &vattr, fp->f_cred, p); 16517701Ssam } 165237741Smckusick VOP_UNLOCK(vp); 165347540Skarels return (error); 16547701Ssam } 16557701Ssam 165654863Storek #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 16579167Ssam /* 165854863Storek * Truncate a file given its path name. 165954863Storek */ 166060428Smckusick struct otruncate_args { 166164410Sbostic char *path; 166254916Storek long length; 166354916Storek }; 166454863Storek /* ARGSUSED */ 166560105Smckusick otruncate(p, uap, retval) 166654863Storek struct proc *p; 166760428Smckusick register struct otruncate_args *uap; 166854863Storek int *retval; 166954863Storek { 167060428Smckusick struct truncate_args nuap; 167154863Storek 167264410Sbostic nuap.path = uap->path; 167354863Storek nuap.length = uap->length; 167460428Smckusick return (truncate(p, &nuap, retval)); 167554863Storek } 167654863Storek 167754863Storek /* 167854863Storek * Truncate a file given a file descriptor. 167954863Storek */ 168060428Smckusick struct oftruncate_args { 168154916Storek int fd; 168254916Storek long length; 168354916Storek }; 168454863Storek /* ARGSUSED */ 168560105Smckusick oftruncate(p, uap, retval) 168654863Storek struct proc *p; 168760428Smckusick register struct oftruncate_args *uap; 168854863Storek int *retval; 168954863Storek { 169060428Smckusick struct ftruncate_args nuap; 169154863Storek 169254863Storek nuap.fd = uap->fd; 169354863Storek nuap.length = uap->length; 169460428Smckusick return (ftruncate(p, &nuap, retval)); 169554863Storek } 169654863Storek #endif /* COMPAT_43 || COMPAT_SUNOS */ 169754863Storek 169854863Storek /* 169964410Sbostic * Sync an open file. 17009167Ssam */ 170154916Storek struct fsync_args { 170254916Storek int fd; 170354916Storek }; 170442441Smckusick /* ARGSUSED */ 170542441Smckusick fsync(p, uap, retval) 170645914Smckusick struct proc *p; 170754916Storek struct fsync_args *uap; 170842441Smckusick int *retval; 17099167Ssam { 171039592Smckusick register struct vnode *vp; 17119167Ssam struct file *fp; 171237741Smckusick int error; 17139167Ssam 171445914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 171547540Skarels return (error); 171639592Smckusick vp = (struct vnode *)fp->f_data; 171739592Smckusick VOP_LOCK(vp); 171854441Smckusick error = VOP_FSYNC(vp, fp->f_cred, MNT_WAIT, p); 171939592Smckusick VOP_UNLOCK(vp); 172047540Skarels return (error); 17219167Ssam } 17229167Ssam 17239167Ssam /* 172464410Sbostic * Rename files. Source and destination must either both be directories, 172564410Sbostic * or both not be directories. If target is a directory, it must be empty. 17269167Ssam */ 172754916Storek struct rename_args { 172854916Storek char *from; 172954916Storek char *to; 173054916Storek }; 173142441Smckusick /* ARGSUSED */ 173242441Smckusick rename(p, uap, retval) 173345914Smckusick struct proc *p; 173454916Storek register struct rename_args *uap; 173542441Smckusick int *retval; 173642441Smckusick { 173737741Smckusick register struct vnode *tvp, *fvp, *tdvp; 173849735Smckusick struct nameidata fromnd, tond; 173937741Smckusick int error; 17407701Ssam 174152322Smckusick NDINIT(&fromnd, DELETE, WANTPARENT | SAVESTART, UIO_USERSPACE, 174252322Smckusick uap->from, p); 174352322Smckusick if (error = namei(&fromnd)) 174447540Skarels return (error); 174549735Smckusick fvp = fromnd.ni_vp; 174652322Smckusick NDINIT(&tond, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART, 174752322Smckusick UIO_USERSPACE, uap->to, p); 174852322Smckusick if (error = namei(&tond)) { 174952230Sheideman VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 175049735Smckusick vrele(fromnd.ni_dvp); 175142465Smckusick vrele(fvp); 175242465Smckusick goto out1; 175342465Smckusick } 175437741Smckusick tdvp = tond.ni_dvp; 175537741Smckusick tvp = tond.ni_vp; 175637741Smckusick if (tvp != NULL) { 175737741Smckusick if (fvp->v_type == VDIR && tvp->v_type != VDIR) { 175839242Sbostic error = ENOTDIR; 175937741Smckusick goto out; 176037741Smckusick } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) { 176139242Sbostic error = EISDIR; 176237741Smckusick goto out; 17639167Ssam } 17649167Ssam } 176539286Smckusick if (fvp == tdvp) 176637741Smckusick error = EINVAL; 176739286Smckusick /* 176849735Smckusick * If source is the same as the destination (that is the 176949735Smckusick * same inode number with the same name in the same directory), 177039286Smckusick * then there is nothing to do. 177139286Smckusick */ 177249735Smckusick if (fvp == tvp && fromnd.ni_dvp == tdvp && 177352322Smckusick fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen && 177452322Smckusick !bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr, 177552322Smckusick fromnd.ni_cnd.cn_namelen)) 177639286Smckusick error = -1; 177737741Smckusick out: 177842465Smckusick if (!error) { 177952192Smckusick LEASE_CHECK(tdvp, p, p->p_ucred, LEASE_WRITE); 178052192Smckusick if (fromnd.ni_dvp != tdvp) 178152192Smckusick LEASE_CHECK(fromnd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 178252192Smckusick if (tvp) 178352192Smckusick LEASE_CHECK(tvp, p, p->p_ucred, LEASE_WRITE); 178452230Sheideman error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd, 178552230Sheideman tond.ni_dvp, tond.ni_vp, &tond.ni_cnd); 178642465Smckusick } else { 178752230Sheideman VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd); 178843344Smckusick if (tdvp == tvp) 178943344Smckusick vrele(tdvp); 179043344Smckusick else 179143344Smckusick vput(tdvp); 179242465Smckusick if (tvp) 179342465Smckusick vput(tvp); 179452230Sheideman VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 179549735Smckusick vrele(fromnd.ni_dvp); 179642465Smckusick vrele(fvp); 17979167Ssam } 179849735Smckusick vrele(tond.ni_startdir); 179952322Smckusick FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI); 180037741Smckusick out1: 180166801Smckusick if (fromnd.ni_startdir) 180266801Smckusick vrele(fromnd.ni_startdir); 180352322Smckusick FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI); 180439286Smckusick if (error == -1) 180547540Skarels return (0); 180647540Skarels return (error); 18077701Ssam } 18087701Ssam 18097535Sroot /* 181064410Sbostic * Make a directory file. 181112756Ssam */ 181254916Storek struct mkdir_args { 181364410Sbostic char *path; 181464410Sbostic int mode; 181554916Storek }; 181642441Smckusick /* ARGSUSED */ 181742441Smckusick mkdir(p, uap, retval) 181845914Smckusick struct proc *p; 181954916Storek register struct mkdir_args *uap; 182042441Smckusick int *retval; 182142441Smckusick { 182237741Smckusick register struct vnode *vp; 182337741Smckusick struct vattr vattr; 182437741Smckusick int error; 182547540Skarels struct nameidata nd; 182612756Ssam 182764410Sbostic NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->path, p); 182852322Smckusick if (error = namei(&nd)) 182947540Skarels return (error); 183052322Smckusick vp = nd.ni_vp; 183137741Smckusick if (vp != NULL) { 183252322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 183352322Smckusick if (nd.ni_dvp == vp) 183452322Smckusick vrele(nd.ni_dvp); 183543344Smckusick else 183652322Smckusick vput(nd.ni_dvp); 183742465Smckusick vrele(vp); 183847540Skarels return (EEXIST); 183912756Ssam } 184041362Smckusick VATTR_NULL(&vattr); 184137741Smckusick vattr.va_type = VDIR; 184264410Sbostic vattr.va_mode = (uap->mode & ACCESSPERMS) &~ p->p_fd->fd_cmask; 184352322Smckusick LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 184452322Smckusick error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr); 184538145Smckusick if (!error) 184652322Smckusick vput(nd.ni_vp); 184747540Skarels return (error); 184812756Ssam } 184912756Ssam 185012756Ssam /* 185164410Sbostic * Remove a directory file. 185212756Ssam */ 185354916Storek struct rmdir_args { 185464410Sbostic char *path; 185554916Storek }; 185642441Smckusick /* ARGSUSED */ 185742441Smckusick rmdir(p, uap, retval) 185845914Smckusick struct proc *p; 185954916Storek struct rmdir_args *uap; 186042441Smckusick int *retval; 186112756Ssam { 186237741Smckusick register struct vnode *vp; 186337741Smckusick int error; 186447540Skarels struct nameidata nd; 186512756Ssam 186664410Sbostic NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE, uap->path, p); 186752322Smckusick if (error = namei(&nd)) 186847540Skarels return (error); 186952322Smckusick vp = nd.ni_vp; 187037741Smckusick if (vp->v_type != VDIR) { 187137741Smckusick error = ENOTDIR; 187212756Ssam goto out; 187312756Ssam } 187412756Ssam /* 187537741Smckusick * No rmdir "." please. 187612756Ssam */ 187752322Smckusick if (nd.ni_dvp == vp) { 187837741Smckusick error = EINVAL; 187912756Ssam goto out; 188012756Ssam } 188112756Ssam /* 188249365Smckusick * The root of a mounted filesystem cannot be deleted. 188312756Ssam */ 188437741Smckusick if (vp->v_flag & VROOT) 188537741Smckusick error = EBUSY; 188612756Ssam out: 188742465Smckusick if (!error) { 188852322Smckusick LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 188952192Smckusick LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 189052322Smckusick error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); 189142465Smckusick } else { 189252322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 189352322Smckusick if (nd.ni_dvp == vp) 189452322Smckusick vrele(nd.ni_dvp); 189543344Smckusick else 189652322Smckusick vput(nd.ni_dvp); 189742465Smckusick vput(vp); 189842465Smckusick } 189947540Skarels return (error); 190012756Ssam } 190112756Ssam 190254620Smckusick #ifdef COMPAT_43 190337741Smckusick /* 190449365Smckusick * Read a block of directory entries in a file system independent format. 190537741Smckusick */ 190654916Storek struct ogetdirentries_args { 190754916Storek int fd; 190854916Storek char *buf; 190964410Sbostic u_int count; 191054916Storek long *basep; 191154916Storek }; 191254620Smckusick ogetdirentries(p, uap, retval) 191354620Smckusick struct proc *p; 191454916Storek register struct ogetdirentries_args *uap; 191554620Smckusick int *retval; 191654620Smckusick { 191754620Smckusick register struct vnode *vp; 191854620Smckusick struct file *fp; 191954620Smckusick struct uio auio, kuio; 192054620Smckusick struct iovec aiov, kiov; 192154620Smckusick struct dirent *dp, *edp; 192254620Smckusick caddr_t dirbuf; 192367362Smckusick int error, eofflag, readcnt; 192454969Smckusick long loff; 192554620Smckusick 192654620Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 192754620Smckusick return (error); 192854620Smckusick if ((fp->f_flag & FREAD) == 0) 192954620Smckusick return (EBADF); 193054620Smckusick vp = (struct vnode *)fp->f_data; 193167362Smckusick unionread: 193254620Smckusick if (vp->v_type != VDIR) 193354620Smckusick return (EINVAL); 193454620Smckusick aiov.iov_base = uap->buf; 193554620Smckusick aiov.iov_len = uap->count; 193654620Smckusick auio.uio_iov = &aiov; 193754620Smckusick auio.uio_iovcnt = 1; 193854620Smckusick auio.uio_rw = UIO_READ; 193954620Smckusick auio.uio_segflg = UIO_USERSPACE; 194054620Smckusick auio.uio_procp = p; 194154620Smckusick auio.uio_resid = uap->count; 194254620Smckusick VOP_LOCK(vp); 194354969Smckusick loff = auio.uio_offset = fp->f_offset; 194454620Smckusick # if (BYTE_ORDER != LITTLE_ENDIAN) 194556339Smckusick if (vp->v_mount->mnt_maxsymlinklen <= 0) { 194667362Smckusick error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, 194767362Smckusick (u_long *)0, 0); 194856339Smckusick fp->f_offset = auio.uio_offset; 194956339Smckusick } else 195054620Smckusick # endif 195154620Smckusick { 195254620Smckusick kuio = auio; 195354620Smckusick kuio.uio_iov = &kiov; 195454620Smckusick kuio.uio_segflg = UIO_SYSSPACE; 195554620Smckusick kiov.iov_len = uap->count; 195654620Smckusick MALLOC(dirbuf, caddr_t, uap->count, M_TEMP, M_WAITOK); 195754620Smckusick kiov.iov_base = dirbuf; 195867362Smckusick error = VOP_READDIR(vp, &kuio, fp->f_cred, &eofflag, 195967362Smckusick (u_long *)0, 0); 196056339Smckusick fp->f_offset = kuio.uio_offset; 196154620Smckusick if (error == 0) { 196254620Smckusick readcnt = uap->count - kuio.uio_resid; 196354620Smckusick edp = (struct dirent *)&dirbuf[readcnt]; 196454620Smckusick for (dp = (struct dirent *)dirbuf; dp < edp; ) { 196554620Smckusick # if (BYTE_ORDER == LITTLE_ENDIAN) 196654969Smckusick /* 196755009Smckusick * The expected low byte of 196855009Smckusick * dp->d_namlen is our dp->d_type. 196955009Smckusick * The high MBZ byte of dp->d_namlen 197055009Smckusick * is our dp->d_namlen. 197154969Smckusick */ 197255009Smckusick dp->d_type = dp->d_namlen; 197355009Smckusick dp->d_namlen = 0; 197455009Smckusick # else 197555009Smckusick /* 197655009Smckusick * The dp->d_type is the high byte 197755009Smckusick * of the expected dp->d_namlen, 197855009Smckusick * so must be zero'ed. 197955009Smckusick */ 198055009Smckusick dp->d_type = 0; 198154620Smckusick # endif 198254620Smckusick if (dp->d_reclen > 0) { 198354620Smckusick dp = (struct dirent *) 198454620Smckusick ((char *)dp + dp->d_reclen); 198554620Smckusick } else { 198654620Smckusick error = EIO; 198754620Smckusick break; 198854620Smckusick } 198954620Smckusick } 199054620Smckusick if (dp >= edp) 199154620Smckusick error = uiomove(dirbuf, readcnt, &auio); 199254620Smckusick } 199354620Smckusick FREE(dirbuf, M_TEMP); 199454620Smckusick } 199554620Smckusick VOP_UNLOCK(vp); 199654620Smckusick if (error) 199754620Smckusick return (error); 199867362Smckusick 199967362Smckusick #ifdef UNION 200067362Smckusick { 200167362Smckusick extern int (**union_vnodeop_p)(); 200267362Smckusick extern struct vnode *union_lowervp __P((struct vnode *)); 200367362Smckusick 200467362Smckusick if ((uap->count == auio.uio_resid) && 200567362Smckusick (vp->v_op == union_vnodeop_p)) { 200667362Smckusick struct vnode *lvp; 200767362Smckusick 200867362Smckusick lvp = union_lowervp(vp); 200967362Smckusick if (lvp != NULLVP) { 2010*67575Spendry struct vattr va; 2011*67575Spendry 2012*67575Spendry /* 2013*67575Spendry * If the directory is opaque, 2014*67575Spendry * then don't show lower entries 2015*67575Spendry */ 2016*67575Spendry error = VOP_GETATTR(vp, &va, fp->f_cred, p); 2017*67575Spendry if (va.va_flags & OPAQUE) { 2018*67575Spendry vrele(lvp); 2019*67575Spendry lvp = NULL; 2020*67575Spendry } 2021*67575Spendry } 2022*67575Spendry 2023*67575Spendry if (lvp != NULLVP) { 202467362Smckusick VOP_LOCK(lvp); 202567362Smckusick error = VOP_OPEN(lvp, FREAD, fp->f_cred, p); 202667362Smckusick VOP_UNLOCK(lvp); 202767362Smckusick 202867362Smckusick if (error) { 202967362Smckusick vrele(lvp); 203067362Smckusick return (error); 203167362Smckusick } 203267362Smckusick fp->f_data = (caddr_t) lvp; 203367362Smckusick fp->f_offset = 0; 203467362Smckusick error = vn_close(vp, FREAD, fp->f_cred, p); 203567362Smckusick if (error) 203667362Smckusick return (error); 203767362Smckusick vp = lvp; 203867362Smckusick goto unionread; 203967362Smckusick } 204067362Smckusick } 204167362Smckusick } 204267362Smckusick #endif /* UNION */ 204367362Smckusick 204467362Smckusick if ((uap->count == auio.uio_resid) && 204567362Smckusick (vp->v_flag & VROOT) && 204667362Smckusick (vp->v_mount->mnt_flag & MNT_UNION)) { 204767362Smckusick struct vnode *tvp = vp; 204867362Smckusick vp = vp->v_mount->mnt_vnodecovered; 204967362Smckusick VREF(vp); 205067362Smckusick fp->f_data = (caddr_t) vp; 205167362Smckusick fp->f_offset = 0; 205267362Smckusick vrele(tvp); 205367362Smckusick goto unionread; 205467362Smckusick } 205554969Smckusick error = copyout((caddr_t)&loff, (caddr_t)uap->basep, sizeof(long)); 205654620Smckusick *retval = uap->count - auio.uio_resid; 205754620Smckusick return (error); 205854620Smckusick } 205967362Smckusick #endif /* COMPAT_43 */ 206054620Smckusick 206154620Smckusick /* 206254620Smckusick * Read a block of directory entries in a file system independent format. 206354620Smckusick */ 206454916Storek struct getdirentries_args { 206554916Storek int fd; 206654916Storek char *buf; 206764410Sbostic u_int count; 206854916Storek long *basep; 206954916Storek }; 207042441Smckusick getdirentries(p, uap, retval) 207145914Smckusick struct proc *p; 207254916Storek register struct getdirentries_args *uap; 207342441Smckusick int *retval; 207442441Smckusick { 207539592Smckusick register struct vnode *vp; 207616540Ssam struct file *fp; 207737741Smckusick struct uio auio; 207837741Smckusick struct iovec aiov; 207954969Smckusick long loff; 208067362Smckusick int error, eofflag; 208112756Ssam 208245914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 208347540Skarels return (error); 208437741Smckusick if ((fp->f_flag & FREAD) == 0) 208547540Skarels return (EBADF); 208639592Smckusick vp = (struct vnode *)fp->f_data; 208755451Spendry unionread: 208839592Smckusick if (vp->v_type != VDIR) 208947540Skarels return (EINVAL); 209037741Smckusick aiov.iov_base = uap->buf; 209137741Smckusick aiov.iov_len = uap->count; 209237741Smckusick auio.uio_iov = &aiov; 209337741Smckusick auio.uio_iovcnt = 1; 209437741Smckusick auio.uio_rw = UIO_READ; 209537741Smckusick auio.uio_segflg = UIO_USERSPACE; 209648026Smckusick auio.uio_procp = p; 209737741Smckusick auio.uio_resid = uap->count; 209839592Smckusick VOP_LOCK(vp); 209954969Smckusick loff = auio.uio_offset = fp->f_offset; 210067362Smckusick error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, (u_long *)0, 0); 210139592Smckusick fp->f_offset = auio.uio_offset; 210239592Smckusick VOP_UNLOCK(vp); 210339592Smckusick if (error) 210447540Skarels return (error); 210566095Spendry 210666095Spendry #ifdef UNION 210766095Spendry { 210866095Spendry extern int (**union_vnodeop_p)(); 210966095Spendry extern struct vnode *union_lowervp __P((struct vnode *)); 211066095Spendry 211155451Spendry if ((uap->count == auio.uio_resid) && 211266095Spendry (vp->v_op == union_vnodeop_p)) { 211367122Spendry struct vnode *lvp; 211466095Spendry 211567122Spendry lvp = union_lowervp(vp); 211667122Spendry if (lvp != NULLVP) { 2117*67575Spendry struct vattr va; 2118*67575Spendry 2119*67575Spendry /* 2120*67575Spendry * If the directory is opaque, 2121*67575Spendry * then don't show lower entries 2122*67575Spendry */ 2123*67575Spendry error = VOP_GETATTR(vp, &va, fp->f_cred, p); 2124*67575Spendry if (va.va_flags & OPAQUE) { 2125*67575Spendry vrele(lvp); 2126*67575Spendry lvp = NULL; 2127*67575Spendry } 2128*67575Spendry } 2129*67575Spendry 2130*67575Spendry if (lvp != NULLVP) { 213167122Spendry VOP_LOCK(lvp); 213267362Smckusick error = VOP_OPEN(lvp, FREAD, fp->f_cred, p); 213367122Spendry VOP_UNLOCK(lvp); 213466095Spendry 213566095Spendry if (error) { 213667122Spendry vrele(lvp); 213766095Spendry return (error); 213866095Spendry } 213967122Spendry fp->f_data = (caddr_t) lvp; 214066095Spendry fp->f_offset = 0; 214167122Spendry error = vn_close(vp, FREAD, fp->f_cred, p); 214266095Spendry if (error) 214366095Spendry return (error); 214467122Spendry vp = lvp; 214566095Spendry goto unionread; 214666095Spendry } 214766095Spendry } 214866095Spendry } 214966095Spendry #endif 215066095Spendry 215166095Spendry if ((uap->count == auio.uio_resid) && 215255451Spendry (vp->v_flag & VROOT) && 215355451Spendry (vp->v_mount->mnt_flag & MNT_UNION)) { 215455451Spendry struct vnode *tvp = vp; 215555451Spendry vp = vp->v_mount->mnt_vnodecovered; 215655451Spendry VREF(vp); 215755451Spendry fp->f_data = (caddr_t) vp; 215855451Spendry fp->f_offset = 0; 215955451Spendry vrele(tvp); 216055451Spendry goto unionread; 216155451Spendry } 216254969Smckusick error = copyout((caddr_t)&loff, (caddr_t)uap->basep, sizeof(long)); 216342441Smckusick *retval = uap->count - auio.uio_resid; 216447540Skarels return (error); 216512756Ssam } 216612756Ssam 216712756Ssam /* 216849365Smckusick * Set the mode mask for creation of filesystem nodes. 216912756Ssam */ 217054916Storek struct umask_args { 217164410Sbostic int newmask; 217254916Storek }; 217354916Storek mode_t /* XXX */ 217442441Smckusick umask(p, uap, retval) 217545914Smckusick struct proc *p; 217654916Storek struct umask_args *uap; 217742441Smckusick int *retval; 217812756Ssam { 217964410Sbostic register struct filedesc *fdp; 218012756Ssam 218164410Sbostic fdp = p->p_fd; 218245914Smckusick *retval = fdp->fd_cmask; 218364410Sbostic fdp->fd_cmask = uap->newmask & ALLPERMS; 218447540Skarels return (0); 218512756Ssam } 218637741Smckusick 218739566Smarc /* 218839566Smarc * Void all references to file by ripping underlying filesystem 218939566Smarc * away from vnode. 219039566Smarc */ 219154916Storek struct revoke_args { 219264410Sbostic char *path; 219354916Storek }; 219442441Smckusick /* ARGSUSED */ 219542441Smckusick revoke(p, uap, retval) 219645914Smckusick struct proc *p; 219754916Storek register struct revoke_args *uap; 219842441Smckusick int *retval; 219942441Smckusick { 220039566Smarc register struct vnode *vp; 220139566Smarc struct vattr vattr; 220239566Smarc int error; 220347540Skarels struct nameidata nd; 220439566Smarc 220564410Sbostic NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); 220652322Smckusick if (error = namei(&nd)) 220747540Skarels return (error); 220852322Smckusick vp = nd.ni_vp; 220939566Smarc if (vp->v_type != VCHR && vp->v_type != VBLK) { 221039566Smarc error = EINVAL; 221139566Smarc goto out; 221239566Smarc } 221348026Smckusick if (error = VOP_GETATTR(vp, &vattr, p->p_ucred, p)) 221439566Smarc goto out; 221547540Skarels if (p->p_ucred->cr_uid != vattr.va_uid && 221647540Skarels (error = suser(p->p_ucred, &p->p_acflag))) 221739566Smarc goto out; 221839805Smckusick if (vp->v_usecount > 1 || (vp->v_flag & VALIASED)) 221939632Smckusick vgoneall(vp); 222039566Smarc out: 222139566Smarc vrele(vp); 222247540Skarels return (error); 222339566Smarc } 222439566Smarc 222549365Smckusick /* 222649365Smckusick * Convert a user file descriptor to a kernel file entry. 222749365Smckusick */ 222864410Sbostic getvnode(fdp, fd, fpp) 222945914Smckusick struct filedesc *fdp; 223037741Smckusick struct file **fpp; 223164410Sbostic int fd; 223237741Smckusick { 223337741Smckusick struct file *fp; 223437741Smckusick 223564410Sbostic if ((u_int)fd >= fdp->fd_nfiles || 223664410Sbostic (fp = fdp->fd_ofiles[fd]) == NULL) 223737741Smckusick return (EBADF); 223837741Smckusick if (fp->f_type != DTYPE_VNODE) 223937741Smckusick return (EINVAL); 224037741Smckusick *fpp = fp; 224137741Smckusick return (0); 224237741Smckusick } 2243