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*67748Smckusick * @(#)vfs_syscalls.c 8.23 (Berkeley) 08/30/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) { 31367678Smckusick /* 31467678Smckusick * Get the next pointer in case we hang on vfs_busy 31567678Smckusick * while we are being unmounted. 31667678Smckusick */ 31765259Smckusick nmp = mp->mnt_list.tqe_next; 31840343Smckusick /* 31940343Smckusick * The lock check below is to avoid races with mount 32040343Smckusick * and unmount. 32140343Smckusick */ 32241400Smckusick if ((mp->mnt_flag & (MNT_MLOCK|MNT_RDONLY|MNT_MPBUSY)) == 0 && 32341298Smckusick !vfs_busy(mp)) { 32465859Smckusick asyncflag = mp->mnt_flag & MNT_ASYNC; 32565859Smckusick mp->mnt_flag &= ~MNT_ASYNC; 32654441Smckusick VFS_SYNC(mp, MNT_NOWAIT, p->p_ucred, p); 32765859Smckusick if (asyncflag) 32865859Smckusick mp->mnt_flag |= MNT_ASYNC; 32967678Smckusick /* 33067678Smckusick * Get the next pointer again, as the next filesystem 33167678Smckusick * might have been unmounted while we were sync'ing. 33267678Smckusick */ 33367678Smckusick nmp = mp->mnt_list.tqe_next; 33465259Smckusick vfs_unbusy(mp); 33565259Smckusick } 33665259Smckusick } 33756352Smckusick #ifdef DIAGNOSTIC 33856352Smckusick if (syncprt) 33956352Smckusick vfs_bufstats(); 34056352Smckusick #endif /* DIAGNOSTIC */ 34147688Skarels return (0); 34237741Smckusick } 34337741Smckusick 34437741Smckusick /* 34564410Sbostic * Change filesystem quotas. 34641298Smckusick */ 34754916Storek struct quotactl_args { 34854916Storek char *path; 34954916Storek int cmd; 35054916Storek int uid; 35154916Storek caddr_t arg; 35254916Storek }; 35342441Smckusick /* ARGSUSED */ 35442441Smckusick quotactl(p, uap, retval) 35545914Smckusick struct proc *p; 35654916Storek register struct quotactl_args *uap; 35742441Smckusick int *retval; 35842441Smckusick { 35941298Smckusick register struct mount *mp; 36041298Smckusick int error; 36147540Skarels struct nameidata nd; 36241298Smckusick 36352322Smckusick NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); 36452322Smckusick if (error = namei(&nd)) 36547540Skarels return (error); 36652322Smckusick mp = nd.ni_vp->v_mount; 36752322Smckusick vrele(nd.ni_vp); 36848026Smckusick return (VFS_QUOTACTL(mp, uap->cmd, uap->uid, uap->arg, p)); 36941298Smckusick } 37041298Smckusick 37141298Smckusick /* 37249365Smckusick * Get filesystem statistics. 37337741Smckusick */ 37454916Storek struct statfs_args { 37554916Storek char *path; 37654916Storek struct statfs *buf; 37754916Storek }; 37842441Smckusick /* ARGSUSED */ 37942441Smckusick statfs(p, uap, retval) 38045914Smckusick struct proc *p; 38154916Storek register struct statfs_args *uap; 38242441Smckusick int *retval; 38342441Smckusick { 38439464Smckusick register struct mount *mp; 38540343Smckusick register struct statfs *sp; 38637741Smckusick int error; 38747540Skarels struct nameidata nd; 38837741Smckusick 38952322Smckusick NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); 39052322Smckusick if (error = namei(&nd)) 39147540Skarels return (error); 39252322Smckusick mp = nd.ni_vp->v_mount; 39341400Smckusick sp = &mp->mnt_stat; 39452322Smckusick vrele(nd.ni_vp); 39548026Smckusick if (error = VFS_STATFS(mp, sp, p)) 39647540Skarels return (error); 39741400Smckusick sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 39847540Skarels return (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp))); 39937741Smckusick } 40037741Smckusick 40142441Smckusick /* 40249365Smckusick * Get filesystem statistics. 40342441Smckusick */ 40454916Storek struct fstatfs_args { 40554916Storek int fd; 40654916Storek struct statfs *buf; 40754916Storek }; 40842441Smckusick /* ARGSUSED */ 40942441Smckusick fstatfs(p, uap, retval) 41045914Smckusick struct proc *p; 41154916Storek register struct fstatfs_args *uap; 41242441Smckusick int *retval; 41342441Smckusick { 41437741Smckusick struct file *fp; 41539464Smckusick struct mount *mp; 41640343Smckusick register struct statfs *sp; 41737741Smckusick int error; 41837741Smckusick 41945914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 42047540Skarels return (error); 42139464Smckusick mp = ((struct vnode *)fp->f_data)->v_mount; 42241400Smckusick sp = &mp->mnt_stat; 42348026Smckusick if (error = VFS_STATFS(mp, sp, p)) 42447540Skarels return (error); 42541400Smckusick sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 42647540Skarels return (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp))); 42737741Smckusick } 42837741Smckusick 42937741Smckusick /* 43049365Smckusick * Get statistics on all filesystems. 43138270Smckusick */ 43254916Storek struct getfsstat_args { 43354916Storek struct statfs *buf; 43454916Storek long bufsize; 43554916Storek int flags; 43654916Storek }; 43742441Smckusick getfsstat(p, uap, retval) 43845914Smckusick struct proc *p; 43954916Storek register struct getfsstat_args *uap; 44042441Smckusick int *retval; 44142441Smckusick { 44265259Smckusick register struct mount *mp, *nmp; 44340343Smckusick register struct statfs *sp; 44439606Smckusick caddr_t sfsp; 44538270Smckusick long count, maxcount, error; 44638270Smckusick 44738270Smckusick maxcount = uap->bufsize / sizeof(struct statfs); 44839606Smckusick sfsp = (caddr_t)uap->buf; 44965259Smckusick for (count = 0, mp = mountlist.tqh_first; mp != NULL; mp = nmp) { 45065259Smckusick nmp = mp->mnt_list.tqe_next; 45141400Smckusick if (sfsp && count < maxcount && 45241400Smckusick ((mp->mnt_flag & MNT_MLOCK) == 0)) { 45341400Smckusick sp = &mp->mnt_stat; 45440343Smckusick /* 45540343Smckusick * If MNT_NOWAIT is specified, do not refresh the 45640343Smckusick * fsstat cache. MNT_WAIT overrides MNT_NOWAIT. 45740343Smckusick */ 45840343Smckusick if (((uap->flags & MNT_NOWAIT) == 0 || 45940343Smckusick (uap->flags & MNT_WAIT)) && 46065259Smckusick (error = VFS_STATFS(mp, sp, p))) 46139607Smckusick continue; 46241400Smckusick sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 46340343Smckusick if (error = copyout((caddr_t)sp, sfsp, sizeof(*sp))) 46447540Skarels return (error); 46540343Smckusick sfsp += sizeof(*sp); 46638270Smckusick } 46739606Smckusick count++; 46865259Smckusick } 46938270Smckusick if (sfsp && count > maxcount) 47042441Smckusick *retval = maxcount; 47138270Smckusick else 47242441Smckusick *retval = count; 47347540Skarels return (0); 47438270Smckusick } 47538270Smckusick 47638270Smckusick /* 47738259Smckusick * Change current working directory to a given file descriptor. 47838259Smckusick */ 47954916Storek struct fchdir_args { 48054916Storek int fd; 48154916Storek }; 48242441Smckusick /* ARGSUSED */ 48342441Smckusick fchdir(p, uap, retval) 48445914Smckusick struct proc *p; 48554916Storek struct fchdir_args *uap; 48642441Smckusick int *retval; 48738259Smckusick { 48845914Smckusick register struct filedesc *fdp = p->p_fd; 48938259Smckusick register struct vnode *vp; 49038259Smckusick struct file *fp; 49138259Smckusick int error; 49238259Smckusick 49345914Smckusick if (error = getvnode(fdp, uap->fd, &fp)) 49447540Skarels return (error); 49538259Smckusick vp = (struct vnode *)fp->f_data; 49638259Smckusick VOP_LOCK(vp); 49738259Smckusick if (vp->v_type != VDIR) 49838259Smckusick error = ENOTDIR; 49938259Smckusick else 50048026Smckusick error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p); 50138259Smckusick VOP_UNLOCK(vp); 50239860Smckusick if (error) 50347540Skarels return (error); 50439860Smckusick VREF(vp); 50545914Smckusick vrele(fdp->fd_cdir); 50645914Smckusick fdp->fd_cdir = vp; 50747540Skarels return (0); 50838259Smckusick } 50938259Smckusick 51038259Smckusick /* 51137741Smckusick * Change current working directory (``.''). 51237741Smckusick */ 51354916Storek struct chdir_args { 51464410Sbostic char *path; 51554916Storek }; 51642441Smckusick /* ARGSUSED */ 51742441Smckusick chdir(p, uap, retval) 51845914Smckusick struct proc *p; 51954916Storek struct chdir_args *uap; 52042441Smckusick int *retval; 52137741Smckusick { 52245914Smckusick register struct filedesc *fdp = p->p_fd; 52337741Smckusick int error; 52447540Skarels struct nameidata nd; 5256254Sroot 52664410Sbostic NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); 52764410Sbostic if (error = change_dir(&nd, p)) 52847540Skarels return (error); 52945914Smckusick vrele(fdp->fd_cdir); 53052322Smckusick fdp->fd_cdir = nd.ni_vp; 53147540Skarels return (0); 53237741Smckusick } 5336254Sroot 53437741Smckusick /* 53537741Smckusick * Change notion of root (``/'') directory. 53637741Smckusick */ 53754916Storek struct chroot_args { 53864410Sbostic char *path; 53954916Storek }; 54042441Smckusick /* ARGSUSED */ 54142441Smckusick chroot(p, uap, retval) 54245914Smckusick struct proc *p; 54354916Storek struct chroot_args *uap; 54442441Smckusick int *retval; 54537741Smckusick { 54645914Smckusick register struct filedesc *fdp = p->p_fd; 54737741Smckusick int error; 54847540Skarels struct nameidata nd; 54937741Smckusick 55047540Skarels if (error = suser(p->p_ucred, &p->p_acflag)) 55147540Skarels return (error); 55264410Sbostic NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); 55364410Sbostic if (error = change_dir(&nd, p)) 55447540Skarels return (error); 55545914Smckusick if (fdp->fd_rdir != NULL) 55645914Smckusick vrele(fdp->fd_rdir); 55752322Smckusick fdp->fd_rdir = nd.ni_vp; 55847540Skarels return (0); 5596254Sroot } 5606254Sroot 56137Sbill /* 56237741Smckusick * Common routine for chroot and chdir. 56337741Smckusick */ 56464410Sbostic static int 56564410Sbostic change_dir(ndp, p) 56652322Smckusick register struct nameidata *ndp; 56747540Skarels struct proc *p; 56837741Smckusick { 56937741Smckusick struct vnode *vp; 57037741Smckusick int error; 57137741Smckusick 57252322Smckusick if (error = namei(ndp)) 57337741Smckusick return (error); 57437741Smckusick vp = ndp->ni_vp; 57537741Smckusick if (vp->v_type != VDIR) 57637741Smckusick error = ENOTDIR; 57737741Smckusick else 57848026Smckusick error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p); 57937741Smckusick VOP_UNLOCK(vp); 58037741Smckusick if (error) 58137741Smckusick vrele(vp); 58237741Smckusick return (error); 58337741Smckusick } 58437741Smckusick 58537741Smckusick /* 58642441Smckusick * Check permissions, allocate an open file structure, 58742441Smckusick * and call the device open routine if any. 5886254Sroot */ 58954916Storek struct open_args { 59064410Sbostic char *path; 59164410Sbostic int flags; 59254916Storek int mode; 59354916Storek }; 59442441Smckusick open(p, uap, retval) 59545914Smckusick struct proc *p; 59654916Storek register struct open_args *uap; 59742441Smckusick int *retval; 5986254Sroot { 59945914Smckusick register struct filedesc *fdp = p->p_fd; 60042441Smckusick register struct file *fp; 60150111Smckusick register struct vnode *vp; 60264410Sbostic int flags, cmode; 60337741Smckusick struct file *nfp; 60449945Smckusick int type, indx, error; 60549945Smckusick struct flock lf; 60647540Skarels struct nameidata nd; 60737741Smckusick extern struct fileops vnops; 6086254Sroot 60945914Smckusick if (error = falloc(p, &nfp, &indx)) 61047540Skarels return (error); 61137741Smckusick fp = nfp; 61264410Sbostic flags = FFLAGS(uap->flags); 61364410Sbostic cmode = ((uap->mode &~ fdp->fd_cmask) & ALLPERMS) &~ S_ISTXT; 61464410Sbostic NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); 61545202Smckusick p->p_dupfd = -indx - 1; /* XXX check for fdopen */ 61664410Sbostic if (error = vn_open(&nd, flags, cmode)) { 61749980Smckusick ffree(fp); 61854723Smckusick if ((error == ENODEV || error == ENXIO) && 61954723Smckusick p->p_dupfd >= 0 && /* XXX from fdopen */ 62064410Sbostic (error = 62164410Sbostic dupfdopen(fdp, indx, p->p_dupfd, flags, error)) == 0) { 62242441Smckusick *retval = indx; 62347540Skarels return (0); 62442441Smckusick } 62540884Smckusick if (error == ERESTART) 62640884Smckusick error = EINTR; 62747688Skarels fdp->fd_ofiles[indx] = NULL; 62847540Skarels return (error); 62912756Ssam } 63053828Spendry p->p_dupfd = 0; 63152322Smckusick vp = nd.ni_vp; 63264410Sbostic fp->f_flag = flags & FMASK; 63354348Smckusick fp->f_type = DTYPE_VNODE; 63454348Smckusick fp->f_ops = &vnops; 63554348Smckusick fp->f_data = (caddr_t)vp; 63664410Sbostic if (flags & (O_EXLOCK | O_SHLOCK)) { 63749945Smckusick lf.l_whence = SEEK_SET; 63849945Smckusick lf.l_start = 0; 63949945Smckusick lf.l_len = 0; 64064410Sbostic if (flags & O_EXLOCK) 64149945Smckusick lf.l_type = F_WRLCK; 64249945Smckusick else 64349945Smckusick lf.l_type = F_RDLCK; 64449945Smckusick type = F_FLOCK; 64564410Sbostic if ((flags & FNONBLOCK) == 0) 64649945Smckusick type |= F_WAIT; 64765757Smckusick VOP_UNLOCK(vp); 64850111Smckusick if (error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, type)) { 64950111Smckusick (void) vn_close(vp, fp->f_flag, fp->f_cred, p); 65049980Smckusick ffree(fp); 65149945Smckusick fdp->fd_ofiles[indx] = NULL; 65249945Smckusick return (error); 65349945Smckusick } 65465757Smckusick VOP_LOCK(vp); 65549949Smckusick fp->f_flag |= FHASLOCK; 65649945Smckusick } 65750111Smckusick VOP_UNLOCK(vp); 65842441Smckusick *retval = indx; 65947540Skarels return (0); 6606254Sroot } 6616254Sroot 66242955Smckusick #ifdef COMPAT_43 6636254Sroot /* 66464410Sbostic * Create a file. 6656254Sroot */ 66654916Storek struct ocreat_args { 66764410Sbostic char *path; 66864410Sbostic int mode; 66954916Storek }; 67042955Smckusick ocreat(p, uap, retval) 67142441Smckusick struct proc *p; 67254916Storek register struct ocreat_args *uap; 67342441Smckusick int *retval; 6746254Sroot { 67554916Storek struct open_args openuap; 67642441Smckusick 67764410Sbostic openuap.path = uap->path; 67864410Sbostic openuap.mode = uap->mode; 67964410Sbostic openuap.flags = O_WRONLY | O_CREAT | O_TRUNC; 68047540Skarels return (open(p, &openuap, retval)); 68142441Smckusick } 68242955Smckusick #endif /* COMPAT_43 */ 68342441Smckusick 68442441Smckusick /* 68564410Sbostic * Create a special file. 68642441Smckusick */ 68754916Storek struct mknod_args { 68864410Sbostic char *path; 68964410Sbostic int mode; 69054916Storek int dev; 69154916Storek }; 69242441Smckusick /* ARGSUSED */ 69342441Smckusick mknod(p, uap, retval) 69445914Smckusick struct proc *p; 69554916Storek register struct mknod_args *uap; 69642441Smckusick int *retval; 69742441Smckusick { 69837741Smckusick register struct vnode *vp; 69937741Smckusick struct vattr vattr; 70037741Smckusick int error; 70167575Spendry int whiteout; 70247540Skarels struct nameidata nd; 7036254Sroot 70447540Skarels if (error = suser(p->p_ucred, &p->p_acflag)) 70547540Skarels return (error); 70664410Sbostic NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->path, p); 70752322Smckusick if (error = namei(&nd)) 70847540Skarels return (error); 70952322Smckusick vp = nd.ni_vp; 71064585Sbostic if (vp != NULL) 71137741Smckusick error = EEXIST; 71264585Sbostic else { 71364585Sbostic VATTR_NULL(&vattr); 71464585Sbostic vattr.va_mode = (uap->mode & ALLPERMS) &~ p->p_fd->fd_cmask; 71564585Sbostic vattr.va_rdev = uap->dev; 71667575Spendry whiteout = 0; 71764585Sbostic 71864585Sbostic switch (uap->mode & S_IFMT) { 71964585Sbostic case S_IFMT: /* used by badsect to flag bad sectors */ 72064585Sbostic vattr.va_type = VBAD; 72164585Sbostic break; 72264585Sbostic case S_IFCHR: 72364585Sbostic vattr.va_type = VCHR; 72464585Sbostic break; 72564585Sbostic case S_IFBLK: 72664585Sbostic vattr.va_type = VBLK; 72764585Sbostic break; 72867575Spendry case S_IFWHT: 72967575Spendry whiteout = 1; 73067575Spendry break; 73164585Sbostic default: 73264585Sbostic error = EINVAL; 73364585Sbostic break; 73464585Sbostic } 7356254Sroot } 73667747Spendry if (!error) { 73767654Smckusick VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 73867747Spendry if (whiteout) { 73967747Spendry error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, CREATE); 74067747Spendry if (error) 74167747Spendry VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 74267747Spendry vput(nd.ni_dvp); 74367747Spendry } else { 74467747Spendry error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, 74567747Spendry &nd.ni_cnd, &vattr); 74667747Spendry } 74742465Smckusick } else { 74852322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 74952322Smckusick if (nd.ni_dvp == vp) 75052322Smckusick vrele(nd.ni_dvp); 75143344Smckusick else 75252322Smckusick vput(nd.ni_dvp); 75342465Smckusick if (vp) 75442465Smckusick vrele(vp); 75542465Smckusick } 75647540Skarels return (error); 7576254Sroot } 7586254Sroot 7596254Sroot /* 76064410Sbostic * Create named pipe. 76140285Smckusick */ 76254916Storek struct mkfifo_args { 76364410Sbostic char *path; 76464410Sbostic int mode; 76554916Storek }; 76642441Smckusick /* ARGSUSED */ 76742441Smckusick mkfifo(p, uap, retval) 76845914Smckusick struct proc *p; 76954916Storek register struct mkfifo_args *uap; 77042441Smckusick int *retval; 77142441Smckusick { 77240285Smckusick struct vattr vattr; 77340285Smckusick int error; 77447540Skarels struct nameidata nd; 77540285Smckusick 77640285Smckusick #ifndef FIFO 77747540Skarels return (EOPNOTSUPP); 77840285Smckusick #else 77964410Sbostic NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->path, p); 78052322Smckusick if (error = namei(&nd)) 78147540Skarels return (error); 78252322Smckusick if (nd.ni_vp != NULL) { 78352322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 78452322Smckusick if (nd.ni_dvp == nd.ni_vp) 78552322Smckusick vrele(nd.ni_dvp); 78643344Smckusick else 78752322Smckusick vput(nd.ni_dvp); 78852322Smckusick vrele(nd.ni_vp); 78947540Skarels return (EEXIST); 79040285Smckusick } 79145785Sbostic VATTR_NULL(&vattr); 79245785Sbostic vattr.va_type = VFIFO; 79364410Sbostic vattr.va_mode = (uap->mode & ALLPERMS) &~ p->p_fd->fd_cmask; 79467654Smckusick VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 79552322Smckusick return (VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr)); 79640285Smckusick #endif /* FIFO */ 79740285Smckusick } 79840285Smckusick 79940285Smckusick /* 80064410Sbostic * Make a hard file link. 8016254Sroot */ 80254916Storek struct link_args { 80364410Sbostic char *path; 80464410Sbostic char *link; 80554916Storek }; 80642441Smckusick /* ARGSUSED */ 80742441Smckusick link(p, uap, retval) 80845914Smckusick struct proc *p; 80954916Storek register struct link_args *uap; 81042441Smckusick int *retval; 81142441Smckusick { 81264410Sbostic register struct vnode *vp; 81364410Sbostic struct nameidata nd; 81437741Smckusick int error; 8156254Sroot 81664410Sbostic NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); 81752322Smckusick if (error = namei(&nd)) 81847540Skarels return (error); 81952322Smckusick vp = nd.ni_vp; 82064585Sbostic if (vp->v_type != VDIR || 82164585Sbostic (error = suser(p->p_ucred, &p->p_acflag)) == 0) { 82264585Sbostic nd.ni_cnd.cn_nameiop = CREATE; 82364585Sbostic nd.ni_cnd.cn_flags = LOCKPARENT; 82464585Sbostic nd.ni_dirp = uap->link; 82564585Sbostic if ((error = namei(&nd)) == 0) { 82664585Sbostic if (nd.ni_vp != NULL) 82764585Sbostic error = EEXIST; 82864585Sbostic if (!error) { 82967654Smckusick VOP_LEASE(nd.ni_dvp, p, p->p_ucred, 83067654Smckusick LEASE_WRITE); 83167654Smckusick VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 83264585Sbostic error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd); 83364585Sbostic } else { 83464585Sbostic VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 83564585Sbostic if (nd.ni_dvp == nd.ni_vp) 83664585Sbostic vrele(nd.ni_dvp); 83764585Sbostic else 83864585Sbostic vput(nd.ni_dvp); 83964585Sbostic if (nd.ni_vp) 84064585Sbostic vrele(nd.ni_vp); 84164585Sbostic } 84264585Sbostic } 84342465Smckusick } 84464585Sbostic vrele(vp); 84547540Skarels return (error); 8466254Sroot } 8476254Sroot 8486254Sroot /* 84949365Smckusick * Make a symbolic link. 8506254Sroot */ 85154916Storek struct symlink_args { 85264410Sbostic char *path; 85364410Sbostic char *link; 85454916Storek }; 85542441Smckusick /* ARGSUSED */ 85642441Smckusick symlink(p, uap, retval) 85745914Smckusick struct proc *p; 85854916Storek register struct symlink_args *uap; 85942441Smckusick int *retval; 86042441Smckusick { 86137741Smckusick struct vattr vattr; 86264410Sbostic char *path; 86337741Smckusick int error; 86447540Skarels struct nameidata nd; 8656254Sroot 86664410Sbostic MALLOC(path, char *, MAXPATHLEN, M_NAMEI, M_WAITOK); 86764410Sbostic if (error = copyinstr(uap->path, path, MAXPATHLEN, NULL)) 86842465Smckusick goto out; 86964410Sbostic NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->link, p); 87052322Smckusick if (error = namei(&nd)) 87142465Smckusick goto out; 87252322Smckusick if (nd.ni_vp) { 87352322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 87452322Smckusick if (nd.ni_dvp == nd.ni_vp) 87552322Smckusick vrele(nd.ni_dvp); 87643344Smckusick else 87752322Smckusick vput(nd.ni_dvp); 87852322Smckusick vrele(nd.ni_vp); 87937741Smckusick error = EEXIST; 88037741Smckusick goto out; 8816254Sroot } 88241362Smckusick VATTR_NULL(&vattr); 88364410Sbostic vattr.va_mode = ACCESSPERMS &~ p->p_fd->fd_cmask; 88467654Smckusick VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 88564410Sbostic error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr, path); 88637741Smckusick out: 88764410Sbostic FREE(path, M_NAMEI); 88847540Skarels return (error); 8896254Sroot } 8906254Sroot 8916254Sroot /* 89267518Spendry * Delete a whiteout from the filesystem. 89367518Spendry */ 89467518Spendry struct unwhiteout_args { 89567518Spendry char *path; 89667518Spendry }; 89767518Spendry /* ARGSUSED */ 89867518Spendry unwhiteout(p, uap, retval) 89967518Spendry struct proc *p; 90067518Spendry struct unwhiteout_args *uap; 90167518Spendry int *retval; 90267518Spendry { 90367518Spendry int error; 90467518Spendry struct nameidata nd; 90567518Spendry 90667575Spendry NDINIT(&nd, DELETE, LOCKPARENT|DOWHITEOUT, UIO_USERSPACE, uap->path, p); 90767575Spendry error = namei(&nd); 90867575Spendry if (error) 90967518Spendry return (error); 91067575Spendry 91167575Spendry if (nd.ni_vp != NULLVP || !(nd.ni_cnd.cn_flags & ISWHITEOUT)) { 91267518Spendry VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 91367518Spendry if (nd.ni_dvp == nd.ni_vp) 91467518Spendry vrele(nd.ni_dvp); 91567518Spendry else 91667518Spendry vput(nd.ni_dvp); 91767518Spendry if (nd.ni_vp) 91867518Spendry vrele(nd.ni_vp); 91967518Spendry return (EEXIST); 92067518Spendry } 92167575Spendry 92267654Smckusick VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 92367747Spendry if (error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, DELETE)) 92467575Spendry VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 92567518Spendry vput(nd.ni_dvp); 92667518Spendry return (error); 92767518Spendry } 92867518Spendry 92967518Spendry /* 93049365Smckusick * Delete a name from the filesystem. 9316254Sroot */ 93254916Storek struct unlink_args { 93364410Sbostic char *path; 93454916Storek }; 93542441Smckusick /* ARGSUSED */ 93642441Smckusick unlink(p, uap, retval) 93745914Smckusick struct proc *p; 93854916Storek struct unlink_args *uap; 93942441Smckusick int *retval; 9406254Sroot { 94137741Smckusick register struct vnode *vp; 94237741Smckusick int error; 94347540Skarels struct nameidata nd; 9446254Sroot 94564410Sbostic NDINIT(&nd, DELETE, LOCKPARENT, UIO_USERSPACE, uap->path, p); 94652322Smckusick if (error = namei(&nd)) 94747540Skarels return (error); 94852322Smckusick vp = nd.ni_vp; 94967654Smckusick VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 95059382Smckusick VOP_LOCK(vp); 95164410Sbostic 95264585Sbostic if (vp->v_type != VDIR || 95364585Sbostic (error = suser(p->p_ucred, &p->p_acflag)) == 0) { 95464585Sbostic /* 95564585Sbostic * The root of a mounted filesystem cannot be deleted. 95664585Sbostic */ 95764585Sbostic if (vp->v_flag & VROOT) 95864585Sbostic error = EBUSY; 95964585Sbostic else 96064585Sbostic (void)vnode_pager_uncache(vp); 96164585Sbostic } 96264585Sbostic 96364585Sbostic if (!error) { 96467654Smckusick VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 96552322Smckusick error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); 96642465Smckusick } else { 96752322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 96852322Smckusick if (nd.ni_dvp == vp) 96952322Smckusick vrele(nd.ni_dvp); 97043344Smckusick else 97152322Smckusick vput(nd.ni_dvp); 97267575Spendry if (vp != NULLVP) 97367575Spendry vput(vp); 97442465Smckusick } 97547540Skarels return (error); 9766254Sroot } 9776254Sroot 97864410Sbostic /* 97964410Sbostic * Reposition read/write file offset. 98064410Sbostic */ 98160428Smckusick struct lseek_args { 98264410Sbostic int fd; 98354863Storek int pad; 98464410Sbostic off_t offset; 98564410Sbostic int whence; 98654863Storek }; 98760414Smckusick lseek(p, uap, retval) 98853468Smckusick struct proc *p; 98960428Smckusick register struct lseek_args *uap; 99054916Storek int *retval; 99142441Smckusick { 99247540Skarels struct ucred *cred = p->p_ucred; 99345914Smckusick register struct filedesc *fdp = p->p_fd; 99442441Smckusick register struct file *fp; 99537741Smckusick struct vattr vattr; 99637741Smckusick int error; 9976254Sroot 99864410Sbostic if ((u_int)uap->fd >= fdp->fd_nfiles || 99964410Sbostic (fp = fdp->fd_ofiles[uap->fd]) == NULL) 100047540Skarels return (EBADF); 100137741Smckusick if (fp->f_type != DTYPE_VNODE) 100247540Skarels return (ESPIPE); 100364410Sbostic switch (uap->whence) { 100413878Ssam case L_INCR: 100564410Sbostic fp->f_offset += uap->offset; 100613878Ssam break; 100713878Ssam case L_XTND: 100864410Sbostic if (error = 100964410Sbostic VOP_GETATTR((struct vnode *)fp->f_data, &vattr, cred, p)) 101047540Skarels return (error); 101164410Sbostic fp->f_offset = uap->offset + vattr.va_size; 101213878Ssam break; 101313878Ssam case L_SET: 101464410Sbostic fp->f_offset = uap->offset; 101513878Ssam break; 101613878Ssam default: 101747540Skarels return (EINVAL); 101813878Ssam } 101954916Storek *(off_t *)retval = fp->f_offset; 102047540Skarels return (0); 10216254Sroot } 10226254Sroot 102360414Smckusick #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 10246254Sroot /* 102564410Sbostic * Reposition read/write file offset. 102660036Smckusick */ 102760428Smckusick struct olseek_args { 102864410Sbostic int fd; 102964410Sbostic long offset; 103064410Sbostic int whence; 103160036Smckusick }; 103260414Smckusick olseek(p, uap, retval) 103360036Smckusick struct proc *p; 103460428Smckusick register struct olseek_args *uap; 103560036Smckusick int *retval; 103660036Smckusick { 103760428Smckusick struct lseek_args nuap; 103860036Smckusick off_t qret; 103960036Smckusick int error; 104060036Smckusick 104164410Sbostic nuap.fd = uap->fd; 104264410Sbostic nuap.offset = uap->offset; 104364410Sbostic nuap.whence = uap->whence; 104460428Smckusick error = lseek(p, &nuap, &qret); 104560036Smckusick *(long *)retval = qret; 104660036Smckusick return (error); 104760036Smckusick } 104860414Smckusick #endif /* COMPAT_43 */ 104960036Smckusick 105060036Smckusick /* 105149365Smckusick * Check access permissions. 10526254Sroot */ 105363427Sbostic struct access_args { 105464410Sbostic char *path; 105564410Sbostic int flags; 105654916Storek }; 105763427Sbostic access(p, uap, retval) 105845914Smckusick struct proc *p; 105963427Sbostic register struct access_args *uap; 106042441Smckusick int *retval; 106142441Smckusick { 106247540Skarels register struct ucred *cred = p->p_ucred; 106337741Smckusick register struct vnode *vp; 106464585Sbostic int error, flags, t_gid, t_uid; 106547540Skarels struct nameidata nd; 10666254Sroot 106764585Sbostic t_uid = cred->cr_uid; 106864585Sbostic t_gid = cred->cr_groups[0]; 106947540Skarels cred->cr_uid = p->p_cred->p_ruid; 107047540Skarels cred->cr_groups[0] = p->p_cred->p_rgid; 107164410Sbostic NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); 107252322Smckusick if (error = namei(&nd)) 107337741Smckusick goto out1; 107452322Smckusick vp = nd.ni_vp; 107564410Sbostic 107664410Sbostic /* Flags == 0 means only check for existence. */ 107764410Sbostic if (uap->flags) { 107864410Sbostic flags = 0; 107964410Sbostic if (uap->flags & R_OK) 108064410Sbostic flags |= VREAD; 108164410Sbostic if (uap->flags & W_OK) 108264410Sbostic flags |= VWRITE; 108364410Sbostic if (uap->flags & X_OK) 108464410Sbostic flags |= VEXEC; 108564410Sbostic if ((flags & VWRITE) == 0 || (error = vn_writechk(vp)) == 0) 108664410Sbostic error = VOP_ACCESS(vp, flags, cred, p); 10876254Sroot } 108837741Smckusick vput(vp); 108937741Smckusick out1: 109064585Sbostic cred->cr_uid = t_uid; 109164585Sbostic cred->cr_groups[0] = t_gid; 109247540Skarels return (error); 10936254Sroot } 10946254Sroot 109554348Smckusick #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 10966254Sroot /* 109764410Sbostic * Get file status; this version follows links. 109837Sbill */ 109954916Storek struct ostat_args { 110064410Sbostic char *path; 110154916Storek struct ostat *ub; 110254916Storek }; 110342441Smckusick /* ARGSUSED */ 110453759Smckusick ostat(p, uap, retval) 110545914Smckusick struct proc *p; 110654916Storek register struct ostat_args *uap; 110753468Smckusick int *retval; 110853468Smckusick { 110953468Smckusick struct stat sb; 111053468Smckusick struct ostat osb; 111153468Smckusick int error; 111253468Smckusick struct nameidata nd; 111353468Smckusick 111464410Sbostic NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); 111553468Smckusick if (error = namei(&nd)) 111653468Smckusick return (error); 111753468Smckusick error = vn_stat(nd.ni_vp, &sb, p); 111853468Smckusick vput(nd.ni_vp); 111953468Smckusick if (error) 112053468Smckusick return (error); 112153468Smckusick cvtstat(&sb, &osb); 112253468Smckusick error = copyout((caddr_t)&osb, (caddr_t)uap->ub, sizeof (osb)); 112353468Smckusick return (error); 112453468Smckusick } 112553468Smckusick 112653468Smckusick /* 112764410Sbostic * Get file status; this version does not follow links. 112853468Smckusick */ 112954916Storek struct olstat_args { 113064410Sbostic char *path; 113154916Storek struct ostat *ub; 113254916Storek }; 113353468Smckusick /* ARGSUSED */ 113453759Smckusick olstat(p, uap, retval) 113553468Smckusick struct proc *p; 113654916Storek register struct olstat_args *uap; 113753468Smckusick int *retval; 113853468Smckusick { 1139*67748Smckusick struct vnode *vp, *dvp; 1140*67748Smckusick struct stat sb, sb1; 114153468Smckusick struct ostat osb; 114253468Smckusick int error; 114353468Smckusick struct nameidata nd; 114453468Smckusick 1145*67748Smckusick NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | LOCKPARENT, UIO_USERSPACE, 1146*67748Smckusick uap->path, p); 114753468Smckusick if (error = namei(&nd)) 114853468Smckusick return (error); 1149*67748Smckusick /* 1150*67748Smckusick * For symbolic links, always return the attributes of its 1151*67748Smckusick * containing directory, except for mode, size, and links. 1152*67748Smckusick */ 1153*67748Smckusick vp = nd.ni_vp; 1154*67748Smckusick dvp = nd.ni_dvp; 1155*67748Smckusick if (vp->v_type != VLNK) { 1156*67748Smckusick if (dvp == vp) 1157*67748Smckusick vrele(dvp); 1158*67748Smckusick else 1159*67748Smckusick vput(dvp); 1160*67748Smckusick error = vn_stat(vp, &sb, p); 1161*67748Smckusick vput(vp); 1162*67748Smckusick if (error) 1163*67748Smckusick return (error); 1164*67748Smckusick } else { 1165*67748Smckusick error = vn_stat(dvp, &sb, p); 1166*67748Smckusick vput(dvp); 1167*67748Smckusick if (error) { 1168*67748Smckusick vput(vp); 1169*67748Smckusick return (error); 1170*67748Smckusick } 1171*67748Smckusick error = vn_stat(vp, &sb1, p); 1172*67748Smckusick vput(vp); 1173*67748Smckusick if (error) 1174*67748Smckusick return (error); 1175*67748Smckusick sb.st_mode &= ~S_IFDIR; 1176*67748Smckusick sb.st_mode |= S_IFLNK; 1177*67748Smckusick sb.st_nlink = sb1.st_nlink; 1178*67748Smckusick sb.st_size = sb1.st_size; 1179*67748Smckusick sb.st_blocks = sb1.st_blocks; 1180*67748Smckusick } 118153468Smckusick cvtstat(&sb, &osb); 118253468Smckusick error = copyout((caddr_t)&osb, (caddr_t)uap->ub, sizeof (osb)); 118353468Smckusick return (error); 118453468Smckusick } 118553468Smckusick 118653468Smckusick /* 118764410Sbostic * Convert from an old to a new stat structure. 118853468Smckusick */ 118953468Smckusick cvtstat(st, ost) 119053468Smckusick struct stat *st; 119153468Smckusick struct ostat *ost; 119253468Smckusick { 119353468Smckusick 119453468Smckusick ost->st_dev = st->st_dev; 119553468Smckusick ost->st_ino = st->st_ino; 119653468Smckusick ost->st_mode = st->st_mode; 119753468Smckusick ost->st_nlink = st->st_nlink; 119853468Smckusick ost->st_uid = st->st_uid; 119953468Smckusick ost->st_gid = st->st_gid; 120053468Smckusick ost->st_rdev = st->st_rdev; 120153468Smckusick if (st->st_size < (quad_t)1 << 32) 120253468Smckusick ost->st_size = st->st_size; 120353468Smckusick else 120453468Smckusick ost->st_size = -2; 120553468Smckusick ost->st_atime = st->st_atime; 120653468Smckusick ost->st_mtime = st->st_mtime; 120753468Smckusick ost->st_ctime = st->st_ctime; 120853468Smckusick ost->st_blksize = st->st_blksize; 120953468Smckusick ost->st_blocks = st->st_blocks; 121053468Smckusick ost->st_flags = st->st_flags; 121153468Smckusick ost->st_gen = st->st_gen; 121253468Smckusick } 121354348Smckusick #endif /* COMPAT_43 || COMPAT_SUNOS */ 121453468Smckusick 121553468Smckusick /* 121664410Sbostic * Get file status; this version follows links. 121753468Smckusick */ 121854916Storek struct stat_args { 121964410Sbostic char *path; 122054916Storek struct stat *ub; 122154916Storek }; 122253468Smckusick /* ARGSUSED */ 122353759Smckusick stat(p, uap, retval) 122453468Smckusick struct proc *p; 122554916Storek register struct stat_args *uap; 122642441Smckusick int *retval; 122737Sbill { 122842441Smckusick struct stat sb; 122942441Smckusick int error; 123047540Skarels struct nameidata nd; 123137Sbill 123264410Sbostic NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); 123352322Smckusick if (error = namei(&nd)) 123447540Skarels return (error); 123552322Smckusick error = vn_stat(nd.ni_vp, &sb, p); 123652322Smckusick vput(nd.ni_vp); 123742441Smckusick if (error) 123847540Skarels return (error); 123942441Smckusick error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb)); 124047540Skarels return (error); 124137Sbill } 124237Sbill 124337Sbill /* 124464410Sbostic * Get file status; this version does not follow links. 12455992Swnj */ 124654916Storek struct lstat_args { 124764410Sbostic char *path; 124854916Storek struct stat *ub; 124954916Storek }; 125042441Smckusick /* ARGSUSED */ 125153759Smckusick lstat(p, uap, retval) 125245914Smckusick struct proc *p; 125354916Storek register struct lstat_args *uap; 125442441Smckusick int *retval; 125542441Smckusick { 125637741Smckusick int error; 125759373Smckusick struct vnode *vp, *dvp; 125859373Smckusick struct stat sb, sb1; 125947540Skarels struct nameidata nd; 12605992Swnj 126159373Smckusick NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | LOCKPARENT, UIO_USERSPACE, 126264410Sbostic uap->path, p); 126352322Smckusick if (error = namei(&nd)) 126447540Skarels return (error); 126559373Smckusick /* 126659373Smckusick * For symbolic links, always return the attributes of its 126759373Smckusick * containing directory, except for mode, size, and links. 126859373Smckusick */ 126959373Smckusick vp = nd.ni_vp; 127059373Smckusick dvp = nd.ni_dvp; 127159373Smckusick if (vp->v_type != VLNK) { 127259373Smckusick if (dvp == vp) 127359373Smckusick vrele(dvp); 127459373Smckusick else 127559373Smckusick vput(dvp); 127659373Smckusick error = vn_stat(vp, &sb, p); 127759373Smckusick vput(vp); 127859373Smckusick if (error) 127959373Smckusick return (error); 128059373Smckusick } else { 128159373Smckusick error = vn_stat(dvp, &sb, p); 128259373Smckusick vput(dvp); 128359373Smckusick if (error) { 128459373Smckusick vput(vp); 128559373Smckusick return (error); 128659373Smckusick } 128759373Smckusick error = vn_stat(vp, &sb1, p); 128859373Smckusick vput(vp); 128959373Smckusick if (error) 129059373Smckusick return (error); 129159373Smckusick sb.st_mode &= ~S_IFDIR; 129259373Smckusick sb.st_mode |= S_IFLNK; 129359373Smckusick sb.st_nlink = sb1.st_nlink; 129459373Smckusick sb.st_size = sb1.st_size; 129559373Smckusick sb.st_blocks = sb1.st_blocks; 129659373Smckusick } 129737741Smckusick error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb)); 129847540Skarels return (error); 12995992Swnj } 13005992Swnj 13015992Swnj /* 130264410Sbostic * Get configurable pathname variables. 130360414Smckusick */ 130460414Smckusick struct pathconf_args { 130564410Sbostic char *path; 130660414Smckusick int name; 130760414Smckusick }; 130860414Smckusick /* ARGSUSED */ 130960414Smckusick pathconf(p, uap, retval) 131060414Smckusick struct proc *p; 131160414Smckusick register struct pathconf_args *uap; 131260414Smckusick int *retval; 131360414Smckusick { 131460414Smckusick int error; 131560414Smckusick struct nameidata nd; 131660414Smckusick 131764410Sbostic NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); 131860414Smckusick if (error = namei(&nd)) 131960414Smckusick return (error); 132060414Smckusick error = VOP_PATHCONF(nd.ni_vp, uap->name, retval); 132160414Smckusick vput(nd.ni_vp); 132260414Smckusick return (error); 132360414Smckusick } 132460414Smckusick 132560414Smckusick /* 132649365Smckusick * Return target name of a symbolic link. 132737Sbill */ 132854916Storek struct readlink_args { 132964410Sbostic char *path; 133054916Storek char *buf; 133154916Storek int count; 133254916Storek }; 133342441Smckusick /* ARGSUSED */ 133442441Smckusick readlink(p, uap, retval) 133545914Smckusick struct proc *p; 133654916Storek register struct readlink_args *uap; 133742441Smckusick int *retval; 133842441Smckusick { 133937741Smckusick register struct vnode *vp; 134037741Smckusick struct iovec aiov; 134137741Smckusick struct uio auio; 134237741Smckusick int error; 134347540Skarels struct nameidata nd; 13445992Swnj 134564410Sbostic NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); 134652322Smckusick if (error = namei(&nd)) 134747540Skarels return (error); 134852322Smckusick vp = nd.ni_vp; 134964410Sbostic if (vp->v_type != VLNK) 135037741Smckusick error = EINVAL; 135164410Sbostic else { 135264410Sbostic aiov.iov_base = uap->buf; 135364410Sbostic aiov.iov_len = uap->count; 135464410Sbostic auio.uio_iov = &aiov; 135564410Sbostic auio.uio_iovcnt = 1; 135664410Sbostic auio.uio_offset = 0; 135764410Sbostic auio.uio_rw = UIO_READ; 135864410Sbostic auio.uio_segflg = UIO_USERSPACE; 135964410Sbostic auio.uio_procp = p; 136064410Sbostic auio.uio_resid = uap->count; 136164410Sbostic error = VOP_READLINK(vp, &auio, p->p_ucred); 13625992Swnj } 136337741Smckusick vput(vp); 136442441Smckusick *retval = uap->count - auio.uio_resid; 136547540Skarels return (error); 13665992Swnj } 13675992Swnj 13689167Ssam /* 136964410Sbostic * Change flags of a file given a path name. 137038259Smckusick */ 137154916Storek struct chflags_args { 137264410Sbostic char *path; 137354916Storek int flags; 137454916Storek }; 137542441Smckusick /* ARGSUSED */ 137642441Smckusick chflags(p, uap, retval) 137745914Smckusick struct proc *p; 137854916Storek register struct chflags_args *uap; 137942441Smckusick int *retval; 138042441Smckusick { 138138259Smckusick register struct vnode *vp; 138238259Smckusick struct vattr vattr; 138338259Smckusick int error; 138447540Skarels struct nameidata nd; 138538259Smckusick 138664410Sbostic NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); 138752322Smckusick if (error = namei(&nd)) 138847540Skarels return (error); 138952322Smckusick vp = nd.ni_vp; 139067654Smckusick VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 139159382Smckusick VOP_LOCK(vp); 139264410Sbostic if (vp->v_mount->mnt_flag & MNT_RDONLY) 139338259Smckusick error = EROFS; 139464410Sbostic else { 139564410Sbostic VATTR_NULL(&vattr); 139664410Sbostic vattr.va_flags = uap->flags; 139764410Sbostic error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 139838259Smckusick } 139938259Smckusick vput(vp); 140047540Skarels return (error); 140138259Smckusick } 140238259Smckusick 140338259Smckusick /* 140438259Smckusick * Change flags of a file given a file descriptor. 140538259Smckusick */ 140654916Storek struct fchflags_args { 140754916Storek int fd; 140854916Storek int flags; 140954916Storek }; 141042441Smckusick /* ARGSUSED */ 141142441Smckusick fchflags(p, uap, retval) 141245914Smckusick struct proc *p; 141354916Storek register struct fchflags_args *uap; 141442441Smckusick int *retval; 141542441Smckusick { 141638259Smckusick struct vattr vattr; 141738259Smckusick struct vnode *vp; 141838259Smckusick struct file *fp; 141938259Smckusick int error; 142038259Smckusick 142145914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 142247540Skarels return (error); 142338259Smckusick vp = (struct vnode *)fp->f_data; 142467654Smckusick VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 142538259Smckusick VOP_LOCK(vp); 142664410Sbostic if (vp->v_mount->mnt_flag & MNT_RDONLY) 142738259Smckusick error = EROFS; 142864410Sbostic else { 142964410Sbostic VATTR_NULL(&vattr); 143064410Sbostic vattr.va_flags = uap->flags; 143164410Sbostic error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 143238259Smckusick } 143338259Smckusick VOP_UNLOCK(vp); 143447540Skarels return (error); 143538259Smckusick } 143638259Smckusick 143738259Smckusick /* 14389167Ssam * Change mode of a file given path name. 14399167Ssam */ 144054916Storek struct chmod_args { 144164410Sbostic char *path; 144264410Sbostic int mode; 144354916Storek }; 144442441Smckusick /* ARGSUSED */ 144542441Smckusick chmod(p, uap, retval) 144645914Smckusick struct proc *p; 144754916Storek register struct chmod_args *uap; 144842441Smckusick int *retval; 144942441Smckusick { 145037741Smckusick register struct vnode *vp; 145137741Smckusick struct vattr vattr; 145237741Smckusick int error; 145347540Skarels struct nameidata nd; 14545992Swnj 145564410Sbostic NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); 145652322Smckusick if (error = namei(&nd)) 145747540Skarels return (error); 145852322Smckusick vp = nd.ni_vp; 145967654Smckusick VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 146059382Smckusick VOP_LOCK(vp); 146164410Sbostic if (vp->v_mount->mnt_flag & MNT_RDONLY) 146237741Smckusick error = EROFS; 146364410Sbostic else { 146464410Sbostic VATTR_NULL(&vattr); 146564410Sbostic vattr.va_mode = uap->mode & ALLPERMS; 146664410Sbostic error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 146737741Smckusick } 146837741Smckusick vput(vp); 146947540Skarels return (error); 14707701Ssam } 14717439Sroot 14729167Ssam /* 14739167Ssam * Change mode of a file given a file descriptor. 14749167Ssam */ 147554916Storek struct fchmod_args { 147654916Storek int fd; 147764410Sbostic int mode; 147854916Storek }; 147942441Smckusick /* ARGSUSED */ 148042441Smckusick fchmod(p, uap, retval) 148145914Smckusick struct proc *p; 148254916Storek register struct fchmod_args *uap; 148342441Smckusick int *retval; 148442441Smckusick { 148537741Smckusick struct vattr vattr; 148637741Smckusick struct vnode *vp; 148737741Smckusick struct file *fp; 148837741Smckusick int error; 14897701Ssam 149045914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 149147540Skarels return (error); 149237741Smckusick vp = (struct vnode *)fp->f_data; 149367654Smckusick VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 149437741Smckusick VOP_LOCK(vp); 149564410Sbostic if (vp->v_mount->mnt_flag & MNT_RDONLY) 149637741Smckusick error = EROFS; 149764410Sbostic else { 149864410Sbostic VATTR_NULL(&vattr); 149964410Sbostic vattr.va_mode = uap->mode & ALLPERMS; 150064410Sbostic error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 15017439Sroot } 150237741Smckusick VOP_UNLOCK(vp); 150347540Skarels return (error); 15045992Swnj } 15055992Swnj 15069167Ssam /* 15079167Ssam * Set ownership given a path name. 15089167Ssam */ 150954916Storek struct chown_args { 151064410Sbostic char *path; 151154916Storek int uid; 151254916Storek int gid; 151354916Storek }; 151442441Smckusick /* ARGSUSED */ 151542441Smckusick chown(p, uap, retval) 151645914Smckusick struct proc *p; 151754916Storek register struct chown_args *uap; 151842441Smckusick int *retval; 151942441Smckusick { 152037741Smckusick register struct vnode *vp; 152137741Smckusick struct vattr vattr; 152237741Smckusick int error; 152347540Skarels struct nameidata nd; 152437Sbill 152566510Sbostic NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); 152652322Smckusick if (error = namei(&nd)) 152747540Skarels return (error); 152852322Smckusick vp = nd.ni_vp; 152967654Smckusick VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 153059382Smckusick VOP_LOCK(vp); 153164410Sbostic if (vp->v_mount->mnt_flag & MNT_RDONLY) 153237741Smckusick error = EROFS; 153364410Sbostic else { 153464410Sbostic VATTR_NULL(&vattr); 153564410Sbostic vattr.va_uid = uap->uid; 153664410Sbostic vattr.va_gid = uap->gid; 153764410Sbostic error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 153837741Smckusick } 153937741Smckusick vput(vp); 154047540Skarels return (error); 15417701Ssam } 15427439Sroot 15439167Ssam /* 15449167Ssam * Set ownership given a file descriptor. 15459167Ssam */ 154654916Storek struct fchown_args { 154754916Storek int fd; 154854916Storek int uid; 154954916Storek int gid; 155054916Storek }; 155142441Smckusick /* ARGSUSED */ 155242441Smckusick fchown(p, uap, retval) 155345914Smckusick struct proc *p; 155454916Storek register struct fchown_args *uap; 155542441Smckusick int *retval; 155642441Smckusick { 155737741Smckusick struct vattr vattr; 155837741Smckusick struct vnode *vp; 155937741Smckusick struct file *fp; 156037741Smckusick int error; 15617701Ssam 156245914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 156347540Skarels return (error); 156437741Smckusick vp = (struct vnode *)fp->f_data; 156567654Smckusick VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 156637741Smckusick VOP_LOCK(vp); 156764410Sbostic if (vp->v_mount->mnt_flag & MNT_RDONLY) 156837741Smckusick error = EROFS; 156964410Sbostic else { 157064410Sbostic VATTR_NULL(&vattr); 157164410Sbostic vattr.va_uid = uap->uid; 157264410Sbostic vattr.va_gid = uap->gid; 157364410Sbostic error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 157437741Smckusick } 157537741Smckusick VOP_UNLOCK(vp); 157647540Skarels return (error); 15777701Ssam } 15787701Ssam 157942441Smckusick /* 158042441Smckusick * Set the access and modification times of a file. 158142441Smckusick */ 158254916Storek struct utimes_args { 158364410Sbostic char *path; 158454916Storek struct timeval *tptr; 158554916Storek }; 158642441Smckusick /* ARGSUSED */ 158742441Smckusick utimes(p, uap, retval) 158845914Smckusick struct proc *p; 158954916Storek register struct utimes_args *uap; 159042441Smckusick int *retval; 159142441Smckusick { 159237741Smckusick register struct vnode *vp; 159311811Ssam struct timeval tv[2]; 159437741Smckusick struct vattr vattr; 159558840Storek int error; 159647540Skarels struct nameidata nd; 159711811Ssam 159858505Sbostic VATTR_NULL(&vattr); 159958505Sbostic if (uap->tptr == NULL) { 160058505Sbostic microtime(&tv[0]); 160158505Sbostic tv[1] = tv[0]; 160258548Sbostic vattr.va_vaflags |= VA_UTIMES_NULL; 160358505Sbostic } else if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv))) 160458505Sbostic return (error); 160564410Sbostic NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); 160652322Smckusick if (error = namei(&nd)) 160747540Skarels return (error); 160852322Smckusick vp = nd.ni_vp; 160967654Smckusick VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 161059382Smckusick VOP_LOCK(vp); 161164410Sbostic if (vp->v_mount->mnt_flag & MNT_RDONLY) 161237741Smckusick error = EROFS; 161364410Sbostic else { 161464410Sbostic vattr.va_atime.ts_sec = tv[0].tv_sec; 161564410Sbostic vattr.va_atime.ts_nsec = tv[0].tv_usec * 1000; 161664410Sbostic vattr.va_mtime.ts_sec = tv[1].tv_sec; 161764410Sbostic vattr.va_mtime.ts_nsec = tv[1].tv_usec * 1000; 161864410Sbostic error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 161921015Smckusick } 162037741Smckusick vput(vp); 162147540Skarels return (error); 162211811Ssam } 162311811Ssam 162464410Sbostic /* 162564410Sbostic * Truncate a file given its path name. 162664410Sbostic */ 162760428Smckusick struct truncate_args { 162864410Sbostic char *path; 162954863Storek int pad; 163054863Storek off_t length; 163154863Storek }; 163253468Smckusick /* ARGSUSED */ 163360414Smckusick truncate(p, uap, retval) 163453468Smckusick struct proc *p; 163560428Smckusick register struct truncate_args *uap; 163653468Smckusick int *retval; 163753468Smckusick { 163837741Smckusick register struct vnode *vp; 163937741Smckusick struct vattr vattr; 164037741Smckusick int error; 164147540Skarels struct nameidata nd; 16427701Ssam 164364410Sbostic NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); 164452322Smckusick if (error = namei(&nd)) 164547540Skarels return (error); 164652322Smckusick vp = nd.ni_vp; 164767654Smckusick VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 164859382Smckusick VOP_LOCK(vp); 164964410Sbostic if (vp->v_type == VDIR) 165037741Smckusick error = EISDIR; 165164410Sbostic else if ((error = vn_writechk(vp)) == 0 && 165264410Sbostic (error = VOP_ACCESS(vp, VWRITE, p->p_ucred, p)) == 0) { 165364410Sbostic VATTR_NULL(&vattr); 165464410Sbostic vattr.va_size = uap->length; 165564410Sbostic error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 16567701Ssam } 165737741Smckusick vput(vp); 165847540Skarels return (error); 16597701Ssam } 16607701Ssam 166164410Sbostic /* 166264410Sbostic * Truncate a file given a file descriptor. 166364410Sbostic */ 166460428Smckusick struct ftruncate_args { 166554863Storek int fd; 166654863Storek int pad; 166754863Storek off_t length; 166854863Storek }; 166942441Smckusick /* ARGSUSED */ 167060414Smckusick ftruncate(p, uap, retval) 167145914Smckusick struct proc *p; 167260428Smckusick register struct ftruncate_args *uap; 167342441Smckusick int *retval; 167442441Smckusick { 167537741Smckusick struct vattr vattr; 167637741Smckusick struct vnode *vp; 16777701Ssam struct file *fp; 167837741Smckusick int error; 16797701Ssam 168045914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 168147540Skarels return (error); 168237741Smckusick if ((fp->f_flag & FWRITE) == 0) 168347540Skarels return (EINVAL); 168437741Smckusick vp = (struct vnode *)fp->f_data; 168567654Smckusick VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 168637741Smckusick VOP_LOCK(vp); 168764410Sbostic if (vp->v_type == VDIR) 168837741Smckusick error = EISDIR; 168964410Sbostic else if ((error = vn_writechk(vp)) == 0) { 169064410Sbostic VATTR_NULL(&vattr); 169164410Sbostic vattr.va_size = uap->length; 169264410Sbostic error = VOP_SETATTR(vp, &vattr, fp->f_cred, p); 16937701Ssam } 169437741Smckusick VOP_UNLOCK(vp); 169547540Skarels return (error); 16967701Ssam } 16977701Ssam 169854863Storek #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 16999167Ssam /* 170054863Storek * Truncate a file given its path name. 170154863Storek */ 170260428Smckusick struct otruncate_args { 170364410Sbostic char *path; 170454916Storek long length; 170554916Storek }; 170654863Storek /* ARGSUSED */ 170760105Smckusick otruncate(p, uap, retval) 170854863Storek struct proc *p; 170960428Smckusick register struct otruncate_args *uap; 171054863Storek int *retval; 171154863Storek { 171260428Smckusick struct truncate_args nuap; 171354863Storek 171464410Sbostic nuap.path = uap->path; 171554863Storek nuap.length = uap->length; 171660428Smckusick return (truncate(p, &nuap, retval)); 171754863Storek } 171854863Storek 171954863Storek /* 172054863Storek * Truncate a file given a file descriptor. 172154863Storek */ 172260428Smckusick struct oftruncate_args { 172354916Storek int fd; 172454916Storek long length; 172554916Storek }; 172654863Storek /* ARGSUSED */ 172760105Smckusick oftruncate(p, uap, retval) 172854863Storek struct proc *p; 172960428Smckusick register struct oftruncate_args *uap; 173054863Storek int *retval; 173154863Storek { 173260428Smckusick struct ftruncate_args nuap; 173354863Storek 173454863Storek nuap.fd = uap->fd; 173554863Storek nuap.length = uap->length; 173660428Smckusick return (ftruncate(p, &nuap, retval)); 173754863Storek } 173854863Storek #endif /* COMPAT_43 || COMPAT_SUNOS */ 173954863Storek 174054863Storek /* 174164410Sbostic * Sync an open file. 17429167Ssam */ 174354916Storek struct fsync_args { 174454916Storek int fd; 174554916Storek }; 174642441Smckusick /* ARGSUSED */ 174742441Smckusick fsync(p, uap, retval) 174845914Smckusick struct proc *p; 174954916Storek struct fsync_args *uap; 175042441Smckusick int *retval; 17519167Ssam { 175239592Smckusick register struct vnode *vp; 17539167Ssam struct file *fp; 175437741Smckusick int error; 17559167Ssam 175645914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 175747540Skarels return (error); 175839592Smckusick vp = (struct vnode *)fp->f_data; 175939592Smckusick VOP_LOCK(vp); 176054441Smckusick error = VOP_FSYNC(vp, fp->f_cred, MNT_WAIT, p); 176139592Smckusick VOP_UNLOCK(vp); 176247540Skarels return (error); 17639167Ssam } 17649167Ssam 17659167Ssam /* 176664410Sbostic * Rename files. Source and destination must either both be directories, 176764410Sbostic * or both not be directories. If target is a directory, it must be empty. 17689167Ssam */ 176954916Storek struct rename_args { 177054916Storek char *from; 177154916Storek char *to; 177254916Storek }; 177342441Smckusick /* ARGSUSED */ 177442441Smckusick rename(p, uap, retval) 177545914Smckusick struct proc *p; 177654916Storek register struct rename_args *uap; 177742441Smckusick int *retval; 177842441Smckusick { 177937741Smckusick register struct vnode *tvp, *fvp, *tdvp; 178049735Smckusick struct nameidata fromnd, tond; 178137741Smckusick int error; 17827701Ssam 178352322Smckusick NDINIT(&fromnd, DELETE, WANTPARENT | SAVESTART, UIO_USERSPACE, 178452322Smckusick uap->from, p); 178552322Smckusick if (error = namei(&fromnd)) 178647540Skarels return (error); 178749735Smckusick fvp = fromnd.ni_vp; 178852322Smckusick NDINIT(&tond, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART, 178952322Smckusick UIO_USERSPACE, uap->to, p); 179052322Smckusick if (error = namei(&tond)) { 179152230Sheideman VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 179249735Smckusick vrele(fromnd.ni_dvp); 179342465Smckusick vrele(fvp); 179442465Smckusick goto out1; 179542465Smckusick } 179637741Smckusick tdvp = tond.ni_dvp; 179737741Smckusick tvp = tond.ni_vp; 179837741Smckusick if (tvp != NULL) { 179937741Smckusick if (fvp->v_type == VDIR && tvp->v_type != VDIR) { 180039242Sbostic error = ENOTDIR; 180137741Smckusick goto out; 180237741Smckusick } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) { 180339242Sbostic error = EISDIR; 180437741Smckusick goto out; 18059167Ssam } 18069167Ssam } 180739286Smckusick if (fvp == tdvp) 180837741Smckusick error = EINVAL; 180939286Smckusick /* 181049735Smckusick * If source is the same as the destination (that is the 181149735Smckusick * same inode number with the same name in the same directory), 181239286Smckusick * then there is nothing to do. 181339286Smckusick */ 181449735Smckusick if (fvp == tvp && fromnd.ni_dvp == tdvp && 181552322Smckusick fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen && 181652322Smckusick !bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr, 181752322Smckusick fromnd.ni_cnd.cn_namelen)) 181839286Smckusick error = -1; 181937741Smckusick out: 182042465Smckusick if (!error) { 182167654Smckusick VOP_LEASE(tdvp, p, p->p_ucred, LEASE_WRITE); 182252192Smckusick if (fromnd.ni_dvp != tdvp) 182367654Smckusick VOP_LEASE(fromnd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 182452192Smckusick if (tvp) 182567654Smckusick VOP_LEASE(tvp, p, p->p_ucred, LEASE_WRITE); 182652230Sheideman error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd, 182752230Sheideman tond.ni_dvp, tond.ni_vp, &tond.ni_cnd); 182842465Smckusick } else { 182952230Sheideman VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd); 183043344Smckusick if (tdvp == tvp) 183143344Smckusick vrele(tdvp); 183243344Smckusick else 183343344Smckusick vput(tdvp); 183442465Smckusick if (tvp) 183542465Smckusick vput(tvp); 183652230Sheideman VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 183749735Smckusick vrele(fromnd.ni_dvp); 183842465Smckusick vrele(fvp); 18399167Ssam } 184049735Smckusick vrele(tond.ni_startdir); 184152322Smckusick FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI); 184237741Smckusick out1: 184366801Smckusick if (fromnd.ni_startdir) 184466801Smckusick vrele(fromnd.ni_startdir); 184552322Smckusick FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI); 184639286Smckusick if (error == -1) 184747540Skarels return (0); 184847540Skarels return (error); 18497701Ssam } 18507701Ssam 18517535Sroot /* 185264410Sbostic * Make a directory file. 185312756Ssam */ 185454916Storek struct mkdir_args { 185564410Sbostic char *path; 185664410Sbostic int mode; 185754916Storek }; 185842441Smckusick /* ARGSUSED */ 185942441Smckusick mkdir(p, uap, retval) 186045914Smckusick struct proc *p; 186154916Storek register struct mkdir_args *uap; 186242441Smckusick int *retval; 186342441Smckusick { 186437741Smckusick register struct vnode *vp; 186537741Smckusick struct vattr vattr; 186637741Smckusick int error; 186747540Skarels struct nameidata nd; 186812756Ssam 186964410Sbostic NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->path, p); 187052322Smckusick if (error = namei(&nd)) 187147540Skarels return (error); 187252322Smckusick vp = nd.ni_vp; 187337741Smckusick if (vp != NULL) { 187452322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 187552322Smckusick if (nd.ni_dvp == vp) 187652322Smckusick vrele(nd.ni_dvp); 187743344Smckusick else 187852322Smckusick vput(nd.ni_dvp); 187942465Smckusick vrele(vp); 188047540Skarels return (EEXIST); 188112756Ssam } 188241362Smckusick VATTR_NULL(&vattr); 188337741Smckusick vattr.va_type = VDIR; 188464410Sbostic vattr.va_mode = (uap->mode & ACCESSPERMS) &~ p->p_fd->fd_cmask; 188567654Smckusick VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 188652322Smckusick error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr); 188738145Smckusick if (!error) 188852322Smckusick vput(nd.ni_vp); 188947540Skarels return (error); 189012756Ssam } 189112756Ssam 189212756Ssam /* 189364410Sbostic * Remove a directory file. 189412756Ssam */ 189554916Storek struct rmdir_args { 189664410Sbostic char *path; 189754916Storek }; 189842441Smckusick /* ARGSUSED */ 189942441Smckusick rmdir(p, uap, retval) 190045914Smckusick struct proc *p; 190154916Storek struct rmdir_args *uap; 190242441Smckusick int *retval; 190312756Ssam { 190437741Smckusick register struct vnode *vp; 190537741Smckusick int error; 190647540Skarels struct nameidata nd; 190712756Ssam 190864410Sbostic NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE, uap->path, p); 190952322Smckusick if (error = namei(&nd)) 191047540Skarels return (error); 191152322Smckusick vp = nd.ni_vp; 191237741Smckusick if (vp->v_type != VDIR) { 191337741Smckusick error = ENOTDIR; 191412756Ssam goto out; 191512756Ssam } 191612756Ssam /* 191737741Smckusick * No rmdir "." please. 191812756Ssam */ 191952322Smckusick if (nd.ni_dvp == vp) { 192037741Smckusick error = EINVAL; 192112756Ssam goto out; 192212756Ssam } 192312756Ssam /* 192449365Smckusick * The root of a mounted filesystem cannot be deleted. 192512756Ssam */ 192637741Smckusick if (vp->v_flag & VROOT) 192737741Smckusick error = EBUSY; 192812756Ssam out: 192942465Smckusick if (!error) { 193067654Smckusick VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 193167654Smckusick VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 193252322Smckusick error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); 193342465Smckusick } else { 193452322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 193552322Smckusick if (nd.ni_dvp == vp) 193652322Smckusick vrele(nd.ni_dvp); 193743344Smckusick else 193852322Smckusick vput(nd.ni_dvp); 193942465Smckusick vput(vp); 194042465Smckusick } 194147540Skarels return (error); 194212756Ssam } 194312756Ssam 194454620Smckusick #ifdef COMPAT_43 194537741Smckusick /* 194649365Smckusick * Read a block of directory entries in a file system independent format. 194737741Smckusick */ 194854916Storek struct ogetdirentries_args { 194954916Storek int fd; 195054916Storek char *buf; 195164410Sbostic u_int count; 195254916Storek long *basep; 195354916Storek }; 195454620Smckusick ogetdirentries(p, uap, retval) 195554620Smckusick struct proc *p; 195654916Storek register struct ogetdirentries_args *uap; 195754620Smckusick int *retval; 195854620Smckusick { 195954620Smckusick register struct vnode *vp; 196054620Smckusick struct file *fp; 196154620Smckusick struct uio auio, kuio; 196254620Smckusick struct iovec aiov, kiov; 196354620Smckusick struct dirent *dp, *edp; 196454620Smckusick caddr_t dirbuf; 196567362Smckusick int error, eofflag, readcnt; 196654969Smckusick long loff; 196754620Smckusick 196854620Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 196954620Smckusick return (error); 197054620Smckusick if ((fp->f_flag & FREAD) == 0) 197154620Smckusick return (EBADF); 197254620Smckusick vp = (struct vnode *)fp->f_data; 197367362Smckusick unionread: 197454620Smckusick if (vp->v_type != VDIR) 197554620Smckusick return (EINVAL); 197654620Smckusick aiov.iov_base = uap->buf; 197754620Smckusick aiov.iov_len = uap->count; 197854620Smckusick auio.uio_iov = &aiov; 197954620Smckusick auio.uio_iovcnt = 1; 198054620Smckusick auio.uio_rw = UIO_READ; 198154620Smckusick auio.uio_segflg = UIO_USERSPACE; 198254620Smckusick auio.uio_procp = p; 198354620Smckusick auio.uio_resid = uap->count; 198454620Smckusick VOP_LOCK(vp); 198554969Smckusick loff = auio.uio_offset = fp->f_offset; 198654620Smckusick # if (BYTE_ORDER != LITTLE_ENDIAN) 198756339Smckusick if (vp->v_mount->mnt_maxsymlinklen <= 0) { 198867362Smckusick error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, 198967362Smckusick (u_long *)0, 0); 199056339Smckusick fp->f_offset = auio.uio_offset; 199156339Smckusick } else 199254620Smckusick # endif 199354620Smckusick { 199454620Smckusick kuio = auio; 199554620Smckusick kuio.uio_iov = &kiov; 199654620Smckusick kuio.uio_segflg = UIO_SYSSPACE; 199754620Smckusick kiov.iov_len = uap->count; 199854620Smckusick MALLOC(dirbuf, caddr_t, uap->count, M_TEMP, M_WAITOK); 199954620Smckusick kiov.iov_base = dirbuf; 200067362Smckusick error = VOP_READDIR(vp, &kuio, fp->f_cred, &eofflag, 200167362Smckusick (u_long *)0, 0); 200256339Smckusick fp->f_offset = kuio.uio_offset; 200354620Smckusick if (error == 0) { 200454620Smckusick readcnt = uap->count - kuio.uio_resid; 200554620Smckusick edp = (struct dirent *)&dirbuf[readcnt]; 200654620Smckusick for (dp = (struct dirent *)dirbuf; dp < edp; ) { 200754620Smckusick # if (BYTE_ORDER == LITTLE_ENDIAN) 200854969Smckusick /* 200955009Smckusick * The expected low byte of 201055009Smckusick * dp->d_namlen is our dp->d_type. 201155009Smckusick * The high MBZ byte of dp->d_namlen 201255009Smckusick * is our dp->d_namlen. 201354969Smckusick */ 201455009Smckusick dp->d_type = dp->d_namlen; 201555009Smckusick dp->d_namlen = 0; 201655009Smckusick # else 201755009Smckusick /* 201855009Smckusick * The dp->d_type is the high byte 201955009Smckusick * of the expected dp->d_namlen, 202055009Smckusick * so must be zero'ed. 202155009Smckusick */ 202255009Smckusick dp->d_type = 0; 202354620Smckusick # endif 202454620Smckusick if (dp->d_reclen > 0) { 202554620Smckusick dp = (struct dirent *) 202654620Smckusick ((char *)dp + dp->d_reclen); 202754620Smckusick } else { 202854620Smckusick error = EIO; 202954620Smckusick break; 203054620Smckusick } 203154620Smckusick } 203254620Smckusick if (dp >= edp) 203354620Smckusick error = uiomove(dirbuf, readcnt, &auio); 203454620Smckusick } 203554620Smckusick FREE(dirbuf, M_TEMP); 203654620Smckusick } 203754620Smckusick VOP_UNLOCK(vp); 203854620Smckusick if (error) 203954620Smckusick return (error); 204067362Smckusick 204167362Smckusick #ifdef UNION 204267362Smckusick { 204367362Smckusick extern int (**union_vnodeop_p)(); 204467362Smckusick extern struct vnode *union_lowervp __P((struct vnode *)); 204567362Smckusick 204667362Smckusick if ((uap->count == auio.uio_resid) && 204767362Smckusick (vp->v_op == union_vnodeop_p)) { 204867362Smckusick struct vnode *lvp; 204967362Smckusick 205067362Smckusick lvp = union_lowervp(vp); 205167362Smckusick if (lvp != NULLVP) { 205267575Spendry struct vattr va; 205367575Spendry 205467575Spendry /* 205567575Spendry * If the directory is opaque, 205667575Spendry * then don't show lower entries 205767575Spendry */ 205867575Spendry error = VOP_GETATTR(vp, &va, fp->f_cred, p); 205967575Spendry if (va.va_flags & OPAQUE) { 206067575Spendry vrele(lvp); 206167575Spendry lvp = NULL; 206267575Spendry } 206367575Spendry } 206467575Spendry 206567575Spendry if (lvp != NULLVP) { 206667362Smckusick VOP_LOCK(lvp); 206767362Smckusick error = VOP_OPEN(lvp, FREAD, fp->f_cred, p); 206867362Smckusick VOP_UNLOCK(lvp); 206967362Smckusick 207067362Smckusick if (error) { 207167362Smckusick vrele(lvp); 207267362Smckusick return (error); 207367362Smckusick } 207467362Smckusick fp->f_data = (caddr_t) lvp; 207567362Smckusick fp->f_offset = 0; 207667362Smckusick error = vn_close(vp, FREAD, fp->f_cred, p); 207767362Smckusick if (error) 207867362Smckusick return (error); 207967362Smckusick vp = lvp; 208067362Smckusick goto unionread; 208167362Smckusick } 208267362Smckusick } 208367362Smckusick } 208467362Smckusick #endif /* UNION */ 208567362Smckusick 208667362Smckusick if ((uap->count == auio.uio_resid) && 208767362Smckusick (vp->v_flag & VROOT) && 208867362Smckusick (vp->v_mount->mnt_flag & MNT_UNION)) { 208967362Smckusick struct vnode *tvp = vp; 209067362Smckusick vp = vp->v_mount->mnt_vnodecovered; 209167362Smckusick VREF(vp); 209267362Smckusick fp->f_data = (caddr_t) vp; 209367362Smckusick fp->f_offset = 0; 209467362Smckusick vrele(tvp); 209567362Smckusick goto unionread; 209667362Smckusick } 209754969Smckusick error = copyout((caddr_t)&loff, (caddr_t)uap->basep, sizeof(long)); 209854620Smckusick *retval = uap->count - auio.uio_resid; 209954620Smckusick return (error); 210054620Smckusick } 210167362Smckusick #endif /* COMPAT_43 */ 210254620Smckusick 210354620Smckusick /* 210454620Smckusick * Read a block of directory entries in a file system independent format. 210554620Smckusick */ 210654916Storek struct getdirentries_args { 210754916Storek int fd; 210854916Storek char *buf; 210964410Sbostic u_int count; 211054916Storek long *basep; 211154916Storek }; 211242441Smckusick getdirentries(p, uap, retval) 211345914Smckusick struct proc *p; 211454916Storek register struct getdirentries_args *uap; 211542441Smckusick int *retval; 211642441Smckusick { 211739592Smckusick register struct vnode *vp; 211816540Ssam struct file *fp; 211937741Smckusick struct uio auio; 212037741Smckusick struct iovec aiov; 212154969Smckusick long loff; 212267362Smckusick int error, eofflag; 212312756Ssam 212445914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 212547540Skarels return (error); 212637741Smckusick if ((fp->f_flag & FREAD) == 0) 212747540Skarels return (EBADF); 212839592Smckusick vp = (struct vnode *)fp->f_data; 212955451Spendry unionread: 213039592Smckusick if (vp->v_type != VDIR) 213147540Skarels return (EINVAL); 213237741Smckusick aiov.iov_base = uap->buf; 213337741Smckusick aiov.iov_len = uap->count; 213437741Smckusick auio.uio_iov = &aiov; 213537741Smckusick auio.uio_iovcnt = 1; 213637741Smckusick auio.uio_rw = UIO_READ; 213737741Smckusick auio.uio_segflg = UIO_USERSPACE; 213848026Smckusick auio.uio_procp = p; 213937741Smckusick auio.uio_resid = uap->count; 214039592Smckusick VOP_LOCK(vp); 214154969Smckusick loff = auio.uio_offset = fp->f_offset; 214267362Smckusick error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, (u_long *)0, 0); 214339592Smckusick fp->f_offset = auio.uio_offset; 214439592Smckusick VOP_UNLOCK(vp); 214539592Smckusick if (error) 214647540Skarels return (error); 214766095Spendry 214866095Spendry #ifdef UNION 214966095Spendry { 215066095Spendry extern int (**union_vnodeop_p)(); 215166095Spendry extern struct vnode *union_lowervp __P((struct vnode *)); 215266095Spendry 215355451Spendry if ((uap->count == auio.uio_resid) && 215466095Spendry (vp->v_op == union_vnodeop_p)) { 215567122Spendry struct vnode *lvp; 215666095Spendry 215767122Spendry lvp = union_lowervp(vp); 215867122Spendry if (lvp != NULLVP) { 215967575Spendry struct vattr va; 216067575Spendry 216167575Spendry /* 216267575Spendry * If the directory is opaque, 216367575Spendry * then don't show lower entries 216467575Spendry */ 216567575Spendry error = VOP_GETATTR(vp, &va, fp->f_cred, p); 216667575Spendry if (va.va_flags & OPAQUE) { 216767575Spendry vrele(lvp); 216867575Spendry lvp = NULL; 216967575Spendry } 217067575Spendry } 217167575Spendry 217267575Spendry if (lvp != NULLVP) { 217367122Spendry VOP_LOCK(lvp); 217467362Smckusick error = VOP_OPEN(lvp, FREAD, fp->f_cred, p); 217567122Spendry VOP_UNLOCK(lvp); 217666095Spendry 217766095Spendry if (error) { 217867122Spendry vrele(lvp); 217966095Spendry return (error); 218066095Spendry } 218167122Spendry fp->f_data = (caddr_t) lvp; 218266095Spendry fp->f_offset = 0; 218367122Spendry error = vn_close(vp, FREAD, fp->f_cred, p); 218466095Spendry if (error) 218566095Spendry return (error); 218667122Spendry vp = lvp; 218766095Spendry goto unionread; 218866095Spendry } 218966095Spendry } 219066095Spendry } 219166095Spendry #endif 219266095Spendry 219366095Spendry if ((uap->count == auio.uio_resid) && 219455451Spendry (vp->v_flag & VROOT) && 219555451Spendry (vp->v_mount->mnt_flag & MNT_UNION)) { 219655451Spendry struct vnode *tvp = vp; 219755451Spendry vp = vp->v_mount->mnt_vnodecovered; 219855451Spendry VREF(vp); 219955451Spendry fp->f_data = (caddr_t) vp; 220055451Spendry fp->f_offset = 0; 220155451Spendry vrele(tvp); 220255451Spendry goto unionread; 220355451Spendry } 220454969Smckusick error = copyout((caddr_t)&loff, (caddr_t)uap->basep, sizeof(long)); 220542441Smckusick *retval = uap->count - auio.uio_resid; 220647540Skarels return (error); 220712756Ssam } 220812756Ssam 220912756Ssam /* 221049365Smckusick * Set the mode mask for creation of filesystem nodes. 221112756Ssam */ 221254916Storek struct umask_args { 221364410Sbostic int newmask; 221454916Storek }; 221554916Storek mode_t /* XXX */ 221642441Smckusick umask(p, uap, retval) 221745914Smckusick struct proc *p; 221854916Storek struct umask_args *uap; 221942441Smckusick int *retval; 222012756Ssam { 222164410Sbostic register struct filedesc *fdp; 222212756Ssam 222364410Sbostic fdp = p->p_fd; 222445914Smckusick *retval = fdp->fd_cmask; 222564410Sbostic fdp->fd_cmask = uap->newmask & ALLPERMS; 222647540Skarels return (0); 222712756Ssam } 222837741Smckusick 222939566Smarc /* 223039566Smarc * Void all references to file by ripping underlying filesystem 223139566Smarc * away from vnode. 223239566Smarc */ 223354916Storek struct revoke_args { 223464410Sbostic char *path; 223554916Storek }; 223642441Smckusick /* ARGSUSED */ 223742441Smckusick revoke(p, uap, retval) 223845914Smckusick struct proc *p; 223954916Storek register struct revoke_args *uap; 224042441Smckusick int *retval; 224142441Smckusick { 224239566Smarc register struct vnode *vp; 224339566Smarc struct vattr vattr; 224439566Smarc int error; 224547540Skarels struct nameidata nd; 224639566Smarc 224764410Sbostic NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); 224852322Smckusick if (error = namei(&nd)) 224947540Skarels return (error); 225052322Smckusick vp = nd.ni_vp; 225139566Smarc if (vp->v_type != VCHR && vp->v_type != VBLK) { 225239566Smarc error = EINVAL; 225339566Smarc goto out; 225439566Smarc } 225548026Smckusick if (error = VOP_GETATTR(vp, &vattr, p->p_ucred, p)) 225639566Smarc goto out; 225747540Skarels if (p->p_ucred->cr_uid != vattr.va_uid && 225847540Skarels (error = suser(p->p_ucred, &p->p_acflag))) 225939566Smarc goto out; 226039805Smckusick if (vp->v_usecount > 1 || (vp->v_flag & VALIASED)) 226139632Smckusick vgoneall(vp); 226239566Smarc out: 226339566Smarc vrele(vp); 226447540Skarels return (error); 226539566Smarc } 226639566Smarc 226749365Smckusick /* 226849365Smckusick * Convert a user file descriptor to a kernel file entry. 226949365Smckusick */ 227064410Sbostic getvnode(fdp, fd, fpp) 227145914Smckusick struct filedesc *fdp; 227237741Smckusick struct file **fpp; 227364410Sbostic int fd; 227437741Smckusick { 227537741Smckusick struct file *fp; 227637741Smckusick 227764410Sbostic if ((u_int)fd >= fdp->fd_nfiles || 227864410Sbostic (fp = fdp->fd_ofiles[fd]) == NULL) 227937741Smckusick return (EBADF); 228037741Smckusick if (fp->f_type != DTYPE_VNODE) 228137741Smckusick return (EINVAL); 228237741Smckusick *fpp = fp; 228337741Smckusick return (0); 228437741Smckusick } 2285