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*69334Smckusick * @(#)vfs_syscalls.c 8.35 (Berkeley) 05/10/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) { 22669325Smckusick 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 /* 318*69334Smckusick * Don't allow unmounting the root file system. 319*69334Smckusick */ 320*69334Smckusick if (mp->mnt_flag & MNT_ROOTFS) { 321*69334Smckusick vput(vp); 322*69334Smckusick return (EINVAL); 323*69334Smckusick } 324*69334Smckusick 325*69334Smckusick /* 32637741Smckusick * Must be the root of the filesystem 32737741Smckusick */ 32837741Smckusick if ((vp->v_flag & VROOT) == 0) { 32937741Smckusick vput(vp); 33047540Skarels return (EINVAL); 33137741Smckusick } 33237741Smckusick vput(vp); 33368318Scgd return (dounmount(mp, SCARG(uap, flags), p)); 33439356Smckusick } 33539356Smckusick 33639356Smckusick /* 33764410Sbostic * Do the actual file system unmount. 33839356Smckusick */ 33968318Scgd int 34048026Smckusick dounmount(mp, flags, p) 34139356Smckusick register struct mount *mp; 34239356Smckusick int flags; 34348026Smckusick struct proc *p; 34439356Smckusick { 34539356Smckusick struct vnode *coveredvp; 34639356Smckusick int error; 34739356Smckusick 34841400Smckusick coveredvp = mp->mnt_vnodecovered; 34941298Smckusick if (vfs_busy(mp)) 35041298Smckusick return (EBUSY); 35141400Smckusick mp->mnt_flag |= MNT_UNMOUNT; 35237741Smckusick if (error = vfs_lock(mp)) 35339356Smckusick return (error); 35437741Smckusick 35565859Smckusick mp->mnt_flag &=~ MNT_ASYNC; 35645738Smckusick vnode_pager_umount(mp); /* release cached vnodes */ 35737741Smckusick cache_purgevfs(mp); /* remove cache entries for this file sys */ 35854441Smckusick if ((error = VFS_SYNC(mp, MNT_WAIT, p->p_ucred, p)) == 0 || 35954441Smckusick (flags & MNT_FORCE)) 36048026Smckusick error = VFS_UNMOUNT(mp, flags, p); 36141400Smckusick mp->mnt_flag &= ~MNT_UNMOUNT; 36241298Smckusick vfs_unbusy(mp); 36337741Smckusick if (error) { 36437741Smckusick vfs_unlock(mp); 36537741Smckusick } else { 36669325Smckusick CIRCLEQ_REMOVE(&mountlist, mp, mnt_list); 36769325Smckusick if (coveredvp != NULLVP) { 36869325Smckusick vrele(coveredvp); 36969325Smckusick mp->mnt_vnodecovered->v_mountedhere = (struct mount *)0; 37069325Smckusick } 37168663Smckusick mp->mnt_vfc->vfc_refcount--; 37265259Smckusick vfs_unlock(mp); 37365259Smckusick if (mp->mnt_vnodelist.lh_first != NULL) 37452287Smckusick panic("unmount: dangling vnode"); 37537741Smckusick free((caddr_t)mp, M_MOUNT); 37637741Smckusick } 37739356Smckusick return (error); 3786254Sroot } 3796254Sroot 3809167Ssam /* 38137741Smckusick * Sync each mounted filesystem. 3829167Ssam */ 38367403Smckusick #ifdef DEBUG 38456352Smckusick int syncprt = 0; 38559875Smckusick struct ctldebug debug0 = { "syncprt", &syncprt }; 38656352Smckusick #endif 38756352Smckusick 38839491Smckusick /* ARGSUSED */ 38968318Scgd int 39042441Smckusick sync(p, uap, retval) 39145914Smckusick struct proc *p; 39268318Scgd void *uap; 39368318Scgd register_t *retval; 3946254Sroot { 39565259Smckusick register struct mount *mp, *nmp; 39665859Smckusick int asyncflag; 39737741Smckusick 39869325Smckusick for (mp = mountlist.cqh_first; mp != (void *)&mountlist; mp = nmp) { 39967678Smckusick /* 40067678Smckusick * Get the next pointer in case we hang on vfs_busy 40167678Smckusick * while we are being unmounted. 40267678Smckusick */ 40369325Smckusick nmp = mp->mnt_list.cqe_next; 40440343Smckusick /* 40540343Smckusick * The lock check below is to avoid races with mount 40640343Smckusick * and unmount. 40740343Smckusick */ 40841400Smckusick if ((mp->mnt_flag & (MNT_MLOCK|MNT_RDONLY|MNT_MPBUSY)) == 0 && 40941298Smckusick !vfs_busy(mp)) { 41065859Smckusick asyncflag = mp->mnt_flag & MNT_ASYNC; 41165859Smckusick mp->mnt_flag &= ~MNT_ASYNC; 41254441Smckusick VFS_SYNC(mp, MNT_NOWAIT, p->p_ucred, p); 41365859Smckusick if (asyncflag) 41465859Smckusick mp->mnt_flag |= MNT_ASYNC; 41567678Smckusick /* 41667678Smckusick * Get the next pointer again, as the next filesystem 41767678Smckusick * might have been unmounted while we were sync'ing. 41867678Smckusick */ 41969325Smckusick nmp = mp->mnt_list.cqe_next; 42065259Smckusick vfs_unbusy(mp); 42165259Smckusick } 42265259Smckusick } 42356352Smckusick #ifdef DIAGNOSTIC 42456352Smckusick if (syncprt) 42556352Smckusick vfs_bufstats(); 42656352Smckusick #endif /* DIAGNOSTIC */ 42747688Skarels return (0); 42837741Smckusick } 42937741Smckusick 43037741Smckusick /* 43164410Sbostic * Change filesystem quotas. 43241298Smckusick */ 43342441Smckusick /* ARGSUSED */ 43468318Scgd int 43542441Smckusick quotactl(p, uap, retval) 43645914Smckusick struct proc *p; 43768318Scgd register struct quotactl_args /* { 43868318Scgd syscallarg(char *) path; 43968318Scgd syscallarg(int) cmd; 44068318Scgd syscallarg(int) uid; 44168318Scgd syscallarg(caddr_t) arg; 44268318Scgd } */ *uap; 44368318Scgd register_t *retval; 44442441Smckusick { 44541298Smckusick register struct mount *mp; 44641298Smckusick int error; 44747540Skarels struct nameidata nd; 44841298Smckusick 44968318Scgd NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 45052322Smckusick if (error = namei(&nd)) 45147540Skarels return (error); 45252322Smckusick mp = nd.ni_vp->v_mount; 45352322Smckusick vrele(nd.ni_vp); 45468318Scgd return (VFS_QUOTACTL(mp, SCARG(uap, cmd), SCARG(uap, uid), 45568318Scgd SCARG(uap, arg), p)); 45641298Smckusick } 45741298Smckusick 45841298Smckusick /* 45949365Smckusick * Get filesystem statistics. 46037741Smckusick */ 46142441Smckusick /* ARGSUSED */ 46268318Scgd int 46342441Smckusick statfs(p, uap, retval) 46445914Smckusick struct proc *p; 46568318Scgd register struct statfs_args /* { 46668318Scgd syscallarg(char *) path; 46768318Scgd syscallarg(struct statfs *) buf; 46868318Scgd } */ *uap; 46968318Scgd register_t *retval; 47042441Smckusick { 47139464Smckusick register struct mount *mp; 47240343Smckusick register struct statfs *sp; 47337741Smckusick int error; 47447540Skarels struct nameidata nd; 47537741Smckusick 47668318Scgd NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 47752322Smckusick if (error = namei(&nd)) 47847540Skarels return (error); 47952322Smckusick mp = nd.ni_vp->v_mount; 48041400Smckusick sp = &mp->mnt_stat; 48152322Smckusick vrele(nd.ni_vp); 48248026Smckusick if (error = VFS_STATFS(mp, sp, p)) 48347540Skarels return (error); 48441400Smckusick sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 48568318Scgd return (copyout((caddr_t)sp, (caddr_t)SCARG(uap, buf), sizeof(*sp))); 48637741Smckusick } 48737741Smckusick 48842441Smckusick /* 48949365Smckusick * Get filesystem statistics. 49042441Smckusick */ 49142441Smckusick /* ARGSUSED */ 49268318Scgd int 49342441Smckusick fstatfs(p, uap, retval) 49445914Smckusick struct proc *p; 49568318Scgd register struct fstatfs_args /* { 49668318Scgd syscallarg(int) fd; 49768318Scgd syscallarg(struct statfs *) buf; 49868318Scgd } */ *uap; 49968318Scgd register_t *retval; 50042441Smckusick { 50137741Smckusick struct file *fp; 50239464Smckusick struct mount *mp; 50340343Smckusick register struct statfs *sp; 50437741Smckusick int error; 50537741Smckusick 50668318Scgd if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) 50747540Skarels return (error); 50839464Smckusick mp = ((struct vnode *)fp->f_data)->v_mount; 50941400Smckusick sp = &mp->mnt_stat; 51048026Smckusick if (error = VFS_STATFS(mp, sp, p)) 51147540Skarels return (error); 51241400Smckusick sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 51368318Scgd return (copyout((caddr_t)sp, (caddr_t)SCARG(uap, buf), sizeof(*sp))); 51437741Smckusick } 51537741Smckusick 51637741Smckusick /* 51749365Smckusick * Get statistics on all filesystems. 51838270Smckusick */ 51968318Scgd int 52042441Smckusick getfsstat(p, uap, retval) 52145914Smckusick struct proc *p; 52268318Scgd register struct getfsstat_args /* { 52368318Scgd syscallarg(struct statfs *) buf; 52468318Scgd syscallarg(long) bufsize; 52568318Scgd syscallarg(int) flags; 52668318Scgd } */ *uap; 52768318Scgd register_t *retval; 52842441Smckusick { 52965259Smckusick register struct mount *mp, *nmp; 53040343Smckusick register struct statfs *sp; 53139606Smckusick caddr_t sfsp; 53238270Smckusick long count, maxcount, error; 53338270Smckusick 53468318Scgd maxcount = SCARG(uap, bufsize) / sizeof(struct statfs); 53568318Scgd sfsp = (caddr_t)SCARG(uap, buf); 53669325Smckusick count = 0; 53769325Smckusick for (mp = mountlist.cqh_first; mp != (void *)&mountlist; mp = nmp) { 53869325Smckusick nmp = mp->mnt_list.cqe_next; 53941400Smckusick if (sfsp && count < maxcount && 54041400Smckusick ((mp->mnt_flag & MNT_MLOCK) == 0)) { 54141400Smckusick sp = &mp->mnt_stat; 54240343Smckusick /* 54340343Smckusick * If MNT_NOWAIT is specified, do not refresh the 54440343Smckusick * fsstat cache. MNT_WAIT overrides MNT_NOWAIT. 54540343Smckusick */ 54668318Scgd if (((SCARG(uap, flags) & MNT_NOWAIT) == 0 || 54768318Scgd (SCARG(uap, flags) & MNT_WAIT)) && 54865259Smckusick (error = VFS_STATFS(mp, sp, p))) 54939607Smckusick continue; 55041400Smckusick sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 55140343Smckusick if (error = copyout((caddr_t)sp, sfsp, sizeof(*sp))) 55247540Skarels return (error); 55340343Smckusick sfsp += sizeof(*sp); 55438270Smckusick } 55539606Smckusick count++; 55665259Smckusick } 55738270Smckusick if (sfsp && count > maxcount) 55842441Smckusick *retval = maxcount; 55938270Smckusick else 56042441Smckusick *retval = count; 56147540Skarels return (0); 56238270Smckusick } 56338270Smckusick 56438270Smckusick /* 56538259Smckusick * Change current working directory to a given file descriptor. 56638259Smckusick */ 56742441Smckusick /* ARGSUSED */ 56868318Scgd int 56942441Smckusick fchdir(p, uap, retval) 57045914Smckusick struct proc *p; 57168318Scgd struct fchdir_args /* { 57268318Scgd syscallarg(int) fd; 57368318Scgd } */ *uap; 57468318Scgd register_t *retval; 57538259Smckusick { 57645914Smckusick register struct filedesc *fdp = p->p_fd; 57767974Smckusick struct vnode *vp, *tdp; 57867974Smckusick struct mount *mp; 57938259Smckusick struct file *fp; 58038259Smckusick int error; 58138259Smckusick 58268318Scgd if (error = getvnode(fdp, SCARG(uap, fd), &fp)) 58347540Skarels return (error); 58438259Smckusick vp = (struct vnode *)fp->f_data; 58567974Smckusick VREF(vp); 58638259Smckusick VOP_LOCK(vp); 58738259Smckusick if (vp->v_type != VDIR) 58838259Smckusick error = ENOTDIR; 58938259Smckusick else 59048026Smckusick error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p); 59167974Smckusick while (!error && (mp = vp->v_mountedhere) != NULL) { 59267974Smckusick if (mp->mnt_flag & MNT_MLOCK) { 59367974Smckusick mp->mnt_flag |= MNT_MWAIT; 59467974Smckusick sleep((caddr_t)mp, PVFS); 59567974Smckusick continue; 59667974Smckusick } 59767974Smckusick if (error = VFS_ROOT(mp, &tdp)) 59867974Smckusick break; 59967974Smckusick vput(vp); 60067974Smckusick vp = tdp; 60167974Smckusick } 60238259Smckusick VOP_UNLOCK(vp); 60367974Smckusick if (error) { 60467974Smckusick vrele(vp); 60547540Skarels return (error); 60667974Smckusick } 60745914Smckusick vrele(fdp->fd_cdir); 60845914Smckusick fdp->fd_cdir = vp; 60947540Skarels return (0); 61038259Smckusick } 61138259Smckusick 61238259Smckusick /* 61337741Smckusick * Change current working directory (``.''). 61437741Smckusick */ 61542441Smckusick /* ARGSUSED */ 61668318Scgd int 61742441Smckusick chdir(p, uap, retval) 61845914Smckusick struct proc *p; 61968318Scgd struct chdir_args /* { 62068318Scgd syscallarg(char *) path; 62168318Scgd } */ *uap; 62268318Scgd register_t *retval; 62337741Smckusick { 62445914Smckusick register struct filedesc *fdp = p->p_fd; 62537741Smckusick int error; 62647540Skarels struct nameidata nd; 6276254Sroot 62868318Scgd NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, 62968318Scgd SCARG(uap, path), p); 63064410Sbostic if (error = change_dir(&nd, p)) 63147540Skarels return (error); 63245914Smckusick vrele(fdp->fd_cdir); 63352322Smckusick fdp->fd_cdir = nd.ni_vp; 63447540Skarels return (0); 63537741Smckusick } 6366254Sroot 63737741Smckusick /* 63837741Smckusick * Change notion of root (``/'') directory. 63937741Smckusick */ 64042441Smckusick /* ARGSUSED */ 64168318Scgd int 64242441Smckusick chroot(p, uap, retval) 64345914Smckusick struct proc *p; 64468318Scgd struct chroot_args /* { 64568318Scgd syscallarg(char *) path; 64668318Scgd } */ *uap; 64768318Scgd register_t *retval; 64837741Smckusick { 64945914Smckusick register struct filedesc *fdp = p->p_fd; 65037741Smckusick int error; 65147540Skarels struct nameidata nd; 65237741Smckusick 65347540Skarels if (error = suser(p->p_ucred, &p->p_acflag)) 65447540Skarels return (error); 65568318Scgd NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, 65668318Scgd SCARG(uap, path), p); 65764410Sbostic if (error = change_dir(&nd, p)) 65847540Skarels return (error); 65945914Smckusick if (fdp->fd_rdir != NULL) 66045914Smckusick vrele(fdp->fd_rdir); 66152322Smckusick fdp->fd_rdir = nd.ni_vp; 66247540Skarels return (0); 6636254Sroot } 6646254Sroot 66537Sbill /* 66637741Smckusick * Common routine for chroot and chdir. 66737741Smckusick */ 66864410Sbostic static int 66964410Sbostic change_dir(ndp, p) 67052322Smckusick register struct nameidata *ndp; 67147540Skarels struct proc *p; 67237741Smckusick { 67337741Smckusick struct vnode *vp; 67437741Smckusick int error; 67537741Smckusick 67652322Smckusick if (error = namei(ndp)) 67737741Smckusick return (error); 67837741Smckusick vp = ndp->ni_vp; 67937741Smckusick if (vp->v_type != VDIR) 68037741Smckusick error = ENOTDIR; 68137741Smckusick else 68248026Smckusick error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p); 68337741Smckusick VOP_UNLOCK(vp); 68437741Smckusick if (error) 68537741Smckusick vrele(vp); 68637741Smckusick return (error); 68737741Smckusick } 68837741Smckusick 68937741Smckusick /* 69042441Smckusick * Check permissions, allocate an open file structure, 69142441Smckusick * and call the device open routine if any. 6926254Sroot */ 69368318Scgd int 69442441Smckusick open(p, uap, retval) 69545914Smckusick struct proc *p; 69668318Scgd register struct open_args /* { 69768318Scgd syscallarg(char *) path; 69868318Scgd syscallarg(int) flags; 69968318Scgd syscallarg(int) mode; 70068318Scgd } */ *uap; 70168318Scgd register_t *retval; 7026254Sroot { 70345914Smckusick register struct filedesc *fdp = p->p_fd; 70442441Smckusick register struct file *fp; 70550111Smckusick register struct vnode *vp; 70664410Sbostic int flags, cmode; 70737741Smckusick struct file *nfp; 70849945Smckusick int type, indx, error; 70949945Smckusick struct flock lf; 71047540Skarels struct nameidata nd; 71137741Smckusick extern struct fileops vnops; 7126254Sroot 71345914Smckusick if (error = falloc(p, &nfp, &indx)) 71447540Skarels return (error); 71537741Smckusick fp = nfp; 71668318Scgd flags = FFLAGS(SCARG(uap, flags)); 71768318Scgd cmode = ((SCARG(uap, mode) &~ fdp->fd_cmask) & ALLPERMS) &~ S_ISTXT; 71868318Scgd NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 71945202Smckusick p->p_dupfd = -indx - 1; /* XXX check for fdopen */ 72064410Sbostic if (error = vn_open(&nd, flags, cmode)) { 72149980Smckusick ffree(fp); 72254723Smckusick if ((error == ENODEV || error == ENXIO) && 72368318Scgd p->p_dupfd >= 0 && /* XXX from fdopen */ 72464410Sbostic (error = 72568318Scgd dupfdopen(fdp, indx, p->p_dupfd, flags, error)) == 0) { 72642441Smckusick *retval = indx; 72747540Skarels return (0); 72842441Smckusick } 72940884Smckusick if (error == ERESTART) 73040884Smckusick error = EINTR; 73147688Skarels fdp->fd_ofiles[indx] = NULL; 73247540Skarels return (error); 73312756Ssam } 73453828Spendry p->p_dupfd = 0; 73552322Smckusick vp = nd.ni_vp; 73664410Sbostic fp->f_flag = flags & FMASK; 73754348Smckusick fp->f_type = DTYPE_VNODE; 73854348Smckusick fp->f_ops = &vnops; 73954348Smckusick fp->f_data = (caddr_t)vp; 74064410Sbostic if (flags & (O_EXLOCK | O_SHLOCK)) { 74149945Smckusick lf.l_whence = SEEK_SET; 74249945Smckusick lf.l_start = 0; 74349945Smckusick lf.l_len = 0; 74464410Sbostic if (flags & O_EXLOCK) 74549945Smckusick lf.l_type = F_WRLCK; 74649945Smckusick else 74749945Smckusick lf.l_type = F_RDLCK; 74849945Smckusick type = F_FLOCK; 74964410Sbostic if ((flags & FNONBLOCK) == 0) 75049945Smckusick type |= F_WAIT; 75165757Smckusick VOP_UNLOCK(vp); 75250111Smckusick if (error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, type)) { 75350111Smckusick (void) vn_close(vp, fp->f_flag, fp->f_cred, p); 75449980Smckusick ffree(fp); 75549945Smckusick fdp->fd_ofiles[indx] = NULL; 75649945Smckusick return (error); 75749945Smckusick } 75865757Smckusick VOP_LOCK(vp); 75949949Smckusick fp->f_flag |= FHASLOCK; 76049945Smckusick } 76150111Smckusick VOP_UNLOCK(vp); 76242441Smckusick *retval = indx; 76347540Skarels return (0); 7646254Sroot } 7656254Sroot 76642955Smckusick #ifdef COMPAT_43 7676254Sroot /* 76864410Sbostic * Create a file. 7696254Sroot */ 77068318Scgd int 77168318Scgd compat_43_creat(p, uap, retval) 77242441Smckusick struct proc *p; 77368318Scgd register struct compat_43_creat_args /* { 77468318Scgd syscallarg(char *) path; 77568318Scgd syscallarg(int) mode; 77668318Scgd } */ *uap; 77768318Scgd register_t *retval; 7786254Sroot { 77968318Scgd struct open_args /* { 78068318Scgd syscallarg(char *) path; 78168318Scgd syscallarg(int) flags; 78268318Scgd syscallarg(int) mode; 78368318Scgd } */ nuap; 78442441Smckusick 78568318Scgd SCARG(&nuap, path) = SCARG(uap, path); 78668318Scgd SCARG(&nuap, mode) = SCARG(uap, mode); 78768318Scgd SCARG(&nuap, flags) = O_WRONLY | O_CREAT | O_TRUNC; 78868318Scgd return (open(p, &nuap, retval)); 78942441Smckusick } 79042955Smckusick #endif /* COMPAT_43 */ 79142441Smckusick 79242441Smckusick /* 79364410Sbostic * Create a special file. 79442441Smckusick */ 79542441Smckusick /* ARGSUSED */ 79668318Scgd int 79742441Smckusick mknod(p, uap, retval) 79845914Smckusick struct proc *p; 79968318Scgd register struct mknod_args /* { 80068318Scgd syscallarg(char *) path; 80168318Scgd syscallarg(int) mode; 80268318Scgd syscallarg(int) dev; 80368318Scgd } */ *uap; 80468318Scgd register_t *retval; 80542441Smckusick { 80637741Smckusick register struct vnode *vp; 80737741Smckusick struct vattr vattr; 80837741Smckusick int error; 80967575Spendry int whiteout; 81047540Skarels struct nameidata nd; 8116254Sroot 81247540Skarels if (error = suser(p->p_ucred, &p->p_acflag)) 81347540Skarels return (error); 81468318Scgd NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p); 81552322Smckusick if (error = namei(&nd)) 81647540Skarels return (error); 81752322Smckusick vp = nd.ni_vp; 81864585Sbostic if (vp != NULL) 81937741Smckusick error = EEXIST; 82064585Sbostic else { 82164585Sbostic VATTR_NULL(&vattr); 82268318Scgd vattr.va_mode = (SCARG(uap, mode) & ALLPERMS) &~ p->p_fd->fd_cmask; 82368318Scgd vattr.va_rdev = SCARG(uap, dev); 82467575Spendry whiteout = 0; 82564585Sbostic 82668318Scgd switch (SCARG(uap, mode) & S_IFMT) { 82764585Sbostic case S_IFMT: /* used by badsect to flag bad sectors */ 82864585Sbostic vattr.va_type = VBAD; 82964585Sbostic break; 83064585Sbostic case S_IFCHR: 83164585Sbostic vattr.va_type = VCHR; 83264585Sbostic break; 83364585Sbostic case S_IFBLK: 83464585Sbostic vattr.va_type = VBLK; 83564585Sbostic break; 83667575Spendry case S_IFWHT: 83767575Spendry whiteout = 1; 83867575Spendry break; 83964585Sbostic default: 84064585Sbostic error = EINVAL; 84164585Sbostic break; 84264585Sbostic } 8436254Sroot } 84467747Spendry if (!error) { 84567654Smckusick VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 84667747Spendry if (whiteout) { 84767747Spendry error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, CREATE); 84867747Spendry if (error) 84967747Spendry VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 85067747Spendry vput(nd.ni_dvp); 85167747Spendry } else { 85267747Spendry error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, 85367747Spendry &nd.ni_cnd, &vattr); 85467747Spendry } 85542465Smckusick } else { 85652322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 85752322Smckusick if (nd.ni_dvp == vp) 85852322Smckusick vrele(nd.ni_dvp); 85943344Smckusick else 86052322Smckusick vput(nd.ni_dvp); 86142465Smckusick if (vp) 86242465Smckusick vrele(vp); 86342465Smckusick } 86447540Skarels return (error); 8656254Sroot } 8666254Sroot 8676254Sroot /* 86868318Scgd * Create a named pipe. 86940285Smckusick */ 87042441Smckusick /* ARGSUSED */ 87168318Scgd int 87242441Smckusick mkfifo(p, uap, retval) 87345914Smckusick struct proc *p; 87468318Scgd register struct mkfifo_args /* { 87568318Scgd syscallarg(char *) path; 87668318Scgd syscallarg(int) mode; 87768318Scgd } */ *uap; 87868318Scgd register_t *retval; 87942441Smckusick { 88040285Smckusick struct vattr vattr; 88140285Smckusick int error; 88247540Skarels struct nameidata nd; 88340285Smckusick 88440285Smckusick #ifndef FIFO 88547540Skarels return (EOPNOTSUPP); 88640285Smckusick #else 88768318Scgd NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p); 88852322Smckusick if (error = namei(&nd)) 88947540Skarels return (error); 89052322Smckusick if (nd.ni_vp != NULL) { 89152322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 89252322Smckusick if (nd.ni_dvp == nd.ni_vp) 89352322Smckusick vrele(nd.ni_dvp); 89443344Smckusick else 89552322Smckusick vput(nd.ni_dvp); 89652322Smckusick vrele(nd.ni_vp); 89747540Skarels return (EEXIST); 89840285Smckusick } 89945785Sbostic VATTR_NULL(&vattr); 90045785Sbostic vattr.va_type = VFIFO; 90168318Scgd vattr.va_mode = (SCARG(uap, mode) & ALLPERMS) &~ p->p_fd->fd_cmask; 90267654Smckusick VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 90352322Smckusick return (VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr)); 90440285Smckusick #endif /* FIFO */ 90540285Smckusick } 90640285Smckusick 90740285Smckusick /* 90864410Sbostic * Make a hard file link. 9096254Sroot */ 91042441Smckusick /* ARGSUSED */ 91168318Scgd int 91242441Smckusick link(p, uap, retval) 91345914Smckusick struct proc *p; 91468318Scgd register struct link_args /* { 91568318Scgd syscallarg(char *) path; 91668318Scgd syscallarg(char *) link; 91768318Scgd } */ *uap; 91868318Scgd register_t *retval; 91942441Smckusick { 92064410Sbostic register struct vnode *vp; 92164410Sbostic struct nameidata nd; 92237741Smckusick int error; 9236254Sroot 92468318Scgd NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 92552322Smckusick if (error = namei(&nd)) 92647540Skarels return (error); 92752322Smckusick vp = nd.ni_vp; 92864585Sbostic if (vp->v_type != VDIR || 92964585Sbostic (error = suser(p->p_ucred, &p->p_acflag)) == 0) { 93064585Sbostic nd.ni_cnd.cn_nameiop = CREATE; 93164585Sbostic nd.ni_cnd.cn_flags = LOCKPARENT; 93268318Scgd nd.ni_dirp = SCARG(uap, link); 93364585Sbostic if ((error = namei(&nd)) == 0) { 93464585Sbostic if (nd.ni_vp != NULL) 93564585Sbostic error = EEXIST; 93664585Sbostic if (!error) { 93767654Smckusick VOP_LEASE(nd.ni_dvp, p, p->p_ucred, 93867654Smckusick LEASE_WRITE); 93967654Smckusick VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 94068538Smckusick error = VOP_LINK(vp, nd.ni_dvp, &nd.ni_cnd); 94164585Sbostic } else { 94264585Sbostic VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 94364585Sbostic if (nd.ni_dvp == nd.ni_vp) 94464585Sbostic vrele(nd.ni_dvp); 94564585Sbostic else 94664585Sbostic vput(nd.ni_dvp); 94764585Sbostic if (nd.ni_vp) 94864585Sbostic vrele(nd.ni_vp); 94964585Sbostic } 95064585Sbostic } 95142465Smckusick } 95264585Sbostic vrele(vp); 95347540Skarels return (error); 9546254Sroot } 9556254Sroot 9566254Sroot /* 95749365Smckusick * Make a symbolic link. 9586254Sroot */ 95942441Smckusick /* ARGSUSED */ 96068318Scgd int 96142441Smckusick symlink(p, uap, retval) 96245914Smckusick struct proc *p; 96368318Scgd register struct symlink_args /* { 96468318Scgd syscallarg(char *) path; 96568318Scgd syscallarg(char *) link; 96668318Scgd } */ *uap; 96768318Scgd register_t *retval; 96842441Smckusick { 96937741Smckusick struct vattr vattr; 97064410Sbostic char *path; 97137741Smckusick int error; 97247540Skarels struct nameidata nd; 9736254Sroot 97464410Sbostic MALLOC(path, char *, MAXPATHLEN, M_NAMEI, M_WAITOK); 97568318Scgd if (error = copyinstr(SCARG(uap, path), path, MAXPATHLEN, NULL)) 97642465Smckusick goto out; 97768318Scgd NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, link), p); 97852322Smckusick if (error = namei(&nd)) 97942465Smckusick goto out; 98052322Smckusick if (nd.ni_vp) { 98152322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 98252322Smckusick if (nd.ni_dvp == nd.ni_vp) 98352322Smckusick vrele(nd.ni_dvp); 98443344Smckusick else 98552322Smckusick vput(nd.ni_dvp); 98652322Smckusick vrele(nd.ni_vp); 98737741Smckusick error = EEXIST; 98837741Smckusick goto out; 9896254Sroot } 99041362Smckusick VATTR_NULL(&vattr); 99164410Sbostic vattr.va_mode = ACCESSPERMS &~ p->p_fd->fd_cmask; 99267654Smckusick VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 99364410Sbostic error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr, path); 99437741Smckusick out: 99564410Sbostic FREE(path, M_NAMEI); 99647540Skarels return (error); 9976254Sroot } 9986254Sroot 9996254Sroot /* 100067518Spendry * Delete a whiteout from the filesystem. 100167518Spendry */ 100267518Spendry /* ARGSUSED */ 100368318Scgd int 100467845Smckusick undelete(p, uap, retval) 100567518Spendry struct proc *p; 100668318Scgd register struct undelete_args /* { 100768318Scgd syscallarg(char *) path; 100868318Scgd } */ *uap; 100968318Scgd register_t *retval; 101067518Spendry { 101167518Spendry int error; 101267518Spendry struct nameidata nd; 101367518Spendry 101468318Scgd NDINIT(&nd, DELETE, LOCKPARENT|DOWHITEOUT, UIO_USERSPACE, 101568318Scgd SCARG(uap, path), p); 101667575Spendry error = namei(&nd); 101767575Spendry if (error) 101867518Spendry return (error); 101967575Spendry 102067575Spendry if (nd.ni_vp != NULLVP || !(nd.ni_cnd.cn_flags & ISWHITEOUT)) { 102167518Spendry VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 102267518Spendry if (nd.ni_dvp == nd.ni_vp) 102367518Spendry vrele(nd.ni_dvp); 102467518Spendry else 102567518Spendry vput(nd.ni_dvp); 102667518Spendry if (nd.ni_vp) 102767518Spendry vrele(nd.ni_vp); 102867518Spendry return (EEXIST); 102967518Spendry } 103067575Spendry 103167654Smckusick VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 103267747Spendry if (error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, DELETE)) 103367575Spendry VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 103467518Spendry vput(nd.ni_dvp); 103567518Spendry return (error); 103667518Spendry } 103767518Spendry 103867518Spendry /* 103949365Smckusick * Delete a name from the filesystem. 10406254Sroot */ 104142441Smckusick /* ARGSUSED */ 104268318Scgd int 104342441Smckusick unlink(p, uap, retval) 104445914Smckusick struct proc *p; 104568318Scgd struct unlink_args /* { 104668318Scgd syscallarg(char *) path; 104768318Scgd } */ *uap; 104868318Scgd register_t *retval; 10496254Sroot { 105037741Smckusick register struct vnode *vp; 105137741Smckusick int error; 105247540Skarels struct nameidata nd; 10536254Sroot 105468318Scgd NDINIT(&nd, DELETE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p); 105552322Smckusick if (error = namei(&nd)) 105647540Skarels return (error); 105752322Smckusick vp = nd.ni_vp; 105867654Smckusick VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 105959382Smckusick VOP_LOCK(vp); 106064410Sbostic 106164585Sbostic if (vp->v_type != VDIR || 106264585Sbostic (error = suser(p->p_ucred, &p->p_acflag)) == 0) { 106364585Sbostic /* 106464585Sbostic * The root of a mounted filesystem cannot be deleted. 106564585Sbostic */ 106664585Sbostic if (vp->v_flag & VROOT) 106764585Sbostic error = EBUSY; 106864585Sbostic else 106964585Sbostic (void)vnode_pager_uncache(vp); 107064585Sbostic } 107164585Sbostic 107264585Sbostic if (!error) { 107367654Smckusick VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 107452322Smckusick error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); 107542465Smckusick } else { 107652322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 107752322Smckusick if (nd.ni_dvp == vp) 107852322Smckusick vrele(nd.ni_dvp); 107943344Smckusick else 108052322Smckusick vput(nd.ni_dvp); 108167575Spendry if (vp != NULLVP) 108267575Spendry vput(vp); 108342465Smckusick } 108447540Skarels return (error); 10856254Sroot } 10866254Sroot 108764410Sbostic /* 108864410Sbostic * Reposition read/write file offset. 108964410Sbostic */ 109068318Scgd int 109160414Smckusick lseek(p, uap, retval) 109253468Smckusick struct proc *p; 109368318Scgd register struct lseek_args /* { 109468318Scgd syscallarg(int) fd; 109568318Scgd syscallarg(int) pad; 109668318Scgd syscallarg(off_t) offset; 109768318Scgd syscallarg(int) whence; 109868318Scgd } */ *uap; 109968318Scgd register_t *retval; 110042441Smckusick { 110147540Skarels struct ucred *cred = p->p_ucred; 110245914Smckusick register struct filedesc *fdp = p->p_fd; 110342441Smckusick register struct file *fp; 110437741Smckusick struct vattr vattr; 110537741Smckusick int error; 11066254Sroot 110768318Scgd if ((u_int)SCARG(uap, fd) >= fdp->fd_nfiles || 110868318Scgd (fp = fdp->fd_ofiles[SCARG(uap, fd)]) == NULL) 110947540Skarels return (EBADF); 111037741Smckusick if (fp->f_type != DTYPE_VNODE) 111147540Skarels return (ESPIPE); 111268318Scgd switch (SCARG(uap, whence)) { 111313878Ssam case L_INCR: 111468318Scgd fp->f_offset += SCARG(uap, offset); 111513878Ssam break; 111613878Ssam case L_XTND: 111764410Sbostic if (error = 111864410Sbostic VOP_GETATTR((struct vnode *)fp->f_data, &vattr, cred, p)) 111947540Skarels return (error); 112068318Scgd fp->f_offset = SCARG(uap, offset) + vattr.va_size; 112113878Ssam break; 112213878Ssam case L_SET: 112368318Scgd fp->f_offset = SCARG(uap, offset); 112413878Ssam break; 112513878Ssam default: 112647540Skarels return (EINVAL); 112713878Ssam } 112854916Storek *(off_t *)retval = fp->f_offset; 112947540Skarels return (0); 11306254Sroot } 11316254Sroot 113260414Smckusick #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 11336254Sroot /* 113464410Sbostic * Reposition read/write file offset. 113560036Smckusick */ 113668318Scgd int 113768318Scgd compat_43_lseek(p, uap, retval) 113860036Smckusick struct proc *p; 113968318Scgd register struct compat_43_lseek_args /* { 114068318Scgd syscallarg(int) fd; 114168318Scgd syscallarg(long) offset; 114268318Scgd syscallarg(int) whence; 114368318Scgd } */ *uap; 114468318Scgd register_t *retval; 114560036Smckusick { 114668318Scgd struct lseek_args /* { 114768318Scgd syscallarg(int) fd; 114868318Scgd syscallarg(int) pad; 114968318Scgd syscallarg(off_t) offset; 115068318Scgd syscallarg(int) whence; 115168318Scgd } */ nuap; 115260036Smckusick off_t qret; 115360036Smckusick int error; 115460036Smckusick 115568318Scgd SCARG(&nuap, fd) = SCARG(uap, fd); 115668318Scgd SCARG(&nuap, offset) = SCARG(uap, offset); 115768318Scgd SCARG(&nuap, whence) = SCARG(uap, whence); 115860428Smckusick error = lseek(p, &nuap, &qret); 115960036Smckusick *(long *)retval = qret; 116060036Smckusick return (error); 116160036Smckusick } 116260414Smckusick #endif /* COMPAT_43 */ 116360036Smckusick 116460036Smckusick /* 116549365Smckusick * Check access permissions. 11666254Sroot */ 116768318Scgd int 116863427Sbostic access(p, uap, retval) 116945914Smckusick struct proc *p; 117068318Scgd register struct access_args /* { 117168318Scgd syscallarg(char *) path; 117268318Scgd syscallarg(int) flags; 117368318Scgd } */ *uap; 117468318Scgd register_t *retval; 117542441Smckusick { 117647540Skarels register struct ucred *cred = p->p_ucred; 117737741Smckusick register struct vnode *vp; 117864585Sbostic int error, flags, t_gid, t_uid; 117947540Skarels struct nameidata nd; 11806254Sroot 118164585Sbostic t_uid = cred->cr_uid; 118264585Sbostic t_gid = cred->cr_groups[0]; 118347540Skarels cred->cr_uid = p->p_cred->p_ruid; 118447540Skarels cred->cr_groups[0] = p->p_cred->p_rgid; 118568318Scgd NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, 118668318Scgd SCARG(uap, path), p); 118752322Smckusick if (error = namei(&nd)) 118837741Smckusick goto out1; 118952322Smckusick vp = nd.ni_vp; 119064410Sbostic 119164410Sbostic /* Flags == 0 means only check for existence. */ 119268318Scgd if (SCARG(uap, flags)) { 119364410Sbostic flags = 0; 119468318Scgd if (SCARG(uap, flags) & R_OK) 119564410Sbostic flags |= VREAD; 119668318Scgd if (SCARG(uap, flags) & W_OK) 119764410Sbostic flags |= VWRITE; 119868318Scgd if (SCARG(uap, flags) & X_OK) 119964410Sbostic flags |= VEXEC; 120064410Sbostic if ((flags & VWRITE) == 0 || (error = vn_writechk(vp)) == 0) 120164410Sbostic error = VOP_ACCESS(vp, flags, cred, p); 12026254Sroot } 120337741Smckusick vput(vp); 120437741Smckusick out1: 120564585Sbostic cred->cr_uid = t_uid; 120664585Sbostic cred->cr_groups[0] = t_gid; 120747540Skarels return (error); 12086254Sroot } 12096254Sroot 121054348Smckusick #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 12116254Sroot /* 121264410Sbostic * Get file status; this version follows links. 121337Sbill */ 121442441Smckusick /* ARGSUSED */ 121568318Scgd int 121668318Scgd compat_43_stat(p, uap, retval) 121745914Smckusick struct proc *p; 121868318Scgd register struct compat_43_stat_args /* { 121968318Scgd syscallarg(char *) path; 122068318Scgd syscallarg(struct ostat *) ub; 122168318Scgd } */ *uap; 122268318Scgd register_t *retval; 122353468Smckusick { 122453468Smckusick struct stat sb; 122553468Smckusick struct ostat osb; 122653468Smckusick int error; 122753468Smckusick struct nameidata nd; 122853468Smckusick 122968318Scgd NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, 123068318Scgd SCARG(uap, path), p); 123153468Smckusick if (error = namei(&nd)) 123253468Smckusick return (error); 123353468Smckusick error = vn_stat(nd.ni_vp, &sb, p); 123453468Smckusick vput(nd.ni_vp); 123553468Smckusick if (error) 123653468Smckusick return (error); 123753468Smckusick cvtstat(&sb, &osb); 123868318Scgd error = copyout((caddr_t)&osb, (caddr_t)SCARG(uap, ub), sizeof (osb)); 123953468Smckusick return (error); 124053468Smckusick } 124153468Smckusick 124253468Smckusick /* 124364410Sbostic * Get file status; this version does not follow links. 124453468Smckusick */ 124553468Smckusick /* ARGSUSED */ 124668318Scgd int 124768318Scgd compat_43_lstat(p, uap, retval) 124853468Smckusick struct proc *p; 124968318Scgd register struct compat_43_lstat_args /* { 125068318Scgd syscallarg(char *) path; 125168318Scgd syscallarg(struct ostat *) ub; 125268318Scgd } */ *uap; 125368318Scgd register_t *retval; 125453468Smckusick { 125567748Smckusick struct vnode *vp, *dvp; 125667748Smckusick struct stat sb, sb1; 125753468Smckusick struct ostat osb; 125853468Smckusick int error; 125953468Smckusick struct nameidata nd; 126053468Smckusick 126167748Smckusick NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | LOCKPARENT, UIO_USERSPACE, 126268318Scgd SCARG(uap, path), p); 126353468Smckusick if (error = namei(&nd)) 126453468Smckusick return (error); 126567748Smckusick /* 126667748Smckusick * For symbolic links, always return the attributes of its 126767748Smckusick * containing directory, except for mode, size, and links. 126867748Smckusick */ 126967748Smckusick vp = nd.ni_vp; 127067748Smckusick dvp = nd.ni_dvp; 127167748Smckusick if (vp->v_type != VLNK) { 127267748Smckusick if (dvp == vp) 127367748Smckusick vrele(dvp); 127467748Smckusick else 127567748Smckusick vput(dvp); 127667748Smckusick error = vn_stat(vp, &sb, p); 127767748Smckusick vput(vp); 127867748Smckusick if (error) 127967748Smckusick return (error); 128067748Smckusick } else { 128167748Smckusick error = vn_stat(dvp, &sb, p); 128267748Smckusick vput(dvp); 128367748Smckusick if (error) { 128467748Smckusick vput(vp); 128567748Smckusick return (error); 128667748Smckusick } 128767748Smckusick error = vn_stat(vp, &sb1, p); 128867748Smckusick vput(vp); 128967748Smckusick if (error) 129067748Smckusick return (error); 129167748Smckusick sb.st_mode &= ~S_IFDIR; 129267748Smckusick sb.st_mode |= S_IFLNK; 129367748Smckusick sb.st_nlink = sb1.st_nlink; 129467748Smckusick sb.st_size = sb1.st_size; 129567748Smckusick sb.st_blocks = sb1.st_blocks; 129667748Smckusick } 129753468Smckusick cvtstat(&sb, &osb); 129868318Scgd error = copyout((caddr_t)&osb, (caddr_t)SCARG(uap, ub), sizeof (osb)); 129953468Smckusick return (error); 130053468Smckusick } 130153468Smckusick 130253468Smckusick /* 130364410Sbostic * Convert from an old to a new stat structure. 130453468Smckusick */ 130568318Scgd void 130653468Smckusick cvtstat(st, ost) 130753468Smckusick struct stat *st; 130853468Smckusick struct ostat *ost; 130953468Smckusick { 131053468Smckusick 131153468Smckusick ost->st_dev = st->st_dev; 131253468Smckusick ost->st_ino = st->st_ino; 131353468Smckusick ost->st_mode = st->st_mode; 131453468Smckusick ost->st_nlink = st->st_nlink; 131553468Smckusick ost->st_uid = st->st_uid; 131653468Smckusick ost->st_gid = st->st_gid; 131753468Smckusick ost->st_rdev = st->st_rdev; 131853468Smckusick if (st->st_size < (quad_t)1 << 32) 131953468Smckusick ost->st_size = st->st_size; 132053468Smckusick else 132153468Smckusick ost->st_size = -2; 132253468Smckusick ost->st_atime = st->st_atime; 132353468Smckusick ost->st_mtime = st->st_mtime; 132453468Smckusick ost->st_ctime = st->st_ctime; 132553468Smckusick ost->st_blksize = st->st_blksize; 132653468Smckusick ost->st_blocks = st->st_blocks; 132753468Smckusick ost->st_flags = st->st_flags; 132853468Smckusick ost->st_gen = st->st_gen; 132953468Smckusick } 133054348Smckusick #endif /* COMPAT_43 || COMPAT_SUNOS */ 133153468Smckusick 133253468Smckusick /* 133364410Sbostic * Get file status; this version follows links. 133453468Smckusick */ 133553468Smckusick /* ARGSUSED */ 133668318Scgd int 133753759Smckusick stat(p, uap, retval) 133853468Smckusick struct proc *p; 133968318Scgd register struct stat_args /* { 134068318Scgd syscallarg(char *) path; 134168318Scgd syscallarg(struct stat *) ub; 134268318Scgd } */ *uap; 134368318Scgd register_t *retval; 134437Sbill { 134542441Smckusick struct stat sb; 134642441Smckusick int error; 134747540Skarels struct nameidata nd; 134837Sbill 134968318Scgd NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, 135068318Scgd SCARG(uap, path), p); 135152322Smckusick if (error = namei(&nd)) 135247540Skarels return (error); 135352322Smckusick error = vn_stat(nd.ni_vp, &sb, p); 135452322Smckusick vput(nd.ni_vp); 135542441Smckusick if (error) 135647540Skarels return (error); 135768318Scgd error = copyout((caddr_t)&sb, (caddr_t)SCARG(uap, ub), sizeof (sb)); 135847540Skarels return (error); 135937Sbill } 136037Sbill 136137Sbill /* 136264410Sbostic * Get file status; this version does not follow links. 13635992Swnj */ 136442441Smckusick /* ARGSUSED */ 136568318Scgd int 136653759Smckusick lstat(p, uap, retval) 136745914Smckusick struct proc *p; 136868318Scgd register struct lstat_args /* { 136968318Scgd syscallarg(char *) path; 137068318Scgd syscallarg(struct stat *) ub; 137168318Scgd } */ *uap; 137268318Scgd register_t *retval; 137342441Smckusick { 137437741Smckusick int error; 137559373Smckusick struct vnode *vp, *dvp; 137659373Smckusick struct stat sb, sb1; 137747540Skarels struct nameidata nd; 13785992Swnj 137959373Smckusick NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | LOCKPARENT, UIO_USERSPACE, 138068318Scgd SCARG(uap, path), p); 138152322Smckusick if (error = namei(&nd)) 138247540Skarels return (error); 138359373Smckusick /* 138468579Smckusick * For symbolic links, always return the attributes of its containing 138568579Smckusick * directory, except for mode, size, inode number, and links. 138659373Smckusick */ 138759373Smckusick vp = nd.ni_vp; 138859373Smckusick dvp = nd.ni_dvp; 138959373Smckusick if (vp->v_type != VLNK) { 139059373Smckusick if (dvp == vp) 139159373Smckusick vrele(dvp); 139259373Smckusick else 139359373Smckusick vput(dvp); 139459373Smckusick error = vn_stat(vp, &sb, p); 139559373Smckusick vput(vp); 139659373Smckusick if (error) 139759373Smckusick return (error); 139859373Smckusick } else { 139959373Smckusick error = vn_stat(dvp, &sb, p); 140059373Smckusick vput(dvp); 140159373Smckusick if (error) { 140259373Smckusick vput(vp); 140359373Smckusick return (error); 140459373Smckusick } 140559373Smckusick error = vn_stat(vp, &sb1, p); 140659373Smckusick vput(vp); 140759373Smckusick if (error) 140859373Smckusick return (error); 140959373Smckusick sb.st_mode &= ~S_IFDIR; 141059373Smckusick sb.st_mode |= S_IFLNK; 141159373Smckusick sb.st_nlink = sb1.st_nlink; 141259373Smckusick sb.st_size = sb1.st_size; 141359373Smckusick sb.st_blocks = sb1.st_blocks; 141468579Smckusick sb.st_ino = sb1.st_ino; 141559373Smckusick } 141668318Scgd error = copyout((caddr_t)&sb, (caddr_t)SCARG(uap, ub), sizeof (sb)); 141747540Skarels return (error); 14185992Swnj } 14195992Swnj 14205992Swnj /* 142164410Sbostic * Get configurable pathname variables. 142260414Smckusick */ 142360414Smckusick /* ARGSUSED */ 142468318Scgd int 142560414Smckusick pathconf(p, uap, retval) 142660414Smckusick struct proc *p; 142768318Scgd register struct pathconf_args /* { 142868318Scgd syscallarg(char *) path; 142968318Scgd syscallarg(int) name; 143068318Scgd } */ *uap; 143168318Scgd register_t *retval; 143260414Smckusick { 143360414Smckusick int error; 143460414Smckusick struct nameidata nd; 143560414Smckusick 143668318Scgd NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, 143768318Scgd SCARG(uap, path), p); 143860414Smckusick if (error = namei(&nd)) 143960414Smckusick return (error); 144068318Scgd error = VOP_PATHCONF(nd.ni_vp, SCARG(uap, name), retval); 144160414Smckusick vput(nd.ni_vp); 144260414Smckusick return (error); 144360414Smckusick } 144460414Smckusick 144560414Smckusick /* 144649365Smckusick * Return target name of a symbolic link. 144737Sbill */ 144842441Smckusick /* ARGSUSED */ 144968318Scgd int 145042441Smckusick readlink(p, uap, retval) 145145914Smckusick struct proc *p; 145268318Scgd register struct readlink_args /* { 145368318Scgd syscallarg(char *) path; 145468318Scgd syscallarg(char *) buf; 145568318Scgd syscallarg(int) count; 145668318Scgd } */ *uap; 145768318Scgd register_t *retval; 145842441Smckusick { 145937741Smckusick register struct vnode *vp; 146037741Smckusick struct iovec aiov; 146137741Smckusick struct uio auio; 146237741Smckusick int error; 146347540Skarels struct nameidata nd; 14645992Swnj 146568318Scgd NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, 146668318Scgd SCARG(uap, path), p); 146752322Smckusick if (error = namei(&nd)) 146847540Skarels return (error); 146952322Smckusick vp = nd.ni_vp; 147064410Sbostic if (vp->v_type != VLNK) 147137741Smckusick error = EINVAL; 147264410Sbostic else { 147368318Scgd aiov.iov_base = SCARG(uap, buf); 147468318Scgd aiov.iov_len = SCARG(uap, count); 147564410Sbostic auio.uio_iov = &aiov; 147664410Sbostic auio.uio_iovcnt = 1; 147764410Sbostic auio.uio_offset = 0; 147864410Sbostic auio.uio_rw = UIO_READ; 147964410Sbostic auio.uio_segflg = UIO_USERSPACE; 148064410Sbostic auio.uio_procp = p; 148168318Scgd auio.uio_resid = SCARG(uap, count); 148264410Sbostic error = VOP_READLINK(vp, &auio, p->p_ucred); 14835992Swnj } 148437741Smckusick vput(vp); 148568318Scgd *retval = SCARG(uap, count) - auio.uio_resid; 148647540Skarels return (error); 14875992Swnj } 14885992Swnj 14899167Ssam /* 149064410Sbostic * Change flags of a file given a path name. 149138259Smckusick */ 149242441Smckusick /* ARGSUSED */ 149368318Scgd int 149442441Smckusick chflags(p, uap, retval) 149545914Smckusick struct proc *p; 149668318Scgd register struct chflags_args /* { 149768318Scgd syscallarg(char *) path; 149868318Scgd syscallarg(int) flags; 149968318Scgd } */ *uap; 150068318Scgd register_t *retval; 150142441Smckusick { 150238259Smckusick register struct vnode *vp; 150338259Smckusick struct vattr vattr; 150438259Smckusick int error; 150547540Skarels struct nameidata nd; 150638259Smckusick 150768318Scgd NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 150852322Smckusick if (error = namei(&nd)) 150947540Skarels return (error); 151052322Smckusick vp = nd.ni_vp; 151167654Smckusick VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 151259382Smckusick VOP_LOCK(vp); 151364410Sbostic if (vp->v_mount->mnt_flag & MNT_RDONLY) 151438259Smckusick error = EROFS; 151564410Sbostic else { 151664410Sbostic VATTR_NULL(&vattr); 151768318Scgd vattr.va_flags = SCARG(uap, flags); 151864410Sbostic error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 151938259Smckusick } 152038259Smckusick vput(vp); 152147540Skarels return (error); 152238259Smckusick } 152338259Smckusick 152438259Smckusick /* 152538259Smckusick * Change flags of a file given a file descriptor. 152638259Smckusick */ 152742441Smckusick /* ARGSUSED */ 152868318Scgd int 152942441Smckusick fchflags(p, uap, retval) 153045914Smckusick struct proc *p; 153168318Scgd register struct fchflags_args /* { 153268318Scgd syscallarg(int) fd; 153368318Scgd syscallarg(int) flags; 153468318Scgd } */ *uap; 153568318Scgd register_t *retval; 153642441Smckusick { 153738259Smckusick struct vattr vattr; 153838259Smckusick struct vnode *vp; 153938259Smckusick struct file *fp; 154038259Smckusick int error; 154138259Smckusick 154268318Scgd if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) 154347540Skarels return (error); 154438259Smckusick vp = (struct vnode *)fp->f_data; 154567654Smckusick VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 154638259Smckusick VOP_LOCK(vp); 154764410Sbostic if (vp->v_mount->mnt_flag & MNT_RDONLY) 154838259Smckusick error = EROFS; 154964410Sbostic else { 155064410Sbostic VATTR_NULL(&vattr); 155168318Scgd vattr.va_flags = SCARG(uap, flags); 155264410Sbostic error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 155338259Smckusick } 155438259Smckusick VOP_UNLOCK(vp); 155547540Skarels return (error); 155638259Smckusick } 155738259Smckusick 155838259Smckusick /* 15599167Ssam * Change mode of a file given path name. 15609167Ssam */ 156142441Smckusick /* ARGSUSED */ 156268318Scgd int 156342441Smckusick chmod(p, uap, retval) 156445914Smckusick struct proc *p; 156568318Scgd register struct chmod_args /* { 156668318Scgd syscallarg(char *) path; 156768318Scgd syscallarg(int) mode; 156868318Scgd } */ *uap; 156968318Scgd register_t *retval; 157042441Smckusick { 157137741Smckusick register struct vnode *vp; 157237741Smckusick struct vattr vattr; 157337741Smckusick int error; 157447540Skarels struct nameidata nd; 15755992Swnj 157668318Scgd NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 157752322Smckusick if (error = namei(&nd)) 157847540Skarels return (error); 157952322Smckusick vp = nd.ni_vp; 158067654Smckusick VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 158159382Smckusick VOP_LOCK(vp); 158264410Sbostic if (vp->v_mount->mnt_flag & MNT_RDONLY) 158337741Smckusick error = EROFS; 158464410Sbostic else { 158564410Sbostic VATTR_NULL(&vattr); 158668318Scgd vattr.va_mode = SCARG(uap, mode) & ALLPERMS; 158764410Sbostic error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 158837741Smckusick } 158937741Smckusick vput(vp); 159047540Skarels return (error); 15917701Ssam } 15927439Sroot 15939167Ssam /* 15949167Ssam * Change mode of a file given a file descriptor. 15959167Ssam */ 159642441Smckusick /* ARGSUSED */ 159768318Scgd int 159842441Smckusick fchmod(p, uap, retval) 159945914Smckusick struct proc *p; 160068318Scgd register struct fchmod_args /* { 160168318Scgd syscallarg(int) fd; 160268318Scgd syscallarg(int) mode; 160368318Scgd } */ *uap; 160468318Scgd register_t *retval; 160542441Smckusick { 160637741Smckusick struct vattr vattr; 160737741Smckusick struct vnode *vp; 160837741Smckusick struct file *fp; 160937741Smckusick int error; 16107701Ssam 161168318Scgd if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) 161247540Skarels return (error); 161337741Smckusick vp = (struct vnode *)fp->f_data; 161467654Smckusick VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 161537741Smckusick VOP_LOCK(vp); 161664410Sbostic if (vp->v_mount->mnt_flag & MNT_RDONLY) 161737741Smckusick error = EROFS; 161864410Sbostic else { 161964410Sbostic VATTR_NULL(&vattr); 162068318Scgd vattr.va_mode = SCARG(uap, mode) & ALLPERMS; 162164410Sbostic error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 16227439Sroot } 162337741Smckusick VOP_UNLOCK(vp); 162447540Skarels return (error); 16255992Swnj } 16265992Swnj 16279167Ssam /* 16289167Ssam * Set ownership given a path name. 16299167Ssam */ 163042441Smckusick /* ARGSUSED */ 163168318Scgd int 163242441Smckusick chown(p, uap, retval) 163345914Smckusick struct proc *p; 163468318Scgd register struct chown_args /* { 163568318Scgd syscallarg(char *) path; 163668318Scgd syscallarg(int) uid; 163768318Scgd syscallarg(int) gid; 163868318Scgd } */ *uap; 163968318Scgd register_t *retval; 164042441Smckusick { 164137741Smckusick register struct vnode *vp; 164237741Smckusick struct vattr vattr; 164337741Smckusick int error; 164447540Skarels struct nameidata nd; 164537Sbill 164668318Scgd NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 164752322Smckusick if (error = namei(&nd)) 164847540Skarels return (error); 164952322Smckusick vp = nd.ni_vp; 165067654Smckusick VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 165159382Smckusick VOP_LOCK(vp); 165264410Sbostic if (vp->v_mount->mnt_flag & MNT_RDONLY) 165337741Smckusick error = EROFS; 165464410Sbostic else { 165564410Sbostic VATTR_NULL(&vattr); 165668318Scgd vattr.va_uid = SCARG(uap, uid); 165768318Scgd vattr.va_gid = SCARG(uap, gid); 165864410Sbostic error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 165937741Smckusick } 166037741Smckusick vput(vp); 166147540Skarels return (error); 16627701Ssam } 16637439Sroot 16649167Ssam /* 16659167Ssam * Set ownership given a file descriptor. 16669167Ssam */ 166742441Smckusick /* ARGSUSED */ 166868318Scgd int 166942441Smckusick fchown(p, uap, retval) 167045914Smckusick struct proc *p; 167168318Scgd register struct fchown_args /* { 167268318Scgd syscallarg(int) fd; 167368318Scgd syscallarg(int) uid; 167468318Scgd syscallarg(int) gid; 167568318Scgd } */ *uap; 167668318Scgd register_t *retval; 167742441Smckusick { 167837741Smckusick struct vattr vattr; 167937741Smckusick struct vnode *vp; 168037741Smckusick struct file *fp; 168137741Smckusick int error; 16827701Ssam 168368318Scgd if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) 168447540Skarels return (error); 168537741Smckusick vp = (struct vnode *)fp->f_data; 168667654Smckusick VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 168737741Smckusick VOP_LOCK(vp); 168864410Sbostic if (vp->v_mount->mnt_flag & MNT_RDONLY) 168937741Smckusick error = EROFS; 169064410Sbostic else { 169164410Sbostic VATTR_NULL(&vattr); 169268318Scgd vattr.va_uid = SCARG(uap, uid); 169368318Scgd vattr.va_gid = SCARG(uap, gid); 169464410Sbostic error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 169537741Smckusick } 169637741Smckusick VOP_UNLOCK(vp); 169747540Skarels return (error); 16987701Ssam } 16997701Ssam 170042441Smckusick /* 170142441Smckusick * Set the access and modification times of a file. 170242441Smckusick */ 170342441Smckusick /* ARGSUSED */ 170468318Scgd int 170542441Smckusick utimes(p, uap, retval) 170645914Smckusick struct proc *p; 170768318Scgd register struct utimes_args /* { 170868318Scgd syscallarg(char *) path; 170968318Scgd syscallarg(struct timeval *) tptr; 171068318Scgd } */ *uap; 171168318Scgd register_t *retval; 171242441Smckusick { 171337741Smckusick register struct vnode *vp; 171411811Ssam struct timeval tv[2]; 171537741Smckusick struct vattr vattr; 171658840Storek int error; 171747540Skarels struct nameidata nd; 171811811Ssam 171958505Sbostic VATTR_NULL(&vattr); 172068318Scgd if (SCARG(uap, tptr) == NULL) { 172158505Sbostic microtime(&tv[0]); 172258505Sbostic tv[1] = tv[0]; 172358548Sbostic vattr.va_vaflags |= VA_UTIMES_NULL; 172468318Scgd } else if (error = copyin((caddr_t)SCARG(uap, tptr), (caddr_t)tv, 172568318Scgd sizeof (tv))) 172658505Sbostic return (error); 172768318Scgd NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 172852322Smckusick if (error = namei(&nd)) 172947540Skarels return (error); 173052322Smckusick vp = nd.ni_vp; 173167654Smckusick VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 173259382Smckusick VOP_LOCK(vp); 173364410Sbostic if (vp->v_mount->mnt_flag & MNT_RDONLY) 173437741Smckusick error = EROFS; 173564410Sbostic else { 173664410Sbostic vattr.va_atime.ts_sec = tv[0].tv_sec; 173764410Sbostic vattr.va_atime.ts_nsec = tv[0].tv_usec * 1000; 173864410Sbostic vattr.va_mtime.ts_sec = tv[1].tv_sec; 173964410Sbostic vattr.va_mtime.ts_nsec = tv[1].tv_usec * 1000; 174064410Sbostic error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 174121015Smckusick } 174237741Smckusick vput(vp); 174347540Skarels return (error); 174411811Ssam } 174511811Ssam 174664410Sbostic /* 174764410Sbostic * Truncate a file given its path name. 174864410Sbostic */ 174953468Smckusick /* ARGSUSED */ 175068318Scgd int 175160414Smckusick truncate(p, uap, retval) 175253468Smckusick struct proc *p; 175368318Scgd register struct truncate_args /* { 175468318Scgd syscallarg(char *) path; 175568318Scgd syscallarg(int) pad; 175668318Scgd syscallarg(off_t) length; 175768318Scgd } */ *uap; 175868318Scgd register_t *retval; 175953468Smckusick { 176037741Smckusick register struct vnode *vp; 176137741Smckusick struct vattr vattr; 176237741Smckusick int error; 176347540Skarels struct nameidata nd; 17647701Ssam 176568318Scgd NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 176652322Smckusick if (error = namei(&nd)) 176747540Skarels return (error); 176852322Smckusick vp = nd.ni_vp; 176967654Smckusick VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 177059382Smckusick VOP_LOCK(vp); 177164410Sbostic if (vp->v_type == VDIR) 177237741Smckusick error = EISDIR; 177364410Sbostic else if ((error = vn_writechk(vp)) == 0 && 177464410Sbostic (error = VOP_ACCESS(vp, VWRITE, p->p_ucred, p)) == 0) { 177564410Sbostic VATTR_NULL(&vattr); 177668318Scgd vattr.va_size = SCARG(uap, length); 177764410Sbostic error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 17787701Ssam } 177937741Smckusick vput(vp); 178047540Skarels return (error); 17817701Ssam } 17827701Ssam 178364410Sbostic /* 178464410Sbostic * Truncate a file given a file descriptor. 178564410Sbostic */ 178642441Smckusick /* ARGSUSED */ 178768318Scgd int 178860414Smckusick ftruncate(p, uap, retval) 178945914Smckusick struct proc *p; 179068318Scgd register struct ftruncate_args /* { 179168318Scgd syscallarg(int) fd; 179268318Scgd syscallarg(int) pad; 179368318Scgd syscallarg(off_t) length; 179468318Scgd } */ *uap; 179568318Scgd register_t *retval; 179642441Smckusick { 179737741Smckusick struct vattr vattr; 179837741Smckusick struct vnode *vp; 17997701Ssam struct file *fp; 180037741Smckusick int error; 18017701Ssam 180268318Scgd if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) 180347540Skarels return (error); 180437741Smckusick if ((fp->f_flag & FWRITE) == 0) 180547540Skarels return (EINVAL); 180637741Smckusick vp = (struct vnode *)fp->f_data; 180767654Smckusick VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 180837741Smckusick VOP_LOCK(vp); 180964410Sbostic if (vp->v_type == VDIR) 181037741Smckusick error = EISDIR; 181164410Sbostic else if ((error = vn_writechk(vp)) == 0) { 181264410Sbostic VATTR_NULL(&vattr); 181368318Scgd vattr.va_size = SCARG(uap, length); 181464410Sbostic error = VOP_SETATTR(vp, &vattr, fp->f_cred, p); 18157701Ssam } 181637741Smckusick VOP_UNLOCK(vp); 181747540Skarels return (error); 18187701Ssam } 18197701Ssam 182054863Storek #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 18219167Ssam /* 182254863Storek * Truncate a file given its path name. 182354863Storek */ 182454863Storek /* ARGSUSED */ 182568318Scgd int 182668318Scgd compat_43_truncate(p, uap, retval) 182754863Storek struct proc *p; 182868318Scgd register struct compat_43_truncate_args /* { 182968318Scgd syscallarg(char *) path; 183068318Scgd syscallarg(long) length; 183168318Scgd } */ *uap; 183268318Scgd register_t *retval; 183354863Storek { 183468318Scgd struct truncate_args /* { 183568318Scgd syscallarg(char *) path; 183668318Scgd syscallarg(int) pad; 183768318Scgd syscallarg(off_t) length; 183868318Scgd } */ nuap; 183954863Storek 184068318Scgd SCARG(&nuap, path) = SCARG(uap, path); 184168318Scgd SCARG(&nuap, length) = SCARG(uap, length); 184260428Smckusick return (truncate(p, &nuap, retval)); 184354863Storek } 184454863Storek 184554863Storek /* 184654863Storek * Truncate a file given a file descriptor. 184754863Storek */ 184854863Storek /* ARGSUSED */ 184968318Scgd int 185068318Scgd compat_43_ftruncate(p, uap, retval) 185154863Storek struct proc *p; 185268318Scgd register struct compat_43_ftruncate_args /* { 185368318Scgd syscallarg(int) fd; 185468318Scgd syscallarg(long) length; 185568318Scgd } */ *uap; 185668318Scgd register_t *retval; 185754863Storek { 185868318Scgd struct ftruncate_args /* { 185968318Scgd syscallarg(int) fd; 186068318Scgd syscallarg(int) pad; 186168318Scgd syscallarg(off_t) length; 186268318Scgd } */ nuap; 186354863Storek 186468318Scgd SCARG(&nuap, fd) = SCARG(uap, fd); 186568318Scgd SCARG(&nuap, length) = SCARG(uap, length); 186660428Smckusick return (ftruncate(p, &nuap, retval)); 186754863Storek } 186854863Storek #endif /* COMPAT_43 || COMPAT_SUNOS */ 186954863Storek 187054863Storek /* 187164410Sbostic * Sync an open file. 18729167Ssam */ 187342441Smckusick /* ARGSUSED */ 187468318Scgd int 187542441Smckusick fsync(p, uap, retval) 187645914Smckusick struct proc *p; 187768318Scgd struct fsync_args /* { 187868318Scgd syscallarg(int) fd; 187968318Scgd } */ *uap; 188068318Scgd register_t *retval; 18819167Ssam { 188239592Smckusick register struct vnode *vp; 18839167Ssam struct file *fp; 188437741Smckusick int error; 18859167Ssam 188668318Scgd if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) 188747540Skarels return (error); 188839592Smckusick vp = (struct vnode *)fp->f_data; 188939592Smckusick VOP_LOCK(vp); 189054441Smckusick error = VOP_FSYNC(vp, fp->f_cred, MNT_WAIT, p); 189139592Smckusick VOP_UNLOCK(vp); 189247540Skarels return (error); 18939167Ssam } 18949167Ssam 18959167Ssam /* 189664410Sbostic * Rename files. Source and destination must either both be directories, 189764410Sbostic * or both not be directories. If target is a directory, it must be empty. 18989167Ssam */ 189942441Smckusick /* ARGSUSED */ 190068318Scgd int 190142441Smckusick rename(p, uap, retval) 190245914Smckusick struct proc *p; 190368318Scgd register struct rename_args /* { 190468318Scgd syscallarg(char *) from; 190568318Scgd syscallarg(char *) to; 190668318Scgd } */ *uap; 190768318Scgd register_t *retval; 190842441Smckusick { 190937741Smckusick register struct vnode *tvp, *fvp, *tdvp; 191049735Smckusick struct nameidata fromnd, tond; 191137741Smckusick int error; 19127701Ssam 191352322Smckusick NDINIT(&fromnd, DELETE, WANTPARENT | SAVESTART, UIO_USERSPACE, 191468318Scgd SCARG(uap, from), p); 191552322Smckusick if (error = namei(&fromnd)) 191647540Skarels return (error); 191749735Smckusick fvp = fromnd.ni_vp; 191852322Smckusick NDINIT(&tond, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART, 191968318Scgd UIO_USERSPACE, SCARG(uap, to), p); 192052322Smckusick if (error = namei(&tond)) { 192152230Sheideman VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 192249735Smckusick vrele(fromnd.ni_dvp); 192342465Smckusick vrele(fvp); 192442465Smckusick goto out1; 192542465Smckusick } 192637741Smckusick tdvp = tond.ni_dvp; 192737741Smckusick tvp = tond.ni_vp; 192837741Smckusick if (tvp != NULL) { 192937741Smckusick if (fvp->v_type == VDIR && tvp->v_type != VDIR) { 193039242Sbostic error = ENOTDIR; 193137741Smckusick goto out; 193237741Smckusick } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) { 193339242Sbostic error = EISDIR; 193437741Smckusick goto out; 19359167Ssam } 19369167Ssam } 193739286Smckusick if (fvp == tdvp) 193837741Smckusick error = EINVAL; 193939286Smckusick /* 194049735Smckusick * If source is the same as the destination (that is the 194149735Smckusick * same inode number with the same name in the same directory), 194239286Smckusick * then there is nothing to do. 194339286Smckusick */ 194449735Smckusick if (fvp == tvp && fromnd.ni_dvp == tdvp && 194552322Smckusick fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen && 194652322Smckusick !bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr, 194752322Smckusick fromnd.ni_cnd.cn_namelen)) 194839286Smckusick error = -1; 194937741Smckusick out: 195042465Smckusick if (!error) { 195167654Smckusick VOP_LEASE(tdvp, p, p->p_ucred, LEASE_WRITE); 195252192Smckusick if (fromnd.ni_dvp != tdvp) 195367654Smckusick VOP_LEASE(fromnd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 195452192Smckusick if (tvp) 195567654Smckusick VOP_LEASE(tvp, p, p->p_ucred, LEASE_WRITE); 195652230Sheideman error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd, 195752230Sheideman tond.ni_dvp, tond.ni_vp, &tond.ni_cnd); 195842465Smckusick } else { 195952230Sheideman VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd); 196043344Smckusick if (tdvp == tvp) 196143344Smckusick vrele(tdvp); 196243344Smckusick else 196343344Smckusick vput(tdvp); 196442465Smckusick if (tvp) 196542465Smckusick vput(tvp); 196652230Sheideman VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 196749735Smckusick vrele(fromnd.ni_dvp); 196842465Smckusick vrele(fvp); 19699167Ssam } 197049735Smckusick vrele(tond.ni_startdir); 197152322Smckusick FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI); 197237741Smckusick out1: 197366801Smckusick if (fromnd.ni_startdir) 197466801Smckusick vrele(fromnd.ni_startdir); 197552322Smckusick FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI); 197639286Smckusick if (error == -1) 197747540Skarels return (0); 197847540Skarels return (error); 19797701Ssam } 19807701Ssam 19817535Sroot /* 198264410Sbostic * Make a directory file. 198312756Ssam */ 198442441Smckusick /* ARGSUSED */ 198568318Scgd int 198642441Smckusick mkdir(p, uap, retval) 198745914Smckusick struct proc *p; 198868318Scgd register struct mkdir_args /* { 198968318Scgd syscallarg(char *) path; 199068318Scgd syscallarg(int) mode; 199168318Scgd } */ *uap; 199268318Scgd register_t *retval; 199342441Smckusick { 199437741Smckusick register struct vnode *vp; 199537741Smckusick struct vattr vattr; 199637741Smckusick int error; 199747540Skarels struct nameidata nd; 199812756Ssam 199968318Scgd NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p); 200052322Smckusick if (error = namei(&nd)) 200147540Skarels return (error); 200252322Smckusick vp = nd.ni_vp; 200337741Smckusick if (vp != NULL) { 200452322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 200552322Smckusick if (nd.ni_dvp == vp) 200652322Smckusick vrele(nd.ni_dvp); 200743344Smckusick else 200852322Smckusick vput(nd.ni_dvp); 200942465Smckusick vrele(vp); 201047540Skarels return (EEXIST); 201112756Ssam } 201241362Smckusick VATTR_NULL(&vattr); 201337741Smckusick vattr.va_type = VDIR; 201468318Scgd vattr.va_mode = (SCARG(uap, mode) & ACCESSPERMS) &~ p->p_fd->fd_cmask; 201567654Smckusick VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 201652322Smckusick error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr); 201738145Smckusick if (!error) 201852322Smckusick vput(nd.ni_vp); 201947540Skarels return (error); 202012756Ssam } 202112756Ssam 202212756Ssam /* 202364410Sbostic * Remove a directory file. 202412756Ssam */ 202542441Smckusick /* ARGSUSED */ 202668318Scgd int 202742441Smckusick rmdir(p, uap, retval) 202845914Smckusick struct proc *p; 202968318Scgd struct rmdir_args /* { 203068318Scgd syscallarg(char *) path; 203168318Scgd } */ *uap; 203268318Scgd register_t *retval; 203312756Ssam { 203437741Smckusick register struct vnode *vp; 203537741Smckusick int error; 203647540Skarels struct nameidata nd; 203712756Ssam 203868318Scgd NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE, 203968318Scgd SCARG(uap, path), p); 204052322Smckusick if (error = namei(&nd)) 204147540Skarels return (error); 204252322Smckusick vp = nd.ni_vp; 204337741Smckusick if (vp->v_type != VDIR) { 204437741Smckusick error = ENOTDIR; 204512756Ssam goto out; 204612756Ssam } 204712756Ssam /* 204837741Smckusick * No rmdir "." please. 204912756Ssam */ 205052322Smckusick if (nd.ni_dvp == vp) { 205137741Smckusick error = EINVAL; 205212756Ssam goto out; 205312756Ssam } 205412756Ssam /* 205549365Smckusick * The root of a mounted filesystem cannot be deleted. 205612756Ssam */ 205737741Smckusick if (vp->v_flag & VROOT) 205837741Smckusick error = EBUSY; 205912756Ssam out: 206042465Smckusick if (!error) { 206167654Smckusick VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 206267654Smckusick VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 206352322Smckusick error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); 206442465Smckusick } else { 206552322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 206652322Smckusick if (nd.ni_dvp == vp) 206752322Smckusick vrele(nd.ni_dvp); 206843344Smckusick else 206952322Smckusick vput(nd.ni_dvp); 207042465Smckusick vput(vp); 207142465Smckusick } 207247540Skarels return (error); 207312756Ssam } 207412756Ssam 207554620Smckusick #ifdef COMPAT_43 207637741Smckusick /* 207749365Smckusick * Read a block of directory entries in a file system independent format. 207837741Smckusick */ 207968318Scgd int 208068318Scgd compat_43_getdirentries(p, uap, retval) 208154620Smckusick struct proc *p; 208268318Scgd register struct compat_43_getdirentries_args /* { 208368318Scgd syscallarg(int) fd; 208468318Scgd syscallarg(char *) buf; 208568318Scgd syscallarg(u_int) count; 208668318Scgd syscallarg(long *) basep; 208768318Scgd } */ *uap; 208868318Scgd register_t *retval; 208954620Smckusick { 209054620Smckusick register struct vnode *vp; 209154620Smckusick struct file *fp; 209254620Smckusick struct uio auio, kuio; 209354620Smckusick struct iovec aiov, kiov; 209454620Smckusick struct dirent *dp, *edp; 209554620Smckusick caddr_t dirbuf; 209667362Smckusick int error, eofflag, readcnt; 209754969Smckusick long loff; 209854620Smckusick 209968318Scgd if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) 210054620Smckusick return (error); 210154620Smckusick if ((fp->f_flag & FREAD) == 0) 210254620Smckusick return (EBADF); 210354620Smckusick vp = (struct vnode *)fp->f_data; 210467362Smckusick unionread: 210554620Smckusick if (vp->v_type != VDIR) 210654620Smckusick return (EINVAL); 210768318Scgd aiov.iov_base = SCARG(uap, buf); 210868318Scgd aiov.iov_len = SCARG(uap, count); 210954620Smckusick auio.uio_iov = &aiov; 211054620Smckusick auio.uio_iovcnt = 1; 211154620Smckusick auio.uio_rw = UIO_READ; 211254620Smckusick auio.uio_segflg = UIO_USERSPACE; 211354620Smckusick auio.uio_procp = p; 211468318Scgd auio.uio_resid = SCARG(uap, count); 211554620Smckusick VOP_LOCK(vp); 211654969Smckusick loff = auio.uio_offset = fp->f_offset; 211754620Smckusick # if (BYTE_ORDER != LITTLE_ENDIAN) 211856339Smckusick if (vp->v_mount->mnt_maxsymlinklen <= 0) { 211967362Smckusick error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, 212068663Smckusick (int *)0, (u_long *)0); 212156339Smckusick fp->f_offset = auio.uio_offset; 212256339Smckusick } else 212354620Smckusick # endif 212454620Smckusick { 212554620Smckusick kuio = auio; 212654620Smckusick kuio.uio_iov = &kiov; 212754620Smckusick kuio.uio_segflg = UIO_SYSSPACE; 212868318Scgd kiov.iov_len = SCARG(uap, count); 212968318Scgd MALLOC(dirbuf, caddr_t, SCARG(uap, count), M_TEMP, M_WAITOK); 213054620Smckusick kiov.iov_base = dirbuf; 213167362Smckusick error = VOP_READDIR(vp, &kuio, fp->f_cred, &eofflag, 213268663Smckusick (int *)0, (u_long *)0); 213356339Smckusick fp->f_offset = kuio.uio_offset; 213454620Smckusick if (error == 0) { 213568318Scgd readcnt = SCARG(uap, count) - kuio.uio_resid; 213654620Smckusick edp = (struct dirent *)&dirbuf[readcnt]; 213754620Smckusick for (dp = (struct dirent *)dirbuf; dp < edp; ) { 213854620Smckusick # if (BYTE_ORDER == LITTLE_ENDIAN) 213954969Smckusick /* 214055009Smckusick * The expected low byte of 214155009Smckusick * dp->d_namlen is our dp->d_type. 214255009Smckusick * The high MBZ byte of dp->d_namlen 214355009Smckusick * is our dp->d_namlen. 214454969Smckusick */ 214555009Smckusick dp->d_type = dp->d_namlen; 214655009Smckusick dp->d_namlen = 0; 214755009Smckusick # else 214855009Smckusick /* 214955009Smckusick * The dp->d_type is the high byte 215055009Smckusick * of the expected dp->d_namlen, 215155009Smckusick * so must be zero'ed. 215255009Smckusick */ 215355009Smckusick dp->d_type = 0; 215454620Smckusick # endif 215554620Smckusick if (dp->d_reclen > 0) { 215654620Smckusick dp = (struct dirent *) 215754620Smckusick ((char *)dp + dp->d_reclen); 215854620Smckusick } else { 215954620Smckusick error = EIO; 216054620Smckusick break; 216154620Smckusick } 216254620Smckusick } 216354620Smckusick if (dp >= edp) 216454620Smckusick error = uiomove(dirbuf, readcnt, &auio); 216554620Smckusick } 216654620Smckusick FREE(dirbuf, M_TEMP); 216754620Smckusick } 216854620Smckusick VOP_UNLOCK(vp); 216954620Smckusick if (error) 217054620Smckusick return (error); 217167362Smckusick 217267362Smckusick #ifdef UNION 217367362Smckusick { 217467362Smckusick extern int (**union_vnodeop_p)(); 217568079Spendry extern struct vnode *union_dircache __P((struct vnode *)); 217667362Smckusick 217768318Scgd if ((SCARG(uap, count) == auio.uio_resid) && 217867362Smckusick (vp->v_op == union_vnodeop_p)) { 217967362Smckusick struct vnode *lvp; 218067362Smckusick 218168079Spendry lvp = union_dircache(vp); 218267362Smckusick if (lvp != NULLVP) { 218367575Spendry struct vattr va; 218467575Spendry 218567575Spendry /* 218667575Spendry * If the directory is opaque, 218767575Spendry * then don't show lower entries 218867575Spendry */ 218967575Spendry error = VOP_GETATTR(vp, &va, fp->f_cred, p); 219067575Spendry if (va.va_flags & OPAQUE) { 219168079Spendry vput(lvp); 219267575Spendry lvp = NULL; 219367575Spendry } 219467575Spendry } 219567575Spendry 219667575Spendry if (lvp != NULLVP) { 219767362Smckusick error = VOP_OPEN(lvp, FREAD, fp->f_cred, p); 219867362Smckusick VOP_UNLOCK(lvp); 219967362Smckusick 220067362Smckusick if (error) { 220167362Smckusick vrele(lvp); 220267362Smckusick return (error); 220367362Smckusick } 220467362Smckusick fp->f_data = (caddr_t) lvp; 220567362Smckusick fp->f_offset = 0; 220667362Smckusick error = vn_close(vp, FREAD, fp->f_cred, p); 220767362Smckusick if (error) 220867362Smckusick return (error); 220967362Smckusick vp = lvp; 221067362Smckusick goto unionread; 221167362Smckusick } 221267362Smckusick } 221367362Smckusick } 221467362Smckusick #endif /* UNION */ 221567362Smckusick 221668318Scgd if ((SCARG(uap, count) == auio.uio_resid) && 221767362Smckusick (vp->v_flag & VROOT) && 221867362Smckusick (vp->v_mount->mnt_flag & MNT_UNION)) { 221967362Smckusick struct vnode *tvp = vp; 222067362Smckusick vp = vp->v_mount->mnt_vnodecovered; 222167362Smckusick VREF(vp); 222267362Smckusick fp->f_data = (caddr_t) vp; 222367362Smckusick fp->f_offset = 0; 222467362Smckusick vrele(tvp); 222567362Smckusick goto unionread; 222667362Smckusick } 222768318Scgd error = copyout((caddr_t)&loff, (caddr_t)SCARG(uap, basep), 222868318Scgd sizeof(long)); 222968318Scgd *retval = SCARG(uap, count) - auio.uio_resid; 223054620Smckusick return (error); 223154620Smckusick } 223267362Smckusick #endif /* COMPAT_43 */ 223354620Smckusick 223454620Smckusick /* 223554620Smckusick * Read a block of directory entries in a file system independent format. 223654620Smckusick */ 223768318Scgd int 223842441Smckusick getdirentries(p, uap, retval) 223945914Smckusick struct proc *p; 224068318Scgd register struct getdirentries_args /* { 224168318Scgd syscallarg(int) fd; 224268318Scgd syscallarg(char *) buf; 224368318Scgd syscallarg(u_int) count; 224468318Scgd syscallarg(long *) basep; 224568318Scgd } */ *uap; 224668318Scgd register_t *retval; 224742441Smckusick { 224839592Smckusick register struct vnode *vp; 224916540Ssam struct file *fp; 225037741Smckusick struct uio auio; 225137741Smckusick struct iovec aiov; 225254969Smckusick long loff; 225367362Smckusick int error, eofflag; 225412756Ssam 225568318Scgd if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) 225647540Skarels return (error); 225737741Smckusick if ((fp->f_flag & FREAD) == 0) 225847540Skarels return (EBADF); 225939592Smckusick vp = (struct vnode *)fp->f_data; 226055451Spendry unionread: 226139592Smckusick if (vp->v_type != VDIR) 226247540Skarels return (EINVAL); 226368318Scgd aiov.iov_base = SCARG(uap, buf); 226468318Scgd aiov.iov_len = SCARG(uap, count); 226537741Smckusick auio.uio_iov = &aiov; 226637741Smckusick auio.uio_iovcnt = 1; 226737741Smckusick auio.uio_rw = UIO_READ; 226837741Smckusick auio.uio_segflg = UIO_USERSPACE; 226948026Smckusick auio.uio_procp = p; 227068318Scgd auio.uio_resid = SCARG(uap, count); 227139592Smckusick VOP_LOCK(vp); 227254969Smckusick loff = auio.uio_offset = fp->f_offset; 227368663Smckusick error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, 227468663Smckusick (int *)0, (u_long *)0); 227539592Smckusick fp->f_offset = auio.uio_offset; 227639592Smckusick VOP_UNLOCK(vp); 227739592Smckusick if (error) 227847540Skarels return (error); 227966095Spendry 228066095Spendry #ifdef UNION 228166095Spendry { 228266095Spendry extern int (**union_vnodeop_p)(); 228368079Spendry extern struct vnode *union_dircache __P((struct vnode *)); 228466095Spendry 228568318Scgd if ((SCARG(uap, count) == auio.uio_resid) && 228666095Spendry (vp->v_op == union_vnodeop_p)) { 228767122Spendry struct vnode *lvp; 228866095Spendry 228968079Spendry lvp = union_dircache(vp); 229067122Spendry if (lvp != NULLVP) { 229167575Spendry struct vattr va; 229267575Spendry 229367575Spendry /* 229467575Spendry * If the directory is opaque, 229567575Spendry * then don't show lower entries 229667575Spendry */ 229767575Spendry error = VOP_GETATTR(vp, &va, fp->f_cred, p); 229867575Spendry if (va.va_flags & OPAQUE) { 229968079Spendry vput(lvp); 230067575Spendry lvp = NULL; 230167575Spendry } 230267575Spendry } 230367575Spendry 230467575Spendry if (lvp != NULLVP) { 230567362Smckusick error = VOP_OPEN(lvp, FREAD, fp->f_cred, p); 230667122Spendry VOP_UNLOCK(lvp); 230766095Spendry 230866095Spendry if (error) { 230967122Spendry vrele(lvp); 231066095Spendry return (error); 231166095Spendry } 231267122Spendry fp->f_data = (caddr_t) lvp; 231366095Spendry fp->f_offset = 0; 231467122Spendry error = vn_close(vp, FREAD, fp->f_cred, p); 231566095Spendry if (error) 231666095Spendry return (error); 231767122Spendry vp = lvp; 231866095Spendry goto unionread; 231966095Spendry } 232066095Spendry } 232166095Spendry } 232268318Scgd #endif /* UNION */ 232366095Spendry 232468318Scgd if ((SCARG(uap, count) == auio.uio_resid) && 232555451Spendry (vp->v_flag & VROOT) && 232655451Spendry (vp->v_mount->mnt_flag & MNT_UNION)) { 232755451Spendry struct vnode *tvp = vp; 232855451Spendry vp = vp->v_mount->mnt_vnodecovered; 232955451Spendry VREF(vp); 233055451Spendry fp->f_data = (caddr_t) vp; 233155451Spendry fp->f_offset = 0; 233255451Spendry vrele(tvp); 233355451Spendry goto unionread; 233455451Spendry } 233568318Scgd error = copyout((caddr_t)&loff, (caddr_t)SCARG(uap, basep), 233668318Scgd sizeof(long)); 233768318Scgd *retval = SCARG(uap, count) - auio.uio_resid; 233847540Skarels return (error); 233912756Ssam } 234012756Ssam 234112756Ssam /* 234249365Smckusick * Set the mode mask for creation of filesystem nodes. 234312756Ssam */ 234468318Scgd int 234542441Smckusick umask(p, uap, retval) 234645914Smckusick struct proc *p; 234768318Scgd struct umask_args /* { 234868318Scgd syscallarg(int) newmask; 234968318Scgd } */ *uap; 235068318Scgd register_t *retval; 235112756Ssam { 235264410Sbostic register struct filedesc *fdp; 235312756Ssam 235464410Sbostic fdp = p->p_fd; 235545914Smckusick *retval = fdp->fd_cmask; 235668318Scgd fdp->fd_cmask = SCARG(uap, newmask) & ALLPERMS; 235747540Skarels return (0); 235812756Ssam } 235937741Smckusick 236039566Smarc /* 236139566Smarc * Void all references to file by ripping underlying filesystem 236239566Smarc * away from vnode. 236339566Smarc */ 236442441Smckusick /* ARGSUSED */ 236568318Scgd int 236642441Smckusick revoke(p, uap, retval) 236745914Smckusick struct proc *p; 236868318Scgd register struct revoke_args /* { 236968318Scgd syscallarg(char *) path; 237068318Scgd } */ *uap; 237168318Scgd register_t *retval; 237242441Smckusick { 237339566Smarc register struct vnode *vp; 237439566Smarc struct vattr vattr; 237539566Smarc int error; 237647540Skarels struct nameidata nd; 237739566Smarc 237868318Scgd NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 237952322Smckusick if (error = namei(&nd)) 238047540Skarels return (error); 238152322Smckusick vp = nd.ni_vp; 238248026Smckusick if (error = VOP_GETATTR(vp, &vattr, p->p_ucred, p)) 238339566Smarc goto out; 238447540Skarels if (p->p_ucred->cr_uid != vattr.va_uid && 238547540Skarels (error = suser(p->p_ucred, &p->p_acflag))) 238639566Smarc goto out; 238739805Smckusick if (vp->v_usecount > 1 || (vp->v_flag & VALIASED)) 238868423Smckusick VOP_REVOKE(vp, REVOKEALL); 238939566Smarc out: 239039566Smarc vrele(vp); 239147540Skarels return (error); 239239566Smarc } 239339566Smarc 239449365Smckusick /* 239549365Smckusick * Convert a user file descriptor to a kernel file entry. 239649365Smckusick */ 239768318Scgd int 239864410Sbostic getvnode(fdp, fd, fpp) 239945914Smckusick struct filedesc *fdp; 240037741Smckusick struct file **fpp; 240164410Sbostic int fd; 240237741Smckusick { 240337741Smckusick struct file *fp; 240437741Smckusick 240564410Sbostic if ((u_int)fd >= fdp->fd_nfiles || 240664410Sbostic (fp = fdp->fd_ofiles[fd]) == NULL) 240737741Smckusick return (EBADF); 240837741Smckusick if (fp->f_type != DTYPE_VNODE) 240937741Smckusick return (EINVAL); 241037741Smckusick *fpp = fp; 241137741Smckusick return (0); 241237741Smckusick } 2413