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*69325Smckusick * @(#)vfs_syscalls.c 8.34 (Berkeley) 05/09/95 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 2968318Scgd #include <sys/syscallargs.h> 3068318Scgd 3153468Smckusick #include <vm/vm.h> 3259875Smckusick #include <sys/sysctl.h> 3337Sbill 3464410Sbostic static int change_dir __P((struct nameidata *ndp, struct proc *p)); 3568318Scgd static void checkdirs __P((struct vnode *olddp)); 3664410Sbostic 3737741Smckusick /* 3837741Smckusick * Virtual File System System Calls 3937741Smckusick */ 4012756Ssam 419167Ssam /* 4264410Sbostic * Mount a file system. 439167Ssam */ 4442441Smckusick /* ARGSUSED */ 4568318Scgd int 4642441Smckusick mount(p, uap, retval) 4745914Smckusick struct proc *p; 4868318Scgd register struct mount_args /* { 4968663Smckusick syscallarg(char *) type; 5068318Scgd syscallarg(char *) path; 5168318Scgd syscallarg(int) flags; 5268318Scgd syscallarg(caddr_t) data; 5368318Scgd } */ *uap; 5468318Scgd register_t *retval; 5542441Smckusick { 5668663Smckusick struct vnode *vp; 5768663Smckusick struct mount *mp; 5868663Smckusick struct vfsconf *vfsp; 5940111Smckusick int error, flag; 6067532Smckusick struct vattr va; 6168663Smckusick u_long fstypenum; 6247540Skarels struct nameidata nd; 6368663Smckusick char fstypename[MFSNAMELEN]; 646254Sroot 6537741Smckusick /* 6637741Smckusick * Get vnode to be covered 6737741Smckusick */ 6868318Scgd NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, 6968318Scgd SCARG(uap, path), p); 7052322Smckusick if (error = namei(&nd)) 7147540Skarels return (error); 7252322Smckusick vp = nd.ni_vp; 7368318Scgd if (SCARG(uap, flags) & MNT_UPDATE) { 7439335Smckusick if ((vp->v_flag & VROOT) == 0) { 7539335Smckusick vput(vp); 7647540Skarels return (EINVAL); 7739335Smckusick } 7839335Smckusick mp = vp->v_mount; 7957047Smckusick flag = mp->mnt_flag; 8039335Smckusick /* 8157047Smckusick * We only allow the filesystem to be reloaded if it 8257047Smckusick * is currently mounted read-only. 8339335Smckusick */ 8468318Scgd if ((SCARG(uap, flags) & MNT_RELOAD) && 8557047Smckusick ((mp->mnt_flag & MNT_RDONLY) == 0)) { 8639335Smckusick vput(vp); 8747540Skarels return (EOPNOTSUPP); /* Needs translation */ 8839335Smckusick } 8957047Smckusick mp->mnt_flag |= 9068318Scgd SCARG(uap, flags) & (MNT_RELOAD | MNT_FORCE | MNT_UPDATE); 9167532Smckusick /* 9267532Smckusick * Only root, or the user that did the original mount is 9367532Smckusick * permitted to update it. 9467532Smckusick */ 9567532Smckusick if (mp->mnt_stat.f_owner != p->p_ucred->cr_uid && 9667532Smckusick (error = suser(p->p_ucred, &p->p_acflag))) { 9767532Smckusick vput(vp); 9867532Smckusick return (error); 9967532Smckusick } 10067532Smckusick /* 10167532Smckusick * Do not allow NFS export by non-root users. Silently 10267532Smckusick * enforce MNT_NOSUID and MNT_NODEV for non-root users. 10367532Smckusick */ 10467532Smckusick if (p->p_ucred->cr_uid != 0) { 10568318Scgd if (SCARG(uap, flags) & MNT_EXPORTED) { 10667532Smckusick vput(vp); 10767532Smckusick return (EPERM); 10867532Smckusick } 10968318Scgd SCARG(uap, flags) |= MNT_NOSUID | MNT_NODEV; 11067532Smckusick } 11139335Smckusick VOP_UNLOCK(vp); 11239335Smckusick goto update; 11339335Smckusick } 11467532Smckusick /* 11567532Smckusick * If the user is not root, ensure that they own the directory 11667532Smckusick * onto which we are attempting to mount. 11767532Smckusick */ 11867532Smckusick if ((error = VOP_GETATTR(vp, &va, p->p_ucred, p)) || 11967532Smckusick (va.va_uid != p->p_ucred->cr_uid && 12067532Smckusick (error = suser(p->p_ucred, &p->p_acflag)))) { 12167532Smckusick vput(vp); 12267532Smckusick return (error); 12367532Smckusick } 12467532Smckusick /* 12567532Smckusick * Do not allow NFS export by non-root users. Silently 12667532Smckusick * enforce MNT_NOSUID and MNT_NODEV for non-root users. 12767532Smckusick */ 12867532Smckusick if (p->p_ucred->cr_uid != 0) { 12968318Scgd if (SCARG(uap, flags) & MNT_EXPORTED) { 13067532Smckusick vput(vp); 13167532Smckusick return (EPERM); 13267532Smckusick } 13368318Scgd SCARG(uap, flags) |= MNT_NOSUID | MNT_NODEV; 13467532Smckusick } 13557793Smckusick if (error = vinvalbuf(vp, V_SAVE, p->p_ucred, p, 0, 0)) 13654441Smckusick return (error); 13737741Smckusick if (vp->v_type != VDIR) { 13837741Smckusick vput(vp); 13947540Skarels return (ENOTDIR); 14037741Smckusick } 14168663Smckusick #ifdef COMPAT_43 14268663Smckusick /* 14368663Smckusick * Historically filesystem types were identified by number. If we 14468663Smckusick * get an integer for the filesystem type instead of a string, we 14568663Smckusick * check to see if it matches one of the historic filesystem types. 14668663Smckusick */ 14768663Smckusick fstypenum = (u_long)SCARG(uap, type); 14868663Smckusick if (fstypenum < maxvfsconf) { 14968663Smckusick for (vfsp = vfsconf; vfsp; vfsp = vfsp->vfc_next) 15068663Smckusick if (vfsp->vfc_typenum == fstypenum) 15168663Smckusick break; 15268663Smckusick if (vfsp == NULL) { 15368663Smckusick vput(vp); 15468663Smckusick return (ENODEV); 15568663Smckusick } 15668663Smckusick strncpy(fstypename, vfsp->vfc_name, MFSNAMELEN); 15768663Smckusick } else 15868663Smckusick #endif /* COMPAT_43 */ 15968663Smckusick if (error = copyinstr(SCARG(uap, type), fstypename, MFSNAMELEN, NULL)) { 16037741Smckusick vput(vp); 16168663Smckusick return (error); 16268663Smckusick } 16368663Smckusick for (vfsp = vfsconf; vfsp; vfsp = vfsp->vfc_next) 16468663Smckusick if (!strcmp(vfsp->vfc_name, fstypename)) 16568663Smckusick break; 16668663Smckusick if (vfsp == NULL) { 16768663Smckusick vput(vp); 16847540Skarels return (ENODEV); 16937741Smckusick } 17067969Spendry if (vp->v_mountedhere != NULL) { 17167961Smckusick vput(vp); 17267961Smckusick return (EBUSY); 17367961Smckusick } 17437741Smckusick 17537741Smckusick /* 17668663Smckusick * Allocate and initialize the filesystem. 17737741Smckusick */ 17837741Smckusick mp = (struct mount *)malloc((u_long)sizeof(struct mount), 17937741Smckusick M_MOUNT, M_WAITOK); 18054172Smckusick bzero((char *)mp, (u_long)sizeof(struct mount)); 18168663Smckusick mp->mnt_op = vfsp->vfc_vfsops; 18239335Smckusick if (error = vfs_lock(mp)) { 18339335Smckusick free((caddr_t)mp, M_MOUNT); 18439335Smckusick vput(vp); 18547540Skarels return (error); 18639335Smckusick } 18768663Smckusick mp->mnt_vfc = vfsp; 18868663Smckusick vfsp->vfc_refcount++; 18968663Smckusick mp->mnt_stat.f_type = vfsp->vfc_typenum; 19068663Smckusick mp->mnt_flag |= vfsp->vfc_flags & MNT_VISFLAGMASK; 19168663Smckusick strncpy(mp->mnt_stat.f_fstypename, vfsp->vfc_name, MFSNAMELEN); 19239335Smckusick vp->v_mountedhere = mp; 19341400Smckusick mp->mnt_vnodecovered = vp; 19467532Smckusick mp->mnt_stat.f_owner = p->p_ucred->cr_uid; 19539335Smckusick update: 19639335Smckusick /* 19739335Smckusick * Set the mount level flags. 19839335Smckusick */ 19968318Scgd if (SCARG(uap, flags) & MNT_RDONLY) 20041400Smckusick mp->mnt_flag |= MNT_RDONLY; 20157047Smckusick else if (mp->mnt_flag & MNT_RDONLY) 20257047Smckusick mp->mnt_flag |= MNT_WANTRDWR; 20365613Smckusick mp->mnt_flag &=~ (MNT_NOSUID | MNT_NOEXEC | MNT_NODEV | 20465613Smckusick MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC); 20568318Scgd mp->mnt_flag |= SCARG(uap, flags) & (MNT_NOSUID | MNT_NOEXEC | 20668318Scgd MNT_NODEV | MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC); 20739335Smckusick /* 20839335Smckusick * Mount the filesystem. 20939335Smckusick */ 21068318Scgd error = VFS_MOUNT(mp, SCARG(uap, path), SCARG(uap, data), &nd, p); 21141400Smckusick if (mp->mnt_flag & MNT_UPDATE) { 21239335Smckusick vrele(vp); 21357047Smckusick if (mp->mnt_flag & MNT_WANTRDWR) 21457047Smckusick mp->mnt_flag &= ~MNT_RDONLY; 21557047Smckusick mp->mnt_flag &=~ 21657047Smckusick (MNT_UPDATE | MNT_RELOAD | MNT_FORCE | MNT_WANTRDWR); 21740111Smckusick if (error) 21841400Smckusick mp->mnt_flag = flag; 21947540Skarels return (error); 22039335Smckusick } 22140110Smckusick /* 22240110Smckusick * Put the new filesystem on the mount list after root. 22340110Smckusick */ 22437741Smckusick cache_purge(vp); 22537741Smckusick if (!error) { 226*69325Smckusick CIRCLEQ_INSERT_TAIL(&mountlist, mp, mnt_list); 22767974Smckusick checkdirs(vp); 22839335Smckusick VOP_UNLOCK(vp); 22937741Smckusick vfs_unlock(mp); 23048026Smckusick error = VFS_START(mp, 0, p); 23137741Smckusick } else { 23265259Smckusick mp->mnt_vnodecovered->v_mountedhere = (struct mount *)0; 23368663Smckusick mp->mnt_vfc->vfc_refcount--; 23465259Smckusick vfs_unlock(mp); 23537741Smckusick free((caddr_t)mp, M_MOUNT); 23639335Smckusick vput(vp); 23737741Smckusick } 23847540Skarels return (error); 2396254Sroot } 2406254Sroot 2419167Ssam /* 24267974Smckusick * Scan all active processes to see if any of them have a current 24367974Smckusick * or root directory onto which the new filesystem has just been 24467974Smckusick * mounted. If so, replace them with the new mount point. 24567974Smckusick */ 24668318Scgd static void 24767974Smckusick checkdirs(olddp) 24867974Smckusick struct vnode *olddp; 24967974Smckusick { 25067974Smckusick struct filedesc *fdp; 25167974Smckusick struct vnode *newdp; 25267974Smckusick struct proc *p; 25367974Smckusick 25467974Smckusick if (olddp->v_usecount == 1) 25567974Smckusick return; 25667974Smckusick if (VFS_ROOT(olddp->v_mountedhere, &newdp)) 25767974Smckusick panic("mount: lost mount"); 25867974Smckusick for (p = allproc.lh_first; p != 0; p = p->p_list.le_next) { 25967974Smckusick fdp = p->p_fd; 26067974Smckusick if (fdp->fd_cdir == olddp) { 26167974Smckusick vrele(fdp->fd_cdir); 26267974Smckusick VREF(newdp); 26367974Smckusick fdp->fd_cdir = newdp; 26467974Smckusick } 26567974Smckusick if (fdp->fd_rdir == olddp) { 26667974Smckusick vrele(fdp->fd_rdir); 26767974Smckusick VREF(newdp); 26867974Smckusick fdp->fd_rdir = newdp; 26967974Smckusick } 27067974Smckusick } 27167974Smckusick if (rootvnode == olddp) { 27267974Smckusick vrele(rootvnode); 27367974Smckusick VREF(newdp); 27467974Smckusick rootvnode = newdp; 27567974Smckusick } 27667974Smckusick vput(newdp); 27767974Smckusick } 27867974Smckusick 27967974Smckusick /* 28064410Sbostic * Unmount a file system. 28137741Smckusick * 28237741Smckusick * Note: unmount takes a path to the vnode mounted on as argument, 28337741Smckusick * not special file (as before). 2849167Ssam */ 28542441Smckusick /* ARGSUSED */ 28668318Scgd int 28742441Smckusick unmount(p, uap, retval) 28845914Smckusick struct proc *p; 28968318Scgd register struct unmount_args /* { 29068318Scgd syscallarg(char *) path; 29168318Scgd syscallarg(int) flags; 29268318Scgd } */ *uap; 29368318Scgd register_t *retval; 29442441Smckusick { 29537741Smckusick register struct vnode *vp; 29639356Smckusick struct mount *mp; 29737741Smckusick int error; 29847540Skarels struct nameidata nd; 2996254Sroot 30068318Scgd NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, 30168318Scgd SCARG(uap, path), p); 30252322Smckusick if (error = namei(&nd)) 30347540Skarels return (error); 30452322Smckusick vp = nd.ni_vp; 30567532Smckusick mp = vp->v_mount; 30666172Spendry 30737741Smckusick /* 30867532Smckusick * Only root, or the user that did the original mount is 30967532Smckusick * permitted to unmount this filesystem. 31066172Spendry */ 31167532Smckusick if ((mp->mnt_stat.f_owner != p->p_ucred->cr_uid) && 31266172Spendry (error = suser(p->p_ucred, &p->p_acflag))) { 31366172Spendry vput(vp); 31466172Spendry return (error); 31566172Spendry } 31666172Spendry 31766172Spendry /* 31837741Smckusick * Must be the root of the filesystem 31937741Smckusick */ 32037741Smckusick if ((vp->v_flag & VROOT) == 0) { 32137741Smckusick vput(vp); 32247540Skarels return (EINVAL); 32337741Smckusick } 32437741Smckusick vput(vp); 32568318Scgd return (dounmount(mp, SCARG(uap, flags), p)); 32639356Smckusick } 32739356Smckusick 32839356Smckusick /* 32964410Sbostic * Do the actual file system unmount. 33039356Smckusick */ 33168318Scgd int 33248026Smckusick dounmount(mp, flags, p) 33339356Smckusick register struct mount *mp; 33439356Smckusick int flags; 33548026Smckusick struct proc *p; 33639356Smckusick { 33739356Smckusick struct vnode *coveredvp; 33839356Smckusick int error; 33939356Smckusick 34041400Smckusick coveredvp = mp->mnt_vnodecovered; 34141298Smckusick if (vfs_busy(mp)) 34241298Smckusick return (EBUSY); 34341400Smckusick mp->mnt_flag |= MNT_UNMOUNT; 34437741Smckusick if (error = vfs_lock(mp)) 34539356Smckusick return (error); 34637741Smckusick 34765859Smckusick mp->mnt_flag &=~ MNT_ASYNC; 34845738Smckusick vnode_pager_umount(mp); /* release cached vnodes */ 34937741Smckusick cache_purgevfs(mp); /* remove cache entries for this file sys */ 35054441Smckusick if ((error = VFS_SYNC(mp, MNT_WAIT, p->p_ucred, p)) == 0 || 35154441Smckusick (flags & MNT_FORCE)) 35248026Smckusick error = VFS_UNMOUNT(mp, flags, p); 35341400Smckusick mp->mnt_flag &= ~MNT_UNMOUNT; 35441298Smckusick vfs_unbusy(mp); 35537741Smckusick if (error) { 35637741Smckusick vfs_unlock(mp); 35737741Smckusick } else { 358*69325Smckusick CIRCLEQ_REMOVE(&mountlist, mp, mnt_list); 359*69325Smckusick if (coveredvp != NULLVP) { 360*69325Smckusick vrele(coveredvp); 361*69325Smckusick mp->mnt_vnodecovered->v_mountedhere = (struct mount *)0; 362*69325Smckusick } 36368663Smckusick mp->mnt_vfc->vfc_refcount--; 36465259Smckusick vfs_unlock(mp); 36565259Smckusick if (mp->mnt_vnodelist.lh_first != NULL) 36652287Smckusick panic("unmount: dangling vnode"); 36737741Smckusick free((caddr_t)mp, M_MOUNT); 36837741Smckusick } 36939356Smckusick return (error); 3706254Sroot } 3716254Sroot 3729167Ssam /* 37337741Smckusick * Sync each mounted filesystem. 3749167Ssam */ 37567403Smckusick #ifdef DEBUG 37656352Smckusick int syncprt = 0; 37759875Smckusick struct ctldebug debug0 = { "syncprt", &syncprt }; 37856352Smckusick #endif 37956352Smckusick 38039491Smckusick /* ARGSUSED */ 38168318Scgd int 38242441Smckusick sync(p, uap, retval) 38345914Smckusick struct proc *p; 38468318Scgd void *uap; 38568318Scgd register_t *retval; 3866254Sroot { 38765259Smckusick register struct mount *mp, *nmp; 38865859Smckusick int asyncflag; 38937741Smckusick 390*69325Smckusick for (mp = mountlist.cqh_first; mp != (void *)&mountlist; mp = nmp) { 39167678Smckusick /* 39267678Smckusick * Get the next pointer in case we hang on vfs_busy 39367678Smckusick * while we are being unmounted. 39467678Smckusick */ 395*69325Smckusick nmp = mp->mnt_list.cqe_next; 39640343Smckusick /* 39740343Smckusick * The lock check below is to avoid races with mount 39840343Smckusick * and unmount. 39940343Smckusick */ 40041400Smckusick if ((mp->mnt_flag & (MNT_MLOCK|MNT_RDONLY|MNT_MPBUSY)) == 0 && 40141298Smckusick !vfs_busy(mp)) { 40265859Smckusick asyncflag = mp->mnt_flag & MNT_ASYNC; 40365859Smckusick mp->mnt_flag &= ~MNT_ASYNC; 40454441Smckusick VFS_SYNC(mp, MNT_NOWAIT, p->p_ucred, p); 40565859Smckusick if (asyncflag) 40665859Smckusick mp->mnt_flag |= MNT_ASYNC; 40767678Smckusick /* 40867678Smckusick * Get the next pointer again, as the next filesystem 40967678Smckusick * might have been unmounted while we were sync'ing. 41067678Smckusick */ 411*69325Smckusick nmp = mp->mnt_list.cqe_next; 41265259Smckusick vfs_unbusy(mp); 41365259Smckusick } 41465259Smckusick } 41556352Smckusick #ifdef DIAGNOSTIC 41656352Smckusick if (syncprt) 41756352Smckusick vfs_bufstats(); 41856352Smckusick #endif /* DIAGNOSTIC */ 41947688Skarels return (0); 42037741Smckusick } 42137741Smckusick 42237741Smckusick /* 42364410Sbostic * Change filesystem quotas. 42441298Smckusick */ 42542441Smckusick /* ARGSUSED */ 42668318Scgd int 42742441Smckusick quotactl(p, uap, retval) 42845914Smckusick struct proc *p; 42968318Scgd register struct quotactl_args /* { 43068318Scgd syscallarg(char *) path; 43168318Scgd syscallarg(int) cmd; 43268318Scgd syscallarg(int) uid; 43368318Scgd syscallarg(caddr_t) arg; 43468318Scgd } */ *uap; 43568318Scgd register_t *retval; 43642441Smckusick { 43741298Smckusick register struct mount *mp; 43841298Smckusick int error; 43947540Skarels struct nameidata nd; 44041298Smckusick 44168318Scgd NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 44252322Smckusick if (error = namei(&nd)) 44347540Skarels return (error); 44452322Smckusick mp = nd.ni_vp->v_mount; 44552322Smckusick vrele(nd.ni_vp); 44668318Scgd return (VFS_QUOTACTL(mp, SCARG(uap, cmd), SCARG(uap, uid), 44768318Scgd SCARG(uap, arg), p)); 44841298Smckusick } 44941298Smckusick 45041298Smckusick /* 45149365Smckusick * Get filesystem statistics. 45237741Smckusick */ 45342441Smckusick /* ARGSUSED */ 45468318Scgd int 45542441Smckusick statfs(p, uap, retval) 45645914Smckusick struct proc *p; 45768318Scgd register struct statfs_args /* { 45868318Scgd syscallarg(char *) path; 45968318Scgd syscallarg(struct statfs *) buf; 46068318Scgd } */ *uap; 46168318Scgd register_t *retval; 46242441Smckusick { 46339464Smckusick register struct mount *mp; 46440343Smckusick register struct statfs *sp; 46537741Smckusick int error; 46647540Skarels struct nameidata nd; 46737741Smckusick 46868318Scgd NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 46952322Smckusick if (error = namei(&nd)) 47047540Skarels return (error); 47152322Smckusick mp = nd.ni_vp->v_mount; 47241400Smckusick sp = &mp->mnt_stat; 47352322Smckusick vrele(nd.ni_vp); 47448026Smckusick if (error = VFS_STATFS(mp, sp, p)) 47547540Skarels return (error); 47641400Smckusick sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 47768318Scgd return (copyout((caddr_t)sp, (caddr_t)SCARG(uap, buf), sizeof(*sp))); 47837741Smckusick } 47937741Smckusick 48042441Smckusick /* 48149365Smckusick * Get filesystem statistics. 48242441Smckusick */ 48342441Smckusick /* ARGSUSED */ 48468318Scgd int 48542441Smckusick fstatfs(p, uap, retval) 48645914Smckusick struct proc *p; 48768318Scgd register struct fstatfs_args /* { 48868318Scgd syscallarg(int) fd; 48968318Scgd syscallarg(struct statfs *) buf; 49068318Scgd } */ *uap; 49168318Scgd register_t *retval; 49242441Smckusick { 49337741Smckusick struct file *fp; 49439464Smckusick struct mount *mp; 49540343Smckusick register struct statfs *sp; 49637741Smckusick int error; 49737741Smckusick 49868318Scgd if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) 49947540Skarels return (error); 50039464Smckusick mp = ((struct vnode *)fp->f_data)->v_mount; 50141400Smckusick sp = &mp->mnt_stat; 50248026Smckusick if (error = VFS_STATFS(mp, sp, p)) 50347540Skarels return (error); 50441400Smckusick sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 50568318Scgd return (copyout((caddr_t)sp, (caddr_t)SCARG(uap, buf), sizeof(*sp))); 50637741Smckusick } 50737741Smckusick 50837741Smckusick /* 50949365Smckusick * Get statistics on all filesystems. 51038270Smckusick */ 51168318Scgd int 51242441Smckusick getfsstat(p, uap, retval) 51345914Smckusick struct proc *p; 51468318Scgd register struct getfsstat_args /* { 51568318Scgd syscallarg(struct statfs *) buf; 51668318Scgd syscallarg(long) bufsize; 51768318Scgd syscallarg(int) flags; 51868318Scgd } */ *uap; 51968318Scgd register_t *retval; 52042441Smckusick { 52165259Smckusick register struct mount *mp, *nmp; 52240343Smckusick register struct statfs *sp; 52339606Smckusick caddr_t sfsp; 52438270Smckusick long count, maxcount, error; 52538270Smckusick 52668318Scgd maxcount = SCARG(uap, bufsize) / sizeof(struct statfs); 52768318Scgd sfsp = (caddr_t)SCARG(uap, buf); 528*69325Smckusick count = 0; 529*69325Smckusick for (mp = mountlist.cqh_first; mp != (void *)&mountlist; mp = nmp) { 530*69325Smckusick nmp = mp->mnt_list.cqe_next; 53141400Smckusick if (sfsp && count < maxcount && 53241400Smckusick ((mp->mnt_flag & MNT_MLOCK) == 0)) { 53341400Smckusick sp = &mp->mnt_stat; 53440343Smckusick /* 53540343Smckusick * If MNT_NOWAIT is specified, do not refresh the 53640343Smckusick * fsstat cache. MNT_WAIT overrides MNT_NOWAIT. 53740343Smckusick */ 53868318Scgd if (((SCARG(uap, flags) & MNT_NOWAIT) == 0 || 53968318Scgd (SCARG(uap, flags) & MNT_WAIT)) && 54065259Smckusick (error = VFS_STATFS(mp, sp, p))) 54139607Smckusick continue; 54241400Smckusick sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 54340343Smckusick if (error = copyout((caddr_t)sp, sfsp, sizeof(*sp))) 54447540Skarels return (error); 54540343Smckusick sfsp += sizeof(*sp); 54638270Smckusick } 54739606Smckusick count++; 54865259Smckusick } 54938270Smckusick if (sfsp && count > maxcount) 55042441Smckusick *retval = maxcount; 55138270Smckusick else 55242441Smckusick *retval = count; 55347540Skarels return (0); 55438270Smckusick } 55538270Smckusick 55638270Smckusick /* 55738259Smckusick * Change current working directory to a given file descriptor. 55838259Smckusick */ 55942441Smckusick /* ARGSUSED */ 56068318Scgd int 56142441Smckusick fchdir(p, uap, retval) 56245914Smckusick struct proc *p; 56368318Scgd struct fchdir_args /* { 56468318Scgd syscallarg(int) fd; 56568318Scgd } */ *uap; 56668318Scgd register_t *retval; 56738259Smckusick { 56845914Smckusick register struct filedesc *fdp = p->p_fd; 56967974Smckusick struct vnode *vp, *tdp; 57067974Smckusick struct mount *mp; 57138259Smckusick struct file *fp; 57238259Smckusick int error; 57338259Smckusick 57468318Scgd if (error = getvnode(fdp, SCARG(uap, fd), &fp)) 57547540Skarels return (error); 57638259Smckusick vp = (struct vnode *)fp->f_data; 57767974Smckusick VREF(vp); 57838259Smckusick VOP_LOCK(vp); 57938259Smckusick if (vp->v_type != VDIR) 58038259Smckusick error = ENOTDIR; 58138259Smckusick else 58248026Smckusick error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p); 58367974Smckusick while (!error && (mp = vp->v_mountedhere) != NULL) { 58467974Smckusick if (mp->mnt_flag & MNT_MLOCK) { 58567974Smckusick mp->mnt_flag |= MNT_MWAIT; 58667974Smckusick sleep((caddr_t)mp, PVFS); 58767974Smckusick continue; 58867974Smckusick } 58967974Smckusick if (error = VFS_ROOT(mp, &tdp)) 59067974Smckusick break; 59167974Smckusick vput(vp); 59267974Smckusick vp = tdp; 59367974Smckusick } 59438259Smckusick VOP_UNLOCK(vp); 59567974Smckusick if (error) { 59667974Smckusick vrele(vp); 59747540Skarels return (error); 59867974Smckusick } 59945914Smckusick vrele(fdp->fd_cdir); 60045914Smckusick fdp->fd_cdir = vp; 60147540Skarels return (0); 60238259Smckusick } 60338259Smckusick 60438259Smckusick /* 60537741Smckusick * Change current working directory (``.''). 60637741Smckusick */ 60742441Smckusick /* ARGSUSED */ 60868318Scgd int 60942441Smckusick chdir(p, uap, retval) 61045914Smckusick struct proc *p; 61168318Scgd struct chdir_args /* { 61268318Scgd syscallarg(char *) path; 61368318Scgd } */ *uap; 61468318Scgd register_t *retval; 61537741Smckusick { 61645914Smckusick register struct filedesc *fdp = p->p_fd; 61737741Smckusick int error; 61847540Skarels struct nameidata nd; 6196254Sroot 62068318Scgd NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, 62168318Scgd SCARG(uap, path), p); 62264410Sbostic if (error = change_dir(&nd, p)) 62347540Skarels return (error); 62445914Smckusick vrele(fdp->fd_cdir); 62552322Smckusick fdp->fd_cdir = nd.ni_vp; 62647540Skarels return (0); 62737741Smckusick } 6286254Sroot 62937741Smckusick /* 63037741Smckusick * Change notion of root (``/'') directory. 63137741Smckusick */ 63242441Smckusick /* ARGSUSED */ 63368318Scgd int 63442441Smckusick chroot(p, uap, retval) 63545914Smckusick struct proc *p; 63668318Scgd struct chroot_args /* { 63768318Scgd syscallarg(char *) path; 63868318Scgd } */ *uap; 63968318Scgd register_t *retval; 64037741Smckusick { 64145914Smckusick register struct filedesc *fdp = p->p_fd; 64237741Smckusick int error; 64347540Skarels struct nameidata nd; 64437741Smckusick 64547540Skarels if (error = suser(p->p_ucred, &p->p_acflag)) 64647540Skarels return (error); 64768318Scgd NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, 64868318Scgd SCARG(uap, path), p); 64964410Sbostic if (error = change_dir(&nd, p)) 65047540Skarels return (error); 65145914Smckusick if (fdp->fd_rdir != NULL) 65245914Smckusick vrele(fdp->fd_rdir); 65352322Smckusick fdp->fd_rdir = nd.ni_vp; 65447540Skarels return (0); 6556254Sroot } 6566254Sroot 65737Sbill /* 65837741Smckusick * Common routine for chroot and chdir. 65937741Smckusick */ 66064410Sbostic static int 66164410Sbostic change_dir(ndp, p) 66252322Smckusick register struct nameidata *ndp; 66347540Skarels struct proc *p; 66437741Smckusick { 66537741Smckusick struct vnode *vp; 66637741Smckusick int error; 66737741Smckusick 66852322Smckusick if (error = namei(ndp)) 66937741Smckusick return (error); 67037741Smckusick vp = ndp->ni_vp; 67137741Smckusick if (vp->v_type != VDIR) 67237741Smckusick error = ENOTDIR; 67337741Smckusick else 67448026Smckusick error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p); 67537741Smckusick VOP_UNLOCK(vp); 67637741Smckusick if (error) 67737741Smckusick vrele(vp); 67837741Smckusick return (error); 67937741Smckusick } 68037741Smckusick 68137741Smckusick /* 68242441Smckusick * Check permissions, allocate an open file structure, 68342441Smckusick * and call the device open routine if any. 6846254Sroot */ 68568318Scgd int 68642441Smckusick open(p, uap, retval) 68745914Smckusick struct proc *p; 68868318Scgd register struct open_args /* { 68968318Scgd syscallarg(char *) path; 69068318Scgd syscallarg(int) flags; 69168318Scgd syscallarg(int) mode; 69268318Scgd } */ *uap; 69368318Scgd register_t *retval; 6946254Sroot { 69545914Smckusick register struct filedesc *fdp = p->p_fd; 69642441Smckusick register struct file *fp; 69750111Smckusick register struct vnode *vp; 69864410Sbostic int flags, cmode; 69937741Smckusick struct file *nfp; 70049945Smckusick int type, indx, error; 70149945Smckusick struct flock lf; 70247540Skarels struct nameidata nd; 70337741Smckusick extern struct fileops vnops; 7046254Sroot 70545914Smckusick if (error = falloc(p, &nfp, &indx)) 70647540Skarels return (error); 70737741Smckusick fp = nfp; 70868318Scgd flags = FFLAGS(SCARG(uap, flags)); 70968318Scgd cmode = ((SCARG(uap, mode) &~ fdp->fd_cmask) & ALLPERMS) &~ S_ISTXT; 71068318Scgd NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 71145202Smckusick p->p_dupfd = -indx - 1; /* XXX check for fdopen */ 71264410Sbostic if (error = vn_open(&nd, flags, cmode)) { 71349980Smckusick ffree(fp); 71454723Smckusick if ((error == ENODEV || error == ENXIO) && 71568318Scgd p->p_dupfd >= 0 && /* XXX from fdopen */ 71664410Sbostic (error = 71768318Scgd dupfdopen(fdp, indx, p->p_dupfd, flags, error)) == 0) { 71842441Smckusick *retval = indx; 71947540Skarels return (0); 72042441Smckusick } 72140884Smckusick if (error == ERESTART) 72240884Smckusick error = EINTR; 72347688Skarels fdp->fd_ofiles[indx] = NULL; 72447540Skarels return (error); 72512756Ssam } 72653828Spendry p->p_dupfd = 0; 72752322Smckusick vp = nd.ni_vp; 72864410Sbostic fp->f_flag = flags & FMASK; 72954348Smckusick fp->f_type = DTYPE_VNODE; 73054348Smckusick fp->f_ops = &vnops; 73154348Smckusick fp->f_data = (caddr_t)vp; 73264410Sbostic if (flags & (O_EXLOCK | O_SHLOCK)) { 73349945Smckusick lf.l_whence = SEEK_SET; 73449945Smckusick lf.l_start = 0; 73549945Smckusick lf.l_len = 0; 73664410Sbostic if (flags & O_EXLOCK) 73749945Smckusick lf.l_type = F_WRLCK; 73849945Smckusick else 73949945Smckusick lf.l_type = F_RDLCK; 74049945Smckusick type = F_FLOCK; 74164410Sbostic if ((flags & FNONBLOCK) == 0) 74249945Smckusick type |= F_WAIT; 74365757Smckusick VOP_UNLOCK(vp); 74450111Smckusick if (error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, type)) { 74550111Smckusick (void) vn_close(vp, fp->f_flag, fp->f_cred, p); 74649980Smckusick ffree(fp); 74749945Smckusick fdp->fd_ofiles[indx] = NULL; 74849945Smckusick return (error); 74949945Smckusick } 75065757Smckusick VOP_LOCK(vp); 75149949Smckusick fp->f_flag |= FHASLOCK; 75249945Smckusick } 75350111Smckusick VOP_UNLOCK(vp); 75442441Smckusick *retval = indx; 75547540Skarels return (0); 7566254Sroot } 7576254Sroot 75842955Smckusick #ifdef COMPAT_43 7596254Sroot /* 76064410Sbostic * Create a file. 7616254Sroot */ 76268318Scgd int 76368318Scgd compat_43_creat(p, uap, retval) 76442441Smckusick struct proc *p; 76568318Scgd register struct compat_43_creat_args /* { 76668318Scgd syscallarg(char *) path; 76768318Scgd syscallarg(int) mode; 76868318Scgd } */ *uap; 76968318Scgd register_t *retval; 7706254Sroot { 77168318Scgd struct open_args /* { 77268318Scgd syscallarg(char *) path; 77368318Scgd syscallarg(int) flags; 77468318Scgd syscallarg(int) mode; 77568318Scgd } */ nuap; 77642441Smckusick 77768318Scgd SCARG(&nuap, path) = SCARG(uap, path); 77868318Scgd SCARG(&nuap, mode) = SCARG(uap, mode); 77968318Scgd SCARG(&nuap, flags) = O_WRONLY | O_CREAT | O_TRUNC; 78068318Scgd return (open(p, &nuap, retval)); 78142441Smckusick } 78242955Smckusick #endif /* COMPAT_43 */ 78342441Smckusick 78442441Smckusick /* 78564410Sbostic * Create a special file. 78642441Smckusick */ 78742441Smckusick /* ARGSUSED */ 78868318Scgd int 78942441Smckusick mknod(p, uap, retval) 79045914Smckusick struct proc *p; 79168318Scgd register struct mknod_args /* { 79268318Scgd syscallarg(char *) path; 79368318Scgd syscallarg(int) mode; 79468318Scgd syscallarg(int) dev; 79568318Scgd } */ *uap; 79668318Scgd register_t *retval; 79742441Smckusick { 79837741Smckusick register struct vnode *vp; 79937741Smckusick struct vattr vattr; 80037741Smckusick int error; 80167575Spendry int whiteout; 80247540Skarels struct nameidata nd; 8036254Sroot 80447540Skarels if (error = suser(p->p_ucred, &p->p_acflag)) 80547540Skarels return (error); 80668318Scgd NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p); 80752322Smckusick if (error = namei(&nd)) 80847540Skarels return (error); 80952322Smckusick vp = nd.ni_vp; 81064585Sbostic if (vp != NULL) 81137741Smckusick error = EEXIST; 81264585Sbostic else { 81364585Sbostic VATTR_NULL(&vattr); 81468318Scgd vattr.va_mode = (SCARG(uap, mode) & ALLPERMS) &~ p->p_fd->fd_cmask; 81568318Scgd vattr.va_rdev = SCARG(uap, dev); 81667575Spendry whiteout = 0; 81764585Sbostic 81868318Scgd switch (SCARG(uap, mode) & S_IFMT) { 81964585Sbostic case S_IFMT: /* used by badsect to flag bad sectors */ 82064585Sbostic vattr.va_type = VBAD; 82164585Sbostic break; 82264585Sbostic case S_IFCHR: 82364585Sbostic vattr.va_type = VCHR; 82464585Sbostic break; 82564585Sbostic case S_IFBLK: 82664585Sbostic vattr.va_type = VBLK; 82764585Sbostic break; 82867575Spendry case S_IFWHT: 82967575Spendry whiteout = 1; 83067575Spendry break; 83164585Sbostic default: 83264585Sbostic error = EINVAL; 83364585Sbostic break; 83464585Sbostic } 8356254Sroot } 83667747Spendry if (!error) { 83767654Smckusick VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 83867747Spendry if (whiteout) { 83967747Spendry error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, CREATE); 84067747Spendry if (error) 84167747Spendry VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 84267747Spendry vput(nd.ni_dvp); 84367747Spendry } else { 84467747Spendry error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, 84567747Spendry &nd.ni_cnd, &vattr); 84667747Spendry } 84742465Smckusick } else { 84852322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 84952322Smckusick if (nd.ni_dvp == vp) 85052322Smckusick vrele(nd.ni_dvp); 85143344Smckusick else 85252322Smckusick vput(nd.ni_dvp); 85342465Smckusick if (vp) 85442465Smckusick vrele(vp); 85542465Smckusick } 85647540Skarels return (error); 8576254Sroot } 8586254Sroot 8596254Sroot /* 86068318Scgd * Create a named pipe. 86140285Smckusick */ 86242441Smckusick /* ARGSUSED */ 86368318Scgd int 86442441Smckusick mkfifo(p, uap, retval) 86545914Smckusick struct proc *p; 86668318Scgd register struct mkfifo_args /* { 86768318Scgd syscallarg(char *) path; 86868318Scgd syscallarg(int) mode; 86968318Scgd } */ *uap; 87068318Scgd register_t *retval; 87142441Smckusick { 87240285Smckusick struct vattr vattr; 87340285Smckusick int error; 87447540Skarels struct nameidata nd; 87540285Smckusick 87640285Smckusick #ifndef FIFO 87747540Skarels return (EOPNOTSUPP); 87840285Smckusick #else 87968318Scgd NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p); 88052322Smckusick if (error = namei(&nd)) 88147540Skarels return (error); 88252322Smckusick if (nd.ni_vp != NULL) { 88352322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 88452322Smckusick if (nd.ni_dvp == nd.ni_vp) 88552322Smckusick vrele(nd.ni_dvp); 88643344Smckusick else 88752322Smckusick vput(nd.ni_dvp); 88852322Smckusick vrele(nd.ni_vp); 88947540Skarels return (EEXIST); 89040285Smckusick } 89145785Sbostic VATTR_NULL(&vattr); 89245785Sbostic vattr.va_type = VFIFO; 89368318Scgd vattr.va_mode = (SCARG(uap, mode) & ALLPERMS) &~ p->p_fd->fd_cmask; 89467654Smckusick VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 89552322Smckusick return (VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr)); 89640285Smckusick #endif /* FIFO */ 89740285Smckusick } 89840285Smckusick 89940285Smckusick /* 90064410Sbostic * Make a hard file link. 9016254Sroot */ 90242441Smckusick /* ARGSUSED */ 90368318Scgd int 90442441Smckusick link(p, uap, retval) 90545914Smckusick struct proc *p; 90668318Scgd register struct link_args /* { 90768318Scgd syscallarg(char *) path; 90868318Scgd syscallarg(char *) link; 90968318Scgd } */ *uap; 91068318Scgd register_t *retval; 91142441Smckusick { 91264410Sbostic register struct vnode *vp; 91364410Sbostic struct nameidata nd; 91437741Smckusick int error; 9156254Sroot 91668318Scgd NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 91752322Smckusick if (error = namei(&nd)) 91847540Skarels return (error); 91952322Smckusick vp = nd.ni_vp; 92064585Sbostic if (vp->v_type != VDIR || 92164585Sbostic (error = suser(p->p_ucred, &p->p_acflag)) == 0) { 92264585Sbostic nd.ni_cnd.cn_nameiop = CREATE; 92364585Sbostic nd.ni_cnd.cn_flags = LOCKPARENT; 92468318Scgd nd.ni_dirp = SCARG(uap, link); 92564585Sbostic if ((error = namei(&nd)) == 0) { 92664585Sbostic if (nd.ni_vp != NULL) 92764585Sbostic error = EEXIST; 92864585Sbostic if (!error) { 92967654Smckusick VOP_LEASE(nd.ni_dvp, p, p->p_ucred, 93067654Smckusick LEASE_WRITE); 93167654Smckusick VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 93268538Smckusick error = VOP_LINK(vp, nd.ni_dvp, &nd.ni_cnd); 93364585Sbostic } else { 93464585Sbostic VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 93564585Sbostic if (nd.ni_dvp == nd.ni_vp) 93664585Sbostic vrele(nd.ni_dvp); 93764585Sbostic else 93864585Sbostic vput(nd.ni_dvp); 93964585Sbostic if (nd.ni_vp) 94064585Sbostic vrele(nd.ni_vp); 94164585Sbostic } 94264585Sbostic } 94342465Smckusick } 94464585Sbostic vrele(vp); 94547540Skarels return (error); 9466254Sroot } 9476254Sroot 9486254Sroot /* 94949365Smckusick * Make a symbolic link. 9506254Sroot */ 95142441Smckusick /* ARGSUSED */ 95268318Scgd int 95342441Smckusick symlink(p, uap, retval) 95445914Smckusick struct proc *p; 95568318Scgd register struct symlink_args /* { 95668318Scgd syscallarg(char *) path; 95768318Scgd syscallarg(char *) link; 95868318Scgd } */ *uap; 95968318Scgd register_t *retval; 96042441Smckusick { 96137741Smckusick struct vattr vattr; 96264410Sbostic char *path; 96337741Smckusick int error; 96447540Skarels struct nameidata nd; 9656254Sroot 96664410Sbostic MALLOC(path, char *, MAXPATHLEN, M_NAMEI, M_WAITOK); 96768318Scgd if (error = copyinstr(SCARG(uap, path), path, MAXPATHLEN, NULL)) 96842465Smckusick goto out; 96968318Scgd NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, link), p); 97052322Smckusick if (error = namei(&nd)) 97142465Smckusick goto out; 97252322Smckusick if (nd.ni_vp) { 97352322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 97452322Smckusick if (nd.ni_dvp == nd.ni_vp) 97552322Smckusick vrele(nd.ni_dvp); 97643344Smckusick else 97752322Smckusick vput(nd.ni_dvp); 97852322Smckusick vrele(nd.ni_vp); 97937741Smckusick error = EEXIST; 98037741Smckusick goto out; 9816254Sroot } 98241362Smckusick VATTR_NULL(&vattr); 98364410Sbostic vattr.va_mode = ACCESSPERMS &~ p->p_fd->fd_cmask; 98467654Smckusick VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 98564410Sbostic error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr, path); 98637741Smckusick out: 98764410Sbostic FREE(path, M_NAMEI); 98847540Skarels return (error); 9896254Sroot } 9906254Sroot 9916254Sroot /* 99267518Spendry * Delete a whiteout from the filesystem. 99367518Spendry */ 99467518Spendry /* ARGSUSED */ 99568318Scgd int 99667845Smckusick undelete(p, uap, retval) 99767518Spendry struct proc *p; 99868318Scgd register struct undelete_args /* { 99968318Scgd syscallarg(char *) path; 100068318Scgd } */ *uap; 100168318Scgd register_t *retval; 100267518Spendry { 100367518Spendry int error; 100467518Spendry struct nameidata nd; 100567518Spendry 100668318Scgd NDINIT(&nd, DELETE, LOCKPARENT|DOWHITEOUT, UIO_USERSPACE, 100768318Scgd SCARG(uap, path), p); 100867575Spendry error = namei(&nd); 100967575Spendry if (error) 101067518Spendry return (error); 101167575Spendry 101267575Spendry if (nd.ni_vp != NULLVP || !(nd.ni_cnd.cn_flags & ISWHITEOUT)) { 101367518Spendry VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 101467518Spendry if (nd.ni_dvp == nd.ni_vp) 101567518Spendry vrele(nd.ni_dvp); 101667518Spendry else 101767518Spendry vput(nd.ni_dvp); 101867518Spendry if (nd.ni_vp) 101967518Spendry vrele(nd.ni_vp); 102067518Spendry return (EEXIST); 102167518Spendry } 102267575Spendry 102367654Smckusick VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 102467747Spendry if (error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, DELETE)) 102567575Spendry VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 102667518Spendry vput(nd.ni_dvp); 102767518Spendry return (error); 102867518Spendry } 102967518Spendry 103067518Spendry /* 103149365Smckusick * Delete a name from the filesystem. 10326254Sroot */ 103342441Smckusick /* ARGSUSED */ 103468318Scgd int 103542441Smckusick unlink(p, uap, retval) 103645914Smckusick struct proc *p; 103768318Scgd struct unlink_args /* { 103868318Scgd syscallarg(char *) path; 103968318Scgd } */ *uap; 104068318Scgd register_t *retval; 10416254Sroot { 104237741Smckusick register struct vnode *vp; 104337741Smckusick int error; 104447540Skarels struct nameidata nd; 10456254Sroot 104668318Scgd NDINIT(&nd, DELETE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p); 104752322Smckusick if (error = namei(&nd)) 104847540Skarels return (error); 104952322Smckusick vp = nd.ni_vp; 105067654Smckusick VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 105159382Smckusick VOP_LOCK(vp); 105264410Sbostic 105364585Sbostic if (vp->v_type != VDIR || 105464585Sbostic (error = suser(p->p_ucred, &p->p_acflag)) == 0) { 105564585Sbostic /* 105664585Sbostic * The root of a mounted filesystem cannot be deleted. 105764585Sbostic */ 105864585Sbostic if (vp->v_flag & VROOT) 105964585Sbostic error = EBUSY; 106064585Sbostic else 106164585Sbostic (void)vnode_pager_uncache(vp); 106264585Sbostic } 106364585Sbostic 106464585Sbostic if (!error) { 106567654Smckusick VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 106652322Smckusick error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); 106742465Smckusick } else { 106852322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 106952322Smckusick if (nd.ni_dvp == vp) 107052322Smckusick vrele(nd.ni_dvp); 107143344Smckusick else 107252322Smckusick vput(nd.ni_dvp); 107367575Spendry if (vp != NULLVP) 107467575Spendry vput(vp); 107542465Smckusick } 107647540Skarels return (error); 10776254Sroot } 10786254Sroot 107964410Sbostic /* 108064410Sbostic * Reposition read/write file offset. 108164410Sbostic */ 108268318Scgd int 108360414Smckusick lseek(p, uap, retval) 108453468Smckusick struct proc *p; 108568318Scgd register struct lseek_args /* { 108668318Scgd syscallarg(int) fd; 108768318Scgd syscallarg(int) pad; 108868318Scgd syscallarg(off_t) offset; 108968318Scgd syscallarg(int) whence; 109068318Scgd } */ *uap; 109168318Scgd register_t *retval; 109242441Smckusick { 109347540Skarels struct ucred *cred = p->p_ucred; 109445914Smckusick register struct filedesc *fdp = p->p_fd; 109542441Smckusick register struct file *fp; 109637741Smckusick struct vattr vattr; 109737741Smckusick int error; 10986254Sroot 109968318Scgd if ((u_int)SCARG(uap, fd) >= fdp->fd_nfiles || 110068318Scgd (fp = fdp->fd_ofiles[SCARG(uap, fd)]) == NULL) 110147540Skarels return (EBADF); 110237741Smckusick if (fp->f_type != DTYPE_VNODE) 110347540Skarels return (ESPIPE); 110468318Scgd switch (SCARG(uap, whence)) { 110513878Ssam case L_INCR: 110668318Scgd fp->f_offset += SCARG(uap, offset); 110713878Ssam break; 110813878Ssam case L_XTND: 110964410Sbostic if (error = 111064410Sbostic VOP_GETATTR((struct vnode *)fp->f_data, &vattr, cred, p)) 111147540Skarels return (error); 111268318Scgd fp->f_offset = SCARG(uap, offset) + vattr.va_size; 111313878Ssam break; 111413878Ssam case L_SET: 111568318Scgd fp->f_offset = SCARG(uap, offset); 111613878Ssam break; 111713878Ssam default: 111847540Skarels return (EINVAL); 111913878Ssam } 112054916Storek *(off_t *)retval = fp->f_offset; 112147540Skarels return (0); 11226254Sroot } 11236254Sroot 112460414Smckusick #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 11256254Sroot /* 112664410Sbostic * Reposition read/write file offset. 112760036Smckusick */ 112868318Scgd int 112968318Scgd compat_43_lseek(p, uap, retval) 113060036Smckusick struct proc *p; 113168318Scgd register struct compat_43_lseek_args /* { 113268318Scgd syscallarg(int) fd; 113368318Scgd syscallarg(long) offset; 113468318Scgd syscallarg(int) whence; 113568318Scgd } */ *uap; 113668318Scgd register_t *retval; 113760036Smckusick { 113868318Scgd struct lseek_args /* { 113968318Scgd syscallarg(int) fd; 114068318Scgd syscallarg(int) pad; 114168318Scgd syscallarg(off_t) offset; 114268318Scgd syscallarg(int) whence; 114368318Scgd } */ nuap; 114460036Smckusick off_t qret; 114560036Smckusick int error; 114660036Smckusick 114768318Scgd SCARG(&nuap, fd) = SCARG(uap, fd); 114868318Scgd SCARG(&nuap, offset) = SCARG(uap, offset); 114968318Scgd SCARG(&nuap, whence) = SCARG(uap, whence); 115060428Smckusick error = lseek(p, &nuap, &qret); 115160036Smckusick *(long *)retval = qret; 115260036Smckusick return (error); 115360036Smckusick } 115460414Smckusick #endif /* COMPAT_43 */ 115560036Smckusick 115660036Smckusick /* 115749365Smckusick * Check access permissions. 11586254Sroot */ 115968318Scgd int 116063427Sbostic access(p, uap, retval) 116145914Smckusick struct proc *p; 116268318Scgd register struct access_args /* { 116368318Scgd syscallarg(char *) path; 116468318Scgd syscallarg(int) flags; 116568318Scgd } */ *uap; 116668318Scgd register_t *retval; 116742441Smckusick { 116847540Skarels register struct ucred *cred = p->p_ucred; 116937741Smckusick register struct vnode *vp; 117064585Sbostic int error, flags, t_gid, t_uid; 117147540Skarels struct nameidata nd; 11726254Sroot 117364585Sbostic t_uid = cred->cr_uid; 117464585Sbostic t_gid = cred->cr_groups[0]; 117547540Skarels cred->cr_uid = p->p_cred->p_ruid; 117647540Skarels cred->cr_groups[0] = p->p_cred->p_rgid; 117768318Scgd NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, 117868318Scgd SCARG(uap, path), p); 117952322Smckusick if (error = namei(&nd)) 118037741Smckusick goto out1; 118152322Smckusick vp = nd.ni_vp; 118264410Sbostic 118364410Sbostic /* Flags == 0 means only check for existence. */ 118468318Scgd if (SCARG(uap, flags)) { 118564410Sbostic flags = 0; 118668318Scgd if (SCARG(uap, flags) & R_OK) 118764410Sbostic flags |= VREAD; 118868318Scgd if (SCARG(uap, flags) & W_OK) 118964410Sbostic flags |= VWRITE; 119068318Scgd if (SCARG(uap, flags) & X_OK) 119164410Sbostic flags |= VEXEC; 119264410Sbostic if ((flags & VWRITE) == 0 || (error = vn_writechk(vp)) == 0) 119364410Sbostic error = VOP_ACCESS(vp, flags, cred, p); 11946254Sroot } 119537741Smckusick vput(vp); 119637741Smckusick out1: 119764585Sbostic cred->cr_uid = t_uid; 119864585Sbostic cred->cr_groups[0] = t_gid; 119947540Skarels return (error); 12006254Sroot } 12016254Sroot 120254348Smckusick #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 12036254Sroot /* 120464410Sbostic * Get file status; this version follows links. 120537Sbill */ 120642441Smckusick /* ARGSUSED */ 120768318Scgd int 120868318Scgd compat_43_stat(p, uap, retval) 120945914Smckusick struct proc *p; 121068318Scgd register struct compat_43_stat_args /* { 121168318Scgd syscallarg(char *) path; 121268318Scgd syscallarg(struct ostat *) ub; 121368318Scgd } */ *uap; 121468318Scgd register_t *retval; 121553468Smckusick { 121653468Smckusick struct stat sb; 121753468Smckusick struct ostat osb; 121853468Smckusick int error; 121953468Smckusick struct nameidata nd; 122053468Smckusick 122168318Scgd NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, 122268318Scgd SCARG(uap, path), p); 122353468Smckusick if (error = namei(&nd)) 122453468Smckusick return (error); 122553468Smckusick error = vn_stat(nd.ni_vp, &sb, p); 122653468Smckusick vput(nd.ni_vp); 122753468Smckusick if (error) 122853468Smckusick return (error); 122953468Smckusick cvtstat(&sb, &osb); 123068318Scgd error = copyout((caddr_t)&osb, (caddr_t)SCARG(uap, ub), sizeof (osb)); 123153468Smckusick return (error); 123253468Smckusick } 123353468Smckusick 123453468Smckusick /* 123564410Sbostic * Get file status; this version does not follow links. 123653468Smckusick */ 123753468Smckusick /* ARGSUSED */ 123868318Scgd int 123968318Scgd compat_43_lstat(p, uap, retval) 124053468Smckusick struct proc *p; 124168318Scgd register struct compat_43_lstat_args /* { 124268318Scgd syscallarg(char *) path; 124368318Scgd syscallarg(struct ostat *) ub; 124468318Scgd } */ *uap; 124568318Scgd register_t *retval; 124653468Smckusick { 124767748Smckusick struct vnode *vp, *dvp; 124867748Smckusick struct stat sb, sb1; 124953468Smckusick struct ostat osb; 125053468Smckusick int error; 125153468Smckusick struct nameidata nd; 125253468Smckusick 125367748Smckusick NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | LOCKPARENT, UIO_USERSPACE, 125468318Scgd SCARG(uap, path), p); 125553468Smckusick if (error = namei(&nd)) 125653468Smckusick return (error); 125767748Smckusick /* 125867748Smckusick * For symbolic links, always return the attributes of its 125967748Smckusick * containing directory, except for mode, size, and links. 126067748Smckusick */ 126167748Smckusick vp = nd.ni_vp; 126267748Smckusick dvp = nd.ni_dvp; 126367748Smckusick if (vp->v_type != VLNK) { 126467748Smckusick if (dvp == vp) 126567748Smckusick vrele(dvp); 126667748Smckusick else 126767748Smckusick vput(dvp); 126867748Smckusick error = vn_stat(vp, &sb, p); 126967748Smckusick vput(vp); 127067748Smckusick if (error) 127167748Smckusick return (error); 127267748Smckusick } else { 127367748Smckusick error = vn_stat(dvp, &sb, p); 127467748Smckusick vput(dvp); 127567748Smckusick if (error) { 127667748Smckusick vput(vp); 127767748Smckusick return (error); 127867748Smckusick } 127967748Smckusick error = vn_stat(vp, &sb1, p); 128067748Smckusick vput(vp); 128167748Smckusick if (error) 128267748Smckusick return (error); 128367748Smckusick sb.st_mode &= ~S_IFDIR; 128467748Smckusick sb.st_mode |= S_IFLNK; 128567748Smckusick sb.st_nlink = sb1.st_nlink; 128667748Smckusick sb.st_size = sb1.st_size; 128767748Smckusick sb.st_blocks = sb1.st_blocks; 128867748Smckusick } 128953468Smckusick cvtstat(&sb, &osb); 129068318Scgd error = copyout((caddr_t)&osb, (caddr_t)SCARG(uap, ub), sizeof (osb)); 129153468Smckusick return (error); 129253468Smckusick } 129353468Smckusick 129453468Smckusick /* 129564410Sbostic * Convert from an old to a new stat structure. 129653468Smckusick */ 129768318Scgd void 129853468Smckusick cvtstat(st, ost) 129953468Smckusick struct stat *st; 130053468Smckusick struct ostat *ost; 130153468Smckusick { 130253468Smckusick 130353468Smckusick ost->st_dev = st->st_dev; 130453468Smckusick ost->st_ino = st->st_ino; 130553468Smckusick ost->st_mode = st->st_mode; 130653468Smckusick ost->st_nlink = st->st_nlink; 130753468Smckusick ost->st_uid = st->st_uid; 130853468Smckusick ost->st_gid = st->st_gid; 130953468Smckusick ost->st_rdev = st->st_rdev; 131053468Smckusick if (st->st_size < (quad_t)1 << 32) 131153468Smckusick ost->st_size = st->st_size; 131253468Smckusick else 131353468Smckusick ost->st_size = -2; 131453468Smckusick ost->st_atime = st->st_atime; 131553468Smckusick ost->st_mtime = st->st_mtime; 131653468Smckusick ost->st_ctime = st->st_ctime; 131753468Smckusick ost->st_blksize = st->st_blksize; 131853468Smckusick ost->st_blocks = st->st_blocks; 131953468Smckusick ost->st_flags = st->st_flags; 132053468Smckusick ost->st_gen = st->st_gen; 132153468Smckusick } 132254348Smckusick #endif /* COMPAT_43 || COMPAT_SUNOS */ 132353468Smckusick 132453468Smckusick /* 132564410Sbostic * Get file status; this version follows links. 132653468Smckusick */ 132753468Smckusick /* ARGSUSED */ 132868318Scgd int 132953759Smckusick stat(p, uap, retval) 133053468Smckusick struct proc *p; 133168318Scgd register struct stat_args /* { 133268318Scgd syscallarg(char *) path; 133368318Scgd syscallarg(struct stat *) ub; 133468318Scgd } */ *uap; 133568318Scgd register_t *retval; 133637Sbill { 133742441Smckusick struct stat sb; 133842441Smckusick int error; 133947540Skarels struct nameidata nd; 134037Sbill 134168318Scgd NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, 134268318Scgd SCARG(uap, path), p); 134352322Smckusick if (error = namei(&nd)) 134447540Skarels return (error); 134552322Smckusick error = vn_stat(nd.ni_vp, &sb, p); 134652322Smckusick vput(nd.ni_vp); 134742441Smckusick if (error) 134847540Skarels return (error); 134968318Scgd error = copyout((caddr_t)&sb, (caddr_t)SCARG(uap, ub), sizeof (sb)); 135047540Skarels return (error); 135137Sbill } 135237Sbill 135337Sbill /* 135464410Sbostic * Get file status; this version does not follow links. 13555992Swnj */ 135642441Smckusick /* ARGSUSED */ 135768318Scgd int 135853759Smckusick lstat(p, uap, retval) 135945914Smckusick struct proc *p; 136068318Scgd register struct lstat_args /* { 136168318Scgd syscallarg(char *) path; 136268318Scgd syscallarg(struct stat *) ub; 136368318Scgd } */ *uap; 136468318Scgd register_t *retval; 136542441Smckusick { 136637741Smckusick int error; 136759373Smckusick struct vnode *vp, *dvp; 136859373Smckusick struct stat sb, sb1; 136947540Skarels struct nameidata nd; 13705992Swnj 137159373Smckusick NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | LOCKPARENT, UIO_USERSPACE, 137268318Scgd SCARG(uap, path), p); 137352322Smckusick if (error = namei(&nd)) 137447540Skarels return (error); 137559373Smckusick /* 137668579Smckusick * For symbolic links, always return the attributes of its containing 137768579Smckusick * directory, except for mode, size, inode number, and links. 137859373Smckusick */ 137959373Smckusick vp = nd.ni_vp; 138059373Smckusick dvp = nd.ni_dvp; 138159373Smckusick if (vp->v_type != VLNK) { 138259373Smckusick if (dvp == vp) 138359373Smckusick vrele(dvp); 138459373Smckusick else 138559373Smckusick vput(dvp); 138659373Smckusick error = vn_stat(vp, &sb, p); 138759373Smckusick vput(vp); 138859373Smckusick if (error) 138959373Smckusick return (error); 139059373Smckusick } else { 139159373Smckusick error = vn_stat(dvp, &sb, p); 139259373Smckusick vput(dvp); 139359373Smckusick if (error) { 139459373Smckusick vput(vp); 139559373Smckusick return (error); 139659373Smckusick } 139759373Smckusick error = vn_stat(vp, &sb1, p); 139859373Smckusick vput(vp); 139959373Smckusick if (error) 140059373Smckusick return (error); 140159373Smckusick sb.st_mode &= ~S_IFDIR; 140259373Smckusick sb.st_mode |= S_IFLNK; 140359373Smckusick sb.st_nlink = sb1.st_nlink; 140459373Smckusick sb.st_size = sb1.st_size; 140559373Smckusick sb.st_blocks = sb1.st_blocks; 140668579Smckusick sb.st_ino = sb1.st_ino; 140759373Smckusick } 140868318Scgd error = copyout((caddr_t)&sb, (caddr_t)SCARG(uap, ub), sizeof (sb)); 140947540Skarels return (error); 14105992Swnj } 14115992Swnj 14125992Swnj /* 141364410Sbostic * Get configurable pathname variables. 141460414Smckusick */ 141560414Smckusick /* ARGSUSED */ 141668318Scgd int 141760414Smckusick pathconf(p, uap, retval) 141860414Smckusick struct proc *p; 141968318Scgd register struct pathconf_args /* { 142068318Scgd syscallarg(char *) path; 142168318Scgd syscallarg(int) name; 142268318Scgd } */ *uap; 142368318Scgd register_t *retval; 142460414Smckusick { 142560414Smckusick int error; 142660414Smckusick struct nameidata nd; 142760414Smckusick 142868318Scgd NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, 142968318Scgd SCARG(uap, path), p); 143060414Smckusick if (error = namei(&nd)) 143160414Smckusick return (error); 143268318Scgd error = VOP_PATHCONF(nd.ni_vp, SCARG(uap, name), retval); 143360414Smckusick vput(nd.ni_vp); 143460414Smckusick return (error); 143560414Smckusick } 143660414Smckusick 143760414Smckusick /* 143849365Smckusick * Return target name of a symbolic link. 143937Sbill */ 144042441Smckusick /* ARGSUSED */ 144168318Scgd int 144242441Smckusick readlink(p, uap, retval) 144345914Smckusick struct proc *p; 144468318Scgd register struct readlink_args /* { 144568318Scgd syscallarg(char *) path; 144668318Scgd syscallarg(char *) buf; 144768318Scgd syscallarg(int) count; 144868318Scgd } */ *uap; 144968318Scgd register_t *retval; 145042441Smckusick { 145137741Smckusick register struct vnode *vp; 145237741Smckusick struct iovec aiov; 145337741Smckusick struct uio auio; 145437741Smckusick int error; 145547540Skarels struct nameidata nd; 14565992Swnj 145768318Scgd NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, 145868318Scgd SCARG(uap, path), p); 145952322Smckusick if (error = namei(&nd)) 146047540Skarels return (error); 146152322Smckusick vp = nd.ni_vp; 146264410Sbostic if (vp->v_type != VLNK) 146337741Smckusick error = EINVAL; 146464410Sbostic else { 146568318Scgd aiov.iov_base = SCARG(uap, buf); 146668318Scgd aiov.iov_len = SCARG(uap, count); 146764410Sbostic auio.uio_iov = &aiov; 146864410Sbostic auio.uio_iovcnt = 1; 146964410Sbostic auio.uio_offset = 0; 147064410Sbostic auio.uio_rw = UIO_READ; 147164410Sbostic auio.uio_segflg = UIO_USERSPACE; 147264410Sbostic auio.uio_procp = p; 147368318Scgd auio.uio_resid = SCARG(uap, count); 147464410Sbostic error = VOP_READLINK(vp, &auio, p->p_ucred); 14755992Swnj } 147637741Smckusick vput(vp); 147768318Scgd *retval = SCARG(uap, count) - auio.uio_resid; 147847540Skarels return (error); 14795992Swnj } 14805992Swnj 14819167Ssam /* 148264410Sbostic * Change flags of a file given a path name. 148338259Smckusick */ 148442441Smckusick /* ARGSUSED */ 148568318Scgd int 148642441Smckusick chflags(p, uap, retval) 148745914Smckusick struct proc *p; 148868318Scgd register struct chflags_args /* { 148968318Scgd syscallarg(char *) path; 149068318Scgd syscallarg(int) flags; 149168318Scgd } */ *uap; 149268318Scgd register_t *retval; 149342441Smckusick { 149438259Smckusick register struct vnode *vp; 149538259Smckusick struct vattr vattr; 149638259Smckusick int error; 149747540Skarels struct nameidata nd; 149838259Smckusick 149968318Scgd NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 150052322Smckusick if (error = namei(&nd)) 150147540Skarels return (error); 150252322Smckusick vp = nd.ni_vp; 150367654Smckusick VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 150459382Smckusick VOP_LOCK(vp); 150564410Sbostic if (vp->v_mount->mnt_flag & MNT_RDONLY) 150638259Smckusick error = EROFS; 150764410Sbostic else { 150864410Sbostic VATTR_NULL(&vattr); 150968318Scgd vattr.va_flags = SCARG(uap, flags); 151064410Sbostic error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 151138259Smckusick } 151238259Smckusick vput(vp); 151347540Skarels return (error); 151438259Smckusick } 151538259Smckusick 151638259Smckusick /* 151738259Smckusick * Change flags of a file given a file descriptor. 151838259Smckusick */ 151942441Smckusick /* ARGSUSED */ 152068318Scgd int 152142441Smckusick fchflags(p, uap, retval) 152245914Smckusick struct proc *p; 152368318Scgd register struct fchflags_args /* { 152468318Scgd syscallarg(int) fd; 152568318Scgd syscallarg(int) flags; 152668318Scgd } */ *uap; 152768318Scgd register_t *retval; 152842441Smckusick { 152938259Smckusick struct vattr vattr; 153038259Smckusick struct vnode *vp; 153138259Smckusick struct file *fp; 153238259Smckusick int error; 153338259Smckusick 153468318Scgd if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) 153547540Skarels return (error); 153638259Smckusick vp = (struct vnode *)fp->f_data; 153767654Smckusick VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 153838259Smckusick VOP_LOCK(vp); 153964410Sbostic if (vp->v_mount->mnt_flag & MNT_RDONLY) 154038259Smckusick error = EROFS; 154164410Sbostic else { 154264410Sbostic VATTR_NULL(&vattr); 154368318Scgd vattr.va_flags = SCARG(uap, flags); 154464410Sbostic error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 154538259Smckusick } 154638259Smckusick VOP_UNLOCK(vp); 154747540Skarels return (error); 154838259Smckusick } 154938259Smckusick 155038259Smckusick /* 15519167Ssam * Change mode of a file given path name. 15529167Ssam */ 155342441Smckusick /* ARGSUSED */ 155468318Scgd int 155542441Smckusick chmod(p, uap, retval) 155645914Smckusick struct proc *p; 155768318Scgd register struct chmod_args /* { 155868318Scgd syscallarg(char *) path; 155968318Scgd syscallarg(int) mode; 156068318Scgd } */ *uap; 156168318Scgd register_t *retval; 156242441Smckusick { 156337741Smckusick register struct vnode *vp; 156437741Smckusick struct vattr vattr; 156537741Smckusick int error; 156647540Skarels struct nameidata nd; 15675992Swnj 156868318Scgd NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 156952322Smckusick if (error = namei(&nd)) 157047540Skarels return (error); 157152322Smckusick vp = nd.ni_vp; 157267654Smckusick VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 157359382Smckusick VOP_LOCK(vp); 157464410Sbostic if (vp->v_mount->mnt_flag & MNT_RDONLY) 157537741Smckusick error = EROFS; 157664410Sbostic else { 157764410Sbostic VATTR_NULL(&vattr); 157868318Scgd vattr.va_mode = SCARG(uap, mode) & ALLPERMS; 157964410Sbostic error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 158037741Smckusick } 158137741Smckusick vput(vp); 158247540Skarels return (error); 15837701Ssam } 15847439Sroot 15859167Ssam /* 15869167Ssam * Change mode of a file given a file descriptor. 15879167Ssam */ 158842441Smckusick /* ARGSUSED */ 158968318Scgd int 159042441Smckusick fchmod(p, uap, retval) 159145914Smckusick struct proc *p; 159268318Scgd register struct fchmod_args /* { 159368318Scgd syscallarg(int) fd; 159468318Scgd syscallarg(int) mode; 159568318Scgd } */ *uap; 159668318Scgd register_t *retval; 159742441Smckusick { 159837741Smckusick struct vattr vattr; 159937741Smckusick struct vnode *vp; 160037741Smckusick struct file *fp; 160137741Smckusick int error; 16027701Ssam 160368318Scgd if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) 160447540Skarels return (error); 160537741Smckusick vp = (struct vnode *)fp->f_data; 160667654Smckusick VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 160737741Smckusick VOP_LOCK(vp); 160864410Sbostic if (vp->v_mount->mnt_flag & MNT_RDONLY) 160937741Smckusick error = EROFS; 161064410Sbostic else { 161164410Sbostic VATTR_NULL(&vattr); 161268318Scgd vattr.va_mode = SCARG(uap, mode) & ALLPERMS; 161364410Sbostic error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 16147439Sroot } 161537741Smckusick VOP_UNLOCK(vp); 161647540Skarels return (error); 16175992Swnj } 16185992Swnj 16199167Ssam /* 16209167Ssam * Set ownership given a path name. 16219167Ssam */ 162242441Smckusick /* ARGSUSED */ 162368318Scgd int 162442441Smckusick chown(p, uap, retval) 162545914Smckusick struct proc *p; 162668318Scgd register struct chown_args /* { 162768318Scgd syscallarg(char *) path; 162868318Scgd syscallarg(int) uid; 162968318Scgd syscallarg(int) gid; 163068318Scgd } */ *uap; 163168318Scgd register_t *retval; 163242441Smckusick { 163337741Smckusick register struct vnode *vp; 163437741Smckusick struct vattr vattr; 163537741Smckusick int error; 163647540Skarels struct nameidata nd; 163737Sbill 163868318Scgd NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 163952322Smckusick if (error = namei(&nd)) 164047540Skarels return (error); 164152322Smckusick vp = nd.ni_vp; 164267654Smckusick VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 164359382Smckusick VOP_LOCK(vp); 164464410Sbostic if (vp->v_mount->mnt_flag & MNT_RDONLY) 164537741Smckusick error = EROFS; 164664410Sbostic else { 164764410Sbostic VATTR_NULL(&vattr); 164868318Scgd vattr.va_uid = SCARG(uap, uid); 164968318Scgd vattr.va_gid = SCARG(uap, gid); 165064410Sbostic error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 165137741Smckusick } 165237741Smckusick vput(vp); 165347540Skarels return (error); 16547701Ssam } 16557439Sroot 16569167Ssam /* 16579167Ssam * Set ownership given a file descriptor. 16589167Ssam */ 165942441Smckusick /* ARGSUSED */ 166068318Scgd int 166142441Smckusick fchown(p, uap, retval) 166245914Smckusick struct proc *p; 166368318Scgd register struct fchown_args /* { 166468318Scgd syscallarg(int) fd; 166568318Scgd syscallarg(int) uid; 166668318Scgd syscallarg(int) gid; 166768318Scgd } */ *uap; 166868318Scgd register_t *retval; 166942441Smckusick { 167037741Smckusick struct vattr vattr; 167137741Smckusick struct vnode *vp; 167237741Smckusick struct file *fp; 167337741Smckusick int error; 16747701Ssam 167568318Scgd if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) 167647540Skarels return (error); 167737741Smckusick vp = (struct vnode *)fp->f_data; 167867654Smckusick VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 167937741Smckusick VOP_LOCK(vp); 168064410Sbostic if (vp->v_mount->mnt_flag & MNT_RDONLY) 168137741Smckusick error = EROFS; 168264410Sbostic else { 168364410Sbostic VATTR_NULL(&vattr); 168468318Scgd vattr.va_uid = SCARG(uap, uid); 168568318Scgd vattr.va_gid = SCARG(uap, gid); 168664410Sbostic error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 168737741Smckusick } 168837741Smckusick VOP_UNLOCK(vp); 168947540Skarels return (error); 16907701Ssam } 16917701Ssam 169242441Smckusick /* 169342441Smckusick * Set the access and modification times of a file. 169442441Smckusick */ 169542441Smckusick /* ARGSUSED */ 169668318Scgd int 169742441Smckusick utimes(p, uap, retval) 169845914Smckusick struct proc *p; 169968318Scgd register struct utimes_args /* { 170068318Scgd syscallarg(char *) path; 170168318Scgd syscallarg(struct timeval *) tptr; 170268318Scgd } */ *uap; 170368318Scgd register_t *retval; 170442441Smckusick { 170537741Smckusick register struct vnode *vp; 170611811Ssam struct timeval tv[2]; 170737741Smckusick struct vattr vattr; 170858840Storek int error; 170947540Skarels struct nameidata nd; 171011811Ssam 171158505Sbostic VATTR_NULL(&vattr); 171268318Scgd if (SCARG(uap, tptr) == NULL) { 171358505Sbostic microtime(&tv[0]); 171458505Sbostic tv[1] = tv[0]; 171558548Sbostic vattr.va_vaflags |= VA_UTIMES_NULL; 171668318Scgd } else if (error = copyin((caddr_t)SCARG(uap, tptr), (caddr_t)tv, 171768318Scgd sizeof (tv))) 171858505Sbostic return (error); 171968318Scgd NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 172052322Smckusick if (error = namei(&nd)) 172147540Skarels return (error); 172252322Smckusick vp = nd.ni_vp; 172367654Smckusick VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 172459382Smckusick VOP_LOCK(vp); 172564410Sbostic if (vp->v_mount->mnt_flag & MNT_RDONLY) 172637741Smckusick error = EROFS; 172764410Sbostic else { 172864410Sbostic vattr.va_atime.ts_sec = tv[0].tv_sec; 172964410Sbostic vattr.va_atime.ts_nsec = tv[0].tv_usec * 1000; 173064410Sbostic vattr.va_mtime.ts_sec = tv[1].tv_sec; 173164410Sbostic vattr.va_mtime.ts_nsec = tv[1].tv_usec * 1000; 173264410Sbostic error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 173321015Smckusick } 173437741Smckusick vput(vp); 173547540Skarels return (error); 173611811Ssam } 173711811Ssam 173864410Sbostic /* 173964410Sbostic * Truncate a file given its path name. 174064410Sbostic */ 174153468Smckusick /* ARGSUSED */ 174268318Scgd int 174360414Smckusick truncate(p, uap, retval) 174453468Smckusick struct proc *p; 174568318Scgd register struct truncate_args /* { 174668318Scgd syscallarg(char *) path; 174768318Scgd syscallarg(int) pad; 174868318Scgd syscallarg(off_t) length; 174968318Scgd } */ *uap; 175068318Scgd register_t *retval; 175153468Smckusick { 175237741Smckusick register struct vnode *vp; 175337741Smckusick struct vattr vattr; 175437741Smckusick int error; 175547540Skarels struct nameidata nd; 17567701Ssam 175768318Scgd NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 175852322Smckusick if (error = namei(&nd)) 175947540Skarels return (error); 176052322Smckusick vp = nd.ni_vp; 176167654Smckusick VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 176259382Smckusick VOP_LOCK(vp); 176364410Sbostic if (vp->v_type == VDIR) 176437741Smckusick error = EISDIR; 176564410Sbostic else if ((error = vn_writechk(vp)) == 0 && 176664410Sbostic (error = VOP_ACCESS(vp, VWRITE, p->p_ucred, p)) == 0) { 176764410Sbostic VATTR_NULL(&vattr); 176868318Scgd vattr.va_size = SCARG(uap, length); 176964410Sbostic error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 17707701Ssam } 177137741Smckusick vput(vp); 177247540Skarels return (error); 17737701Ssam } 17747701Ssam 177564410Sbostic /* 177664410Sbostic * Truncate a file given a file descriptor. 177764410Sbostic */ 177842441Smckusick /* ARGSUSED */ 177968318Scgd int 178060414Smckusick ftruncate(p, uap, retval) 178145914Smckusick struct proc *p; 178268318Scgd register struct ftruncate_args /* { 178368318Scgd syscallarg(int) fd; 178468318Scgd syscallarg(int) pad; 178568318Scgd syscallarg(off_t) length; 178668318Scgd } */ *uap; 178768318Scgd register_t *retval; 178842441Smckusick { 178937741Smckusick struct vattr vattr; 179037741Smckusick struct vnode *vp; 17917701Ssam struct file *fp; 179237741Smckusick int error; 17937701Ssam 179468318Scgd if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) 179547540Skarels return (error); 179637741Smckusick if ((fp->f_flag & FWRITE) == 0) 179747540Skarels return (EINVAL); 179837741Smckusick vp = (struct vnode *)fp->f_data; 179967654Smckusick VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 180037741Smckusick VOP_LOCK(vp); 180164410Sbostic if (vp->v_type == VDIR) 180237741Smckusick error = EISDIR; 180364410Sbostic else if ((error = vn_writechk(vp)) == 0) { 180464410Sbostic VATTR_NULL(&vattr); 180568318Scgd vattr.va_size = SCARG(uap, length); 180664410Sbostic error = VOP_SETATTR(vp, &vattr, fp->f_cred, p); 18077701Ssam } 180837741Smckusick VOP_UNLOCK(vp); 180947540Skarels return (error); 18107701Ssam } 18117701Ssam 181254863Storek #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 18139167Ssam /* 181454863Storek * Truncate a file given its path name. 181554863Storek */ 181654863Storek /* ARGSUSED */ 181768318Scgd int 181868318Scgd compat_43_truncate(p, uap, retval) 181954863Storek struct proc *p; 182068318Scgd register struct compat_43_truncate_args /* { 182168318Scgd syscallarg(char *) path; 182268318Scgd syscallarg(long) length; 182368318Scgd } */ *uap; 182468318Scgd register_t *retval; 182554863Storek { 182668318Scgd struct truncate_args /* { 182768318Scgd syscallarg(char *) path; 182868318Scgd syscallarg(int) pad; 182968318Scgd syscallarg(off_t) length; 183068318Scgd } */ nuap; 183154863Storek 183268318Scgd SCARG(&nuap, path) = SCARG(uap, path); 183368318Scgd SCARG(&nuap, length) = SCARG(uap, length); 183460428Smckusick return (truncate(p, &nuap, retval)); 183554863Storek } 183654863Storek 183754863Storek /* 183854863Storek * Truncate a file given a file descriptor. 183954863Storek */ 184054863Storek /* ARGSUSED */ 184168318Scgd int 184268318Scgd compat_43_ftruncate(p, uap, retval) 184354863Storek struct proc *p; 184468318Scgd register struct compat_43_ftruncate_args /* { 184568318Scgd syscallarg(int) fd; 184668318Scgd syscallarg(long) length; 184768318Scgd } */ *uap; 184868318Scgd register_t *retval; 184954863Storek { 185068318Scgd struct ftruncate_args /* { 185168318Scgd syscallarg(int) fd; 185268318Scgd syscallarg(int) pad; 185368318Scgd syscallarg(off_t) length; 185468318Scgd } */ nuap; 185554863Storek 185668318Scgd SCARG(&nuap, fd) = SCARG(uap, fd); 185768318Scgd SCARG(&nuap, length) = SCARG(uap, length); 185860428Smckusick return (ftruncate(p, &nuap, retval)); 185954863Storek } 186054863Storek #endif /* COMPAT_43 || COMPAT_SUNOS */ 186154863Storek 186254863Storek /* 186364410Sbostic * Sync an open file. 18649167Ssam */ 186542441Smckusick /* ARGSUSED */ 186668318Scgd int 186742441Smckusick fsync(p, uap, retval) 186845914Smckusick struct proc *p; 186968318Scgd struct fsync_args /* { 187068318Scgd syscallarg(int) fd; 187168318Scgd } */ *uap; 187268318Scgd register_t *retval; 18739167Ssam { 187439592Smckusick register struct vnode *vp; 18759167Ssam struct file *fp; 187637741Smckusick int error; 18779167Ssam 187868318Scgd if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) 187947540Skarels return (error); 188039592Smckusick vp = (struct vnode *)fp->f_data; 188139592Smckusick VOP_LOCK(vp); 188254441Smckusick error = VOP_FSYNC(vp, fp->f_cred, MNT_WAIT, p); 188339592Smckusick VOP_UNLOCK(vp); 188447540Skarels return (error); 18859167Ssam } 18869167Ssam 18879167Ssam /* 188864410Sbostic * Rename files. Source and destination must either both be directories, 188964410Sbostic * or both not be directories. If target is a directory, it must be empty. 18909167Ssam */ 189142441Smckusick /* ARGSUSED */ 189268318Scgd int 189342441Smckusick rename(p, uap, retval) 189445914Smckusick struct proc *p; 189568318Scgd register struct rename_args /* { 189668318Scgd syscallarg(char *) from; 189768318Scgd syscallarg(char *) to; 189868318Scgd } */ *uap; 189968318Scgd register_t *retval; 190042441Smckusick { 190137741Smckusick register struct vnode *tvp, *fvp, *tdvp; 190249735Smckusick struct nameidata fromnd, tond; 190337741Smckusick int error; 19047701Ssam 190552322Smckusick NDINIT(&fromnd, DELETE, WANTPARENT | SAVESTART, UIO_USERSPACE, 190668318Scgd SCARG(uap, from), p); 190752322Smckusick if (error = namei(&fromnd)) 190847540Skarels return (error); 190949735Smckusick fvp = fromnd.ni_vp; 191052322Smckusick NDINIT(&tond, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART, 191168318Scgd UIO_USERSPACE, SCARG(uap, to), p); 191252322Smckusick if (error = namei(&tond)) { 191352230Sheideman VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 191449735Smckusick vrele(fromnd.ni_dvp); 191542465Smckusick vrele(fvp); 191642465Smckusick goto out1; 191742465Smckusick } 191837741Smckusick tdvp = tond.ni_dvp; 191937741Smckusick tvp = tond.ni_vp; 192037741Smckusick if (tvp != NULL) { 192137741Smckusick if (fvp->v_type == VDIR && tvp->v_type != VDIR) { 192239242Sbostic error = ENOTDIR; 192337741Smckusick goto out; 192437741Smckusick } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) { 192539242Sbostic error = EISDIR; 192637741Smckusick goto out; 19279167Ssam } 19289167Ssam } 192939286Smckusick if (fvp == tdvp) 193037741Smckusick error = EINVAL; 193139286Smckusick /* 193249735Smckusick * If source is the same as the destination (that is the 193349735Smckusick * same inode number with the same name in the same directory), 193439286Smckusick * then there is nothing to do. 193539286Smckusick */ 193649735Smckusick if (fvp == tvp && fromnd.ni_dvp == tdvp && 193752322Smckusick fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen && 193852322Smckusick !bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr, 193952322Smckusick fromnd.ni_cnd.cn_namelen)) 194039286Smckusick error = -1; 194137741Smckusick out: 194242465Smckusick if (!error) { 194367654Smckusick VOP_LEASE(tdvp, p, p->p_ucred, LEASE_WRITE); 194452192Smckusick if (fromnd.ni_dvp != tdvp) 194567654Smckusick VOP_LEASE(fromnd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 194652192Smckusick if (tvp) 194767654Smckusick VOP_LEASE(tvp, p, p->p_ucred, LEASE_WRITE); 194852230Sheideman error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd, 194952230Sheideman tond.ni_dvp, tond.ni_vp, &tond.ni_cnd); 195042465Smckusick } else { 195152230Sheideman VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd); 195243344Smckusick if (tdvp == tvp) 195343344Smckusick vrele(tdvp); 195443344Smckusick else 195543344Smckusick vput(tdvp); 195642465Smckusick if (tvp) 195742465Smckusick vput(tvp); 195852230Sheideman VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 195949735Smckusick vrele(fromnd.ni_dvp); 196042465Smckusick vrele(fvp); 19619167Ssam } 196249735Smckusick vrele(tond.ni_startdir); 196352322Smckusick FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI); 196437741Smckusick out1: 196566801Smckusick if (fromnd.ni_startdir) 196666801Smckusick vrele(fromnd.ni_startdir); 196752322Smckusick FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI); 196839286Smckusick if (error == -1) 196947540Skarels return (0); 197047540Skarels return (error); 19717701Ssam } 19727701Ssam 19737535Sroot /* 197464410Sbostic * Make a directory file. 197512756Ssam */ 197642441Smckusick /* ARGSUSED */ 197768318Scgd int 197842441Smckusick mkdir(p, uap, retval) 197945914Smckusick struct proc *p; 198068318Scgd register struct mkdir_args /* { 198168318Scgd syscallarg(char *) path; 198268318Scgd syscallarg(int) mode; 198368318Scgd } */ *uap; 198468318Scgd register_t *retval; 198542441Smckusick { 198637741Smckusick register struct vnode *vp; 198737741Smckusick struct vattr vattr; 198837741Smckusick int error; 198947540Skarels struct nameidata nd; 199012756Ssam 199168318Scgd NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p); 199252322Smckusick if (error = namei(&nd)) 199347540Skarels return (error); 199452322Smckusick vp = nd.ni_vp; 199537741Smckusick if (vp != NULL) { 199652322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 199752322Smckusick if (nd.ni_dvp == vp) 199852322Smckusick vrele(nd.ni_dvp); 199943344Smckusick else 200052322Smckusick vput(nd.ni_dvp); 200142465Smckusick vrele(vp); 200247540Skarels return (EEXIST); 200312756Ssam } 200441362Smckusick VATTR_NULL(&vattr); 200537741Smckusick vattr.va_type = VDIR; 200668318Scgd vattr.va_mode = (SCARG(uap, mode) & ACCESSPERMS) &~ p->p_fd->fd_cmask; 200767654Smckusick VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 200852322Smckusick error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr); 200938145Smckusick if (!error) 201052322Smckusick vput(nd.ni_vp); 201147540Skarels return (error); 201212756Ssam } 201312756Ssam 201412756Ssam /* 201564410Sbostic * Remove a directory file. 201612756Ssam */ 201742441Smckusick /* ARGSUSED */ 201868318Scgd int 201942441Smckusick rmdir(p, uap, retval) 202045914Smckusick struct proc *p; 202168318Scgd struct rmdir_args /* { 202268318Scgd syscallarg(char *) path; 202368318Scgd } */ *uap; 202468318Scgd register_t *retval; 202512756Ssam { 202637741Smckusick register struct vnode *vp; 202737741Smckusick int error; 202847540Skarels struct nameidata nd; 202912756Ssam 203068318Scgd NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE, 203168318Scgd SCARG(uap, path), p); 203252322Smckusick if (error = namei(&nd)) 203347540Skarels return (error); 203452322Smckusick vp = nd.ni_vp; 203537741Smckusick if (vp->v_type != VDIR) { 203637741Smckusick error = ENOTDIR; 203712756Ssam goto out; 203812756Ssam } 203912756Ssam /* 204037741Smckusick * No rmdir "." please. 204112756Ssam */ 204252322Smckusick if (nd.ni_dvp == vp) { 204337741Smckusick error = EINVAL; 204412756Ssam goto out; 204512756Ssam } 204612756Ssam /* 204749365Smckusick * The root of a mounted filesystem cannot be deleted. 204812756Ssam */ 204937741Smckusick if (vp->v_flag & VROOT) 205037741Smckusick error = EBUSY; 205112756Ssam out: 205242465Smckusick if (!error) { 205367654Smckusick VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 205467654Smckusick VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 205552322Smckusick error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); 205642465Smckusick } else { 205752322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 205852322Smckusick if (nd.ni_dvp == vp) 205952322Smckusick vrele(nd.ni_dvp); 206043344Smckusick else 206152322Smckusick vput(nd.ni_dvp); 206242465Smckusick vput(vp); 206342465Smckusick } 206447540Skarels return (error); 206512756Ssam } 206612756Ssam 206754620Smckusick #ifdef COMPAT_43 206837741Smckusick /* 206949365Smckusick * Read a block of directory entries in a file system independent format. 207037741Smckusick */ 207168318Scgd int 207268318Scgd compat_43_getdirentries(p, uap, retval) 207354620Smckusick struct proc *p; 207468318Scgd register struct compat_43_getdirentries_args /* { 207568318Scgd syscallarg(int) fd; 207668318Scgd syscallarg(char *) buf; 207768318Scgd syscallarg(u_int) count; 207868318Scgd syscallarg(long *) basep; 207968318Scgd } */ *uap; 208068318Scgd register_t *retval; 208154620Smckusick { 208254620Smckusick register struct vnode *vp; 208354620Smckusick struct file *fp; 208454620Smckusick struct uio auio, kuio; 208554620Smckusick struct iovec aiov, kiov; 208654620Smckusick struct dirent *dp, *edp; 208754620Smckusick caddr_t dirbuf; 208867362Smckusick int error, eofflag, readcnt; 208954969Smckusick long loff; 209054620Smckusick 209168318Scgd if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) 209254620Smckusick return (error); 209354620Smckusick if ((fp->f_flag & FREAD) == 0) 209454620Smckusick return (EBADF); 209554620Smckusick vp = (struct vnode *)fp->f_data; 209667362Smckusick unionread: 209754620Smckusick if (vp->v_type != VDIR) 209854620Smckusick return (EINVAL); 209968318Scgd aiov.iov_base = SCARG(uap, buf); 210068318Scgd aiov.iov_len = SCARG(uap, count); 210154620Smckusick auio.uio_iov = &aiov; 210254620Smckusick auio.uio_iovcnt = 1; 210354620Smckusick auio.uio_rw = UIO_READ; 210454620Smckusick auio.uio_segflg = UIO_USERSPACE; 210554620Smckusick auio.uio_procp = p; 210668318Scgd auio.uio_resid = SCARG(uap, count); 210754620Smckusick VOP_LOCK(vp); 210854969Smckusick loff = auio.uio_offset = fp->f_offset; 210954620Smckusick # if (BYTE_ORDER != LITTLE_ENDIAN) 211056339Smckusick if (vp->v_mount->mnt_maxsymlinklen <= 0) { 211167362Smckusick error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, 211268663Smckusick (int *)0, (u_long *)0); 211356339Smckusick fp->f_offset = auio.uio_offset; 211456339Smckusick } else 211554620Smckusick # endif 211654620Smckusick { 211754620Smckusick kuio = auio; 211854620Smckusick kuio.uio_iov = &kiov; 211954620Smckusick kuio.uio_segflg = UIO_SYSSPACE; 212068318Scgd kiov.iov_len = SCARG(uap, count); 212168318Scgd MALLOC(dirbuf, caddr_t, SCARG(uap, count), M_TEMP, M_WAITOK); 212254620Smckusick kiov.iov_base = dirbuf; 212367362Smckusick error = VOP_READDIR(vp, &kuio, fp->f_cred, &eofflag, 212468663Smckusick (int *)0, (u_long *)0); 212556339Smckusick fp->f_offset = kuio.uio_offset; 212654620Smckusick if (error == 0) { 212768318Scgd readcnt = SCARG(uap, count) - kuio.uio_resid; 212854620Smckusick edp = (struct dirent *)&dirbuf[readcnt]; 212954620Smckusick for (dp = (struct dirent *)dirbuf; dp < edp; ) { 213054620Smckusick # if (BYTE_ORDER == LITTLE_ENDIAN) 213154969Smckusick /* 213255009Smckusick * The expected low byte of 213355009Smckusick * dp->d_namlen is our dp->d_type. 213455009Smckusick * The high MBZ byte of dp->d_namlen 213555009Smckusick * is our dp->d_namlen. 213654969Smckusick */ 213755009Smckusick dp->d_type = dp->d_namlen; 213855009Smckusick dp->d_namlen = 0; 213955009Smckusick # else 214055009Smckusick /* 214155009Smckusick * The dp->d_type is the high byte 214255009Smckusick * of the expected dp->d_namlen, 214355009Smckusick * so must be zero'ed. 214455009Smckusick */ 214555009Smckusick dp->d_type = 0; 214654620Smckusick # endif 214754620Smckusick if (dp->d_reclen > 0) { 214854620Smckusick dp = (struct dirent *) 214954620Smckusick ((char *)dp + dp->d_reclen); 215054620Smckusick } else { 215154620Smckusick error = EIO; 215254620Smckusick break; 215354620Smckusick } 215454620Smckusick } 215554620Smckusick if (dp >= edp) 215654620Smckusick error = uiomove(dirbuf, readcnt, &auio); 215754620Smckusick } 215854620Smckusick FREE(dirbuf, M_TEMP); 215954620Smckusick } 216054620Smckusick VOP_UNLOCK(vp); 216154620Smckusick if (error) 216254620Smckusick return (error); 216367362Smckusick 216467362Smckusick #ifdef UNION 216567362Smckusick { 216667362Smckusick extern int (**union_vnodeop_p)(); 216768079Spendry extern struct vnode *union_dircache __P((struct vnode *)); 216867362Smckusick 216968318Scgd if ((SCARG(uap, count) == auio.uio_resid) && 217067362Smckusick (vp->v_op == union_vnodeop_p)) { 217167362Smckusick struct vnode *lvp; 217267362Smckusick 217368079Spendry lvp = union_dircache(vp); 217467362Smckusick if (lvp != NULLVP) { 217567575Spendry struct vattr va; 217667575Spendry 217767575Spendry /* 217867575Spendry * If the directory is opaque, 217967575Spendry * then don't show lower entries 218067575Spendry */ 218167575Spendry error = VOP_GETATTR(vp, &va, fp->f_cred, p); 218267575Spendry if (va.va_flags & OPAQUE) { 218368079Spendry vput(lvp); 218467575Spendry lvp = NULL; 218567575Spendry } 218667575Spendry } 218767575Spendry 218867575Spendry if (lvp != NULLVP) { 218967362Smckusick error = VOP_OPEN(lvp, FREAD, fp->f_cred, p); 219067362Smckusick VOP_UNLOCK(lvp); 219167362Smckusick 219267362Smckusick if (error) { 219367362Smckusick vrele(lvp); 219467362Smckusick return (error); 219567362Smckusick } 219667362Smckusick fp->f_data = (caddr_t) lvp; 219767362Smckusick fp->f_offset = 0; 219867362Smckusick error = vn_close(vp, FREAD, fp->f_cred, p); 219967362Smckusick if (error) 220067362Smckusick return (error); 220167362Smckusick vp = lvp; 220267362Smckusick goto unionread; 220367362Smckusick } 220467362Smckusick } 220567362Smckusick } 220667362Smckusick #endif /* UNION */ 220767362Smckusick 220868318Scgd if ((SCARG(uap, count) == auio.uio_resid) && 220967362Smckusick (vp->v_flag & VROOT) && 221067362Smckusick (vp->v_mount->mnt_flag & MNT_UNION)) { 221167362Smckusick struct vnode *tvp = vp; 221267362Smckusick vp = vp->v_mount->mnt_vnodecovered; 221367362Smckusick VREF(vp); 221467362Smckusick fp->f_data = (caddr_t) vp; 221567362Smckusick fp->f_offset = 0; 221667362Smckusick vrele(tvp); 221767362Smckusick goto unionread; 221867362Smckusick } 221968318Scgd error = copyout((caddr_t)&loff, (caddr_t)SCARG(uap, basep), 222068318Scgd sizeof(long)); 222168318Scgd *retval = SCARG(uap, count) - auio.uio_resid; 222254620Smckusick return (error); 222354620Smckusick } 222467362Smckusick #endif /* COMPAT_43 */ 222554620Smckusick 222654620Smckusick /* 222754620Smckusick * Read a block of directory entries in a file system independent format. 222854620Smckusick */ 222968318Scgd int 223042441Smckusick getdirentries(p, uap, retval) 223145914Smckusick struct proc *p; 223268318Scgd register struct getdirentries_args /* { 223368318Scgd syscallarg(int) fd; 223468318Scgd syscallarg(char *) buf; 223568318Scgd syscallarg(u_int) count; 223668318Scgd syscallarg(long *) basep; 223768318Scgd } */ *uap; 223868318Scgd register_t *retval; 223942441Smckusick { 224039592Smckusick register struct vnode *vp; 224116540Ssam struct file *fp; 224237741Smckusick struct uio auio; 224337741Smckusick struct iovec aiov; 224454969Smckusick long loff; 224567362Smckusick int error, eofflag; 224612756Ssam 224768318Scgd if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) 224847540Skarels return (error); 224937741Smckusick if ((fp->f_flag & FREAD) == 0) 225047540Skarels return (EBADF); 225139592Smckusick vp = (struct vnode *)fp->f_data; 225255451Spendry unionread: 225339592Smckusick if (vp->v_type != VDIR) 225447540Skarels return (EINVAL); 225568318Scgd aiov.iov_base = SCARG(uap, buf); 225668318Scgd aiov.iov_len = SCARG(uap, count); 225737741Smckusick auio.uio_iov = &aiov; 225837741Smckusick auio.uio_iovcnt = 1; 225937741Smckusick auio.uio_rw = UIO_READ; 226037741Smckusick auio.uio_segflg = UIO_USERSPACE; 226148026Smckusick auio.uio_procp = p; 226268318Scgd auio.uio_resid = SCARG(uap, count); 226339592Smckusick VOP_LOCK(vp); 226454969Smckusick loff = auio.uio_offset = fp->f_offset; 226568663Smckusick error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, 226668663Smckusick (int *)0, (u_long *)0); 226739592Smckusick fp->f_offset = auio.uio_offset; 226839592Smckusick VOP_UNLOCK(vp); 226939592Smckusick if (error) 227047540Skarels return (error); 227166095Spendry 227266095Spendry #ifdef UNION 227366095Spendry { 227466095Spendry extern int (**union_vnodeop_p)(); 227568079Spendry extern struct vnode *union_dircache __P((struct vnode *)); 227666095Spendry 227768318Scgd if ((SCARG(uap, count) == auio.uio_resid) && 227866095Spendry (vp->v_op == union_vnodeop_p)) { 227967122Spendry struct vnode *lvp; 228066095Spendry 228168079Spendry lvp = union_dircache(vp); 228267122Spendry if (lvp != NULLVP) { 228367575Spendry struct vattr va; 228467575Spendry 228567575Spendry /* 228667575Spendry * If the directory is opaque, 228767575Spendry * then don't show lower entries 228867575Spendry */ 228967575Spendry error = VOP_GETATTR(vp, &va, fp->f_cred, p); 229067575Spendry if (va.va_flags & OPAQUE) { 229168079Spendry vput(lvp); 229267575Spendry lvp = NULL; 229367575Spendry } 229467575Spendry } 229567575Spendry 229667575Spendry if (lvp != NULLVP) { 229767362Smckusick error = VOP_OPEN(lvp, FREAD, fp->f_cred, p); 229867122Spendry VOP_UNLOCK(lvp); 229966095Spendry 230066095Spendry if (error) { 230167122Spendry vrele(lvp); 230266095Spendry return (error); 230366095Spendry } 230467122Spendry fp->f_data = (caddr_t) lvp; 230566095Spendry fp->f_offset = 0; 230667122Spendry error = vn_close(vp, FREAD, fp->f_cred, p); 230766095Spendry if (error) 230866095Spendry return (error); 230967122Spendry vp = lvp; 231066095Spendry goto unionread; 231166095Spendry } 231266095Spendry } 231366095Spendry } 231468318Scgd #endif /* UNION */ 231566095Spendry 231668318Scgd if ((SCARG(uap, count) == auio.uio_resid) && 231755451Spendry (vp->v_flag & VROOT) && 231855451Spendry (vp->v_mount->mnt_flag & MNT_UNION)) { 231955451Spendry struct vnode *tvp = vp; 232055451Spendry vp = vp->v_mount->mnt_vnodecovered; 232155451Spendry VREF(vp); 232255451Spendry fp->f_data = (caddr_t) vp; 232355451Spendry fp->f_offset = 0; 232455451Spendry vrele(tvp); 232555451Spendry goto unionread; 232655451Spendry } 232768318Scgd error = copyout((caddr_t)&loff, (caddr_t)SCARG(uap, basep), 232868318Scgd sizeof(long)); 232968318Scgd *retval = SCARG(uap, count) - auio.uio_resid; 233047540Skarels return (error); 233112756Ssam } 233212756Ssam 233312756Ssam /* 233449365Smckusick * Set the mode mask for creation of filesystem nodes. 233512756Ssam */ 233668318Scgd int 233742441Smckusick umask(p, uap, retval) 233845914Smckusick struct proc *p; 233968318Scgd struct umask_args /* { 234068318Scgd syscallarg(int) newmask; 234168318Scgd } */ *uap; 234268318Scgd register_t *retval; 234312756Ssam { 234464410Sbostic register struct filedesc *fdp; 234512756Ssam 234664410Sbostic fdp = p->p_fd; 234745914Smckusick *retval = fdp->fd_cmask; 234868318Scgd fdp->fd_cmask = SCARG(uap, newmask) & ALLPERMS; 234947540Skarels return (0); 235012756Ssam } 235137741Smckusick 235239566Smarc /* 235339566Smarc * Void all references to file by ripping underlying filesystem 235439566Smarc * away from vnode. 235539566Smarc */ 235642441Smckusick /* ARGSUSED */ 235768318Scgd int 235842441Smckusick revoke(p, uap, retval) 235945914Smckusick struct proc *p; 236068318Scgd register struct revoke_args /* { 236168318Scgd syscallarg(char *) path; 236268318Scgd } */ *uap; 236368318Scgd register_t *retval; 236442441Smckusick { 236539566Smarc register struct vnode *vp; 236639566Smarc struct vattr vattr; 236739566Smarc int error; 236847540Skarels struct nameidata nd; 236939566Smarc 237068318Scgd NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 237152322Smckusick if (error = namei(&nd)) 237247540Skarels return (error); 237352322Smckusick vp = nd.ni_vp; 237448026Smckusick if (error = VOP_GETATTR(vp, &vattr, p->p_ucred, p)) 237539566Smarc goto out; 237647540Skarels if (p->p_ucred->cr_uid != vattr.va_uid && 237747540Skarels (error = suser(p->p_ucred, &p->p_acflag))) 237839566Smarc goto out; 237939805Smckusick if (vp->v_usecount > 1 || (vp->v_flag & VALIASED)) 238068423Smckusick VOP_REVOKE(vp, REVOKEALL); 238139566Smarc out: 238239566Smarc vrele(vp); 238347540Skarels return (error); 238439566Smarc } 238539566Smarc 238649365Smckusick /* 238749365Smckusick * Convert a user file descriptor to a kernel file entry. 238849365Smckusick */ 238968318Scgd int 239064410Sbostic getvnode(fdp, fd, fpp) 239145914Smckusick struct filedesc *fdp; 239237741Smckusick struct file **fpp; 239364410Sbostic int fd; 239437741Smckusick { 239537741Smckusick struct file *fp; 239637741Smckusick 239764410Sbostic if ((u_int)fd >= fdp->fd_nfiles || 239864410Sbostic (fp = fdp->fd_ofiles[fd]) == NULL) 239937741Smckusick return (EBADF); 240037741Smckusick if (fp->f_type != DTYPE_VNODE) 240137741Smckusick return (EINVAL); 240237741Smckusick *fpp = fp; 240337741Smckusick return (0); 240437741Smckusick } 2405