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*68663Smckusick * @(#)vfs_syscalls.c 8.33 (Berkeley) 03/30/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 /* { 49*68663Smckusick syscallarg(char *) type; 5068318Scgd syscallarg(char *) path; 5168318Scgd syscallarg(int) flags; 5268318Scgd syscallarg(caddr_t) data; 5368318Scgd } */ *uap; 5468318Scgd register_t *retval; 5542441Smckusick { 56*68663Smckusick struct vnode *vp; 57*68663Smckusick struct mount *mp; 58*68663Smckusick struct vfsconf *vfsp; 5940111Smckusick int error, flag; 6067532Smckusick struct vattr va; 61*68663Smckusick u_long fstypenum; 6247540Skarels struct nameidata nd; 63*68663Smckusick 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 } 141*68663Smckusick #ifdef COMPAT_43 142*68663Smckusick /* 143*68663Smckusick * Historically filesystem types were identified by number. If we 144*68663Smckusick * get an integer for the filesystem type instead of a string, we 145*68663Smckusick * check to see if it matches one of the historic filesystem types. 146*68663Smckusick */ 147*68663Smckusick fstypenum = (u_long)SCARG(uap, type); 148*68663Smckusick if (fstypenum < maxvfsconf) { 149*68663Smckusick for (vfsp = vfsconf; vfsp; vfsp = vfsp->vfc_next) 150*68663Smckusick if (vfsp->vfc_typenum == fstypenum) 151*68663Smckusick break; 152*68663Smckusick if (vfsp == NULL) { 153*68663Smckusick vput(vp); 154*68663Smckusick return (ENODEV); 155*68663Smckusick } 156*68663Smckusick strncpy(fstypename, vfsp->vfc_name, MFSNAMELEN); 157*68663Smckusick } else 158*68663Smckusick #endif /* COMPAT_43 */ 159*68663Smckusick if (error = copyinstr(SCARG(uap, type), fstypename, MFSNAMELEN, NULL)) { 16037741Smckusick vput(vp); 161*68663Smckusick return (error); 162*68663Smckusick } 163*68663Smckusick for (vfsp = vfsconf; vfsp; vfsp = vfsp->vfc_next) 164*68663Smckusick if (!strcmp(vfsp->vfc_name, fstypename)) 165*68663Smckusick break; 166*68663Smckusick if (vfsp == NULL) { 167*68663Smckusick vput(vp); 16847540Skarels return (ENODEV); 16937741Smckusick } 17067969Spendry if (vp->v_mountedhere != NULL) { 17167961Smckusick vput(vp); 17267961Smckusick return (EBUSY); 17367961Smckusick } 17437741Smckusick 17537741Smckusick /* 176*68663Smckusick * 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)); 181*68663Smckusick 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 } 187*68663Smckusick mp->mnt_vfc = vfsp; 188*68663Smckusick vfsp->vfc_refcount++; 189*68663Smckusick mp->mnt_stat.f_type = vfsp->vfc_typenum; 190*68663Smckusick mp->mnt_flag |= vfsp->vfc_flags & MNT_VISFLAGMASK; 191*68663Smckusick 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) { 22665259Smckusick TAILQ_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; 233*68663Smckusick 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 { 35837741Smckusick vrele(coveredvp); 35965259Smckusick TAILQ_REMOVE(&mountlist, mp, mnt_list); 36065259Smckusick mp->mnt_vnodecovered->v_mountedhere = (struct mount *)0; 361*68663Smckusick mp->mnt_vfc->vfc_refcount--; 36265259Smckusick vfs_unlock(mp); 36365259Smckusick if (mp->mnt_vnodelist.lh_first != NULL) 36452287Smckusick panic("unmount: dangling vnode"); 36537741Smckusick free((caddr_t)mp, M_MOUNT); 36637741Smckusick } 36739356Smckusick return (error); 3686254Sroot } 3696254Sroot 3709167Ssam /* 37137741Smckusick * Sync each mounted filesystem. 3729167Ssam */ 37367403Smckusick #ifdef DEBUG 37456352Smckusick int syncprt = 0; 37559875Smckusick struct ctldebug debug0 = { "syncprt", &syncprt }; 37656352Smckusick #endif 37756352Smckusick 37839491Smckusick /* ARGSUSED */ 37968318Scgd int 38042441Smckusick sync(p, uap, retval) 38145914Smckusick struct proc *p; 38268318Scgd void *uap; 38368318Scgd register_t *retval; 3846254Sroot { 38565259Smckusick register struct mount *mp, *nmp; 38665859Smckusick int asyncflag; 38737741Smckusick 38865259Smckusick for (mp = mountlist.tqh_first; mp != NULL; mp = nmp) { 38967678Smckusick /* 39067678Smckusick * Get the next pointer in case we hang on vfs_busy 39167678Smckusick * while we are being unmounted. 39267678Smckusick */ 39365259Smckusick nmp = mp->mnt_list.tqe_next; 39440343Smckusick /* 39540343Smckusick * The lock check below is to avoid races with mount 39640343Smckusick * and unmount. 39740343Smckusick */ 39841400Smckusick if ((mp->mnt_flag & (MNT_MLOCK|MNT_RDONLY|MNT_MPBUSY)) == 0 && 39941298Smckusick !vfs_busy(mp)) { 40065859Smckusick asyncflag = mp->mnt_flag & MNT_ASYNC; 40165859Smckusick mp->mnt_flag &= ~MNT_ASYNC; 40254441Smckusick VFS_SYNC(mp, MNT_NOWAIT, p->p_ucred, p); 40365859Smckusick if (asyncflag) 40465859Smckusick mp->mnt_flag |= MNT_ASYNC; 40567678Smckusick /* 40667678Smckusick * Get the next pointer again, as the next filesystem 40767678Smckusick * might have been unmounted while we were sync'ing. 40867678Smckusick */ 40967678Smckusick nmp = mp->mnt_list.tqe_next; 41065259Smckusick vfs_unbusy(mp); 41165259Smckusick } 41265259Smckusick } 41356352Smckusick #ifdef DIAGNOSTIC 41456352Smckusick if (syncprt) 41556352Smckusick vfs_bufstats(); 41656352Smckusick #endif /* DIAGNOSTIC */ 41747688Skarels return (0); 41837741Smckusick } 41937741Smckusick 42037741Smckusick /* 42164410Sbostic * Change filesystem quotas. 42241298Smckusick */ 42342441Smckusick /* ARGSUSED */ 42468318Scgd int 42542441Smckusick quotactl(p, uap, retval) 42645914Smckusick struct proc *p; 42768318Scgd register struct quotactl_args /* { 42868318Scgd syscallarg(char *) path; 42968318Scgd syscallarg(int) cmd; 43068318Scgd syscallarg(int) uid; 43168318Scgd syscallarg(caddr_t) arg; 43268318Scgd } */ *uap; 43368318Scgd register_t *retval; 43442441Smckusick { 43541298Smckusick register struct mount *mp; 43641298Smckusick int error; 43747540Skarels struct nameidata nd; 43841298Smckusick 43968318Scgd NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 44052322Smckusick if (error = namei(&nd)) 44147540Skarels return (error); 44252322Smckusick mp = nd.ni_vp->v_mount; 44352322Smckusick vrele(nd.ni_vp); 44468318Scgd return (VFS_QUOTACTL(mp, SCARG(uap, cmd), SCARG(uap, uid), 44568318Scgd SCARG(uap, arg), p)); 44641298Smckusick } 44741298Smckusick 44841298Smckusick /* 44949365Smckusick * Get filesystem statistics. 45037741Smckusick */ 45142441Smckusick /* ARGSUSED */ 45268318Scgd int 45342441Smckusick statfs(p, uap, retval) 45445914Smckusick struct proc *p; 45568318Scgd register struct statfs_args /* { 45668318Scgd syscallarg(char *) path; 45768318Scgd syscallarg(struct statfs *) buf; 45868318Scgd } */ *uap; 45968318Scgd register_t *retval; 46042441Smckusick { 46139464Smckusick register struct mount *mp; 46240343Smckusick register struct statfs *sp; 46337741Smckusick int error; 46447540Skarels struct nameidata nd; 46537741Smckusick 46668318Scgd NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 46752322Smckusick if (error = namei(&nd)) 46847540Skarels return (error); 46952322Smckusick mp = nd.ni_vp->v_mount; 47041400Smckusick sp = &mp->mnt_stat; 47152322Smckusick vrele(nd.ni_vp); 47248026Smckusick if (error = VFS_STATFS(mp, sp, p)) 47347540Skarels return (error); 47441400Smckusick sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 47568318Scgd return (copyout((caddr_t)sp, (caddr_t)SCARG(uap, buf), sizeof(*sp))); 47637741Smckusick } 47737741Smckusick 47842441Smckusick /* 47949365Smckusick * Get filesystem statistics. 48042441Smckusick */ 48142441Smckusick /* ARGSUSED */ 48268318Scgd int 48342441Smckusick fstatfs(p, uap, retval) 48445914Smckusick struct proc *p; 48568318Scgd register struct fstatfs_args /* { 48668318Scgd syscallarg(int) fd; 48768318Scgd syscallarg(struct statfs *) buf; 48868318Scgd } */ *uap; 48968318Scgd register_t *retval; 49042441Smckusick { 49137741Smckusick struct file *fp; 49239464Smckusick struct mount *mp; 49340343Smckusick register struct statfs *sp; 49437741Smckusick int error; 49537741Smckusick 49668318Scgd if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) 49747540Skarels return (error); 49839464Smckusick mp = ((struct vnode *)fp->f_data)->v_mount; 49941400Smckusick sp = &mp->mnt_stat; 50048026Smckusick if (error = VFS_STATFS(mp, sp, p)) 50147540Skarels return (error); 50241400Smckusick sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 50368318Scgd return (copyout((caddr_t)sp, (caddr_t)SCARG(uap, buf), sizeof(*sp))); 50437741Smckusick } 50537741Smckusick 50637741Smckusick /* 50749365Smckusick * Get statistics on all filesystems. 50838270Smckusick */ 50968318Scgd int 51042441Smckusick getfsstat(p, uap, retval) 51145914Smckusick struct proc *p; 51268318Scgd register struct getfsstat_args /* { 51368318Scgd syscallarg(struct statfs *) buf; 51468318Scgd syscallarg(long) bufsize; 51568318Scgd syscallarg(int) flags; 51668318Scgd } */ *uap; 51768318Scgd register_t *retval; 51842441Smckusick { 51965259Smckusick register struct mount *mp, *nmp; 52040343Smckusick register struct statfs *sp; 52139606Smckusick caddr_t sfsp; 52238270Smckusick long count, maxcount, error; 52338270Smckusick 52468318Scgd maxcount = SCARG(uap, bufsize) / sizeof(struct statfs); 52568318Scgd sfsp = (caddr_t)SCARG(uap, buf); 52665259Smckusick for (count = 0, mp = mountlist.tqh_first; mp != NULL; mp = nmp) { 52765259Smckusick nmp = mp->mnt_list.tqe_next; 52841400Smckusick if (sfsp && count < maxcount && 52941400Smckusick ((mp->mnt_flag & MNT_MLOCK) == 0)) { 53041400Smckusick sp = &mp->mnt_stat; 53140343Smckusick /* 53240343Smckusick * If MNT_NOWAIT is specified, do not refresh the 53340343Smckusick * fsstat cache. MNT_WAIT overrides MNT_NOWAIT. 53440343Smckusick */ 53568318Scgd if (((SCARG(uap, flags) & MNT_NOWAIT) == 0 || 53668318Scgd (SCARG(uap, flags) & MNT_WAIT)) && 53765259Smckusick (error = VFS_STATFS(mp, sp, p))) 53839607Smckusick continue; 53941400Smckusick sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 54040343Smckusick if (error = copyout((caddr_t)sp, sfsp, sizeof(*sp))) 54147540Skarels return (error); 54240343Smckusick sfsp += sizeof(*sp); 54338270Smckusick } 54439606Smckusick count++; 54565259Smckusick } 54638270Smckusick if (sfsp && count > maxcount) 54742441Smckusick *retval = maxcount; 54838270Smckusick else 54942441Smckusick *retval = count; 55047540Skarels return (0); 55138270Smckusick } 55238270Smckusick 55338270Smckusick /* 55438259Smckusick * Change current working directory to a given file descriptor. 55538259Smckusick */ 55642441Smckusick /* ARGSUSED */ 55768318Scgd int 55842441Smckusick fchdir(p, uap, retval) 55945914Smckusick struct proc *p; 56068318Scgd struct fchdir_args /* { 56168318Scgd syscallarg(int) fd; 56268318Scgd } */ *uap; 56368318Scgd register_t *retval; 56438259Smckusick { 56545914Smckusick register struct filedesc *fdp = p->p_fd; 56667974Smckusick struct vnode *vp, *tdp; 56767974Smckusick struct mount *mp; 56838259Smckusick struct file *fp; 56938259Smckusick int error; 57038259Smckusick 57168318Scgd if (error = getvnode(fdp, SCARG(uap, fd), &fp)) 57247540Skarels return (error); 57338259Smckusick vp = (struct vnode *)fp->f_data; 57467974Smckusick VREF(vp); 57538259Smckusick VOP_LOCK(vp); 57638259Smckusick if (vp->v_type != VDIR) 57738259Smckusick error = ENOTDIR; 57838259Smckusick else 57948026Smckusick error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p); 58067974Smckusick while (!error && (mp = vp->v_mountedhere) != NULL) { 58167974Smckusick if (mp->mnt_flag & MNT_MLOCK) { 58267974Smckusick mp->mnt_flag |= MNT_MWAIT; 58367974Smckusick sleep((caddr_t)mp, PVFS); 58467974Smckusick continue; 58567974Smckusick } 58667974Smckusick if (error = VFS_ROOT(mp, &tdp)) 58767974Smckusick break; 58867974Smckusick vput(vp); 58967974Smckusick vp = tdp; 59067974Smckusick } 59138259Smckusick VOP_UNLOCK(vp); 59267974Smckusick if (error) { 59367974Smckusick vrele(vp); 59447540Skarels return (error); 59567974Smckusick } 59645914Smckusick vrele(fdp->fd_cdir); 59745914Smckusick fdp->fd_cdir = vp; 59847540Skarels return (0); 59938259Smckusick } 60038259Smckusick 60138259Smckusick /* 60237741Smckusick * Change current working directory (``.''). 60337741Smckusick */ 60442441Smckusick /* ARGSUSED */ 60568318Scgd int 60642441Smckusick chdir(p, uap, retval) 60745914Smckusick struct proc *p; 60868318Scgd struct chdir_args /* { 60968318Scgd syscallarg(char *) path; 61068318Scgd } */ *uap; 61168318Scgd register_t *retval; 61237741Smckusick { 61345914Smckusick register struct filedesc *fdp = p->p_fd; 61437741Smckusick int error; 61547540Skarels struct nameidata nd; 6166254Sroot 61768318Scgd NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, 61868318Scgd SCARG(uap, path), p); 61964410Sbostic if (error = change_dir(&nd, p)) 62047540Skarels return (error); 62145914Smckusick vrele(fdp->fd_cdir); 62252322Smckusick fdp->fd_cdir = nd.ni_vp; 62347540Skarels return (0); 62437741Smckusick } 6256254Sroot 62637741Smckusick /* 62737741Smckusick * Change notion of root (``/'') directory. 62837741Smckusick */ 62942441Smckusick /* ARGSUSED */ 63068318Scgd int 63142441Smckusick chroot(p, uap, retval) 63245914Smckusick struct proc *p; 63368318Scgd struct chroot_args /* { 63468318Scgd syscallarg(char *) path; 63568318Scgd } */ *uap; 63668318Scgd register_t *retval; 63737741Smckusick { 63845914Smckusick register struct filedesc *fdp = p->p_fd; 63937741Smckusick int error; 64047540Skarels struct nameidata nd; 64137741Smckusick 64247540Skarels if (error = suser(p->p_ucred, &p->p_acflag)) 64347540Skarels return (error); 64468318Scgd NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, 64568318Scgd SCARG(uap, path), p); 64664410Sbostic if (error = change_dir(&nd, p)) 64747540Skarels return (error); 64845914Smckusick if (fdp->fd_rdir != NULL) 64945914Smckusick vrele(fdp->fd_rdir); 65052322Smckusick fdp->fd_rdir = nd.ni_vp; 65147540Skarels return (0); 6526254Sroot } 6536254Sroot 65437Sbill /* 65537741Smckusick * Common routine for chroot and chdir. 65637741Smckusick */ 65764410Sbostic static int 65864410Sbostic change_dir(ndp, p) 65952322Smckusick register struct nameidata *ndp; 66047540Skarels struct proc *p; 66137741Smckusick { 66237741Smckusick struct vnode *vp; 66337741Smckusick int error; 66437741Smckusick 66552322Smckusick if (error = namei(ndp)) 66637741Smckusick return (error); 66737741Smckusick vp = ndp->ni_vp; 66837741Smckusick if (vp->v_type != VDIR) 66937741Smckusick error = ENOTDIR; 67037741Smckusick else 67148026Smckusick error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p); 67237741Smckusick VOP_UNLOCK(vp); 67337741Smckusick if (error) 67437741Smckusick vrele(vp); 67537741Smckusick return (error); 67637741Smckusick } 67737741Smckusick 67837741Smckusick /* 67942441Smckusick * Check permissions, allocate an open file structure, 68042441Smckusick * and call the device open routine if any. 6816254Sroot */ 68268318Scgd int 68342441Smckusick open(p, uap, retval) 68445914Smckusick struct proc *p; 68568318Scgd register struct open_args /* { 68668318Scgd syscallarg(char *) path; 68768318Scgd syscallarg(int) flags; 68868318Scgd syscallarg(int) mode; 68968318Scgd } */ *uap; 69068318Scgd register_t *retval; 6916254Sroot { 69245914Smckusick register struct filedesc *fdp = p->p_fd; 69342441Smckusick register struct file *fp; 69450111Smckusick register struct vnode *vp; 69564410Sbostic int flags, cmode; 69637741Smckusick struct file *nfp; 69749945Smckusick int type, indx, error; 69849945Smckusick struct flock lf; 69947540Skarels struct nameidata nd; 70037741Smckusick extern struct fileops vnops; 7016254Sroot 70245914Smckusick if (error = falloc(p, &nfp, &indx)) 70347540Skarels return (error); 70437741Smckusick fp = nfp; 70568318Scgd flags = FFLAGS(SCARG(uap, flags)); 70668318Scgd cmode = ((SCARG(uap, mode) &~ fdp->fd_cmask) & ALLPERMS) &~ S_ISTXT; 70768318Scgd NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 70845202Smckusick p->p_dupfd = -indx - 1; /* XXX check for fdopen */ 70964410Sbostic if (error = vn_open(&nd, flags, cmode)) { 71049980Smckusick ffree(fp); 71154723Smckusick if ((error == ENODEV || error == ENXIO) && 71268318Scgd p->p_dupfd >= 0 && /* XXX from fdopen */ 71364410Sbostic (error = 71468318Scgd dupfdopen(fdp, indx, p->p_dupfd, flags, error)) == 0) { 71542441Smckusick *retval = indx; 71647540Skarels return (0); 71742441Smckusick } 71840884Smckusick if (error == ERESTART) 71940884Smckusick error = EINTR; 72047688Skarels fdp->fd_ofiles[indx] = NULL; 72147540Skarels return (error); 72212756Ssam } 72353828Spendry p->p_dupfd = 0; 72452322Smckusick vp = nd.ni_vp; 72564410Sbostic fp->f_flag = flags & FMASK; 72654348Smckusick fp->f_type = DTYPE_VNODE; 72754348Smckusick fp->f_ops = &vnops; 72854348Smckusick fp->f_data = (caddr_t)vp; 72964410Sbostic if (flags & (O_EXLOCK | O_SHLOCK)) { 73049945Smckusick lf.l_whence = SEEK_SET; 73149945Smckusick lf.l_start = 0; 73249945Smckusick lf.l_len = 0; 73364410Sbostic if (flags & O_EXLOCK) 73449945Smckusick lf.l_type = F_WRLCK; 73549945Smckusick else 73649945Smckusick lf.l_type = F_RDLCK; 73749945Smckusick type = F_FLOCK; 73864410Sbostic if ((flags & FNONBLOCK) == 0) 73949945Smckusick type |= F_WAIT; 74065757Smckusick VOP_UNLOCK(vp); 74150111Smckusick if (error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, type)) { 74250111Smckusick (void) vn_close(vp, fp->f_flag, fp->f_cred, p); 74349980Smckusick ffree(fp); 74449945Smckusick fdp->fd_ofiles[indx] = NULL; 74549945Smckusick return (error); 74649945Smckusick } 74765757Smckusick VOP_LOCK(vp); 74849949Smckusick fp->f_flag |= FHASLOCK; 74949945Smckusick } 75050111Smckusick VOP_UNLOCK(vp); 75142441Smckusick *retval = indx; 75247540Skarels return (0); 7536254Sroot } 7546254Sroot 75542955Smckusick #ifdef COMPAT_43 7566254Sroot /* 75764410Sbostic * Create a file. 7586254Sroot */ 75968318Scgd int 76068318Scgd compat_43_creat(p, uap, retval) 76142441Smckusick struct proc *p; 76268318Scgd register struct compat_43_creat_args /* { 76368318Scgd syscallarg(char *) path; 76468318Scgd syscallarg(int) mode; 76568318Scgd } */ *uap; 76668318Scgd register_t *retval; 7676254Sroot { 76868318Scgd struct open_args /* { 76968318Scgd syscallarg(char *) path; 77068318Scgd syscallarg(int) flags; 77168318Scgd syscallarg(int) mode; 77268318Scgd } */ nuap; 77342441Smckusick 77468318Scgd SCARG(&nuap, path) = SCARG(uap, path); 77568318Scgd SCARG(&nuap, mode) = SCARG(uap, mode); 77668318Scgd SCARG(&nuap, flags) = O_WRONLY | O_CREAT | O_TRUNC; 77768318Scgd return (open(p, &nuap, retval)); 77842441Smckusick } 77942955Smckusick #endif /* COMPAT_43 */ 78042441Smckusick 78142441Smckusick /* 78264410Sbostic * Create a special file. 78342441Smckusick */ 78442441Smckusick /* ARGSUSED */ 78568318Scgd int 78642441Smckusick mknod(p, uap, retval) 78745914Smckusick struct proc *p; 78868318Scgd register struct mknod_args /* { 78968318Scgd syscallarg(char *) path; 79068318Scgd syscallarg(int) mode; 79168318Scgd syscallarg(int) dev; 79268318Scgd } */ *uap; 79368318Scgd register_t *retval; 79442441Smckusick { 79537741Smckusick register struct vnode *vp; 79637741Smckusick struct vattr vattr; 79737741Smckusick int error; 79867575Spendry int whiteout; 79947540Skarels struct nameidata nd; 8006254Sroot 80147540Skarels if (error = suser(p->p_ucred, &p->p_acflag)) 80247540Skarels return (error); 80368318Scgd NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p); 80452322Smckusick if (error = namei(&nd)) 80547540Skarels return (error); 80652322Smckusick vp = nd.ni_vp; 80764585Sbostic if (vp != NULL) 80837741Smckusick error = EEXIST; 80964585Sbostic else { 81064585Sbostic VATTR_NULL(&vattr); 81168318Scgd vattr.va_mode = (SCARG(uap, mode) & ALLPERMS) &~ p->p_fd->fd_cmask; 81268318Scgd vattr.va_rdev = SCARG(uap, dev); 81367575Spendry whiteout = 0; 81464585Sbostic 81568318Scgd switch (SCARG(uap, mode) & S_IFMT) { 81664585Sbostic case S_IFMT: /* used by badsect to flag bad sectors */ 81764585Sbostic vattr.va_type = VBAD; 81864585Sbostic break; 81964585Sbostic case S_IFCHR: 82064585Sbostic vattr.va_type = VCHR; 82164585Sbostic break; 82264585Sbostic case S_IFBLK: 82364585Sbostic vattr.va_type = VBLK; 82464585Sbostic break; 82567575Spendry case S_IFWHT: 82667575Spendry whiteout = 1; 82767575Spendry break; 82864585Sbostic default: 82964585Sbostic error = EINVAL; 83064585Sbostic break; 83164585Sbostic } 8326254Sroot } 83367747Spendry if (!error) { 83467654Smckusick VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 83567747Spendry if (whiteout) { 83667747Spendry error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, CREATE); 83767747Spendry if (error) 83867747Spendry VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 83967747Spendry vput(nd.ni_dvp); 84067747Spendry } else { 84167747Spendry error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, 84267747Spendry &nd.ni_cnd, &vattr); 84367747Spendry } 84442465Smckusick } else { 84552322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 84652322Smckusick if (nd.ni_dvp == vp) 84752322Smckusick vrele(nd.ni_dvp); 84843344Smckusick else 84952322Smckusick vput(nd.ni_dvp); 85042465Smckusick if (vp) 85142465Smckusick vrele(vp); 85242465Smckusick } 85347540Skarels return (error); 8546254Sroot } 8556254Sroot 8566254Sroot /* 85768318Scgd * Create a named pipe. 85840285Smckusick */ 85942441Smckusick /* ARGSUSED */ 86068318Scgd int 86142441Smckusick mkfifo(p, uap, retval) 86245914Smckusick struct proc *p; 86368318Scgd register struct mkfifo_args /* { 86468318Scgd syscallarg(char *) path; 86568318Scgd syscallarg(int) mode; 86668318Scgd } */ *uap; 86768318Scgd register_t *retval; 86842441Smckusick { 86940285Smckusick struct vattr vattr; 87040285Smckusick int error; 87147540Skarels struct nameidata nd; 87240285Smckusick 87340285Smckusick #ifndef FIFO 87447540Skarels return (EOPNOTSUPP); 87540285Smckusick #else 87668318Scgd NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p); 87752322Smckusick if (error = namei(&nd)) 87847540Skarels return (error); 87952322Smckusick if (nd.ni_vp != NULL) { 88052322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 88152322Smckusick if (nd.ni_dvp == nd.ni_vp) 88252322Smckusick vrele(nd.ni_dvp); 88343344Smckusick else 88452322Smckusick vput(nd.ni_dvp); 88552322Smckusick vrele(nd.ni_vp); 88647540Skarels return (EEXIST); 88740285Smckusick } 88845785Sbostic VATTR_NULL(&vattr); 88945785Sbostic vattr.va_type = VFIFO; 89068318Scgd vattr.va_mode = (SCARG(uap, mode) & ALLPERMS) &~ p->p_fd->fd_cmask; 89167654Smckusick VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 89252322Smckusick return (VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr)); 89340285Smckusick #endif /* FIFO */ 89440285Smckusick } 89540285Smckusick 89640285Smckusick /* 89764410Sbostic * Make a hard file link. 8986254Sroot */ 89942441Smckusick /* ARGSUSED */ 90068318Scgd int 90142441Smckusick link(p, uap, retval) 90245914Smckusick struct proc *p; 90368318Scgd register struct link_args /* { 90468318Scgd syscallarg(char *) path; 90568318Scgd syscallarg(char *) link; 90668318Scgd } */ *uap; 90768318Scgd register_t *retval; 90842441Smckusick { 90964410Sbostic register struct vnode *vp; 91064410Sbostic struct nameidata nd; 91137741Smckusick int error; 9126254Sroot 91368318Scgd NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 91452322Smckusick if (error = namei(&nd)) 91547540Skarels return (error); 91652322Smckusick vp = nd.ni_vp; 91764585Sbostic if (vp->v_type != VDIR || 91864585Sbostic (error = suser(p->p_ucred, &p->p_acflag)) == 0) { 91964585Sbostic nd.ni_cnd.cn_nameiop = CREATE; 92064585Sbostic nd.ni_cnd.cn_flags = LOCKPARENT; 92168318Scgd nd.ni_dirp = SCARG(uap, link); 92264585Sbostic if ((error = namei(&nd)) == 0) { 92364585Sbostic if (nd.ni_vp != NULL) 92464585Sbostic error = EEXIST; 92564585Sbostic if (!error) { 92667654Smckusick VOP_LEASE(nd.ni_dvp, p, p->p_ucred, 92767654Smckusick LEASE_WRITE); 92867654Smckusick VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 92968538Smckusick error = VOP_LINK(vp, nd.ni_dvp, &nd.ni_cnd); 93064585Sbostic } else { 93164585Sbostic VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 93264585Sbostic if (nd.ni_dvp == nd.ni_vp) 93364585Sbostic vrele(nd.ni_dvp); 93464585Sbostic else 93564585Sbostic vput(nd.ni_dvp); 93664585Sbostic if (nd.ni_vp) 93764585Sbostic vrele(nd.ni_vp); 93864585Sbostic } 93964585Sbostic } 94042465Smckusick } 94164585Sbostic vrele(vp); 94247540Skarels return (error); 9436254Sroot } 9446254Sroot 9456254Sroot /* 94649365Smckusick * Make a symbolic link. 9476254Sroot */ 94842441Smckusick /* ARGSUSED */ 94968318Scgd int 95042441Smckusick symlink(p, uap, retval) 95145914Smckusick struct proc *p; 95268318Scgd register struct symlink_args /* { 95368318Scgd syscallarg(char *) path; 95468318Scgd syscallarg(char *) link; 95568318Scgd } */ *uap; 95668318Scgd register_t *retval; 95742441Smckusick { 95837741Smckusick struct vattr vattr; 95964410Sbostic char *path; 96037741Smckusick int error; 96147540Skarels struct nameidata nd; 9626254Sroot 96364410Sbostic MALLOC(path, char *, MAXPATHLEN, M_NAMEI, M_WAITOK); 96468318Scgd if (error = copyinstr(SCARG(uap, path), path, MAXPATHLEN, NULL)) 96542465Smckusick goto out; 96668318Scgd NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, link), p); 96752322Smckusick if (error = namei(&nd)) 96842465Smckusick goto out; 96952322Smckusick if (nd.ni_vp) { 97052322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 97152322Smckusick if (nd.ni_dvp == nd.ni_vp) 97252322Smckusick vrele(nd.ni_dvp); 97343344Smckusick else 97452322Smckusick vput(nd.ni_dvp); 97552322Smckusick vrele(nd.ni_vp); 97637741Smckusick error = EEXIST; 97737741Smckusick goto out; 9786254Sroot } 97941362Smckusick VATTR_NULL(&vattr); 98064410Sbostic vattr.va_mode = ACCESSPERMS &~ p->p_fd->fd_cmask; 98167654Smckusick VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 98264410Sbostic error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr, path); 98337741Smckusick out: 98464410Sbostic FREE(path, M_NAMEI); 98547540Skarels return (error); 9866254Sroot } 9876254Sroot 9886254Sroot /* 98967518Spendry * Delete a whiteout from the filesystem. 99067518Spendry */ 99167518Spendry /* ARGSUSED */ 99268318Scgd int 99367845Smckusick undelete(p, uap, retval) 99467518Spendry struct proc *p; 99568318Scgd register struct undelete_args /* { 99668318Scgd syscallarg(char *) path; 99768318Scgd } */ *uap; 99868318Scgd register_t *retval; 99967518Spendry { 100067518Spendry int error; 100167518Spendry struct nameidata nd; 100267518Spendry 100368318Scgd NDINIT(&nd, DELETE, LOCKPARENT|DOWHITEOUT, UIO_USERSPACE, 100468318Scgd SCARG(uap, path), p); 100567575Spendry error = namei(&nd); 100667575Spendry if (error) 100767518Spendry return (error); 100867575Spendry 100967575Spendry if (nd.ni_vp != NULLVP || !(nd.ni_cnd.cn_flags & ISWHITEOUT)) { 101067518Spendry VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 101167518Spendry if (nd.ni_dvp == nd.ni_vp) 101267518Spendry vrele(nd.ni_dvp); 101367518Spendry else 101467518Spendry vput(nd.ni_dvp); 101567518Spendry if (nd.ni_vp) 101667518Spendry vrele(nd.ni_vp); 101767518Spendry return (EEXIST); 101867518Spendry } 101967575Spendry 102067654Smckusick VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 102167747Spendry if (error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, DELETE)) 102267575Spendry VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 102367518Spendry vput(nd.ni_dvp); 102467518Spendry return (error); 102567518Spendry } 102667518Spendry 102767518Spendry /* 102849365Smckusick * Delete a name from the filesystem. 10296254Sroot */ 103042441Smckusick /* ARGSUSED */ 103168318Scgd int 103242441Smckusick unlink(p, uap, retval) 103345914Smckusick struct proc *p; 103468318Scgd struct unlink_args /* { 103568318Scgd syscallarg(char *) path; 103668318Scgd } */ *uap; 103768318Scgd register_t *retval; 10386254Sroot { 103937741Smckusick register struct vnode *vp; 104037741Smckusick int error; 104147540Skarels struct nameidata nd; 10426254Sroot 104368318Scgd NDINIT(&nd, DELETE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p); 104452322Smckusick if (error = namei(&nd)) 104547540Skarels return (error); 104652322Smckusick vp = nd.ni_vp; 104767654Smckusick VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 104859382Smckusick VOP_LOCK(vp); 104964410Sbostic 105064585Sbostic if (vp->v_type != VDIR || 105164585Sbostic (error = suser(p->p_ucred, &p->p_acflag)) == 0) { 105264585Sbostic /* 105364585Sbostic * The root of a mounted filesystem cannot be deleted. 105464585Sbostic */ 105564585Sbostic if (vp->v_flag & VROOT) 105664585Sbostic error = EBUSY; 105764585Sbostic else 105864585Sbostic (void)vnode_pager_uncache(vp); 105964585Sbostic } 106064585Sbostic 106164585Sbostic if (!error) { 106267654Smckusick VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 106352322Smckusick error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); 106442465Smckusick } else { 106552322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 106652322Smckusick if (nd.ni_dvp == vp) 106752322Smckusick vrele(nd.ni_dvp); 106843344Smckusick else 106952322Smckusick vput(nd.ni_dvp); 107067575Spendry if (vp != NULLVP) 107167575Spendry vput(vp); 107242465Smckusick } 107347540Skarels return (error); 10746254Sroot } 10756254Sroot 107664410Sbostic /* 107764410Sbostic * Reposition read/write file offset. 107864410Sbostic */ 107968318Scgd int 108060414Smckusick lseek(p, uap, retval) 108153468Smckusick struct proc *p; 108268318Scgd register struct lseek_args /* { 108368318Scgd syscallarg(int) fd; 108468318Scgd syscallarg(int) pad; 108568318Scgd syscallarg(off_t) offset; 108668318Scgd syscallarg(int) whence; 108768318Scgd } */ *uap; 108868318Scgd register_t *retval; 108942441Smckusick { 109047540Skarels struct ucred *cred = p->p_ucred; 109145914Smckusick register struct filedesc *fdp = p->p_fd; 109242441Smckusick register struct file *fp; 109337741Smckusick struct vattr vattr; 109437741Smckusick int error; 10956254Sroot 109668318Scgd if ((u_int)SCARG(uap, fd) >= fdp->fd_nfiles || 109768318Scgd (fp = fdp->fd_ofiles[SCARG(uap, fd)]) == NULL) 109847540Skarels return (EBADF); 109937741Smckusick if (fp->f_type != DTYPE_VNODE) 110047540Skarels return (ESPIPE); 110168318Scgd switch (SCARG(uap, whence)) { 110213878Ssam case L_INCR: 110368318Scgd fp->f_offset += SCARG(uap, offset); 110413878Ssam break; 110513878Ssam case L_XTND: 110664410Sbostic if (error = 110764410Sbostic VOP_GETATTR((struct vnode *)fp->f_data, &vattr, cred, p)) 110847540Skarels return (error); 110968318Scgd fp->f_offset = SCARG(uap, offset) + vattr.va_size; 111013878Ssam break; 111113878Ssam case L_SET: 111268318Scgd fp->f_offset = SCARG(uap, offset); 111313878Ssam break; 111413878Ssam default: 111547540Skarels return (EINVAL); 111613878Ssam } 111754916Storek *(off_t *)retval = fp->f_offset; 111847540Skarels return (0); 11196254Sroot } 11206254Sroot 112160414Smckusick #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 11226254Sroot /* 112364410Sbostic * Reposition read/write file offset. 112460036Smckusick */ 112568318Scgd int 112668318Scgd compat_43_lseek(p, uap, retval) 112760036Smckusick struct proc *p; 112868318Scgd register struct compat_43_lseek_args /* { 112968318Scgd syscallarg(int) fd; 113068318Scgd syscallarg(long) offset; 113168318Scgd syscallarg(int) whence; 113268318Scgd } */ *uap; 113368318Scgd register_t *retval; 113460036Smckusick { 113568318Scgd struct lseek_args /* { 113668318Scgd syscallarg(int) fd; 113768318Scgd syscallarg(int) pad; 113868318Scgd syscallarg(off_t) offset; 113968318Scgd syscallarg(int) whence; 114068318Scgd } */ nuap; 114160036Smckusick off_t qret; 114260036Smckusick int error; 114360036Smckusick 114468318Scgd SCARG(&nuap, fd) = SCARG(uap, fd); 114568318Scgd SCARG(&nuap, offset) = SCARG(uap, offset); 114668318Scgd SCARG(&nuap, whence) = SCARG(uap, whence); 114760428Smckusick error = lseek(p, &nuap, &qret); 114860036Smckusick *(long *)retval = qret; 114960036Smckusick return (error); 115060036Smckusick } 115160414Smckusick #endif /* COMPAT_43 */ 115260036Smckusick 115360036Smckusick /* 115449365Smckusick * Check access permissions. 11556254Sroot */ 115668318Scgd int 115763427Sbostic access(p, uap, retval) 115845914Smckusick struct proc *p; 115968318Scgd register struct access_args /* { 116068318Scgd syscallarg(char *) path; 116168318Scgd syscallarg(int) flags; 116268318Scgd } */ *uap; 116368318Scgd register_t *retval; 116442441Smckusick { 116547540Skarels register struct ucred *cred = p->p_ucred; 116637741Smckusick register struct vnode *vp; 116764585Sbostic int error, flags, t_gid, t_uid; 116847540Skarels struct nameidata nd; 11696254Sroot 117064585Sbostic t_uid = cred->cr_uid; 117164585Sbostic t_gid = cred->cr_groups[0]; 117247540Skarels cred->cr_uid = p->p_cred->p_ruid; 117347540Skarels cred->cr_groups[0] = p->p_cred->p_rgid; 117468318Scgd NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, 117568318Scgd SCARG(uap, path), p); 117652322Smckusick if (error = namei(&nd)) 117737741Smckusick goto out1; 117852322Smckusick vp = nd.ni_vp; 117964410Sbostic 118064410Sbostic /* Flags == 0 means only check for existence. */ 118168318Scgd if (SCARG(uap, flags)) { 118264410Sbostic flags = 0; 118368318Scgd if (SCARG(uap, flags) & R_OK) 118464410Sbostic flags |= VREAD; 118568318Scgd if (SCARG(uap, flags) & W_OK) 118664410Sbostic flags |= VWRITE; 118768318Scgd if (SCARG(uap, flags) & X_OK) 118864410Sbostic flags |= VEXEC; 118964410Sbostic if ((flags & VWRITE) == 0 || (error = vn_writechk(vp)) == 0) 119064410Sbostic error = VOP_ACCESS(vp, flags, cred, p); 11916254Sroot } 119237741Smckusick vput(vp); 119337741Smckusick out1: 119464585Sbostic cred->cr_uid = t_uid; 119564585Sbostic cred->cr_groups[0] = t_gid; 119647540Skarels return (error); 11976254Sroot } 11986254Sroot 119954348Smckusick #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 12006254Sroot /* 120164410Sbostic * Get file status; this version follows links. 120237Sbill */ 120342441Smckusick /* ARGSUSED */ 120468318Scgd int 120568318Scgd compat_43_stat(p, uap, retval) 120645914Smckusick struct proc *p; 120768318Scgd register struct compat_43_stat_args /* { 120868318Scgd syscallarg(char *) path; 120968318Scgd syscallarg(struct ostat *) ub; 121068318Scgd } */ *uap; 121168318Scgd register_t *retval; 121253468Smckusick { 121353468Smckusick struct stat sb; 121453468Smckusick struct ostat osb; 121553468Smckusick int error; 121653468Smckusick struct nameidata nd; 121753468Smckusick 121868318Scgd NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, 121968318Scgd SCARG(uap, path), p); 122053468Smckusick if (error = namei(&nd)) 122153468Smckusick return (error); 122253468Smckusick error = vn_stat(nd.ni_vp, &sb, p); 122353468Smckusick vput(nd.ni_vp); 122453468Smckusick if (error) 122553468Smckusick return (error); 122653468Smckusick cvtstat(&sb, &osb); 122768318Scgd error = copyout((caddr_t)&osb, (caddr_t)SCARG(uap, ub), sizeof (osb)); 122853468Smckusick return (error); 122953468Smckusick } 123053468Smckusick 123153468Smckusick /* 123264410Sbostic * Get file status; this version does not follow links. 123353468Smckusick */ 123453468Smckusick /* ARGSUSED */ 123568318Scgd int 123668318Scgd compat_43_lstat(p, uap, retval) 123753468Smckusick struct proc *p; 123868318Scgd register struct compat_43_lstat_args /* { 123968318Scgd syscallarg(char *) path; 124068318Scgd syscallarg(struct ostat *) ub; 124168318Scgd } */ *uap; 124268318Scgd register_t *retval; 124353468Smckusick { 124467748Smckusick struct vnode *vp, *dvp; 124567748Smckusick struct stat sb, sb1; 124653468Smckusick struct ostat osb; 124753468Smckusick int error; 124853468Smckusick struct nameidata nd; 124953468Smckusick 125067748Smckusick NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | LOCKPARENT, UIO_USERSPACE, 125168318Scgd SCARG(uap, path), p); 125253468Smckusick if (error = namei(&nd)) 125353468Smckusick return (error); 125467748Smckusick /* 125567748Smckusick * For symbolic links, always return the attributes of its 125667748Smckusick * containing directory, except for mode, size, and links. 125767748Smckusick */ 125867748Smckusick vp = nd.ni_vp; 125967748Smckusick dvp = nd.ni_dvp; 126067748Smckusick if (vp->v_type != VLNK) { 126167748Smckusick if (dvp == vp) 126267748Smckusick vrele(dvp); 126367748Smckusick else 126467748Smckusick vput(dvp); 126567748Smckusick error = vn_stat(vp, &sb, p); 126667748Smckusick vput(vp); 126767748Smckusick if (error) 126867748Smckusick return (error); 126967748Smckusick } else { 127067748Smckusick error = vn_stat(dvp, &sb, p); 127167748Smckusick vput(dvp); 127267748Smckusick if (error) { 127367748Smckusick vput(vp); 127467748Smckusick return (error); 127567748Smckusick } 127667748Smckusick error = vn_stat(vp, &sb1, p); 127767748Smckusick vput(vp); 127867748Smckusick if (error) 127967748Smckusick return (error); 128067748Smckusick sb.st_mode &= ~S_IFDIR; 128167748Smckusick sb.st_mode |= S_IFLNK; 128267748Smckusick sb.st_nlink = sb1.st_nlink; 128367748Smckusick sb.st_size = sb1.st_size; 128467748Smckusick sb.st_blocks = sb1.st_blocks; 128567748Smckusick } 128653468Smckusick cvtstat(&sb, &osb); 128768318Scgd error = copyout((caddr_t)&osb, (caddr_t)SCARG(uap, ub), sizeof (osb)); 128853468Smckusick return (error); 128953468Smckusick } 129053468Smckusick 129153468Smckusick /* 129264410Sbostic * Convert from an old to a new stat structure. 129353468Smckusick */ 129468318Scgd void 129553468Smckusick cvtstat(st, ost) 129653468Smckusick struct stat *st; 129753468Smckusick struct ostat *ost; 129853468Smckusick { 129953468Smckusick 130053468Smckusick ost->st_dev = st->st_dev; 130153468Smckusick ost->st_ino = st->st_ino; 130253468Smckusick ost->st_mode = st->st_mode; 130353468Smckusick ost->st_nlink = st->st_nlink; 130453468Smckusick ost->st_uid = st->st_uid; 130553468Smckusick ost->st_gid = st->st_gid; 130653468Smckusick ost->st_rdev = st->st_rdev; 130753468Smckusick if (st->st_size < (quad_t)1 << 32) 130853468Smckusick ost->st_size = st->st_size; 130953468Smckusick else 131053468Smckusick ost->st_size = -2; 131153468Smckusick ost->st_atime = st->st_atime; 131253468Smckusick ost->st_mtime = st->st_mtime; 131353468Smckusick ost->st_ctime = st->st_ctime; 131453468Smckusick ost->st_blksize = st->st_blksize; 131553468Smckusick ost->st_blocks = st->st_blocks; 131653468Smckusick ost->st_flags = st->st_flags; 131753468Smckusick ost->st_gen = st->st_gen; 131853468Smckusick } 131954348Smckusick #endif /* COMPAT_43 || COMPAT_SUNOS */ 132053468Smckusick 132153468Smckusick /* 132264410Sbostic * Get file status; this version follows links. 132353468Smckusick */ 132453468Smckusick /* ARGSUSED */ 132568318Scgd int 132653759Smckusick stat(p, uap, retval) 132753468Smckusick struct proc *p; 132868318Scgd register struct stat_args /* { 132968318Scgd syscallarg(char *) path; 133068318Scgd syscallarg(struct stat *) ub; 133168318Scgd } */ *uap; 133268318Scgd register_t *retval; 133337Sbill { 133442441Smckusick struct stat sb; 133542441Smckusick int error; 133647540Skarels struct nameidata nd; 133737Sbill 133868318Scgd NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, 133968318Scgd SCARG(uap, path), p); 134052322Smckusick if (error = namei(&nd)) 134147540Skarels return (error); 134252322Smckusick error = vn_stat(nd.ni_vp, &sb, p); 134352322Smckusick vput(nd.ni_vp); 134442441Smckusick if (error) 134547540Skarels return (error); 134668318Scgd error = copyout((caddr_t)&sb, (caddr_t)SCARG(uap, ub), sizeof (sb)); 134747540Skarels return (error); 134837Sbill } 134937Sbill 135037Sbill /* 135164410Sbostic * Get file status; this version does not follow links. 13525992Swnj */ 135342441Smckusick /* ARGSUSED */ 135468318Scgd int 135553759Smckusick lstat(p, uap, retval) 135645914Smckusick struct proc *p; 135768318Scgd register struct lstat_args /* { 135868318Scgd syscallarg(char *) path; 135968318Scgd syscallarg(struct stat *) ub; 136068318Scgd } */ *uap; 136168318Scgd register_t *retval; 136242441Smckusick { 136337741Smckusick int error; 136459373Smckusick struct vnode *vp, *dvp; 136559373Smckusick struct stat sb, sb1; 136647540Skarels struct nameidata nd; 13675992Swnj 136859373Smckusick NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | LOCKPARENT, UIO_USERSPACE, 136968318Scgd SCARG(uap, path), p); 137052322Smckusick if (error = namei(&nd)) 137147540Skarels return (error); 137259373Smckusick /* 137368579Smckusick * For symbolic links, always return the attributes of its containing 137468579Smckusick * directory, except for mode, size, inode number, and links. 137559373Smckusick */ 137659373Smckusick vp = nd.ni_vp; 137759373Smckusick dvp = nd.ni_dvp; 137859373Smckusick if (vp->v_type != VLNK) { 137959373Smckusick if (dvp == vp) 138059373Smckusick vrele(dvp); 138159373Smckusick else 138259373Smckusick vput(dvp); 138359373Smckusick error = vn_stat(vp, &sb, p); 138459373Smckusick vput(vp); 138559373Smckusick if (error) 138659373Smckusick return (error); 138759373Smckusick } else { 138859373Smckusick error = vn_stat(dvp, &sb, p); 138959373Smckusick vput(dvp); 139059373Smckusick if (error) { 139159373Smckusick vput(vp); 139259373Smckusick return (error); 139359373Smckusick } 139459373Smckusick error = vn_stat(vp, &sb1, p); 139559373Smckusick vput(vp); 139659373Smckusick if (error) 139759373Smckusick return (error); 139859373Smckusick sb.st_mode &= ~S_IFDIR; 139959373Smckusick sb.st_mode |= S_IFLNK; 140059373Smckusick sb.st_nlink = sb1.st_nlink; 140159373Smckusick sb.st_size = sb1.st_size; 140259373Smckusick sb.st_blocks = sb1.st_blocks; 140368579Smckusick sb.st_ino = sb1.st_ino; 140459373Smckusick } 140568318Scgd error = copyout((caddr_t)&sb, (caddr_t)SCARG(uap, ub), sizeof (sb)); 140647540Skarels return (error); 14075992Swnj } 14085992Swnj 14095992Swnj /* 141064410Sbostic * Get configurable pathname variables. 141160414Smckusick */ 141260414Smckusick /* ARGSUSED */ 141368318Scgd int 141460414Smckusick pathconf(p, uap, retval) 141560414Smckusick struct proc *p; 141668318Scgd register struct pathconf_args /* { 141768318Scgd syscallarg(char *) path; 141868318Scgd syscallarg(int) name; 141968318Scgd } */ *uap; 142068318Scgd register_t *retval; 142160414Smckusick { 142260414Smckusick int error; 142360414Smckusick struct nameidata nd; 142460414Smckusick 142568318Scgd NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, 142668318Scgd SCARG(uap, path), p); 142760414Smckusick if (error = namei(&nd)) 142860414Smckusick return (error); 142968318Scgd error = VOP_PATHCONF(nd.ni_vp, SCARG(uap, name), retval); 143060414Smckusick vput(nd.ni_vp); 143160414Smckusick return (error); 143260414Smckusick } 143360414Smckusick 143460414Smckusick /* 143549365Smckusick * Return target name of a symbolic link. 143637Sbill */ 143742441Smckusick /* ARGSUSED */ 143868318Scgd int 143942441Smckusick readlink(p, uap, retval) 144045914Smckusick struct proc *p; 144168318Scgd register struct readlink_args /* { 144268318Scgd syscallarg(char *) path; 144368318Scgd syscallarg(char *) buf; 144468318Scgd syscallarg(int) count; 144568318Scgd } */ *uap; 144668318Scgd register_t *retval; 144742441Smckusick { 144837741Smckusick register struct vnode *vp; 144937741Smckusick struct iovec aiov; 145037741Smckusick struct uio auio; 145137741Smckusick int error; 145247540Skarels struct nameidata nd; 14535992Swnj 145468318Scgd NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, 145568318Scgd SCARG(uap, path), p); 145652322Smckusick if (error = namei(&nd)) 145747540Skarels return (error); 145852322Smckusick vp = nd.ni_vp; 145964410Sbostic if (vp->v_type != VLNK) 146037741Smckusick error = EINVAL; 146164410Sbostic else { 146268318Scgd aiov.iov_base = SCARG(uap, buf); 146368318Scgd aiov.iov_len = SCARG(uap, count); 146464410Sbostic auio.uio_iov = &aiov; 146564410Sbostic auio.uio_iovcnt = 1; 146664410Sbostic auio.uio_offset = 0; 146764410Sbostic auio.uio_rw = UIO_READ; 146864410Sbostic auio.uio_segflg = UIO_USERSPACE; 146964410Sbostic auio.uio_procp = p; 147068318Scgd auio.uio_resid = SCARG(uap, count); 147164410Sbostic error = VOP_READLINK(vp, &auio, p->p_ucred); 14725992Swnj } 147337741Smckusick vput(vp); 147468318Scgd *retval = SCARG(uap, count) - auio.uio_resid; 147547540Skarels return (error); 14765992Swnj } 14775992Swnj 14789167Ssam /* 147964410Sbostic * Change flags of a file given a path name. 148038259Smckusick */ 148142441Smckusick /* ARGSUSED */ 148268318Scgd int 148342441Smckusick chflags(p, uap, retval) 148445914Smckusick struct proc *p; 148568318Scgd register struct chflags_args /* { 148668318Scgd syscallarg(char *) path; 148768318Scgd syscallarg(int) flags; 148868318Scgd } */ *uap; 148968318Scgd register_t *retval; 149042441Smckusick { 149138259Smckusick register struct vnode *vp; 149238259Smckusick struct vattr vattr; 149338259Smckusick int error; 149447540Skarels struct nameidata nd; 149538259Smckusick 149668318Scgd NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 149752322Smckusick if (error = namei(&nd)) 149847540Skarels return (error); 149952322Smckusick vp = nd.ni_vp; 150067654Smckusick VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 150159382Smckusick VOP_LOCK(vp); 150264410Sbostic if (vp->v_mount->mnt_flag & MNT_RDONLY) 150338259Smckusick error = EROFS; 150464410Sbostic else { 150564410Sbostic VATTR_NULL(&vattr); 150668318Scgd vattr.va_flags = SCARG(uap, flags); 150764410Sbostic error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 150838259Smckusick } 150938259Smckusick vput(vp); 151047540Skarels return (error); 151138259Smckusick } 151238259Smckusick 151338259Smckusick /* 151438259Smckusick * Change flags of a file given a file descriptor. 151538259Smckusick */ 151642441Smckusick /* ARGSUSED */ 151768318Scgd int 151842441Smckusick fchflags(p, uap, retval) 151945914Smckusick struct proc *p; 152068318Scgd register struct fchflags_args /* { 152168318Scgd syscallarg(int) fd; 152268318Scgd syscallarg(int) flags; 152368318Scgd } */ *uap; 152468318Scgd register_t *retval; 152542441Smckusick { 152638259Smckusick struct vattr vattr; 152738259Smckusick struct vnode *vp; 152838259Smckusick struct file *fp; 152938259Smckusick int error; 153038259Smckusick 153168318Scgd if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) 153247540Skarels return (error); 153338259Smckusick vp = (struct vnode *)fp->f_data; 153467654Smckusick VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 153538259Smckusick VOP_LOCK(vp); 153664410Sbostic if (vp->v_mount->mnt_flag & MNT_RDONLY) 153738259Smckusick error = EROFS; 153864410Sbostic else { 153964410Sbostic VATTR_NULL(&vattr); 154068318Scgd vattr.va_flags = SCARG(uap, flags); 154164410Sbostic error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 154238259Smckusick } 154338259Smckusick VOP_UNLOCK(vp); 154447540Skarels return (error); 154538259Smckusick } 154638259Smckusick 154738259Smckusick /* 15489167Ssam * Change mode of a file given path name. 15499167Ssam */ 155042441Smckusick /* ARGSUSED */ 155168318Scgd int 155242441Smckusick chmod(p, uap, retval) 155345914Smckusick struct proc *p; 155468318Scgd register struct chmod_args /* { 155568318Scgd syscallarg(char *) path; 155668318Scgd syscallarg(int) mode; 155768318Scgd } */ *uap; 155868318Scgd register_t *retval; 155942441Smckusick { 156037741Smckusick register struct vnode *vp; 156137741Smckusick struct vattr vattr; 156237741Smckusick int error; 156347540Skarels struct nameidata nd; 15645992Swnj 156568318Scgd NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 156652322Smckusick if (error = namei(&nd)) 156747540Skarels return (error); 156852322Smckusick vp = nd.ni_vp; 156967654Smckusick VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 157059382Smckusick VOP_LOCK(vp); 157164410Sbostic if (vp->v_mount->mnt_flag & MNT_RDONLY) 157237741Smckusick error = EROFS; 157364410Sbostic else { 157464410Sbostic VATTR_NULL(&vattr); 157568318Scgd vattr.va_mode = SCARG(uap, mode) & ALLPERMS; 157664410Sbostic error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 157737741Smckusick } 157837741Smckusick vput(vp); 157947540Skarels return (error); 15807701Ssam } 15817439Sroot 15829167Ssam /* 15839167Ssam * Change mode of a file given a file descriptor. 15849167Ssam */ 158542441Smckusick /* ARGSUSED */ 158668318Scgd int 158742441Smckusick fchmod(p, uap, retval) 158845914Smckusick struct proc *p; 158968318Scgd register struct fchmod_args /* { 159068318Scgd syscallarg(int) fd; 159168318Scgd syscallarg(int) mode; 159268318Scgd } */ *uap; 159368318Scgd register_t *retval; 159442441Smckusick { 159537741Smckusick struct vattr vattr; 159637741Smckusick struct vnode *vp; 159737741Smckusick struct file *fp; 159837741Smckusick int error; 15997701Ssam 160068318Scgd if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) 160147540Skarels return (error); 160237741Smckusick vp = (struct vnode *)fp->f_data; 160367654Smckusick VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 160437741Smckusick VOP_LOCK(vp); 160564410Sbostic if (vp->v_mount->mnt_flag & MNT_RDONLY) 160637741Smckusick error = EROFS; 160764410Sbostic else { 160864410Sbostic VATTR_NULL(&vattr); 160968318Scgd vattr.va_mode = SCARG(uap, mode) & ALLPERMS; 161064410Sbostic error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 16117439Sroot } 161237741Smckusick VOP_UNLOCK(vp); 161347540Skarels return (error); 16145992Swnj } 16155992Swnj 16169167Ssam /* 16179167Ssam * Set ownership given a path name. 16189167Ssam */ 161942441Smckusick /* ARGSUSED */ 162068318Scgd int 162142441Smckusick chown(p, uap, retval) 162245914Smckusick struct proc *p; 162368318Scgd register struct chown_args /* { 162468318Scgd syscallarg(char *) path; 162568318Scgd syscallarg(int) uid; 162668318Scgd syscallarg(int) gid; 162768318Scgd } */ *uap; 162868318Scgd register_t *retval; 162942441Smckusick { 163037741Smckusick register struct vnode *vp; 163137741Smckusick struct vattr vattr; 163237741Smckusick int error; 163347540Skarels struct nameidata nd; 163437Sbill 163568318Scgd NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 163652322Smckusick if (error = namei(&nd)) 163747540Skarels return (error); 163852322Smckusick vp = nd.ni_vp; 163967654Smckusick VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 164059382Smckusick VOP_LOCK(vp); 164164410Sbostic if (vp->v_mount->mnt_flag & MNT_RDONLY) 164237741Smckusick error = EROFS; 164364410Sbostic else { 164464410Sbostic VATTR_NULL(&vattr); 164568318Scgd vattr.va_uid = SCARG(uap, uid); 164668318Scgd vattr.va_gid = SCARG(uap, gid); 164764410Sbostic error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 164837741Smckusick } 164937741Smckusick vput(vp); 165047540Skarels return (error); 16517701Ssam } 16527439Sroot 16539167Ssam /* 16549167Ssam * Set ownership given a file descriptor. 16559167Ssam */ 165642441Smckusick /* ARGSUSED */ 165768318Scgd int 165842441Smckusick fchown(p, uap, retval) 165945914Smckusick struct proc *p; 166068318Scgd register struct fchown_args /* { 166168318Scgd syscallarg(int) fd; 166268318Scgd syscallarg(int) uid; 166368318Scgd syscallarg(int) gid; 166468318Scgd } */ *uap; 166568318Scgd register_t *retval; 166642441Smckusick { 166737741Smckusick struct vattr vattr; 166837741Smckusick struct vnode *vp; 166937741Smckusick struct file *fp; 167037741Smckusick int error; 16717701Ssam 167268318Scgd if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) 167347540Skarels return (error); 167437741Smckusick vp = (struct vnode *)fp->f_data; 167567654Smckusick VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 167637741Smckusick VOP_LOCK(vp); 167764410Sbostic if (vp->v_mount->mnt_flag & MNT_RDONLY) 167837741Smckusick error = EROFS; 167964410Sbostic else { 168064410Sbostic VATTR_NULL(&vattr); 168168318Scgd vattr.va_uid = SCARG(uap, uid); 168268318Scgd vattr.va_gid = SCARG(uap, gid); 168364410Sbostic error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 168437741Smckusick } 168537741Smckusick VOP_UNLOCK(vp); 168647540Skarels return (error); 16877701Ssam } 16887701Ssam 168942441Smckusick /* 169042441Smckusick * Set the access and modification times of a file. 169142441Smckusick */ 169242441Smckusick /* ARGSUSED */ 169368318Scgd int 169442441Smckusick utimes(p, uap, retval) 169545914Smckusick struct proc *p; 169668318Scgd register struct utimes_args /* { 169768318Scgd syscallarg(char *) path; 169868318Scgd syscallarg(struct timeval *) tptr; 169968318Scgd } */ *uap; 170068318Scgd register_t *retval; 170142441Smckusick { 170237741Smckusick register struct vnode *vp; 170311811Ssam struct timeval tv[2]; 170437741Smckusick struct vattr vattr; 170558840Storek int error; 170647540Skarels struct nameidata nd; 170711811Ssam 170858505Sbostic VATTR_NULL(&vattr); 170968318Scgd if (SCARG(uap, tptr) == NULL) { 171058505Sbostic microtime(&tv[0]); 171158505Sbostic tv[1] = tv[0]; 171258548Sbostic vattr.va_vaflags |= VA_UTIMES_NULL; 171368318Scgd } else if (error = copyin((caddr_t)SCARG(uap, tptr), (caddr_t)tv, 171468318Scgd sizeof (tv))) 171558505Sbostic return (error); 171668318Scgd NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 171752322Smckusick if (error = namei(&nd)) 171847540Skarels return (error); 171952322Smckusick vp = nd.ni_vp; 172067654Smckusick VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 172159382Smckusick VOP_LOCK(vp); 172264410Sbostic if (vp->v_mount->mnt_flag & MNT_RDONLY) 172337741Smckusick error = EROFS; 172464410Sbostic else { 172564410Sbostic vattr.va_atime.ts_sec = tv[0].tv_sec; 172664410Sbostic vattr.va_atime.ts_nsec = tv[0].tv_usec * 1000; 172764410Sbostic vattr.va_mtime.ts_sec = tv[1].tv_sec; 172864410Sbostic vattr.va_mtime.ts_nsec = tv[1].tv_usec * 1000; 172964410Sbostic error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 173021015Smckusick } 173137741Smckusick vput(vp); 173247540Skarels return (error); 173311811Ssam } 173411811Ssam 173564410Sbostic /* 173664410Sbostic * Truncate a file given its path name. 173764410Sbostic */ 173853468Smckusick /* ARGSUSED */ 173968318Scgd int 174060414Smckusick truncate(p, uap, retval) 174153468Smckusick struct proc *p; 174268318Scgd register struct truncate_args /* { 174368318Scgd syscallarg(char *) path; 174468318Scgd syscallarg(int) pad; 174568318Scgd syscallarg(off_t) length; 174668318Scgd } */ *uap; 174768318Scgd register_t *retval; 174853468Smckusick { 174937741Smckusick register struct vnode *vp; 175037741Smckusick struct vattr vattr; 175137741Smckusick int error; 175247540Skarels struct nameidata nd; 17537701Ssam 175468318Scgd NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 175552322Smckusick if (error = namei(&nd)) 175647540Skarels return (error); 175752322Smckusick vp = nd.ni_vp; 175867654Smckusick VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 175959382Smckusick VOP_LOCK(vp); 176064410Sbostic if (vp->v_type == VDIR) 176137741Smckusick error = EISDIR; 176264410Sbostic else if ((error = vn_writechk(vp)) == 0 && 176364410Sbostic (error = VOP_ACCESS(vp, VWRITE, p->p_ucred, p)) == 0) { 176464410Sbostic VATTR_NULL(&vattr); 176568318Scgd vattr.va_size = SCARG(uap, length); 176664410Sbostic error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 17677701Ssam } 176837741Smckusick vput(vp); 176947540Skarels return (error); 17707701Ssam } 17717701Ssam 177264410Sbostic /* 177364410Sbostic * Truncate a file given a file descriptor. 177464410Sbostic */ 177542441Smckusick /* ARGSUSED */ 177668318Scgd int 177760414Smckusick ftruncate(p, uap, retval) 177845914Smckusick struct proc *p; 177968318Scgd register struct ftruncate_args /* { 178068318Scgd syscallarg(int) fd; 178168318Scgd syscallarg(int) pad; 178268318Scgd syscallarg(off_t) length; 178368318Scgd } */ *uap; 178468318Scgd register_t *retval; 178542441Smckusick { 178637741Smckusick struct vattr vattr; 178737741Smckusick struct vnode *vp; 17887701Ssam struct file *fp; 178937741Smckusick int error; 17907701Ssam 179168318Scgd if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) 179247540Skarels return (error); 179337741Smckusick if ((fp->f_flag & FWRITE) == 0) 179447540Skarels return (EINVAL); 179537741Smckusick vp = (struct vnode *)fp->f_data; 179667654Smckusick VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 179737741Smckusick VOP_LOCK(vp); 179864410Sbostic if (vp->v_type == VDIR) 179937741Smckusick error = EISDIR; 180064410Sbostic else if ((error = vn_writechk(vp)) == 0) { 180164410Sbostic VATTR_NULL(&vattr); 180268318Scgd vattr.va_size = SCARG(uap, length); 180364410Sbostic error = VOP_SETATTR(vp, &vattr, fp->f_cred, p); 18047701Ssam } 180537741Smckusick VOP_UNLOCK(vp); 180647540Skarels return (error); 18077701Ssam } 18087701Ssam 180954863Storek #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 18109167Ssam /* 181154863Storek * Truncate a file given its path name. 181254863Storek */ 181354863Storek /* ARGSUSED */ 181468318Scgd int 181568318Scgd compat_43_truncate(p, uap, retval) 181654863Storek struct proc *p; 181768318Scgd register struct compat_43_truncate_args /* { 181868318Scgd syscallarg(char *) path; 181968318Scgd syscallarg(long) length; 182068318Scgd } */ *uap; 182168318Scgd register_t *retval; 182254863Storek { 182368318Scgd struct truncate_args /* { 182468318Scgd syscallarg(char *) path; 182568318Scgd syscallarg(int) pad; 182668318Scgd syscallarg(off_t) length; 182768318Scgd } */ nuap; 182854863Storek 182968318Scgd SCARG(&nuap, path) = SCARG(uap, path); 183068318Scgd SCARG(&nuap, length) = SCARG(uap, length); 183160428Smckusick return (truncate(p, &nuap, retval)); 183254863Storek } 183354863Storek 183454863Storek /* 183554863Storek * Truncate a file given a file descriptor. 183654863Storek */ 183754863Storek /* ARGSUSED */ 183868318Scgd int 183968318Scgd compat_43_ftruncate(p, uap, retval) 184054863Storek struct proc *p; 184168318Scgd register struct compat_43_ftruncate_args /* { 184268318Scgd syscallarg(int) fd; 184368318Scgd syscallarg(long) length; 184468318Scgd } */ *uap; 184568318Scgd register_t *retval; 184654863Storek { 184768318Scgd struct ftruncate_args /* { 184868318Scgd syscallarg(int) fd; 184968318Scgd syscallarg(int) pad; 185068318Scgd syscallarg(off_t) length; 185168318Scgd } */ nuap; 185254863Storek 185368318Scgd SCARG(&nuap, fd) = SCARG(uap, fd); 185468318Scgd SCARG(&nuap, length) = SCARG(uap, length); 185560428Smckusick return (ftruncate(p, &nuap, retval)); 185654863Storek } 185754863Storek #endif /* COMPAT_43 || COMPAT_SUNOS */ 185854863Storek 185954863Storek /* 186064410Sbostic * Sync an open file. 18619167Ssam */ 186242441Smckusick /* ARGSUSED */ 186368318Scgd int 186442441Smckusick fsync(p, uap, retval) 186545914Smckusick struct proc *p; 186668318Scgd struct fsync_args /* { 186768318Scgd syscallarg(int) fd; 186868318Scgd } */ *uap; 186968318Scgd register_t *retval; 18709167Ssam { 187139592Smckusick register struct vnode *vp; 18729167Ssam struct file *fp; 187337741Smckusick int error; 18749167Ssam 187568318Scgd if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) 187647540Skarels return (error); 187739592Smckusick vp = (struct vnode *)fp->f_data; 187839592Smckusick VOP_LOCK(vp); 187954441Smckusick error = VOP_FSYNC(vp, fp->f_cred, MNT_WAIT, p); 188039592Smckusick VOP_UNLOCK(vp); 188147540Skarels return (error); 18829167Ssam } 18839167Ssam 18849167Ssam /* 188564410Sbostic * Rename files. Source and destination must either both be directories, 188664410Sbostic * or both not be directories. If target is a directory, it must be empty. 18879167Ssam */ 188842441Smckusick /* ARGSUSED */ 188968318Scgd int 189042441Smckusick rename(p, uap, retval) 189145914Smckusick struct proc *p; 189268318Scgd register struct rename_args /* { 189368318Scgd syscallarg(char *) from; 189468318Scgd syscallarg(char *) to; 189568318Scgd } */ *uap; 189668318Scgd register_t *retval; 189742441Smckusick { 189837741Smckusick register struct vnode *tvp, *fvp, *tdvp; 189949735Smckusick struct nameidata fromnd, tond; 190037741Smckusick int error; 19017701Ssam 190252322Smckusick NDINIT(&fromnd, DELETE, WANTPARENT | SAVESTART, UIO_USERSPACE, 190368318Scgd SCARG(uap, from), p); 190452322Smckusick if (error = namei(&fromnd)) 190547540Skarels return (error); 190649735Smckusick fvp = fromnd.ni_vp; 190752322Smckusick NDINIT(&tond, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART, 190868318Scgd UIO_USERSPACE, SCARG(uap, to), p); 190952322Smckusick if (error = namei(&tond)) { 191052230Sheideman VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 191149735Smckusick vrele(fromnd.ni_dvp); 191242465Smckusick vrele(fvp); 191342465Smckusick goto out1; 191442465Smckusick } 191537741Smckusick tdvp = tond.ni_dvp; 191637741Smckusick tvp = tond.ni_vp; 191737741Smckusick if (tvp != NULL) { 191837741Smckusick if (fvp->v_type == VDIR && tvp->v_type != VDIR) { 191939242Sbostic error = ENOTDIR; 192037741Smckusick goto out; 192137741Smckusick } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) { 192239242Sbostic error = EISDIR; 192337741Smckusick goto out; 19249167Ssam } 19259167Ssam } 192639286Smckusick if (fvp == tdvp) 192737741Smckusick error = EINVAL; 192839286Smckusick /* 192949735Smckusick * If source is the same as the destination (that is the 193049735Smckusick * same inode number with the same name in the same directory), 193139286Smckusick * then there is nothing to do. 193239286Smckusick */ 193349735Smckusick if (fvp == tvp && fromnd.ni_dvp == tdvp && 193452322Smckusick fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen && 193552322Smckusick !bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr, 193652322Smckusick fromnd.ni_cnd.cn_namelen)) 193739286Smckusick error = -1; 193837741Smckusick out: 193942465Smckusick if (!error) { 194067654Smckusick VOP_LEASE(tdvp, p, p->p_ucred, LEASE_WRITE); 194152192Smckusick if (fromnd.ni_dvp != tdvp) 194267654Smckusick VOP_LEASE(fromnd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 194352192Smckusick if (tvp) 194467654Smckusick VOP_LEASE(tvp, p, p->p_ucred, LEASE_WRITE); 194552230Sheideman error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd, 194652230Sheideman tond.ni_dvp, tond.ni_vp, &tond.ni_cnd); 194742465Smckusick } else { 194852230Sheideman VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd); 194943344Smckusick if (tdvp == tvp) 195043344Smckusick vrele(tdvp); 195143344Smckusick else 195243344Smckusick vput(tdvp); 195342465Smckusick if (tvp) 195442465Smckusick vput(tvp); 195552230Sheideman VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 195649735Smckusick vrele(fromnd.ni_dvp); 195742465Smckusick vrele(fvp); 19589167Ssam } 195949735Smckusick vrele(tond.ni_startdir); 196052322Smckusick FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI); 196137741Smckusick out1: 196266801Smckusick if (fromnd.ni_startdir) 196366801Smckusick vrele(fromnd.ni_startdir); 196452322Smckusick FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI); 196539286Smckusick if (error == -1) 196647540Skarels return (0); 196747540Skarels return (error); 19687701Ssam } 19697701Ssam 19707535Sroot /* 197164410Sbostic * Make a directory file. 197212756Ssam */ 197342441Smckusick /* ARGSUSED */ 197468318Scgd int 197542441Smckusick mkdir(p, uap, retval) 197645914Smckusick struct proc *p; 197768318Scgd register struct mkdir_args /* { 197868318Scgd syscallarg(char *) path; 197968318Scgd syscallarg(int) mode; 198068318Scgd } */ *uap; 198168318Scgd register_t *retval; 198242441Smckusick { 198337741Smckusick register struct vnode *vp; 198437741Smckusick struct vattr vattr; 198537741Smckusick int error; 198647540Skarels struct nameidata nd; 198712756Ssam 198868318Scgd NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p); 198952322Smckusick if (error = namei(&nd)) 199047540Skarels return (error); 199152322Smckusick vp = nd.ni_vp; 199237741Smckusick if (vp != NULL) { 199352322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 199452322Smckusick if (nd.ni_dvp == vp) 199552322Smckusick vrele(nd.ni_dvp); 199643344Smckusick else 199752322Smckusick vput(nd.ni_dvp); 199842465Smckusick vrele(vp); 199947540Skarels return (EEXIST); 200012756Ssam } 200141362Smckusick VATTR_NULL(&vattr); 200237741Smckusick vattr.va_type = VDIR; 200368318Scgd vattr.va_mode = (SCARG(uap, mode) & ACCESSPERMS) &~ p->p_fd->fd_cmask; 200467654Smckusick VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 200552322Smckusick error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr); 200638145Smckusick if (!error) 200752322Smckusick vput(nd.ni_vp); 200847540Skarels return (error); 200912756Ssam } 201012756Ssam 201112756Ssam /* 201264410Sbostic * Remove a directory file. 201312756Ssam */ 201442441Smckusick /* ARGSUSED */ 201568318Scgd int 201642441Smckusick rmdir(p, uap, retval) 201745914Smckusick struct proc *p; 201868318Scgd struct rmdir_args /* { 201968318Scgd syscallarg(char *) path; 202068318Scgd } */ *uap; 202168318Scgd register_t *retval; 202212756Ssam { 202337741Smckusick register struct vnode *vp; 202437741Smckusick int error; 202547540Skarels struct nameidata nd; 202612756Ssam 202768318Scgd NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE, 202868318Scgd SCARG(uap, path), p); 202952322Smckusick if (error = namei(&nd)) 203047540Skarels return (error); 203152322Smckusick vp = nd.ni_vp; 203237741Smckusick if (vp->v_type != VDIR) { 203337741Smckusick error = ENOTDIR; 203412756Ssam goto out; 203512756Ssam } 203612756Ssam /* 203737741Smckusick * No rmdir "." please. 203812756Ssam */ 203952322Smckusick if (nd.ni_dvp == vp) { 204037741Smckusick error = EINVAL; 204112756Ssam goto out; 204212756Ssam } 204312756Ssam /* 204449365Smckusick * The root of a mounted filesystem cannot be deleted. 204512756Ssam */ 204637741Smckusick if (vp->v_flag & VROOT) 204737741Smckusick error = EBUSY; 204812756Ssam out: 204942465Smckusick if (!error) { 205067654Smckusick VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 205167654Smckusick VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 205252322Smckusick error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); 205342465Smckusick } else { 205452322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 205552322Smckusick if (nd.ni_dvp == vp) 205652322Smckusick vrele(nd.ni_dvp); 205743344Smckusick else 205852322Smckusick vput(nd.ni_dvp); 205942465Smckusick vput(vp); 206042465Smckusick } 206147540Skarels return (error); 206212756Ssam } 206312756Ssam 206454620Smckusick #ifdef COMPAT_43 206537741Smckusick /* 206649365Smckusick * Read a block of directory entries in a file system independent format. 206737741Smckusick */ 206868318Scgd int 206968318Scgd compat_43_getdirentries(p, uap, retval) 207054620Smckusick struct proc *p; 207168318Scgd register struct compat_43_getdirentries_args /* { 207268318Scgd syscallarg(int) fd; 207368318Scgd syscallarg(char *) buf; 207468318Scgd syscallarg(u_int) count; 207568318Scgd syscallarg(long *) basep; 207668318Scgd } */ *uap; 207768318Scgd register_t *retval; 207854620Smckusick { 207954620Smckusick register struct vnode *vp; 208054620Smckusick struct file *fp; 208154620Smckusick struct uio auio, kuio; 208254620Smckusick struct iovec aiov, kiov; 208354620Smckusick struct dirent *dp, *edp; 208454620Smckusick caddr_t dirbuf; 208567362Smckusick int error, eofflag, readcnt; 208654969Smckusick long loff; 208754620Smckusick 208868318Scgd if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) 208954620Smckusick return (error); 209054620Smckusick if ((fp->f_flag & FREAD) == 0) 209154620Smckusick return (EBADF); 209254620Smckusick vp = (struct vnode *)fp->f_data; 209367362Smckusick unionread: 209454620Smckusick if (vp->v_type != VDIR) 209554620Smckusick return (EINVAL); 209668318Scgd aiov.iov_base = SCARG(uap, buf); 209768318Scgd aiov.iov_len = SCARG(uap, count); 209854620Smckusick auio.uio_iov = &aiov; 209954620Smckusick auio.uio_iovcnt = 1; 210054620Smckusick auio.uio_rw = UIO_READ; 210154620Smckusick auio.uio_segflg = UIO_USERSPACE; 210254620Smckusick auio.uio_procp = p; 210368318Scgd auio.uio_resid = SCARG(uap, count); 210454620Smckusick VOP_LOCK(vp); 210554969Smckusick loff = auio.uio_offset = fp->f_offset; 210654620Smckusick # if (BYTE_ORDER != LITTLE_ENDIAN) 210756339Smckusick if (vp->v_mount->mnt_maxsymlinklen <= 0) { 210867362Smckusick error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, 2109*68663Smckusick (int *)0, (u_long *)0); 211056339Smckusick fp->f_offset = auio.uio_offset; 211156339Smckusick } else 211254620Smckusick # endif 211354620Smckusick { 211454620Smckusick kuio = auio; 211554620Smckusick kuio.uio_iov = &kiov; 211654620Smckusick kuio.uio_segflg = UIO_SYSSPACE; 211768318Scgd kiov.iov_len = SCARG(uap, count); 211868318Scgd MALLOC(dirbuf, caddr_t, SCARG(uap, count), M_TEMP, M_WAITOK); 211954620Smckusick kiov.iov_base = dirbuf; 212067362Smckusick error = VOP_READDIR(vp, &kuio, fp->f_cred, &eofflag, 2121*68663Smckusick (int *)0, (u_long *)0); 212256339Smckusick fp->f_offset = kuio.uio_offset; 212354620Smckusick if (error == 0) { 212468318Scgd readcnt = SCARG(uap, count) - kuio.uio_resid; 212554620Smckusick edp = (struct dirent *)&dirbuf[readcnt]; 212654620Smckusick for (dp = (struct dirent *)dirbuf; dp < edp; ) { 212754620Smckusick # if (BYTE_ORDER == LITTLE_ENDIAN) 212854969Smckusick /* 212955009Smckusick * The expected low byte of 213055009Smckusick * dp->d_namlen is our dp->d_type. 213155009Smckusick * The high MBZ byte of dp->d_namlen 213255009Smckusick * is our dp->d_namlen. 213354969Smckusick */ 213455009Smckusick dp->d_type = dp->d_namlen; 213555009Smckusick dp->d_namlen = 0; 213655009Smckusick # else 213755009Smckusick /* 213855009Smckusick * The dp->d_type is the high byte 213955009Smckusick * of the expected dp->d_namlen, 214055009Smckusick * so must be zero'ed. 214155009Smckusick */ 214255009Smckusick dp->d_type = 0; 214354620Smckusick # endif 214454620Smckusick if (dp->d_reclen > 0) { 214554620Smckusick dp = (struct dirent *) 214654620Smckusick ((char *)dp + dp->d_reclen); 214754620Smckusick } else { 214854620Smckusick error = EIO; 214954620Smckusick break; 215054620Smckusick } 215154620Smckusick } 215254620Smckusick if (dp >= edp) 215354620Smckusick error = uiomove(dirbuf, readcnt, &auio); 215454620Smckusick } 215554620Smckusick FREE(dirbuf, M_TEMP); 215654620Smckusick } 215754620Smckusick VOP_UNLOCK(vp); 215854620Smckusick if (error) 215954620Smckusick return (error); 216067362Smckusick 216167362Smckusick #ifdef UNION 216267362Smckusick { 216367362Smckusick extern int (**union_vnodeop_p)(); 216468079Spendry extern struct vnode *union_dircache __P((struct vnode *)); 216567362Smckusick 216668318Scgd if ((SCARG(uap, count) == auio.uio_resid) && 216767362Smckusick (vp->v_op == union_vnodeop_p)) { 216867362Smckusick struct vnode *lvp; 216967362Smckusick 217068079Spendry lvp = union_dircache(vp); 217167362Smckusick if (lvp != NULLVP) { 217267575Spendry struct vattr va; 217367575Spendry 217467575Spendry /* 217567575Spendry * If the directory is opaque, 217667575Spendry * then don't show lower entries 217767575Spendry */ 217867575Spendry error = VOP_GETATTR(vp, &va, fp->f_cred, p); 217967575Spendry if (va.va_flags & OPAQUE) { 218068079Spendry vput(lvp); 218167575Spendry lvp = NULL; 218267575Spendry } 218367575Spendry } 218467575Spendry 218567575Spendry if (lvp != NULLVP) { 218667362Smckusick error = VOP_OPEN(lvp, FREAD, fp->f_cred, p); 218767362Smckusick VOP_UNLOCK(lvp); 218867362Smckusick 218967362Smckusick if (error) { 219067362Smckusick vrele(lvp); 219167362Smckusick return (error); 219267362Smckusick } 219367362Smckusick fp->f_data = (caddr_t) lvp; 219467362Smckusick fp->f_offset = 0; 219567362Smckusick error = vn_close(vp, FREAD, fp->f_cred, p); 219667362Smckusick if (error) 219767362Smckusick return (error); 219867362Smckusick vp = lvp; 219967362Smckusick goto unionread; 220067362Smckusick } 220167362Smckusick } 220267362Smckusick } 220367362Smckusick #endif /* UNION */ 220467362Smckusick 220568318Scgd if ((SCARG(uap, count) == auio.uio_resid) && 220667362Smckusick (vp->v_flag & VROOT) && 220767362Smckusick (vp->v_mount->mnt_flag & MNT_UNION)) { 220867362Smckusick struct vnode *tvp = vp; 220967362Smckusick vp = vp->v_mount->mnt_vnodecovered; 221067362Smckusick VREF(vp); 221167362Smckusick fp->f_data = (caddr_t) vp; 221267362Smckusick fp->f_offset = 0; 221367362Smckusick vrele(tvp); 221467362Smckusick goto unionread; 221567362Smckusick } 221668318Scgd error = copyout((caddr_t)&loff, (caddr_t)SCARG(uap, basep), 221768318Scgd sizeof(long)); 221868318Scgd *retval = SCARG(uap, count) - auio.uio_resid; 221954620Smckusick return (error); 222054620Smckusick } 222167362Smckusick #endif /* COMPAT_43 */ 222254620Smckusick 222354620Smckusick /* 222454620Smckusick * Read a block of directory entries in a file system independent format. 222554620Smckusick */ 222668318Scgd int 222742441Smckusick getdirentries(p, uap, retval) 222845914Smckusick struct proc *p; 222968318Scgd register struct getdirentries_args /* { 223068318Scgd syscallarg(int) fd; 223168318Scgd syscallarg(char *) buf; 223268318Scgd syscallarg(u_int) count; 223368318Scgd syscallarg(long *) basep; 223468318Scgd } */ *uap; 223568318Scgd register_t *retval; 223642441Smckusick { 223739592Smckusick register struct vnode *vp; 223816540Ssam struct file *fp; 223937741Smckusick struct uio auio; 224037741Smckusick struct iovec aiov; 224154969Smckusick long loff; 224267362Smckusick int error, eofflag; 224312756Ssam 224468318Scgd if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) 224547540Skarels return (error); 224637741Smckusick if ((fp->f_flag & FREAD) == 0) 224747540Skarels return (EBADF); 224839592Smckusick vp = (struct vnode *)fp->f_data; 224955451Spendry unionread: 225039592Smckusick if (vp->v_type != VDIR) 225147540Skarels return (EINVAL); 225268318Scgd aiov.iov_base = SCARG(uap, buf); 225368318Scgd aiov.iov_len = SCARG(uap, count); 225437741Smckusick auio.uio_iov = &aiov; 225537741Smckusick auio.uio_iovcnt = 1; 225637741Smckusick auio.uio_rw = UIO_READ; 225737741Smckusick auio.uio_segflg = UIO_USERSPACE; 225848026Smckusick auio.uio_procp = p; 225968318Scgd auio.uio_resid = SCARG(uap, count); 226039592Smckusick VOP_LOCK(vp); 226154969Smckusick loff = auio.uio_offset = fp->f_offset; 2262*68663Smckusick error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, 2263*68663Smckusick (int *)0, (u_long *)0); 226439592Smckusick fp->f_offset = auio.uio_offset; 226539592Smckusick VOP_UNLOCK(vp); 226639592Smckusick if (error) 226747540Skarels return (error); 226866095Spendry 226966095Spendry #ifdef UNION 227066095Spendry { 227166095Spendry extern int (**union_vnodeop_p)(); 227268079Spendry extern struct vnode *union_dircache __P((struct vnode *)); 227366095Spendry 227468318Scgd if ((SCARG(uap, count) == auio.uio_resid) && 227566095Spendry (vp->v_op == union_vnodeop_p)) { 227667122Spendry struct vnode *lvp; 227766095Spendry 227868079Spendry lvp = union_dircache(vp); 227967122Spendry if (lvp != NULLVP) { 228067575Spendry struct vattr va; 228167575Spendry 228267575Spendry /* 228367575Spendry * If the directory is opaque, 228467575Spendry * then don't show lower entries 228567575Spendry */ 228667575Spendry error = VOP_GETATTR(vp, &va, fp->f_cred, p); 228767575Spendry if (va.va_flags & OPAQUE) { 228868079Spendry vput(lvp); 228967575Spendry lvp = NULL; 229067575Spendry } 229167575Spendry } 229267575Spendry 229367575Spendry if (lvp != NULLVP) { 229467362Smckusick error = VOP_OPEN(lvp, FREAD, fp->f_cred, p); 229567122Spendry VOP_UNLOCK(lvp); 229666095Spendry 229766095Spendry if (error) { 229867122Spendry vrele(lvp); 229966095Spendry return (error); 230066095Spendry } 230167122Spendry fp->f_data = (caddr_t) lvp; 230266095Spendry fp->f_offset = 0; 230367122Spendry error = vn_close(vp, FREAD, fp->f_cred, p); 230466095Spendry if (error) 230566095Spendry return (error); 230667122Spendry vp = lvp; 230766095Spendry goto unionread; 230866095Spendry } 230966095Spendry } 231066095Spendry } 231168318Scgd #endif /* UNION */ 231266095Spendry 231368318Scgd if ((SCARG(uap, count) == auio.uio_resid) && 231455451Spendry (vp->v_flag & VROOT) && 231555451Spendry (vp->v_mount->mnt_flag & MNT_UNION)) { 231655451Spendry struct vnode *tvp = vp; 231755451Spendry vp = vp->v_mount->mnt_vnodecovered; 231855451Spendry VREF(vp); 231955451Spendry fp->f_data = (caddr_t) vp; 232055451Spendry fp->f_offset = 0; 232155451Spendry vrele(tvp); 232255451Spendry goto unionread; 232355451Spendry } 232468318Scgd error = copyout((caddr_t)&loff, (caddr_t)SCARG(uap, basep), 232568318Scgd sizeof(long)); 232668318Scgd *retval = SCARG(uap, count) - auio.uio_resid; 232747540Skarels return (error); 232812756Ssam } 232912756Ssam 233012756Ssam /* 233149365Smckusick * Set the mode mask for creation of filesystem nodes. 233212756Ssam */ 233368318Scgd int 233442441Smckusick umask(p, uap, retval) 233545914Smckusick struct proc *p; 233668318Scgd struct umask_args /* { 233768318Scgd syscallarg(int) newmask; 233868318Scgd } */ *uap; 233968318Scgd register_t *retval; 234012756Ssam { 234164410Sbostic register struct filedesc *fdp; 234212756Ssam 234364410Sbostic fdp = p->p_fd; 234445914Smckusick *retval = fdp->fd_cmask; 234568318Scgd fdp->fd_cmask = SCARG(uap, newmask) & ALLPERMS; 234647540Skarels return (0); 234712756Ssam } 234837741Smckusick 234939566Smarc /* 235039566Smarc * Void all references to file by ripping underlying filesystem 235139566Smarc * away from vnode. 235239566Smarc */ 235342441Smckusick /* ARGSUSED */ 235468318Scgd int 235542441Smckusick revoke(p, uap, retval) 235645914Smckusick struct proc *p; 235768318Scgd register struct revoke_args /* { 235868318Scgd syscallarg(char *) path; 235968318Scgd } */ *uap; 236068318Scgd register_t *retval; 236142441Smckusick { 236239566Smarc register struct vnode *vp; 236339566Smarc struct vattr vattr; 236439566Smarc int error; 236547540Skarels struct nameidata nd; 236639566Smarc 236768318Scgd NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 236852322Smckusick if (error = namei(&nd)) 236947540Skarels return (error); 237052322Smckusick vp = nd.ni_vp; 237148026Smckusick if (error = VOP_GETATTR(vp, &vattr, p->p_ucred, p)) 237239566Smarc goto out; 237347540Skarels if (p->p_ucred->cr_uid != vattr.va_uid && 237447540Skarels (error = suser(p->p_ucred, &p->p_acflag))) 237539566Smarc goto out; 237639805Smckusick if (vp->v_usecount > 1 || (vp->v_flag & VALIASED)) 237768423Smckusick VOP_REVOKE(vp, REVOKEALL); 237839566Smarc out: 237939566Smarc vrele(vp); 238047540Skarels return (error); 238139566Smarc } 238239566Smarc 238349365Smckusick /* 238449365Smckusick * Convert a user file descriptor to a kernel file entry. 238549365Smckusick */ 238668318Scgd int 238764410Sbostic getvnode(fdp, fd, fpp) 238845914Smckusick struct filedesc *fdp; 238937741Smckusick struct file **fpp; 239064410Sbostic int fd; 239137741Smckusick { 239237741Smckusick struct file *fp; 239337741Smckusick 239464410Sbostic if ((u_int)fd >= fdp->fd_nfiles || 239564410Sbostic (fp = fdp->fd_ofiles[fd]) == NULL) 239637741Smckusick return (EBADF); 239737741Smckusick if (fp->f_type != DTYPE_VNODE) 239837741Smckusick return (EINVAL); 239937741Smckusick *fpp = fp; 240037741Smckusick return (0); 240137741Smckusick } 2402