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*68079Spendry * @(#)vfs_syscalls.c 8.28 (Berkeley) 12/10/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 } 13867969Spendry if (vp->v_mountedhere != NULL) { 13967961Smckusick vput(vp); 14067961Smckusick return (EBUSY); 14167961Smckusick } 14237741Smckusick 14337741Smckusick /* 14439335Smckusick * Allocate and initialize the file system. 14537741Smckusick */ 14637741Smckusick mp = (struct mount *)malloc((u_long)sizeof(struct mount), 14737741Smckusick M_MOUNT, M_WAITOK); 14854172Smckusick bzero((char *)mp, (u_long)sizeof(struct mount)); 14941400Smckusick mp->mnt_op = vfssw[uap->type]; 15039335Smckusick if (error = vfs_lock(mp)) { 15139335Smckusick free((caddr_t)mp, M_MOUNT); 15239335Smckusick vput(vp); 15347540Skarels return (error); 15439335Smckusick } 15539335Smckusick vp->v_mountedhere = mp; 15641400Smckusick mp->mnt_vnodecovered = vp; 15767532Smckusick mp->mnt_stat.f_owner = p->p_ucred->cr_uid; 15839335Smckusick update: 15939335Smckusick /* 16039335Smckusick * Set the mount level flags. 16139335Smckusick */ 16241400Smckusick if (uap->flags & MNT_RDONLY) 16341400Smckusick mp->mnt_flag |= MNT_RDONLY; 16457047Smckusick else if (mp->mnt_flag & MNT_RDONLY) 16557047Smckusick mp->mnt_flag |= MNT_WANTRDWR; 16665613Smckusick mp->mnt_flag &=~ (MNT_NOSUID | MNT_NOEXEC | MNT_NODEV | 16765613Smckusick MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC); 16865613Smckusick mp->mnt_flag |= uap->flags & (MNT_NOSUID | MNT_NOEXEC | MNT_NODEV | 16965613Smckusick MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC); 17039335Smckusick /* 17139335Smckusick * Mount the filesystem. 17239335Smckusick */ 17364410Sbostic error = VFS_MOUNT(mp, uap->path, uap->data, &nd, p); 17441400Smckusick if (mp->mnt_flag & MNT_UPDATE) { 17539335Smckusick vrele(vp); 17657047Smckusick if (mp->mnt_flag & MNT_WANTRDWR) 17757047Smckusick mp->mnt_flag &= ~MNT_RDONLY; 17857047Smckusick mp->mnt_flag &=~ 17957047Smckusick (MNT_UPDATE | MNT_RELOAD | MNT_FORCE | MNT_WANTRDWR); 18040111Smckusick if (error) 18141400Smckusick mp->mnt_flag = flag; 18247540Skarels return (error); 18339335Smckusick } 18440110Smckusick /* 18540110Smckusick * Put the new filesystem on the mount list after root. 18640110Smckusick */ 18737741Smckusick cache_purge(vp); 18837741Smckusick if (!error) { 18965259Smckusick TAILQ_INSERT_TAIL(&mountlist, mp, mnt_list); 19067974Smckusick checkdirs(vp); 19139335Smckusick VOP_UNLOCK(vp); 19237741Smckusick vfs_unlock(mp); 19348026Smckusick error = VFS_START(mp, 0, p); 19437741Smckusick } else { 19565259Smckusick mp->mnt_vnodecovered->v_mountedhere = (struct mount *)0; 19665259Smckusick vfs_unlock(mp); 19737741Smckusick free((caddr_t)mp, M_MOUNT); 19839335Smckusick vput(vp); 19937741Smckusick } 20047540Skarels return (error); 2016254Sroot } 2026254Sroot 2039167Ssam /* 20467974Smckusick * Scan all active processes to see if any of them have a current 20567974Smckusick * or root directory onto which the new filesystem has just been 20667974Smckusick * mounted. If so, replace them with the new mount point. 20767974Smckusick */ 20867974Smckusick checkdirs(olddp) 20967974Smckusick struct vnode *olddp; 21067974Smckusick { 21167974Smckusick struct filedesc *fdp; 21267974Smckusick struct vnode *newdp; 21367974Smckusick struct proc *p; 21467974Smckusick 21567974Smckusick if (olddp->v_usecount == 1) 21667974Smckusick return; 21767974Smckusick if (VFS_ROOT(olddp->v_mountedhere, &newdp)) 21867974Smckusick panic("mount: lost mount"); 21967974Smckusick for (p = allproc.lh_first; p != 0; p = p->p_list.le_next) { 22067974Smckusick fdp = p->p_fd; 22167974Smckusick if (fdp->fd_cdir == olddp) { 22267974Smckusick vrele(fdp->fd_cdir); 22367974Smckusick VREF(newdp); 22467974Smckusick fdp->fd_cdir = newdp; 22567974Smckusick } 22667974Smckusick if (fdp->fd_rdir == olddp) { 22767974Smckusick vrele(fdp->fd_rdir); 22867974Smckusick VREF(newdp); 22967974Smckusick fdp->fd_rdir = newdp; 23067974Smckusick } 23167974Smckusick } 23267974Smckusick if (rootvnode == olddp) { 23367974Smckusick vrele(rootvnode); 23467974Smckusick VREF(newdp); 23567974Smckusick rootvnode = newdp; 23667974Smckusick } 23767974Smckusick vput(newdp); 23867974Smckusick } 23967974Smckusick 24067974Smckusick /* 24164410Sbostic * Unmount a file system. 24237741Smckusick * 24337741Smckusick * Note: unmount takes a path to the vnode mounted on as argument, 24437741Smckusick * not special file (as before). 2459167Ssam */ 24654916Storek struct unmount_args { 24764410Sbostic char *path; 24854916Storek int flags; 24954916Storek }; 25042441Smckusick /* ARGSUSED */ 25142441Smckusick unmount(p, uap, retval) 25245914Smckusick struct proc *p; 25354916Storek register struct unmount_args *uap; 25442441Smckusick int *retval; 25542441Smckusick { 25637741Smckusick register struct vnode *vp; 25739356Smckusick struct mount *mp; 25837741Smckusick int error; 25947540Skarels struct nameidata nd; 2606254Sroot 26164410Sbostic NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); 26252322Smckusick if (error = namei(&nd)) 26347540Skarels return (error); 26452322Smckusick vp = nd.ni_vp; 26567532Smckusick mp = vp->v_mount; 26666172Spendry 26737741Smckusick /* 26867532Smckusick * Only root, or the user that did the original mount is 26967532Smckusick * permitted to unmount this filesystem. 27066172Spendry */ 27167532Smckusick if ((mp->mnt_stat.f_owner != p->p_ucred->cr_uid) && 27266172Spendry (error = suser(p->p_ucred, &p->p_acflag))) { 27366172Spendry vput(vp); 27466172Spendry return (error); 27566172Spendry } 27666172Spendry 27766172Spendry /* 27837741Smckusick * Must be the root of the filesystem 27937741Smckusick */ 28037741Smckusick if ((vp->v_flag & VROOT) == 0) { 28137741Smckusick vput(vp); 28247540Skarels return (EINVAL); 28337741Smckusick } 28437741Smckusick vput(vp); 28548026Smckusick return (dounmount(mp, uap->flags, p)); 28639356Smckusick } 28739356Smckusick 28839356Smckusick /* 28964410Sbostic * Do the actual file system unmount. 29039356Smckusick */ 29148026Smckusick dounmount(mp, flags, p) 29239356Smckusick register struct mount *mp; 29339356Smckusick int flags; 29448026Smckusick struct proc *p; 29539356Smckusick { 29639356Smckusick struct vnode *coveredvp; 29739356Smckusick int error; 29839356Smckusick 29941400Smckusick coveredvp = mp->mnt_vnodecovered; 30041298Smckusick if (vfs_busy(mp)) 30141298Smckusick return (EBUSY); 30241400Smckusick mp->mnt_flag |= MNT_UNMOUNT; 30337741Smckusick if (error = vfs_lock(mp)) 30439356Smckusick return (error); 30537741Smckusick 30665859Smckusick mp->mnt_flag &=~ MNT_ASYNC; 30745738Smckusick vnode_pager_umount(mp); /* release cached vnodes */ 30837741Smckusick cache_purgevfs(mp); /* remove cache entries for this file sys */ 30954441Smckusick if ((error = VFS_SYNC(mp, MNT_WAIT, p->p_ucred, p)) == 0 || 31054441Smckusick (flags & MNT_FORCE)) 31148026Smckusick error = VFS_UNMOUNT(mp, flags, p); 31241400Smckusick mp->mnt_flag &= ~MNT_UNMOUNT; 31341298Smckusick vfs_unbusy(mp); 31437741Smckusick if (error) { 31537741Smckusick vfs_unlock(mp); 31637741Smckusick } else { 31737741Smckusick vrele(coveredvp); 31865259Smckusick TAILQ_REMOVE(&mountlist, mp, mnt_list); 31965259Smckusick mp->mnt_vnodecovered->v_mountedhere = (struct mount *)0; 32065259Smckusick vfs_unlock(mp); 32165259Smckusick if (mp->mnt_vnodelist.lh_first != NULL) 32252287Smckusick panic("unmount: dangling vnode"); 32337741Smckusick free((caddr_t)mp, M_MOUNT); 32437741Smckusick } 32539356Smckusick return (error); 3266254Sroot } 3276254Sroot 3289167Ssam /* 32937741Smckusick * Sync each mounted filesystem. 3309167Ssam */ 33167403Smckusick #ifdef DEBUG 33256352Smckusick int syncprt = 0; 33359875Smckusick struct ctldebug debug0 = { "syncprt", &syncprt }; 33456352Smckusick #endif 33556352Smckusick 33654916Storek struct sync_args { 33754916Storek int dummy; 33854916Storek }; 33939491Smckusick /* ARGSUSED */ 34042441Smckusick sync(p, uap, retval) 34145914Smckusick struct proc *p; 34254916Storek struct sync_args *uap; 34342441Smckusick int *retval; 3446254Sroot { 34565259Smckusick register struct mount *mp, *nmp; 34665859Smckusick int asyncflag; 34737741Smckusick 34865259Smckusick for (mp = mountlist.tqh_first; mp != NULL; mp = nmp) { 34967678Smckusick /* 35067678Smckusick * Get the next pointer in case we hang on vfs_busy 35167678Smckusick * while we are being unmounted. 35267678Smckusick */ 35365259Smckusick nmp = mp->mnt_list.tqe_next; 35440343Smckusick /* 35540343Smckusick * The lock check below is to avoid races with mount 35640343Smckusick * and unmount. 35740343Smckusick */ 35841400Smckusick if ((mp->mnt_flag & (MNT_MLOCK|MNT_RDONLY|MNT_MPBUSY)) == 0 && 35941298Smckusick !vfs_busy(mp)) { 36065859Smckusick asyncflag = mp->mnt_flag & MNT_ASYNC; 36165859Smckusick mp->mnt_flag &= ~MNT_ASYNC; 36254441Smckusick VFS_SYNC(mp, MNT_NOWAIT, p->p_ucred, p); 36365859Smckusick if (asyncflag) 36465859Smckusick mp->mnt_flag |= MNT_ASYNC; 36567678Smckusick /* 36667678Smckusick * Get the next pointer again, as the next filesystem 36767678Smckusick * might have been unmounted while we were sync'ing. 36867678Smckusick */ 36967678Smckusick nmp = mp->mnt_list.tqe_next; 37065259Smckusick vfs_unbusy(mp); 37165259Smckusick } 37265259Smckusick } 37356352Smckusick #ifdef DIAGNOSTIC 37456352Smckusick if (syncprt) 37556352Smckusick vfs_bufstats(); 37656352Smckusick #endif /* DIAGNOSTIC */ 37747688Skarels return (0); 37837741Smckusick } 37937741Smckusick 38037741Smckusick /* 38164410Sbostic * Change filesystem quotas. 38241298Smckusick */ 38354916Storek struct quotactl_args { 38454916Storek char *path; 38554916Storek int cmd; 38654916Storek int uid; 38754916Storek caddr_t arg; 38854916Storek }; 38942441Smckusick /* ARGSUSED */ 39042441Smckusick quotactl(p, uap, retval) 39145914Smckusick struct proc *p; 39254916Storek register struct quotactl_args *uap; 39342441Smckusick int *retval; 39442441Smckusick { 39541298Smckusick register struct mount *mp; 39641298Smckusick int error; 39747540Skarels struct nameidata nd; 39841298Smckusick 39952322Smckusick NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); 40052322Smckusick if (error = namei(&nd)) 40147540Skarels return (error); 40252322Smckusick mp = nd.ni_vp->v_mount; 40352322Smckusick vrele(nd.ni_vp); 40448026Smckusick return (VFS_QUOTACTL(mp, uap->cmd, uap->uid, uap->arg, p)); 40541298Smckusick } 40641298Smckusick 40741298Smckusick /* 40849365Smckusick * Get filesystem statistics. 40937741Smckusick */ 41054916Storek struct statfs_args { 41154916Storek char *path; 41254916Storek struct statfs *buf; 41354916Storek }; 41442441Smckusick /* ARGSUSED */ 41542441Smckusick statfs(p, uap, retval) 41645914Smckusick struct proc *p; 41754916Storek register struct statfs_args *uap; 41842441Smckusick int *retval; 41942441Smckusick { 42039464Smckusick register struct mount *mp; 42140343Smckusick register struct statfs *sp; 42237741Smckusick int error; 42347540Skarels struct nameidata nd; 42437741Smckusick 42552322Smckusick NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); 42652322Smckusick if (error = namei(&nd)) 42747540Skarels return (error); 42852322Smckusick mp = nd.ni_vp->v_mount; 42941400Smckusick sp = &mp->mnt_stat; 43052322Smckusick vrele(nd.ni_vp); 43148026Smckusick if (error = VFS_STATFS(mp, sp, p)) 43247540Skarels return (error); 43341400Smckusick sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 43447540Skarels return (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp))); 43537741Smckusick } 43637741Smckusick 43742441Smckusick /* 43849365Smckusick * Get filesystem statistics. 43942441Smckusick */ 44054916Storek struct fstatfs_args { 44154916Storek int fd; 44254916Storek struct statfs *buf; 44354916Storek }; 44442441Smckusick /* ARGSUSED */ 44542441Smckusick fstatfs(p, uap, retval) 44645914Smckusick struct proc *p; 44754916Storek register struct fstatfs_args *uap; 44842441Smckusick int *retval; 44942441Smckusick { 45037741Smckusick struct file *fp; 45139464Smckusick struct mount *mp; 45240343Smckusick register struct statfs *sp; 45337741Smckusick int error; 45437741Smckusick 45545914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 45647540Skarels return (error); 45739464Smckusick mp = ((struct vnode *)fp->f_data)->v_mount; 45841400Smckusick sp = &mp->mnt_stat; 45948026Smckusick if (error = VFS_STATFS(mp, sp, p)) 46047540Skarels return (error); 46141400Smckusick sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 46247540Skarels return (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp))); 46337741Smckusick } 46437741Smckusick 46537741Smckusick /* 46649365Smckusick * Get statistics on all filesystems. 46738270Smckusick */ 46854916Storek struct getfsstat_args { 46954916Storek struct statfs *buf; 47054916Storek long bufsize; 47154916Storek int flags; 47254916Storek }; 47342441Smckusick getfsstat(p, uap, retval) 47445914Smckusick struct proc *p; 47554916Storek register struct getfsstat_args *uap; 47642441Smckusick int *retval; 47742441Smckusick { 47865259Smckusick register struct mount *mp, *nmp; 47940343Smckusick register struct statfs *sp; 48039606Smckusick caddr_t sfsp; 48138270Smckusick long count, maxcount, error; 48238270Smckusick 48338270Smckusick maxcount = uap->bufsize / sizeof(struct statfs); 48439606Smckusick sfsp = (caddr_t)uap->buf; 48565259Smckusick for (count = 0, mp = mountlist.tqh_first; mp != NULL; mp = nmp) { 48665259Smckusick nmp = mp->mnt_list.tqe_next; 48741400Smckusick if (sfsp && count < maxcount && 48841400Smckusick ((mp->mnt_flag & MNT_MLOCK) == 0)) { 48941400Smckusick sp = &mp->mnt_stat; 49040343Smckusick /* 49140343Smckusick * If MNT_NOWAIT is specified, do not refresh the 49240343Smckusick * fsstat cache. MNT_WAIT overrides MNT_NOWAIT. 49340343Smckusick */ 49440343Smckusick if (((uap->flags & MNT_NOWAIT) == 0 || 49540343Smckusick (uap->flags & MNT_WAIT)) && 49665259Smckusick (error = VFS_STATFS(mp, sp, p))) 49739607Smckusick continue; 49841400Smckusick sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 49940343Smckusick if (error = copyout((caddr_t)sp, sfsp, sizeof(*sp))) 50047540Skarels return (error); 50140343Smckusick sfsp += sizeof(*sp); 50238270Smckusick } 50339606Smckusick count++; 50465259Smckusick } 50538270Smckusick if (sfsp && count > maxcount) 50642441Smckusick *retval = maxcount; 50738270Smckusick else 50842441Smckusick *retval = count; 50947540Skarels return (0); 51038270Smckusick } 51138270Smckusick 51238270Smckusick /* 51338259Smckusick * Change current working directory to a given file descriptor. 51438259Smckusick */ 51554916Storek struct fchdir_args { 51654916Storek int fd; 51754916Storek }; 51842441Smckusick /* ARGSUSED */ 51942441Smckusick fchdir(p, uap, retval) 52045914Smckusick struct proc *p; 52154916Storek struct fchdir_args *uap; 52242441Smckusick int *retval; 52338259Smckusick { 52445914Smckusick register struct filedesc *fdp = p->p_fd; 52567974Smckusick struct vnode *vp, *tdp; 52667974Smckusick struct mount *mp; 52738259Smckusick struct file *fp; 52838259Smckusick int error; 52938259Smckusick 53045914Smckusick if (error = getvnode(fdp, uap->fd, &fp)) 53147540Skarels return (error); 53238259Smckusick vp = (struct vnode *)fp->f_data; 53367974Smckusick VREF(vp); 53438259Smckusick VOP_LOCK(vp); 53538259Smckusick if (vp->v_type != VDIR) 53638259Smckusick error = ENOTDIR; 53738259Smckusick else 53848026Smckusick error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p); 53967974Smckusick while (!error && (mp = vp->v_mountedhere) != NULL) { 54067974Smckusick if (mp->mnt_flag & MNT_MLOCK) { 54167974Smckusick mp->mnt_flag |= MNT_MWAIT; 54267974Smckusick sleep((caddr_t)mp, PVFS); 54367974Smckusick continue; 54467974Smckusick } 54567974Smckusick if (error = VFS_ROOT(mp, &tdp)) 54667974Smckusick break; 54767974Smckusick vput(vp); 54867974Smckusick vp = tdp; 54967974Smckusick } 55038259Smckusick VOP_UNLOCK(vp); 55167974Smckusick if (error) { 55267974Smckusick vrele(vp); 55347540Skarels return (error); 55467974Smckusick } 55545914Smckusick vrele(fdp->fd_cdir); 55645914Smckusick fdp->fd_cdir = vp; 55747540Skarels return (0); 55838259Smckusick } 55938259Smckusick 56038259Smckusick /* 56137741Smckusick * Change current working directory (``.''). 56237741Smckusick */ 56354916Storek struct chdir_args { 56464410Sbostic char *path; 56554916Storek }; 56642441Smckusick /* ARGSUSED */ 56742441Smckusick chdir(p, uap, retval) 56845914Smckusick struct proc *p; 56954916Storek struct chdir_args *uap; 57042441Smckusick int *retval; 57137741Smckusick { 57245914Smckusick register struct filedesc *fdp = p->p_fd; 57337741Smckusick int error; 57447540Skarels struct nameidata nd; 5756254Sroot 57664410Sbostic NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); 57764410Sbostic if (error = change_dir(&nd, p)) 57847540Skarels return (error); 57945914Smckusick vrele(fdp->fd_cdir); 58052322Smckusick fdp->fd_cdir = nd.ni_vp; 58147540Skarels return (0); 58237741Smckusick } 5836254Sroot 58437741Smckusick /* 58537741Smckusick * Change notion of root (``/'') directory. 58637741Smckusick */ 58754916Storek struct chroot_args { 58864410Sbostic char *path; 58954916Storek }; 59042441Smckusick /* ARGSUSED */ 59142441Smckusick chroot(p, uap, retval) 59245914Smckusick struct proc *p; 59354916Storek struct chroot_args *uap; 59442441Smckusick int *retval; 59537741Smckusick { 59645914Smckusick register struct filedesc *fdp = p->p_fd; 59737741Smckusick int error; 59847540Skarels struct nameidata nd; 59937741Smckusick 60047540Skarels if (error = suser(p->p_ucred, &p->p_acflag)) 60147540Skarels return (error); 60264410Sbostic NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); 60364410Sbostic if (error = change_dir(&nd, p)) 60447540Skarels return (error); 60545914Smckusick if (fdp->fd_rdir != NULL) 60645914Smckusick vrele(fdp->fd_rdir); 60752322Smckusick fdp->fd_rdir = nd.ni_vp; 60847540Skarels return (0); 6096254Sroot } 6106254Sroot 61137Sbill /* 61237741Smckusick * Common routine for chroot and chdir. 61337741Smckusick */ 61464410Sbostic static int 61564410Sbostic change_dir(ndp, p) 61652322Smckusick register struct nameidata *ndp; 61747540Skarels struct proc *p; 61837741Smckusick { 61937741Smckusick struct vnode *vp; 62037741Smckusick int error; 62137741Smckusick 62252322Smckusick if (error = namei(ndp)) 62337741Smckusick return (error); 62437741Smckusick vp = ndp->ni_vp; 62537741Smckusick if (vp->v_type != VDIR) 62637741Smckusick error = ENOTDIR; 62737741Smckusick else 62848026Smckusick error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p); 62937741Smckusick VOP_UNLOCK(vp); 63037741Smckusick if (error) 63137741Smckusick vrele(vp); 63237741Smckusick return (error); 63337741Smckusick } 63437741Smckusick 63537741Smckusick /* 63642441Smckusick * Check permissions, allocate an open file structure, 63742441Smckusick * and call the device open routine if any. 6386254Sroot */ 63954916Storek struct open_args { 64064410Sbostic char *path; 64164410Sbostic int flags; 64254916Storek int mode; 64354916Storek }; 64442441Smckusick open(p, uap, retval) 64545914Smckusick struct proc *p; 64654916Storek register struct open_args *uap; 64742441Smckusick int *retval; 6486254Sroot { 64945914Smckusick register struct filedesc *fdp = p->p_fd; 65042441Smckusick register struct file *fp; 65150111Smckusick register struct vnode *vp; 65264410Sbostic int flags, cmode; 65337741Smckusick struct file *nfp; 65449945Smckusick int type, indx, error; 65549945Smckusick struct flock lf; 65647540Skarels struct nameidata nd; 65737741Smckusick extern struct fileops vnops; 6586254Sroot 65945914Smckusick if (error = falloc(p, &nfp, &indx)) 66047540Skarels return (error); 66137741Smckusick fp = nfp; 66264410Sbostic flags = FFLAGS(uap->flags); 66364410Sbostic cmode = ((uap->mode &~ fdp->fd_cmask) & ALLPERMS) &~ S_ISTXT; 66464410Sbostic NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); 66545202Smckusick p->p_dupfd = -indx - 1; /* XXX check for fdopen */ 66664410Sbostic if (error = vn_open(&nd, flags, cmode)) { 66749980Smckusick ffree(fp); 66854723Smckusick if ((error == ENODEV || error == ENXIO) && 66954723Smckusick p->p_dupfd >= 0 && /* XXX from fdopen */ 67064410Sbostic (error = 67164410Sbostic dupfdopen(fdp, indx, p->p_dupfd, flags, error)) == 0) { 67242441Smckusick *retval = indx; 67347540Skarels return (0); 67442441Smckusick } 67540884Smckusick if (error == ERESTART) 67640884Smckusick error = EINTR; 67747688Skarels fdp->fd_ofiles[indx] = NULL; 67847540Skarels return (error); 67912756Ssam } 68053828Spendry p->p_dupfd = 0; 68152322Smckusick vp = nd.ni_vp; 68264410Sbostic fp->f_flag = flags & FMASK; 68354348Smckusick fp->f_type = DTYPE_VNODE; 68454348Smckusick fp->f_ops = &vnops; 68554348Smckusick fp->f_data = (caddr_t)vp; 68664410Sbostic if (flags & (O_EXLOCK | O_SHLOCK)) { 68749945Smckusick lf.l_whence = SEEK_SET; 68849945Smckusick lf.l_start = 0; 68949945Smckusick lf.l_len = 0; 69064410Sbostic if (flags & O_EXLOCK) 69149945Smckusick lf.l_type = F_WRLCK; 69249945Smckusick else 69349945Smckusick lf.l_type = F_RDLCK; 69449945Smckusick type = F_FLOCK; 69564410Sbostic if ((flags & FNONBLOCK) == 0) 69649945Smckusick type |= F_WAIT; 69765757Smckusick VOP_UNLOCK(vp); 69850111Smckusick if (error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, type)) { 69950111Smckusick (void) vn_close(vp, fp->f_flag, fp->f_cred, p); 70049980Smckusick ffree(fp); 70149945Smckusick fdp->fd_ofiles[indx] = NULL; 70249945Smckusick return (error); 70349945Smckusick } 70465757Smckusick VOP_LOCK(vp); 70549949Smckusick fp->f_flag |= FHASLOCK; 70649945Smckusick } 70750111Smckusick VOP_UNLOCK(vp); 70842441Smckusick *retval = indx; 70947540Skarels return (0); 7106254Sroot } 7116254Sroot 71242955Smckusick #ifdef COMPAT_43 7136254Sroot /* 71464410Sbostic * Create a file. 7156254Sroot */ 71654916Storek struct ocreat_args { 71764410Sbostic char *path; 71864410Sbostic int mode; 71954916Storek }; 72042955Smckusick ocreat(p, uap, retval) 72142441Smckusick struct proc *p; 72254916Storek register struct ocreat_args *uap; 72342441Smckusick int *retval; 7246254Sroot { 72554916Storek struct open_args openuap; 72642441Smckusick 72764410Sbostic openuap.path = uap->path; 72864410Sbostic openuap.mode = uap->mode; 72964410Sbostic openuap.flags = O_WRONLY | O_CREAT | O_TRUNC; 73047540Skarels return (open(p, &openuap, retval)); 73142441Smckusick } 73242955Smckusick #endif /* COMPAT_43 */ 73342441Smckusick 73442441Smckusick /* 73564410Sbostic * Create a special file. 73642441Smckusick */ 73754916Storek struct mknod_args { 73864410Sbostic char *path; 73964410Sbostic int mode; 74054916Storek int dev; 74154916Storek }; 74242441Smckusick /* ARGSUSED */ 74342441Smckusick mknod(p, uap, retval) 74445914Smckusick struct proc *p; 74554916Storek register struct mknod_args *uap; 74642441Smckusick int *retval; 74742441Smckusick { 74837741Smckusick register struct vnode *vp; 74937741Smckusick struct vattr vattr; 75037741Smckusick int error; 75167575Spendry int whiteout; 75247540Skarels struct nameidata nd; 7536254Sroot 75447540Skarels if (error = suser(p->p_ucred, &p->p_acflag)) 75547540Skarels return (error); 75664410Sbostic NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->path, p); 75752322Smckusick if (error = namei(&nd)) 75847540Skarels return (error); 75952322Smckusick vp = nd.ni_vp; 76064585Sbostic if (vp != NULL) 76137741Smckusick error = EEXIST; 76264585Sbostic else { 76364585Sbostic VATTR_NULL(&vattr); 76464585Sbostic vattr.va_mode = (uap->mode & ALLPERMS) &~ p->p_fd->fd_cmask; 76564585Sbostic vattr.va_rdev = uap->dev; 76667575Spendry whiteout = 0; 76764585Sbostic 76864585Sbostic switch (uap->mode & S_IFMT) { 76964585Sbostic case S_IFMT: /* used by badsect to flag bad sectors */ 77064585Sbostic vattr.va_type = VBAD; 77164585Sbostic break; 77264585Sbostic case S_IFCHR: 77364585Sbostic vattr.va_type = VCHR; 77464585Sbostic break; 77564585Sbostic case S_IFBLK: 77664585Sbostic vattr.va_type = VBLK; 77764585Sbostic break; 77867575Spendry case S_IFWHT: 77967575Spendry whiteout = 1; 78067575Spendry break; 78164585Sbostic default: 78264585Sbostic error = EINVAL; 78364585Sbostic break; 78464585Sbostic } 7856254Sroot } 78667747Spendry if (!error) { 78767654Smckusick VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 78867747Spendry if (whiteout) { 78967747Spendry error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, CREATE); 79067747Spendry if (error) 79167747Spendry VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 79267747Spendry vput(nd.ni_dvp); 79367747Spendry } else { 79467747Spendry error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, 79567747Spendry &nd.ni_cnd, &vattr); 79667747Spendry } 79742465Smckusick } else { 79852322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 79952322Smckusick if (nd.ni_dvp == vp) 80052322Smckusick vrele(nd.ni_dvp); 80143344Smckusick else 80252322Smckusick vput(nd.ni_dvp); 80342465Smckusick if (vp) 80442465Smckusick vrele(vp); 80542465Smckusick } 80647540Skarels return (error); 8076254Sroot } 8086254Sroot 8096254Sroot /* 81064410Sbostic * Create named pipe. 81140285Smckusick */ 81254916Storek struct mkfifo_args { 81364410Sbostic char *path; 81464410Sbostic int mode; 81554916Storek }; 81642441Smckusick /* ARGSUSED */ 81742441Smckusick mkfifo(p, uap, retval) 81845914Smckusick struct proc *p; 81954916Storek register struct mkfifo_args *uap; 82042441Smckusick int *retval; 82142441Smckusick { 82240285Smckusick struct vattr vattr; 82340285Smckusick int error; 82447540Skarels struct nameidata nd; 82540285Smckusick 82640285Smckusick #ifndef FIFO 82747540Skarels return (EOPNOTSUPP); 82840285Smckusick #else 82964410Sbostic NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->path, p); 83052322Smckusick if (error = namei(&nd)) 83147540Skarels return (error); 83252322Smckusick if (nd.ni_vp != NULL) { 83352322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 83452322Smckusick if (nd.ni_dvp == nd.ni_vp) 83552322Smckusick vrele(nd.ni_dvp); 83643344Smckusick else 83752322Smckusick vput(nd.ni_dvp); 83852322Smckusick vrele(nd.ni_vp); 83947540Skarels return (EEXIST); 84040285Smckusick } 84145785Sbostic VATTR_NULL(&vattr); 84245785Sbostic vattr.va_type = VFIFO; 84364410Sbostic vattr.va_mode = (uap->mode & ALLPERMS) &~ p->p_fd->fd_cmask; 84467654Smckusick VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 84552322Smckusick return (VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr)); 84640285Smckusick #endif /* FIFO */ 84740285Smckusick } 84840285Smckusick 84940285Smckusick /* 85064410Sbostic * Make a hard file link. 8516254Sroot */ 85254916Storek struct link_args { 85364410Sbostic char *path; 85464410Sbostic char *link; 85554916Storek }; 85642441Smckusick /* ARGSUSED */ 85742441Smckusick link(p, uap, retval) 85845914Smckusick struct proc *p; 85954916Storek register struct link_args *uap; 86042441Smckusick int *retval; 86142441Smckusick { 86264410Sbostic register struct vnode *vp; 86364410Sbostic struct nameidata nd; 86437741Smckusick int error; 8656254Sroot 86664410Sbostic NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); 86752322Smckusick if (error = namei(&nd)) 86847540Skarels return (error); 86952322Smckusick vp = nd.ni_vp; 87064585Sbostic if (vp->v_type != VDIR || 87164585Sbostic (error = suser(p->p_ucred, &p->p_acflag)) == 0) { 87264585Sbostic nd.ni_cnd.cn_nameiop = CREATE; 87364585Sbostic nd.ni_cnd.cn_flags = LOCKPARENT; 87464585Sbostic nd.ni_dirp = uap->link; 87564585Sbostic if ((error = namei(&nd)) == 0) { 87664585Sbostic if (nd.ni_vp != NULL) 87764585Sbostic error = EEXIST; 87864585Sbostic if (!error) { 87967654Smckusick VOP_LEASE(nd.ni_dvp, p, p->p_ucred, 88067654Smckusick LEASE_WRITE); 88167654Smckusick VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 88264585Sbostic error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd); 88364585Sbostic } else { 88464585Sbostic VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 88564585Sbostic if (nd.ni_dvp == nd.ni_vp) 88664585Sbostic vrele(nd.ni_dvp); 88764585Sbostic else 88864585Sbostic vput(nd.ni_dvp); 88964585Sbostic if (nd.ni_vp) 89064585Sbostic vrele(nd.ni_vp); 89164585Sbostic } 89264585Sbostic } 89342465Smckusick } 89464585Sbostic vrele(vp); 89547540Skarels return (error); 8966254Sroot } 8976254Sroot 8986254Sroot /* 89949365Smckusick * Make a symbolic link. 9006254Sroot */ 90154916Storek struct symlink_args { 90264410Sbostic char *path; 90364410Sbostic char *link; 90454916Storek }; 90542441Smckusick /* ARGSUSED */ 90642441Smckusick symlink(p, uap, retval) 90745914Smckusick struct proc *p; 90854916Storek register struct symlink_args *uap; 90942441Smckusick int *retval; 91042441Smckusick { 91137741Smckusick struct vattr vattr; 91264410Sbostic char *path; 91337741Smckusick int error; 91447540Skarels struct nameidata nd; 9156254Sroot 91664410Sbostic MALLOC(path, char *, MAXPATHLEN, M_NAMEI, M_WAITOK); 91764410Sbostic if (error = copyinstr(uap->path, path, MAXPATHLEN, NULL)) 91842465Smckusick goto out; 91964410Sbostic NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->link, p); 92052322Smckusick if (error = namei(&nd)) 92142465Smckusick goto out; 92252322Smckusick if (nd.ni_vp) { 92352322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 92452322Smckusick if (nd.ni_dvp == nd.ni_vp) 92552322Smckusick vrele(nd.ni_dvp); 92643344Smckusick else 92752322Smckusick vput(nd.ni_dvp); 92852322Smckusick vrele(nd.ni_vp); 92937741Smckusick error = EEXIST; 93037741Smckusick goto out; 9316254Sroot } 93241362Smckusick VATTR_NULL(&vattr); 93364410Sbostic vattr.va_mode = ACCESSPERMS &~ p->p_fd->fd_cmask; 93467654Smckusick VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 93564410Sbostic error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr, path); 93637741Smckusick out: 93764410Sbostic FREE(path, M_NAMEI); 93847540Skarels return (error); 9396254Sroot } 9406254Sroot 9416254Sroot /* 94267518Spendry * Delete a whiteout from the filesystem. 94367518Spendry */ 94467845Smckusick struct undelete_args { 94567518Spendry char *path; 94667518Spendry }; 94767518Spendry /* ARGSUSED */ 94867845Smckusick undelete(p, uap, retval) 94967518Spendry struct proc *p; 95067845Smckusick struct undelete_args *uap; 95167518Spendry int *retval; 95267518Spendry { 95367518Spendry int error; 95467518Spendry struct nameidata nd; 95567518Spendry 95667575Spendry NDINIT(&nd, DELETE, LOCKPARENT|DOWHITEOUT, UIO_USERSPACE, uap->path, p); 95767575Spendry error = namei(&nd); 95867575Spendry if (error) 95967518Spendry return (error); 96067575Spendry 96167575Spendry if (nd.ni_vp != NULLVP || !(nd.ni_cnd.cn_flags & ISWHITEOUT)) { 96267518Spendry VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 96367518Spendry if (nd.ni_dvp == nd.ni_vp) 96467518Spendry vrele(nd.ni_dvp); 96567518Spendry else 96667518Spendry vput(nd.ni_dvp); 96767518Spendry if (nd.ni_vp) 96867518Spendry vrele(nd.ni_vp); 96967518Spendry return (EEXIST); 97067518Spendry } 97167575Spendry 97267654Smckusick VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 97367747Spendry if (error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, DELETE)) 97467575Spendry VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 97567518Spendry vput(nd.ni_dvp); 97667518Spendry return (error); 97767518Spendry } 97867518Spendry 97967518Spendry /* 98049365Smckusick * Delete a name from the filesystem. 9816254Sroot */ 98254916Storek struct unlink_args { 98364410Sbostic char *path; 98454916Storek }; 98542441Smckusick /* ARGSUSED */ 98642441Smckusick unlink(p, uap, retval) 98745914Smckusick struct proc *p; 98854916Storek struct unlink_args *uap; 98942441Smckusick int *retval; 9906254Sroot { 99137741Smckusick register struct vnode *vp; 99237741Smckusick int error; 99347540Skarels struct nameidata nd; 9946254Sroot 99564410Sbostic NDINIT(&nd, DELETE, LOCKPARENT, UIO_USERSPACE, uap->path, p); 99652322Smckusick if (error = namei(&nd)) 99747540Skarels return (error); 99852322Smckusick vp = nd.ni_vp; 99967654Smckusick VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 100059382Smckusick VOP_LOCK(vp); 100164410Sbostic 100264585Sbostic if (vp->v_type != VDIR || 100364585Sbostic (error = suser(p->p_ucred, &p->p_acflag)) == 0) { 100464585Sbostic /* 100564585Sbostic * The root of a mounted filesystem cannot be deleted. 100664585Sbostic */ 100764585Sbostic if (vp->v_flag & VROOT) 100864585Sbostic error = EBUSY; 100964585Sbostic else 101064585Sbostic (void)vnode_pager_uncache(vp); 101164585Sbostic } 101264585Sbostic 101364585Sbostic if (!error) { 101467654Smckusick VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 101552322Smckusick error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); 101642465Smckusick } else { 101752322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 101852322Smckusick if (nd.ni_dvp == vp) 101952322Smckusick vrele(nd.ni_dvp); 102043344Smckusick else 102152322Smckusick vput(nd.ni_dvp); 102267575Spendry if (vp != NULLVP) 102367575Spendry vput(vp); 102442465Smckusick } 102547540Skarels return (error); 10266254Sroot } 10276254Sroot 102864410Sbostic /* 102964410Sbostic * Reposition read/write file offset. 103064410Sbostic */ 103160428Smckusick struct lseek_args { 103264410Sbostic int fd; 103354863Storek int pad; 103464410Sbostic off_t offset; 103564410Sbostic int whence; 103654863Storek }; 103760414Smckusick lseek(p, uap, retval) 103853468Smckusick struct proc *p; 103960428Smckusick register struct lseek_args *uap; 104054916Storek int *retval; 104142441Smckusick { 104247540Skarels struct ucred *cred = p->p_ucred; 104345914Smckusick register struct filedesc *fdp = p->p_fd; 104442441Smckusick register struct file *fp; 104537741Smckusick struct vattr vattr; 104637741Smckusick int error; 10476254Sroot 104864410Sbostic if ((u_int)uap->fd >= fdp->fd_nfiles || 104964410Sbostic (fp = fdp->fd_ofiles[uap->fd]) == NULL) 105047540Skarels return (EBADF); 105137741Smckusick if (fp->f_type != DTYPE_VNODE) 105247540Skarels return (ESPIPE); 105364410Sbostic switch (uap->whence) { 105413878Ssam case L_INCR: 105564410Sbostic fp->f_offset += uap->offset; 105613878Ssam break; 105713878Ssam case L_XTND: 105864410Sbostic if (error = 105964410Sbostic VOP_GETATTR((struct vnode *)fp->f_data, &vattr, cred, p)) 106047540Skarels return (error); 106164410Sbostic fp->f_offset = uap->offset + vattr.va_size; 106213878Ssam break; 106313878Ssam case L_SET: 106464410Sbostic fp->f_offset = uap->offset; 106513878Ssam break; 106613878Ssam default: 106747540Skarels return (EINVAL); 106813878Ssam } 106954916Storek *(off_t *)retval = fp->f_offset; 107047540Skarels return (0); 10716254Sroot } 10726254Sroot 107360414Smckusick #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 10746254Sroot /* 107564410Sbostic * Reposition read/write file offset. 107660036Smckusick */ 107760428Smckusick struct olseek_args { 107864410Sbostic int fd; 107964410Sbostic long offset; 108064410Sbostic int whence; 108160036Smckusick }; 108260414Smckusick olseek(p, uap, retval) 108360036Smckusick struct proc *p; 108460428Smckusick register struct olseek_args *uap; 108560036Smckusick int *retval; 108660036Smckusick { 108760428Smckusick struct lseek_args nuap; 108860036Smckusick off_t qret; 108960036Smckusick int error; 109060036Smckusick 109164410Sbostic nuap.fd = uap->fd; 109264410Sbostic nuap.offset = uap->offset; 109364410Sbostic nuap.whence = uap->whence; 109460428Smckusick error = lseek(p, &nuap, &qret); 109560036Smckusick *(long *)retval = qret; 109660036Smckusick return (error); 109760036Smckusick } 109860414Smckusick #endif /* COMPAT_43 */ 109960036Smckusick 110060036Smckusick /* 110149365Smckusick * Check access permissions. 11026254Sroot */ 110363427Sbostic struct access_args { 110464410Sbostic char *path; 110564410Sbostic int flags; 110654916Storek }; 110763427Sbostic access(p, uap, retval) 110845914Smckusick struct proc *p; 110963427Sbostic register struct access_args *uap; 111042441Smckusick int *retval; 111142441Smckusick { 111247540Skarels register struct ucred *cred = p->p_ucred; 111337741Smckusick register struct vnode *vp; 111464585Sbostic int error, flags, t_gid, t_uid; 111547540Skarels struct nameidata nd; 11166254Sroot 111764585Sbostic t_uid = cred->cr_uid; 111864585Sbostic t_gid = cred->cr_groups[0]; 111947540Skarels cred->cr_uid = p->p_cred->p_ruid; 112047540Skarels cred->cr_groups[0] = p->p_cred->p_rgid; 112164410Sbostic NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); 112252322Smckusick if (error = namei(&nd)) 112337741Smckusick goto out1; 112452322Smckusick vp = nd.ni_vp; 112564410Sbostic 112664410Sbostic /* Flags == 0 means only check for existence. */ 112764410Sbostic if (uap->flags) { 112864410Sbostic flags = 0; 112964410Sbostic if (uap->flags & R_OK) 113064410Sbostic flags |= VREAD; 113164410Sbostic if (uap->flags & W_OK) 113264410Sbostic flags |= VWRITE; 113364410Sbostic if (uap->flags & X_OK) 113464410Sbostic flags |= VEXEC; 113564410Sbostic if ((flags & VWRITE) == 0 || (error = vn_writechk(vp)) == 0) 113664410Sbostic error = VOP_ACCESS(vp, flags, cred, p); 11376254Sroot } 113837741Smckusick vput(vp); 113937741Smckusick out1: 114064585Sbostic cred->cr_uid = t_uid; 114164585Sbostic cred->cr_groups[0] = t_gid; 114247540Skarels return (error); 11436254Sroot } 11446254Sroot 114554348Smckusick #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 11466254Sroot /* 114764410Sbostic * Get file status; this version follows links. 114837Sbill */ 114954916Storek struct ostat_args { 115064410Sbostic char *path; 115154916Storek struct ostat *ub; 115254916Storek }; 115342441Smckusick /* ARGSUSED */ 115453759Smckusick ostat(p, uap, retval) 115545914Smckusick struct proc *p; 115654916Storek register struct ostat_args *uap; 115753468Smckusick int *retval; 115853468Smckusick { 115953468Smckusick struct stat sb; 116053468Smckusick struct ostat osb; 116153468Smckusick int error; 116253468Smckusick struct nameidata nd; 116353468Smckusick 116464410Sbostic NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); 116553468Smckusick if (error = namei(&nd)) 116653468Smckusick return (error); 116753468Smckusick error = vn_stat(nd.ni_vp, &sb, p); 116853468Smckusick vput(nd.ni_vp); 116953468Smckusick if (error) 117053468Smckusick return (error); 117153468Smckusick cvtstat(&sb, &osb); 117253468Smckusick error = copyout((caddr_t)&osb, (caddr_t)uap->ub, sizeof (osb)); 117353468Smckusick return (error); 117453468Smckusick } 117553468Smckusick 117653468Smckusick /* 117764410Sbostic * Get file status; this version does not follow links. 117853468Smckusick */ 117954916Storek struct olstat_args { 118064410Sbostic char *path; 118154916Storek struct ostat *ub; 118254916Storek }; 118353468Smckusick /* ARGSUSED */ 118453759Smckusick olstat(p, uap, retval) 118553468Smckusick struct proc *p; 118654916Storek register struct olstat_args *uap; 118753468Smckusick int *retval; 118853468Smckusick { 118967748Smckusick struct vnode *vp, *dvp; 119067748Smckusick struct stat sb, sb1; 119153468Smckusick struct ostat osb; 119253468Smckusick int error; 119353468Smckusick struct nameidata nd; 119453468Smckusick 119567748Smckusick NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | LOCKPARENT, UIO_USERSPACE, 119667748Smckusick uap->path, p); 119753468Smckusick if (error = namei(&nd)) 119853468Smckusick return (error); 119967748Smckusick /* 120067748Smckusick * For symbolic links, always return the attributes of its 120167748Smckusick * containing directory, except for mode, size, and links. 120267748Smckusick */ 120367748Smckusick vp = nd.ni_vp; 120467748Smckusick dvp = nd.ni_dvp; 120567748Smckusick if (vp->v_type != VLNK) { 120667748Smckusick if (dvp == vp) 120767748Smckusick vrele(dvp); 120867748Smckusick else 120967748Smckusick vput(dvp); 121067748Smckusick error = vn_stat(vp, &sb, p); 121167748Smckusick vput(vp); 121267748Smckusick if (error) 121367748Smckusick return (error); 121467748Smckusick } else { 121567748Smckusick error = vn_stat(dvp, &sb, p); 121667748Smckusick vput(dvp); 121767748Smckusick if (error) { 121867748Smckusick vput(vp); 121967748Smckusick return (error); 122067748Smckusick } 122167748Smckusick error = vn_stat(vp, &sb1, p); 122267748Smckusick vput(vp); 122367748Smckusick if (error) 122467748Smckusick return (error); 122567748Smckusick sb.st_mode &= ~S_IFDIR; 122667748Smckusick sb.st_mode |= S_IFLNK; 122767748Smckusick sb.st_nlink = sb1.st_nlink; 122867748Smckusick sb.st_size = sb1.st_size; 122967748Smckusick sb.st_blocks = sb1.st_blocks; 123067748Smckusick } 123153468Smckusick cvtstat(&sb, &osb); 123253468Smckusick error = copyout((caddr_t)&osb, (caddr_t)uap->ub, sizeof (osb)); 123353468Smckusick return (error); 123453468Smckusick } 123553468Smckusick 123653468Smckusick /* 123764410Sbostic * Convert from an old to a new stat structure. 123853468Smckusick */ 123953468Smckusick cvtstat(st, ost) 124053468Smckusick struct stat *st; 124153468Smckusick struct ostat *ost; 124253468Smckusick { 124353468Smckusick 124453468Smckusick ost->st_dev = st->st_dev; 124553468Smckusick ost->st_ino = st->st_ino; 124653468Smckusick ost->st_mode = st->st_mode; 124753468Smckusick ost->st_nlink = st->st_nlink; 124853468Smckusick ost->st_uid = st->st_uid; 124953468Smckusick ost->st_gid = st->st_gid; 125053468Smckusick ost->st_rdev = st->st_rdev; 125153468Smckusick if (st->st_size < (quad_t)1 << 32) 125253468Smckusick ost->st_size = st->st_size; 125353468Smckusick else 125453468Smckusick ost->st_size = -2; 125553468Smckusick ost->st_atime = st->st_atime; 125653468Smckusick ost->st_mtime = st->st_mtime; 125753468Smckusick ost->st_ctime = st->st_ctime; 125853468Smckusick ost->st_blksize = st->st_blksize; 125953468Smckusick ost->st_blocks = st->st_blocks; 126053468Smckusick ost->st_flags = st->st_flags; 126153468Smckusick ost->st_gen = st->st_gen; 126253468Smckusick } 126354348Smckusick #endif /* COMPAT_43 || COMPAT_SUNOS */ 126453468Smckusick 126553468Smckusick /* 126664410Sbostic * Get file status; this version follows links. 126753468Smckusick */ 126854916Storek struct stat_args { 126964410Sbostic char *path; 127054916Storek struct stat *ub; 127154916Storek }; 127253468Smckusick /* ARGSUSED */ 127353759Smckusick stat(p, uap, retval) 127453468Smckusick struct proc *p; 127554916Storek register struct stat_args *uap; 127642441Smckusick int *retval; 127737Sbill { 127842441Smckusick struct stat sb; 127942441Smckusick int error; 128047540Skarels struct nameidata nd; 128137Sbill 128264410Sbostic NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); 128352322Smckusick if (error = namei(&nd)) 128447540Skarels return (error); 128552322Smckusick error = vn_stat(nd.ni_vp, &sb, p); 128652322Smckusick vput(nd.ni_vp); 128742441Smckusick if (error) 128847540Skarels return (error); 128942441Smckusick error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb)); 129047540Skarels return (error); 129137Sbill } 129237Sbill 129337Sbill /* 129464410Sbostic * Get file status; this version does not follow links. 12955992Swnj */ 129654916Storek struct lstat_args { 129764410Sbostic char *path; 129854916Storek struct stat *ub; 129954916Storek }; 130042441Smckusick /* ARGSUSED */ 130153759Smckusick lstat(p, uap, retval) 130245914Smckusick struct proc *p; 130354916Storek register struct lstat_args *uap; 130442441Smckusick int *retval; 130542441Smckusick { 130637741Smckusick int error; 130759373Smckusick struct vnode *vp, *dvp; 130859373Smckusick struct stat sb, sb1; 130947540Skarels struct nameidata nd; 13105992Swnj 131159373Smckusick NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | LOCKPARENT, UIO_USERSPACE, 131264410Sbostic uap->path, p); 131352322Smckusick if (error = namei(&nd)) 131447540Skarels return (error); 131559373Smckusick /* 131659373Smckusick * For symbolic links, always return the attributes of its 131759373Smckusick * containing directory, except for mode, size, and links. 131859373Smckusick */ 131959373Smckusick vp = nd.ni_vp; 132059373Smckusick dvp = nd.ni_dvp; 132159373Smckusick if (vp->v_type != VLNK) { 132259373Smckusick if (dvp == vp) 132359373Smckusick vrele(dvp); 132459373Smckusick else 132559373Smckusick vput(dvp); 132659373Smckusick error = vn_stat(vp, &sb, p); 132759373Smckusick vput(vp); 132859373Smckusick if (error) 132959373Smckusick return (error); 133059373Smckusick } else { 133159373Smckusick error = vn_stat(dvp, &sb, p); 133259373Smckusick vput(dvp); 133359373Smckusick if (error) { 133459373Smckusick vput(vp); 133559373Smckusick return (error); 133659373Smckusick } 133759373Smckusick error = vn_stat(vp, &sb1, p); 133859373Smckusick vput(vp); 133959373Smckusick if (error) 134059373Smckusick return (error); 134159373Smckusick sb.st_mode &= ~S_IFDIR; 134259373Smckusick sb.st_mode |= S_IFLNK; 134359373Smckusick sb.st_nlink = sb1.st_nlink; 134459373Smckusick sb.st_size = sb1.st_size; 134559373Smckusick sb.st_blocks = sb1.st_blocks; 134659373Smckusick } 134737741Smckusick error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb)); 134847540Skarels return (error); 13495992Swnj } 13505992Swnj 13515992Swnj /* 135264410Sbostic * Get configurable pathname variables. 135360414Smckusick */ 135460414Smckusick struct pathconf_args { 135564410Sbostic char *path; 135660414Smckusick int name; 135760414Smckusick }; 135860414Smckusick /* ARGSUSED */ 135960414Smckusick pathconf(p, uap, retval) 136060414Smckusick struct proc *p; 136160414Smckusick register struct pathconf_args *uap; 136260414Smckusick int *retval; 136360414Smckusick { 136460414Smckusick int error; 136560414Smckusick struct nameidata nd; 136660414Smckusick 136764410Sbostic NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); 136860414Smckusick if (error = namei(&nd)) 136960414Smckusick return (error); 137060414Smckusick error = VOP_PATHCONF(nd.ni_vp, uap->name, retval); 137160414Smckusick vput(nd.ni_vp); 137260414Smckusick return (error); 137360414Smckusick } 137460414Smckusick 137560414Smckusick /* 137649365Smckusick * Return target name of a symbolic link. 137737Sbill */ 137854916Storek struct readlink_args { 137964410Sbostic char *path; 138054916Storek char *buf; 138154916Storek int count; 138254916Storek }; 138342441Smckusick /* ARGSUSED */ 138442441Smckusick readlink(p, uap, retval) 138545914Smckusick struct proc *p; 138654916Storek register struct readlink_args *uap; 138742441Smckusick int *retval; 138842441Smckusick { 138937741Smckusick register struct vnode *vp; 139037741Smckusick struct iovec aiov; 139137741Smckusick struct uio auio; 139237741Smckusick int error; 139347540Skarels struct nameidata nd; 13945992Swnj 139564410Sbostic NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); 139652322Smckusick if (error = namei(&nd)) 139747540Skarels return (error); 139852322Smckusick vp = nd.ni_vp; 139964410Sbostic if (vp->v_type != VLNK) 140037741Smckusick error = EINVAL; 140164410Sbostic else { 140264410Sbostic aiov.iov_base = uap->buf; 140364410Sbostic aiov.iov_len = uap->count; 140464410Sbostic auio.uio_iov = &aiov; 140564410Sbostic auio.uio_iovcnt = 1; 140664410Sbostic auio.uio_offset = 0; 140764410Sbostic auio.uio_rw = UIO_READ; 140864410Sbostic auio.uio_segflg = UIO_USERSPACE; 140964410Sbostic auio.uio_procp = p; 141064410Sbostic auio.uio_resid = uap->count; 141164410Sbostic error = VOP_READLINK(vp, &auio, p->p_ucred); 14125992Swnj } 141337741Smckusick vput(vp); 141442441Smckusick *retval = uap->count - auio.uio_resid; 141547540Skarels return (error); 14165992Swnj } 14175992Swnj 14189167Ssam /* 141964410Sbostic * Change flags of a file given a path name. 142038259Smckusick */ 142154916Storek struct chflags_args { 142264410Sbostic char *path; 142354916Storek int flags; 142454916Storek }; 142542441Smckusick /* ARGSUSED */ 142642441Smckusick chflags(p, uap, retval) 142745914Smckusick struct proc *p; 142854916Storek register struct chflags_args *uap; 142942441Smckusick int *retval; 143042441Smckusick { 143138259Smckusick register struct vnode *vp; 143238259Smckusick struct vattr vattr; 143338259Smckusick int error; 143447540Skarels struct nameidata nd; 143538259Smckusick 143664410Sbostic NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); 143752322Smckusick if (error = namei(&nd)) 143847540Skarels return (error); 143952322Smckusick vp = nd.ni_vp; 144067654Smckusick VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 144159382Smckusick VOP_LOCK(vp); 144264410Sbostic if (vp->v_mount->mnt_flag & MNT_RDONLY) 144338259Smckusick error = EROFS; 144464410Sbostic else { 144564410Sbostic VATTR_NULL(&vattr); 144664410Sbostic vattr.va_flags = uap->flags; 144764410Sbostic error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 144838259Smckusick } 144938259Smckusick vput(vp); 145047540Skarels return (error); 145138259Smckusick } 145238259Smckusick 145338259Smckusick /* 145438259Smckusick * Change flags of a file given a file descriptor. 145538259Smckusick */ 145654916Storek struct fchflags_args { 145754916Storek int fd; 145854916Storek int flags; 145954916Storek }; 146042441Smckusick /* ARGSUSED */ 146142441Smckusick fchflags(p, uap, retval) 146245914Smckusick struct proc *p; 146354916Storek register struct fchflags_args *uap; 146442441Smckusick int *retval; 146542441Smckusick { 146638259Smckusick struct vattr vattr; 146738259Smckusick struct vnode *vp; 146838259Smckusick struct file *fp; 146938259Smckusick int error; 147038259Smckusick 147145914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 147247540Skarels return (error); 147338259Smckusick vp = (struct vnode *)fp->f_data; 147467654Smckusick VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 147538259Smckusick VOP_LOCK(vp); 147664410Sbostic if (vp->v_mount->mnt_flag & MNT_RDONLY) 147738259Smckusick error = EROFS; 147864410Sbostic else { 147964410Sbostic VATTR_NULL(&vattr); 148064410Sbostic vattr.va_flags = uap->flags; 148164410Sbostic error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 148238259Smckusick } 148338259Smckusick VOP_UNLOCK(vp); 148447540Skarels return (error); 148538259Smckusick } 148638259Smckusick 148738259Smckusick /* 14889167Ssam * Change mode of a file given path name. 14899167Ssam */ 149054916Storek struct chmod_args { 149164410Sbostic char *path; 149264410Sbostic int mode; 149354916Storek }; 149442441Smckusick /* ARGSUSED */ 149542441Smckusick chmod(p, uap, retval) 149645914Smckusick struct proc *p; 149754916Storek register struct chmod_args *uap; 149842441Smckusick int *retval; 149942441Smckusick { 150037741Smckusick register struct vnode *vp; 150137741Smckusick struct vattr vattr; 150237741Smckusick int error; 150347540Skarels struct nameidata nd; 15045992Swnj 150564410Sbostic NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); 150652322Smckusick if (error = namei(&nd)) 150747540Skarels return (error); 150852322Smckusick vp = nd.ni_vp; 150967654Smckusick VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 151059382Smckusick VOP_LOCK(vp); 151164410Sbostic if (vp->v_mount->mnt_flag & MNT_RDONLY) 151237741Smckusick error = EROFS; 151364410Sbostic else { 151464410Sbostic VATTR_NULL(&vattr); 151564410Sbostic vattr.va_mode = uap->mode & ALLPERMS; 151664410Sbostic error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 151737741Smckusick } 151837741Smckusick vput(vp); 151947540Skarels return (error); 15207701Ssam } 15217439Sroot 15229167Ssam /* 15239167Ssam * Change mode of a file given a file descriptor. 15249167Ssam */ 152554916Storek struct fchmod_args { 152654916Storek int fd; 152764410Sbostic int mode; 152854916Storek }; 152942441Smckusick /* ARGSUSED */ 153042441Smckusick fchmod(p, uap, retval) 153145914Smckusick struct proc *p; 153254916Storek register struct fchmod_args *uap; 153342441Smckusick int *retval; 153442441Smckusick { 153537741Smckusick struct vattr vattr; 153637741Smckusick struct vnode *vp; 153737741Smckusick struct file *fp; 153837741Smckusick int error; 15397701Ssam 154045914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 154147540Skarels return (error); 154237741Smckusick vp = (struct vnode *)fp->f_data; 154367654Smckusick VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 154437741Smckusick VOP_LOCK(vp); 154564410Sbostic if (vp->v_mount->mnt_flag & MNT_RDONLY) 154637741Smckusick error = EROFS; 154764410Sbostic else { 154864410Sbostic VATTR_NULL(&vattr); 154964410Sbostic vattr.va_mode = uap->mode & ALLPERMS; 155064410Sbostic error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 15517439Sroot } 155237741Smckusick VOP_UNLOCK(vp); 155347540Skarels return (error); 15545992Swnj } 15555992Swnj 15569167Ssam /* 15579167Ssam * Set ownership given a path name. 15589167Ssam */ 155954916Storek struct chown_args { 156064410Sbostic char *path; 156154916Storek int uid; 156254916Storek int gid; 156354916Storek }; 156442441Smckusick /* ARGSUSED */ 156542441Smckusick chown(p, uap, retval) 156645914Smckusick struct proc *p; 156754916Storek register struct chown_args *uap; 156842441Smckusick int *retval; 156942441Smckusick { 157037741Smckusick register struct vnode *vp; 157137741Smckusick struct vattr vattr; 157237741Smckusick int error; 157347540Skarels struct nameidata nd; 157437Sbill 157566510Sbostic NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); 157652322Smckusick if (error = namei(&nd)) 157747540Skarels return (error); 157852322Smckusick vp = nd.ni_vp; 157967654Smckusick VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 158059382Smckusick VOP_LOCK(vp); 158164410Sbostic if (vp->v_mount->mnt_flag & MNT_RDONLY) 158237741Smckusick error = EROFS; 158364410Sbostic else { 158464410Sbostic VATTR_NULL(&vattr); 158564410Sbostic vattr.va_uid = uap->uid; 158664410Sbostic vattr.va_gid = uap->gid; 158764410Sbostic error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 158837741Smckusick } 158937741Smckusick vput(vp); 159047540Skarels return (error); 15917701Ssam } 15927439Sroot 15939167Ssam /* 15949167Ssam * Set ownership given a file descriptor. 15959167Ssam */ 159654916Storek struct fchown_args { 159754916Storek int fd; 159854916Storek int uid; 159954916Storek int gid; 160054916Storek }; 160142441Smckusick /* ARGSUSED */ 160242441Smckusick fchown(p, uap, retval) 160345914Smckusick struct proc *p; 160454916Storek register struct fchown_args *uap; 160542441Smckusick int *retval; 160642441Smckusick { 160737741Smckusick struct vattr vattr; 160837741Smckusick struct vnode *vp; 160937741Smckusick struct file *fp; 161037741Smckusick int error; 16117701Ssam 161245914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 161347540Skarels return (error); 161437741Smckusick vp = (struct vnode *)fp->f_data; 161567654Smckusick VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 161637741Smckusick VOP_LOCK(vp); 161764410Sbostic if (vp->v_mount->mnt_flag & MNT_RDONLY) 161837741Smckusick error = EROFS; 161964410Sbostic else { 162064410Sbostic VATTR_NULL(&vattr); 162164410Sbostic vattr.va_uid = uap->uid; 162264410Sbostic vattr.va_gid = uap->gid; 162364410Sbostic error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 162437741Smckusick } 162537741Smckusick VOP_UNLOCK(vp); 162647540Skarels return (error); 16277701Ssam } 16287701Ssam 162942441Smckusick /* 163042441Smckusick * Set the access and modification times of a file. 163142441Smckusick */ 163254916Storek struct utimes_args { 163364410Sbostic char *path; 163454916Storek struct timeval *tptr; 163554916Storek }; 163642441Smckusick /* ARGSUSED */ 163742441Smckusick utimes(p, uap, retval) 163845914Smckusick struct proc *p; 163954916Storek register struct utimes_args *uap; 164042441Smckusick int *retval; 164142441Smckusick { 164237741Smckusick register struct vnode *vp; 164311811Ssam struct timeval tv[2]; 164437741Smckusick struct vattr vattr; 164558840Storek int error; 164647540Skarels struct nameidata nd; 164711811Ssam 164858505Sbostic VATTR_NULL(&vattr); 164958505Sbostic if (uap->tptr == NULL) { 165058505Sbostic microtime(&tv[0]); 165158505Sbostic tv[1] = tv[0]; 165258548Sbostic vattr.va_vaflags |= VA_UTIMES_NULL; 165358505Sbostic } else if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv))) 165458505Sbostic return (error); 165564410Sbostic NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); 165652322Smckusick if (error = namei(&nd)) 165747540Skarels return (error); 165852322Smckusick vp = nd.ni_vp; 165967654Smckusick VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 166059382Smckusick VOP_LOCK(vp); 166164410Sbostic if (vp->v_mount->mnt_flag & MNT_RDONLY) 166237741Smckusick error = EROFS; 166364410Sbostic else { 166464410Sbostic vattr.va_atime.ts_sec = tv[0].tv_sec; 166564410Sbostic vattr.va_atime.ts_nsec = tv[0].tv_usec * 1000; 166664410Sbostic vattr.va_mtime.ts_sec = tv[1].tv_sec; 166764410Sbostic vattr.va_mtime.ts_nsec = tv[1].tv_usec * 1000; 166864410Sbostic error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 166921015Smckusick } 167037741Smckusick vput(vp); 167147540Skarels return (error); 167211811Ssam } 167311811Ssam 167464410Sbostic /* 167564410Sbostic * Truncate a file given its path name. 167664410Sbostic */ 167760428Smckusick struct truncate_args { 167864410Sbostic char *path; 167954863Storek int pad; 168054863Storek off_t length; 168154863Storek }; 168253468Smckusick /* ARGSUSED */ 168360414Smckusick truncate(p, uap, retval) 168453468Smckusick struct proc *p; 168560428Smckusick register struct truncate_args *uap; 168653468Smckusick int *retval; 168753468Smckusick { 168837741Smckusick register struct vnode *vp; 168937741Smckusick struct vattr vattr; 169037741Smckusick int error; 169147540Skarels struct nameidata nd; 16927701Ssam 169364410Sbostic NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); 169452322Smckusick if (error = namei(&nd)) 169547540Skarels return (error); 169652322Smckusick vp = nd.ni_vp; 169767654Smckusick VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 169859382Smckusick VOP_LOCK(vp); 169964410Sbostic if (vp->v_type == VDIR) 170037741Smckusick error = EISDIR; 170164410Sbostic else if ((error = vn_writechk(vp)) == 0 && 170264410Sbostic (error = VOP_ACCESS(vp, VWRITE, p->p_ucred, p)) == 0) { 170364410Sbostic VATTR_NULL(&vattr); 170464410Sbostic vattr.va_size = uap->length; 170564410Sbostic error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 17067701Ssam } 170737741Smckusick vput(vp); 170847540Skarels return (error); 17097701Ssam } 17107701Ssam 171164410Sbostic /* 171264410Sbostic * Truncate a file given a file descriptor. 171364410Sbostic */ 171460428Smckusick struct ftruncate_args { 171554863Storek int fd; 171654863Storek int pad; 171754863Storek off_t length; 171854863Storek }; 171942441Smckusick /* ARGSUSED */ 172060414Smckusick ftruncate(p, uap, retval) 172145914Smckusick struct proc *p; 172260428Smckusick register struct ftruncate_args *uap; 172342441Smckusick int *retval; 172442441Smckusick { 172537741Smckusick struct vattr vattr; 172637741Smckusick struct vnode *vp; 17277701Ssam struct file *fp; 172837741Smckusick int error; 17297701Ssam 173045914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 173147540Skarels return (error); 173237741Smckusick if ((fp->f_flag & FWRITE) == 0) 173347540Skarels return (EINVAL); 173437741Smckusick vp = (struct vnode *)fp->f_data; 173567654Smckusick VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 173637741Smckusick VOP_LOCK(vp); 173764410Sbostic if (vp->v_type == VDIR) 173837741Smckusick error = EISDIR; 173964410Sbostic else if ((error = vn_writechk(vp)) == 0) { 174064410Sbostic VATTR_NULL(&vattr); 174164410Sbostic vattr.va_size = uap->length; 174264410Sbostic error = VOP_SETATTR(vp, &vattr, fp->f_cred, p); 17437701Ssam } 174437741Smckusick VOP_UNLOCK(vp); 174547540Skarels return (error); 17467701Ssam } 17477701Ssam 174854863Storek #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 17499167Ssam /* 175054863Storek * Truncate a file given its path name. 175154863Storek */ 175260428Smckusick struct otruncate_args { 175364410Sbostic char *path; 175454916Storek long length; 175554916Storek }; 175654863Storek /* ARGSUSED */ 175760105Smckusick otruncate(p, uap, retval) 175854863Storek struct proc *p; 175960428Smckusick register struct otruncate_args *uap; 176054863Storek int *retval; 176154863Storek { 176260428Smckusick struct truncate_args nuap; 176354863Storek 176464410Sbostic nuap.path = uap->path; 176554863Storek nuap.length = uap->length; 176660428Smckusick return (truncate(p, &nuap, retval)); 176754863Storek } 176854863Storek 176954863Storek /* 177054863Storek * Truncate a file given a file descriptor. 177154863Storek */ 177260428Smckusick struct oftruncate_args { 177354916Storek int fd; 177454916Storek long length; 177554916Storek }; 177654863Storek /* ARGSUSED */ 177760105Smckusick oftruncate(p, uap, retval) 177854863Storek struct proc *p; 177960428Smckusick register struct oftruncate_args *uap; 178054863Storek int *retval; 178154863Storek { 178260428Smckusick struct ftruncate_args nuap; 178354863Storek 178454863Storek nuap.fd = uap->fd; 178554863Storek nuap.length = uap->length; 178660428Smckusick return (ftruncate(p, &nuap, retval)); 178754863Storek } 178854863Storek #endif /* COMPAT_43 || COMPAT_SUNOS */ 178954863Storek 179054863Storek /* 179164410Sbostic * Sync an open file. 17929167Ssam */ 179354916Storek struct fsync_args { 179454916Storek int fd; 179554916Storek }; 179642441Smckusick /* ARGSUSED */ 179742441Smckusick fsync(p, uap, retval) 179845914Smckusick struct proc *p; 179954916Storek struct fsync_args *uap; 180042441Smckusick int *retval; 18019167Ssam { 180239592Smckusick register struct vnode *vp; 18039167Ssam struct file *fp; 180437741Smckusick int error; 18059167Ssam 180645914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 180747540Skarels return (error); 180839592Smckusick vp = (struct vnode *)fp->f_data; 180939592Smckusick VOP_LOCK(vp); 181054441Smckusick error = VOP_FSYNC(vp, fp->f_cred, MNT_WAIT, p); 181139592Smckusick VOP_UNLOCK(vp); 181247540Skarels return (error); 18139167Ssam } 18149167Ssam 18159167Ssam /* 181664410Sbostic * Rename files. Source and destination must either both be directories, 181764410Sbostic * or both not be directories. If target is a directory, it must be empty. 18189167Ssam */ 181954916Storek struct rename_args { 182054916Storek char *from; 182154916Storek char *to; 182254916Storek }; 182342441Smckusick /* ARGSUSED */ 182442441Smckusick rename(p, uap, retval) 182545914Smckusick struct proc *p; 182654916Storek register struct rename_args *uap; 182742441Smckusick int *retval; 182842441Smckusick { 182937741Smckusick register struct vnode *tvp, *fvp, *tdvp; 183049735Smckusick struct nameidata fromnd, tond; 183137741Smckusick int error; 18327701Ssam 183352322Smckusick NDINIT(&fromnd, DELETE, WANTPARENT | SAVESTART, UIO_USERSPACE, 183452322Smckusick uap->from, p); 183552322Smckusick if (error = namei(&fromnd)) 183647540Skarels return (error); 183749735Smckusick fvp = fromnd.ni_vp; 183852322Smckusick NDINIT(&tond, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART, 183952322Smckusick UIO_USERSPACE, uap->to, p); 184052322Smckusick if (error = namei(&tond)) { 184152230Sheideman VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 184249735Smckusick vrele(fromnd.ni_dvp); 184342465Smckusick vrele(fvp); 184442465Smckusick goto out1; 184542465Smckusick } 184637741Smckusick tdvp = tond.ni_dvp; 184737741Smckusick tvp = tond.ni_vp; 184837741Smckusick if (tvp != NULL) { 184937741Smckusick if (fvp->v_type == VDIR && tvp->v_type != VDIR) { 185039242Sbostic error = ENOTDIR; 185137741Smckusick goto out; 185237741Smckusick } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) { 185339242Sbostic error = EISDIR; 185437741Smckusick goto out; 18559167Ssam } 18569167Ssam } 185739286Smckusick if (fvp == tdvp) 185837741Smckusick error = EINVAL; 185939286Smckusick /* 186049735Smckusick * If source is the same as the destination (that is the 186149735Smckusick * same inode number with the same name in the same directory), 186239286Smckusick * then there is nothing to do. 186339286Smckusick */ 186449735Smckusick if (fvp == tvp && fromnd.ni_dvp == tdvp && 186552322Smckusick fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen && 186652322Smckusick !bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr, 186752322Smckusick fromnd.ni_cnd.cn_namelen)) 186839286Smckusick error = -1; 186937741Smckusick out: 187042465Smckusick if (!error) { 187167654Smckusick VOP_LEASE(tdvp, p, p->p_ucred, LEASE_WRITE); 187252192Smckusick if (fromnd.ni_dvp != tdvp) 187367654Smckusick VOP_LEASE(fromnd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 187452192Smckusick if (tvp) 187567654Smckusick VOP_LEASE(tvp, p, p->p_ucred, LEASE_WRITE); 187652230Sheideman error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd, 187752230Sheideman tond.ni_dvp, tond.ni_vp, &tond.ni_cnd); 187842465Smckusick } else { 187952230Sheideman VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd); 188043344Smckusick if (tdvp == tvp) 188143344Smckusick vrele(tdvp); 188243344Smckusick else 188343344Smckusick vput(tdvp); 188442465Smckusick if (tvp) 188542465Smckusick vput(tvp); 188652230Sheideman VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 188749735Smckusick vrele(fromnd.ni_dvp); 188842465Smckusick vrele(fvp); 18899167Ssam } 189049735Smckusick vrele(tond.ni_startdir); 189152322Smckusick FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI); 189237741Smckusick out1: 189366801Smckusick if (fromnd.ni_startdir) 189466801Smckusick vrele(fromnd.ni_startdir); 189552322Smckusick FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI); 189639286Smckusick if (error == -1) 189747540Skarels return (0); 189847540Skarels return (error); 18997701Ssam } 19007701Ssam 19017535Sroot /* 190264410Sbostic * Make a directory file. 190312756Ssam */ 190454916Storek struct mkdir_args { 190564410Sbostic char *path; 190664410Sbostic int mode; 190754916Storek }; 190842441Smckusick /* ARGSUSED */ 190942441Smckusick mkdir(p, uap, retval) 191045914Smckusick struct proc *p; 191154916Storek register struct mkdir_args *uap; 191242441Smckusick int *retval; 191342441Smckusick { 191437741Smckusick register struct vnode *vp; 191537741Smckusick struct vattr vattr; 191637741Smckusick int error; 191747540Skarels struct nameidata nd; 191812756Ssam 191964410Sbostic NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->path, p); 192052322Smckusick if (error = namei(&nd)) 192147540Skarels return (error); 192252322Smckusick vp = nd.ni_vp; 192337741Smckusick if (vp != NULL) { 192452322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 192552322Smckusick if (nd.ni_dvp == vp) 192652322Smckusick vrele(nd.ni_dvp); 192743344Smckusick else 192852322Smckusick vput(nd.ni_dvp); 192942465Smckusick vrele(vp); 193047540Skarels return (EEXIST); 193112756Ssam } 193241362Smckusick VATTR_NULL(&vattr); 193337741Smckusick vattr.va_type = VDIR; 193464410Sbostic vattr.va_mode = (uap->mode & ACCESSPERMS) &~ p->p_fd->fd_cmask; 193567654Smckusick VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 193652322Smckusick error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr); 193738145Smckusick if (!error) 193852322Smckusick vput(nd.ni_vp); 193947540Skarels return (error); 194012756Ssam } 194112756Ssam 194212756Ssam /* 194364410Sbostic * Remove a directory file. 194412756Ssam */ 194554916Storek struct rmdir_args { 194664410Sbostic char *path; 194754916Storek }; 194842441Smckusick /* ARGSUSED */ 194942441Smckusick rmdir(p, uap, retval) 195045914Smckusick struct proc *p; 195154916Storek struct rmdir_args *uap; 195242441Smckusick int *retval; 195312756Ssam { 195437741Smckusick register struct vnode *vp; 195537741Smckusick int error; 195647540Skarels struct nameidata nd; 195712756Ssam 195864410Sbostic NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE, uap->path, p); 195952322Smckusick if (error = namei(&nd)) 196047540Skarels return (error); 196152322Smckusick vp = nd.ni_vp; 196237741Smckusick if (vp->v_type != VDIR) { 196337741Smckusick error = ENOTDIR; 196412756Ssam goto out; 196512756Ssam } 196612756Ssam /* 196737741Smckusick * No rmdir "." please. 196812756Ssam */ 196952322Smckusick if (nd.ni_dvp == vp) { 197037741Smckusick error = EINVAL; 197112756Ssam goto out; 197212756Ssam } 197312756Ssam /* 197449365Smckusick * The root of a mounted filesystem cannot be deleted. 197512756Ssam */ 197637741Smckusick if (vp->v_flag & VROOT) 197737741Smckusick error = EBUSY; 197812756Ssam out: 197942465Smckusick if (!error) { 198067654Smckusick VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 198167654Smckusick VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 198252322Smckusick error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); 198342465Smckusick } else { 198452322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 198552322Smckusick if (nd.ni_dvp == vp) 198652322Smckusick vrele(nd.ni_dvp); 198743344Smckusick else 198852322Smckusick vput(nd.ni_dvp); 198942465Smckusick vput(vp); 199042465Smckusick } 199147540Skarels return (error); 199212756Ssam } 199312756Ssam 199454620Smckusick #ifdef COMPAT_43 199537741Smckusick /* 199649365Smckusick * Read a block of directory entries in a file system independent format. 199737741Smckusick */ 199854916Storek struct ogetdirentries_args { 199954916Storek int fd; 200054916Storek char *buf; 200164410Sbostic u_int count; 200254916Storek long *basep; 200354916Storek }; 200454620Smckusick ogetdirentries(p, uap, retval) 200554620Smckusick struct proc *p; 200654916Storek register struct ogetdirentries_args *uap; 200754620Smckusick int *retval; 200854620Smckusick { 200954620Smckusick register struct vnode *vp; 201054620Smckusick struct file *fp; 201154620Smckusick struct uio auio, kuio; 201254620Smckusick struct iovec aiov, kiov; 201354620Smckusick struct dirent *dp, *edp; 201454620Smckusick caddr_t dirbuf; 201567362Smckusick int error, eofflag, readcnt; 201654969Smckusick long loff; 201754620Smckusick 201854620Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 201954620Smckusick return (error); 202054620Smckusick if ((fp->f_flag & FREAD) == 0) 202154620Smckusick return (EBADF); 202254620Smckusick vp = (struct vnode *)fp->f_data; 202367362Smckusick unionread: 202454620Smckusick if (vp->v_type != VDIR) 202554620Smckusick return (EINVAL); 202654620Smckusick aiov.iov_base = uap->buf; 202754620Smckusick aiov.iov_len = uap->count; 202854620Smckusick auio.uio_iov = &aiov; 202954620Smckusick auio.uio_iovcnt = 1; 203054620Smckusick auio.uio_rw = UIO_READ; 203154620Smckusick auio.uio_segflg = UIO_USERSPACE; 203254620Smckusick auio.uio_procp = p; 203354620Smckusick auio.uio_resid = uap->count; 203454620Smckusick VOP_LOCK(vp); 203554969Smckusick loff = auio.uio_offset = fp->f_offset; 203654620Smckusick # if (BYTE_ORDER != LITTLE_ENDIAN) 203756339Smckusick if (vp->v_mount->mnt_maxsymlinklen <= 0) { 203867362Smckusick error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, 203967362Smckusick (u_long *)0, 0); 204056339Smckusick fp->f_offset = auio.uio_offset; 204156339Smckusick } else 204254620Smckusick # endif 204354620Smckusick { 204454620Smckusick kuio = auio; 204554620Smckusick kuio.uio_iov = &kiov; 204654620Smckusick kuio.uio_segflg = UIO_SYSSPACE; 204754620Smckusick kiov.iov_len = uap->count; 204854620Smckusick MALLOC(dirbuf, caddr_t, uap->count, M_TEMP, M_WAITOK); 204954620Smckusick kiov.iov_base = dirbuf; 205067362Smckusick error = VOP_READDIR(vp, &kuio, fp->f_cred, &eofflag, 205167362Smckusick (u_long *)0, 0); 205256339Smckusick fp->f_offset = kuio.uio_offset; 205354620Smckusick if (error == 0) { 205454620Smckusick readcnt = uap->count - kuio.uio_resid; 205554620Smckusick edp = (struct dirent *)&dirbuf[readcnt]; 205654620Smckusick for (dp = (struct dirent *)dirbuf; dp < edp; ) { 205754620Smckusick # if (BYTE_ORDER == LITTLE_ENDIAN) 205854969Smckusick /* 205955009Smckusick * The expected low byte of 206055009Smckusick * dp->d_namlen is our dp->d_type. 206155009Smckusick * The high MBZ byte of dp->d_namlen 206255009Smckusick * is our dp->d_namlen. 206354969Smckusick */ 206455009Smckusick dp->d_type = dp->d_namlen; 206555009Smckusick dp->d_namlen = 0; 206655009Smckusick # else 206755009Smckusick /* 206855009Smckusick * The dp->d_type is the high byte 206955009Smckusick * of the expected dp->d_namlen, 207055009Smckusick * so must be zero'ed. 207155009Smckusick */ 207255009Smckusick dp->d_type = 0; 207354620Smckusick # endif 207454620Smckusick if (dp->d_reclen > 0) { 207554620Smckusick dp = (struct dirent *) 207654620Smckusick ((char *)dp + dp->d_reclen); 207754620Smckusick } else { 207854620Smckusick error = EIO; 207954620Smckusick break; 208054620Smckusick } 208154620Smckusick } 208254620Smckusick if (dp >= edp) 208354620Smckusick error = uiomove(dirbuf, readcnt, &auio); 208454620Smckusick } 208554620Smckusick FREE(dirbuf, M_TEMP); 208654620Smckusick } 208754620Smckusick VOP_UNLOCK(vp); 208854620Smckusick if (error) 208954620Smckusick return (error); 209067362Smckusick 209167362Smckusick #ifdef UNION 209267362Smckusick { 209367362Smckusick extern int (**union_vnodeop_p)(); 2094*68079Spendry extern struct vnode *union_dircache __P((struct vnode *)); 209567362Smckusick 209667362Smckusick if ((uap->count == auio.uio_resid) && 209767362Smckusick (vp->v_op == union_vnodeop_p)) { 209867362Smckusick struct vnode *lvp; 209967362Smckusick 2100*68079Spendry lvp = union_dircache(vp); 210167362Smckusick if (lvp != NULLVP) { 210267575Spendry struct vattr va; 210367575Spendry 210467575Spendry /* 210567575Spendry * If the directory is opaque, 210667575Spendry * then don't show lower entries 210767575Spendry */ 210867575Spendry error = VOP_GETATTR(vp, &va, fp->f_cred, p); 210967575Spendry if (va.va_flags & OPAQUE) { 2110*68079Spendry vput(lvp); 211167575Spendry lvp = NULL; 211267575Spendry } 211367575Spendry } 211467575Spendry 211567575Spendry if (lvp != NULLVP) { 211667362Smckusick error = VOP_OPEN(lvp, FREAD, fp->f_cred, p); 211767362Smckusick VOP_UNLOCK(lvp); 211867362Smckusick 211967362Smckusick if (error) { 212067362Smckusick vrele(lvp); 212167362Smckusick return (error); 212267362Smckusick } 212367362Smckusick fp->f_data = (caddr_t) lvp; 212467362Smckusick fp->f_offset = 0; 212567362Smckusick error = vn_close(vp, FREAD, fp->f_cred, p); 212667362Smckusick if (error) 212767362Smckusick return (error); 212867362Smckusick vp = lvp; 212967362Smckusick goto unionread; 213067362Smckusick } 213167362Smckusick } 213267362Smckusick } 213367362Smckusick #endif /* UNION */ 213467362Smckusick 213567362Smckusick if ((uap->count == auio.uio_resid) && 213667362Smckusick (vp->v_flag & VROOT) && 213767362Smckusick (vp->v_mount->mnt_flag & MNT_UNION)) { 213867362Smckusick struct vnode *tvp = vp; 213967362Smckusick vp = vp->v_mount->mnt_vnodecovered; 214067362Smckusick VREF(vp); 214167362Smckusick fp->f_data = (caddr_t) vp; 214267362Smckusick fp->f_offset = 0; 214367362Smckusick vrele(tvp); 214467362Smckusick goto unionread; 214567362Smckusick } 214654969Smckusick error = copyout((caddr_t)&loff, (caddr_t)uap->basep, sizeof(long)); 214754620Smckusick *retval = uap->count - auio.uio_resid; 214854620Smckusick return (error); 214954620Smckusick } 215067362Smckusick #endif /* COMPAT_43 */ 215154620Smckusick 215254620Smckusick /* 215354620Smckusick * Read a block of directory entries in a file system independent format. 215454620Smckusick */ 215554916Storek struct getdirentries_args { 215654916Storek int fd; 215754916Storek char *buf; 215864410Sbostic u_int count; 215954916Storek long *basep; 216054916Storek }; 216142441Smckusick getdirentries(p, uap, retval) 216245914Smckusick struct proc *p; 216354916Storek register struct getdirentries_args *uap; 216442441Smckusick int *retval; 216542441Smckusick { 216639592Smckusick register struct vnode *vp; 216716540Ssam struct file *fp; 216837741Smckusick struct uio auio; 216937741Smckusick struct iovec aiov; 217054969Smckusick long loff; 217167362Smckusick int error, eofflag; 217212756Ssam 217345914Smckusick if (error = getvnode(p->p_fd, uap->fd, &fp)) 217447540Skarels return (error); 217537741Smckusick if ((fp->f_flag & FREAD) == 0) 217647540Skarels return (EBADF); 217739592Smckusick vp = (struct vnode *)fp->f_data; 217855451Spendry unionread: 217939592Smckusick if (vp->v_type != VDIR) 218047540Skarels return (EINVAL); 218137741Smckusick aiov.iov_base = uap->buf; 218237741Smckusick aiov.iov_len = uap->count; 218337741Smckusick auio.uio_iov = &aiov; 218437741Smckusick auio.uio_iovcnt = 1; 218537741Smckusick auio.uio_rw = UIO_READ; 218637741Smckusick auio.uio_segflg = UIO_USERSPACE; 218748026Smckusick auio.uio_procp = p; 218837741Smckusick auio.uio_resid = uap->count; 218939592Smckusick VOP_LOCK(vp); 219054969Smckusick loff = auio.uio_offset = fp->f_offset; 219167362Smckusick error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, (u_long *)0, 0); 219239592Smckusick fp->f_offset = auio.uio_offset; 219339592Smckusick VOP_UNLOCK(vp); 219439592Smckusick if (error) 219547540Skarels return (error); 219666095Spendry 219766095Spendry #ifdef UNION 219866095Spendry { 219966095Spendry extern int (**union_vnodeop_p)(); 2200*68079Spendry extern struct vnode *union_dircache __P((struct vnode *)); 220166095Spendry 220255451Spendry if ((uap->count == auio.uio_resid) && 220366095Spendry (vp->v_op == union_vnodeop_p)) { 220467122Spendry struct vnode *lvp; 220566095Spendry 2206*68079Spendry lvp = union_dircache(vp); 220767122Spendry if (lvp != NULLVP) { 220867575Spendry struct vattr va; 220967575Spendry 221067575Spendry /* 221167575Spendry * If the directory is opaque, 221267575Spendry * then don't show lower entries 221367575Spendry */ 221467575Spendry error = VOP_GETATTR(vp, &va, fp->f_cred, p); 221567575Spendry if (va.va_flags & OPAQUE) { 2216*68079Spendry vput(lvp); 221767575Spendry lvp = NULL; 221867575Spendry } 221967575Spendry } 222067575Spendry 222167575Spendry if (lvp != NULLVP) { 222267362Smckusick error = VOP_OPEN(lvp, FREAD, fp->f_cred, p); 222367122Spendry VOP_UNLOCK(lvp); 222466095Spendry 222566095Spendry if (error) { 222667122Spendry vrele(lvp); 222766095Spendry return (error); 222866095Spendry } 222967122Spendry fp->f_data = (caddr_t) lvp; 223066095Spendry fp->f_offset = 0; 223167122Spendry error = vn_close(vp, FREAD, fp->f_cred, p); 223266095Spendry if (error) 223366095Spendry return (error); 223467122Spendry vp = lvp; 223566095Spendry goto unionread; 223666095Spendry } 223766095Spendry } 223866095Spendry } 223966095Spendry #endif 224066095Spendry 224166095Spendry if ((uap->count == auio.uio_resid) && 224255451Spendry (vp->v_flag & VROOT) && 224355451Spendry (vp->v_mount->mnt_flag & MNT_UNION)) { 224455451Spendry struct vnode *tvp = vp; 224555451Spendry vp = vp->v_mount->mnt_vnodecovered; 224655451Spendry VREF(vp); 224755451Spendry fp->f_data = (caddr_t) vp; 224855451Spendry fp->f_offset = 0; 224955451Spendry vrele(tvp); 225055451Spendry goto unionread; 225155451Spendry } 225254969Smckusick error = copyout((caddr_t)&loff, (caddr_t)uap->basep, sizeof(long)); 225342441Smckusick *retval = uap->count - auio.uio_resid; 225447540Skarels return (error); 225512756Ssam } 225612756Ssam 225712756Ssam /* 225849365Smckusick * Set the mode mask for creation of filesystem nodes. 225912756Ssam */ 226054916Storek struct umask_args { 226164410Sbostic int newmask; 226254916Storek }; 226354916Storek mode_t /* XXX */ 226442441Smckusick umask(p, uap, retval) 226545914Smckusick struct proc *p; 226654916Storek struct umask_args *uap; 226742441Smckusick int *retval; 226812756Ssam { 226964410Sbostic register struct filedesc *fdp; 227012756Ssam 227164410Sbostic fdp = p->p_fd; 227245914Smckusick *retval = fdp->fd_cmask; 227364410Sbostic fdp->fd_cmask = uap->newmask & ALLPERMS; 227447540Skarels return (0); 227512756Ssam } 227637741Smckusick 227739566Smarc /* 227839566Smarc * Void all references to file by ripping underlying filesystem 227939566Smarc * away from vnode. 228039566Smarc */ 228154916Storek struct revoke_args { 228264410Sbostic char *path; 228354916Storek }; 228442441Smckusick /* ARGSUSED */ 228542441Smckusick revoke(p, uap, retval) 228645914Smckusick struct proc *p; 228754916Storek register struct revoke_args *uap; 228842441Smckusick int *retval; 228942441Smckusick { 229039566Smarc register struct vnode *vp; 229139566Smarc struct vattr vattr; 229239566Smarc int error; 229347540Skarels struct nameidata nd; 229439566Smarc 229564410Sbostic NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); 229652322Smckusick if (error = namei(&nd)) 229747540Skarels return (error); 229852322Smckusick vp = nd.ni_vp; 229939566Smarc if (vp->v_type != VCHR && vp->v_type != VBLK) { 230039566Smarc error = EINVAL; 230139566Smarc goto out; 230239566Smarc } 230348026Smckusick if (error = VOP_GETATTR(vp, &vattr, p->p_ucred, p)) 230439566Smarc goto out; 230547540Skarels if (p->p_ucred->cr_uid != vattr.va_uid && 230647540Skarels (error = suser(p->p_ucred, &p->p_acflag))) 230739566Smarc goto out; 230839805Smckusick if (vp->v_usecount > 1 || (vp->v_flag & VALIASED)) 230939632Smckusick vgoneall(vp); 231039566Smarc out: 231139566Smarc vrele(vp); 231247540Skarels return (error); 231339566Smarc } 231439566Smarc 231549365Smckusick /* 231649365Smckusick * Convert a user file descriptor to a kernel file entry. 231749365Smckusick */ 231864410Sbostic getvnode(fdp, fd, fpp) 231945914Smckusick struct filedesc *fdp; 232037741Smckusick struct file **fpp; 232164410Sbostic int fd; 232237741Smckusick { 232337741Smckusick struct file *fp; 232437741Smckusick 232564410Sbostic if ((u_int)fd >= fdp->fd_nfiles || 232664410Sbostic (fp = fdp->fd_ofiles[fd]) == NULL) 232737741Smckusick return (EBADF); 232837741Smckusick if (fp->f_type != DTYPE_VNODE) 232937741Smckusick return (EINVAL); 233037741Smckusick *fpp = fp; 233137741Smckusick return (0); 233237741Smckusick } 2333